Commit 128a5ebdb2fc8c44107a4752d92b422ac4e8c83c
1 parent
29b5c630
wip: implement digitalDashboardComponent && DashboardComponent
Showing
17 changed files
with
585 additions
and
108 deletions
| @@ -7,6 +7,7 @@ import { | @@ -7,6 +7,7 @@ import { | ||
| 7 | Layout, | 7 | Layout, |
| 8 | UpdateDataBoardLayoutParams, | 8 | UpdateDataBoardLayoutParams, |
| 9 | UpdateDataBoardParams, | 9 | UpdateDataBoardParams, |
| 10 | + UpdateDataComponentParams, | ||
| 10 | } from './model'; | 11 | } from './model'; |
| 11 | import { defHttp } from '/@/utils/http/axios'; | 12 | import { defHttp } from '/@/utils/http/axios'; |
| 12 | 13 | ||
| @@ -22,6 +23,7 @@ enum DataComponentUrl { | @@ -22,6 +23,7 @@ enum DataComponentUrl { | ||
| 22 | GET_DATA_COMPONENT = '/data_component', | 23 | GET_DATA_COMPONENT = '/data_component', |
| 23 | ADD_DATA_COMPONENT = '/data_component', | 24 | ADD_DATA_COMPONENT = '/data_component', |
| 24 | DELETE_DATA_COMPONENT = '/data_component', | 25 | DELETE_DATA_COMPONENT = '/data_component', |
| 26 | + UPDATE_DATA_COMPONENT = '/data_component', | ||
| 25 | } | 27 | } |
| 26 | 28 | ||
| 27 | /** | 29 | /** |
| @@ -118,3 +120,15 @@ export const deleteDataComponent = (params: string[]) => { | @@ -118,3 +120,15 @@ export const deleteDataComponent = (params: string[]) => { | ||
| 118 | }, | 120 | }, |
| 119 | }); | 121 | }); |
| 120 | }; | 122 | }; |
| 123 | + | ||
| 124 | +/** | ||
| 125 | + * @description 更新数据组件 | ||
| 126 | + * @param params | ||
| 127 | + * @returns | ||
| 128 | + */ | ||
| 129 | +export const updateDataComponent = (params: UpdateDataComponentParams) => { | ||
| 130 | + return defHttp.post({ | ||
| 131 | + url: `${DataComponentUrl.UPDATE_DATA_COMPONENT}/${params.boardId}/update`, | ||
| 132 | + params: params.record, | ||
| 133 | + }); | ||
| 134 | +}; |
| @@ -111,3 +111,8 @@ export interface UpdateDataBoardLayoutParams { | @@ -111,3 +111,8 @@ export interface UpdateDataBoardLayoutParams { | ||
| 111 | boardId: string; | 111 | boardId: string; |
| 112 | layout: Layout[]; | 112 | layout: Layout[]; |
| 113 | } | 113 | } |
| 114 | + | ||
| 115 | +export interface UpdateDataComponentParams { | ||
| 116 | + boardId: string; | ||
| 117 | + record: Partial<DataComponentRecord>; | ||
| 118 | +} |
| @@ -3,67 +3,31 @@ | @@ -3,67 +3,31 @@ | ||
| 3 | import type { PropType } from 'vue'; | 3 | import type { PropType } from 'vue'; |
| 4 | import { nextTick, onMounted, onUnmounted, ref, unref } from 'vue'; | 4 | import { nextTick, onMounted, onUnmounted, ref, unref } from 'vue'; |
| 5 | import { init } from 'echarts'; | 5 | import { init } from 'echarts'; |
| 6 | - | ||
| 7 | - interface DataSource { | ||
| 8 | - id: string | number; | ||
| 9 | - } | 6 | + import { instrumentComponent1 } from './dashBoardComponent.config'; |
| 7 | + import { dateUtil } from '/@/utils/dateUtil'; | ||
| 10 | 8 | ||
| 11 | const props = defineProps({ | 9 | const props = defineProps({ |
| 12 | - dataSource: { | ||
| 13 | - type: Object as PropType<DataSource>, | ||
| 14 | - required: true, | ||
| 15 | - }, | ||
| 16 | - chartOption: { | ||
| 17 | - type: Object as PropType<EChartsOption>, | ||
| 18 | - // required: true, | ||
| 19 | - }, | ||
| 20 | add: { | 10 | add: { |
| 21 | type: Function, | 11 | type: Function, |
| 22 | - required: true, | 12 | + }, |
| 13 | + layout: { | ||
| 14 | + type: Object as PropType<Recordable>, | ||
| 15 | + default: () => ({}), | ||
| 16 | + }, | ||
| 17 | + value: { | ||
| 18 | + type: Object as PropType<Recordable>, | ||
| 19 | + default: () => ({}), | ||
| 23 | }, | 20 | }, |
| 24 | }); | 21 | }); |
| 25 | 22 | ||
| 26 | - const getControlsWidgetId = () => `widget-chart-${props.dataSource.id}`; | 23 | + const getControlsWidgetId = () => `widget-chart-${props.value.id}`; |
| 27 | 24 | ||
| 28 | const chartRef = ref<Nullable<ECharts>>(null); | 25 | const chartRef = ref<Nullable<ECharts>>(null); |
| 29 | 26 | ||
| 30 | function initChart() { | 27 | function initChart() { |
| 31 | const chartDom = document.getElementById(getControlsWidgetId())!; | 28 | const chartDom = document.getElementById(getControlsWidgetId())!; |
| 32 | chartRef.value = init(chartDom); | 29 | chartRef.value = init(chartDom); |
| 33 | - const option: EChartsOption = props.chartOption || { | ||
| 34 | - tooltip: { | ||
| 35 | - trigger: 'item', | ||
| 36 | - // confine: true, | ||
| 37 | - extraCssText: 'position: fixed;', | ||
| 38 | - position: (point, params, dom) => { | ||
| 39 | - const parentEl = (dom as HTMLDivElement).parentElement!; | ||
| 40 | - | ||
| 41 | - const { top = 0, left = 0 } = parentEl.getBoundingClientRect()!; | ||
| 42 | - return [left, top]; | ||
| 43 | - }, | ||
| 44 | - }, | ||
| 45 | - series: [ | ||
| 46 | - { | ||
| 47 | - name: 'Access From', | ||
| 48 | - type: 'pie', | ||
| 49 | - radius: '50%', | ||
| 50 | - data: [ | ||
| 51 | - { value: 1048, name: 'Search Engine' }, | ||
| 52 | - { value: 735, name: 'Direct' }, | ||
| 53 | - { value: 580, name: 'Email' }, | ||
| 54 | - { value: 484, name: 'Union Ads' }, | ||
| 55 | - { value: 300, name: 'Video Ads' }, | ||
| 56 | - ], | ||
| 57 | - emphasis: { | ||
| 58 | - itemStyle: { | ||
| 59 | - shadowBlur: 10, | ||
| 60 | - shadowOffsetX: 0, | ||
| 61 | - shadowColor: 'rgba(0, 0, 0, 0.5)', | ||
| 62 | - }, | ||
| 63 | - }, | ||
| 64 | - }, | ||
| 65 | - ], | ||
| 66 | - }; | 30 | + const option: EChartsOption = props.layout || instrumentComponent1(); |
| 67 | 31 | ||
| 68 | nextTick(() => { | 32 | nextTick(() => { |
| 69 | option && unref(chartRef)?.setOption(option); | 33 | option && unref(chartRef)?.setOption(option); |
| @@ -76,7 +40,7 @@ | @@ -76,7 +40,7 @@ | ||
| 76 | 40 | ||
| 77 | onMounted(() => { | 41 | onMounted(() => { |
| 78 | initChart(); | 42 | initChart(); |
| 79 | - props.add(props.dataSource.id, update); | 43 | + props.add && props.add(props.value.id, update); |
| 80 | }); | 44 | }); |
| 81 | 45 | ||
| 82 | onUnmounted(() => { | 46 | onUnmounted(() => { |
| @@ -89,7 +53,13 @@ | @@ -89,7 +53,13 @@ | ||
| 89 | <template> | 53 | <template> |
| 90 | <div class="flex flex-col w-full h-full min-w-3 min-h-3"> | 54 | <div class="flex flex-col w-full h-full min-w-3 min-h-3"> |
| 91 | <div :id="getControlsWidgetId()" class="widget-charts w-full h-full"></div> | 55 | <div :id="getControlsWidgetId()" class="widget-charts w-full h-full"></div> |
| 92 | - <div class="text-xs text-center text-gray-400">更新时间:</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> | ||
| 62 | + </div> | ||
| 93 | </div> | 63 | </div> |
| 94 | </template> | 64 | </template> |
| 95 | 65 |
| 1 | -<script lang="ts" setup></script> | 1 | +<script lang="ts" setup> |
| 2 | + import { computed } from 'vue'; | ||
| 3 | + import { Space } from 'ant-design-vue'; | ||
| 4 | + import type { DigitalDashBoardLayout, DigitalDashBoardValue } from './digitalDashBoard.config'; | ||
| 5 | + import { dateUtil } from '/@/utils/dateUtil'; | ||
| 2 | 6 | ||
| 3 | -<template> </template> | 7 | + const props = defineProps<{ |
| 8 | + layout: DigitalDashBoardLayout; | ||
| 9 | + value: DigitalDashBoardValue; | ||
| 10 | + }>(); | ||
| 11 | + | ||
| 12 | + const integerPart = computed(() => { | ||
| 13 | + const { value = 0 } = props.value; | ||
| 14 | + const { max = 5 } = props.layout; | ||
| 15 | + let _value = value?.toFixed(2).split('.')[0]; | ||
| 16 | + if (_value.length < max) _value = _value.padStart(5, '0'); | ||
| 17 | + | ||
| 18 | + if (_value.length > max) _value = ''.padStart(5, '9'); | ||
| 19 | + | ||
| 20 | + return _value; | ||
| 21 | + }); | ||
| 22 | + | ||
| 23 | + const decimalPart = computed(() => { | ||
| 24 | + const { value = 0 } = props.value; | ||
| 25 | + const { keepNumber = 2 } = props.layout; | ||
| 26 | + let _value = value?.toFixed(2).split('.')[1]; | ||
| 27 | + if (_value.length < keepNumber) _value = _value.padStart(5, '0'); | ||
| 28 | + | ||
| 29 | + if (_value.length > keepNumber) _value = ''.padStart(5, '0'); | ||
| 30 | + | ||
| 31 | + return _value; | ||
| 32 | + }); | ||
| 33 | +</script> | ||
| 34 | + | ||
| 35 | +<template> | ||
| 36 | + <section class="w-full h-full"> | ||
| 37 | + <div class="flex flex-col w-full h-full"> | ||
| 38 | + <div class="flex-1 flex justify-center items-center"> | ||
| 39 | + <div class="flex flex-col"> | ||
| 40 | + <Space justify="end" class="justify-end"> | ||
| 41 | + <div | ||
| 42 | + v-for="number in integerPart" | ||
| 43 | + :key="number" | ||
| 44 | + class="border border-gray-400 p-2" | ||
| 45 | + :style="{ color: props.value.valueColor }" | ||
| 46 | + > | ||
| 47 | + {{ number }} | ||
| 48 | + </div> | ||
| 49 | + </Space> | ||
| 50 | + <Space justify="end" class="justify-end mt-2"> | ||
| 51 | + <div | ||
| 52 | + v-for="number in decimalPart" | ||
| 53 | + :key="number" | ||
| 54 | + class="border border-gray-400 p-1" | ||
| 55 | + :style="{ color: props.value.valueColor }" | ||
| 56 | + > | ||
| 57 | + {{ number }} | ||
| 58 | + </div> | ||
| 59 | + </Space> | ||
| 60 | + </div> | ||
| 61 | + </div> | ||
| 62 | + | ||
| 63 | + <div class="text-center"> | ||
| 64 | + <span>{{ props.value.name || '电表' }}</span> | ||
| 65 | + <span class="px-1">({{ props.value.unit || 'kw/h' }})</span> | ||
| 66 | + </div> | ||
| 67 | + <div class="text-center mt-1 text-gray-400 text-xs"> | ||
| 68 | + <span class="mr-1">更新时间:</span> | ||
| 69 | + <span>{{ props.value.updateTime || dateUtil().format('YYYY-MM-DD HH:mm:ss') }}</span> | ||
| 70 | + </div> | ||
| 71 | + </div> | ||
| 72 | + <div></div> | ||
| 73 | + </section> | ||
| 74 | +</template> |
| 1 | +import { EChartsOption } from 'echarts'; | ||
| 2 | +import { visualOptionField } from '../../detail/config/visualOptions'; | ||
| 3 | + | ||
| 4 | +export type InstrumentComponentType = 'instrument-component-1' | 'instrument-component-2'; | ||
| 5 | + | ||
| 6 | +export type GradientKey = | ||
| 7 | + | visualOptionField.FIRST_PHASE_COLOR | ||
| 8 | + | visualOptionField.FIRST_PHASE_VALUE | ||
| 9 | + | visualOptionField.SECOND_PHASE_COLOR | ||
| 10 | + | visualOptionField.SECOND_PHASE_VALUE | ||
| 11 | + | visualOptionField.THIRD_PHASE_COLOR | ||
| 12 | + | visualOptionField.THIRD_PHASE_VALUE; | ||
| 13 | +export interface GradientInfoRecord { | ||
| 14 | + key: GradientKey; | ||
| 15 | + value: number | string; | ||
| 16 | +} | ||
| 17 | + | ||
| 18 | +export interface DashBoardValue { | ||
| 19 | + unit?: string; | ||
| 20 | + name?: string; | ||
| 21 | + updateTime?: string; | ||
| 22 | + value?: number; | ||
| 23 | + valueColor?: string; | ||
| 24 | + gradientInfo?: GradientInfoRecord[]; | ||
| 25 | +} | ||
| 26 | + | ||
| 27 | +export const instrumentComponent1 = (params?: { value: number; unit: string }): EChartsOption => { | ||
| 28 | + const { value = 10, unit = '°C' } = params || {}; | ||
| 29 | + return { | ||
| 30 | + series: [ | ||
| 31 | + { | ||
| 32 | + type: 'gauge', | ||
| 33 | + center: ['50%', '60%'], | ||
| 34 | + startAngle: 200, | ||
| 35 | + endAngle: -20, | ||
| 36 | + min: 0, | ||
| 37 | + max: 60, | ||
| 38 | + splitNumber: 12, | ||
| 39 | + itemStyle: { | ||
| 40 | + color: '#FFAB91', | ||
| 41 | + }, | ||
| 42 | + progress: { | ||
| 43 | + show: true, | ||
| 44 | + width: 30, | ||
| 45 | + }, | ||
| 46 | + pointer: { | ||
| 47 | + show: false, | ||
| 48 | + }, | ||
| 49 | + axisLine: { | ||
| 50 | + lineStyle: { | ||
| 51 | + width: 30, | ||
| 52 | + }, | ||
| 53 | + }, | ||
| 54 | + axisTick: { | ||
| 55 | + distance: -45, | ||
| 56 | + splitNumber: 5, | ||
| 57 | + lineStyle: { | ||
| 58 | + width: 2, | ||
| 59 | + color: '#999', | ||
| 60 | + }, | ||
| 61 | + }, | ||
| 62 | + splitLine: { | ||
| 63 | + distance: -52, | ||
| 64 | + length: 14, | ||
| 65 | + lineStyle: { | ||
| 66 | + width: 3, | ||
| 67 | + color: '#999', | ||
| 68 | + }, | ||
| 69 | + }, | ||
| 70 | + axisLabel: { | ||
| 71 | + distance: -20, | ||
| 72 | + color: '#999', | ||
| 73 | + fontSize: 20, | ||
| 74 | + }, | ||
| 75 | + anchor: { | ||
| 76 | + show: false, | ||
| 77 | + }, | ||
| 78 | + title: { | ||
| 79 | + show: false, | ||
| 80 | + }, | ||
| 81 | + detail: { | ||
| 82 | + valueAnimation: true, | ||
| 83 | + width: '60%', | ||
| 84 | + lineHeight: 40, | ||
| 85 | + borderRadius: 8, | ||
| 86 | + offsetCenter: [0, '-15%'], | ||
| 87 | + fontSize: 16, | ||
| 88 | + fontWeight: 'bolder', | ||
| 89 | + formatter: `{value} ${unit}`, | ||
| 90 | + color: 'auto', | ||
| 91 | + }, | ||
| 92 | + data: [ | ||
| 93 | + { | ||
| 94 | + value: value, | ||
| 95 | + }, | ||
| 96 | + ], | ||
| 97 | + }, | ||
| 98 | + { | ||
| 99 | + type: 'gauge', | ||
| 100 | + center: ['50%', '60%'], | ||
| 101 | + startAngle: 200, | ||
| 102 | + endAngle: -20, | ||
| 103 | + min: 0, | ||
| 104 | + max: 60, | ||
| 105 | + itemStyle: { | ||
| 106 | + color: '#FD7347', | ||
| 107 | + }, | ||
| 108 | + progress: { | ||
| 109 | + show: true, | ||
| 110 | + width: 8, | ||
| 111 | + }, | ||
| 112 | + pointer: { | ||
| 113 | + show: false, | ||
| 114 | + }, | ||
| 115 | + axisLine: { | ||
| 116 | + show: false, | ||
| 117 | + }, | ||
| 118 | + axisTick: { | ||
| 119 | + show: false, | ||
| 120 | + }, | ||
| 121 | + splitLine: { | ||
| 122 | + show: false, | ||
| 123 | + }, | ||
| 124 | + axisLabel: { | ||
| 125 | + show: false, | ||
| 126 | + }, | ||
| 127 | + detail: { | ||
| 128 | + show: false, | ||
| 129 | + }, | ||
| 130 | + data: [ | ||
| 131 | + { | ||
| 132 | + value: value, | ||
| 133 | + }, | ||
| 134 | + ], | ||
| 135 | + }, | ||
| 136 | + ], | ||
| 137 | + }; | ||
| 138 | +}; | ||
| 139 | + | ||
| 140 | +export const instrumentComponent2 = (params?: { | ||
| 141 | + gradient: GradientInfoRecord[]; | ||
| 142 | + value: number; | ||
| 143 | + unit: string; | ||
| 144 | +}): EChartsOption => { | ||
| 145 | + const { gradient = [], value = 0, unit = 'km/h' } = params || {}; | ||
| 146 | + return { | ||
| 147 | + series: [ | ||
| 148 | + { | ||
| 149 | + type: 'gauge', | ||
| 150 | + axisLine: { | ||
| 151 | + lineStyle: { | ||
| 152 | + width: 30, | ||
| 153 | + color: [ | ||
| 154 | + [ | ||
| 155 | + 0.3, | ||
| 156 | + (getGradientValue(visualOptionField.FIRST_PHASE_COLOR, gradient) as string) || | ||
| 157 | + '#67e0e3', | ||
| 158 | + ], | ||
| 159 | + [ | ||
| 160 | + 0.7, | ||
| 161 | + (getGradientValue(visualOptionField.SECOND_PHASE_COLOR, gradient) as string) || | ||
| 162 | + '#37a2da', | ||
| 163 | + ], | ||
| 164 | + [ | ||
| 165 | + 1, | ||
| 166 | + (getGradientValue(visualOptionField.THIRD_PHASE_COLOR, gradient) as string) || | ||
| 167 | + '#fd666d', | ||
| 168 | + ], | ||
| 169 | + ], | ||
| 170 | + }, | ||
| 171 | + }, | ||
| 172 | + pointer: { | ||
| 173 | + itemStyle: { | ||
| 174 | + color: 'auto', | ||
| 175 | + }, | ||
| 176 | + }, | ||
| 177 | + axisTick: { | ||
| 178 | + distance: -30, | ||
| 179 | + length: 8, | ||
| 180 | + lineStyle: { | ||
| 181 | + color: '#fff', | ||
| 182 | + width: 2, | ||
| 183 | + }, | ||
| 184 | + }, | ||
| 185 | + splitLine: { | ||
| 186 | + distance: -30, | ||
| 187 | + length: 30, | ||
| 188 | + lineStyle: { | ||
| 189 | + color: '#fff', | ||
| 190 | + width: 4, | ||
| 191 | + }, | ||
| 192 | + }, | ||
| 193 | + axisLabel: { | ||
| 194 | + color: 'auto', | ||
| 195 | + distance: 40, | ||
| 196 | + fontSize: 14, | ||
| 197 | + }, | ||
| 198 | + detail: { | ||
| 199 | + valueAnimation: true, | ||
| 200 | + formatter: `{value} ${unit}`, | ||
| 201 | + color: 'auto', | ||
| 202 | + fontSize: '16', | ||
| 203 | + }, | ||
| 204 | + data: [ | ||
| 205 | + { | ||
| 206 | + value: value, | ||
| 207 | + }, | ||
| 208 | + ], | ||
| 209 | + }, | ||
| 210 | + ], | ||
| 211 | + }; | ||
| 212 | +}; | ||
| 213 | + | ||
| 214 | +export const getGradientValue = (key: GradientKey, record: GradientInfoRecord[]) => { | ||
| 215 | + return record.find((item) => item.key === key)?.value; | ||
| 216 | +}; |
| 1 | +export type DigitalDashBoardComponentType = 'digital-dashboard'; | ||
| 2 | + | ||
| 3 | +export interface DigitalDashBoardLayout { | ||
| 4 | + max: number; | ||
| 5 | + keepNumber: number; | ||
| 6 | +} | ||
| 7 | + | ||
| 8 | +export interface DigitalDashBoardValue { | ||
| 9 | + unit?: string; | ||
| 10 | + name?: string; | ||
| 11 | + updateTime?: string; | ||
| 12 | + value?: number; | ||
| 13 | + valueColor?: string; | ||
| 14 | +} |
| 1 | +import { Component } from 'vue'; | ||
| 2 | +import { WidgetComponentType } from '../../detail/config/visualOptions'; | ||
| 3 | +import { instrumentComponent1, instrumentComponent2 } from './dashBoardComponent.config'; | ||
| 4 | +import DashBoardComponent from './DashBoardComponent.vue'; | ||
| 5 | +import DigitalDashBoard from './DigitalDashBoard.vue'; | ||
| 6 | +import { buildUUID } from '/@/utils/uuid'; | ||
| 7 | + | ||
| 8 | +interface InstrumentComponentConfig { | ||
| 9 | + id: WidgetComponentType; | ||
| 10 | + layout: Recordable; | ||
| 11 | + component: Component; | ||
| 12 | + value: Recordable; | ||
| 13 | +} | ||
| 14 | + | ||
| 15 | +export const instrumentComponentConfig: InstrumentComponentConfig[] = [ | ||
| 16 | + { | ||
| 17 | + id: 'instrument-component-1', | ||
| 18 | + layout: instrumentComponent1(), | ||
| 19 | + component: DashBoardComponent, | ||
| 20 | + value: { id: buildUUID() }, | ||
| 21 | + }, | ||
| 22 | + { | ||
| 23 | + id: 'instrument-component-2', | ||
| 24 | + layout: instrumentComponent2(), | ||
| 25 | + component: DashBoardComponent, | ||
| 26 | + value: { id: buildUUID() }, | ||
| 27 | + }, | ||
| 28 | + { | ||
| 29 | + id: 'digital-dashboard', | ||
| 30 | + layout: {}, | ||
| 31 | + component: DigitalDashBoard, | ||
| 32 | + value: {}, | ||
| 33 | + }, | ||
| 34 | +]; |
| @@ -18,6 +18,13 @@ export interface TextComponentValue { | @@ -18,6 +18,13 @@ export interface TextComponentValue { | ||
| 18 | iconColor?: string; | 18 | iconColor?: string; |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | +export type TextComponentType = | ||
| 22 | + | 'text-component-1' | ||
| 23 | + | 'text-component-2' | ||
| 24 | + | 'text-component-3' | ||
| 25 | + | 'text-component-4' | ||
| 26 | + | 'text-component-5'; | ||
| 27 | + | ||
| 21 | type TextComponentDefault = TextComponentLayout & { value: TextComponentValue }; | 28 | type TextComponentDefault = TextComponentLayout & { value: TextComponentValue }; |
| 22 | 29 | ||
| 23 | export const TextComponent1Config: TextComponentDefault = { | 30 | export const TextComponent1Config: TextComponentDefault = { |
| @@ -10,8 +10,6 @@ | @@ -10,8 +10,6 @@ | ||
| 10 | 10 | ||
| 11 | const slot = useSlots(); | 11 | const slot = useSlots(); |
| 12 | 12 | ||
| 13 | - console.log({ dataSource: props.dataSource }); | ||
| 14 | - | ||
| 15 | const { update, add, remove } = useUpdateCenter(); | 13 | const { update, add, remove } = useUpdateCenter(); |
| 16 | 14 | ||
| 17 | onMounted(() => { | 15 | onMounted(() => { |
| @@ -4,27 +4,28 @@ | @@ -4,27 +4,28 @@ | ||
| 4 | import { FormActionType, useForm } from '/@/components/Form'; | 4 | import { FormActionType, useForm } from '/@/components/Form'; |
| 5 | import { basicSchema, dataSourceSchema } from '../config/basicConfiguration'; | 5 | import { basicSchema, dataSourceSchema } from '../config/basicConfiguration'; |
| 6 | import BasicForm from '/@/components/Form/src/BasicForm.vue'; | 6 | import BasicForm from '/@/components/Form/src/BasicForm.vue'; |
| 7 | - import { onMounted, reactive, ref, shallowReactive, unref, nextTick } from 'vue'; | 7 | + import { reactive, ref, shallowReactive, unref, nextTick, watch } from 'vue'; |
| 8 | import VisualOptionsModal from './VisualOptionsModal.vue'; | 8 | import VisualOptionsModal from './VisualOptionsModal.vue'; |
| 9 | import { useModal } from '/@/components/Modal'; | 9 | import { useModal } from '/@/components/Modal'; |
| 10 | import { buildUUID } from '/@/utils/uuid'; | 10 | import { buildUUID } from '/@/utils/uuid'; |
| 11 | - import type { DataComponentRecord, ComponentInfo, DataSource } from '/@/api/dataBoard/model'; | 11 | + import type { ComponentInfo, DataSource } from '/@/api/dataBoard/model'; |
| 12 | import { useMessage } from '/@/hooks/web/useMessage'; | 12 | import { useMessage } from '/@/hooks/web/useMessage'; |
| 13 | + import { DataBoardLayoutInfo } from '../../types/type'; | ||
| 13 | 14 | ||
| 14 | type DataSourceFormEL = { [key: string]: Nullable<FormActionType> }; | 15 | type DataSourceFormEL = { [key: string]: Nullable<FormActionType> }; |
| 15 | 16 | ||
| 16 | type DataSourceEl = DataSource & { id: string }; | 17 | type DataSourceEl = DataSource & { id: string }; |
| 17 | 18 | ||
| 18 | const props = defineProps<{ | 19 | const props = defineProps<{ |
| 19 | - record: DataComponentRecord; | 20 | + record: DataBoardLayoutInfo; |
| 20 | frontId?: string; | 21 | frontId?: string; |
| 21 | }>(); | 22 | }>(); |
| 22 | 23 | ||
| 23 | const { createMessage } = useMessage(); | 24 | const { createMessage } = useMessage(); |
| 24 | 25 | ||
| 25 | - const componentRecord = reactive<DataComponentRecord>({ | ||
| 26 | - id: 'string', | ||
| 27 | - } as unknown as DataComponentRecord); | 26 | + // const componentRecord = reactive<DataBoardLayoutInfo>({ |
| 27 | + // ...props.record, | ||
| 28 | + // } as unknown as DataBoardLayoutInfo); | ||
| 28 | 29 | ||
| 29 | const dataSource = ref<DataSourceEl[]>([{ id: buildUUID() } as unknown as DataSourceEl]); | 30 | const dataSource = ref<DataSourceEl[]>([{ id: buildUUID() } as unknown as DataSourceEl]); |
| 30 | 31 | ||
| @@ -38,7 +39,6 @@ | @@ -38,7 +39,6 @@ | ||
| 38 | 39 | ||
| 39 | const setFormEl = (el: any, id: string) => { | 40 | const setFormEl = (el: any, id: string) => { |
| 40 | if (!dataSourceEl[id] && el) { | 41 | if (!dataSourceEl[id] && el) { |
| 41 | - console.log({ el, id }); | ||
| 42 | const { formActionType } = el as unknown as { formActionType: FormActionType }; | 42 | const { formActionType } = el as unknown as { formActionType: FormActionType }; |
| 43 | dataSourceEl[id] = formActionType; | 43 | dataSourceEl[id] = formActionType; |
| 44 | } | 44 | } |
| @@ -59,12 +59,12 @@ | @@ -59,12 +59,12 @@ | ||
| 59 | for (const id of hasExistEl) { | 59 | for (const id of hasExistEl) { |
| 60 | const index = unref(dataSource).findIndex((item) => item.id === id); | 60 | const index = unref(dataSource).findIndex((item) => item.id === id); |
| 61 | const value = (dataSourceEl[id] as FormActionType).getFieldsValue() as DataSource; | 61 | const value = (dataSourceEl[id] as FormActionType).getFieldsValue() as DataSource; |
| 62 | + if (!~index) continue; | ||
| 62 | const componentInfo = unref(dataSource)[index].componentInfo || {}; | 63 | const componentInfo = unref(dataSource)[index].componentInfo || {}; |
| 63 | - ~index && | ||
| 64 | - _dataSource.push({ | ||
| 65 | - ...value, | ||
| 66 | - componentInfo: { ...componentInfo }, | ||
| 67 | - }); | 64 | + _dataSource.push({ |
| 65 | + ...value, | ||
| 66 | + componentInfo: { ...componentInfo }, | ||
| 67 | + }); | ||
| 68 | } | 68 | } |
| 69 | return _dataSource; | 69 | return _dataSource; |
| 70 | }; | 70 | }; |
| @@ -113,19 +113,38 @@ | @@ -113,19 +113,38 @@ | ||
| 113 | }; | 113 | }; |
| 114 | 114 | ||
| 115 | const echoDataSource = () => { | 115 | const echoDataSource = () => { |
| 116 | - basicMethod.setFieldsValue(props.record); | ||
| 117 | - // dataSourceMethod.setFieldsValue(props.record); | 116 | + basicMethod.setFieldsValue(props.record.record); |
| 117 | + dataSource.value = []; | ||
| 118 | + dataSource.value = props.record.record.dataSource.map((item) => { | ||
| 119 | + const id = buildUUID(); | ||
| 120 | + | ||
| 121 | + dataSource.value.push({ | ||
| 122 | + id, | ||
| 123 | + ...item, | ||
| 124 | + }); | ||
| 125 | + | ||
| 126 | + nextTick(() => { | ||
| 127 | + (dataSourceEl[id] as FormActionType).setFieldsValue(item); | ||
| 128 | + }); | ||
| 129 | + return { | ||
| 130 | + id, | ||
| 131 | + ...item, | ||
| 132 | + }; | ||
| 133 | + }); | ||
| 118 | }; | 134 | }; |
| 119 | 135 | ||
| 136 | + watch( | ||
| 137 | + () => props.record, | ||
| 138 | + () => { | ||
| 139 | + if (Object.keys(props.record).length) echoDataSource(); | ||
| 140 | + } | ||
| 141 | + ); | ||
| 142 | + | ||
| 120 | const handleRowComponentInfo = (recordId: string, value: ComponentInfo) => { | 143 | const handleRowComponentInfo = (recordId: string, value: ComponentInfo) => { |
| 121 | const index = unref(dataSource).findIndex((item) => item.id === recordId); | 144 | const index = unref(dataSource).findIndex((item) => item.id === recordId); |
| 122 | ~index && (unref(dataSource)[index].componentInfo = value); | 145 | ~index && (unref(dataSource)[index].componentInfo = value); |
| 123 | }; | 146 | }; |
| 124 | 147 | ||
| 125 | - onMounted(() => { | ||
| 126 | - echoDataSource(); | ||
| 127 | - }); | ||
| 128 | - | ||
| 129 | defineExpose({ | 148 | defineExpose({ |
| 130 | getAllDataSourceFieldValue, | 149 | getAllDataSourceFieldValue, |
| 131 | }); | 150 | }); |
| @@ -179,7 +198,11 @@ | @@ -179,7 +198,11 @@ | ||
| 179 | <div class="text-center"> | 198 | <div class="text-center"> |
| 180 | <Button type="primary" @click="handleAdd">添加数据源</Button> | 199 | <Button type="primary" @click="handleAdd">添加数据源</Button> |
| 181 | </div> | 200 | </div> |
| 182 | - <VisualOptionsModal @close="handleRowComponentInfo" @register="registerVisualOptionModal" /> | 201 | + <VisualOptionsModal |
| 202 | + :value="props.frontId" | ||
| 203 | + @close="handleRowComponentInfo" | ||
| 204 | + @register="registerVisualOptionModal" | ||
| 205 | + /> | ||
| 183 | </section> | 206 | </section> |
| 184 | </template> | 207 | </template> |
| 185 | 208 |
| @@ -4,11 +4,12 @@ | @@ -4,11 +4,12 @@ | ||
| 4 | import BasicConfiguration from './BasicConfiguration.vue'; | 4 | import BasicConfiguration from './BasicConfiguration.vue'; |
| 5 | import VisualConfiguration from './VisualConfiguration.vue'; | 5 | import VisualConfiguration from './VisualConfiguration.vue'; |
| 6 | import { computed, ref, unref } from 'vue'; | 6 | import { computed, ref, unref } from 'vue'; |
| 7 | - import type { DataComponentRecord } from '/@/api/dataBoard/model'; | ||
| 8 | import { RouteParams, useRoute } from 'vue-router'; | 7 | import { RouteParams, useRoute } from 'vue-router'; |
| 9 | - import { addDataComponent, updateDataBoardLayout } from '/@/api/dataBoard'; | 8 | + import { addDataComponent, updateDataBoardLayout, updateDataComponent } from '/@/api/dataBoard'; |
| 10 | import { useModalInner } from '/@/components/Modal'; | 9 | import { useModalInner } from '/@/components/Modal'; |
| 11 | import { DEFAULT_WIDGET_HEIGHT, DEFAULT_WIDGET_WIDTH } from '../../config/config'; | 10 | import { DEFAULT_WIDGET_HEIGHT, DEFAULT_WIDGET_WIDTH } from '../../config/config'; |
| 11 | + import { DataBoardLayoutInfo } from '../../types/type'; | ||
| 12 | + import { useMessage } from '/@/hooks/web/useMessage'; | ||
| 12 | 13 | ||
| 13 | interface DataComponentRouteParams extends RouteParams { | 14 | interface DataComponentRouteParams extends RouteParams { |
| 14 | id: string; | 15 | id: string; |
| @@ -18,11 +19,7 @@ | @@ -18,11 +19,7 @@ | ||
| 18 | 19 | ||
| 19 | const ROUTE = useRoute(); | 20 | const ROUTE = useRoute(); |
| 20 | 21 | ||
| 21 | - const [register, { closeModal }] = useModalInner(); | ||
| 22 | - | ||
| 23 | - const basicConfigurationEl = ref<{ | ||
| 24 | - getAllDataSourceFieldValue: Fn<any, Recordable>; | ||
| 25 | - }>(); | 22 | + const { createMessage } = useMessage(); |
| 26 | 23 | ||
| 27 | const boardId = computed(() => { | 24 | const boardId = computed(() => { |
| 28 | return (ROUTE.params as DataComponentRouteParams).id; | 25 | return (ROUTE.params as DataComponentRouteParams).id; |
| @@ -30,12 +27,26 @@ | @@ -30,12 +27,26 @@ | ||
| 30 | 27 | ||
| 31 | const frontId = ref(''); | 28 | const frontId = ref(''); |
| 32 | 29 | ||
| 33 | - const componentRecord = ref<DataComponentRecord>({} as unknown as DataComponentRecord); | 30 | + const isEdit = ref(false); |
| 31 | + | ||
| 32 | + const componentRecord = ref<DataBoardLayoutInfo>({} as unknown as DataBoardLayoutInfo); | ||
| 33 | + | ||
| 34 | + const [register, { closeModal }] = useModalInner( | ||
| 35 | + (record: DataBoardLayoutInfo & { isEdit: boolean }) => { | ||
| 36 | + componentRecord.value = record; | ||
| 37 | + frontId.value = record.record.frontId; | ||
| 38 | + isEdit.value = record.isEdit; | ||
| 39 | + } | ||
| 40 | + ); | ||
| 41 | + | ||
| 42 | + const basicConfigurationEl = ref<{ | ||
| 43 | + getAllDataSourceFieldValue: Fn<any, Recordable>; | ||
| 44 | + }>(); | ||
| 34 | 45 | ||
| 35 | const handleSubmit = () => { | 46 | const handleSubmit = () => { |
| 36 | const { getAllDataSourceFieldValue } = unref(basicConfigurationEl)!; | 47 | const { getAllDataSourceFieldValue } = unref(basicConfigurationEl)!; |
| 37 | const value = getAllDataSourceFieldValue(); | 48 | const value = getAllDataSourceFieldValue(); |
| 38 | - handleAddComponent(value); | 49 | + unref(isEdit) ? handleUpdateComponent(value) : handleAddComponent(value); |
| 39 | }; | 50 | }; |
| 40 | 51 | ||
| 41 | const handleAddComponent = async (value: Recordable) => { | 52 | const handleAddComponent = async (value: Recordable) => { |
| @@ -44,6 +55,7 @@ | @@ -44,6 +55,7 @@ | ||
| 44 | boardId: unref(boardId), | 55 | boardId: unref(boardId), |
| 45 | record: { dataBoardId: unref(boardId), frontId: unref(frontId), ...value }, | 56 | record: { dataBoardId: unref(boardId), frontId: unref(frontId), ...value }, |
| 46 | }); | 57 | }); |
| 58 | + createMessage.success('创建成功'); | ||
| 47 | const id = data.data.id; | 59 | const id = data.data.id; |
| 48 | await updateDataBoardLayout({ | 60 | await updateDataBoardLayout({ |
| 49 | boardId: unref(boardId), | 61 | boardId: unref(boardId), |
| @@ -51,7 +63,28 @@ | @@ -51,7 +63,28 @@ | ||
| 51 | }); | 63 | }); |
| 52 | closeModal(); | 64 | closeModal(); |
| 53 | emit('submit'); | 65 | emit('submit'); |
| 54 | - } catch (error) {} | 66 | + } catch (error) { |
| 67 | + // createMessage.error('创建失败'); | ||
| 68 | + } | ||
| 69 | + }; | ||
| 70 | + | ||
| 71 | + const handleUpdateComponent = async (value: Recordable) => { | ||
| 72 | + try { | ||
| 73 | + await updateDataComponent({ | ||
| 74 | + boardId: unref(boardId), | ||
| 75 | + record: { | ||
| 76 | + id: unref(componentRecord).i, | ||
| 77 | + dataBoardId: unref(boardId), | ||
| 78 | + frontId: unref(frontId), | ||
| 79 | + ...value, | ||
| 80 | + }, | ||
| 81 | + }); | ||
| 82 | + createMessage.success('修改成功'); | ||
| 83 | + closeModal(); | ||
| 84 | + emit('submit'); | ||
| 85 | + } catch (error) { | ||
| 86 | + // createMessage.error('修改失败'); | ||
| 87 | + } | ||
| 55 | }; | 88 | }; |
| 56 | </script> | 89 | </script> |
| 57 | 90 | ||
| @@ -61,6 +94,7 @@ | @@ -61,6 +94,7 @@ | ||
| 61 | @register="register" | 94 | @register="register" |
| 62 | title="自定义组件" | 95 | title="自定义组件" |
| 63 | width="70%" | 96 | width="70%" |
| 97 | + destroy-on-close | ||
| 64 | @ok="handleSubmit" | 98 | @ok="handleSubmit" |
| 65 | > | 99 | > |
| 66 | <section> | 100 | <section> |
| @@ -3,6 +3,7 @@ | @@ -3,6 +3,7 @@ | ||
| 3 | import VisualWidgetSelect from './VisualWidgetSelect.vue'; | 3 | import VisualWidgetSelect from './VisualWidgetSelect.vue'; |
| 4 | import TextComponent from '../../components/TextComponent/TextComponent.vue'; | 4 | import TextComponent from '../../components/TextComponent/TextComponent.vue'; |
| 5 | import { textComponentConfig } from '../../components/TextComponent/config'; | 5 | import { textComponentConfig } from '../../components/TextComponent/config'; |
| 6 | + import { instrumentComponentConfig } from '../../components/InstrumentComponent'; | ||
| 6 | const props = defineProps<{ | 7 | const props = defineProps<{ |
| 7 | value: string; | 8 | value: string; |
| 8 | }>(); | 9 | }>(); |
| @@ -35,7 +36,22 @@ | @@ -35,7 +36,22 @@ | ||
| 35 | </List> | 36 | </List> |
| 36 | </Tabs.TabPane> | 37 | </Tabs.TabPane> |
| 37 | <Tabs.TabPane key="2" tab="仪表组件"> | 38 | <Tabs.TabPane key="2" tab="仪表组件"> |
| 38 | - <div>仪表组件</div> | 39 | + <List |
| 40 | + :grid="{ gutter: 10, column: 3, xs: 3, sm: 3, md: 3, lg: 3, xl: 3, xxl: 3 }" | ||
| 41 | + :data-source="instrumentComponentConfig" | ||
| 42 | + > | ||
| 43 | + <template #renderItem="{ item }"> | ||
| 44 | + <List.Item class="!flex !justify-center"> | ||
| 45 | + <VisualWidgetSelect | ||
| 46 | + :checked-id="props.value" | ||
| 47 | + :control-id="item.id" | ||
| 48 | + @change="handleCheck" | ||
| 49 | + > | ||
| 50 | + <component :is="item.component" :layout="item.layout" :value="item.value" /> | ||
| 51 | + </VisualWidgetSelect> | ||
| 52 | + </List.Item> | ||
| 53 | + </template> | ||
| 54 | + </List> | ||
| 39 | </Tabs.TabPane> | 55 | </Tabs.TabPane> |
| 40 | </Tabs> | 56 | </Tabs> |
| 41 | </section> | 57 | </section> |
| 1 | <script lang="ts" setup> | 1 | <script lang="ts" setup> |
| 2 | - import { onMounted, ref, unref } from 'vue'; | ||
| 3 | - import { modeOne, modeTwo, modeThree, modeFour } from '../config/visualOptions'; | 2 | + import { ref, unref } from 'vue'; |
| 3 | + import { WidgetComponentType, schemasMap } from '../config/visualOptions'; | ||
| 4 | import { useForm, BasicForm } from '/@/components/Form'; | 4 | import { useForm, BasicForm } from '/@/components/Form'; |
| 5 | import { BasicModal, useModalInner } from '/@/components/Modal'; | 5 | import { BasicModal, useModalInner } from '/@/components/Modal'; |
| 6 | import { ComponentInfo } from '/@/api/dataBoard/model'; | 6 | import { ComponentInfo } from '/@/api/dataBoard/model'; |
| 7 | + import { computed } from '@vue/reactivity'; | ||
| 7 | 8 | ||
| 8 | const emit = defineEmits(['close']); | 9 | const emit = defineEmits(['close']); |
| 9 | 10 | ||
| 11 | + const props = defineProps<{ | ||
| 12 | + value?: string; | ||
| 13 | + }>(); | ||
| 14 | + | ||
| 10 | const recordId = ref(''); | 15 | const recordId = ref(''); |
| 11 | 16 | ||
| 17 | + const getSchemas = computed(() => { | ||
| 18 | + return schemasMap.get((props.value as WidgetComponentType) || 'text-component-1'); | ||
| 19 | + }); | ||
| 20 | + | ||
| 12 | const [registerForm, method] = useForm({ | 21 | const [registerForm, method] = useForm({ |
| 13 | - schemas: modeTwo, | ||
| 14 | showActionButtonGroup: false, | 22 | showActionButtonGroup: false, |
| 15 | labelWidth: 120, | 23 | labelWidth: 120, |
| 16 | baseColProps: { | 24 | baseColProps: { |
| @@ -45,6 +53,6 @@ | @@ -45,6 +53,6 @@ | ||
| 45 | title="选项" | 53 | title="选项" |
| 46 | width="60%" | 54 | width="60%" |
| 47 | > | 55 | > |
| 48 | - <BasicForm @register="registerForm" /> | 56 | + <BasicForm @register="registerForm" :schemas="getSchemas" /> |
| 49 | </BasicModal> | 57 | </BasicModal> |
| 50 | </template> | 58 | </template> |
| 1 | +import { InstrumentComponentType } from '../../components/InstrumentComponent/dashBoardComponent.config'; | ||
| 2 | +import { DigitalDashBoardComponentType } from '../../components/InstrumentComponent/digitalDashBoard.config'; | ||
| 3 | +import { TextComponentType } from '../../components/TextComponent/config'; | ||
| 1 | import { FormSchema } from '/@/components/Form'; | 4 | import { FormSchema } from '/@/components/Form'; |
| 2 | export enum defaultOptions { | 5 | export enum defaultOptions { |
| 3 | fontColor = '#rer', | 6 | fontColor = '#rer', |
| 4 | } | 7 | } |
| 5 | 8 | ||
| 9 | +export type WidgetComponentType = | ||
| 10 | + | TextComponentType | ||
| 11 | + | InstrumentComponentType | ||
| 12 | + | DigitalDashBoardComponentType; | ||
| 13 | + | ||
| 6 | export enum visualOptionField { | 14 | export enum visualOptionField { |
| 7 | FONT_COLOR = 'fontColor', | 15 | FONT_COLOR = 'fontColor', |
| 8 | UNIT = 'unit', | 16 | UNIT = 'unit', |
| @@ -137,3 +145,13 @@ export const modeFour: FormSchema[] = [ | @@ -137,3 +145,13 @@ export const modeFour: FormSchema[] = [ | ||
| 137 | }, | 145 | }, |
| 138 | }, | 146 | }, |
| 139 | ]; | 147 | ]; |
| 148 | + | ||
| 149 | +export const schemasMap = new Map<WidgetComponentType, FormSchema[]>(); | ||
| 150 | + | ||
| 151 | +schemasMap.set('text-component-1', modeOne); | ||
| 152 | +schemasMap.set('text-component-2', modeOne); | ||
| 153 | +schemasMap.set('text-component-3', modeOne); | ||
| 154 | +schemasMap.set('text-component-4', modeTwo); | ||
| 155 | +schemasMap.set('text-component-4', modeTwo); | ||
| 156 | +schemasMap.set('instrument-component-1', modeOne); | ||
| 157 | +schemasMap.set('instrument-component-2', modeThree); |
| 1 | <script lang="ts" setup> | 1 | <script lang="ts" setup> |
| 2 | import { Button, PageHeader } from 'ant-design-vue'; | 2 | import { Button, PageHeader } from 'ant-design-vue'; |
| 3 | - import { GridItem, GridLayout, Layout } 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'; |
| 6 | import BaseWidgetHeader from '../components/WidgetHeader/BaseWidgetHeader.vue'; | 6 | import BaseWidgetHeader from '../components/WidgetHeader/BaseWidgetHeader.vue'; |
| 7 | import { DropMenu } from '/@/components/Dropdown'; | 7 | import { DropMenu } from '/@/components/Dropdown'; |
| 8 | import DataBindModal from './components/DataBindModal.vue'; | 8 | import DataBindModal from './components/DataBindModal.vue'; |
| 9 | import { useModal } from '/@/components/Modal'; | 9 | import { useModal } from '/@/components/Modal'; |
| 10 | - import { MoreActionEvent } from '../config/config'; | ||
| 11 | - import { deleteDataComponent, getDataComponent } from '/@/api/dataBoard'; | 10 | + import { DEFAULT_WIDGET_HEIGHT, DEFAULT_WIDGET_WIDTH, MoreActionEvent } from '../config/config'; |
| 11 | + import { | ||
| 12 | + addDataComponent, | ||
| 13 | + deleteDataComponent, | ||
| 14 | + getDataComponent, | ||
| 15 | + updateDataBoardLayout, | ||
| 16 | + } from '/@/api/dataBoard'; | ||
| 12 | import { useRoute } from 'vue-router'; | 17 | import { useRoute } from 'vue-router'; |
| 13 | import { computed, unref } from '@vue/reactivity'; | 18 | import { computed, unref } from '@vue/reactivity'; |
| 14 | - import { DataComponentRecord, DataSource, Layout as LayoutRecord } from '/@/api/dataBoard/model'; | 19 | + import { DataComponentRecord, DataSource } from '/@/api/dataBoard/model'; |
| 15 | import { frontComponentMap, FrontComponentType } from './config/help'; | 20 | import { frontComponentMap, FrontComponentType } from './config/help'; |
| 16 | import { useMessage } from '/@/hooks/web/useMessage'; | 21 | import { useMessage } from '/@/hooks/web/useMessage'; |
| 17 | - const handleBack = () => {}; | ||
| 18 | - | ||
| 19 | - type DataBoardRecord = DataComponentRecord & { layout: LayoutRecord }; | ||
| 20 | - | ||
| 21 | - type DataBoardLayoutInfo = Layout & { | ||
| 22 | - record: DataComponentRecord & { width: number; height: number }; | ||
| 23 | - }; | 22 | + import { DataBoardLayoutInfo } from '../types/type'; |
| 24 | 23 | ||
| 25 | const ROUTE = useRoute(); | 24 | const ROUTE = useRoute(); |
| 26 | 25 | ||
| 27 | - const { createMessage } = useMessage(); | 26 | + const { createMessage, createConfirm } = useMessage(); |
| 28 | const getBoardId = computed(() => { | 27 | const getBoardId = computed(() => { |
| 29 | return (ROUTE.params as { id: string }).id; | 28 | return (ROUTE.params as { id: string }).id; |
| 30 | }); | 29 | }); |
| @@ -74,7 +73,7 @@ | @@ -74,7 +73,7 @@ | ||
| 74 | height, | 73 | height, |
| 75 | }; | 74 | }; |
| 76 | }); | 75 | }); |
| 77 | - console.log(unref(dataBoardList)); | 76 | + |
| 78 | nextTick(() => { | 77 | nextTick(() => { |
| 79 | const updateFn = widgetEl.get(i); | 78 | const updateFn = widgetEl.get(i); |
| 80 | if (updateFn) updateFn(); | 79 | if (updateFn) updateFn(); |
| @@ -83,6 +82,7 @@ | @@ -83,6 +82,7 @@ | ||
| 83 | 82 | ||
| 84 | const itemResized = (i: string, newH: number, newW: number, newHPx: number, newWPx: number) => { | 83 | const itemResized = (i: string, newH: number, newW: number, newHPx: number, newWPx: number) => { |
| 85 | updateSize(i, newH, newW, newHPx, newWPx); | 84 | updateSize(i, newH, newW, newHPx, newWPx); |
| 85 | + console.log({ newH, newW, newHPx, newWPx }); | ||
| 86 | }; | 86 | }; |
| 87 | 87 | ||
| 88 | const itemContainerResized = ( | 88 | const itemContainerResized = ( |
| @@ -111,8 +111,15 @@ | @@ -111,8 +111,15 @@ | ||
| 111 | const [register, { openModal }] = useModal(); | 111 | const [register, { openModal }] = useModal(); |
| 112 | 112 | ||
| 113 | const handleMoreAction = (event: DropMenu, id: string) => { | 113 | const handleMoreAction = (event: DropMenu, id: string) => { |
| 114 | - if (event.event === MoreActionEvent.EDIT) openModal(true); | ||
| 115 | - if (event.event === MoreActionEvent.DELETE) handleDelete(id); | 114 | + if (event.event === MoreActionEvent.DELETE) { |
| 115 | + createConfirm({ | ||
| 116 | + iconType: 'warning', | ||
| 117 | + content: '是否确认删除?', | ||
| 118 | + onOk: () => handleDelete(id), | ||
| 119 | + }); | ||
| 120 | + } | ||
| 121 | + if (event.event === MoreActionEvent.EDIT) handleUpdate(id); | ||
| 122 | + if (event.event === MoreActionEvent.COPY) handleCopy(id); | ||
| 116 | }; | 123 | }; |
| 117 | 124 | ||
| 118 | const handleOpenCreatePanel = () => { | 125 | const handleOpenCreatePanel = () => { |
| @@ -124,7 +131,12 @@ | @@ -124,7 +131,12 @@ | ||
| 124 | const data = await getDataComponent(unref(getBoardId)); | 131 | const data = await getDataComponent(unref(getBoardId)); |
| 125 | dataBoardList.value = data.data.componentData.map((item) => { | 132 | dataBoardList.value = data.data.componentData.map((item) => { |
| 126 | const index = data.data.componentLayout.findIndex((each) => item.id === each.id); | 133 | const index = data.data.componentLayout.findIndex((each) => item.id === each.id); |
| 127 | - const layout = data.data.componentLayout[index]; | 134 | + let layout; |
| 135 | + if (!~index) { | ||
| 136 | + layout = {}; | ||
| 137 | + } else { | ||
| 138 | + layout = data.data.componentLayout[index]; | ||
| 139 | + } | ||
| 128 | return { | 140 | return { |
| 129 | i: item.id, | 141 | i: item.id, |
| 130 | w: layout.w || defaultWidth, | 142 | w: layout.w || defaultWidth, |
| @@ -138,6 +150,7 @@ | @@ -138,6 +150,7 @@ | ||
| 138 | }, | 150 | }, |
| 139 | }; | 151 | }; |
| 140 | }); | 152 | }); |
| 153 | + console.log(unref(dataBoardList)); | ||
| 141 | } catch (error) {} | 154 | } catch (error) {} |
| 142 | }; | 155 | }; |
| 143 | 156 | ||
| @@ -153,13 +166,40 @@ | @@ -153,13 +166,40 @@ | ||
| 153 | return component?.transformConfig(component.ComponentConfig, record, dataSourceRecord); | 166 | return component?.transformConfig(component.ComponentConfig, record, dataSourceRecord); |
| 154 | }; | 167 | }; |
| 155 | 168 | ||
| 169 | + const handleUpdate = async (id: string) => { | ||
| 170 | + const record = unref(dataBoardList).find((item) => item.i === id); | ||
| 171 | + openModal(true, { isEdit: true, ...record }); | ||
| 172 | + }; | ||
| 173 | + | ||
| 174 | + const handleCopy = async (id: string) => { | ||
| 175 | + const record = unref(dataBoardList).find((item) => item.i === id); | ||
| 176 | + console.log({ record }); | ||
| 177 | + try { | ||
| 178 | + const data = await addDataComponent({ | ||
| 179 | + boardId: unref(getBoardId), | ||
| 180 | + record: { | ||
| 181 | + dataBoardId: unref(getBoardId), | ||
| 182 | + frontId: record?.record.frontId, | ||
| 183 | + dataSource: record?.record.dataSource, | ||
| 184 | + }, | ||
| 185 | + }); | ||
| 186 | + createMessage.success('复制成功'); | ||
| 187 | + const id = data.data.id; | ||
| 188 | + await updateDataBoardLayout({ | ||
| 189 | + boardId: unref(getBoardId), | ||
| 190 | + layout: [{ id, w: DEFAULT_WIDGET_WIDTH, h: DEFAULT_WIDGET_HEIGHT, x: 0, y: 0 }], | ||
| 191 | + }); | ||
| 192 | + getDataBoardComponent(); | ||
| 193 | + } catch (error) {} | ||
| 194 | + }; | ||
| 195 | + | ||
| 156 | const handleDelete = async (id: string) => { | 196 | const handleDelete = async (id: string) => { |
| 157 | try { | 197 | try { |
| 158 | await deleteDataComponent([id]); | 198 | await deleteDataComponent([id]); |
| 159 | createMessage.success('删除成功'); | 199 | createMessage.success('删除成功'); |
| 160 | await getDataBoardComponent(); | 200 | await getDataBoardComponent(); |
| 161 | } catch (error) { | 201 | } catch (error) { |
| 162 | - createMessage.error('删除失败'); | 202 | + // createMessage.error('删除失败'); |
| 163 | } | 203 | } |
| 164 | }; | 204 | }; |
| 165 | 205 | ||
| @@ -170,11 +210,14 @@ | @@ -170,11 +210,14 @@ | ||
| 170 | 210 | ||
| 171 | <template> | 211 | <template> |
| 172 | <section class="bg-light-50 flex flex-col overflow-hidden h-full w-full"> | 212 | <section class="bg-light-50 flex flex-col overflow-hidden h-full w-full"> |
| 173 | - <PageHeader title="水电表看板" @back="handleBack"> | 213 | + <PageHeader title="水电表看板"> |
| 174 | <template #extra> | 214 | <template #extra> |
| 175 | <Button type="primary" @click="handleOpenCreatePanel">创建组件</Button> | 215 | <Button type="primary" @click="handleOpenCreatePanel">创建组件</Button> |
| 176 | </template> | 216 | </template> |
| 177 | - <div>已创建组件: 3个</div> | 217 | + <div> |
| 218 | + <span class="mr-3 text-gray-400">已创建组件:</span> | ||
| 219 | + <span class="text-cyan-400"> {{ dataBoardList.length }}个</span> | ||
| 220 | + </div> | ||
| 178 | </PageHeader> | 221 | </PageHeader> |
| 179 | <section class="flex-1"> | 222 | <section class="flex-1"> |
| 180 | <GridLayout | 223 | <GridLayout |
| @@ -159,7 +159,7 @@ | @@ -159,7 +159,7 @@ | ||
| 159 | {{ item.viewType === ViewType.PRIVATE_VIEW ? '私有看板' : '公共看板' }} | 159 | {{ item.viewType === ViewType.PRIVATE_VIEW ? '私有看板' : '公共看板' }} |
| 160 | </span> | 160 | </span> |
| 161 | <span v-if="item.viewType === ViewType.PUBLIC_VIEW"> | 161 | <span v-if="item.viewType === ViewType.PUBLIC_VIEW"> |
| 162 | - <Tooltip title="分享链接"> | 162 | + <Tooltip title="点击复制分享链接"> |
| 163 | <ShareAltOutlined class="ml-2" @click="handleCopyShareUrl(item)" /> | 163 | <ShareAltOutlined class="ml-2" @click="handleCopyShareUrl(item)" /> |
| 164 | </Tooltip> | 164 | </Tooltip> |
| 165 | </span> | 165 | </span> |