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 | }; |