Commit 6f9ac029a1fbb6420ba06f83a2762dbdbbd37a1f
1 parent
e535013c
feat: data dashboard data source add slave device field
Showing
12 changed files
with
108 additions
and
85 deletions
1 | +import { RadioRecord } from '/@/views/data/board/detail/config/util'; | ||
2 | + | ||
1 | export interface AddDataBoardParams { | 3 | export interface AddDataBoardParams { |
2 | name: string; | 4 | name: string; |
3 | viewType: string; | 5 | viewType: string; |
@@ -75,6 +77,13 @@ export interface DataSource { | @@ -75,6 +77,13 @@ export interface DataSource { | ||
75 | slaveDeviceId: string; | 77 | slaveDeviceId: string; |
76 | isGatewayDevice: boolean; | 78 | isGatewayDevice: boolean; |
77 | componentInfo: ComponentInfo; | 79 | componentInfo: ComponentInfo; |
80 | + deviceName?: string; | ||
81 | + | ||
82 | + // front usage | ||
83 | + uuid?: string; | ||
84 | + width?: number; | ||
85 | + height?: number; | ||
86 | + radio?: RadioRecord; | ||
78 | } | 87 | } |
79 | 88 | ||
80 | export interface DataComponentRecord { | 89 | export interface DataComponentRecord { |
@@ -99,7 +99,7 @@ | @@ -99,7 +99,7 @@ | ||
99 | 99 | ||
100 | <template> | 100 | <template> |
101 | <div class="flex flex-col w-full h-full min-w-3 min-h-3"> | 101 | <div class="flex flex-col w-full h-full min-w-3 min-h-3"> |
102 | - <div :id="getControlsWidgetId()" class="widget-charts flex-auto"></div> | 102 | + <div :id="getControlsWidgetId()" class="widget-charts min-w-1 min-h-1 flex-auto"></div> |
103 | <div> | 103 | <div> |
104 | <div class="text-center" :style="{ fontSize: fontSize({ radio: getRadio, basic: 16 }) }">{{ | 104 | <div class="text-center" :style="{ fontSize: fontSize({ radio: getRadio, basic: 16 }) }">{{ |
105 | props.value.name | 105 | props.value.name |
@@ -13,7 +13,7 @@ | @@ -13,7 +13,7 @@ | ||
13 | const props = defineProps<{ | 13 | const props = defineProps<{ |
14 | layout: DigitalDashBoardLayout; | 14 | layout: DigitalDashBoardLayout; |
15 | value: DigitalDashBoardValue; | 15 | value: DigitalDashBoardValue; |
16 | - radio: RadioRecord; | 16 | + radio?: RadioRecord; |
17 | }>(); | 17 | }>(); |
18 | 18 | ||
19 | const integerPart = computed(() => { | 19 | const integerPart = computed(() => { |
@@ -13,7 +13,7 @@ | @@ -13,7 +13,7 @@ | ||
13 | const props = defineProps<{ | 13 | const props = defineProps<{ |
14 | layout?: PictureComponentLayout; | 14 | layout?: PictureComponentLayout; |
15 | value?: PictureComponentValue; | 15 | value?: PictureComponentValue; |
16 | - radio: RadioRecord; | 16 | + radio?: RadioRecord; |
17 | }>(); | 17 | }>(); |
18 | 18 | ||
19 | const fallback = | 19 | const fallback = |
@@ -7,10 +7,12 @@ | @@ -7,10 +7,12 @@ | ||
7 | import { MoreActionEvent } from '../../config/config'; | 7 | import { MoreActionEvent } from '../../config/config'; |
8 | import { computed } from '@vue/reactivity'; | 8 | import { computed } from '@vue/reactivity'; |
9 | import { usePermission } from '/@/hooks/web/usePermission'; | 9 | import { usePermission } from '/@/hooks/web/usePermission'; |
10 | + import { DataSource } from '/@/api/dataBoard/model'; | ||
10 | 11 | ||
11 | const emit = defineEmits(['action']); | 12 | const emit = defineEmits(['action']); |
12 | const props = defineProps<{ | 13 | const props = defineProps<{ |
13 | id: string; | 14 | id: string; |
15 | + record: DataSource[]; | ||
14 | }>(); | 16 | }>(); |
15 | const { hasPermission } = usePermission(); | 17 | const { hasPermission } = usePermission(); |
16 | const dropMenuList = computed<DropMenu[]>(() => { | 18 | const dropMenuList = computed<DropMenu[]>(() => { |
@@ -45,20 +47,27 @@ | @@ -45,20 +47,27 @@ | ||
45 | </script> | 47 | </script> |
46 | 48 | ||
47 | <template> | 49 | <template> |
48 | - <div class="flex justify-between"> | ||
49 | - <div class="flex flex-auto"> | ||
50 | - <div v-for="item in 1" class="flex mx-2" :key="item"> | ||
51 | - <div class="flex items-center"> | 50 | + <div class="flex justify-between w-full"> |
51 | + <div class="flex" :style="{ width: `calc(100% - 60px)` }"> | ||
52 | + <div | ||
53 | + v-for="(item, index) in props.record" | ||
54 | + class="box-border truncate" | ||
55 | + :style="{ width: `${100 / props.record.length}%` }" | ||
56 | + :key="index" | ||
57 | + > | ||
58 | + <SvgIcon name="" prefix="iconfont" class="!fill-emerald-400" /> | ||
59 | + {{ item.deviceName }} | ||
60 | + <!-- <div class="flex items-center"> | ||
52 | <Tooltip> | 61 | <Tooltip> |
53 | <SvgIcon name="online" prefix="iconfont" class="!fill-emerald-400" /> | 62 | <SvgIcon name="online" prefix="iconfont" class="!fill-emerald-400" /> |
54 | </Tooltip> | 63 | </Tooltip> |
55 | - <span class="truncate max-w-25 ml-2">设备名称{{ item }}</span> | ||
56 | - </div> | 64 | + <div class="truncate">{{ item.deviceName || item.deviceId }}</div> |
65 | + </div> --> | ||
57 | </div> | 66 | </div> |
58 | </div> | 67 | </div> |
59 | - <div class="flex items-center wx-9"> | 68 | + <div class="flex items-center w-10"> |
60 | <Tooltip title="趋势"> | 69 | <Tooltip title="趋势"> |
61 | - <LineChartOutlined class="cursor-pointer mx-2" /> | 70 | + <LineChartOutlined class="cursor-pointer mx-1" /> |
62 | </Tooltip> | 71 | </Tooltip> |
63 | <Dropdown | 72 | <Dropdown |
64 | v-if="dropMenuList.length" | 73 | v-if="dropMenuList.length" |
1 | <script lang="ts" setup> | 1 | <script lang="ts" setup> |
2 | - import { onMounted, useSlots } from 'vue'; | 2 | + import { useSlots } from 'vue'; |
3 | import { useUpdateCenter } from '../../hook/useUpdateCenter'; | 3 | import { useUpdateCenter } from '../../hook/useUpdateCenter'; |
4 | - import { DataBoardLayoutInfo } from '../../types/type'; | ||
5 | - import type { WidgetWrapperRegister } from './type'; | ||
6 | - import { DataSource } from '/@/api/dataBoard/model'; | 4 | + import { FrontDataSourceRecord } from '../../types/type'; |
5 | + // import type { WidgetWrapperRegister } from './type'; | ||
6 | + // import { DataSource } from '/@/api/dataBoard/model'; | ||
7 | 7 | ||
8 | const props = defineProps<{ | 8 | const props = defineProps<{ |
9 | - dataSource: DataBoardLayoutInfo['record'][]; | ||
10 | - register?: WidgetWrapperRegister; | 9 | + dataSource: FrontDataSourceRecord[]; |
11 | }>(); | 10 | }>(); |
12 | 11 | ||
13 | const slot = useSlots(); | 12 | const slot = useSlots(); |
14 | 13 | ||
15 | const { update, add, remove } = useUpdateCenter(); | 14 | const { update, add, remove } = useUpdateCenter(); |
16 | 15 | ||
17 | - onMounted(() => { | ||
18 | - props.register && props.register(props.dataSource); | ||
19 | - }); | ||
20 | - | ||
21 | defineExpose({ update }); | 16 | defineExpose({ update }); |
22 | </script> | 17 | </script> |
23 | 18 | ||
@@ -28,7 +23,7 @@ | @@ -28,7 +23,7 @@ | ||
28 | <div class="widget-content" :style="{ height: slot.header ? 'calc(100% - 22px)' : '100%' }"> | 23 | <div class="widget-content" :style="{ height: slot.header ? 'calc(100% - 22px)' : '100%' }"> |
29 | <div | 24 | <div |
30 | v-for="item in props.dataSource" | 25 | v-for="item in props.dataSource" |
31 | - :key="item.id" | 26 | + :key="item.uuid" |
32 | :style="{ width: `${item.width}%`, height: `${item.height}%` }" | 27 | :style="{ width: `${item.width}%`, height: `${item.height}%` }" |
33 | class="widget-item" | 28 | class="widget-item" |
34 | > | 29 | > |
1 | -import { DataBoardLayoutInfo } from '../../types/type'; | 1 | +// import { DataBoardLayoutInfo } from '../../types/type'; |
2 | 2 | ||
3 | -export type WidgetWrapperRegister = (dataSource: DataBoardLayoutInfo['record'][]) => any; | 3 | +// export type WidgetWrapperRegister = (dataSource: DataBoardLayoutInfo['record'][]) => any; |
@@ -12,7 +12,7 @@ | @@ -12,7 +12,7 @@ | ||
12 | import { ComponentInfo } from '/@/api/dataBoard/model'; | 12 | import { ComponentInfo } from '/@/api/dataBoard/model'; |
13 | import { computed } from '@vue/reactivity'; | 13 | import { computed } from '@vue/reactivity'; |
14 | 14 | ||
15 | - const emit = defineEmits(['close']); | 15 | + const emit = defineEmits(['close', 'register']); |
16 | 16 | ||
17 | const props = defineProps<{ | 17 | const props = defineProps<{ |
18 | value?: string; | 18 | value?: string; |
@@ -35,8 +35,7 @@ | @@ -35,8 +35,7 @@ | ||
35 | const [register, { closeModal }] = useModalInner( | 35 | const [register, { closeModal }] = useModalInner( |
36 | (data: { recordId: string; componentInfo: ComponentInfo }) => { | 36 | (data: { recordId: string; componentInfo: ComponentInfo }) => { |
37 | recordId.value = data.recordId; | 37 | recordId.value = data.recordId; |
38 | - console.log(data.componentInfo); | ||
39 | - const gradientInfo = data.componentInfo.gradientInfo; | 38 | + const gradientInfo = data.componentInfo?.gradientInfo || []; |
40 | let gradientRecord = {}; | 39 | let gradientRecord = {}; |
41 | if (gradientInfo && gradientInfo.length) { | 40 | if (gradientInfo && gradientInfo.length) { |
42 | const first = gradientInfo.find((item) => item.key === Gradient.FIRST); | 41 | const first = gradientInfo.find((item) => item.key === Gradient.FIRST); |
1 | import { getAllDeviceByOrg, getDeviceAttributes, getGatewaySlaveDevice } from '/@/api/dataBoard'; | 1 | import { getAllDeviceByOrg, getDeviceAttributes, getGatewaySlaveDevice } from '/@/api/dataBoard'; |
2 | -import { MasterDeviceList } from '/@/api/dataBoard/model'; | ||
3 | import { getOrganizationList } from '/@/api/system/system'; | 2 | import { getOrganizationList } from '/@/api/system/system'; |
4 | import { FormSchema } from '/@/components/Form'; | 3 | import { FormSchema } from '/@/components/Form'; |
5 | import { copyTransFun } from '/@/utils/fnUtils'; | 4 | import { copyTransFun } from '/@/utils/fnUtils'; |
1 | <script lang="ts" setup> | 1 | <script lang="ts" setup> |
2 | - import { Button, PageHeader, Empty } from 'ant-design-vue'; | 2 | + import { Button, PageHeader, Empty, Spin } from 'ant-design-vue'; |
3 | import { GridItem, GridLayout } from 'vue3-grid-layout'; | 3 | import { GridItem, GridLayout } from 'vue3-grid-layout'; |
4 | import { nextTick, onMounted, ref } from 'vue'; | 4 | import { nextTick, onMounted, ref } from 'vue'; |
5 | import WidgetWrapper from '../components/WidgetWrapper/WidgetWrapper.vue'; | 5 | import WidgetWrapper from '../components/WidgetWrapper/WidgetWrapper.vue'; |
@@ -24,6 +24,7 @@ | @@ -24,6 +24,7 @@ | ||
24 | import { WidgetComponentType } from './config/visualOptions'; | 24 | import { WidgetComponentType } from './config/visualOptions'; |
25 | import Authority from '/@/components/Authority/src/Authority.vue'; | 25 | import Authority from '/@/components/Authority/src/Authority.vue'; |
26 | import { useSocketConnect } from '../hook/useSocketConnect'; | 26 | import { useSocketConnect } from '../hook/useSocketConnect'; |
27 | + import { buildUUID } from '/@/utils/uuid'; | ||
27 | 28 | ||
28 | const ROUTE = useRoute(); | 29 | const ROUTE = useRoute(); |
29 | 30 | ||
@@ -74,6 +75,7 @@ | @@ -74,6 +75,7 @@ | ||
74 | } | 75 | } |
75 | 76 | ||
76 | data.record.dataSource = data?.record.dataSource.map((item) => { | 77 | data.record.dataSource = data?.record.dataSource.map((item) => { |
78 | + if (!item.uuid) item.uuid = buildUUID(); | ||
77 | return { | 79 | return { |
78 | ...item, | 80 | ...item, |
79 | width, | 81 | width, |
@@ -164,9 +166,11 @@ | @@ -164,9 +166,11 @@ | ||
164 | 166 | ||
165 | const { beginSendMessage } = useSocketConnect(dataBoardList); | 167 | const { beginSendMessage } = useSocketConnect(dataBoardList); |
166 | 168 | ||
169 | + const loading = ref(false); | ||
167 | const getDataBoardComponent = async () => { | 170 | const getDataBoardComponent = async () => { |
168 | try { | 171 | try { |
169 | // dataBoardList.value = []; | 172 | // dataBoardList.value = []; |
173 | + loading.value = true; | ||
170 | const data = await getDataComponent(unref(getBoardId)); | 174 | const data = await getDataComponent(unref(getBoardId)); |
171 | dataBoardList.value = data.data.componentData.map((item) => { | 175 | dataBoardList.value = data.data.componentData.map((item) => { |
172 | const index = data.data.componentLayout.findIndex((each) => item.id === each.id); | 176 | const index = data.data.componentLayout.findIndex((each) => item.id === each.id); |
@@ -182,15 +186,15 @@ | @@ -182,15 +186,15 @@ | ||
182 | h: layout.h || DEFAULT_WIDGET_HEIGHT, | 186 | h: layout.h || DEFAULT_WIDGET_HEIGHT, |
183 | x: layout.x || 0, | 187 | x: layout.x || 0, |
184 | y: layout.y || 0, | 188 | y: layout.y || 0, |
185 | - record: { | ||
186 | - ...item, | ||
187 | - width: 100, | ||
188 | - height: 100, | ||
189 | - }, | 189 | + record: item, |
190 | }; | 190 | }; |
191 | }); | 191 | }); |
192 | + | ||
192 | beginSendMessage(); | 193 | beginSendMessage(); |
193 | - } catch (error) {} | 194 | + } catch (error) { |
195 | + } finally { | ||
196 | + loading.value = false; | ||
197 | + } | ||
194 | }; | 198 | }; |
195 | 199 | ||
196 | const getComponent = (record: DataComponentRecord) => { | 200 | const getComponent = (record: DataComponentRecord) => { |
@@ -258,56 +262,62 @@ | @@ -258,56 +262,62 @@ | ||
258 | </div> | 262 | </div> |
259 | </PageHeader> | 263 | </PageHeader> |
260 | <section class="flex-1"> | 264 | <section class="flex-1"> |
261 | - <GridLayout | ||
262 | - v-model:layout="dataBoardList" | ||
263 | - :col-num="GirdLayoutColNum" | ||
264 | - :row-height="30" | ||
265 | - :margin="[GridLayoutMargin, GridLayoutMargin]" | ||
266 | - :is-draggable="draggable" | ||
267 | - :is-resizable="resizable" | ||
268 | - :vertical-compact="true" | ||
269 | - :use-css-transforms="true" | ||
270 | - style="width: 100%" | ||
271 | - > | ||
272 | - <GridItem | ||
273 | - v-for="item in dataBoardList" | ||
274 | - :key="item.i" | ||
275 | - :static="item.static" | ||
276 | - :x="item.x" | ||
277 | - :y="item.y" | ||
278 | - :w="item.w" | ||
279 | - :h="item.h" | ||
280 | - :i="item.i" | ||
281 | - :style="{ display: 'flex', flexWrap: 'wrap' }" | ||
282 | - class="grid-item-layout" | ||
283 | - @resized="itemResized" | ||
284 | - @resize="itemResize" | ||
285 | - @moved="itemMoved" | ||
286 | - @container-resized="itemContainerResized" | 265 | + <Spin :spinning="loading"> |
266 | + <GridLayout | ||
267 | + v-model:layout="dataBoardList" | ||
268 | + :col-num="GirdLayoutColNum" | ||
269 | + :row-height="30" | ||
270 | + :margin="[GridLayoutMargin, GridLayoutMargin]" | ||
271 | + :is-draggable="draggable" | ||
272 | + :is-resizable="resizable" | ||
273 | + :vertical-compact="true" | ||
274 | + :use-css-transforms="true" | ||
275 | + style="width: 100%" | ||
287 | > | 276 | > |
288 | - <WidgetWrapper | 277 | + <GridItem |
278 | + v-for="item in dataBoardList" | ||
289 | :key="item.i" | 279 | :key="item.i" |
290 | - :ref="(el: Element) => setComponentRef(el, item)" | ||
291 | - :data-source="item.record.dataSource" | 280 | + :static="item.static" |
281 | + :x="item.x" | ||
282 | + :y="item.y" | ||
283 | + :w="item.w" | ||
284 | + :h="item.h" | ||
285 | + :i="item.i" | ||
286 | + :style="{ display: 'flex', flexWrap: 'wrap' }" | ||
287 | + class="grid-item-layout" | ||
288 | + @resized="itemResized" | ||
289 | + @resize="itemResize" | ||
290 | + @moved="itemMoved" | ||
291 | + @container-resized="itemContainerResized" | ||
292 | > | 292 | > |
293 | - <template #header> | ||
294 | - <!-- <div>header</div> --> | ||
295 | - <BaseWidgetHeader :id="item.record.id" @action="handleMoreAction" /> | ||
296 | - </template> | ||
297 | - <template #controls="{ record, add, remove, update }"> | ||
298 | - <component | ||
299 | - :is="getComponent(item.record)" | ||
300 | - :add="add" | ||
301 | - :remove="remove" | ||
302 | - :update="update" | ||
303 | - :radio="record.radio" | ||
304 | - v-bind="getComponentConfig(item.record, record)" | ||
305 | - /> | ||
306 | - </template> | ||
307 | - </WidgetWrapper> | ||
308 | - </GridItem> | ||
309 | - </GridLayout> | ||
310 | - <Empty v-if="!dataBoardList.length" /> | 293 | + <WidgetWrapper |
294 | + :key="item.i" | ||
295 | + :ref="(el: Element) => setComponentRef(el, item)" | ||
296 | + :data-source="item.record.dataSource" | ||
297 | + > | ||
298 | + <template #header> | ||
299 | + <!-- <div>header</div> --> | ||
300 | + <BaseWidgetHeader | ||
301 | + :record="item.record.dataSource" | ||
302 | + :id="item.record.id" | ||
303 | + @action="handleMoreAction" | ||
304 | + /> | ||
305 | + </template> | ||
306 | + <template #controls="{ record, add, remove, update }"> | ||
307 | + <component | ||
308 | + :is="getComponent(item.record)" | ||
309 | + :add="add" | ||
310 | + :remove="remove" | ||
311 | + :update="update" | ||
312 | + :radio="record.radio || {}" | ||
313 | + v-bind="getComponentConfig(item.record, record)" | ||
314 | + /> | ||
315 | + </template> | ||
316 | + </WidgetWrapper> | ||
317 | + </GridItem> | ||
318 | + </GridLayout> | ||
319 | + <Empty v-if="!dataBoardList.length" /> | ||
320 | + </Spin> | ||
311 | </section> | 321 | </section> |
312 | <DataBindModal @register="register" @submit="getDataBoardComponent" /> | 322 | <DataBindModal @register="register" @submit="getDataBoardComponent" /> |
313 | </section> | 323 | </section> |
1 | import { Layout } from 'vue3-grid-layout'; | 1 | import { Layout } from 'vue3-grid-layout'; |
2 | -import { DataComponentRecord } from '/@/api/dataBoard/model'; | 2 | +import { DataComponentRecord, DataSource } from '/@/api/dataBoard/model'; |
3 | + | ||
4 | +export type FrontDataSourceRecord = DataSource; | ||
3 | 5 | ||
4 | export type DataBoardLayoutInfo = Layout & { | 6 | export type DataBoardLayoutInfo = Layout & { |
5 | - record: DataComponentRecord & { width: number; height: number; radio?: number }; | 7 | + record: DataComponentRecord; |
6 | }; | 8 | }; |