Commit 7688959653aab9820613769926435ce87993bacd

Authored by xp.Huang
1 parent cea7fdf2

Merge branch 'ft' into 'main_dev'

fix: 修复Teambition上的问题

See merge request yunteng/thingskit-front!534

(cherry picked from commit 518484644c1ee2565e68856a0d7087323c033096)

8c3fb46a fix:DEFECT-1119...
a8dbbbd9 fix:DEFECT-1114 组态名称限制长度
b4c765f4 fix:DEFECT-1080 暗黑模式看板返回看不见
6011295a fix:DEFECT-1131 测试未输入ID时,提示错误,应提示未输入参数
7a7258d6 fix:DEFECT-1131 测试未输入ID时,提示错误,应提示未输入参数
1a7113e4 fix: 修复大屏公共接口管理操作权限问题
eaf22bd7 fix: DEFECT-1138 websocket接口还未选择产品,数据就测试出结果了
8637830f fix: DEFECT-1138 websocket接口还未选择产品,数据就测试出结果了
b3c40c28 fix: 修复报表配置corn表达式问题
1 -export enum VideoPlayerType {  
2 - m3u8 = 'application/x-mpegURL',  
3 - mp4 = 'video/mp4',  
4 - webm = 'video/webm',  
5 -}  
6 -  
7 -export const getVideoTypeByUrl = (url: string) => {  
8 - const splitExtReg = /(?:.*)(?<=\.)/;  
9 -  
10 - const type = url.replace(splitExtReg, '');  
11 -  
12 - if (VideoPlayerType[type]) return VideoPlayerType[type];  
13 -  
14 - return VideoPlayerType.mp4;  
15 -}; 1 +export enum VideoPlayerType {
  2 + m3u8 = 'application/x-mpegURL',
  3 + mp4 = 'video/mp4',
  4 + webm = 'video/webm',
  5 +}
  6 +
  7 +export const getVideoTypeByUrl = (url: string) => {
  8 + const splitExtReg = /(?:.*)(?<=\.)/;
  9 + const type = url.replace(splitExtReg, '');
  10 + /**
  11 + * https://vcsplay.scjtonline.cn:8200/live/HD_1569b634-4789-11eb-ab67-3cd2e55e0b20.m3u8?auth_key=1681179278-0-0-5c54a376f2ca32d05c4a152ee96336e9
  12 + * 如果是这种格式的m3u8,则截取的是这一部分.m3u8?auth_key=1681179278-0-0-5c54a376f2ca32d05c4a152ee96336e9
  13 + */
  14 + if (type.startsWith('m3u8')) return VideoPlayerType.m3u8;
  15 + if (type.startsWith('mp4')) return VideoPlayerType.mp4;
  16 + if (type.startsWith('webm')) return VideoPlayerType.webm;
  17 + return;
  18 +};
@@ -119,7 +119,7 @@ export const formSchema: FormSchema[] = [ @@ -119,7 +119,7 @@ export const formSchema: FormSchema[] = [
119 component: 'Input', 119 component: 'Input',
120 componentProps: { 120 componentProps: {
121 placeholder: '请输入组态名称', 121 placeholder: '请输入组态名称',
122 - maxLength: 255, 122 + maxLength: 36,
123 }, 123 },
124 }, 124 },
125 { 125 {
@@ -125,8 +125,8 @@ @@ -125,8 +125,8 @@
125 const getTable = getTestTableKeyValue(); 125 const getTable = getTestTableKeyValue();
126 const hasRequired = getTable?.some((it) => it.required === true && !it.value); 126 const hasRequired = getTable?.some((it) => it.required === true && !it.value);
127 if (hasRequired) { 127 if (hasRequired) {
128 - createMessage.error('选择项为必须的,参数不能为空');  
129 - throw new Error('选择项为必须的,参数不能为空'); 128 + createMessage.error('参数不能为空');
  129 + throw new Error('参数不能为空');
130 } 130 }
131 getTable?.map((it) => (params[it.key!] = it.value!)); 131 getTable?.map((it) => (params[it.key!] = it.value!));
132 } else if (props.data?.type === 'json') { 132 } else if (props.data?.type === 'json') {
@@ -8,7 +8,7 @@ @@ -8,7 +8,7 @@
8 <a-col :span="2"> 测试结果 </a-col> 8 <a-col :span="2"> 测试结果 </a-col>
9 <a-col :span="22"> 9 <a-col :span="22">
10 <a-textarea 10 <a-textarea
11 - v-if="ifWebSocket === '2'" 11 + v-if="isWebSocketType === '2'"
12 allow-clear 12 allow-clear
13 show-count 13 show-count
14 v-model:value="testResult" 14 v-model:value="testResult"
@@ -29,13 +29,12 @@ @@ -29,13 +29,12 @@
29 </div> 29 </div>
30 </template> 30 </template>
31 <script lang="ts" setup name="testRequest"> 31 <script lang="ts" setup name="testRequest">
32 - import { nextTick, ref, reactive } from 'vue'; 32 + import { nextTick, ref, reactive, onUnmounted } from 'vue';
33 import { Button } from 'ant-design-vue'; 33 import { Button } from 'ant-design-vue';
34 import { otherHttp } from '/@/utils/http/axios'; 34 import { otherHttp } from '/@/utils/http/axios';
35 import { useWebSocket } from '@vueuse/core'; 35 import { useWebSocket } from '@vueuse/core';
36 import { JWT_TOKEN_KEY } from '/@/enums/cacheEnum'; 36 import { JWT_TOKEN_KEY } from '/@/enums/cacheEnum';
37 import { getAuthCache } from '/@/utils/auth'; 37 import { getAuthCache } from '/@/utils/auth';
38 - import { useMessage } from '/@/hooks/web/useMessage';  
39 import { useUtils } from '../../../hooks/useUtils'; 38 import { useUtils } from '../../../hooks/useUtils';
40 39
41 const emits = defineEmits(['emitExcute']); 40 const emits = defineEmits(['emitExcute']);
@@ -48,10 +47,6 @@ @@ -48,10 +47,6 @@
48 47
49 const showTestFlag = ref(false); 48 const showTestFlag = ref(false);
50 49
51 - const ifWebSocket = ref('');  
52 -  
53 - const { createMessage } = useMessage();  
54 -  
55 const token = getAuthCache(JWT_TOKEN_KEY); 50 const token = getAuthCache(JWT_TOKEN_KEY);
56 51
57 const socketUrls = ref(''); 52 const socketUrls = ref('');
@@ -87,6 +82,8 @@ @@ -87,6 +82,8 @@
87 82
88 const httpResult = ref(''); 83 const httpResult = ref('');
89 84
  85 + const isWebSocketType = ref('');
  86 +
90 //执行测试接口 87 //执行测试接口
91 const handleExcute = () => { 88 const handleExcute = () => {
92 emits('emitExcute'); 89 emits('emitExcute');
@@ -97,15 +94,14 @@ @@ -97,15 +94,14 @@
97 await nextTick(); 94 await nextTick();
98 //获取Params和Header和Body 95 //获取Params和Header和Body
99 const Objects = props.data; 96 const Objects = props.data;
100 - const isWebSocketType = Objects?.method; 97 + isWebSocketType.value = Objects?.method;
101 const apiType = Objects?.apiType; 98 const apiType = Objects?.apiType;
102 const url = Objects?.apiGetUrl; 99 const url = Objects?.apiGetUrl;
103 const headers = Objects?.Header?.params; 100 const headers = Objects?.Header?.params;
104 const params = Objects?.Params?.params; 101 const params = Objects?.Params?.params;
105 const body = Objects?.Body?.params; 102 const body = Objects?.Body?.params;
106 const apiUrl = url?.restfulFormat(params); 103 const apiUrl = url?.restfulFormat(params);
107 - ifWebSocket.value = isWebSocketType;  
108 - if (isWebSocketType === '2') { 104 + if (isWebSocketType.value === '2') {
109 socketUrls.value = url; 105 socketUrls.value = url;
110 socketMessage.server = `${socketUrls.value}?token=${token}`; 106 socketMessage.server = `${socketUrls.value}?token=${token}`;
111 websocketRequest(params); 107 websocketRequest(params);
@@ -117,13 +113,15 @@ @@ -117,13 +113,15 @@
117 }; 113 };
118 114
119 //websocket请求 115 //websocket请求
120 - const websocketRequest = (params) => { 116 + const websocketRequest = (params, destroy = false) => {
121 //websocket请求 117 //websocket请求
122 - Reflect.deleteProperty(params, 'deviceProfileId');  
123 - Reflect.deleteProperty(params, 'organizationId');  
124 - Reflect.set(params, 'cmdId', 1);  
125 - Reflect.set(params, 'scope', 'LATEST_TELEMETRY');  
126 - Reflect.set(params, 'entityType', 'DEVICE'); 118 + if (Object.prototype.toString.call(params) === '[object Object]') {
  119 + Reflect.deleteProperty(params, 'deviceProfileId');
  120 + Reflect.deleteProperty(params, 'organizationId');
  121 + Reflect.set(params, 'cmdId', 1);
  122 + Reflect.set(params, 'scope', 'LATEST_TELEMETRY');
  123 + Reflect.set(params, 'entityType', 'DEVICE');
  124 + }
127 socketMessage.sendValue.tsSubCmds.push(params); 125 socketMessage.sendValue.tsSubCmds.push(params);
128 const { send, close } = useWebSocket(socketMessage.server, { 126 const { send, close } = useWebSocket(socketMessage.server, {
129 onConnected() { 127 onConnected() {
@@ -138,12 +136,17 @@ @@ -138,12 +136,17 @@
138 console.log('断开连接了'); 136 console.log('断开连接了');
139 close(); 137 close();
140 }, 138 },
141 - onError() {  
142 - createMessage.error('webSocket连接超时,请联系管理员');  
143 - }, 139 + onError() {},
144 }); 140 });
  141 + if (destroy) close();
145 }; 142 };
146 143
  144 + onUnmounted(() => {
  145 + if (isWebSocketType.value === '2') {
  146 + websocketRequest(null, true);
  147 + }
  148 + });
  149 +
147 //TODO: 待优化 项目自带第三方请求 150 //TODO: 待优化 项目自带第三方请求
148 const otherHttpRequest = async ( 151 const otherHttpRequest = async (
149 apiType, 152 apiType,
@@ -188,7 +191,7 @@ @@ -188,7 +191,7 @@
188 } 191 }
189 httpResult.value = '测试结果为:'; 192 httpResult.value = '测试结果为:';
190 testResult.value = '测试结果为:'; 193 testResult.value = '测试结果为:';
191 - ifWebSocket.value = '0'; 194 + isWebSocketType.value = '0';
192 }; 195 };
193 196
194 const showTest = () => (showTestFlag.value = true); 197 const showTest = () => (showTestFlag.value = true);
@@ -64,8 +64,8 @@ @@ -64,8 +64,8 @@
64 const getTable = getTestTableKeyValue(); 64 const getTable = getTestTableKeyValue();
65 const hasRequired = getTable?.some((it) => it.required === true && !it.value); 65 const hasRequired = getTable?.some((it) => it.required === true && !it.value);
66 if (hasRequired) { 66 if (hasRequired) {
67 - createMessage.error('选择项为必须的,参数不能为空');  
68 - throw new Error('选择项为必须的,参数不能为空'); 67 + createMessage.error('参数不能为空');
  68 + throw new Error('参数不能为空');
69 } 69 }
70 const params: any = {}; 70 const params: any = {};
71 getTable?.map((it: any) => (params[it.key!] = it.value!)); 71 getTable?.map((it: any) => (params[it.key!] = it.value!));
@@ -105,8 +105,8 @@ @@ -105,8 +105,8 @@
105 const getTable = getTestTableKeyValue(); 105 const getTable = getTestTableKeyValue();
106 const hasRequired = getTable?.some((it) => it.required === true && !it.value); 106 const hasRequired = getTable?.some((it) => it.required === true && !it.value);
107 if (hasRequired) { 107 if (hasRequired) {
108 - createMessage.error('选择项为必须的,参数不能为空');  
109 - throw new Error('选择项为必须的,参数不能为空'); 108 + createMessage.error('参数不能为空');
  109 + throw new Error('参数不能为空');
110 } 110 }
111 const params: any = {}; 111 const params: any = {};
112 getTable?.map((it) => (params[it.key!] = it.value!)); 112 getTable?.map((it) => (params[it.key!] = it.value!));
1 <template> 1 <template>
2 <div> 2 <div>
3 <BasicDrawer 3 <BasicDrawer
  4 + destroyOnClose
4 showFooter 5 showFooter
5 v-bind="$attrs" 6 v-bind="$attrs"
6 @register="registerDrawer" 7 @register="registerDrawer"
@@ -46,7 +47,7 @@ @@ -46,7 +47,7 @@
46 import { useMessage } from '/@/hooks/web/useMessage'; 47 import { useMessage } from '/@/hooks/web/useMessage';
47 import { useUtils } from './hooks/useUtils'; 48 import { useUtils } from './hooks/useUtils';
48 49
49 - const { resetReqHttpType, resetUpdateSchema } = useUtils(); 50 + const { resetReqHttpType } = useUtils();
50 51
51 const emits = defineEmits(['success', 'register']); 52 const emits = defineEmits(['success', 'register']);
52 53
@@ -69,10 +70,15 @@ @@ -69,10 +70,15 @@
69 const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => { 70 const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
70 await resetFields(); 71 await resetFields();
71 await nextTick(); 72 await nextTick();
72 - updateSchema(resetUpdateSchema);  
73 setFieldsValue(resetReqHttpType); 73 setFieldsValue(resetReqHttpType);
74 const title = `${!data.isUpdate ? '新增' : '修改'}公共接口`; 74 const title = `${!data.isUpdate ? '新增' : '修改'}公共接口`;
75 setDrawerProps({ title }); 75 setDrawerProps({ title });
  76 + updateSchema({
  77 + field: 'requestHttpTypeAndUrl',
  78 + componentProps: {
  79 + type: '0',
  80 + },
  81 + });
76 isUpdate.value = data.isUpdate; 82 isUpdate.value = data.isUpdate;
77 !isUpdate.value ? (putId.value = '') : (putId.value = data.record.id); 83 !isUpdate.value ? (putId.value = '') : (putId.value = data.record.id);
78 simpleRequestRef.value?.resetValue() && testSqlRef.value?.resetValue(); 84 simpleRequestRef.value?.resetValue() && testSqlRef.value?.resetValue();
@@ -39,7 +39,7 @@ @@ -39,7 +39,7 @@
39 icon: 'ant-design:node-expand-outlined', 39 icon: 'ant-design:node-expand-outlined',
40 onClick: handlePublish.bind(null, 'publish', record), 40 onClick: handlePublish.bind(null, 'publish', record),
41 ifShow: () => { 41 ifShow: () => {
42 - return record.state === 0; 42 + return record.state === 0 && record.creator === userId;
43 }, 43 },
44 }, 44 },
45 { 45 {
@@ -47,7 +47,7 @@ @@ -47,7 +47,7 @@
47 icon: 'ant-design:node-collapse-outlined', 47 icon: 'ant-design:node-collapse-outlined',
48 onClick: handlePublish.bind(null, 'canelPublish', record), 48 onClick: handlePublish.bind(null, 'canelPublish', record),
49 ifShow: () => { 49 ifShow: () => {
50 - return record.state === 1; 50 + return record.state === 1 && record.creator === userId;
51 }, 51 },
52 }, 52 },
53 { 53 {
@@ -55,7 +55,7 @@ @@ -55,7 +55,7 @@
55 icon: 'clarity:note-edit-line', 55 icon: 'clarity:note-edit-line',
56 onClick: handleCreateOrEdit.bind(null, record), 56 onClick: handleCreateOrEdit.bind(null, record),
57 ifShow: () => { 57 ifShow: () => {
58 - return record.state === 0; 58 + return record.state === 0 && record.creator === userId;
59 }, 59 },
60 }, 60 },
61 { 61 {
@@ -63,7 +63,7 @@ @@ -63,7 +63,7 @@
63 icon: 'ant-design:delete-outlined', 63 icon: 'ant-design:delete-outlined',
64 color: 'error', 64 color: 'error',
65 ifShow: () => { 65 ifShow: () => {
66 - return record.state === 0; 66 + return record.state === 0 && record.creator === userId;
67 }, 67 },
68 popConfirm: { 68 popConfirm: {
69 title: '是否确认删除', 69 title: '是否确认删除',
@@ -93,6 +93,12 @@ @@ -93,6 +93,12 @@
93 import { Popconfirm, Modal } from 'ant-design-vue'; 93 import { Popconfirm, Modal } from 'ant-design-vue';
94 import { JsonPreview } from '/@/components/CodeEditor'; 94 import { JsonPreview } from '/@/components/CodeEditor';
95 import { useMessage } from '/@/hooks/web/useMessage'; 95 import { useMessage } from '/@/hooks/web/useMessage';
  96 + import { USER_INFO_KEY } from '/@/enums/cacheEnum';
  97 + import { getAuthCache } from '/@/utils/auth';
  98 +
  99 + const userInfo = getAuthCache(USER_INFO_KEY) as any;
  100 +
  101 + const userId = ref(userInfo?.userId);
96 102
97 const [registerTable, { reload, clearSelectedRowKeys }] = useTable({ 103 const [registerTable, { reload, clearSelectedRowKeys }] = useTable({
98 api: getDataViewInterfacePage, 104 api: getDataViewInterfacePage,
1 -<template>  
2 - <BasicDrawer  
3 - :maskClosable="false"  
4 - @close="handleClose"  
5 - destroyOnClose  
6 - v-bind="$attrs"  
7 - @register="registerDrawer"  
8 - showFooter  
9 - :title="getTitle"  
10 - width="30%"  
11 - @ok="handleSubmit"  
12 - >  
13 - <BasicForm @register="registerForm">  
14 - <template #devices="{ model, field }">  
15 - <p style="display: none">{{ field }}</p>  
16 - <p>{{ queryModeFunc(model['queryMode']) }}</p>  
17 - <p>{{ orgFunc(model['organizationId']) }}</p>  
18 - <p>{{ dataTypeFunc(model['dataType']) }}</p>  
19 - <Select  
20 - placeholder="请选择设备"  
21 - v-model:value="selectDevice"  
22 - style="width: 100%"  
23 - :options="selectOptions"  
24 - @change="handleDeviceChange"  
25 - @deselect="handleDeselect"  
26 - mode="multiple"  
27 - labelInValue  
28 - notFoundContent="请选择设备"  
29 - />  
30 - <div style="margin-top: 1.5vh"></div>  
31 - <template v-for="(item, index) in deviceList" :key="item.value">  
32 - <p style="display: none">{{ index }}</p>  
33 - <DeviceAttrCpns  
34 - :ref="bindDeviceRefObj.deviceAttrRef"  
35 - :value="item"  
36 - :orgId="organizationId || orgId"  
37 - />  
38 - </template>  
39 - </template>  
40 - </BasicForm>  
41 - </BasicDrawer>  
42 -</template>  
43 -<script lang="ts" setup>  
44 - import { ref, computed, unref, reactive, watch, Ref } from 'vue';  
45 - import { BasicForm, useForm } from '/@/components/Form';  
46 - import { formSchema, organizationId } from './config.data';  
47 - import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';  
48 - import {  
49 - createOrEditReportManage,  
50 - putReportConfigManage,  
51 - reportEditDetailPage,  
52 - } from '/@/api/report/reportManager';  
53 - import { useMessage } from '/@/hooks/web/useMessage';  
54 - import moment from 'moment';  
55 - import { screenLinkPageByDeptIdGetDevice } from '/@/api/ruleengine/ruleengineApi';  
56 - import { Select } from 'ant-design-vue';  
57 - import DeviceAttrCpns from './cpns/DeviceAttrCpns.vue';  
58 - import { SchemaFiled } from './config.data';  
59 - import { QueryWay } from '../../device/localtion/cpns/TimePeriodForm/config';  
60 - import { AggregateDataEnum } from '../../device/localtion/cpns/TimePeriodForm/config';  
61 -  
62 - type TDeviceList = {  
63 - key?: string;  
64 - value?: string;  
65 - label?: string;  
66 - attribute?: string;  
67 - device?: string;  
68 - name?: string;  
69 - attributes?: string | undefined;  
70 - deviceProfileId?: string;  
71 - id?: string;  
72 - };  
73 - type TSelectOption = {  
74 - value?: string;  
75 - label?: string;  
76 - deviceProfileId?: string;  
77 - id?: string;  
78 - };  
79 - const emit = defineEmits(['success', 'register']);  
80 - const bindDeviceRefObj = {  
81 - deviceAttrRef: ref([]),  
82 - };  
83 - const isUpdate = ref(true);  
84 - const editId = ref('');  
85 - const orgId = ref('');  
86 - const selectOptions: Ref<TSelectOption[]> = ref([]);  
87 - const selectDevice = ref([]);  
88 - const deviceList: Ref<TDeviceList[]> = ref([]);  
89 - const editDeviceList: Ref<TDeviceList[]> = ref([]);  
90 - let editResData: any = reactive({});  
91 - const editDeviceAttr: any = ref([]);  
92 - const orgFuncId = ref('');  
93 - const queryModeStr = ref('');  
94 - const dataTypeStr = ref(0);  
95 - const orgFunc = (e) => {  
96 - orgFuncId.value = e;  
97 - };  
98 - const queryModeFunc = (e) => {  
99 - queryModeStr.value = e;  
100 - };  
101 - const dataTypeFunc = (e) => {  
102 - dataTypeStr.value = e;  
103 - };  
104 - watch(  
105 - () => dataTypeStr.value,  
106 - (newValue) => {  
107 - if (newValue == 0) {  
108 - setFieldsValue({ limit: 100 });  
109 - } else {  
110 - }  
111 - }  
112 - );  
113 - watch(  
114 - () => queryModeStr.value,  
115 - (newValue: string) => {  
116 - if (newValue == 'latest') {  
117 - setFieldsValue({ startTs: 1000 });  
118 - setFieldsValue({ interval: 1000 });  
119 - } else {  
120 - }  
121 - }  
122 - );  
123 - watch(  
124 - () => orgFuncId.value,  
125 - async (newValue: string) => {  
126 - if (newValue) {  
127 - //获取设备  
128 - const { items } = await screenLinkPageByDeptIdGetDevice({  
129 - organizationId: newValue,  
130 - });  
131 - selectOptions.value = items.map((item) => {  
132 - if (item.deviceType !== 'GATEWAY')  
133 - return {  
134 - label: item.alias ? item.alias : item.name,  
135 - value: item.tbDeviceId,  
136 - id: item.id,  
137 - deviceProfileId: item.deviceProfileId,  
138 - };  
139 - });  
140 - }  
141 - }  
142 - );  
143 - //设备Select选中  
144 - const handleDeviceChange = (_, o) => {  
145 - if (unref(isUpdate)) {  
146 - //编辑  
147 - let temp: any = [];  
148 - editDeviceAttr.value.forEach((f) => {  
149 - temp = [f, ...o];  
150 - });  
151 - let deWeightThree = () => {  
152 - let map = new Map();  
153 - for (let item of deviceList.value) {  
154 - if (!map.has(item.value)) {  
155 - map.set(item.value, item);  
156 - }  
157 - }  
158 - return [...map.values()];  
159 - };  
160 - temp = deWeightThree();  
161 - deviceList.value = temp;  
162 - if (o.length !== 0) {  
163 - deviceList.value = o;  
164 - }  
165 - } else {  
166 - deviceList.value = o;  
167 - }  
168 - };  
169 - //设备取消删除  
170 - const handleDeselect = (e) => {  
171 - if (unref(isUpdate)) {  
172 - //编辑  
173 - let deWeightThree = () => {  
174 - let map = new Map();  
175 - for (let item of deviceList.value) {  
176 - if (!map.has(item.value)) {  
177 - map.set(item.value, item);  
178 - }  
179 - }  
180 - return [...map.values()];  
181 - };  
182 - deviceList.value = deWeightThree();  
183 - const findEditValue = deviceList.value.findIndex((f) => f.value == e.value);  
184 - if (findEditValue !== -1) deviceList.value.splice(findEditValue, 1);  
185 - } else {  
186 - const eDevice = e.key || e.value;  
187 - const findValue = deviceList.value.findIndex((f) => f.value == eDevice);  
188 - if (findValue !== -1) deviceList.value.splice(findValue, 1);  
189 - }  
190 - };  
191 - const [registerForm, { validate, setFieldsValue, resetFields, updateSchema, getFieldsValue }] =  
192 - useForm({  
193 - labelWidth: 120,  
194 - schemas: formSchema,  
195 - showActionButtonGroup: false,  
196 - fieldMapToTime: [[SchemaFiled.DATE_RANGE, [SchemaFiled.START_TS, SchemaFiled.END_TS]]],  
197 - });  
198 - const isViewDetail = ref(false);  
199 -  
200 - const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {  
201 - await resetFields();  
202 - setDrawerProps({ confirmLoading: false });  
203 - isUpdate.value = !!data?.isUpdate;  
204 - isViewDetail.value = !!data?.isView;  
205 - if (unref(isViewDetail)) {  
206 - setDrawerProps({ showFooter: true });  
207 - if (unref(isUpdate)) {  
208 - setDrawerProps({ title: '编辑报表配置' });  
209 - } else {  
210 - setDrawerProps({ title: '新增报表配置' });  
211 - }  
212 - } else {  
213 - setDrawerProps({ showFooter: false });  
214 - setDrawerProps({ title: '查看报表配置' });  
215 - }  
216 - if (unref(isUpdate)) {  
217 - //编辑回显数据  
218 - editResData = await reportEditDetailPage(data.record.id);  
219 - //回显基础数据  
220 - editId.value = editResData.data.id;  
221 - await setFieldsValue(editResData.data);  
222 - //回显嵌套数据  
223 - await setFieldsValue({  
224 - agg: editResData.data.queryCondition?.agg,  
225 - interval: editResData.data.queryCondition?.interval,  
226 - limit: editResData.data.queryCondition?.limit,  
227 - orderBy: editResData.data.queryCondition?.orderBy,  
228 - useStrictDataTypes: editResData.data.queryCondition?.useStrictDataTypes,  
229 - startTs: editResData.data.queryCondition?.startTs,  
230 - endTs: editResData.data.queryCondition?.endTs,  
231 - way: editResData.data?.way,  
232 - queryMode: editResData.data.queryCondition?.queryMode === 0 ? 'latest' : 'timePeriod',  
233 - cronTime: editResData.data?.executeContent,  
234 - currentCycle: editResData.data?.cycle?.currentCycle,  
235 - cycleTime: editResData.data?.cycle?.cycleTime,  
236 - cycleType: editResData.data?.cycle?.cycleType,  
237 - });  
238 - const endTsTime = editResData.data.queryCondition?.endTs;  
239 - const startTsTime = editResData.data.queryCondition?.startTs;  
240 - const mathFloor = (endTsTime - startTsTime) / 10;  
241 - const multTen = Math.floor(mathFloor) * 10;  
242 - await setFieldsValue({  
243 - startTs: multTen,  
244 - });  
245 - if (editResData.data.queryCondition?.queryMode == 1) {  
246 - await setFieldsValue({  
247 - dataRange: [  
248 - editResData.data.queryCondition?.startTs,  
249 - editResData.data.queryCondition?.endTs,  
250 - ],  
251 - });  
252 - }  
253 - //回显聚合条件  
254 - const dataCompareOpions = [  
255 - { label: '最小值', value: AggregateDataEnum.MIN },  
256 - { label: '最大值', value: AggregateDataEnum.MAX },  
257 - { label: '平均值', value: AggregateDataEnum.AVG },  
258 - { label: '求和', value: AggregateDataEnum.SUM },  
259 - { label: '空', value: AggregateDataEnum.NONE },  
260 - ];  
261 - const updateSchemaAgg = (options: {}) => {  
262 - updateSchema({  
263 - field: SchemaFiled.AGG,  
264 - componentProps: {  
265 - options,  
266 - },  
267 - });  
268 - };  
269 - if (editResData.data.dataType == 1) updateSchemaAgg(dataCompareOpions.slice(0, 4));  
270 - else updateSchemaAgg(dataCompareOpions.slice(4, 5));  
271 - //回显执行方式和查询周期  
272 - const dataQueryOpions = [  
273 - { label: '固定周期', value: QueryWay.LATEST },  
274 - { label: '自定义周期', value: QueryWay.TIME_PERIOD },  
275 - ];  
276 - const updateSchemaQuery = (options: {}) => {  
277 - updateSchema({  
278 - field: SchemaFiled.WAY,  
279 - componentProps: {  
280 - options,  
281 - },  
282 - });  
283 - };  
284 - if (editResData.data.executeWay == 0) updateSchemaQuery(dataQueryOpions);  
285 - else updateSchemaQuery(dataQueryOpions.slice(0, 1));  
286 - //回显设备  
287 - orgId.value = editResData.data.organizationId;  
288 - const { items } = await screenLinkPageByDeptIdGetDevice({  
289 - organizationId: editResData.data.organizationId,  
290 - });  
291 - selectOptions.value = items.map((item) => {  
292 - if (item.deviceType !== 'GATEWAY')  
293 - return {  
294 - label: item.alias ? item.alias : item.name,  
295 - value: item.tbDeviceId,  
296 - id: item.id,  
297 - deviceProfileId: item.deviceProfileId,  
298 - };  
299 - });  
300 - const deviceIds = editResData.data.executeAttributes.map((m) => {  
301 - return {  
302 - label: m.name,  
303 - key: m.device,  
304 - };  
305 - });  
306 - selectDevice.value = deviceIds;  
307 - //回显设备属性  
308 - editDeviceAttr.value = editResData.data.executeAttributes?.map((item) => {  
309 - const T = selectOptions.value.find((o) => {  
310 - if (item.device === o.value) {  
311 - return {  
312 - id: o.id,  
313 - deviceProfileId: o.deviceProfileId,  
314 - };  
315 - }  
316 - });  
317 - return {  
318 - ...T,  
319 - label: item.alias ? item.alias : item.name,  
320 - value: item.device,  
321 - attributes: item.attributes,  
322 - };  
323 - });  
324 - deviceList.value = editDeviceAttr.value;  
325 - editDeviceList.value = editResData.data.executeAttributes;  
326 - } else {  
327 - setFieldsValue({  
328 - startTs: 1000,  
329 - interval: 1000,  
330 - });  
331 - editId.value = '';  
332 - orgId.value = '';  
333 - selectDevice.value = [];  
334 - selectOptions.value = [];  
335 - deviceList.value = [];  
336 - getAttrDevice.value = [];  
337 - editDeviceList.value = [];  
338 - editDeviceAttr.value = [];  
339 - updateSchema({  
340 - field: SchemaFiled.AGG,  
341 - componentProps: {  
342 - options: [],  
343 - },  
344 - });  
345 - //新增显示执行方式和查询周期  
346 - const dataQueryOpions = [  
347 - { label: '固定周期', value: QueryWay.LATEST },  
348 - { label: '自定义周期', value: QueryWay.TIME_PERIOD },  
349 - ];  
350 - const updateSchemaQuery = (options: {}) => {  
351 - updateSchema({  
352 - field: SchemaFiled.WAY,  
353 - componentProps: {  
354 - options,  
355 - },  
356 - });  
357 - };  
358 - if (getFieldsValue().executeWay == 0) updateSchemaQuery(dataQueryOpions);  
359 - }  
360 - });  
361 - const handleClose = () => {  
362 - deviceList.value = [];  
363 - editId.value = '';  
364 - orgId.value = '';  
365 - selectDevice.value = [];  
366 - selectOptions.value = [];  
367 - getAttrDevice.value = [];  
368 - editDeviceList.value = [];  
369 - editDeviceAttr.value = [];  
370 - };  
371 - const getAttrDevice: Ref<TDeviceList[]> = ref([]);  
372 - const getTitle = computed(() => (!unref(isUpdate) ? '新增报表配置' : '编辑报表配置'));  
373 - let postObj: any = reactive({});  
374 - let queryCondition: any = reactive({});  
375 - let executeContent: any = reactive({});  
376 - const startTs = ref(0);  
377 - const endTs = ref(0);  
378 -  
379 - const getFormValueFunc = () => {  
380 - const item: any = unref(bindDeviceRefObj.deviceAttrRef)?.map((item: any) => item.emitChange());  
381 - getAttrDevice.value = item;  
382 - };  
383 -  
384 - async function handleSubmit() {  
385 - setDrawerProps({ confirmLoading: true });  
386 - try {  
387 - const { createMessage } = useMessage();  
388 - const values = await validate();  
389 - if (!values) return;  
390 - getFormValueFunc();  
391 - let hasAttr = false;  
392 - if (!unref(isUpdate)) {  
393 - if (getAttrDevice.value.length === 0) {  
394 - return createMessage.error('请选择设备及其属性');  
395 - } else {  
396 - getAttrDevice.value.forEach((f: any) => {  
397 - if (f.attributes == undefined || f.attributes.length == 0) hasAttr = true;  
398 - });  
399 - }  
400 - } else {  
401 - if (getAttrDevice.value.length === 0) {  
402 - return createMessage.error('请选择设备及其属性');  
403 - } else {  
404 - getAttrDevice.value.forEach((f: any) => {  
405 - if (f.attributes == undefined || f.attributes.length == 0) hasAttr = true;  
406 - });  
407 - }  
408 - }  
409 - if (hasAttr) return createMessage.error('请选择设备属性');  
410 - if (values.executeWay == 0) {  
411 - executeContent = null;  
412 - } else {  
413 - executeContent = values.cronTime;  
414 - }  
415 - if (values.queryMode === QueryWay.LATEST) {  
416 - startTs.value = moment().subtract(values.startTs, 'ms').valueOf();  
417 - endTs.value = Date.now();  
418 - } else {  
419 - const fT = JSON.parse(JSON.stringify(values.dataRange));  
420 - startTs.value = moment(fT[0]).valueOf();  
421 - endTs.value = moment(fT[1]).valueOf();  
422 - }  
423 - queryCondition = {  
424 - agg: values.agg,  
425 - interval: values.interval,  
426 - limit: values.limit,  
427 - ...{  
428 - startTs: startTs.value,  
429 - },  
430 - ...{  
431 - endTs: endTs.value,  
432 - },  
433 - queryMode: values?.queryMode === 'latest' ? 0 : 1,  
434 - };  
435 - const cycle = {  
436 - currentCycle: values.currentCycle,  
437 - cycleTime: values.cycleTime,  
438 - cycleType: values.cycleType,  
439 - };  
440 - delete values.devices;  
441 - delete values.agg;  
442 - delete values.interval;  
443 - delete values.timeZone;  
444 - delete values.cronTime;  
445 - delete values.currentCycle;  
446 - delete values.cycleTime;  
447 - delete values.limit1;  
448 - delete values.startTs;  
449 - delete values.queryMode;  
450 - delete values.cycleType;  
451 - postObj = {  
452 - ...values,  
453 - ...{  
454 - executeAttributes:  
455 - getAttrDevice.value.length == 0 ? editDeviceList.value : getAttrDevice.value,  
456 - },  
457 - ...{ queryCondition },  
458 - ...{ cycle },  
459 - ...{ executeContent },  
460 - ...{ id: editId.value !== '' ? editId.value : '' },  
461 - };  
462 - let saveMessage = '添加成功';  
463 - let updateMessage = '修改成功';  
464 - editId.value !== ''  
465 - ? await putReportConfigManage(postObj)  
466 - : await createOrEditReportManage(postObj);  
467 -  
468 - closeDrawer();  
469 - emit('success');  
470 - createMessage.success(unref(isUpdate) ? updateMessage : saveMessage);  
471 - handleClose();  
472 - } finally {  
473 - setTimeout(() => {  
474 - setDrawerProps({ confirmLoading: false });  
475 - }, 300);  
476 - }  
477 - }  
478 -</script> 1 +<template>
  2 + <BasicDrawer
  3 + :maskClosable="false"
  4 + @close="handleClose"
  5 + destroyOnClose
  6 + v-bind="$attrs"
  7 + @register="registerDrawer"
  8 + showFooter
  9 + :title="getTitle"
  10 + width="30%"
  11 + @ok="handleSubmit"
  12 + >
  13 + <BasicForm @register="registerForm">
  14 + <template #devices="{ model, field }">
  15 + <p style="display: none">{{ field }}</p>
  16 + <p>{{ queryModeFunc(model['queryMode']) }}</p>
  17 + <p>{{ orgFunc(model['organizationId']) }}</p>
  18 + <p>{{ dataTypeFunc(model['dataType']) }}</p>
  19 + <Select
  20 + placeholder="请选择设备"
  21 + v-model:value="selectDevice"
  22 + style="width: 100%"
  23 + :options="selectOptions"
  24 + @change="handleDeviceChange"
  25 + @deselect="handleDeselect"
  26 + mode="multiple"
  27 + labelInValue
  28 + notFoundContent="请选择设备"
  29 + />
  30 + <div style="margin-top: 1.5vh"></div>
  31 + <template v-for="(item, index) in deviceList" :key="item.value">
  32 + <p style="display: none">{{ index }}</p>
  33 + <DeviceAttrCpns
  34 + :ref="bindDeviceRefObj.deviceAttrRef"
  35 + :value="item"
  36 + :orgId="organizationId || orgId"
  37 + />
  38 + </template>
  39 + </template>
  40 + </BasicForm>
  41 + </BasicDrawer>
  42 +</template>
  43 +<script lang="ts" setup>
  44 + import { ref, computed, unref, reactive, watch, Ref } from 'vue';
  45 + import { BasicForm, useForm } from '/@/components/Form';
  46 + import { formSchema, organizationId } from './config.data';
  47 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  48 + import {
  49 + createOrEditReportManage,
  50 + putReportConfigManage,
  51 + reportEditDetailPage,
  52 + } from '/@/api/report/reportManager';
  53 + import { useMessage } from '/@/hooks/web/useMessage';
  54 + import moment from 'moment';
  55 + import { screenLinkPageByDeptIdGetDevice } from '/@/api/ruleengine/ruleengineApi';
  56 + import { Select } from 'ant-design-vue';
  57 + import DeviceAttrCpns from './cpns/DeviceAttrCpns.vue';
  58 + import { SchemaFiled } from './config.data';
  59 + import { QueryWay } from '../../device/localtion/cpns/TimePeriodForm/config';
  60 + import { AggregateDataEnum } from '../../device/localtion/cpns/TimePeriodForm/config';
  61 +
  62 + type TDeviceList = {
  63 + key?: string;
  64 + value?: string;
  65 + label?: string;
  66 + attribute?: string;
  67 + device?: string;
  68 + name?: string;
  69 + attributes?: string | undefined;
  70 + deviceProfileId?: string;
  71 + id?: string;
  72 + };
  73 + type TSelectOption = {
  74 + value?: string;
  75 + label?: string;
  76 + deviceProfileId?: string;
  77 + id?: string;
  78 + };
  79 + const emit = defineEmits(['success', 'register']);
  80 + const bindDeviceRefObj = {
  81 + deviceAttrRef: ref([]),
  82 + };
  83 + const isUpdate = ref(true);
  84 + const editId = ref('');
  85 + const orgId = ref('');
  86 + const selectOptions: Ref<TSelectOption[]> = ref([]);
  87 + const selectDevice = ref([]);
  88 + const deviceList: Ref<TDeviceList[]> = ref([]);
  89 + const editDeviceList: Ref<TDeviceList[]> = ref([]);
  90 + let editResData: any = reactive({});
  91 + const editDeviceAttr: any = ref([]);
  92 + const orgFuncId = ref('');
  93 + const queryModeStr = ref('');
  94 + const dataTypeStr = ref(0);
  95 + const orgFunc = (e) => {
  96 + orgFuncId.value = e;
  97 + };
  98 + const queryModeFunc = (e) => {
  99 + queryModeStr.value = e;
  100 + };
  101 + const dataTypeFunc = (e) => {
  102 + dataTypeStr.value = e;
  103 + };
  104 + watch(
  105 + () => dataTypeStr.value,
  106 + (newValue) => {
  107 + if (newValue == 0) {
  108 + setFieldsValue({ limit: 100 });
  109 + } else {
  110 + }
  111 + }
  112 + );
  113 + watch(
  114 + () => queryModeStr.value,
  115 + (newValue: string) => {
  116 + if (newValue == 'latest') {
  117 + setFieldsValue({ startTs: 1000 });
  118 + setFieldsValue({ interval: 1000 });
  119 + } else {
  120 + }
  121 + }
  122 + );
  123 + watch(
  124 + () => orgFuncId.value,
  125 + async (newValue: string) => {
  126 + if (newValue) {
  127 + //获取设备
  128 + const { items } = await screenLinkPageByDeptIdGetDevice({
  129 + organizationId: newValue,
  130 + });
  131 + selectOptions.value = items.map((item) => {
  132 + if (item.deviceType !== 'GATEWAY')
  133 + return {
  134 + label: item.alias ? item.alias : item.name,
  135 + value: item.tbDeviceId,
  136 + id: item.id,
  137 + deviceProfileId: item.deviceProfileId,
  138 + };
  139 + });
  140 + }
  141 + }
  142 + );
  143 + //设备Select选中
  144 + const handleDeviceChange = (_, o) => {
  145 + if (unref(isUpdate)) {
  146 + //编辑
  147 + let temp: any = [];
  148 + editDeviceAttr.value.forEach((f) => {
  149 + temp = [f, ...o];
  150 + });
  151 + let deWeightThree = () => {
  152 + let map = new Map();
  153 + for (let item of deviceList.value) {
  154 + if (!map.has(item.value)) {
  155 + map.set(item.value, item);
  156 + }
  157 + }
  158 + return [...map.values()];
  159 + };
  160 + temp = deWeightThree();
  161 + deviceList.value = temp;
  162 + if (o.length !== 0) {
  163 + deviceList.value = o;
  164 + }
  165 + } else {
  166 + deviceList.value = o;
  167 + }
  168 + };
  169 + //设备取消删除
  170 + const handleDeselect = (e) => {
  171 + if (unref(isUpdate)) {
  172 + //编辑
  173 + let deWeightThree = () => {
  174 + let map = new Map();
  175 + for (let item of deviceList.value) {
  176 + if (!map.has(item.value)) {
  177 + map.set(item.value, item);
  178 + }
  179 + }
  180 + return [...map.values()];
  181 + };
  182 + deviceList.value = deWeightThree();
  183 + const findEditValue = deviceList.value.findIndex((f) => f.value == e.value);
  184 + if (findEditValue !== -1) deviceList.value.splice(findEditValue, 1);
  185 + } else {
  186 + const eDevice = e.key || e.value;
  187 + const findValue = deviceList.value.findIndex((f) => f.value == eDevice);
  188 + if (findValue !== -1) deviceList.value.splice(findValue, 1);
  189 + }
  190 + };
  191 + const [registerForm, { validate, setFieldsValue, resetFields, updateSchema, getFieldsValue }] =
  192 + useForm({
  193 + labelWidth: 120,
  194 + schemas: formSchema,
  195 + showActionButtonGroup: false,
  196 + fieldMapToTime: [[SchemaFiled.DATE_RANGE, [SchemaFiled.START_TS, SchemaFiled.END_TS]]],
  197 + });
  198 + const isViewDetail = ref(false);
  199 +
  200 + const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
  201 + await resetFields();
  202 + setDrawerProps({ confirmLoading: false });
  203 + isUpdate.value = !!data?.isUpdate;
  204 + isViewDetail.value = !!data?.isView;
  205 + if (unref(isViewDetail)) {
  206 + setDrawerProps({ showFooter: true });
  207 + if (unref(isUpdate)) {
  208 + setDrawerProps({ title: '编辑报表配置' });
  209 + } else {
  210 + setDrawerProps({ title: '新增报表配置' });
  211 + }
  212 + } else {
  213 + setDrawerProps({ showFooter: false });
  214 + setDrawerProps({ title: '查看报表配置' });
  215 + }
  216 + if (unref(isUpdate)) {
  217 + //编辑回显数据
  218 + editResData = await reportEditDetailPage(data.record.id);
  219 + //回显基础数据
  220 + editId.value = editResData.data.id;
  221 + const spanDisance = editResData.data.executeContent.split(' ');
  222 + await setFieldsValue(editResData.data);
  223 + //回显嵌套数据
  224 + await setFieldsValue({
  225 + agg: editResData.data.queryCondition?.agg,
  226 + interval: editResData.data.queryCondition?.interval,
  227 + limit: editResData.data.queryCondition?.limit,
  228 + orderBy: editResData.data.queryCondition?.orderBy,
  229 + useStrictDataTypes: editResData.data.queryCondition?.useStrictDataTypes,
  230 + startTs: editResData.data.queryCondition?.startTs,
  231 + endTs: editResData.data.queryCondition?.endTs,
  232 + way: editResData.data?.way,
  233 + queryMode: editResData.data.queryCondition?.queryMode === 0 ? 'latest' : 'timePeriod',
  234 + cronTime:
  235 + editResData.data?.cycle?.cycleType === 2
  236 + ? spanDisance[2] < 10
  237 + ? editResData.data.executeContent.slice(0, 7) + '* * ?'
  238 + : editResData.data.executeContent.slice(0, 7) + ' ' + '* * ?'
  239 + : editResData.data?.cycle?.cycleType === 1
  240 + ? spanDisance[2] < 10
  241 + ? editResData.data.executeContent.slice(0, 5) + ' ' + ' * * ?'
  242 + : editResData.data.executeContent.slice(0, 6) + ' ' + ' * * ?'
  243 + : editResData.data.executeContent,
  244 + currentCycle: editResData.data?.cycle?.currentCycle,
  245 + cycleTime: editResData.data?.cycle?.cycleTime,
  246 + cycleType: editResData.data?.cycle?.cycleType,
  247 + });
  248 + const endTsTime = editResData.data.queryCondition?.endTs;
  249 + const startTsTime = editResData.data.queryCondition?.startTs;
  250 + const mathFloor = (endTsTime - startTsTime) / 10;
  251 + const multTen = Math.floor(mathFloor) * 10;
  252 + await setFieldsValue({
  253 + startTs: multTen,
  254 + });
  255 + if (editResData.data.queryCondition?.queryMode == 1) {
  256 + await setFieldsValue({
  257 + dataRange: [
  258 + editResData.data.queryCondition?.startTs,
  259 + editResData.data.queryCondition?.endTs,
  260 + ],
  261 + });
  262 + }
  263 + //回显聚合条件
  264 + const dataCompareOpions = [
  265 + { label: '最小值', value: AggregateDataEnum.MIN },
  266 + { label: '最大值', value: AggregateDataEnum.MAX },
  267 + { label: '平均值', value: AggregateDataEnum.AVG },
  268 + { label: '求和', value: AggregateDataEnum.SUM },
  269 + { label: '空', value: AggregateDataEnum.NONE },
  270 + ];
  271 + const updateSchemaAgg = (options: {}) => {
  272 + updateSchema({
  273 + field: SchemaFiled.AGG,
  274 + componentProps: {
  275 + options,
  276 + },
  277 + });
  278 + };
  279 + if (editResData.data.dataType == 1) updateSchemaAgg(dataCompareOpions.slice(0, 4));
  280 + else updateSchemaAgg(dataCompareOpions.slice(4, 5));
  281 + //回显执行方式和查询周期
  282 + const dataQueryOpions = [
  283 + { label: '固定周期', value: QueryWay.LATEST },
  284 + { label: '自定义周期', value: QueryWay.TIME_PERIOD },
  285 + ];
  286 + const updateSchemaQuery = (options: {}) => {
  287 + updateSchema({
  288 + field: SchemaFiled.WAY,
  289 + componentProps: {
  290 + options,
  291 + },
  292 + });
  293 + };
  294 + if (editResData.data.executeWay == 0) updateSchemaQuery(dataQueryOpions);
  295 + else updateSchemaQuery(dataQueryOpions.slice(0, 1));
  296 + //回显设备
  297 + orgId.value = editResData.data.organizationId;
  298 + const { items } = await screenLinkPageByDeptIdGetDevice({
  299 + organizationId: editResData.data.organizationId,
  300 + });
  301 + selectOptions.value = items.map((item) => {
  302 + if (item.deviceType !== 'GATEWAY')
  303 + return {
  304 + label: item.alias ? item.alias : item.name,
  305 + value: item.tbDeviceId,
  306 + id: item.id,
  307 + deviceProfileId: item.deviceProfileId,
  308 + };
  309 + });
  310 + const deviceIds = editResData.data.executeAttributes.map((m) => {
  311 + return {
  312 + label: m.name,
  313 + key: m.device,
  314 + };
  315 + });
  316 + selectDevice.value = deviceIds;
  317 + //回显设备属性
  318 + editDeviceAttr.value = editResData.data.executeAttributes?.map((item) => {
  319 + const T = selectOptions.value.find((o) => {
  320 + if (item.device === o.value) {
  321 + return {
  322 + id: o.id,
  323 + deviceProfileId: o.deviceProfileId,
  324 + };
  325 + }
  326 + });
  327 + return {
  328 + ...T,
  329 + label: item.alias ? item.alias : item.name,
  330 + value: item.device,
  331 + attributes: item.attributes,
  332 + };
  333 + });
  334 + deviceList.value = editDeviceAttr.value;
  335 + editDeviceList.value = editResData.data.executeAttributes;
  336 + } else {
  337 + setFieldsValue({
  338 + startTs: 1000,
  339 + interval: 1000,
  340 + });
  341 + editId.value = '';
  342 + orgId.value = '';
  343 + selectDevice.value = [];
  344 + selectOptions.value = [];
  345 + deviceList.value = [];
  346 + getAttrDevice.value = [];
  347 + editDeviceList.value = [];
  348 + editDeviceAttr.value = [];
  349 + updateSchema({
  350 + field: SchemaFiled.AGG,
  351 + componentProps: {
  352 + options: [],
  353 + },
  354 + });
  355 + //新增显示执行方式和查询周期
  356 + const dataQueryOpions = [
  357 + { label: '固定周期', value: QueryWay.LATEST },
  358 + { label: '自定义周期', value: QueryWay.TIME_PERIOD },
  359 + ];
  360 + const updateSchemaQuery = (options: {}) => {
  361 + updateSchema({
  362 + field: SchemaFiled.WAY,
  363 + componentProps: {
  364 + options,
  365 + },
  366 + });
  367 + };
  368 + if (getFieldsValue().executeWay == 0) updateSchemaQuery(dataQueryOpions);
  369 + }
  370 + });
  371 + const handleClose = () => {
  372 + deviceList.value = [];
  373 + editId.value = '';
  374 + orgId.value = '';
  375 + selectDevice.value = [];
  376 + selectOptions.value = [];
  377 + getAttrDevice.value = [];
  378 + editDeviceList.value = [];
  379 + editDeviceAttr.value = [];
  380 + };
  381 + const getAttrDevice: Ref<TDeviceList[]> = ref([]);
  382 + const getTitle = computed(() => (!unref(isUpdate) ? '新增报表配置' : '编辑报表配置'));
  383 + let postObj: any = reactive({});
  384 + let queryCondition: any = reactive({});
  385 + let executeContent: any = reactive({});
  386 + const startTs = ref(0);
  387 + const endTs = ref(0);
  388 +
  389 + const getFormValueFunc = () => {
  390 + const item: any = unref(bindDeviceRefObj.deviceAttrRef)?.map((item: any) => item.emitChange());
  391 + getAttrDevice.value = item;
  392 + };
  393 +
  394 + async function handleSubmit() {
  395 + setDrawerProps({ confirmLoading: true });
  396 + try {
  397 + const { createMessage } = useMessage();
  398 + const values = await validate();
  399 + if (!values) return;
  400 + getFormValueFunc();
  401 + let hasAttr = false;
  402 + if (!unref(isUpdate)) {
  403 + if (getAttrDevice.value.length === 0) {
  404 + return createMessage.error('请选择设备及其属性');
  405 + } else {
  406 + getAttrDevice.value.forEach((f: any) => {
  407 + if (f.attributes == undefined || f.attributes.length == 0) hasAttr = true;
  408 + });
  409 + }
  410 + } else {
  411 + if (getAttrDevice.value.length === 0) {
  412 + return createMessage.error('请选择设备及其属性');
  413 + } else {
  414 + getAttrDevice.value.forEach((f: any) => {
  415 + if (f.attributes == undefined || f.attributes.length == 0) hasAttr = true;
  416 + });
  417 + }
  418 + }
  419 + if (hasAttr) return createMessage.error('请选择设备属性');
  420 + if (values.executeWay == 0) {
  421 + executeContent = null;
  422 + } else {
  423 + //拼接corn
  424 + let joinCorn = '';
  425 + if (values.cycleType === 1) {
  426 + joinCorn = values.cronTime.slice(0, 6) + values.currentCycle.slice(5);
  427 + executeContent = joinCorn;
  428 + } else if (values.cycleType === 0) {
  429 + executeContent = values.cronTime;
  430 + } else if (values.cycleType === 2) {
  431 + joinCorn = values.cronTime.slice(0, 6) + values.cycleTime.slice(5);
  432 + executeContent = joinCorn;
  433 + }
  434 + }
  435 + if (values.queryMode === QueryWay.LATEST) {
  436 + startTs.value = moment().subtract(values.startTs, 'ms').valueOf();
  437 + endTs.value = Date.now();
  438 + } else {
  439 + const fT = JSON.parse(JSON.stringify(values.dataRange));
  440 + startTs.value = moment(fT[0]).valueOf();
  441 + endTs.value = moment(fT[1]).valueOf();
  442 + }
  443 + queryCondition = {
  444 + agg: values.agg,
  445 + interval: values.interval,
  446 + limit: values.limit,
  447 + ...{
  448 + startTs: startTs.value,
  449 + },
  450 + ...{
  451 + endTs: endTs.value,
  452 + },
  453 + queryMode: values?.queryMode === 'latest' ? 0 : 1,
  454 + };
  455 + const cycle: any = {};
  456 + if (values.cycleType === 0) {
  457 + cycle.cycleType = values.cycleType;
  458 + cycle.cronTime = values.cronTime;
  459 + }
  460 + if (values.cycleType === 1) {
  461 + cycle.cycleType = values.cycleType;
  462 + cycle.currentCycle = values.currentCycle;
  463 + cycle.cronTime = values.cronTime;
  464 + }
  465 + if (values.cycleType === 2) {
  466 + cycle.cycleType = values.cycleType;
  467 + cycle.cycleTime = values.cycleTime;
  468 + cycle.cronTime = values.cronTime;
  469 + }
  470 + // const cycle = {
  471 + // currentCycle: values.currentCycle,
  472 + // cycleTime: values.cycleTime,
  473 + // cronTime: values.cronTime,
  474 + // cycleType: values.cycleType,
  475 + // };
  476 + delete values.devices;
  477 + delete values.agg;
  478 + delete values.interval;
  479 + delete values.timeZone;
  480 + delete values.cronTime;
  481 + delete values.currentCycle;
  482 + delete values.cycleTime;
  483 + delete values.limit1;
  484 + delete values.startTs;
  485 + delete values.queryMode;
  486 + delete values.cycleType;
  487 + postObj = {
  488 + ...values,
  489 + ...{
  490 + executeAttributes:
  491 + getAttrDevice.value.length == 0 ? editDeviceList.value : getAttrDevice.value,
  492 + },
  493 + ...{ queryCondition },
  494 + ...{ cycle },
  495 + ...{ executeContent },
  496 + ...{ id: editId.value !== '' ? editId.value : '' },
  497 + };
  498 + let saveMessage = '添加成功';
  499 + let updateMessage = '修改成功';
  500 + editId.value !== ''
  501 + ? await putReportConfigManage(postObj)
  502 + : await createOrEditReportManage(postObj);
  503 +
  504 + closeDrawer();
  505 + emit('success');
  506 + createMessage.success(unref(isUpdate) ? updateMessage : saveMessage);
  507 + handleClose();
  508 + } finally {
  509 + setTimeout(() => {
  510 + setDrawerProps({ confirmLoading: false });
  511 + }, 300);
  512 + }
  513 + }
  514 +</script>
1 -import { ref } from 'vue';  
2 -import { BasicColumn, FormSchema } from '/@/components/Table';  
3 -import type { FormSchema as QFormSchema } from '/@/components/Form/index';  
4 -import moment from 'moment';  
5 -import { getOrganizationList } from '/@/api/system/system';  
6 -import { copyTransFun } from '/@/utils/fnUtils';  
7 -import { findDictItemByCode } from '/@/api/system/dict';  
8 -import { isTiming, isWeek, isMonth, isFixedTime } from './timeConfig';  
9 -import { AggregateDataEnum } from '../../device/localtion/cpns/TimePeriodForm/config';  
10 -import {  
11 - getPacketIntervalByRange,  
12 - getPacketIntervalByValue,  
13 - intervalOption,  
14 -} from '../../device/localtion/cpns/TimePeriodForm/helper';  
15 -  
16 -export enum QueryWay {  
17 - LATEST = 'latest',  
18 - TIME_PERIOD = 'timePeriod',  
19 -}  
20 -export enum SchemaFiled {  
21 - WAY = 'queryMode',  
22 - TIME_PERIOD = 'timePeriod',  
23 - KEYS = 'keys',  
24 - DATE_RANGE = 'dataRange',  
25 - START_TS = 'startTs',  
26 - END_TS = 'endTs',  
27 - INTERVAL = 'interval',  
28 - LIMIT = 'limit',  
29 - AGG = 'agg',  
30 - ORDER_BY = 'orderBy',  
31 -}  
32 -export const organizationId = ref('');  
33 -  
34 -// 表格配置  
35 -export const columns: BasicColumn[] = [  
36 - {  
37 - title: '配置名称',  
38 - dataIndex: 'name',  
39 - width: 120,  
40 - },  
41 - {  
42 - title: '所属组织',  
43 - dataIndex: 'organizationDTO.name',  
44 - width: 120,  
45 - },  
46 - {  
47 - title: '数据类型',  
48 - dataIndex: 'dataType',  
49 - width: 120,  
50 - format: (_text: string, record: Recordable) => {  
51 - return record.dataType === 0 ? '原始数据' : '聚合数据';  
52 - },  
53 - },  
54 - {  
55 - title: '配置状态',  
56 - dataIndex: 'status',  
57 - width: 120,  
58 - slots: { customRender: 'configStatus' },  
59 - },  
60 - {  
61 - title: '执行方式',  
62 - dataIndex: 'executeWay',  
63 - width: 160,  
64 - format: (_text: string, record: Recordable) => {  
65 - return record.executeWay === 0 ? '立即执行' : '定时执行';  
66 - },  
67 - },  
68 - {  
69 - title: '执行设备',  
70 - dataIndex: 'devices',  
71 - width: 160,  
72 - slots: { customRender: 'doDeviceSlot' },  
73 - },  
74 - {  
75 - title: '创建人',  
76 - dataIndex: 'createUserName',  
77 - width: 180,  
78 - },  
79 - {  
80 - title: '创建时间',  
81 - dataIndex: 'createTime',  
82 - width: 180,  
83 - },  
84 -];  
85 -export const viewDeviceColumn: BasicColumn[] = [  
86 - {  
87 - title: '设备',  
88 - dataIndex: 'device',  
89 - width: 80,  
90 - },  
91 - {  
92 - title: '属性',  
93 - dataIndex: 'attribute',  
94 - width: 120,  
95 - },  
96 -];  
97 -  
98 -// 查询配置  
99 -export const searchFormSchema: FormSchema[] = [  
100 - {  
101 - field: 'name',  
102 - label: '配置名称',  
103 - component: 'Input',  
104 - colProps: { span: 6 },  
105 - componentProps: {  
106 - maxLength: 36,  
107 - placeholder: '请输入配置名称',  
108 - },  
109 - },  
110 - {  
111 - field: 'status',  
112 - label: '配置状态',  
113 - component: 'Select',  
114 - colProps: { span: 6 },  
115 - componentProps: {  
116 - options: [  
117 - {  
118 - label: '启用',  
119 - value: 1,  
120 - },  
121 - {  
122 - label: '禁用',  
123 - value: 0,  
124 - },  
125 - ],  
126 - placeholder: '请选择配置状态',  
127 - },  
128 - },  
129 - {  
130 - field: 'sendTime',  
131 - label: '创建时间',  
132 - component: 'RangePicker',  
133 - componentProps: {  
134 - showTime: {  
135 - defaultValue: [moment('00:00:00', 'HH:mm:ss'), moment('23:59:59', 'HH:mm:ss')],  
136 - },  
137 - },  
138 - colProps: { span: 6 },  
139 - },  
140 -];  
141 -  
142 -// 新增编辑配置  
143 -export const formSchema: QFormSchema[] = [  
144 - {  
145 - field: 'name',  
146 - label: '报表名称',  
147 - colProps: { span: 24 },  
148 - required: true,  
149 - component: 'Input',  
150 - componentProps: {  
151 - maxLength: 64,  
152 - placeholder: '请输入报表名称',  
153 - },  
154 - },  
155 - {  
156 - field: 'organizationId',  
157 - label: '所属组织',  
158 - colProps: { span: 24 },  
159 - component: 'ApiTreeSelect',  
160 - required: true,  
161 - componentProps: () => {  
162 - return {  
163 - maxLength: 250,  
164 - placeholder: '请选择所属组织',  
165 - api: async () => {  
166 - const data = await getOrganizationList();  
167 - copyTransFun(data as any as any[]);  
168 - return data;  
169 - },  
170 - async onChange(e) {  
171 - organizationId.value = e;  
172 - },  
173 - };  
174 - },  
175 - },  
176 - {  
177 - field: 'remark',  
178 - label: '描述',  
179 - colProps: { span: 24 },  
180 - component: 'InputTextArea',  
181 - componentProps: {  
182 - maxLength: 255,  
183 - placeholder: '请输入描述',  
184 - },  
185 - },  
186 - {  
187 - field: 'executeWay',  
188 - component: 'RadioGroup',  
189 - helpMessage: [  
190 - `立即执行,在创建完报表配置后,启用配置即执行。  
191 - 定时执行,用户定义执行时间,启用后,  
192 - 在满足执行时间条件后,自动执行。`,  
193 - ],  
194 - label: '执行方式',  
195 - colProps: {  
196 - span: 24,  
197 - },  
198 - defaultValue: 0,  
199 - componentProps: ({ formActionType }) => {  
200 - const { updateSchema, setFieldsValue } = formActionType;  
201 - const options = [  
202 - {  
203 - label: '立即执行',  
204 - value: 0,  
205 - },  
206 - {  
207 - label: '定时执行',  
208 - value: 1,  
209 - },  
210 - ];  
211 - return {  
212 - options,  
213 - placeholder: '请选择执行方式',  
214 - onChange(e) {  
215 - let dataCompareOpions: any = [];  
216 - setFieldsValue({  
217 - startTs: 1000,  
218 - interval: 1000,  
219 - });  
220 - if (e.target.value == 0) {  
221 - setFieldsValue({ queryMode: QueryWay.LATEST });  
222 - dataCompareOpions = [  
223 - { label: '固定周期', value: QueryWay.LATEST },  
224 - { label: '自定义周期', value: QueryWay.TIME_PERIOD },  
225 - ];  
226 - updateSchema({  
227 - field: SchemaFiled.WAY,  
228 - componentProps: {  
229 - options: dataCompareOpions,  
230 - },  
231 - });  
232 - } else {  
233 - setFieldsValue({ queryMode: QueryWay.LATEST });  
234 - setFieldsValue({ startTs: 5000 });  
235 - setFieldsValue({ interval: 1000 });  
236 - dataCompareOpions = [{ label: '固定周期', value: QueryWay.LATEST }];  
237 - updateSchema({  
238 - defaultValue: QueryWay.LATEST,  
239 - field: SchemaFiled.WAY,  
240 - componentProps: {  
241 - options: dataCompareOpions,  
242 - },  
243 - });  
244 - }  
245 - },  
246 - maxLength: 250,  
247 - };  
248 - },  
249 - },  
250 - {  
251 - field: 'cycleType',  
252 - component: 'Select',  
253 - label: '周期',  
254 - required: true,  
255 - colProps: { span: 24 },  
256 - defaultValue: 0,  
257 - componentProps: {  
258 - placeholder: '请选择周期',  
259 - options: [  
260 - { label: '每日', value: 0 },  
261 - { label: '每周', value: 1 },  
262 - { label: '每月', value: 2 },  
263 - ],  
264 - },  
265 - ifShow: ({ values }) => isTiming(values.executeWay),  
266 - },  
267 - {  
268 - field: 'currentCycle',  
269 - component: 'ApiSelect',  
270 - label: '每周',  
271 - required: true,  
272 - colProps: { span: 24 },  
273 - defaultValue: '0 0 0 ? * 1',  
274 - componentProps: {  
275 - placeholder: '请选择周期',  
276 - api: findDictItemByCode,  
277 - params: {  
278 - dictCode: 'every_week',  
279 - },  
280 - labelField: 'itemText',  
281 - valueField: 'itemValue',  
282 - },  
283 - ifShow: ({ values }) => isWeek(values.cycleType),  
284 - },  
285 - {  
286 - field: 'cycleTime',  
287 - component: 'ApiSelect',  
288 - label: '每月',  
289 - required: true,  
290 - colProps: { span: 24 },  
291 - defaultValue: '0 0 0 1 * ? *',  
292 - componentProps: {  
293 - placeholder: '请选择月份',  
294 - api: findDictItemByCode,  
295 - params: {  
296 - dictCode: 'every_month',  
297 - },  
298 - labelField: 'itemText',  
299 - valueField: 'itemValue',  
300 - },  
301 - ifShow: ({ values }) => isMonth(values.cycleType),  
302 - },  
303 - {  
304 - field: 'cronTime',  
305 - component: 'ApiSelect',  
306 - label: '时间',  
307 - required: true,  
308 - colProps: { span: 24 },  
309 - defaultValue: '0 0 0 * * ?',  
310 - componentProps: {  
311 - placeholder: '请选择时间',  
312 - api: findDictItemByCode,  
313 - params: {  
314 - dictCode: 'every_day',  
315 - },  
316 - labelField: 'itemText',  
317 - valueField: 'itemValue',  
318 - },  
319 - ifShow: ({ values }) => isTiming(values.executeWay),  
320 - },  
321 - {  
322 - field: 'devices',  
323 - label: '设备',  
324 - component: 'Select',  
325 - slot: 'devices',  
326 - colProps: { span: 24 },  
327 - },  
328 - {  
329 - field: 'dataType',  
330 - label: '数据类型',  
331 - required: true,  
332 - component: 'Select',  
333 - componentProps: ({ formActionType }) => {  
334 - const { updateSchema, setFieldsValue } = formActionType;  
335 - const options = [  
336 - { label: '原始数据', value: 0 },  
337 - { label: '聚合数据', value: 1 },  
338 - ];  
339 - return {  
340 - options,  
341 - onSelect(e) {  
342 - let dataCompareOpions: any = [];  
343 - if (e == 0) {  
344 - setFieldsValue({ agg: 'NONE' });  
345 - dataCompareOpions = [{ label: '空', value: AggregateDataEnum.NONE }];  
346 - updateSchema({  
347 - field: SchemaFiled.AGG,  
348 - componentProps: {  
349 - options: dataCompareOpions,  
350 - },  
351 - });  
352 - } else {  
353 - setFieldsValue({ agg: '' });  
354 - dataCompareOpions = [  
355 - { label: '最小值', value: AggregateDataEnum.MIN },  
356 - { label: '最大值', value: AggregateDataEnum.MAX },  
357 - { label: '平均值', value: AggregateDataEnum.AVG },  
358 - { label: '求和', value: AggregateDataEnum.SUM },  
359 - { label: '计数', value: AggregateDataEnum.COUNT },  
360 - ];  
361 - updateSchema({  
362 - field: SchemaFiled.AGG,  
363 - componentProps: {  
364 - options: dataCompareOpions,  
365 - },  
366 - });  
367 - }  
368 - },  
369 - maxLength: 250,  
370 - placeholder: '请选择属性性质',  
371 - };  
372 - },  
373 - colProps: { span: 24 },  
374 - },  
375 - {  
376 - field: SchemaFiled.AGG,  
377 - label: '聚合条件',  
378 - component: 'Select',  
379 - required: true,  
380 - componentProps: {  
381 - placeholder: '请选择聚合条件',  
382 - getPopupContainer: () => document.body,  
383 - },  
384 - },  
385 - {  
386 - field: 'limit',  
387 - required: true,  
388 - label: '最大条数',  
389 - component: 'InputNumber',  
390 - defaultValue: 100,  
391 - ifShow({ values }) {  
392 - return values[SchemaFiled.AGG] === AggregateDataEnum.NONE;  
393 - },  
394 - colProps: { span: 12 },  
395 - componentProps: {  
396 - placeholder: '请输入最大条数',  
397 - min: 7,  
398 - max: 50000,  
399 - },  
400 - },  
401 - {  
402 - field: SchemaFiled.WAY,  
403 - label: '查询周期',  
404 - component: 'RadioGroup',  
405 - defaultValue: QueryWay.LATEST,  
406 - required: true,  
407 - componentProps({ formActionType }) {  
408 - const { setFieldsValue } = formActionType;  
409 - return {  
410 - placeholder: '请选择查询周期',  
411 - options: [  
412 - { label: '固定周期', value: QueryWay.LATEST },  
413 - { label: '自定义周期', value: QueryWay.TIME_PERIOD },  
414 - ],  
415 - onChange(value) {  
416 - console.log(value);  
417 - value === QueryWay.LATEST  
418 - ? setFieldsValue({  
419 - [SchemaFiled.DATE_RANGE]: [],  
420 - [SchemaFiled.START_TS]: null,  
421 - [SchemaFiled.END_TS]: null,  
422 - })  
423 - : setFieldsValue({ [SchemaFiled.START_TS]: null });  
424 - },  
425 - };  
426 - },  
427 - },  
428 - {  
429 - field: SchemaFiled.DATE_RANGE,  
430 - label: '时间段',  
431 - component: 'RangePicker',  
432 - required: true,  
433 - ifShow({ values }) {  
434 - return values[SchemaFiled.WAY] === QueryWay.TIME_PERIOD && !isFixedTime(values.executeWay);  
435 - },  
436 - componentProps: {  
437 - showTime: {  
438 - defaultValue: [moment('00:00:00', 'HH:mm:ss'), moment('23:59:59', 'HH:mm:ss')],  
439 - },  
440 - },  
441 - colProps: {  
442 - span: 10,  
443 - },  
444 - },  
445 - {  
446 - field: SchemaFiled.START_TS,  
447 - label: '最近时间',  
448 - component: 'Select',  
449 - required: true,  
450 - ifShow({ values }) {  
451 - return values[SchemaFiled.WAY] == QueryWay.LATEST;  
452 - },  
453 - componentProps({ formActionType }) {  
454 - const { setFieldsValue } = formActionType;  
455 - return {  
456 - defaultValue: 1000,  
457 - placeholder: '请选择近期时间',  
458 - options: intervalOption,  
459 - onChange() {  
460 - setFieldsValue({ [SchemaFiled.INTERVAL]: null });  
461 - },  
462 - };  
463 - },  
464 - },  
465 - {  
466 - field: SchemaFiled.INTERVAL,  
467 - label: '间隔时间',  
468 - component: 'Select',  
469 - required: true,  
470 - ifShow({ values }) {  
471 - return values[SchemaFiled.WAY] == QueryWay.LATEST;  
472 - },  
473 - componentProps({ formModel, formActionType }) {  
474 - const options =  
475 - formModel[SchemaFiled.WAY] === QueryWay.LATEST  
476 - ? getPacketIntervalByValue(formModel[SchemaFiled.START_TS])  
477 - : getPacketIntervalByRange(formModel[SchemaFiled.DATE_RANGE]);  
478 - if (formModel[SchemaFiled.AGG] !== AggregateDataEnum.NONE) {  
479 - formActionType.setFieldsValue({ [SchemaFiled.LIMIT]: null });  
480 - }  
481 - return {  
482 - placeholder: '请选择间隔时间',  
483 - options,  
484 - };  
485 - },  
486 - },  
487 -]; 1 +import { ref } from 'vue';
  2 +import { BasicColumn, FormSchema } from '/@/components/Table';
  3 +import type { FormSchema as QFormSchema } from '/@/components/Form/index';
  4 +import moment from 'moment';
  5 +import { getOrganizationList } from '/@/api/system/system';
  6 +import { copyTransFun } from '/@/utils/fnUtils';
  7 +import { findDictItemByCode } from '/@/api/system/dict';
  8 +import { isTiming, isWeek, isMonth, isFixedTime } from './timeConfig';
  9 +import { AggregateDataEnum } from '../../device/localtion/cpns/TimePeriodForm/config';
  10 +import {
  11 + getPacketIntervalByRange,
  12 + getPacketIntervalByValue,
  13 + intervalOption,
  14 +} from '../../device/localtion/cpns/TimePeriodForm/helper';
  15 +
  16 +export enum QueryWay {
  17 + LATEST = 'latest',
  18 + TIME_PERIOD = 'timePeriod',
  19 +}
  20 +export enum SchemaFiled {
  21 + WAY = 'queryMode',
  22 + TIME_PERIOD = 'timePeriod',
  23 + KEYS = 'keys',
  24 + DATE_RANGE = 'dataRange',
  25 + START_TS = 'startTs',
  26 + END_TS = 'endTs',
  27 + INTERVAL = 'interval',
  28 + LIMIT = 'limit',
  29 + AGG = 'agg',
  30 + ORDER_BY = 'orderBy',
  31 +}
  32 +export const organizationId = ref('');
  33 +
  34 +// 表格配置
  35 +export const columns: BasicColumn[] = [
  36 + {
  37 + title: '配置名称',
  38 + dataIndex: 'name',
  39 + width: 120,
  40 + },
  41 + {
  42 + title: '所属组织',
  43 + dataIndex: 'organizationDTO.name',
  44 + width: 120,
  45 + },
  46 + {
  47 + title: '数据类型',
  48 + dataIndex: 'dataType',
  49 + width: 120,
  50 + format: (_text: string, record: Recordable) => {
  51 + return record.dataType === 0 ? '原始数据' : '聚合数据';
  52 + },
  53 + },
  54 + {
  55 + title: '配置状态',
  56 + dataIndex: 'status',
  57 + width: 120,
  58 + slots: { customRender: 'configStatus' },
  59 + },
  60 + {
  61 + title: '执行方式',
  62 + dataIndex: 'executeWay',
  63 + width: 160,
  64 + format: (_text: string, record: Recordable) => {
  65 + return record.executeWay === 0 ? '立即执行' : '定时执行';
  66 + },
  67 + },
  68 + {
  69 + title: '执行设备',
  70 + dataIndex: 'devices',
  71 + width: 160,
  72 + slots: { customRender: 'doDeviceSlot' },
  73 + },
  74 + {
  75 + title: '创建人',
  76 + dataIndex: 'createUserName',
  77 + width: 180,
  78 + },
  79 + {
  80 + title: '创建时间',
  81 + dataIndex: 'createTime',
  82 + width: 180,
  83 + },
  84 +];
  85 +export const viewDeviceColumn: BasicColumn[] = [
  86 + {
  87 + title: '设备',
  88 + dataIndex: 'device',
  89 + width: 80,
  90 + },
  91 + {
  92 + title: '属性',
  93 + dataIndex: 'attribute',
  94 + width: 120,
  95 + },
  96 +];
  97 +
  98 +// 查询配置
  99 +export const searchFormSchema: FormSchema[] = [
  100 + {
  101 + field: 'name',
  102 + label: '配置名称',
  103 + component: 'Input',
  104 + colProps: { span: 6 },
  105 + componentProps: {
  106 + maxLength: 36,
  107 + placeholder: '请输入配置名称',
  108 + },
  109 + },
  110 + {
  111 + field: 'status',
  112 + label: '配置状态',
  113 + component: 'Select',
  114 + colProps: { span: 6 },
  115 + componentProps: {
  116 + options: [
  117 + {
  118 + label: '启用',
  119 + value: 1,
  120 + },
  121 + {
  122 + label: '禁用',
  123 + value: 0,
  124 + },
  125 + ],
  126 + placeholder: '请选择配置状态',
  127 + },
  128 + },
  129 + {
  130 + field: 'sendTime',
  131 + label: '创建时间',
  132 + component: 'RangePicker',
  133 + componentProps: {
  134 + showTime: {
  135 + defaultValue: [moment('00:00:00', 'HH:mm:ss'), moment('23:59:59', 'HH:mm:ss')],
  136 + },
  137 + },
  138 + colProps: { span: 6 },
  139 + },
  140 +];
  141 +
  142 +// 新增编辑配置
  143 +export const formSchema: QFormSchema[] = [
  144 + {
  145 + field: 'name',
  146 + label: '报表名称',
  147 + colProps: { span: 24 },
  148 + required: true,
  149 + component: 'Input',
  150 + componentProps: {
  151 + maxLength: 64,
  152 + placeholder: '请输入报表名称',
  153 + },
  154 + },
  155 + {
  156 + field: 'organizationId',
  157 + label: '所属组织',
  158 + colProps: { span: 24 },
  159 + component: 'ApiTreeSelect',
  160 + required: true,
  161 + componentProps: () => {
  162 + return {
  163 + maxLength: 250,
  164 + placeholder: '请选择所属组织',
  165 + api: async () => {
  166 + const data = await getOrganizationList();
  167 + copyTransFun(data as any as any[]);
  168 + return data;
  169 + },
  170 + async onChange(e) {
  171 + organizationId.value = e;
  172 + },
  173 + };
  174 + },
  175 + },
  176 + {
  177 + field: 'remark',
  178 + label: '描述',
  179 + colProps: { span: 24 },
  180 + component: 'InputTextArea',
  181 + componentProps: {
  182 + maxLength: 255,
  183 + placeholder: '请输入描述',
  184 + },
  185 + },
  186 + {
  187 + field: 'executeWay',
  188 + component: 'RadioGroup',
  189 + helpMessage: [
  190 + `立即执行,在创建完报表配置后,启用配置即执行。
  191 + 定时执行,用户定义执行时间,启用后,
  192 + 在满足执行时间条件后,自动执行。`,
  193 + ],
  194 + label: '执行方式',
  195 + colProps: {
  196 + span: 24,
  197 + },
  198 + defaultValue: 0,
  199 + componentProps: ({ formActionType }) => {
  200 + const { updateSchema, setFieldsValue } = formActionType;
  201 + const options = [
  202 + {
  203 + label: '立即执行',
  204 + value: 0,
  205 + },
  206 + {
  207 + label: '定时执行',
  208 + value: 1,
  209 + },
  210 + ];
  211 + return {
  212 + options,
  213 + placeholder: '请选择执行方式',
  214 + onChange(e) {
  215 + let dataCompareOpions: any = [];
  216 + setFieldsValue({
  217 + startTs: 1000,
  218 + interval: 1000,
  219 + });
  220 + if (e.target.value == 0) {
  221 + setFieldsValue({ queryMode: QueryWay.LATEST });
  222 + dataCompareOpions = [
  223 + { label: '固定周期', value: QueryWay.LATEST },
  224 + { label: '自定义周期', value: QueryWay.TIME_PERIOD },
  225 + ];
  226 + updateSchema({
  227 + field: SchemaFiled.WAY,
  228 + componentProps: {
  229 + options: dataCompareOpions,
  230 + },
  231 + });
  232 + } else {
  233 + setFieldsValue({ queryMode: QueryWay.LATEST });
  234 + setFieldsValue({ startTs: 5000 });
  235 + setFieldsValue({ interval: 1000 });
  236 + dataCompareOpions = [{ label: '固定周期', value: QueryWay.LATEST }];
  237 + updateSchema({
  238 + defaultValue: QueryWay.LATEST,
  239 + field: SchemaFiled.WAY,
  240 + componentProps: {
  241 + options: dataCompareOpions,
  242 + },
  243 + });
  244 + }
  245 + },
  246 + maxLength: 250,
  247 + };
  248 + },
  249 + },
  250 + {
  251 + field: 'cycleType',
  252 + component: 'Select',
  253 + label: '周期',
  254 + required: true,
  255 + colProps: { span: 24 },
  256 + defaultValue: 0,
  257 + componentProps: {
  258 + placeholder: '请选择周期',
  259 + options: [
  260 + { label: '每日', value: 0 },
  261 + { label: '每周', value: 1 },
  262 + { label: '每月', value: 2 },
  263 + ],
  264 + },
  265 + ifShow: ({ values }) => isTiming(values.executeWay),
  266 + },
  267 + {
  268 + field: 'currentCycle',
  269 + component: 'ApiSelect',
  270 + label: '每周',
  271 + required: true,
  272 + colProps: { span: 24 },
  273 + defaultValue: '0 0 0 ? * MON',
  274 + componentProps: {
  275 + placeholder: '请选择周期',
  276 + api: findDictItemByCode,
  277 + params: {
  278 + dictCode: 'every_week',
  279 + },
  280 + labelField: 'itemText',
  281 + valueField: 'itemValue',
  282 + },
  283 + ifShow: ({ values }) => isWeek(values.cycleType),
  284 + },
  285 + {
  286 + field: 'cycleTime',
  287 + component: 'ApiSelect',
  288 + label: '每月',
  289 + required: true,
  290 + colProps: { span: 24 },
  291 + defaultValue: '0 0 0 1 * ? *',
  292 + componentProps: {
  293 + placeholder: '请选择月份',
  294 + api: findDictItemByCode,
  295 + params: {
  296 + dictCode: 'every_month',
  297 + },
  298 + labelField: 'itemText',
  299 + valueField: 'itemValue',
  300 + },
  301 + ifShow: ({ values }) => isMonth(values.cycleType),
  302 + },
  303 + {
  304 + field: 'cronTime',
  305 + component: 'ApiSelect',
  306 + label: '时间',
  307 + required: true,
  308 + colProps: { span: 24 },
  309 + defaultValue: '0 0 0 * * ?',
  310 + componentProps: {
  311 + placeholder: '请选择时间',
  312 + api: findDictItemByCode,
  313 + params: {
  314 + dictCode: 'every_day',
  315 + },
  316 + labelField: 'itemText',
  317 + valueField: 'itemValue',
  318 + },
  319 + ifShow: ({ values }) => isTiming(values.executeWay),
  320 + },
  321 + {
  322 + field: 'devices',
  323 + label: '设备',
  324 + component: 'Select',
  325 + slot: 'devices',
  326 + colProps: { span: 24 },
  327 + },
  328 + {
  329 + field: 'dataType',
  330 + label: '数据类型',
  331 + required: true,
  332 + component: 'Select',
  333 + componentProps: ({ formActionType }) => {
  334 + const { updateSchema, setFieldsValue } = formActionType;
  335 + const options = [
  336 + { label: '原始数据', value: 0 },
  337 + { label: '聚合数据', value: 1 },
  338 + ];
  339 + return {
  340 + options,
  341 + onSelect(e) {
  342 + let dataCompareOpions: any = [];
  343 + if (e == 0) {
  344 + setFieldsValue({ agg: 'NONE' });
  345 + dataCompareOpions = [{ label: '空', value: AggregateDataEnum.NONE }];
  346 + updateSchema({
  347 + field: SchemaFiled.AGG,
  348 + componentProps: {
  349 + options: dataCompareOpions,
  350 + },
  351 + });
  352 + } else {
  353 + setFieldsValue({ agg: '' });
  354 + dataCompareOpions = [
  355 + { label: '最小值', value: AggregateDataEnum.MIN },
  356 + { label: '最大值', value: AggregateDataEnum.MAX },
  357 + { label: '平均值', value: AggregateDataEnum.AVG },
  358 + { label: '求和', value: AggregateDataEnum.SUM },
  359 + { label: '计数', value: AggregateDataEnum.COUNT },
  360 + ];
  361 + updateSchema({
  362 + field: SchemaFiled.AGG,
  363 + componentProps: {
  364 + options: dataCompareOpions,
  365 + },
  366 + });
  367 + }
  368 + },
  369 + maxLength: 250,
  370 + placeholder: '请选择属性性质',
  371 + };
  372 + },
  373 + colProps: { span: 24 },
  374 + },
  375 + {
  376 + field: SchemaFiled.AGG,
  377 + label: '聚合条件',
  378 + component: 'Select',
  379 + required: true,
  380 + componentProps: {
  381 + placeholder: '请选择聚合条件',
  382 + getPopupContainer: () => document.body,
  383 + },
  384 + },
  385 + {
  386 + field: 'limit',
  387 + required: true,
  388 + label: '最大条数',
  389 + component: 'InputNumber',
  390 + defaultValue: 100,
  391 + ifShow({ values }) {
  392 + return values[SchemaFiled.AGG] === AggregateDataEnum.NONE;
  393 + },
  394 + colProps: { span: 12 },
  395 + componentProps: {
  396 + placeholder: '请输入最大条数',
  397 + min: 7,
  398 + max: 50000,
  399 + },
  400 + },
  401 + {
  402 + field: SchemaFiled.WAY,
  403 + label: '查询周期',
  404 + component: 'RadioGroup',
  405 + defaultValue: QueryWay.LATEST,
  406 + required: true,
  407 + componentProps({ formActionType }) {
  408 + const { setFieldsValue } = formActionType;
  409 + return {
  410 + placeholder: '请选择查询周期',
  411 + options: [
  412 + { label: '固定周期', value: QueryWay.LATEST },
  413 + { label: '自定义周期', value: QueryWay.TIME_PERIOD },
  414 + ],
  415 + onChange(value) {
  416 + console.log(value);
  417 + value === QueryWay.LATEST
  418 + ? setFieldsValue({
  419 + [SchemaFiled.DATE_RANGE]: [],
  420 + [SchemaFiled.START_TS]: null,
  421 + [SchemaFiled.END_TS]: null,
  422 + })
  423 + : setFieldsValue({ [SchemaFiled.START_TS]: null });
  424 + },
  425 + };
  426 + },
  427 + },
  428 + {
  429 + field: SchemaFiled.DATE_RANGE,
  430 + label: '时间段',
  431 + component: 'RangePicker',
  432 + required: true,
  433 + ifShow({ values }) {
  434 + return values[SchemaFiled.WAY] === QueryWay.TIME_PERIOD && !isFixedTime(values.executeWay);
  435 + },
  436 + componentProps: {
  437 + showTime: {
  438 + defaultValue: [moment('00:00:00', 'HH:mm:ss'), moment('23:59:59', 'HH:mm:ss')],
  439 + },
  440 + },
  441 + colProps: {
  442 + span: 10,
  443 + },
  444 + },
  445 + {
  446 + field: SchemaFiled.START_TS,
  447 + label: '最近时间',
  448 + component: 'Select',
  449 + required: true,
  450 + ifShow({ values }) {
  451 + return values[SchemaFiled.WAY] == QueryWay.LATEST;
  452 + },
  453 + componentProps({ formActionType }) {
  454 + const { setFieldsValue } = formActionType;
  455 + return {
  456 + defaultValue: 1000,
  457 + placeholder: '请选择近期时间',
  458 + options: intervalOption,
  459 + onChange() {
  460 + setFieldsValue({ [SchemaFiled.INTERVAL]: null });
  461 + },
  462 + };
  463 + },
  464 + },
  465 + {
  466 + field: SchemaFiled.INTERVAL,
  467 + label: '间隔时间',
  468 + component: 'Select',
  469 + required: true,
  470 + ifShow({ values }) {
  471 + return values[SchemaFiled.WAY] == QueryWay.LATEST;
  472 + },
  473 + componentProps({ formModel, formActionType }) {
  474 + const options =
  475 + formModel[SchemaFiled.WAY] === QueryWay.LATEST
  476 + ? getPacketIntervalByValue(formModel[SchemaFiled.START_TS])
  477 + : getPacketIntervalByRange(formModel[SchemaFiled.DATE_RANGE]);
  478 + if (formModel[SchemaFiled.AGG] !== AggregateDataEnum.NONE) {
  479 + formActionType.setFieldsValue({ [SchemaFiled.LIMIT]: null });
  480 + }
  481 + return {
  482 + placeholder: '请选择间隔时间',
  483 + options,
  484 + };
  485 + },
  486 + },
  487 +];
@@ -41,15 +41,21 @@ @@ -41,15 +41,21 @@
41 import HistoryTrendModal from './components/HistoryTrendModal.vue'; 41 import HistoryTrendModal from './components/HistoryTrendModal.vue';
42 import trendIcon from '/@/assets/svg/trend.svg'; 42 import trendIcon from '/@/assets/svg/trend.svg';
43 import backIcon from '/@/assets/images/back.png'; 43 import backIcon from '/@/assets/images/back.png';
  44 + import backWhiteIcon from '/@/assets/images/backWhite.png';
44 import { useCalcGridLayout } from '../hook/useCalcGridLayout'; 45 import { useCalcGridLayout } from '../hook/useCalcGridLayout';
45 import { FrontComponent } from '../const/const'; 46 import { FrontComponent } from '../const/const';
46 import { useScript } from '/@/hooks/web/useScript'; 47 import { useScript } from '/@/hooks/web/useScript';
47 import { BAI_DU_MAP_GL_LIB, BAI_DU_MAP_TRACK_ANIMATION } from '/@/utils/fnUtils'; 48 import { BAI_DU_MAP_GL_LIB, BAI_DU_MAP_TRACK_ANIMATION } from '/@/utils/fnUtils';
  49 + import { useAppStore } from '/@/store/modules/app';
48 50
49 const props = defineProps<{ 51 const props = defineProps<{
50 value: Recordable; 52 value: Recordable;
51 }>(); 53 }>();
52 54
  55 + const userStore = useAppStore();
  56 +
  57 + const getAceClass = computed((): string => userStore.getDarkMode);
  58 +
53 const ROUTE = useRoute(); 59 const ROUTE = useRoute();
54 60
55 const ROUTER = useRouter(); 61 const ROUTER = useRouter();
@@ -383,7 +389,7 @@ @@ -383,7 +389,7 @@
383 <template #title> 389 <template #title>
384 <div class="flex items-center"> 390 <div class="flex items-center">
385 <img 391 <img
386 - :src="backIcon" 392 + :src="getAceClass === 'dark' ? backWhiteIcon : backIcon"
387 v-if="!getIsSharePage" 393 v-if="!getIsSharePage"
388 class="mr-3 cursor-pointer" 394 class="mr-3 cursor-pointer"
389 @click="handleBack" 395 @click="handleBack"