Commit 9f4289b38bb2ec9b507250d6c930d11dab1e8926

Authored by loveumiko
1 parent a0299143

perf: 新增看板组件地图支持结构体获取经纬度

@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 import { BasicModal, useModalInner } from '/@/components/Modal'; 3 import { BasicModal, useModalInner } from '/@/components/Modal';
4 import { formSchema, getHistorySearchParams, SchemaFiled } from './history.config'; 4 import { formSchema, getHistorySearchParams, SchemaFiled } from './history.config';
5 import { HistoryModalOkEmitParams } from './type'; 5 import { HistoryModalOkEmitParams } from './type';
6 - import { ref } from 'vue'; 6 + import { ref, unref } from 'vue';
7 import { getAllDeviceByOrg } from '/@/api/dataBoard'; 7 import { getAllDeviceByOrg } from '/@/api/dataBoard';
8 import { getDeviceHistoryInfo } from '/@/api/alarm/position'; 8 import { getDeviceHistoryInfo } from '/@/api/alarm/position';
9 import { DataSource } from '/@/views/visual/palette/types'; 9 import { DataSource } from '/@/views/visual/palette/types';
@@ -19,54 +19,149 @@ @@ -19,54 +19,149 @@
19 ], 19 ],
20 }); 20 });
21 21
22 - const [registerModal, { closeModal }] = useModalInner(async (dataSource: DataSource[]) => {  
23 - try {  
24 - dataSource = cloneDeep(dataSource);  
25 - if (dataSource.length < 2) return;  
26 - dataSource = dataSource.splice(0, 2);  
27 - const deviceRecord = dataSource?.at(0) || ({} as DataSource);  
28 - if (!deviceRecord.organizationId) return;  
29 - const deviceList = await getAllDeviceByOrg(  
30 - deviceRecord.organizationId,  
31 - deviceRecord.deviceProfileId  
32 - );  
33 - const options = deviceList  
34 - .filter((item) => item.tbDeviceId === deviceRecord.deviceId)  
35 - .map((item) => ({ ...item, label: item.alias || item.name, value: item.tbDeviceId }));  
36 -  
37 - const attKey = dataSource.map((item) => ({  
38 - ...item,  
39 - label: item.attribute,  
40 - value: item.attribute,  
41 - }));  
42 - updateSchema([  
43 - {  
44 - field: SchemaFiled.DEVICE_ID,  
45 - componentProps: {  
46 - options,  
47 - }, 22 + const getTwoMap = async (dataSource) => {
  23 + if (dataSource.length < 2) return;
  24 + dataSource = dataSource.splice(0, 2);
  25 + const deviceRecord = dataSource?.at(0) || ({} as DataSource);
  26 +
  27 + if (!deviceRecord.organizationId) return;
  28 + const deviceList = await getAllDeviceByOrg(
  29 + deviceRecord.organizationId,
  30 + deviceRecord.deviceProfileId
  31 + );
  32 + const options = deviceList
  33 + .filter((item) => item.tbDeviceId === deviceRecord.deviceId)
  34 + .map((item) => ({ ...item, label: item.alias || item.name, value: item.tbDeviceId }));
  35 +
  36 + const attKey = dataSource.map((item) => ({
  37 + ...item,
  38 + label: item.attribute,
  39 + value: item.attribute,
  40 + }));
  41 +
  42 + updateSchemaMap(options, attKey, deviceRecord);
  43 + };
  44 +
  45 + const getOneMap = async (dataSource) => {
  46 + const deviceRecord = dataSource?.[0];
  47 + if (!deviceRecord.organizationId) return;
  48 + const deviceList = await getAllDeviceByOrg(
  49 + deviceRecord.organizationId,
  50 + deviceRecord.deviceProfileId
  51 + );
  52 + const options = deviceList
  53 + .filter((item) => item.tbDeviceId === deviceRecord.deviceId)
  54 + .map((item) => ({ ...item, label: item.alias || item.name, value: item.tbDeviceId }));
  55 +
  56 + const attKey = dataSource?.map((item) => ({
  57 + ...item,
  58 + label: item.attributeName,
  59 + value: item.attribute,
  60 + }));
  61 + updateSchemaMap(options, attKey, deviceRecord);
  62 + };
  63 +
  64 + const updateSchemaMap = (options, attKey, deviceRecord) => {
  65 + updateSchema([
  66 + {
  67 + field: SchemaFiled.DEVICE_ID,
  68 + componentProps: {
  69 + options,
48 }, 70 },
49 - {  
50 - field: SchemaFiled.KEYS,  
51 - component: 'Select',  
52 - defaultValue: attKey.map((item) => item.value),  
53 - componentProps: {  
54 - options: attKey,  
55 - mode: 'multiple',  
56 - disabled: true,  
57 - }, 71 + },
  72 + {
  73 + field: SchemaFiled.KEYS,
  74 + component: 'Select',
  75 + defaultValue: attKey.map((item) => item.value),
  76 + componentProps: {
  77 + options: attKey,
  78 + mode: 'multiple',
  79 + disabled: true,
58 }, 80 },
59 - ]); 81 + },
  82 + ]);
60 83
61 - setFieldsValue({  
62 - [SchemaFiled.DEVICE_ID]: deviceRecord.deviceId,  
63 - [SchemaFiled.KEYS]: attKey.map((item) => item.value),  
64 - }); 84 + setFieldsValue({
  85 + [SchemaFiled.DEVICE_ID]: deviceRecord.deviceId,
  86 + [SchemaFiled.KEYS]: attKey.map((item) => item.value),
  87 + });
  88 + };
  89 +
  90 + const getDesign = ref();
  91 +
  92 + const [registerModal, { closeModal }] = useModalInner(async (dataSource: DataSource[]) => {
  93 + try {
  94 + getDesign.value = dataSource;
  95 + dataSource = cloneDeep(dataSource);
  96 + //判断选择是不是结构体
  97 + if (dataSource.length == 1 && dataSource?.[0]?.lal) {
  98 + getOneMap(dataSource);
  99 + return;
  100 + }
  101 + getTwoMap(dataSource);
65 } catch (error) { 102 } catch (error) {
66 throw error; 103 throw error;
67 } 104 }
68 }); 105 });
69 106
  107 + const getMultipleDataSource = async (res) => {
  108 + let timespanList = Object.keys(res).reduce((prev, next) => {
  109 + const ts = res[next].map((item) => item.ts);
  110 + return [...prev, ...ts];
  111 + }, [] as number[]);
  112 + timespanList = [...new Set(timespanList)];
  113 +
  114 + const track: Record<'lng' | 'lat', number>[] = [];
  115 + const keys = Object.keys(res);
  116 +
  117 + for (const ts of timespanList) {
  118 + const list: { ts: number; value: number }[] = [];
  119 + for (const key of keys) {
  120 + const record = res[key].find((item) => ts === item.ts);
  121 + if (!validEffective(record?.value)) {
  122 + continue;
  123 + }
  124 + list.push(record as any);
  125 + }
  126 +
  127 + if (list.length === 2 && list.every(Boolean)) {
  128 + const lng = list.at(0)?.value;
  129 + const lat = list.at(1)?.value;
  130 + if (lng && lat) track.push({ lng, lat });
  131 + }
  132 + }
  133 + return track;
  134 + };
  135 +
  136 + const getSingleDataSource = async (res) => {
  137 + const [keys] = Object.keys(res);
  138 + const track: Record<'lng' | 'lat', number>[] = [];
  139 + const dataSource = res[keys]?.map((item) => {
  140 + return {
  141 + value: item.value ? JSON.parse(item.value) : {},
  142 + };
  143 + });
  144 + const list: { value: number }[] = [];
  145 + dataSource?.forEach((item) => {
  146 + if (
  147 + //判断结构体得值是不是数字
  148 + Object.values(item.value).every((item1) => {
  149 + return validEffective(item1 as any);
  150 + })
  151 + ) {
  152 + list.push(item.value);
  153 + }
  154 + });
  155 + const { latitude, longitude } = unref(getDesign)?.[0]; //获取选择得经纬度选项
  156 +
  157 + list.forEach((item) => {
  158 + const lng = item[longitude];
  159 + const lat = item[latitude];
  160 + if (lng && lat) track.push({ lng, lat });
  161 + });
  162 + return track;
  163 + };
  164 +
70 const validEffective = (value = '') => { 165 const validEffective = (value = '') => {
71 return !!(value && !isNaN(value as unknown as number)); 166 return !!(value && !isNaN(value as unknown as number));
72 }; 167 };
@@ -84,33 +179,9 @@ @@ -84,33 +179,9 @@
84 ...value, 179 ...value,
85 [SchemaFiled.KEYS]: value[SchemaFiled.KEYS].join(','), 180 [SchemaFiled.KEYS]: value[SchemaFiled.KEYS].join(','),
86 }); 181 });
  182 + const ifSingle = unref(getDesign).length === 1 && unref(getDesign)?.[0]?.lal;
87 183
88 - let timespanList = Object.keys(res).reduce((prev, next) => {  
89 - const ts = res[next].map((item) => item.ts);  
90 - return [...prev, ...ts];  
91 - }, [] as number[]);  
92 - timespanList = [...new Set(timespanList)];  
93 -  
94 - const track: Record<'lng' | 'lat', number>[] = [];  
95 - const keys = Object.keys(res);  
96 -  
97 - for (const ts of timespanList) {  
98 - const list: { ts: number; value: number }[] = [];  
99 - for (const key of keys) {  
100 - const record = res[key].find((item) => ts === item.ts);  
101 - if (!validEffective(record?.value)) {  
102 - continue;  
103 - }  
104 - list.push(record as any);  
105 - }  
106 -  
107 - if (list.length === 2 && list.every(Boolean)) {  
108 - const lng = list.at(0)?.value;  
109 - const lat = list.at(1)?.value;  
110 - if (lng && lat) track.push({ lng, lat });  
111 - }  
112 - }  
113 - 184 + const track = ifSingle ? await getSingleDataSource(res) : await getMultipleDataSource(res);
114 emit('ok', { track, value } as HistoryModalOkEmitParams); 185 emit('ok', { track, value } as HistoryModalOkEmitParams);
115 closeModal(); 186 closeModal();
116 } catch (error) { 187 } catch (error) {
@@ -24,6 +24,14 @@ @@ -24,6 +24,14 @@
24 return props.config.option.dataSource?.at(0)?.deviceId; 24 return props.config.option.dataSource?.at(0)?.deviceId;
25 }); 25 });
26 26
  27 + const getDesign = computed(() => {
  28 + const { option } = props.config;
  29 + const { dataSource } = option || {};
  30 + return {
  31 + dataSource: dataSource,
  32 + };
  33 + });
  34 +
27 /** 35 /**
28 * @description 经度key 36 * @description 经度key
29 */ 37 */
@@ -42,7 +50,7 @@ @@ -42,7 +50,7 @@
42 return !!(value && !isNaN(value as unknown as number)); 50 return !!(value && !isNaN(value as unknown as number));
43 }; 51 };
44 52
45 - const updateFn: MultipleDataFetchUpdateFn = (message, deviceId) => { 53 + const getTwoMap = (message, deviceId) => {
46 if (unref(getDeviceId) !== deviceId) return; 54 if (unref(getDeviceId) !== deviceId) return;
47 55
48 const { data = {} } = message; 56 const { data = {} } = message;
@@ -51,7 +59,7 @@ @@ -51,7 +59,7 @@
51 59
52 const lngData = bindMessage[unref(getLngKey)] || []; 60 const lngData = bindMessage[unref(getLngKey)] || [];
53 const [lngLatest] = lngData; 61 const [lngLatest] = lngData;
54 - const [, lng] = lngLatest; 62 + const [, lng] = lngLatest || [];
55 63
56 const latData = bindMessage[unref(getLatKey)] || []; 64 const latData = bindMessage[unref(getLatKey)] || [];
57 const [latLatest] = latData; 65 const [latLatest] = latData;
@@ -62,6 +70,35 @@ @@ -62,6 +70,35 @@
62 } 70 }
63 }; 71 };
64 72
  73 + const getOneMap = (message, deviceId) => {
  74 + if (unref(getDeviceId) !== deviceId) return;
  75 +
  76 + const { longitude, latitude, attribute } = unref(getDesign)?.dataSource?.[0] || {};
  77 + const { data } = message || {};
  78 + const bindMessage = data[deviceId];
  79 + const [, values] = attribute && bindMessage?.[attribute][0];
  80 +
  81 + const mapValues = values ? JSON.parse(values) : [];
  82 + const lng = longitude && mapValues[longitude];
  83 + const lat = latitude && mapValues[latitude];
  84 +
  85 + if (validEffective(lng) && validEffective(lat)) {
  86 + drawLine({ lng: Number(lng), lat: Number(lat) });
  87 + }
  88 + };
  89 +
  90 + const updateFn: MultipleDataFetchUpdateFn = (message, deviceId) => {
  91 + const { lal } = unref(getDesign)?.dataSource?.[0] || {};
  92 +
  93 + // 属性选择结构体时
  94 + if (lal) {
  95 + getOneMap(message, deviceId);
  96 + return;
  97 + }
  98 + // 选择两个属性时
  99 + getTwoMap(message, deviceId);
  100 + };
  101 +
65 useMultipleDataFetch(props, updateFn); 102 useMultipleDataFetch(props, updateFn);
66 103
67 const { drawLine } = useMapTrackPlayBack(mapInstance); 104 const { drawLine } = useMapTrackPlayBack(mapInstance);
@@ -247,7 +247,6 @@ export const commonDataSourceSchemas = (): FormSchema[] => { @@ -247,7 +247,6 @@ export const commonDataSourceSchemas = (): FormSchema[] => {
247 }); 247 });
248 }, 248 },
249 placeholder: '请选择设备', 249 placeholder: '请选择设备',
250 - getPopupContainer: () => document.body,  
251 ...createPickerSearch(), 250 ...createPickerSearch(),
252 }; 251 };
253 }, 252 },
@@ -382,11 +381,18 @@ export const commonDataSourceSchemas = (): FormSchema[] => { @@ -382,11 +381,18 @@ export const commonDataSourceSchemas = (): FormSchema[] => {
382 return []; 381 return [];
383 }, 382 },
384 placeholder: '请选择属性', 383 placeholder: '请选择属性',
385 - getPopupContainer: () => document.body,  
386 onChange(value: string, option: Record<'label' | 'value' | any, string>) { 384 onChange(value: string, option: Record<'label' | 'value' | any, string>) {
  385 + const { detail }: any = option || {};
387 setFieldsValue({ 386 setFieldsValue({
388 [DataSourceField.ATTRIBUTE_NAME]: value ? option.label : null, 387 [DataSourceField.ATTRIBUTE_NAME]: value ? option.label : null,
389 [DataSourceField.EXTENSION_DESC]: value ? JSON.stringify(option.extensionDesc) : '', 388 [DataSourceField.EXTENSION_DESC]: value ? JSON.stringify(option.extensionDesc) : '',
  389 + // 地图组件结构体
  390 + lal:
  391 + category === 'MAP' && value && detail?.dataType.type === 'STRUCT'
  392 + ? JSON.stringify(detail?.dataType.specs)
  393 + : null,
  394 + latitude: null,
  395 + longitude: null,
390 }); 396 });
391 }, 397 },
392 ...createPickerSearch(), 398 ...createPickerSearch(),
@@ -394,6 +400,46 @@ export const commonDataSourceSchemas = (): FormSchema[] => { @@ -394,6 +400,46 @@ export const commonDataSourceSchemas = (): FormSchema[] => {
394 }, 400 },
395 }, 401 },
396 { 402 {
  403 + field: 'lal',
  404 + label: '经纬度存储的值',
  405 + component: 'Input',
  406 + show: false,
  407 + },
  408 + {
  409 + field: 'longitude',
  410 + label: '经度',
  411 + colProps: { span: 8 },
  412 + component: 'Select',
  413 + required: true,
  414 + ifShow: ({ model }) => category === 'MAP' && model.lal,
  415 + componentProps({ formModel }) {
  416 + const { lal } = formModel || {};
  417 + return {
  418 + placeholder: '请选择经度',
  419 + options: lal
  420 + ? JSON.parse(lal)?.map((item) => ({ label: item.functionName, value: item.identifier }))
  421 + : [],
  422 + };
  423 + },
  424 + },
  425 + {
  426 + field: 'latitude',
  427 + label: '纬度',
  428 + colProps: { span: 8 },
  429 + required: true,
  430 + component: 'Select',
  431 + ifShow: ({ model }) => category === 'MAP' && model.lal,
  432 + componentProps({ formModel }) {
  433 + const { lal } = formModel || {};
  434 + return {
  435 + placeholder: '请选择纬度',
  436 + options: lal
  437 + ? JSON.parse(lal)?.map((item) => ({ label: item.functionName, value: item.identifier }))
  438 + : [],
  439 + };
  440 + },
  441 + },
  442 + {
397 field: DataSourceField.EXTENSION_DESC, 443 field: DataSourceField.EXTENSION_DESC,
398 component: 'Input', 444 component: 'Input',
399 show: false, 445 show: false,
@@ -29,6 +29,9 @@ export interface DataSource { @@ -29,6 +29,9 @@ export interface DataSource {
29 customCommand: CustomCommand; 29 customCommand: CustomCommand;
30 videoConfig?: VideoConfigType; 30 videoConfig?: VideoConfigType;
31 [key: string]: any; 31 [key: string]: any;
  32 + lal?: string;
  33 + latitude?: string | number;
  34 + longitude?: string | number;
32 } 35 }
33 36
34 export interface ExtraDataSource extends DataSource, PublicComponentOptions { 37 export interface ExtraDataSource extends DataSource, PublicComponentOptions {