Commit ec6d323d158bcdc79dd035ad15baf162a17e47ae
Merge branch 'ww' into 'main'
fix: DEFECT-963 create data component fetch api happend error See merge request huang/yun-teng-iot-front!424
Showing
12 changed files
with
198 additions
and
94 deletions
@@ -44,6 +44,7 @@ enum DeviceUrl { | @@ -44,6 +44,7 @@ enum DeviceUrl { | ||
44 | GET_SLAVE_DEVICE = '/device/list/slave', | 44 | GET_SLAVE_DEVICE = '/device/list/slave', |
45 | GET_DEVICE_ATTRIBUTE = '/device/attributes', | 45 | GET_DEVICE_ATTRIBUTE = '/device/attributes', |
46 | GET_DEVICE = '/device/list', | 46 | GET_DEVICE = '/device/list', |
47 | + GET_DEVICE_RELATION = '/device/device/relation', | ||
47 | } | 48 | } |
48 | 49 | ||
49 | /** | 50 | /** |
@@ -224,3 +225,10 @@ export const sendCommandOneway = (params: SendCommandParams) => { | @@ -224,3 +225,10 @@ export const sendCommandOneway = (params: SendCommandParams) => { | ||
224 | { joinPrefix: false } | 225 | { joinPrefix: false } |
225 | ); | 226 | ); |
226 | }; | 227 | }; |
228 | + | ||
229 | +export const getDeviceRelation = (params: { deviceId: string; isSlave: boolean }) => { | ||
230 | + return defHttp.get<string>({ | ||
231 | + url: DeviceUrl.GET_DEVICE_RELATION, | ||
232 | + params, | ||
233 | + }); | ||
234 | +}; |
1 | import { RadioRecord } from '../../../views/visual/board/detail/config/util'; | 1 | import { RadioRecord } from '../../../views/visual/board/detail/config/util'; |
2 | +import { DeviceTypeEnum } from '../../device/model/deviceModel'; | ||
2 | 3 | ||
3 | export interface AddDataBoardParams { | 4 | export interface AddDataBoardParams { |
4 | name: string; | 5 | name: string; |
@@ -79,12 +80,14 @@ export interface DataSource { | @@ -79,12 +80,14 @@ export interface DataSource { | ||
79 | componentInfo: ComponentInfo; | 80 | componentInfo: ComponentInfo; |
80 | deviceName: string; | 81 | deviceName: string; |
81 | deviceProfileId: string; | 82 | deviceProfileId: string; |
83 | + tbDeviceId: string; | ||
82 | 84 | ||
83 | // front usage | 85 | // front usage |
84 | uuid?: string; | 86 | uuid?: string; |
85 | width?: number; | 87 | width?: number; |
86 | height?: number; | 88 | height?: number; |
87 | radio?: RadioRecord; | 89 | radio?: RadioRecord; |
90 | + deviceType?: DeviceTypeEnum; | ||
88 | } | 91 | } |
89 | 92 | ||
90 | export interface DataComponentRecord { | 93 | export interface DataComponentRecord { |
@@ -163,7 +163,7 @@ | @@ -163,7 +163,7 @@ | ||
163 | <template> | 163 | <template> |
164 | <PageWrapper dense contentFullHeight contentClass="flex"> | 164 | <PageWrapper dense contentFullHeight contentClass="flex"> |
165 | <OrganizationIdTree @select="handleSelect" ref="organizationIdTreeRef" /> | 165 | <OrganizationIdTree @select="handleSelect" ref="organizationIdTreeRef" /> |
166 | - <section class="flex-auto p-4 configuration-list"> | 166 | + <section class="flex-auto p-4 w-full configuration-list"> |
167 | <div class="flex-auto w-full bg-light-50 dark:bg-dark-900 p-4"> | 167 | <div class="flex-auto w-full bg-light-50 dark:bg-dark-900 p-4"> |
168 | <BasicForm @register="registerForm" /> | 168 | <BasicForm @register="registerForm" /> |
169 | </div> | 169 | </div> |
@@ -248,7 +248,10 @@ | @@ -248,7 +248,10 @@ | ||
248 | <EllipsisOutlined key="ellipsis" /> | 248 | <EllipsisOutlined key="ellipsis" /> |
249 | </Dropdown> | 249 | </Dropdown> |
250 | </template> | 250 | </template> |
251 | - <Card.Meta :title="item.name"> | 251 | + <Card.Meta> |
252 | + <template #title> | ||
253 | + <span class="truncate">{{ item.name }}</span> | ||
254 | + </template> | ||
252 | <template #description> | 255 | <template #description> |
253 | <div class="truncate h-11"> | 256 | <div class="truncate h-11"> |
254 | <div class="truncate">{{ item.organizationDTO.name }}</div> | 257 | <div class="truncate">{{ item.organizationDTO.name }}</div> |
@@ -13,12 +13,6 @@ | @@ -13,12 +13,6 @@ | ||
13 | <Tabs.TabPane :key="FunctionType.SERVICE" tab="服务" /> | 13 | <Tabs.TabPane :key="FunctionType.SERVICE" tab="服务" /> |
14 | <!-- <Tabs.TabPane :key="FunctionType.EVENTS" tab="事件" /> --> | 14 | <!-- <Tabs.TabPane :key="FunctionType.EVENTS" tab="事件" /> --> |
15 | <template #tabBarExtraContent> | 15 | <template #tabBarExtraContent> |
16 | - <Button @click="handlePremitter"> | ||
17 | - <template #icon> | ||
18 | - <SortAscendingOutlined /> | ||
19 | - </template> | ||
20 | - 格式化 | ||
21 | - </Button> | ||
22 | <Button class="ml-2" @click="handleCopy"> | 16 | <Button class="ml-2" @click="handleCopy"> |
23 | <template #icon> | 17 | <template #icon> |
24 | <CopyOutlined /> | 18 | <CopyOutlined /> |
@@ -30,24 +24,21 @@ | @@ -30,24 +24,21 @@ | ||
30 | </div> | 24 | </div> |
31 | <div class="relative"> | 25 | <div class="relative"> |
32 | <Spin :spinning="loading"> | 26 | <Spin :spinning="loading"> |
33 | - <div id="jsoneditor" ref="jsoneditorEl"></div> | ||
34 | - <div class="absolute top-0 left-0 w-full h-full"></div> | 27 | + <Textarea :disabled="true" :auto-size="{ minRows: 20, maxRows: 20 }" :value="jsonValue" /> |
35 | </Spin> | 28 | </Spin> |
36 | </div> | 29 | </div> |
37 | </div> | 30 | </div> |
38 | </template> | 31 | </template> |
39 | <script lang="ts" setup> | 32 | <script lang="ts" setup> |
40 | - import { ref, unref, onMounted, nextTick } from 'vue'; | ||
41 | - import { CopyOutlined, SortAscendingOutlined } from '@ant-design/icons-vue'; | ||
42 | - import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard'; | 33 | + import { ref, unref, onMounted } from 'vue'; |
34 | + import { CopyOutlined } from '@ant-design/icons-vue'; | ||
43 | import { useMessage } from '/@/hooks/web/useMessage'; | 35 | import { useMessage } from '/@/hooks/web/useMessage'; |
44 | - import jsoneditor from 'jsoneditor'; | ||
45 | - import 'jsoneditor/dist/jsoneditor.min.css'; | ||
46 | - import { Button, Typography, TypographyParagraph, Tabs, Spin } from 'ant-design-vue'; | 36 | + import { Button, Typography, TypographyParagraph, Tabs, Spin, Textarea } from 'ant-design-vue'; |
47 | import { FunctionType } from './config'; | 37 | import { FunctionType } from './config'; |
48 | import useCommon from '../hook/useCommon'; | 38 | import useCommon from '../hook/useCommon'; |
49 | import { DeviceRecord } from '/@/api/device/model/deviceModel'; | 39 | import { DeviceRecord } from '/@/api/device/model/deviceModel'; |
50 | import { getModelTsl } from '/@/api/device/modelOfMatter'; | 40 | import { getModelTsl } from '/@/api/device/modelOfMatter'; |
41 | + import { useClipboard } from '@vueuse/core'; | ||
51 | 42 | ||
52 | const props = defineProps<{ | 43 | const props = defineProps<{ |
53 | record: DeviceRecord; | 44 | record: DeviceRecord; |
@@ -61,40 +52,17 @@ | @@ -61,40 +52,17 @@ | ||
61 | 52 | ||
62 | const jsonValue = ref(); | 53 | const jsonValue = ref(); |
63 | 54 | ||
64 | - const jsonInstance = ref<{ | ||
65 | - set: (value?: Recordable) => void; | ||
66 | - get: () => Recordable; | ||
67 | - }>(); | ||
68 | - | ||
69 | - const jsoneditorEl = ref<HTMLDivElement>(); | ||
70 | - | ||
71 | const activeKey = ref(FunctionType.PROPERTIES); | 55 | const activeKey = ref(FunctionType.PROPERTIES); |
72 | 56 | ||
73 | - onMounted(() => { | ||
74 | - nextTick(() => { | ||
75 | - let options = { | ||
76 | - mode: 'code', | ||
77 | - mainMenuBar: false, | ||
78 | - statusBar: false, | ||
79 | - }; | ||
80 | - let editor = new jsoneditor(jsoneditorEl.value, options); | ||
81 | - editor.set(jsonValue.value); | ||
82 | - jsonInstance.value = editor; | ||
83 | - }); | ||
84 | - }); | ||
85 | - | ||
86 | - const { clipboardRef, copiedRef } = useCopyToClipboard(); | ||
87 | - | 57 | + const { copy, isSupported } = useClipboard({ source: jsonValue }); |
88 | const handleCopy = () => { | 58 | const handleCopy = () => { |
89 | try { | 59 | try { |
90 | - const valueRef = unref(jsonInstance)?.get(); | ||
91 | - const value = JSON.stringify(unref(valueRef)); | ||
92 | - if (!value) { | 60 | + if (!jsonValue.value) { |
93 | createMessage.warning('请输入要拷贝的内容!'); | 61 | createMessage.warning('请输入要拷贝的内容!'); |
94 | return; | 62 | return; |
95 | } | 63 | } |
96 | - clipboardRef.value = value; | ||
97 | - if (unref(copiedRef)) { | 64 | + if (unref(isSupported)) { |
65 | + copy(); | ||
98 | createMessage.success('复制成功!'); | 66 | createMessage.success('复制成功!'); |
99 | } | 67 | } |
100 | } catch (e) { | 68 | } catch (e) { |
@@ -103,25 +71,18 @@ | @@ -103,25 +71,18 @@ | ||
103 | }; | 71 | }; |
104 | 72 | ||
105 | const getFormData = () => { | 73 | const getFormData = () => { |
106 | - const value = unref(jsonInstance)?.get(); | ||
107 | - if (!value) return; | ||
108 | - return value; | 74 | + return JSON.parse(jsonValue.value); |
109 | }; | 75 | }; |
110 | 76 | ||
111 | const resetFormData = () => { | 77 | const resetFormData = () => { |
112 | - unref(jsonInstance)?.set(); | ||
113 | - }; | ||
114 | - | ||
115 | - const handlePremitter = () => { | ||
116 | - const value = unref(jsonInstance)?.get(); | ||
117 | - return unref(jsonInstance)?.set(value); | 78 | + jsonValue.value = null; |
118 | }; | 79 | }; |
119 | 80 | ||
120 | const handleSwitchTsl = async (functionType: FunctionType) => { | 81 | const handleSwitchTsl = async (functionType: FunctionType) => { |
121 | try { | 82 | try { |
122 | loading.value = true; | 83 | loading.value = true; |
123 | const record = await getModelTsl({ deviceProfileId: props.record.id, functionType }); | 84 | const record = await getModelTsl({ deviceProfileId: props.record.id, functionType }); |
124 | - jsonInstance.value?.set(record); | 85 | + jsonValue.value = JSON.stringify(record, null, 2); |
125 | } catch (error) { | 86 | } catch (error) { |
126 | } finally { | 87 | } finally { |
127 | loading.value = false; | 88 | loading.value = false; |
@@ -138,10 +99,3 @@ | @@ -138,10 +99,3 @@ | ||
138 | resetFormData, | 99 | resetFormData, |
139 | }); | 100 | }); |
140 | </script> | 101 | </script> |
141 | - | ||
142 | -<style lang="less" scope> | ||
143 | - #jsoneditor { | ||
144 | - width: 100%; | ||
145 | - height: 450px; | ||
146 | - } | ||
147 | -</style> |
@@ -41,9 +41,9 @@ | @@ -41,9 +41,9 @@ | ||
41 | > | 41 | > |
42 | <label class="switch"> | 42 | <label class="switch"> |
43 | <input | 43 | <input |
44 | - :value="props.value?.value" | 44 | + :value="!!props.value?.value" |
45 | type="checkbox" | 45 | type="checkbox" |
46 | - :checked="props.value?.value" | 46 | + :checked="!!props.value?.value" |
47 | @change="handleChange" | 47 | @change="handleChange" |
48 | /> | 48 | /> |
49 | <div class="button"> | 49 | <div class="button"> |
1 | import { DataComponentRecord, DataSource } from '/@/api/dataBoard/model'; | 1 | import { DataComponentRecord, DataSource } from '/@/api/dataBoard/model'; |
2 | +import { DeviceTypeEnum } from '/@/api/device/model/deviceModel'; | ||
2 | 3 | ||
3 | export interface ControlComponentLayout { | 4 | export interface ControlComponentLayout { |
4 | [key: string]: any; | 5 | [key: string]: any; |
@@ -14,6 +15,8 @@ export interface ControlComponentValue { | @@ -14,6 +15,8 @@ export interface ControlComponentValue { | ||
14 | fontColor?: string; | 15 | fontColor?: string; |
15 | slaveDeviceId?: string; | 16 | slaveDeviceId?: string; |
16 | deviceProfileId?: string; | 17 | deviceProfileId?: string; |
18 | + deviceType?: DeviceTypeEnum; | ||
19 | + organizationId?: string; | ||
17 | } | 20 | } |
18 | 21 | ||
19 | export const ControlComponentDefaultConfig: ControlComponentValue = { | 22 | export const ControlComponentDefaultConfig: ControlComponentValue = { |
@@ -34,7 +37,9 @@ export const transformControlConfig = ( | @@ -34,7 +37,9 @@ export const transformControlConfig = ( | ||
34 | attributeRename: dataSourceRecord.attributeRename, | 37 | attributeRename: dataSourceRecord.attributeRename, |
35 | deviceProfileId: dataSourceRecord.deviceProfileId, | 38 | deviceProfileId: dataSourceRecord.deviceProfileId, |
36 | deviceId: dataSourceRecord.deviceId, | 39 | deviceId: dataSourceRecord.deviceId, |
40 | + deviceType: dataSourceRecord.deviceType, | ||
37 | slaveDeviceId: dataSourceRecord.slaveDeviceId, | 41 | slaveDeviceId: dataSourceRecord.slaveDeviceId, |
42 | + organizationId: dataSourceRecord.organizationId, | ||
38 | } as ControlComponentValue, | 43 | } as ControlComponentValue, |
39 | }; | 44 | }; |
40 | }; | 45 | }; |
1 | import { ControlComponentValue } from './control.config'; | 1 | import { ControlComponentValue } from './control.config'; |
2 | import { getDeviceProfile } from '/@/api/alarm/position'; | 2 | import { getDeviceProfile } from '/@/api/alarm/position'; |
3 | -import { sendCommandOneway } from '/@/api/dataBoard'; | 3 | +import { getDeviceRelation, sendCommandOneway } from '/@/api/dataBoard'; |
4 | +import { DeviceTypeEnum } from '/@/api/device/model/deviceModel'; | ||
4 | import { getModelServices } from '/@/api/device/modelOfMatter'; | 5 | import { getModelServices } from '/@/api/device/modelOfMatter'; |
5 | import { useMessage } from '/@/hooks/web/useMessage'; | 6 | import { useMessage } from '/@/hooks/web/useMessage'; |
6 | import { isString } from '/@/utils/is'; | 7 | import { isString } from '/@/utils/is'; |
@@ -8,7 +9,9 @@ import { isString } from '/@/utils/is'; | @@ -8,7 +9,9 @@ import { isString } from '/@/utils/is'; | ||
8 | const { createMessage } = useMessage(); | 9 | const { createMessage } = useMessage(); |
9 | export function useSendCommand() { | 10 | export function useSendCommand() { |
10 | const sendCommand = async (record: ControlComponentValue, value: any) => { | 11 | const sendCommand = async (record: ControlComponentValue, value: any) => { |
11 | - const { deviceId, deviceProfileId, attribute } = record; | 12 | + if (!record) return; |
13 | + const { deviceProfileId, attribute, deviceType } = record; | ||
14 | + let { deviceId } = record; | ||
12 | if (!deviceId) return; | 15 | if (!deviceId) return; |
13 | try { | 16 | try { |
14 | const list = await getDeviceProfile(); | 17 | const list = await getDeviceProfile(); |
@@ -23,6 +26,12 @@ export function useSendCommand() { | @@ -23,6 +26,12 @@ export function useSendCommand() { | ||
23 | const sendCommand = record?.functionJson.inputData?.at(0)?.serviceCommand || ''; | 26 | const sendCommand = record?.functionJson.inputData?.at(0)?.serviceCommand || ''; |
24 | params = isString(sendCommand) ? sendCommand : JSON.stringify(sendCommand); | 27 | params = isString(sendCommand) ? sendCommand : JSON.stringify(sendCommand); |
25 | } | 28 | } |
29 | + if (deviceType === DeviceTypeEnum.SENSOR) { | ||
30 | + deviceId = await getDeviceRelation({ | ||
31 | + deviceId, | ||
32 | + isSlave: deviceType === DeviceTypeEnum.SENSOR, | ||
33 | + }); | ||
34 | + } | ||
26 | await sendCommandOneway({ | 35 | await sendCommandOneway({ |
27 | deviceId, | 36 | deviceId, |
28 | value: { | 37 | value: { |
@@ -27,15 +27,19 @@ | @@ -27,15 +27,19 @@ | ||
27 | const { dataSource = [] } = params; | 27 | const { dataSource = [] } = params; |
28 | const deviceRecord = dataSource?.at(0) || ({} as DataSource); | 28 | const deviceRecord = dataSource?.at(0) || ({} as DataSource); |
29 | if (!deviceRecord.organizationId) return; | 29 | if (!deviceRecord.organizationId) return; |
30 | - const deviceList = await getAllDeviceByOrg(deviceRecord.organizationId); | 30 | + const deviceList = await getAllDeviceByOrg( |
31 | + deviceRecord.organizationId, | ||
32 | + deviceRecord.deviceProfileId | ||
33 | + ); | ||
31 | const options = deviceList | 34 | const options = deviceList |
32 | - .filter((item) => item.id === deviceRecord.deviceId) | ||
33 | - .map((item) => ({ ...item, label: item.name, value: item.id })); | 35 | + .filter((item) => item.tbDeviceId === deviceRecord.deviceId) |
36 | + .map((item) => ({ ...item, label: item.name, value: item.tbDeviceId })); | ||
34 | const attKey = dataSource.map((item) => ({ | 37 | const attKey = dataSource.map((item) => ({ |
35 | ...item, | 38 | ...item, |
36 | label: item.attribute, | 39 | label: item.attribute, |
37 | value: item.attribute, | 40 | value: item.attribute, |
38 | })); | 41 | })); |
42 | + console.log(options); | ||
39 | updateSchema([ | 43 | updateSchema([ |
40 | { | 44 | { |
41 | field: SchemaFiled.DEVICE_ID, | 45 | field: SchemaFiled.DEVICE_ID, |
@@ -22,6 +22,7 @@ | @@ -22,6 +22,7 @@ | ||
22 | import { formatToDateTime } from '/@/utils/dateUtil'; | 22 | import { formatToDateTime } from '/@/utils/dateUtil'; |
23 | import { isEqual } from 'lodash-es'; | 23 | import { isEqual } from 'lodash-es'; |
24 | import { useAsyncQueue } from '/@/views/device/localtion/useAsyncQueue'; | 24 | import { useAsyncQueue } from '/@/views/device/localtion/useAsyncQueue'; |
25 | + import { useMessage } from '/@/hooks/web/useMessage'; | ||
25 | 26 | ||
26 | // useVisualBoardContext(); | 27 | // useVisualBoardContext(); |
27 | type TrackRecord = Record<'lng' | 'lat' | 'ts', number>; | 28 | type TrackRecord = Record<'lng' | 'lat' | 'ts', number>; |
@@ -199,7 +200,13 @@ | @@ -199,7 +200,13 @@ | ||
199 | return (trackAni.value || {})._status; | 200 | return (trackAni.value || {})._status; |
200 | }); | 201 | }); |
201 | 202 | ||
203 | + const { createMessage } = useMessage(); | ||
202 | const handlePlay = () => { | 204 | const handlePlay = () => { |
205 | + const { start, end } = timeRange; | ||
206 | + | ||
207 | + if (!props.random && (!start || !end)) { | ||
208 | + createMessage.warning('请先选择时间范围'); | ||
209 | + } | ||
203 | if (unref(getTrackPlayStatus) === TrackAnimationStatus.DONE) unref(trackAni).start(); | 210 | if (unref(getTrackPlayStatus) === TrackAnimationStatus.DONE) unref(trackAni).start(); |
204 | else if (unref(getTrackPlayStatus) === TrackAnimationStatus.PLAY) unref(trackAni).pause(); | 211 | else if (unref(getTrackPlayStatus) === TrackAnimationStatus.PLAY) unref(trackAni).pause(); |
205 | else if (unref(getTrackPlayStatus) === TrackAnimationStatus.PAUSE) unref(trackAni).continue(); | 212 | else if (unref(getTrackPlayStatus) === TrackAnimationStatus.PAUSE) unref(trackAni).continue(); |
@@ -289,7 +289,7 @@ | @@ -289,7 +289,7 @@ | ||
289 | <Alert type="info" show-icon v-if="isMapComponent"> | 289 | <Alert type="info" show-icon v-if="isMapComponent"> |
290 | <template #description> | 290 | <template #description> |
291 | <div> | 291 | <div> |
292 | - 地图组件,需绑定两个数据源,且数据源为同一设备。第一数据源为经度,第二数据源为维度,否则地图组件不能正常显示。 | 292 | + 地图组件,需绑定两个数据源,且数据源为同一设备。第一数据源为经度,第二数据源为纬度,否则地图组件不能正常显示。 |
293 | </div> | 293 | </div> |
294 | </template> | 294 | </template> |
295 | </Alert> | 295 | </Alert> |
1 | <script lang="ts" setup> | 1 | <script lang="ts" setup> |
2 | import { nextTick, Ref, ref, unref } from 'vue'; | 2 | import { nextTick, Ref, ref, unref } from 'vue'; |
3 | import { getDeviceHistoryInfo } from '/@/api/alarm/position'; | 3 | import { getDeviceHistoryInfo } from '/@/api/alarm/position'; |
4 | - import { Empty } from 'ant-design-vue'; | 4 | + import { Empty, Tooltip, Button } from 'ant-design-vue'; |
5 | import { useECharts } from '/@/hooks/web/useECharts'; | 5 | import { useECharts } from '/@/hooks/web/useECharts'; |
6 | import { AggregateDataEnum } from '/@/views/device/localtion/config.data'; | 6 | import { AggregateDataEnum } from '/@/views/device/localtion/config.data'; |
7 | import { useGridLayout } from '/@/hooks/component/useGridLayout'; | 7 | import { useGridLayout } from '/@/hooks/component/useGridLayout'; |
@@ -14,17 +14,29 @@ | @@ -14,17 +14,29 @@ | ||
14 | import { useModalInner } from '/@/components/Modal'; | 14 | import { useModalInner } from '/@/components/Modal'; |
15 | import { getAllDeviceByOrg } from '/@/api/dataBoard'; | 15 | import { getAllDeviceByOrg } from '/@/api/dataBoard'; |
16 | import { useHistoryData } from '/@/views/device/list/hook/useHistoryData'; | 16 | import { useHistoryData } from '/@/views/device/list/hook/useHistoryData'; |
17 | + import { BasicTable, useTable } from '/@/components/Table'; | ||
18 | + import { LineChartOutlined, BarsOutlined } from '@ant-design/icons-vue'; | ||
19 | + import { formatToDateTime } from '/@/utils/dateUtil'; | ||
17 | 20 | ||
18 | type DeviceOption = Record<'label' | 'value' | 'organizationId', string>; | 21 | type DeviceOption = Record<'label' | 'value' | 'organizationId', string>; |
19 | 22 | ||
20 | defineEmits(['register']); | 23 | defineEmits(['register']); |
21 | 24 | ||
25 | + enum Mode { | ||
26 | + TABLE = 'table', | ||
27 | + CHART = 'chart', | ||
28 | + } | ||
29 | + | ||
30 | + const mode = ref<Mode>(Mode.CHART); | ||
31 | + | ||
22 | const chartRef = ref(); | 32 | const chartRef = ref(); |
23 | 33 | ||
24 | const loading = ref(false); | 34 | const loading = ref(false); |
25 | 35 | ||
26 | const isNull = ref(false); | 36 | const isNull = ref(false); |
27 | 37 | ||
38 | + const historyData = ref<{ ts: number; value: string; name: string }[]>([]); | ||
39 | + | ||
28 | const { deviceAttrs, getDeviceKeys, getSearchParams, setChartOptions, getDeviceAttribute } = | 40 | const { deviceAttrs, getDeviceKeys, getSearchParams, setChartOptions, getDeviceAttribute } = |
29 | useHistoryData(); | 41 | useHistoryData(); |
30 | 42 | ||
@@ -52,30 +64,74 @@ | @@ -52,30 +64,74 @@ | ||
52 | loading: loading as unknown as boolean, | 64 | loading: loading as unknown as boolean, |
53 | }, | 65 | }, |
54 | async submitFunc() { | 66 | async submitFunc() { |
55 | - // 表单验证 | ||
56 | - await method.validate(); | ||
57 | - const value = method.getFieldsValue(); | ||
58 | - const searchParams = getSearchParams(value); | ||
59 | - if (!hasDeviceAttr()) return; | ||
60 | - // 发送请求 | ||
61 | - loading.value = true; | ||
62 | - const res = await getDeviceHistoryInfo(searchParams); | ||
63 | - loading.value = false; | ||
64 | - // 判断数据对象是否为空 | ||
65 | - if (!Object.keys(res).length) { | ||
66 | - isNull.value = false; | ||
67 | - return; | ||
68 | - } else { | ||
69 | - isNull.value = true; | ||
70 | - } | ||
71 | - | ||
72 | - const selectedKeys = unref(deviceAttrs).find( | ||
73 | - (item) => item.identifier === value[SchemaFiled.KEYS] | ||
74 | - ); | ||
75 | - setOptions(setChartOptions(res, selectedKeys)); | 67 | + search(); |
76 | }, | 68 | }, |
77 | }); | 69 | }); |
78 | 70 | ||
71 | + const search = async () => { | ||
72 | + // 表单验证 | ||
73 | + await method.validate(); | ||
74 | + const value = method.getFieldsValue(); | ||
75 | + const searchParams = getSearchParams(value); | ||
76 | + if (!hasDeviceAttr()) return; | ||
77 | + // 发送请求 | ||
78 | + loading.value = true; | ||
79 | + const res = await getDeviceHistoryInfo(searchParams); | ||
80 | + historyData.value = getTableHistoryData(res); | ||
81 | + loading.value = false; | ||
82 | + // 判断数据对象是否为空 | ||
83 | + if (!Object.keys(res).length) { | ||
84 | + isNull.value = false; | ||
85 | + return; | ||
86 | + } else { | ||
87 | + isNull.value = true; | ||
88 | + } | ||
89 | + | ||
90 | + const selectedKeys = unref(deviceAttrs).find( | ||
91 | + (item) => item.identifier === value[SchemaFiled.KEYS] | ||
92 | + ); | ||
93 | + setOptions(setChartOptions(res, selectedKeys)); | ||
94 | + }; | ||
95 | + | ||
96 | + const getTableHistoryData = (record: Recordable<{ ts: number; value: string }[]>) => { | ||
97 | + const keys = Object.keys(record); | ||
98 | + const list = keys.reduce((prev, next) => { | ||
99 | + const list = record[next].map((item) => { | ||
100 | + return { | ||
101 | + ...item, | ||
102 | + name: next, | ||
103 | + }; | ||
104 | + }); | ||
105 | + return [...prev, ...list]; | ||
106 | + }, []); | ||
107 | + return list; | ||
108 | + }; | ||
109 | + | ||
110 | + const [registerTable] = useTable({ | ||
111 | + showIndexColumn: false, | ||
112 | + showTableSetting: false, | ||
113 | + dataSource: historyData, | ||
114 | + maxHeight: 300, | ||
115 | + size: 'small', | ||
116 | + columns: [ | ||
117 | + { | ||
118 | + title: '属性', | ||
119 | + dataIndex: 'name', | ||
120 | + }, | ||
121 | + { | ||
122 | + title: '值', | ||
123 | + dataIndex: 'value', | ||
124 | + }, | ||
125 | + { | ||
126 | + title: '更新时间', | ||
127 | + dataIndex: 'ts', | ||
128 | + format: (val) => { | ||
129 | + return formatToDateTime(val, 'YYYY-MM-DD HH:mm:ss'); | ||
130 | + }, | ||
131 | + }, | ||
132 | + ], | ||
133 | + }); | ||
134 | + | ||
79 | const getDeviceDataKey = async (record: DeviceOption) => { | 135 | const getDeviceDataKey = async (record: DeviceOption) => { |
80 | const { organizationId, value } = record; | 136 | const { organizationId, value } = record; |
81 | try { | 137 | try { |
@@ -115,9 +171,9 @@ | @@ -115,9 +171,9 @@ | ||
115 | agg: AggregateDataEnum.NONE, | 171 | agg: AggregateDataEnum.NONE, |
116 | limit: 7, | 172 | limit: 7, |
117 | }); | 173 | }); |
118 | - | 174 | + historyData.value = getTableHistoryData(res); |
119 | // 判断对象是否为空 | 175 | // 判断对象是否为空 |
120 | - if (!Object.keys(res).length) { | 176 | + if (!Object.keys(unref(historyData)).length) { |
121 | isNull.value = false; | 177 | isNull.value = false; |
122 | return; | 178 | return; |
123 | } else { | 179 | } else { |
@@ -181,6 +237,10 @@ | @@ -181,6 +237,10 @@ | ||
181 | const handleCancel = () => { | 237 | const handleCancel = () => { |
182 | destory(); | 238 | destory(); |
183 | }; | 239 | }; |
240 | + | ||
241 | + const switchMode = (flag: Mode) => { | ||
242 | + mode.value = flag; | ||
243 | + }; | ||
184 | </script> | 244 | </script> |
185 | 245 | ||
186 | <template> | 246 | <template> |
@@ -201,14 +261,65 @@ | @@ -201,14 +261,65 @@ | ||
201 | <BasicForm @register="register" /> | 261 | <BasicForm @register="register" /> |
202 | </section> | 262 | </section> |
203 | <section class="bg-white p-3" style="min-height: 350px"> | 263 | <section class="bg-white p-3" style="min-height: 350px"> |
204 | - <div v-show="isNull" ref="chartRef" :style="{ height: '350px', width: '100%' }"> | 264 | + <div v-show="mode === Mode.CHART" class="flex h-70px items-center justify-end p-2"> |
265 | + <Tooltip title="图表模式"> | ||
266 | + <Button | ||
267 | + :class="[mode === Mode.CHART && '!bg-blue-500 svg:text-light-50']" | ||
268 | + class="!p-2 !children:flex flex justify-center items-center border-r-0" | ||
269 | + @click="switchMode(Mode.CHART)" | ||
270 | + > | ||
271 | + <LineChartOutlined /> | ||
272 | + </Button> | ||
273 | + </Tooltip> | ||
274 | + | ||
275 | + <Tooltip title="列表模式"> | ||
276 | + <Button | ||
277 | + class="!p-2 !children:flex flex justify-center items-center" | ||
278 | + @click="switchMode(Mode.TABLE)" | ||
279 | + > | ||
280 | + <BarsOutlined /> | ||
281 | + </Button> | ||
282 | + </Tooltip> | ||
283 | + </div> | ||
284 | + | ||
285 | + <div | ||
286 | + v-show="isNull && mode === Mode.CHART" | ||
287 | + ref="chartRef" | ||
288 | + :style="{ height: '350px', width: '100%' }" | ||
289 | + > | ||
205 | <Loading :loading="loading" :absolute="true" /> | 290 | <Loading :loading="loading" :absolute="true" /> |
206 | </div> | 291 | </div> |
207 | <Empty | 292 | <Empty |
293 | + v-if="mode === Mode.CHART" | ||
208 | class="h-350px flex flex-col justify-center items-center" | 294 | class="h-350px flex flex-col justify-center items-center" |
209 | description="暂无数据,请选择设备查询" | 295 | description="暂无数据,请选择设备查询" |
210 | v-show="!isNull" | 296 | v-show="!isNull" |
211 | /> | 297 | /> |
298 | + | ||
299 | + <BasicTable v-show="mode === Mode.TABLE" @register="registerTable"> | ||
300 | + <template #toolbar> | ||
301 | + <div v-show="mode === Mode.TABLE" class="flex h-70px items-center justify-end p-2"> | ||
302 | + <Tooltip title="图表模式"> | ||
303 | + <Button | ||
304 | + class="!p-2 !children:flex flex justify-center items-center border-r-0" | ||
305 | + @click="switchMode(Mode.CHART)" | ||
306 | + > | ||
307 | + <LineChartOutlined /> | ||
308 | + </Button> | ||
309 | + </Tooltip> | ||
310 | + | ||
311 | + <Tooltip title="列表模式"> | ||
312 | + <Button | ||
313 | + :class="[mode === Mode.TABLE && '!bg-blue-500 svg:text-light-50']" | ||
314 | + class="!p-2 !children:flex flex justify-center items-center" | ||
315 | + @click="switchMode(Mode.TABLE)" | ||
316 | + > | ||
317 | + <BarsOutlined /> | ||
318 | + </Button> | ||
319 | + </Tooltip> | ||
320 | + </div> | ||
321 | + </template> | ||
322 | + </BasicTable> | ||
212 | </section> | 323 | </section> |
213 | </section> | 324 | </section> |
214 | </BasicModal> | 325 | </BasicModal> |
@@ -143,7 +143,7 @@ | @@ -143,7 +143,7 @@ | ||
143 | }; | 143 | }; |
144 | 144 | ||
145 | const handleOpenDetailModal = () => { | 145 | const handleOpenDetailModal = () => { |
146 | - openModal(); | 146 | + openModal(true, { isEdit: false }); |
147 | }; | 147 | }; |
148 | 148 | ||
149 | const handleRemove = async (record: DataBoardRecord) => { | 149 | const handleRemove = async (record: DataBoardRecord) => { |