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 | 3 | export interface AddDataBoardParams { | 
| 2 | 4 | name: string; | 
| 3 | 5 | viewType: string; | 
| ... | ... | @@ -75,6 +77,13 @@ export interface DataSource { | 
| 75 | 77 | slaveDeviceId: string; | 
| 76 | 78 | isGatewayDevice: boolean; | 
| 77 | 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 | 89 | export interface DataComponentRecord { | ... | ... | 
| ... | ... | @@ -99,7 +99,7 @@ | 
| 99 | 99 | |
| 100 | 100 | <template> | 
| 101 | 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 | 103 | <div> | 
| 104 | 104 | <div class="text-center" :style="{ fontSize: fontSize({ radio: getRadio, basic: 16 }) }">{{ | 
| 105 | 105 | props.value.name | ... | ... | 
| ... | ... | @@ -7,10 +7,12 @@ | 
| 7 | 7 | import { MoreActionEvent } from '../../config/config'; | 
| 8 | 8 | import { computed } from '@vue/reactivity'; | 
| 9 | 9 | import { usePermission } from '/@/hooks/web/usePermission'; | 
| 10 | + import { DataSource } from '/@/api/dataBoard/model'; | |
| 10 | 11 | |
| 11 | 12 | const emit = defineEmits(['action']); | 
| 12 | 13 | const props = defineProps<{ | 
| 13 | 14 | id: string; | 
| 15 | + record: DataSource[]; | |
| 14 | 16 | }>(); | 
| 15 | 17 | const { hasPermission } = usePermission(); | 
| 16 | 18 | const dropMenuList = computed<DropMenu[]>(() => { | 
| ... | ... | @@ -45,20 +47,27 @@ | 
| 45 | 47 | </script> | 
| 46 | 48 | |
| 47 | 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 | 61 | <Tooltip> | 
| 53 | 62 | <SvgIcon name="online" prefix="iconfont" class="!fill-emerald-400" /> | 
| 54 | 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 | 66 | </div> | 
| 58 | 67 | </div> | 
| 59 | - <div class="flex items-center wx-9"> | |
| 68 | + <div class="flex items-center w-10"> | |
| 60 | 69 | <Tooltip title="趋势"> | 
| 61 | - <LineChartOutlined class="cursor-pointer mx-2" /> | |
| 70 | + <LineChartOutlined class="cursor-pointer mx-1" /> | |
| 62 | 71 | </Tooltip> | 
| 63 | 72 | <Dropdown | 
| 64 | 73 | v-if="dropMenuList.length" | ... | ... | 
| 1 | 1 | <script lang="ts" setup> | 
| 2 | - import { onMounted, useSlots } from 'vue'; | |
| 2 | + import { useSlots } from 'vue'; | |
| 3 | 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 | 8 | const props = defineProps<{ | 
| 9 | - dataSource: DataBoardLayoutInfo['record'][]; | |
| 10 | - register?: WidgetWrapperRegister; | |
| 9 | + dataSource: FrontDataSourceRecord[]; | |
| 11 | 10 | }>(); | 
| 12 | 11 | |
| 13 | 12 | const slot = useSlots(); | 
| 14 | 13 | |
| 15 | 14 | const { update, add, remove } = useUpdateCenter(); | 
| 16 | 15 | |
| 17 | - onMounted(() => { | |
| 18 | - props.register && props.register(props.dataSource); | |
| 19 | - }); | |
| 20 | - | |
| 21 | 16 | defineExpose({ update }); | 
| 22 | 17 | </script> | 
| 23 | 18 | |
| ... | ... | @@ -28,7 +23,7 @@ | 
| 28 | 23 | <div class="widget-content" :style="{ height: slot.header ? 'calc(100% - 22px)' : '100%' }"> | 
| 29 | 24 | <div | 
| 30 | 25 | v-for="item in props.dataSource" | 
| 31 | - :key="item.id" | |
| 26 | + :key="item.uuid" | |
| 32 | 27 | :style="{ width: `${item.width}%`, height: `${item.height}%` }" | 
| 33 | 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 | 12 | import { ComponentInfo } from '/@/api/dataBoard/model'; | 
| 13 | 13 | import { computed } from '@vue/reactivity'; | 
| 14 | 14 | |
| 15 | - const emit = defineEmits(['close']); | |
| 15 | + const emit = defineEmits(['close', 'register']); | |
| 16 | 16 | |
| 17 | 17 | const props = defineProps<{ | 
| 18 | 18 | value?: string; | 
| ... | ... | @@ -35,8 +35,7 @@ | 
| 35 | 35 | const [register, { closeModal }] = useModalInner( | 
| 36 | 36 | (data: { recordId: string; componentInfo: ComponentInfo }) => { | 
| 37 | 37 | recordId.value = data.recordId; | 
| 38 | - console.log(data.componentInfo); | |
| 39 | - const gradientInfo = data.componentInfo.gradientInfo; | |
| 38 | + const gradientInfo = data.componentInfo?.gradientInfo || []; | |
| 40 | 39 | let gradientRecord = {}; | 
| 41 | 40 | if (gradientInfo && gradientInfo.length) { | 
| 42 | 41 | const first = gradientInfo.find((item) => item.key === Gradient.FIRST); | ... | ... | 
| 1 | 1 | import { getAllDeviceByOrg, getDeviceAttributes, getGatewaySlaveDevice } from '/@/api/dataBoard'; | 
| 2 | -import { MasterDeviceList } from '/@/api/dataBoard/model'; | |
| 3 | 2 | import { getOrganizationList } from '/@/api/system/system'; | 
| 4 | 3 | import { FormSchema } from '/@/components/Form'; | 
| 5 | 4 | import { copyTransFun } from '/@/utils/fnUtils'; | ... | ... | 
| 1 | 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 | 3 | import { GridItem, GridLayout } from 'vue3-grid-layout'; | 
| 4 | 4 | import { nextTick, onMounted, ref } from 'vue'; | 
| 5 | 5 | import WidgetWrapper from '../components/WidgetWrapper/WidgetWrapper.vue'; | 
| ... | ... | @@ -24,6 +24,7 @@ | 
| 24 | 24 | import { WidgetComponentType } from './config/visualOptions'; | 
| 25 | 25 | import Authority from '/@/components/Authority/src/Authority.vue'; | 
| 26 | 26 | import { useSocketConnect } from '../hook/useSocketConnect'; | 
| 27 | + import { buildUUID } from '/@/utils/uuid'; | |
| 27 | 28 | |
| 28 | 29 | const ROUTE = useRoute(); | 
| 29 | 30 | |
| ... | ... | @@ -74,6 +75,7 @@ | 
| 74 | 75 | } | 
| 75 | 76 | |
| 76 | 77 | data.record.dataSource = data?.record.dataSource.map((item) => { | 
| 78 | + if (!item.uuid) item.uuid = buildUUID(); | |
| 77 | 79 | return { | 
| 78 | 80 | ...item, | 
| 79 | 81 | width, | 
| ... | ... | @@ -164,9 +166,11 @@ | 
| 164 | 166 | |
| 165 | 167 | const { beginSendMessage } = useSocketConnect(dataBoardList); | 
| 166 | 168 | |
| 169 | + const loading = ref(false); | |
| 167 | 170 | const getDataBoardComponent = async () => { | 
| 168 | 171 | try { | 
| 169 | 172 | // dataBoardList.value = []; | 
| 173 | + loading.value = true; | |
| 170 | 174 | const data = await getDataComponent(unref(getBoardId)); | 
| 171 | 175 | dataBoardList.value = data.data.componentData.map((item) => { | 
| 172 | 176 | const index = data.data.componentLayout.findIndex((each) => item.id === each.id); | 
| ... | ... | @@ -182,15 +186,15 @@ | 
| 182 | 186 | h: layout.h || DEFAULT_WIDGET_HEIGHT, | 
| 183 | 187 | x: layout.x || 0, | 
| 184 | 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 | 193 | beginSendMessage(); | 
| 193 | - } catch (error) {} | |
| 194 | + } catch (error) { | |
| 195 | + } finally { | |
| 196 | + loading.value = false; | |
| 197 | + } | |
| 194 | 198 | }; | 
| 195 | 199 | |
| 196 | 200 | const getComponent = (record: DataComponentRecord) => { | 
| ... | ... | @@ -258,56 +262,62 @@ | 
| 258 | 262 | </div> | 
| 259 | 263 | </PageHeader> | 
| 260 | 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 | 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 | 321 | </section> | 
| 312 | 322 | <DataBindModal @register="register" @submit="getDataBoardComponent" /> | 
| 313 | 323 | </section> | ... | ... | 
| 1 | 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 | 6 | export type DataBoardLayoutInfo = Layout & { | 
| 5 | - record: DataComponentRecord & { width: number; height: number; radio?: number }; | |
| 7 | + record: DataComponentRecord; | |
| 6 | 8 | }; | ... | ... |