Commit 36f46c76fc7269d90a6dac549076caee33489983

Authored by ww
1 parent 7b1f93b1

fix: report export trend charts not render multiple device charts

... ... @@ -7,3 +7,43 @@ export type ExportParam = {
7 7 orderFiled: string;
8 8 orderType: string;
9 9 };
  10 +export interface ExecuteCondition2 {
  11 + interval: number;
  12 + limit: number;
  13 + agg: string;
  14 + orderBy: string;
  15 + useStrictDataTypes: boolean;
  16 + startTs: number;
  17 + endTs: number;
  18 + queryMode: number;
  19 +}
  20 +
  21 +export interface ExecuteAttribute {
  22 + device: string;
  23 + name: string;
  24 + attributes: string[];
  25 +}
  26 +
  27 +export interface ExecuteCondition {
  28 + executeCondition: ExecuteCondition2;
  29 + executeAttributes: ExecuteAttribute[];
  30 +}
  31 +
  32 +export interface ExecuteReportRecord {
  33 + id: string;
  34 + creator: string;
  35 + createTime: string;
  36 + updateTime: string;
  37 + enabled: boolean;
  38 + tenantId: string;
  39 + reportConfigName: string;
  40 + organizationName: string;
  41 + organizationId: string;
  42 + dataCompare: number;
  43 + executeWay: number;
  44 + executeStatus: number;
  45 + executeTime: string;
  46 + reportPath: string;
  47 + executeCondition: ExecuteCondition;
  48 + jobId: string;
  49 +}
... ...
... ... @@ -7,38 +7,63 @@
7 7 :height="heightNum"
8 8 @register="register"
9 9 title="报表趋势图"
  10 + :minHeight="500"
10 11 :showOkBtn="false"
11 12 >
12   - <div :class="[initChartData.length % 2 !== 0 ? '' : 'wrapper']">
13   - <div
14   - v-if="initChartData.length > 0"
15   - :class="[initChartData.length % 2 !== 0 ? '' : 'chart-style']"
16   - >
  13 + <div :class="[chartInstance.length % 2 !== 0 ? '' : 'wrapper']">
  14 + <Spin :spinning="loading">
17 15 <div
18   - :class="[
19   - initChartData.length % 2 !== 0 ? '' : 'inner',
20   - initChartData.length % 2 !== 0 ? '' : 'item',
21   - ]"
22   - v-for="(item, index) in initChartData"
23   - :key="index"
  16 + v-if="chartInstance.length > 0"
  17 + :class="[chartInstance.length % 2 !== 0 ? '' : 'chart-style']"
24 18 >
25   - <p style="display: none">{{ item }}</p>
26   - <div :id="`chart${index}`" :style="{ height, width }"></div>
  19 + <div
  20 + :class="[
  21 + chartInstance.length % 2 !== 0 ? '' : 'inner',
  22 + chartInstance.length % 2 !== 0 ? '' : 'item',
  23 + ]"
  24 + v-for="item in chartInstance"
  25 + :key="item.device"
  26 + >
  27 + <p class="text-black text-lg">{{ item.name }}</p>
  28 + <div class="flex text-black items-center">
  29 + <div class="mr-4 text-sm">属性:</div>
  30 + <Select
  31 + class="min-w-25"
  32 + v-model:value="item.active"
  33 + @change="(value) => handleChangeChars(value, item.device)"
  34 + placeholder="请选择设备属性"
  35 + >
  36 + <Select.Option v-for="attr in item.attributes" :key="attr" :value="attr">
  37 + {{ attr }}
  38 + </Select.Option>
  39 + </Select>
  40 + </div>
  41 + <div>
  42 + <div :id="`chart-${item.device}`" :style="{ height, width }"></div>
  43 + </div>
  44 + </div>
27 45 </div>
28   - </div>
29   - <div v-else style="display: flex; justify-content: center; align-items: center">
30   - <div style="position: relative; left: 0rem; top: 3rem">暂无数据</div>
31   - </div>
  46 + <div v-else style="display: flex; justify-content: center; align-items: center">
  47 + <div style="position: relative; left: 0rem; top: 3rem">暂无数据</div>
  48 + </div>
  49 + </Spin>
32 50 </div>
33 51 </BasicModal>
34 52 </div>
35 53 </template>
36 54 <script setup lang="ts">
37   - import { ref, PropType, nextTick } from 'vue';
  55 + import { ref, PropType, nextTick, shallowReactive, onMounted, onUnmounted } from 'vue';
38 56 import { BasicModal, useModalInner } from '/@/components/Modal';
39 57 import * as echarts from 'echarts';
40 58 import { exportViewChartApi } from '/@/api/export/exportManager';
41 59 import moment from 'moment';
  60 + import { ExecuteReportRecord } from '/@/api/export/model/exportModel';
  61 + import { Select, Spin } from 'ant-design-vue';
  62 +
  63 + interface ResponsData {
  64 + attr: string;
  65 + val: { ts: number; value: string }[];
  66 + }
42 67
43 68 defineProps({
44 69 width: {
... ... @@ -52,8 +77,14 @@
52 77 });
53 78 defineEmits(['register']);
54 79 const heightNum = ref(800);
55   - const getItem: any = ref([]);
56   - const initChartData: any = ref([]);
  80 +
  81 + let currentRecord: ExecuteReportRecord = {};
  82 +
  83 + const chartInstance = ref<
  84 + { device: string; name: string; attributes: string[]; active?: string }[]
  85 + >([]);
  86 +
  87 + const chartsInstance = shallowReactive<{ [key: string]: echarts.ECharts }>({});
57 88 //生成随机颜色
58 89 let getRandomColor = function () {
59 90 return (
... ... @@ -66,55 +97,72 @@
66 97 ')'
67 98 );
68 99 };
69   - const [register, { setModalProps }] = useModalInner(async (data) => {
70   - setModalProps({ loading: true });
71   - try {
72   - const entityId = data.record.executeCondition?.executeAttributes.map((m) => m?.device);
73   - let key = data.record.executeCondition?.executeAttributes.map((m) => m?.attributes);
74   - let params: any = {};
75   - params = {
76   - ...data.record.executeCondition?.executeCondition,
77   - ...{
78   - keys: key.length !== 0 ? key.join(',') : '',
79   - },
80   - };
81   - const result = await exportViewChartApi(entityId[0], params);
82   - getItem.value = Object.entries(result).map((item) => {
83   - const [attr, val] = item;
84   - return { attr, val };
85   - });
86   - //服务端返回值
87   - initChartData.value = getItem.value.map((item): any => {
  100 +
  101 + const getChartsOption = (result: ResponsData) => {
  102 + const generateInfo = Object.entries(result).map((item) => {
  103 + const [attr, val] = item;
  104 + return { attr, val } as { attr: string; val: { ts: number; value: string }[] };
  105 + });
  106 + const chartDataConfig =
  107 + generateInfo.map((item) => {
88 108 const seriesData = item.val.map((m1) => Number(m1.value));
89 109 return {
90   - attr: item.attr,
91   - lengendData: [item.attr],
92   - xAxisData: item.val.map((m) => moment(m.ts).format('YYYY-MM-DD HH:mm:ss')),
93   - seriesData: [
94   - {
95   - name: item.attr,
96   - type: 'line',
97   - data: seriesData,
98   - lineStyle: {
99   - color: getRandomColor(),
100   - },
  110 + xAxis: item.val.map((m) => moment(m.ts).format('YYYY-MM-DD HH:mm:ss')),
  111 + series: {
  112 + name: item.attr,
  113 + type: 'line',
  114 + data: seriesData,
  115 + lineStyle: {
  116 + color: getRandomColor(),
101 117 },
102   - ],
103   - };
104   - });
105   - nextTick(() => {
106   - initChartData.value.forEach((item, index) => {
107   - let myChart = echarts.init(document.getElementById(`chart${index}`) as HTMLElement);
108   - let myOption = {
  118 + },
  119 + } as echarts.EChartsOption;
  120 + }) || ([] as echarts.EChartsOption[]);
  121 + const chartOption = {
  122 + xAxisData: chartDataConfig.at(0)?.xAxis,
  123 + series: [chartDataConfig.at(0)?.series],
  124 + };
  125 +
  126 + return chartOption;
  127 + };
  128 +
  129 + const [register, { setModalProps }] = useModalInner(
  130 + async (data: { record: ExecuteReportRecord }) => {
  131 + setModalProps({ loading: true });
  132 + try {
  133 + currentRecord = data.record;
  134 + const deviceInfo = data.record.executeCondition.executeAttributes || [];
  135 + chartInstance.value = deviceInfo.map((item) => ({
  136 + ...item,
  137 + active: item.attributes.at(0),
  138 + }));
  139 + for (const item of deviceInfo) {
  140 + const { attributes, device } = item;
  141 + const keys = attributes.length ? attributes.at(0) : '';
  142 + const sendParams = {
  143 + ...data.record.executeCondition.executeCondition,
  144 + ...{
  145 + keys,
  146 + },
  147 + };
  148 +
  149 + const result = await exportViewChartApi(device, sendParams);
  150 + const { xAxisData, series } = getChartsOption(result as unknown as ResponsData);
  151 +
  152 + await nextTick();
  153 + chartsInstance[device] = echarts.init(
  154 + document.getElementById(`chart-${device}`) as HTMLElement
  155 + );
  156 +
  157 + const chartOption = {
109 158 title: {
110   - text: `${item.attr}趋势图`,
111 159 left: 'center',
112 160 },
113 161 tooltip: {
114 162 trigger: 'axis',
115 163 },
116 164 legend: {
117   - data: item.lengendData,
  165 + data: attributes,
118 166 top: '20px',
119 167 },
120 168 toolbox: {},
... ... @@ -136,11 +184,11 @@
136 184 ],
137 185 xAxis: {
138 186 type: 'category',
139   - data: item.xAxisData,
  187 + data: xAxisData,
140 188 boundaryGap: false,
141 189 axisPointer: { type: 'shadow' },
142 190 axisLabel: {
143   - interval: 0,
  191 + interval: 0,
144 192 rotate: 65,
145 193 textStyle: {
146 194 color: '#000',
... ... @@ -159,18 +207,60 @@
159 207 type: 'value',
160 208 boundaryGap: false,
161 209 },
162   - series: item.seriesData,
  210 + series,
163 211 };
164   - myChart.setOption(myOption);
  212 + chartsInstance[device].setOption(chartOption);
165 213 //自适应
166   - window.addEventListener('resize', () => {
167   - myChart.resize();
168   - });
169   - });
170   - });
  214 + // window.addEventListener('resize', () => {
  215 + // chartsInstance[device].resize();
  216 + // });
  217 + }
  218 + } catch (error) {
  219 + throw error;
  220 + } finally {
  221 + setModalProps({ loading: false });
  222 + }
  223 + }
  224 + );
  225 + const loading = ref(false);
  226 + const renderCharts = async (device: string, keys: string) => {
  227 + const sendParams = {
  228 + ...currentRecord.executeCondition.executeCondition,
  229 + ...{
  230 + keys,
  231 + },
  232 + };
  233 + try {
  234 + loading.value = true;
  235 + const result = await exportViewChartApi(device, sendParams);
  236 + const { xAxisData, series } = getChartsOption(result as unknown as ResponsData);
  237 +
  238 + chartsInstance[device].setOption({
  239 + series,
  240 + xAxis: { data: xAxisData },
  241 + } as echarts.EChartsOption);
  242 + } catch (error) {
171 243 } finally {
172   - setModalProps({ loading: false });
  244 + loading.value = false;
173 245 }
  246 + };
  247 +
  248 + const handleChangeChars = (value: string, device: string) => {
  249 + renderCharts(device, value);
  250 + };
  251 +
  252 + const resize = () => {
  253 + Object.keys(chartsInstance).forEach((key) => {
  254 + chartsInstance[key].resize();
  255 + });
  256 + };
  257 +
  258 + onMounted(() => {
  259 + window.addEventListener('resize', resize);
  260 + });
  261 +
  262 + onUnmounted(() => {
  263 + window.removeEventListener('resize', resize);
174 264 });
175 265 </script>
176 266 <style lang="less" scoped>
... ...