| 
 
 | 
1
 | 
+<script lang="ts" setup>
 | 
| 
 
 | 
2
 | 
+  import moment from 'moment';
 | 
| 
 
 | 
3
 | 
+  import { nextTick, onMounted, onUnmounted, Ref, ref, unref } from 'vue';
 | 
| 
 
 | 
4
 | 
+  import { getDeviceDataKeys, getDeviceHistoryInfo } from '/@/api/alarm/position';
 | 
| 
 
 | 
5
 | 
+  import { Empty } from 'ant-design-vue';
 | 
| 
 
 | 
6
 | 
+  import { useECharts } from '/@/hooks/web/useECharts';
 | 
| 
 
 | 
7
 | 
+  import { dateUtil } from '/@/utils/dateUtil';
 | 
| 
 
 | 
8
 | 
+  import {
 | 
| 
 
 | 
9
 | 
+    AggregateDataEnum,
 | 
| 
 
 | 
10
 | 
+    eChartOptions,
 | 
| 
 
 | 
11
 | 
+    selectDeviceAttrSchema,
 | 
| 
 
 | 
12
 | 
+  } from '/@/views/device/localtion/config.data';
 | 
| 
 
 | 
13
 | 
+  import { useTimePeriodForm } from '/@/views/device/localtion/cpns/TimePeriodForm';
 | 
| 
 
 | 
14
 | 
+  import { defaultSchemas, QueryWay } from '/@/views/device/localtion/cpns/TimePeriodForm/config';
 | 
| 
 
 | 
15
 | 
+  import TimePeriodForm from '/@/views/device/localtion/cpns/TimePeriodForm/TimePeriodForm.vue';
 | 
| 
 
 | 
16
 | 
+  import { SchemaFiled } from '/@/views/report/config/config.data';
 | 
| 
 
 | 
17
 | 
+  import { useGridLayout } from '/@/hooks/component/useGridLayout';
 | 
| 
 
 | 
18
 | 
+  import { ColEx } from '/@/components/Form/src/types';
 | 
| 
 
 | 
19
 | 
+
 | 
| 
 
 | 
20
 | 
+  interface DeviceDetail {
 | 
| 
 
 | 
21
 | 
+    tbDeviceId: string;
 | 
| 
 
 | 
22
 | 
+  }
 | 
| 
 
 | 
23
 | 
+
 | 
| 
 
 | 
24
 | 
+  const props = defineProps<{
 | 
| 
 
 | 
25
 | 
+    deviceDetail: DeviceDetail;
 | 
| 
 
 | 
26
 | 
+  }>();
 | 
| 
 
 | 
27
 | 
+
 | 
| 
 
 | 
28
 | 
+  const chartRef = ref();
 | 
| 
 
 | 
29
 | 
+
 | 
| 
 
 | 
30
 | 
+  const deviceAttrs = ref<string[]>([]);
 | 
| 
 
 | 
31
 | 
+
 | 
| 
 
 | 
32
 | 
+  const loading = ref(false);
 | 
| 
 
 | 
33
 | 
+
 | 
| 
 
 | 
34
 | 
+  const isNull = ref(false);
 | 
| 
 
 | 
35
 | 
+
 | 
| 
 
 | 
36
 | 
+  function getSearchParams(value: Recordable) {
 | 
| 
 
 | 
37
 | 
+    const { startTs, endTs, interval, agg, limit, keys, way } = value;
 | 
| 
 
 | 
38
 | 
+    if (way === QueryWay.LATEST) {
 | 
| 
 
 | 
39
 | 
+      return {
 | 
| 
 
 | 
40
 | 
+        entityId: props.deviceDetail.tbDeviceId,
 | 
| 
 
 | 
41
 | 
+        keys: keys ? keys : unref(deviceAttrs).join(),
 | 
| 
 
 | 
42
 | 
+        startTs: moment().subtract(startTs, 'ms').valueOf(),
 | 
| 
 
 | 
43
 | 
+        endTs: Date.now(),
 | 
| 
 
 | 
44
 | 
+        interval,
 | 
| 
 
 | 
45
 | 
+        agg,
 | 
| 
 
 | 
46
 | 
+        limit,
 | 
| 
 
 | 
47
 | 
+      };
 | 
| 
 
 | 
48
 | 
+    } else {
 | 
| 
 
 | 
49
 | 
+      return {
 | 
| 
 
 | 
50
 | 
+        entityId: props.deviceDetail.tbDeviceId,
 | 
| 
 
 | 
51
 | 
+        keys: keys ? keys : unref(deviceAttrs).join(),
 | 
| 
 
 | 
52
 | 
+        startTs: moment(startTs).valueOf(),
 | 
| 
 
 | 
53
 | 
+        endTs: moment(endTs).valueOf(),
 | 
| 
 
 | 
54
 | 
+        interval,
 | 
| 
 
 | 
55
 | 
+        agg,
 | 
| 
 
 | 
56
 | 
+        limit,
 | 
| 
 
 | 
57
 | 
+      };
 | 
| 
 
 | 
58
 | 
+    }
 | 
| 
 
 | 
59
 | 
+  }
 | 
| 
 
 | 
60
 | 
+
 | 
| 
 
 | 
61
 | 
+  function hasDeviceAttr() {
 | 
| 
 
 | 
62
 | 
+    if (!unref(deviceAttrs).length) {
 | 
| 
 
 | 
63
 | 
+      return false;
 | 
| 
 
 | 
64
 | 
+    } else {
 | 
| 
 
 | 
65
 | 
+      return true;
 | 
| 
 
 | 
66
 | 
+    }
 | 
| 
 
 | 
67
 | 
+  }
 | 
| 
 
 | 
68
 | 
+
 | 
| 
 
 | 
69
 | 
+  const { setOptions, getInstance } = useECharts(chartRef as Ref<HTMLDivElement>);
 | 
| 
 
 | 
70
 | 
+
 | 
| 
 
 | 
71
 | 
+  function setChartOptions(data, keys?) {
 | 
| 
 
 | 
72
 | 
+    const dataArray: any[] = [];
 | 
| 
 
 | 
73
 | 
+    for (const key in data) {
 | 
| 
 
 | 
74
 | 
+      for (const item1 of data[key]) {
 | 
| 
 
 | 
75
 | 
+        let { ts, value } = item1;
 | 
| 
 
 | 
76
 | 
+        const time = dateUtil(ts).format('YYYY-MM-DD HH:mm:ss');
 | 
| 
 
 | 
77
 | 
+        value = Number(value).toFixed(2);
 | 
| 
 
 | 
78
 | 
+        dataArray.push([time, value, key]);
 | 
| 
 
 | 
79
 | 
+      }
 | 
| 
 
 | 
80
 | 
+    }
 | 
| 
 
 | 
81
 | 
+    keys = keys ? [keys] : unref(deviceAttrs);
 | 
| 
 
 | 
82
 | 
+    const series: any = keys.map((item) => {
 | 
| 
 
 | 
83
 | 
+      return {
 | 
| 
 
 | 
84
 | 
+        name: item,
 | 
| 
 
 | 
85
 | 
+        type: 'line',
 | 
| 
 
 | 
86
 | 
+        data: dataArray.filter((item1) => item1[2] === item),
 | 
| 
 
 | 
87
 | 
+      };
 | 
| 
 
 | 
88
 | 
+    });
 | 
| 
 
 | 
89
 | 
+    // 设置数据
 | 
| 
 
 | 
90
 | 
+    setOptions(eChartOptions(series, keys));
 | 
| 
 
 | 
91
 | 
+  }
 | 
| 
 
 | 
92
 | 
+
 | 
| 
 
 | 
93
 | 
+  const [register, method] = useTimePeriodForm({
 | 
| 
 
 | 
94
 | 
+    schemas: [...defaultSchemas, ...selectDeviceAttrSchema],
 | 
| 
 
 | 
95
 | 
+    baseColProps: useGridLayout(2, 3, 4) as unknown as ColEx,
 | 
| 
 
 | 
96
 | 
+    async submitFunc() {
 | 
| 
 
 | 
97
 | 
+      // 表单验证
 | 
| 
 
 | 
98
 | 
+      await method.validate();
 | 
| 
 
 | 
99
 | 
+      const value = method.getFieldsValue();
 | 
| 
 
 | 
100
 | 
+      const searchParams = getSearchParams(value);
 | 
| 
 
 | 
101
 | 
+
 | 
| 
 
 | 
102
 | 
+      if (!hasDeviceAttr()) return;
 | 
| 
 
 | 
103
 | 
+      // 发送请求
 | 
| 
 
 | 
104
 | 
+      loading.value = true;
 | 
| 
 
 | 
105
 | 
+      const res = await getDeviceHistoryInfo(searchParams);
 | 
| 
 
 | 
106
 | 
+      // 判断数据对象是否为空
 | 
| 
 
 | 
107
 | 
+      if (!Object.keys(res).length) {
 | 
| 
 
 | 
108
 | 
+        isNull.value = false;
 | 
| 
 
 | 
109
 | 
+        return;
 | 
| 
 
 | 
110
 | 
+      } else {
 | 
| 
 
 | 
111
 | 
+        isNull.value = true;
 | 
| 
 
 | 
112
 | 
+      }
 | 
| 
 
 | 
113
 | 
+      setChartOptions(res, value.keys);
 | 
| 
 
 | 
114
 | 
+      loading.value = false;
 | 
| 
 
 | 
115
 | 
+    },
 | 
| 
 
 | 
116
 | 
+  });
 | 
| 
 
 | 
117
 | 
+
 | 
| 
 
 | 
118
 | 
+  const getDeviceDataKey = async () => {
 | 
| 
 
 | 
119
 | 
+    const { tbDeviceId } = props.deviceDetail || {};
 | 
| 
 
 | 
120
 | 
+    try {
 | 
| 
 
 | 
121
 | 
+      deviceAttrs.value = (await getDeviceDataKeys(tbDeviceId)) || [];
 | 
| 
 
 | 
122
 | 
+    } catch (error) {}
 | 
| 
 
 | 
123
 | 
+  };
 | 
| 
 
 | 
124
 | 
+
 | 
| 
 
 | 
125
 | 
+  const openHistoryPanel = async () => {
 | 
| 
 
 | 
126
 | 
+    await nextTick();
 | 
| 
 
 | 
127
 | 
+    method.updateSchema({
 | 
| 
 
 | 
128
 | 
+      field: 'keys',
 | 
| 
 
 | 
129
 | 
+      componentProps: {
 | 
| 
 
 | 
130
 | 
+        options: unref(deviceAttrs).map((item) => ({ label: item, value: item })),
 | 
| 
 
 | 
131
 | 
+      },
 | 
| 
 
 | 
132
 | 
+    });
 | 
| 
 
 | 
133
 | 
+
 | 
| 
 
 | 
134
 | 
+    method.setFieldsValue({
 | 
| 
 
 | 
135
 | 
+      [SchemaFiled.START_TS]: 1 * 24 * 60 * 60 * 1000,
 | 
| 
 
 | 
136
 | 
+      [SchemaFiled.LIMIT]: 7,
 | 
| 
 
 | 
137
 | 
+      [SchemaFiled.AGG]: AggregateDataEnum.NONE,
 | 
| 
 
 | 
138
 | 
+    });
 | 
| 
 
 | 
139
 | 
+
 | 
| 
 
 | 
140
 | 
+    if (!hasDeviceAttr()) return;
 | 
| 
 
 | 
141
 | 
+
 | 
| 
 
 | 
142
 | 
+    const res = await getDeviceHistoryInfo({
 | 
| 
 
 | 
143
 | 
+      entityId: props.deviceDetail.tbDeviceId,
 | 
| 
 
 | 
144
 | 
+      keys: unref(deviceAttrs).join(),
 | 
| 
 
 | 
145
 | 
+      startTs: Date.now() - 1 * 24 * 60 * 60 * 1000,
 | 
| 
 
 | 
146
 | 
+      endTs: Date.now(),
 | 
| 
 
 | 
147
 | 
+      agg: AggregateDataEnum.NONE,
 | 
| 
 
 | 
148
 | 
+    });
 | 
| 
 
 | 
149
 | 
+
 | 
| 
 
 | 
150
 | 
+    // 判断对象是否为空
 | 
| 
 
 | 
151
 | 
+    if (!Object.keys(res).length) {
 | 
| 
 
 | 
152
 | 
+      isNull.value = false;
 | 
| 
 
 | 
153
 | 
+      return;
 | 
| 
 
 | 
154
 | 
+    } else {
 | 
| 
 
 | 
155
 | 
+      isNull.value = true;
 | 
| 
 
 | 
156
 | 
+    }
 | 
| 
 
 | 
157
 | 
+    setChartOptions(res);
 | 
| 
 
 | 
158
 | 
+  };
 | 
| 
 
 | 
159
 | 
+
 | 
| 
 
 | 
160
 | 
+  onMounted(async () => {
 | 
| 
 
 | 
161
 | 
+    await getDeviceDataKey();
 | 
| 
 
 | 
162
 | 
+    await openHistoryPanel();
 | 
| 
 
 | 
163
 | 
+  });
 | 
| 
 
 | 
164
 | 
+
 | 
| 
 
 | 
165
 | 
+  onUnmounted(() => {
 | 
| 
 
 | 
166
 | 
+    getInstance()?.clear();
 | 
| 
 
 | 
167
 | 
+  });
 | 
| 
 
 | 
168
 | 
+</script>
 | 
| 
 
 | 
169
 | 
+
 | 
| 
 
 | 
170
 | 
+<template>
 | 
| 
 
 | 
171
 | 
+  <section class="flex flex-col p-4 h-full" style="color: #f0f2f5">
 | 
| 
 
 | 
172
 | 
+    <section class="bg-white p-3">
 | 
| 
 
 | 
173
 | 
+      <TimePeriodForm @register="register" />
 | 
| 
 
 | 
174
 | 
+    </section>
 | 
| 
 
 | 
175
 | 
+    <section class="bg-white p-3">
 | 
| 
 
 | 
176
 | 
+      <div v-show="isNull" ref="chartRef" :style="{ height: '550px', width: '100%' }">
 | 
| 
 
 | 
177
 | 
+        <Loading :loading="loading" :absolute="true" />
 | 
| 
 
 | 
178
 | 
+      </div>
 | 
| 
 
 | 
179
 | 
+      <Empty v-show="!isNull" />
 | 
| 
 
 | 
180
 | 
+    </section>
 | 
| 
 
 | 
181
 | 
+  </section>
 | 
| 
 
 | 
182
 | 
+</template>
 | 
| 
 
 | 
183
 | 
+
 | 
| 
 
 | 
184
 | 
+<style scoped></style> | 
...
 | 
...
 | 
 |