Commit e644b8dfb0db08a3fd6c50f0a183e6d2b79d4793
1 parent
128a5ebd
wip: implement drag && drop save layou info
Showing
12 changed files
with
207 additions
and
41 deletions
... | ... | @@ -27,7 +27,7 @@ |
27 | 27 | function initChart() { |
28 | 28 | const chartDom = document.getElementById(getControlsWidgetId())!; |
29 | 29 | chartRef.value = init(chartDom); |
30 | - const option: EChartsOption = props.layout || instrumentComponent1(); | |
30 | + const option: EChartsOption = props.layout.chartOption || instrumentComponent1(); | |
31 | 31 | |
32 | 32 | nextTick(() => { |
33 | 33 | option && unref(chartRef)?.setOption(option); |
... | ... | @@ -52,13 +52,15 @@ |
52 | 52 | |
53 | 53 | <template> |
54 | 54 | <div class="flex flex-col w-full h-full min-w-3 min-h-3"> |
55 | - <div :id="getControlsWidgetId()" class="widget-charts w-full h-full"></div> | |
56 | - <div>{{}}</div> | |
57 | - <div class="text-xs text-center text-gray-400"> | |
58 | - <span>更新时间:</span> | |
59 | - <span> | |
60 | - {{ props.value.updateTime || dateUtil().format('YYYY-MM-DD HH:mm:ss') }} | |
61 | - </span> | |
55 | + <div :id="getControlsWidgetId()" class="widget-charts flex-auto"></div> | |
56 | + <div> | |
57 | + <div class="text-center">{{ props.value.name }}</div> | |
58 | + <div class="text-xs text-center text-gray-400"> | |
59 | + <span>更新时间:</span> | |
60 | + <span> | |
61 | + {{ props.value.updateTime || dateUtil().format('YYYY-MM-DD HH:mm:ss') }} | |
62 | + </span> | |
63 | + </div> | |
62 | 64 | </div> |
63 | 65 | </div> |
64 | 66 | </template> | ... | ... |
1 | +<script lang="ts" setup> | |
2 | + import { Image } from 'ant-design-vue'; | |
3 | + | |
4 | + const props = defineProps<{ | |
5 | + value: { | |
6 | + src: string; | |
7 | + }; | |
8 | + }>(); | |
9 | +</script> | |
10 | + | |
11 | +<template> | |
12 | + <section> | |
13 | + <Image | |
14 | + :src=" | |
15 | + props?.value?.src || | |
16 | + 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png' | |
17 | + " | |
18 | + /> | |
19 | + </section> | |
20 | +</template> | |
21 | + | |
22 | +<style></style> | ... | ... |
1 | 1 | import { EChartsOption } from 'echarts'; |
2 | 2 | import { visualOptionField } from '../../detail/config/visualOptions'; |
3 | +import { DataComponentRecord, DataSource } from '/@/api/dataBoard/model'; | |
4 | +import { buildUUID } from '/@/utils/uuid'; | |
3 | 5 | |
4 | 6 | export type InstrumentComponentType = 'instrument-component-1' | 'instrument-component-2'; |
5 | 7 | |
... | ... | @@ -10,6 +12,7 @@ export type GradientKey = |
10 | 12 | | visualOptionField.SECOND_PHASE_VALUE |
11 | 13 | | visualOptionField.THIRD_PHASE_COLOR |
12 | 14 | | visualOptionField.THIRD_PHASE_VALUE; |
15 | + | |
13 | 16 | export interface GradientInfoRecord { |
14 | 17 | key: GradientKey; |
15 | 18 | value: number | string; |
... | ... | @@ -24,6 +27,10 @@ export interface DashBoardValue { |
24 | 27 | gradientInfo?: GradientInfoRecord[]; |
25 | 28 | } |
26 | 29 | |
30 | +export interface DashboardComponentLayout { | |
31 | + chartOption: EChartsOption; | |
32 | +} | |
33 | + | |
27 | 34 | export const instrumentComponent1 = (params?: { value: number; unit: string }): EChartsOption => { |
28 | 35 | const { value = 10, unit = '°C' } = params || {}; |
29 | 36 | return { |
... | ... | @@ -214,3 +221,24 @@ export const instrumentComponent2 = (params?: { |
214 | 221 | export const getGradientValue = (key: GradientKey, record: GradientInfoRecord[]) => { |
215 | 222 | return record.find((item) => item.key === key)?.value; |
216 | 223 | }; |
224 | + | |
225 | +export const transformDashboardComponentConfig = ( | |
226 | + config: DashboardComponentLayout, | |
227 | + record: DataComponentRecord, | |
228 | + dataSourceRecord: DataSource | |
229 | +) => { | |
230 | + return { | |
231 | + layout: { | |
232 | + chartOption: config, | |
233 | + } as DashboardComponentLayout, | |
234 | + value: { | |
235 | + id: buildUUID(), | |
236 | + name: dataSourceRecord.attributeRename || dataSourceRecord.attribute, | |
237 | + // value: record.va | |
238 | + unit: dataSourceRecord.componentInfo.unit, | |
239 | + updateTime: record.updateTime || record.createTime, | |
240 | + fontColor: dataSourceRecord.componentInfo.fontColor, | |
241 | + gradientInfo: dataSourceRecord.componentInfo.gradientInfo, | |
242 | + }, | |
243 | + }; | |
244 | +}; | ... | ... |
1 | +import { EChartsOption } from 'echarts'; | |
1 | 2 | import { Component } from 'vue'; |
2 | 3 | import { WidgetComponentType } from '../../detail/config/visualOptions'; |
3 | 4 | import { instrumentComponent1, instrumentComponent2 } from './dashBoardComponent.config'; |
... | ... | @@ -5,9 +6,13 @@ import DashBoardComponent from './DashBoardComponent.vue'; |
5 | 6 | import DigitalDashBoard from './DigitalDashBoard.vue'; |
6 | 7 | import { buildUUID } from '/@/utils/uuid'; |
7 | 8 | |
9 | +export interface DashboardComponentLayout { | |
10 | + chartOption: EChartsOption; | |
11 | +} | |
12 | + | |
8 | 13 | interface InstrumentComponentConfig { |
9 | 14 | id: WidgetComponentType; |
10 | - layout: Recordable; | |
15 | + layout: DashboardComponentLayout; | |
11 | 16 | component: Component; |
12 | 17 | value: Recordable; |
13 | 18 | } |
... | ... | @@ -15,18 +20,18 @@ interface InstrumentComponentConfig { |
15 | 20 | export const instrumentComponentConfig: InstrumentComponentConfig[] = [ |
16 | 21 | { |
17 | 22 | id: 'instrument-component-1', |
18 | - layout: instrumentComponent1(), | |
23 | + layout: { chartOption: instrumentComponent1() }, | |
19 | 24 | component: DashBoardComponent, |
20 | 25 | value: { id: buildUUID() }, |
21 | 26 | }, |
22 | 27 | { |
23 | 28 | id: 'instrument-component-2', |
24 | - layout: instrumentComponent2(), | |
29 | + layout: { chartOption: instrumentComponent2() }, | |
25 | 30 | component: DashBoardComponent, |
26 | 31 | value: { id: buildUUID() }, |
27 | 32 | }, |
28 | 33 | { |
29 | - id: 'digital-dashboard', | |
34 | + id: 'digital-dashboard-component', | |
30 | 35 | layout: {}, |
31 | 36 | component: DigitalDashBoard, |
32 | 37 | value: {}, | ... | ... |
... | ... | @@ -62,7 +62,7 @@ |
62 | 62 | /> |
63 | 63 | </div> |
64 | 64 | </div> |
65 | - <div v-if="getShowUpdate" class="h-6 text-center text-xs text-gray-400"> | |
65 | + <div v-if="getShowUpdate" class="text-center text-xs text-gray-400"> | |
66 | 66 | <span> 更新时间: {{ props.value.updateTime }}</span> |
67 | 67 | </div> |
68 | 68 | </div> | ... | ... |
1 | 1 | <script lang="ts" setup> |
2 | 2 | import { ref, unref } from 'vue'; |
3 | - import { WidgetComponentType, schemasMap } from '../config/visualOptions'; | |
3 | + import { | |
4 | + WidgetComponentType, | |
5 | + schemasMap, | |
6 | + VisualOptionParams, | |
7 | + visualOptionField, | |
8 | + Gradient, | |
9 | + } from '../config/visualOptions'; | |
4 | 10 | import { useForm, BasicForm } from '/@/components/Form'; |
5 | 11 | import { BasicModal, useModalInner } from '/@/components/Modal'; |
6 | 12 | import { ComponentInfo } from '/@/api/dataBoard/model'; |
... | ... | @@ -29,13 +35,44 @@ |
29 | 35 | const [register, { closeModal }] = useModalInner( |
30 | 36 | (data: { recordId: string; componentInfo: ComponentInfo }) => { |
31 | 37 | recordId.value = data.recordId; |
32 | - method.setFieldsValue(data.componentInfo || {}); | |
38 | + console.log(data.componentInfo); | |
39 | + const gradientInfo = data.componentInfo.gradientInfo; | |
40 | + let gradientRecord = {}; | |
41 | + if (gradientInfo && gradientInfo.length) { | |
42 | + const first = gradientInfo.find((item) => item.key === Gradient.FIRST); | |
43 | + const second = gradientInfo.find((item) => item.key === Gradient.SECOND); | |
44 | + const third = gradientInfo.find((item) => item.key === Gradient.THIRD); | |
45 | + gradientRecord = { | |
46 | + [visualOptionField.FIRST_PHASE_COLOR]: first?.color, | |
47 | + [visualOptionField.FIRST_PHASE_VALUE]: first?.value, | |
48 | + [visualOptionField.SECOND_PHASE_COLOR]: second?.color, | |
49 | + [visualOptionField.SECOND_PHASE_VALUE]: second?.value, | |
50 | + [visualOptionField.THIRD_PHASE_COLOR]: third?.color, | |
51 | + [visualOptionField.THIRD_PHASE_VALUE]: third?.value, | |
52 | + }; | |
53 | + } | |
54 | + | |
55 | + method.setFieldsValue({ ...(data.componentInfo || {}), ...gradientRecord }); | |
33 | 56 | } |
34 | 57 | ); |
35 | 58 | |
36 | 59 | const handleGetValue = () => { |
37 | 60 | const value = method.getFieldsValue(); |
38 | - emit('close', unref(recordId), value); | |
61 | + emit('close', unref(recordId), transformValue(value)); | |
62 | + }; | |
63 | + | |
64 | + const transformValue = (value: Partial<VisualOptionParams>) => { | |
65 | + return { | |
66 | + fontColor: value.fontColor || null, | |
67 | + icon: value.icon || null, | |
68 | + iconColor: value.iconColor || null, | |
69 | + unit: value.unit || null, | |
70 | + // gradientInfo: [ | |
71 | + // { key: Gradient.FIRST, value: value.firstPhaseValue, color: value.firstPhaseColor }, | |
72 | + // { key: Gradient.SECOND, value: value.secondPhaseValue, color: value.secondPhaseColor }, | |
73 | + // { key: Gradient.THIRD, value: value.thirdPhaseValue, color: value.thirdPhaseColor }, | |
74 | + // ], | |
75 | + }; | |
39 | 76 | }; |
40 | 77 | |
41 | 78 | const handleClose = () => { |
... | ... | @@ -53,6 +90,12 @@ |
53 | 90 | title="选项" |
54 | 91 | width="60%" |
55 | 92 | > |
56 | - <BasicForm @register="registerForm" :schemas="getSchemas" /> | |
93 | + <BasicForm class="form" @register="registerForm" :schemas="getSchemas" /> | |
57 | 94 | </BasicModal> |
58 | 95 | </template> |
96 | + | |
97 | +<style scoped> | |
98 | + .form:deep(.ant-input-number) { | |
99 | + width: 100%; | |
100 | + } | |
101 | +</style> | ... | ... |
... | ... | @@ -9,21 +9,25 @@ import { |
9 | 9 | transformTextComponentConfig, |
10 | 10 | } from '../../components/TextComponent/config'; |
11 | 11 | import { DataComponentRecord, DataSource } from '/@/api/dataBoard/model'; |
12 | +import DashBoardComponent from '../../components/InstrumentComponent/DashBoardComponent.vue'; | |
13 | +import { WidgetComponentType } from './visualOptions'; | |
14 | +import { | |
15 | + instrumentComponent1, | |
16 | + instrumentComponent2, | |
17 | + transformDashboardComponentConfig, | |
18 | +} from '../../components/InstrumentComponent/dashBoardComponent.config'; | |
19 | +import DigitalDashBoard from '../../components/InstrumentComponent/DigitalDashBoard.vue'; | |
12 | 20 | export enum FrontComponent { |
13 | 21 | TEXT_COMPONENT_1 = 'text-component-1', |
14 | 22 | TEXT_COMPONENT_2 = 'text-component-2', |
15 | 23 | TEXT_COMPONENT_3 = 'text-component-3', |
16 | 24 | TEXT_COMPONENT_4 = 'text-component-4', |
17 | 25 | TEXT_COMPONENT_5 = 'text-component-5', |
26 | + INSTRUMENT_COMPONENT_1 = 'instrument-component-1', | |
27 | + INSTRUMENT_COMPONENT_2 = 'instrument-component-2', | |
28 | + DIGITAL_DASHBOARD_COMPONENT = 'digital-dashboard-component', | |
18 | 29 | } |
19 | 30 | |
20 | -export type FrontComponentType = | |
21 | - | 'text-component-1' | |
22 | - | 'text-component-2' | |
23 | - | 'text-component-3' | |
24 | - | 'text-component-4' | |
25 | - | 'text-component-5'; | |
26 | - | |
27 | 31 | export interface ComponentConfig { |
28 | 32 | Component: Component; |
29 | 33 | ComponentConfig: Recordable; |
... | ... | @@ -34,7 +38,7 @@ export interface ComponentConfig { |
34 | 38 | ) => Recordable; |
35 | 39 | } |
36 | 40 | |
37 | -export const frontComponentMap = new Map<FrontComponentType, ComponentConfig>(); | |
41 | +export const frontComponentMap = new Map<WidgetComponentType, ComponentConfig>(); | |
38 | 42 | |
39 | 43 | frontComponentMap.set(FrontComponent.TEXT_COMPONENT_1, { |
40 | 44 | Component: TextComponent, |
... | ... | @@ -65,3 +69,21 @@ frontComponentMap.set(FrontComponent.TEXT_COMPONENT_5, { |
65 | 69 | ComponentConfig: TextComponent5Config, |
66 | 70 | transformConfig: transformTextComponentConfig, |
67 | 71 | }); |
72 | + | |
73 | +frontComponentMap.set(FrontComponent.INSTRUMENT_COMPONENT_1, { | |
74 | + Component: DashBoardComponent, | |
75 | + ComponentConfig: instrumentComponent1(), | |
76 | + transformConfig: transformDashboardComponentConfig, | |
77 | +}); | |
78 | + | |
79 | +frontComponentMap.set(FrontComponent.INSTRUMENT_COMPONENT_2, { | |
80 | + Component: DashBoardComponent, | |
81 | + ComponentConfig: instrumentComponent2(), | |
82 | + transformConfig: transformDashboardComponentConfig, | |
83 | +}); | |
84 | + | |
85 | +frontComponentMap.set(FrontComponent.DIGITAL_DASHBOARD_COMPONENT, { | |
86 | + Component: DigitalDashBoard, | |
87 | + ComponentConfig: {}, | |
88 | + transformConfig: transformDashboardComponentConfig, | |
89 | +}); | ... | ... |
... | ... | @@ -2,15 +2,31 @@ import { InstrumentComponentType } from '../../components/InstrumentComponent/da |
2 | 2 | import { DigitalDashBoardComponentType } from '../../components/InstrumentComponent/digitalDashBoard.config'; |
3 | 3 | import { TextComponentType } from '../../components/TextComponent/config'; |
4 | 4 | import { FormSchema } from '/@/components/Form'; |
5 | -export enum defaultOptions { | |
6 | - fontColor = '#rer', | |
7 | -} | |
8 | 5 | |
9 | 6 | export type WidgetComponentType = |
10 | 7 | | TextComponentType |
11 | 8 | | InstrumentComponentType |
12 | 9 | | DigitalDashBoardComponentType; |
13 | 10 | |
11 | +export interface VisualOptionParams { | |
12 | + [visualOptionField.FONT_COLOR]: string; | |
13 | + [visualOptionField.UNIT]: string; | |
14 | + [visualOptionField.ICON_COLOR]: string; | |
15 | + [visualOptionField.ICON]: string; | |
16 | + [visualOptionField.FIRST_PHASE_COLOR]: string; | |
17 | + [visualOptionField.SECOND_PHASE_COLOR]: string; | |
18 | + [visualOptionField.THIRD_PHASE_COLOR]: string; | |
19 | + [visualOptionField.FIRST_PHASE_VALUE]: string; | |
20 | + [visualOptionField.SECOND_PHASE_VALUE]: string; | |
21 | + [visualOptionField.THIRD_PHASE_VALUE]: string; | |
22 | +} | |
23 | + | |
24 | +export enum Gradient { | |
25 | + FIRST = 'first', | |
26 | + SECOND = 'second', | |
27 | + THIRD = 'third', | |
28 | +} | |
29 | + | |
14 | 30 | export enum visualOptionField { |
15 | 31 | FONT_COLOR = 'fontColor', |
16 | 32 | UNIT = 'unit', |
... | ... | @@ -19,11 +35,9 @@ export enum visualOptionField { |
19 | 35 | FIRST_PHASE_COLOR = 'firstPhaseColor', |
20 | 36 | SECOND_PHASE_COLOR = 'secondPhaseColor', |
21 | 37 | THIRD_PHASE_COLOR = 'thirdPhaseColor', |
22 | - FOURTH_PHASE_COLOR = 'fourthPhaseColor', | |
23 | 38 | FIRST_PHASE_VALUE = 'firstPhaseValue', |
24 | 39 | SECOND_PHASE_VALUE = 'secondPhaseValue', |
25 | 40 | THIRD_PHASE_VALUE = 'thirdPhaseValue', |
26 | - FOURTH_PHASE_VALUE = 'fourthPhaseValue', | |
27 | 41 | } |
28 | 42 | |
29 | 43 | export const modeOne: FormSchema[] = [ |
... | ... | @@ -94,9 +108,10 @@ export const modeThree: FormSchema[] = [ |
94 | 108 | { |
95 | 109 | field: visualOptionField.FIRST_PHASE_VALUE, |
96 | 110 | label: '一阶段阀值', |
97 | - component: 'Input', | |
111 | + component: 'InputNumber', | |
98 | 112 | componentProps: { |
99 | 113 | placeholder: '请输入一阶段阀值', |
114 | + min: 0, | |
100 | 115 | }, |
101 | 116 | }, |
102 | 117 | { |
... | ... | @@ -108,9 +123,10 @@ export const modeThree: FormSchema[] = [ |
108 | 123 | { |
109 | 124 | field: visualOptionField.SECOND_PHASE_VALUE, |
110 | 125 | label: '二阶段阀值', |
111 | - component: 'Input', | |
126 | + component: 'InputNumber', | |
112 | 127 | componentProps: { |
113 | 128 | placeholder: '请输入二阶段阀值', |
129 | + min: 0, | |
114 | 130 | }, |
115 | 131 | }, |
116 | 132 | { |
... | ... | @@ -122,9 +138,10 @@ export const modeThree: FormSchema[] = [ |
122 | 138 | { |
123 | 139 | field: visualOptionField.THIRD_PHASE_VALUE, |
124 | 140 | label: '三阶段阀值', |
125 | - component: 'Input', | |
141 | + component: 'InputNumber', | |
126 | 142 | componentProps: { |
127 | 143 | placeholder: '请输入三阶段阀值', |
144 | + min: 0, | |
128 | 145 | }, |
129 | 146 | }, |
130 | 147 | ]; |
... | ... | @@ -155,3 +172,4 @@ schemasMap.set('text-component-4', modeTwo); |
155 | 172 | schemasMap.set('text-component-4', modeTwo); |
156 | 173 | schemasMap.set('instrument-component-1', modeOne); |
157 | 174 | schemasMap.set('instrument-component-2', modeThree); |
175 | +schemasMap.set('digital-dashboard-component', modeFour); | ... | ... |
... | ... | @@ -16,7 +16,7 @@ |
16 | 16 | } from '/@/api/dataBoard'; |
17 | 17 | import { useRoute } from 'vue-router'; |
18 | 18 | import { computed, unref } from '@vue/reactivity'; |
19 | - import { DataComponentRecord, DataSource } from '/@/api/dataBoard/model'; | |
19 | + import { DataComponentRecord, DataSource, Layout } from '/@/api/dataBoard/model'; | |
20 | 20 | import { frontComponentMap, FrontComponentType } from './config/help'; |
21 | 21 | import { useMessage } from '/@/hooks/web/useMessage'; |
22 | 22 | import { DataBoardLayoutInfo } from '../types/type'; |
... | ... | @@ -79,10 +79,13 @@ |
79 | 79 | if (updateFn) updateFn(); |
80 | 80 | }); |
81 | 81 | } |
82 | + const itemResize = (i: string, newH: number, newW: number, newHPx: number, newWPx: number) => { | |
83 | + updateSize(i, newH, newW, newHPx, newWPx); | |
84 | + }; | |
82 | 85 | |
83 | 86 | const itemResized = (i: string, newH: number, newW: number, newHPx: number, newWPx: number) => { |
87 | + handleSaveLayoutInfo(); | |
84 | 88 | updateSize(i, newH, newW, newHPx, newWPx); |
85 | - console.log({ newH, newW, newHPx, newWPx }); | |
86 | 89 | }; |
87 | 90 | |
88 | 91 | const itemContainerResized = ( |
... | ... | @@ -95,6 +98,11 @@ |
95 | 98 | updateSize(i, newH, newW, newHPx, newWPx); |
96 | 99 | }; |
97 | 100 | |
101 | + const itemMoved = (i: string) => { | |
102 | + handleSaveLayoutInfo(); | |
103 | + updateCharts(i); | |
104 | + }; | |
105 | + | |
98 | 106 | const updateCharts = (i: string) => { |
99 | 107 | nextTick(() => { |
100 | 108 | const updateFn = widgetEl.get(i); |
... | ... | @@ -126,6 +134,25 @@ |
126 | 134 | openModal(true); |
127 | 135 | }; |
128 | 136 | |
137 | + const handleSaveLayoutInfo = async () => { | |
138 | + try { | |
139 | + const layoutInfo = unref(dataBoardList).map((item) => { | |
140 | + return { | |
141 | + id: item.i, | |
142 | + h: item.h, | |
143 | + w: item.w, | |
144 | + x: item.x, | |
145 | + y: item.y, | |
146 | + } as Layout; | |
147 | + }); | |
148 | + | |
149 | + await updateDataBoardLayout({ | |
150 | + boardId: unref(getBoardId), | |
151 | + layout: layoutInfo, | |
152 | + }); | |
153 | + } catch (error) {} | |
154 | + }; | |
155 | + | |
129 | 156 | const getDataBoardComponent = async () => { |
130 | 157 | try { |
131 | 158 | const data = await getDataComponent(unref(getBoardId)); |
... | ... | @@ -150,7 +177,6 @@ |
150 | 177 | }, |
151 | 178 | }; |
152 | 179 | }); |
153 | - console.log(unref(dataBoardList)); | |
154 | 180 | } catch (error) {} |
155 | 181 | }; |
156 | 182 | |
... | ... | @@ -173,7 +199,6 @@ |
173 | 199 | |
174 | 200 | const handleCopy = async (id: string) => { |
175 | 201 | const record = unref(dataBoardList).find((item) => item.i === id); |
176 | - console.log({ record }); | |
177 | 202 | try { |
178 | 203 | const data = await addDataComponent({ |
179 | 204 | boardId: unref(getBoardId), |
... | ... | @@ -243,8 +268,8 @@ |
243 | 268 | :style="{ display: 'flex', flexWrap: 'wrap' }" |
244 | 269 | class="grid-item-layout" |
245 | 270 | @resized="itemResized" |
246 | - @resize="itemResized" | |
247 | - @moved="updateCharts" | |
271 | + @resize="itemResize" | |
272 | + @moved="itemMoved" | |
248 | 273 | @container-resized="itemContainerResized" |
249 | 274 | > |
250 | 275 | <WidgetWrapper | ... | ... |