Commit 9f4289b38bb2ec9b507250d6c930d11dab1e8926

Authored by loveumiko
1 parent a0299143

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

... ... @@ -3,7 +3,7 @@
3 3 import { BasicModal, useModalInner } from '/@/components/Modal';
4 4 import { formSchema, getHistorySearchParams, SchemaFiled } from './history.config';
5 5 import { HistoryModalOkEmitParams } from './type';
6   - import { ref } from 'vue';
  6 + import { ref, unref } from 'vue';
7 7 import { getAllDeviceByOrg } from '/@/api/dataBoard';
8 8 import { getDeviceHistoryInfo } from '/@/api/alarm/position';
9 9 import { DataSource } from '/@/views/visual/palette/types';
... ... @@ -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 102 } catch (error) {
66 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 165 const validEffective = (value = '') => {
71 166 return !!(value && !isNaN(value as unknown as number));
72 167 };
... ... @@ -84,33 +179,9 @@
84 179 ...value,
85 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 185 emit('ok', { track, value } as HistoryModalOkEmitParams);
115 186 closeModal();
116 187 } catch (error) {
... ...
... ... @@ -24,6 +24,14 @@
24 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 36 * @description 经度key
29 37 */
... ... @@ -42,7 +50,7 @@
42 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 54 if (unref(getDeviceId) !== deviceId) return;
47 55
48 56 const { data = {} } = message;
... ... @@ -51,7 +59,7 @@
51 59
52 60 const lngData = bindMessage[unref(getLngKey)] || [];
53 61 const [lngLatest] = lngData;
54   - const [, lng] = lngLatest;
  62 + const [, lng] = lngLatest || [];
55 63
56 64 const latData = bindMessage[unref(getLatKey)] || [];
57 65 const [latLatest] = latData;
... ... @@ -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 102 useMultipleDataFetch(props, updateFn);
66 103
67 104 const { drawLine } = useMapTrackPlayBack(mapInstance);
... ...
... ... @@ -247,7 +247,6 @@ export const commonDataSourceSchemas = (): FormSchema[] => {
247 247 });
248 248 },
249 249 placeholder: '请选择设备',
250   - getPopupContainer: () => document.body,
251 250 ...createPickerSearch(),
252 251 };
253 252 },
... ... @@ -382,11 +381,18 @@ export const commonDataSourceSchemas = (): FormSchema[] => {
382 381 return [];
383 382 },
384 383 placeholder: '请选择属性',
385   - getPopupContainer: () => document.body,
386 384 onChange(value: string, option: Record<'label' | 'value' | any, string>) {
  385 + const { detail }: any = option || {};
387 386 setFieldsValue({
388 387 [DataSourceField.ATTRIBUTE_NAME]: value ? option.label : null,
389 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 398 ...createPickerSearch(),
... ... @@ -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 443 field: DataSourceField.EXTENSION_DESC,
398 444 component: 'Input',
399 445 show: false,
... ...
... ... @@ -29,6 +29,9 @@ export interface DataSource {
29 29 customCommand: CustomCommand;
30 30 videoConfig?: VideoConfigType;
31 31 [key: string]: any;
  32 + lal?: string;
  33 + latitude?: string | number;
  34 + longitude?: string | number;
32 35 }
33 36
34 37 export interface ExtraDataSource extends DataSource, PublicComponentOptions {
... ...