Commit 3020312f4209c8060a2bf2ce8a2de065a18317a2

Authored by xp.Huang
2 parents 57b99d85 971dc763

Merge branch 'ww' into 'main'

feat: visual board add control component

See merge request huang/yun-teng-iot-front!359
Showing 39 changed files with 772 additions and 560 deletions
src/views/visual/board/components/ControlComponent/SlidingSwitch.vue renamed from src/views/visual/board/components/Other/SlidingSwitch.vue
  1 +<script lang="ts">
  2 + export default {
  3 + inheritAttrs: false,
  4 + };
  5 +</script>
1 6 <script lang="ts" setup>
2   - const props = defineProps<{
3   - value?: boolean;
4   - }>();
  7 + import { RadioRecord } from '../../detail/config/util';
  8 +
  9 + interface VisualComponentProps<Layout = Recordable, Value = Recordable> {
  10 + value?: Value;
  11 + layout?: Layout;
  12 + radio?: RadioRecord;
  13 + random?: boolean;
  14 + add?: (key: string, method: Fn) => void;
  15 + update?: () => void;
  16 + remove?: (key: string) => void;
  17 + }
  18 + const props = defineProps<VisualComponentProps>();
5 19
6 20 const emit = defineEmits(['update:value', 'change']);
7 21
... ... @@ -14,7 +28,12 @@
14 28
15 29 <template>
16 30 <label class="sliding-switch">
17   - <input :value="props.value" type="checkbox" :checked="props.value" @change="handleChange" />
  31 + <input
  32 + :value="props.value?.value"
  33 + type="checkbox"
  34 + :checked="props.value?.value"
  35 + @change="handleChange"
  36 + />
18 37 <span class="slider"></span>
19 38 <span class="on">ON</span>
20 39 <span class="off">OFF</span>
... ... @@ -40,12 +59,9 @@
40 59 .slider {
41 60 width: 80px;
42 61 height: 40px;
  62 + display: flex;
  63 + align-items: center;
43 64 box-sizing: border-box;
44   - position: absolute;
45   - top: 0;
46   - left: 0;
47   - right: 0;
48   - bottom: 0;
49 65 border: 2px solid #ecf0f3;
50 66 border-radius: 20px;
51 67 box-shadow: -2px -2px 8px #fff, -2px -2px 12px hsl(0deg 0% 100% / 50%),
... ... @@ -57,15 +73,14 @@
57 73 }
58 74
59 75 .slider::after {
60   - position: absolute;
61 76 cursor: pointer;
62 77 display: block;
63 78 content: '';
64 79 width: 24px;
65 80 height: 24px;
66 81 border-radius: 50%;
67   - top: 6px;
68   - left: 6px;
  82 + margin-left: 6px;
  83 + margin-right: 6px;
69 84 background-color: #ecf0f3;
70 85 box-shadow: -2px -2px 8px #fff, -2px -2px 12px hsl(0deg 0% 100% / 50%),
71 86 inset 2px 2px 4px hsl(0deg 0% 100% / 10%), 2px 2px 8px rgb(0 0 0 / 30%);
... ... @@ -80,13 +95,16 @@
80 95 input:checked ~ .slider::after {
81 96 transform: translateX(35px);
82 97 }
  98 +
83 99 input:not(:checked) ~ .on {
84 100 opacity: 0;
85   - transform: translateX(0px);
  101 + transform: translateX(0);
86 102 }
87 103
88 104 .on,
89 105 .off {
  106 + position: absolute;
  107 + top: 0;
90 108 display: inline-block;
91 109 margin-left: 3px;
92 110 width: 34px;
... ... @@ -97,7 +115,9 @@
97 115 .on {
98 116 color: #039be5;
99 117 }
  118 +
100 119 .off {
  120 + right: 6px;
101 121 color: #999;
102 122 }
103 123 }
... ...
  1 +<script lang="ts">
  2 + export default {
  3 + inheritAttrs: false,
  4 + };
  5 +</script>
  6 +<script lang="ts" setup>
  7 + import { Switch } from 'ant-design-vue';
  8 + import { computed } from 'vue';
  9 + import { DEFAULT_RADIO_RECORD, fontSize, RadioRecord } from '../../detail/config/util';
  10 + import SvgIcon from '/@/components/Icon/src/SvgIcon.vue';
  11 + import {
  12 + ControlComponentDefaultConfig,
  13 + ControlComponentValue,
  14 + ControlComponentLayout,
  15 + } from './control.config';
  16 + const props = withDefaults(
  17 + defineProps<{
  18 + layout?: ControlComponentLayout;
  19 + value?: ControlComponentValue;
  20 + radio?: RadioRecord;
  21 + }>(),
  22 + {
  23 + value: () => ControlComponentDefaultConfig,
  24 + }
  25 + );
  26 + const getRadio = computed(() => {
  27 + return props.radio || DEFAULT_RADIO_RECORD;
  28 + });
  29 +</script>
  30 +
  31 +<template>
  32 + <div class="flex items-center w-full h-full p-4">
  33 + <div class="flex-auto flex truncate">
  34 + <SvgIcon
  35 + :name="props.value?.icon! || ControlComponentDefaultConfig.icon!"
  36 + prefix="iconfont"
  37 + :style="{
  38 + color: props.value?.iconColor || ControlComponentDefaultConfig.iconColor,
  39 + width: fontSize({ radioRecord: getRadio, basic: 30, min: 16 }),
  40 + height: fontSize({ radioRecord: getRadio, basic: 30, min: 16 }),
  41 + }"
  42 + />
  43 + <span class="flex-auto mx-4 flex items-center truncate inline-block">属性名</span>
  44 + </div>
  45 + <Switch />
  46 + </div>
  47 +</template>
... ...
src/views/visual/board/components/ControlComponent/ToggleSwitch.vue renamed from src/views/visual/board/components/Other/ToggleSwitch.vue
  1 +<script lang="ts">
  2 + export default {
  3 + inheritAttrs: false,
  4 + };
  5 +</script>
1 6 <script lang="ts" setup>
  7 + import { computed } from '@vue/reactivity';
  8 + import { DEFAULT_RADIO_RECORD, fontSize, RadioRecord } from '../../detail/config/util';
  9 + import { ControlComponentValue } from './control.config';
  10 +
2 11 const props = defineProps<{
3   - value?: boolean;
  12 + value?: ControlComponentValue;
  13 + layout?: Recordable;
  14 + radio?: RadioRecord;
4 15 }>();
5 16
6 17 const emit = defineEmits(['update:value', 'change']);
... ... @@ -10,12 +21,27 @@
10 21 emit('update:value', _value);
11 22 emit('change', _value);
12 23 };
  24 +
  25 + const getRadio = computed(() => {
  26 + return props.radio! || DEFAULT_RADIO_RECORD;
  27 + });
13 28 </script>
14 29
15 30 <template>
16   - <div class="toggle-switch">
  31 + <div
  32 + class="toggle-switch"
  33 + :style="{
  34 + width: fontSize({ radioRecord: getRadio, basic: 75, max: 75, min: 60 }),
  35 + height: fontSize({ radioRecord: getRadio, basic: 97.5, max: 97.5, min: 80 }),
  36 + }"
  37 + >
17 38 <label class="switch">
18   - <input :value="props.value" type="checkbox" :checked="props.value" @change="handleChange" />
  39 + <input
  40 + :value="props.value?.value"
  41 + type="checkbox"
  42 + :checked="props.value?.value"
  43 + @change="handleChange"
  44 + />
19 45 <div class="button">
20 46 <div class="light"></div>
21 47 <div class="dots"></div>
... ... @@ -29,9 +55,10 @@
29 55
30 56 <style scoped>
31 57 .toggle-switch {
32   - flex: 1 1 auto;
  58 + /* flex: 1 1 auto; */
33 59 max-width: 75px;
34   - height: 97.5px;
  60 +
  61 + /* height: 97.5px; */
35 62 display: flex;
36 63 }
37 64
... ... @@ -76,12 +103,12 @@
76 103 transform-origin: center center -20px;
77 104 transform: translateZ(20px) rotateX(-25deg);
78 105 transform-style: preserve-3d;
79   - background-color: #9b0621;
80 106 width: 100%;
81 107 height: 100%;
82 108 position: relative;
83 109 cursor: pointer;
84 110 background: linear-gradient(#980000 0%, #6f0000 30%, #6f0000 70%, #980000 100%);
  111 + background-color: #9b0621;
85 112 background-repeat: no-repeat;
86 113 }
87 114
... ... @@ -113,7 +140,7 @@
113 140 transform: translateY(30px) rotateX(-90deg);
114 141 position: absolute;
115 142 bottom: 0;
116   - box-shadow: 0 30px 8px 0px black, 0 60px 20px 0px rgb(0 0 0 / 50%);
  143 + box-shadow: 0 30px 8px 0 black, 0 60px 20px 0 rgb(0 0 0 / 50%);
117 144 }
118 145
119 146 .switch .light {
... ...
  1 +import { DataComponentRecord, DataSource } from '/@/api/dataBoard/model';
  2 +
  3 +export interface ControlComponentLayout {
  4 + [key: string]: any;
  5 +}
  6 +
  7 +export interface ControlComponentValue {
  8 + value?: boolean;
  9 + name?: string;
  10 + icon?: string;
  11 + iconColor?: string;
  12 +}
  13 +
  14 +export const ControlComponentDefaultConfig: ControlComponentValue = {
  15 + icon: 'shuiwen',
  16 + iconColor: '#367BFF',
  17 +};
  18 +
  19 +export const transformControlConfig = (
  20 + _ComponentConfig: Recordable,
  21 + _record: DataComponentRecord,
  22 + dataSourceRecord: DataSource
  23 +) => {
  24 + return {
  25 + value: {
  26 + value: dataSourceRecord.componentInfo.value,
  27 + icon: dataSourceRecord.componentInfo.icon,
  28 + } as ControlComponentValue,
  29 + };
  30 +};
... ...
  1 +<script lang="ts">
  2 + export default {
  3 + inheritAttrs: false,
  4 + };
  5 +</script>
1 6 <script lang="ts" setup>
2 7 import type { ECharts, EChartsOption } from 'echarts';
3 8 import { PropType, watch } from 'vue';
... ... @@ -7,21 +12,21 @@
7 12 DashboardComponentLayout,
8 13 DashBoardValue,
9 14 instrumentComponent1,
10   - InstrumentComponentType,
11 15 update_instrument_1_font,
12 16 update_instrument_2_font,
13 17 update_instrument_1_value,
14 18 update_instrument_2_value,
15 19 } from './dashBoardComponent.config';
16   - import { dateUtil } from '/@/utils/dateUtil';
17 20 import {
18 21 DEFAULT_RADIO_RECORD,
19 22 RadioRecord,
20   - DEFAULT_DATE_FORMAT,
21 23 fontSize,
  24 + getUpdateTime,
22 25 } from '../../detail/config/util';
23 26 import { Tooltip } from 'ant-design-vue';
24 27 import { useThrottleFn } from '@vueuse/shared';
  28 + import { buildUUID } from '/@/utils/uuid';
  29 + import { FrontComponent } from '../help';
25 30
26 31 const props = defineProps({
27 32 add: {
... ... @@ -33,7 +38,7 @@
33 38 },
34 39 value: {
35 40 type: Object as PropType<DashBoardValue>,
36   - default: () => ({}),
  41 + default: () => ({ id: buildUUID() }),
37 42 },
38 43 radio: {
39 44 type: Object as PropType<RadioRecord>,
... ... @@ -60,7 +65,6 @@
60 65 }
61 66
62 67 const getRadio = computed(() => {
63   - // const { radio } = props.radio;
64 68 return props.radio;
65 69 });
66 70
... ... @@ -68,7 +72,6 @@
68 72 const realWidth = unref(chartRef)?.getWidth();
69 73 const realHeight = unref(chartRef)?.getHeight();
70 74 const radioRecord = props.radio;
71   - // const widht
72 75 return {
73 76 ...radioRecord,
74 77 height: realHeight || radioRecord.height,
... ... @@ -76,7 +79,7 @@
76 79 };
77 80 });
78 81
79   - const beforeUpdateFn = (componentType: InstrumentComponentType) => {
  82 + const beforeUpdateFn = (componentType: FrontComponent) => {
80 83 if (componentType === 'instrument-component-1') return update_instrument_1_font;
81 84 if (componentType === 'instrument-component-2') return update_instrument_2_font;
82 85 return (_radio: RadioRecord) => {};
... ... @@ -88,7 +91,7 @@
88 91 unref(chartRef)?.resize();
89 92 }
90 93
91   - const getUpdateValueFn = (componentType: InstrumentComponentType) => {
  94 + const getUpdateValueFn = (componentType: FrontComponent) => {
92 95 if (componentType === 'instrument-component-1') return update_instrument_1_value;
93 96 if (componentType === 'instrument-component-2') return update_instrument_2_value;
94 97 return (_radio: DashBoardValue) => {};
... ... @@ -101,11 +104,6 @@
101 104
102 105 watch(() => props.value, updateChartValue);
103 106
104   - // watch(
105   - // () => [props.value.gradientInfo, props.value.unit, props.value.valueColor, props.value.name],
106   - // updateChartValue
107   - // );
108   -
109 107 const updateChartFont = useThrottleFn(() => {
110 108 const option = beforeUpdateFn(props.layout.componentType);
111 109 setTimeout(() => {
... ... @@ -122,8 +120,6 @@
122 120
123 121 watch(() => props.layout.componentType, updateChartType);
124 122
125   - // watch(() => props.value.gradientInfo, updateChartType);
126   -
127 123 let timeout: Nullable<number> = null;
128 124
129 125 function handleRandomValue() {
... ... @@ -170,22 +166,11 @@
170 166 color: '#999',
171 167 }"
172 168 >
173   - <Tooltip
174   - placement="top"
175   - :title="
176   - props.value?.updateTime
177   - ? dateUtil(props?.value?.updateTime).format(DEFAULT_DATE_FORMAT)
178   - : '暂无更新时间'
179   - "
180   - >
  169 + <Tooltip placement="top" :title="getUpdateTime(props.value?.updateTime)">
181 170 <div class="truncate">
182 171 <span class="mr-2">更新时间:</span>
183 172 <span>
184   - {{
185   - props.value?.updateTime
186   - ? dateUtil(props?.value?.updateTime).format(DEFAULT_DATE_FORMAT)
187   - : '暂无更新时间'
188   - }}
  173 + {{ getUpdateTime(props.value?.updateTime) }}
189 174 </span>
190 175 </div>
191 176 </Tooltip>
... ...
  1 +<script lang="ts">
  2 + export default {
  3 + inheritAttrs: false,
  4 + };
  5 +</script>
1 6 <script lang="ts" setup>
2 7 import { computed, onMounted, onUnmounted, ref, unref } from 'vue';
3 8 import { Space, Tooltip } from 'ant-design-vue';
... ... @@ -6,22 +11,27 @@
6 11 DigitalDashBoardLayout,
7 12 DigitalDashBoardValue,
8 13 } from './digitalDashBoard.config';
9   - import { dateUtil } from '/@/utils/dateUtil';
10 14 import {
11 15 fontSize,
12 16 RadioRecord,
13   - DEFAULT_DATE_FORMAT,
  17 + getUpdateTime,
14 18 DEFAULT_RADIO_RECORD,
15 19 DEFAULT_ANIMATION_INTERVAL,
16 20 } from '../../detail/config/util';
17 21 import { isNaN } from 'lodash';
18 22
19   - const props = defineProps<{
20   - layout: DigitalDashBoardLayout;
21   - value: DigitalDashBoardValue;
22   - radio?: RadioRecord;
23   - random?: boolean;
24   - }>();
  23 + const props = withDefaults(
  24 + defineProps<{
  25 + layout?: DigitalDashBoardLayout;
  26 + value?: DigitalDashBoardValue;
  27 + radio?: RadioRecord;
  28 + random?: boolean;
  29 + }>(),
  30 + {
  31 + value: () => ({}),
  32 + layout: () => ({ max: 5, keepNumber: 2 }),
  33 + }
  34 + );
25 35
26 36 const changeValue = ref(0);
27 37
... ... @@ -53,8 +63,6 @@
53 63 });
54 64
55 65 const getRadio = computed(() => {
56   - // const { radio } = props.radio || DEFAULT_RADIO_RECORD;
57   - // return radio;
58 66 return props.radio || DEFAULT_RADIO_RECORD;
59 67 });
60 68
... ... @@ -160,22 +168,11 @@
160 168 color: '#999',
161 169 }"
162 170 >
163   - <Tooltip
164   - placement="top"
165   - :title="
166   - props.value?.updateTime
167   - ? dateUtil(props?.value?.updateTime).format(DEFAULT_DATE_FORMAT)
168   - : '暂无更新时间'
169   - "
170   - >
  171 + <Tooltip placement="top" :title="getUpdateTime(props.value?.updateTime)">
171 172 <div class="truncate">
172 173 <span class="mr-1">更新时间:</span>
173 174 <span>
174   - {{
175   - props.value?.updateTime
176   - ? dateUtil(props?.value?.updateTime).format(DEFAULT_DATE_FORMAT)
177   - : '暂无更新时间'
178   - }}
  175 + {{ getUpdateTime(props.value?.updateTime) }}
179 176 </span>
180 177 </div>
181 178 </Tooltip>
... ... @@ -188,11 +185,12 @@
188 185 <style scoped lang="less">
189 186 .digital-wrapper__int {
190 187 border-radius: 1px;
191   - box-shadow: inset 0px 1px 3px 0px rgba(0, 0, 0, 0.7);
192   - background: url('/@/assets/images/digital-wrapper-bg-int.png') 0px -1px no-repeat;
  188 + box-shadow: inset 0 1px 3px 0 rgba(0, 0, 0, 0.7);
  189 + background: url('/@/assets/images/digital-wrapper-bg-int.png') 0 -1px no-repeat;
193 190 padding: 5px;
194 191 background-size: 100% 100%;
195 192 }
  193 +
196 194 .digital-text_int {
197 195 display: inline-block;
198 196 overflow-wrap: break-word;
... ... @@ -203,11 +201,12 @@
203 201
204 202 .digital-wrapper__float {
205 203 border-radius: 1px;
206   - box-shadow: inset 0px 1px 3px 0px rgba(112, 22, 15, 1);
207   - background: url('/@/assets/images/digital-wrapper-bg-float.png') 0px -1px no-repeat;
  204 + box-shadow: inset 0 1px 3px 0 rgba(112, 22, 15, 1);
  205 + background: url('/@/assets/images/digital-wrapper-bg-float.png') 0 -1px no-repeat;
208 206 padding: 5px;
209 207 background-size: 100% 100%;
210 208 }
  209 +
211 210 .digital-text_float {
212 211 display: inline-block;
213 212 overflow-wrap: break-word;
... ...
1 1 import { EChartsOption } from 'echarts';
  2 +import { FrontComponent, Gradient, GradientColor } from '../../const/const';
2 3 import { fontSize, RadioRecord } from '../../detail/config/util';
3   -import { Gradient, visualOptionField } from '../../detail/config/visualOptions';
4 4 import {
5 5 ComponentInfo,
6 6 DataComponentRecord,
... ... @@ -10,16 +10,6 @@ import {
10 10 import { isArray } from '/@/utils/is';
11 11 import { buildUUID } from '/@/utils/uuid';
12 12
13   -export type InstrumentComponentType = 'instrument-component-1' | 'instrument-component-2';
14   -
15   -export type GradientKey =
16   - | visualOptionField.FIRST_PHASE_COLOR
17   - | visualOptionField.FIRST_PHASE_VALUE
18   - | visualOptionField.SECOND_PHASE_COLOR
19   - | visualOptionField.SECOND_PHASE_VALUE
20   - | visualOptionField.THIRD_PHASE_COLOR
21   - | visualOptionField.THIRD_PHASE_VALUE;
22   -
23 13 export interface GradientInfoRecord {
24 14 key: Gradient;
25 15 value: number;
... ... @@ -38,13 +28,7 @@ export interface DashBoardValue {
38 28
39 29 export interface DashboardComponentLayout {
40 30 chartOption: EChartsOption;
41   - componentType: InstrumentComponentType;
42   -}
43   -
44   -export enum GradientColor {
45   - FIRST = '#67e0e3',
46   - SECOND = '#37a2da',
47   - THIRD = '#fd666d',
  31 + componentType: FrontComponent;
48 32 }
49 33
50 34 export const instrumentComponent1 = (params?: Partial<ComponentInfo>): EChartsOption => {
... ... @@ -94,7 +78,6 @@ export const instrumentComponent1 = (params?: Partial<ComponentInfo>): EChartsOp
94 78 axisLabel: {
95 79 distance: 0,
96 80 color: '#999',
97   - // fontSize: 20,
98 81 },
99 82 anchor: {
100 83 show: false,
... ... @@ -173,7 +156,6 @@ export const instrumentComponent2 = (params?: Partial<ComponentInfo>): EChartsOp
173 156
174 157 const firstGradient = firstRecord?.value ? firstRecord.value / max : 0.3;
175 158 const secondGradient = secondRecord?.value ? secondRecord.value / max : 0.7;
176   - // const thirdGradient = thirdRecord?.value ? thirdRecord.value / max : 1;
177 159
178 160 return {
179 161 series: [
... ... @@ -307,12 +289,15 @@ export const update_instrument_2_value = (params: DashBoardValue) => {
307 289
308 290 let max = thirdRecord?.value || secondRecord?.value || firstRecord?.value || 70;
309 291 max = Number(1 + Array(String(max).length).fill(0).join(''));
  292 + max = value > 1 ? Number(1 + Array(String(value).length).fill(0).join('')) / 2 : 100 / 2;
  293 + max = value > max ? max * 2 : max;
310 294
311 295 const firstGradient = firstRecord?.value ? firstRecord.value / max : 0.3;
312 296 const secondGradient = secondRecord?.value ? secondRecord.value / max : 0.7;
313 297 return {
314 298 series: [
315 299 {
  300 + max: max < 100 ? 100 : max,
316 301 data: [{ value: handleValue(value) }],
317 302 detail: {
318 303 formatter: `{value} ${unit ?? ''}`,
... ... @@ -354,7 +339,7 @@ export const Instrument2DefaultConfig: Partial<ComponentInfo> = {
354 339
355 340 export const transformDashboardComponentConfig = (
356 341 config: DashboardComponentLayout,
357   - record: DataComponentRecord,
  342 + _record: DataComponentRecord,
358 343 dataSourceRecord: DataSource
359 344 ) => {
360 345 let chartOption = config.chartOption;
... ...
1 1 import { ComponentInfo } from '/@/api/dataBoard/model';
2 2
3   -export type DigitalDashBoardComponentType = 'digital-dashboard-component';
4   -
5 3 export interface DigitalDashBoardLayout {
6 4 max: number;
7 5 keepNumber: number;
... ...
1 1 import { EChartsOption } from 'echarts';
2   -import { Component } from 'vue';
3   -import { WidgetComponentType } from '../../detail/config/visualOptions';
4   -import {
5   - Instrument1DefaultConfig,
6   - Instrument2DefaultConfig,
7   - instrumentComponent1,
8   - instrumentComponent2,
9   - InstrumentComponentType,
10   -} from './dashBoardComponent.config';
11   -import DashBoardComponent from './DashBoardComponent.vue';
12   -import DigitalDashBoard from './DigitalDashBoard.vue';
13   -import { buildUUID } from '/@/utils/uuid';
  2 +import { InstrumentComponentType } from './dashBoardComponent.config';
14 3
15 4 export interface DashboardComponentLayout {
16 5 chartOption: EChartsOption;
17 6 componentType: InstrumentComponentType;
18 7 }
19   -
20   -interface InstrumentComponentConfig {
21   - id: WidgetComponentType;
22   - layout: DashboardComponentLayout;
23   - component: Component;
24   - value: Recordable;
25   -}
26   -
27   -export const instrumentComponentConfig: InstrumentComponentConfig[] = [
28   - {
29   - id: 'instrument-component-1',
30   - layout: {
31   - chartOption: instrumentComponent1(Instrument1DefaultConfig),
32   - componentType: 'instrument-component-1',
33   - },
34   - component: DashBoardComponent,
35   - value: { id: buildUUID() },
36   - },
37   - {
38   - id: 'instrument-component-2',
39   - layout: {
40   - chartOption: instrumentComponent2(Instrument2DefaultConfig),
41   - componentType: 'instrument-component-2',
42   - },
43   - component: DashBoardComponent,
44   - value: { id: buildUUID() },
45   - },
46   - {
47   - id: 'digital-dashboard-component',
48   - layout: {},
49   - component: DigitalDashBoard,
50   - value: {},
51   - },
52   -];
... ...
  1 +<script lang="ts">
  2 + export default {
  3 + inheritAttrs: false,
  4 + };
  5 +</script>
  6 +<script lang="ts" setup>
  7 + import { nextTick, onMounted, ref, unref } from 'vue';
  8 + import { useScript } from '/@/hooks/web/useScript';
  9 + import { BAI_DU_MAP_URL } from '/@/utils/fnUtils';
  10 +
  11 + const wrapRef = ref<HTMLDivElement | null>(null);
  12 + const { toPromise } = useScript({ src: BAI_DU_MAP_URL });
  13 +
  14 + async function initMap() {
  15 + await toPromise();
  16 + await nextTick();
  17 + const wrapEl = unref(wrapRef);
  18 + if (!wrapEl) return;
  19 + const BMap = (window as any).BMap;
  20 + const map = new BMap.Map(wrapEl);
  21 + const point = new BMap.Point(116.404, 39.915);
  22 + map.centerAndZoom(point, 15);
  23 + map.enableScrollWheelZoom(true);
  24 + }
  25 +
  26 + onMounted(() => {
  27 + initMap();
  28 + });
  29 +</script>
  30 +
  31 +<template>
  32 + <div class="w-full h-full flex justify-center items-center">
  33 + <div ref="wrapRef" class="w-[95%] h-[95%]"></div>
  34 + </div>
  35 +</template>
... ...
  1 +import { ComponentConfig } from '../help';
  2 +
  3 +export const transfromMapComponentConfig: ComponentConfig['transformConfig'] = (
  4 + _componentConfig,
  5 + _record,
  6 + _dataSourceRecord
  7 +) => {
  8 + return {};
  9 +};
... ...
  1 +<script lang="ts">
  2 + export default {
  3 + inheritAttrs: false,
  4 + };
  5 +</script>
1 6 <script lang="ts" setup>
2 7 import { computed, ref, watch } from 'vue';
3 8 import { Tooltip, Image as AntImage } from 'ant-design-vue';
4 9 import {
5   - DEFAULT_DATE_FORMAT,
  10 + getUpdateTime,
6 11 DEFAULT_RADIO_RECORD,
7 12 fontSize,
8 13 RadioRecord,
9 14 } from '../../detail/config/util';
10   - import { PictureComponentLayout, PictureComponentValue } from './pictureComponent.config';
11   - import { dateUtil } from '/@/utils/dateUtil';
  15 + import { PictureComponentValue } from './pictureComponent.config';
12 16
13 17 const props = defineProps<{
14   - layout?: PictureComponentLayout;
  18 + layout?: Recordable;
15 19 value?: PictureComponentValue;
16 20 radio?: RadioRecord;
17 21 }>();
... ... @@ -22,8 +26,6 @@
22 26 const getImagBase64 = ref(fallback);
23 27
24 28 const getRadio = computed(() => {
25   - // const { radio } = props.radio || DEFAULT_RADIO_RECORD;
26   - // return radio;
27 29 return props.radio || DEFAULT_RADIO_RECORD;
28 30 });
29 31
... ... @@ -67,26 +69,14 @@
67 69 class="w-full h-full flex flex-col justify-center items-center justify-between widget-picture"
68 70 >
69 71 <AntImage :width="getWidth" :src="getImagBase64" :fallback="fallback" />
70   - <!-- <Image :style="{ width: `${getWidth}px` }" :src="getImagBase64" /> -->
71 72 <div
72 73 class="w-full text-center truncate p-5"
73 74 :style="{ fontSize: fontSize({ radioRecord: getRadio, basic: 12, max: 12 }), color: '#999' }"
74 75 >
75   - <Tooltip
76   - placement="top"
77   - :title="
78   - props.value?.updateTime
79   - ? dateUtil(props?.value?.updateTime).format(DEFAULT_DATE_FORMAT)
80   - : '暂无更新时间'
81   - "
82   - >
  76 + <Tooltip placement="top" :title="getUpdateTime(props.value?.updateTime)">
83 77 <span class="mr-1">更新时间:</span>
84 78 <span class="truncate">
85   - {{
86   - props.value?.updateTime
87   - ? dateUtil(props?.value?.updateTime).format(DEFAULT_DATE_FORMAT)
88   - : '暂无更新时间'
89   - }}
  79 + {{ getUpdateTime(props.value?.updateTime) }}
90 80 </span>
91 81 </Tooltip>
92 82 </div>
... ...
1 1 import PictureComponent from './PictureComponent.vue';
2 2
3   -import { PictureComponentType } from './pictureComponent.config';
4   -import { Component } from 'vue';
5   -
6   -interface PictureComponentList {
7   - id: PictureComponentType;
8   - component: Component;
9   -}
10   -// {
11   -// id: 'instrument-component-1',
12   -// layout: { chartOption: instrumentComponent1() },
13   -// component: DashBoardComponent,
14   -// value: { id: buildUUID() },
15   -// }
16   -const pictureComponentList: PictureComponentList[] = [
17   - {
18   - id: 'picture-component-1',
19   - component: PictureComponent,
20   - },
21   -];
22   -
23   -export { PictureComponent, pictureComponentList };
  3 +export { PictureComponent };
... ...
1 1 import { DataComponentRecord, DataSource } from '/@/api/dataBoard/model';
2 2
3   -export type PictureComponentType = 'picture-component-1';
4   -
5   -export interface PictureComponentLayout {}
6   -
7 3 export interface PictureComponentValue {
8 4 value?: string;
9 5 updateTime?: string;
10 6 }
11 7
12 8 export const transformPictureConfig = (
13   - config: PictureComponentLayout,
14   - record: DataComponentRecord,
  9 + _config: Recordable,
  10 + _record: DataComponentRecord,
15 11 dataSourceRecord: DataSource
16 12 ) => {
17 13 const componentInfo = dataSourceRecord.componentInfo;
... ...
  1 +<script lang="ts">
  2 + export default {
  3 + inheritAttrs: false,
  4 + };
  5 +</script>
1 6 <script lang="ts" setup>
2 7 import { computed } from 'vue';
3 8 import { Statistic, Tooltip } from 'ant-design-vue';
4 9 import {
  10 + getUpdateTime,
5 11 fontSize,
6 12 RadioRecord,
7 13 DEFAULT_RADIO_RECORD,
8   - DEFAULT_DATE_FORMAT,
9 14 } from '../../detail/config/util';
10 15 import { TextComponentDefaultConfig, TextComponentLayout, TextComponentValue } from './config';
11 16 import { SvgIcon } from '/@/components/Icon';
12   - import { dateUtil } from '/@/utils/dateUtil';
13 17 const props = defineProps({
14 18 layout: {
15 19 type: Object as PropType<TextComponentLayout>,
... ... @@ -47,8 +51,6 @@
47 51 });
48 52
49 53 const getRadio = computed(() => {
50   - // const { radio } = props.radio;
51   - // return radio;
52 54 return props.radio || DEFAULT_RADIO_RECORD;
53 55 });
54 56 </script>
... ... @@ -84,37 +86,21 @@
84 86 />
85 87 </div>
86 88 <div :style="{ color: '#666', fontSize: fontSize({ radioRecord: getRadio, basic: 16 }) }">
87   - <!-- {{ getShowUnit ? props.value.unit : '' }} -->
88 89 {{ props.value.name }}
89 90 </div>
90   - <!-- <div class="truncate" :style="{ fontSize: fontSize({ radio: getRadio, basic: 16 }) }">
91   - {{ props.value.name }}
92   - </div> -->
93 91 </div>
94 92 </div>
95 93 </div>
96 94
97 95 <div class="text-center text-xs truncate p-5" style="color: #999">
98   - <Tooltip
99   - v-if="getShowUpdate"
100   - placement="top"
101   - :title="
102   - props.value?.updateTime
103   - ? dateUtil(props?.value?.updateTime).format(DEFAULT_DATE_FORMAT)
104   - : '暂无更新时间'
105   - "
106   - >
  96 + <Tooltip v-if="getShowUpdate" placement="top" :title="getUpdateTime(props.value?.updateTime)">
107 97 <div
108 98 :style="{ fontSize: fontSize({ radioRecord: getRadio, basic: 12, max: 12 }) }"
109 99 class="truncate"
110 100 >
111 101 <span class="mr-1">更新时间:</span>
112 102 <span class="truncate">
113   - {{
114   - props.value?.updateTime
115   - ? dateUtil(props?.value?.updateTime).format(DEFAULT_DATE_FORMAT)
116   - : '暂无更新时间'
117   - }}
  103 + {{ getUpdateTime(props.value?.updateTime) }}
118 104 </span>
119 105 </div>
120 106 </Tooltip>
... ...
... ... @@ -18,13 +18,6 @@ export interface TextComponentValue {
18 18 deviceName?: 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   -
28 21 type TextComponentDefault = TextComponentLayout;
29 22
30 23 export const TextComponent1Config: TextComponentDefault = {
... ... @@ -32,10 +25,6 @@ export const TextComponent1Config: TextComponentDefault = {
32 25 base: true,
33 26 };
34 27
35   -export const TextComponent2Config: TextComponentDefault = {
36   - id: 'text-component-2',
37   - base: false,
38   -};
39 28 export const TextComponent3Config: TextComponentDefault = {
40 29 id: 'text-component-3',
41 30 base: false,
... ... @@ -62,17 +51,9 @@ export const TextComponentDefaultConfig: Partial<ComponentInfo> = {
62 51 icon: 'shuiwen',
63 52 };
64 53
65   -export const textComponentConfig: TextComponentDefault[] = [
66   - TextComponent1Config,
67   - // TextComponent2Config,
68   - TextComponent3Config,
69   - TextComponent4Config,
70   - TextComponent5Config,
71   -];
72   -
73 54 export const transformTextComponentConfig = (
74 55 config: TextComponentDefault,
75   - record: DataComponentRecord,
  56 + _record: DataComponentRecord,
76 57 dataSourceRecord: DataSource
77 58 ) => {
78 59 return {
... ...
... ... @@ -3,8 +3,11 @@
3 3 import { DropMenu } from '/@/components/Dropdown';
4 4 import Dropdown from '/@/components/Dropdown/src/Dropdown.vue';
5 5 import { Tooltip } from 'ant-design-vue';
6   - // import SvgIcon from '/@/components/Icon/src/SvgIcon.vue';
7   - import { isBataBoardSharePage, MoreActionEvent } from '../../config/config';
  6 + import {
  7 + isBataBoardSharePage,
  8 + MoreActionEvent,
  9 + VisualComponentPermission,
  10 + } from '../../config/config';
8 11 import { computed } from '@vue/reactivity';
9 12 import { usePermission } from '/@/hooks/web/usePermission';
10 13 import { DataSource } from '/@/api/dataBoard/model';
... ... @@ -19,9 +22,9 @@
19 22 const { hasPermission } = usePermission();
20 23 const dropMenuList = computed<DropMenu[]>(() => {
21 24 const basicMenu: DropMenu[] = [];
22   - const hasUpdatePermission = hasPermission('api:yt:data_component:update:update');
23   - const hasDeletePermission = hasPermission('api:yt:data_component:delete');
24   - const hasCopyPermission = hasPermission('api:yt:dataBoardDetail:copy');
  25 + const hasUpdatePermission = hasPermission(VisualComponentPermission.UPDATE);
  26 + const hasDeletePermission = hasPermission(VisualComponentPermission.DELETE);
  27 + const hasCopyPermission = hasPermission(VisualComponentPermission.COPY);
25 28 if (hasUpdatePermission)
26 29 basicMenu.push({
27 30 text: '编辑组件',
... ... @@ -69,7 +72,6 @@
69 72 >
70 73 <Tooltip :title="item.deviceName" placement="topLeft">
71 74 <div class="flex p-1">
72   - <!-- <SvgIcon name="" prefix="iconfont" class="!fill-emerald-400" /> -->
73 75 <div class="truncate font-bold">{{ item.deviceRename || item.deviceName }}</div>
74 76 </div>
75 77 </Tooltip>
... ...
1 1 <script lang="ts" setup>
2   - import { useSlots } from 'vue';
3 2 import { useUpdateCenter } from '../../hook/useUpdateCenter';
4 3 import { FrontDataSourceRecord } from '../../types/type';
5   - // import type { WidgetWrapperRegister } from './type';
6   - // import { DataSource } from '/@/api/dataBoard/model';
7 4
8 5 const props = defineProps<{
9 6 dataSource: FrontDataSourceRecord[];
10 7 }>();
11 8
12   - const slot = useSlots();
13   -
14 9 const { update, add, remove } = useUpdateCenter();
15 10
16 11 defineExpose({ update });
... ... @@ -20,7 +15,7 @@
20 15 <section class="widget">
21 16 <slot name="header"></slot>
22 17
23   - <div class="widget-content" :style="{ height: slot.header ? 'calc(100% - 22px)' : '100%' }">
  18 + <div class="widget-content">
24 19 <div
25 20 v-for="item in props.dataSource"
26 21 :key="item.id"
... ... @@ -28,10 +23,7 @@
28 23 class="widget-item"
29 24 >
30 25 <div class="widget-box">
31   - <div
32   - class="widget-controls-container"
33   - :style="{ height: slot.footer ? 'calc(100% - 20px)' : '100%' }"
34   - >
  26 + <div class="widget-controls-container">
35 27 <slot
36 28 name="controls"
37 29 :record="item"
... ... @@ -40,12 +32,6 @@
40 32 :update="update"
41 33 ></slot>
42 34 </div>
43   - <div class="widget-value">
44   - <slot name="value" :record="item"></slot>
45   - </div>
46   - <div class="widget-label">
47   - <slot name="label" :record="item"></slot>
48   - </div>
49 35 </div>
50 36 </div>
51 37 </div>
... ... @@ -61,14 +47,14 @@
61 47 height: 100%;
62 48 background-color: #fff;
63 49 border-radius: 3px;
64   - box-shadow: 0px 1px 10px 0px rgba(0, 0, 0, 0.1);
  50 + box-shadow: 0 1px 10px 0 rgba(0, 0, 0, 0.1);
65 51 }
  52 +
66 53 .widget-content {
67 54 display: flex;
68 55 flex-wrap: wrap;
69 56 justify-content: center;
70 57 align-items: center;
71   -
72 58 width: 100%;
73 59 height: 100%;
74 60 }
... ... @@ -94,7 +80,7 @@
94 80 .widget-controls-container {
95 81 flex: 1 1 auto;
96 82 width: 100%;
97   - height: calc(100% - 20px);
  83 + height: 100%;
98 84 display: flex;
99 85 align-items: center;
100 86 justify-content: center;
... ...
1   -// import { DataBoardLayoutInfo } from '../../types/type';
2   -
3   -// export type WidgetWrapperRegister = (dataSource: DataBoardLayoutInfo['record'][]) => any;
  1 +import {
  2 + TextComponent1Config,
  3 + TextComponent3Config,
  4 + TextComponent4Config,
  5 + TextComponent5Config,
  6 + TextComponentDefaultConfig,
  7 + transformTextComponentConfig,
  8 +} from './TextComponent/config';
  9 +import { ComponentInfo } from '/@/api/dataBoard/model';
  10 +import { transformPictureConfig } from './PictureComponent/pictureComponent.config';
  11 +import {
  12 + DashboardComponentLayout,
  13 + Instrument1DefaultConfig,
  14 + Instrument2DefaultConfig,
  15 + instrumentComponent1,
  16 + instrumentComponent2,
  17 + transformDashboardComponentConfig,
  18 +} from './InstrumentComponent/dashBoardComponent.config';
  19 +import { DigitalComponentDefaultConfig } from './InstrumentComponent/digitalDashBoard.config';
  20 +import { transformControlConfig } from './ControlComponent/control.config';
  21 +
  22 +import TextComponent from './TextComponent/TextComponent.vue';
  23 +import DashBoardComponent from './InstrumentComponent/DashBoardComponent.vue';
  24 +import PictureComponent from './PictureComponent/PictureComponent.vue';
  25 +import DigitalDashBoard from './InstrumentComponent/DigitalDashBoard.vue';
  26 +import ToggleSwitch from './ControlComponent/ToggleSwitch.vue';
  27 +import SlidingSwitch from './ControlComponent/SlidingSwitch.vue';
  28 +import SwitchWithIcon from './ControlComponent/SwitchWithIcon.vue';
  29 +import MapComponent from './MapComponent/MapComponent.vue';
  30 +import { transfromMapComponentConfig } from './MapComponent/map.config';
  31 +import { ComponentConfig } from '../types/type';
  32 +import { FrontComponent, FrontComponentCategory } from '../const/const';
  33 +
  34 +export const frontComponentDefaultConfigMap = new Map<FrontComponent, Partial<ComponentInfo>>();
  35 +
  36 +export const frontComponentMap = new Map<FrontComponent, ComponentConfig>();
  37 +
  38 +frontComponentMap.set(FrontComponent.TEXT_COMPONENT_1, {
  39 + Component: TextComponent,
  40 + ComponentName: '文本组件1',
  41 + ComponentKey: FrontComponent.TEXT_COMPONENT_1,
  42 + ComponentConfig: TextComponent1Config,
  43 + ComponentCategory: FrontComponentCategory.TEXT,
  44 + transformConfig: transformTextComponentConfig,
  45 +});
  46 +
  47 +frontComponentMap.set(FrontComponent.TEXT_COMPONENT_3, {
  48 + Component: TextComponent,
  49 + ComponentName: '文本组件2',
  50 + ComponentKey: FrontComponent.TEXT_COMPONENT_3,
  51 + ComponentConfig: TextComponent3Config,
  52 + ComponentCategory: FrontComponentCategory.TEXT,
  53 + transformConfig: transformTextComponentConfig,
  54 +});
  55 +
  56 +frontComponentMap.set(FrontComponent.TEXT_COMPONENT_4, {
  57 + Component: TextComponent,
  58 + ComponentName: '文本组件3',
  59 + ComponentKey: FrontComponent.TEXT_COMPONENT_4,
  60 + ComponentConfig: TextComponent4Config,
  61 + ComponentCategory: FrontComponentCategory.TEXT,
  62 + transformConfig: transformTextComponentConfig,
  63 +});
  64 +
  65 +frontComponentMap.set(FrontComponent.TEXT_COMPONENT_5, {
  66 + Component: TextComponent,
  67 + ComponentName: '文本组件4',
  68 + ComponentKey: FrontComponent.TEXT_COMPONENT_5,
  69 + ComponentConfig: TextComponent5Config,
  70 + ComponentCategory: FrontComponentCategory.TEXT,
  71 + transformConfig: transformTextComponentConfig,
  72 +});
  73 +
  74 +frontComponentMap.set(FrontComponent.INSTRUMENT_COMPONENT_1, {
  75 + Component: DashBoardComponent,
  76 + ComponentName: '仪表盘',
  77 + ComponentKey: FrontComponent.INSTRUMENT_COMPONENT_1,
  78 + ComponentConfig: {
  79 + chartOption: instrumentComponent1(Instrument1DefaultConfig),
  80 + componentType: FrontComponent.INSTRUMENT_COMPONENT_1,
  81 + } as DashboardComponentLayout,
  82 + ComponentCategory: FrontComponentCategory.INSTRUMENT,
  83 + transformConfig: transformDashboardComponentConfig,
  84 +});
  85 +
  86 +frontComponentMap.set(FrontComponent.INSTRUMENT_COMPONENT_2, {
  87 + Component: DashBoardComponent,
  88 + ComponentName: '阶段仪表盘',
  89 + ComponentKey: FrontComponent.INSTRUMENT_COMPONENT_2,
  90 + ComponentConfig: {
  91 + chartOption: instrumentComponent2(Instrument2DefaultConfig),
  92 + componentType: FrontComponent.INSTRUMENT_COMPONENT_2,
  93 + } as DashboardComponentLayout,
  94 + ComponentCategory: FrontComponentCategory.INSTRUMENT,
  95 + transformConfig: transformDashboardComponentConfig,
  96 +});
  97 +
  98 +frontComponentMap.set(FrontComponent.DIGITAL_DASHBOARD_COMPONENT, {
  99 + Component: DigitalDashBoard,
  100 + ComponentName: '数字仪表盘',
  101 + ComponentKey: FrontComponent.DIGITAL_DASHBOARD_COMPONENT,
  102 + ComponentCategory: FrontComponentCategory.INSTRUMENT,
  103 + transformConfig: transformDashboardComponentConfig,
  104 +});
  105 +
  106 +frontComponentMap.set(FrontComponent.PICTURE_COMPONENT_1, {
  107 + Component: PictureComponent,
  108 + ComponentName: '图片组件',
  109 + ComponentKey: FrontComponent.PICTURE_COMPONENT_1,
  110 + ComponentCategory: FrontComponentCategory.PICTURE,
  111 + transformConfig: transformPictureConfig,
  112 +});
  113 +
  114 +frontComponentMap.set(FrontComponent.CONTROL_COMPONENT_SWITCH_WITH_ICON, {
  115 + Component: SwitchWithIcon,
  116 + ComponentName: '控制按钮1',
  117 + ComponentKey: FrontComponent.CONTROL_COMPONENT_SWITCH_WITH_ICON,
  118 + ComponentCategory: FrontComponentCategory.CONTROL,
  119 + transformConfig: transformControlConfig,
  120 +});
  121 +
  122 +frontComponentMap.set(FrontComponent.CONTROL_COMPONENT_SLIDING_SWITCH, {
  123 + Component: SlidingSwitch,
  124 + ComponentName: '控制按钮2',
  125 + ComponentKey: FrontComponent.CONTROL_COMPONENT_SLIDING_SWITCH,
  126 + ComponentCategory: FrontComponentCategory.CONTROL,
  127 + transformConfig: transformControlConfig,
  128 +});
  129 +
  130 +frontComponentMap.set(FrontComponent.CONTROL_COMPONENT_TOGGLE_SWITCH, {
  131 + Component: ToggleSwitch,
  132 + ComponentName: '控制按钮3',
  133 + ComponentKey: FrontComponent.CONTROL_COMPONENT_TOGGLE_SWITCH,
  134 + ComponentCategory: FrontComponentCategory.CONTROL,
  135 + transformConfig: transformControlConfig,
  136 +});
  137 +
  138 +frontComponentMap.set(FrontComponent.MAP_COMPONENT_TRACK, {
  139 + Component: MapComponent,
  140 + ComponentName: '实时轨迹',
  141 + ComponentKey: FrontComponent.MAP_COMPONENT_TRACK,
  142 + ComponentCategory: FrontComponentCategory.MAP,
  143 + transformConfig: transfromMapComponentConfig,
  144 +});
  145 +
  146 +frontComponentDefaultConfigMap.set(FrontComponent.TEXT_COMPONENT_1, TextComponentDefaultConfig);
  147 +frontComponentDefaultConfigMap.set(FrontComponent.TEXT_COMPONENT_3, TextComponentDefaultConfig);
  148 +frontComponentDefaultConfigMap.set(FrontComponent.TEXT_COMPONENT_4, TextComponentDefaultConfig);
  149 +frontComponentDefaultConfigMap.set(FrontComponent.TEXT_COMPONENT_5, TextComponentDefaultConfig);
  150 +
  151 +frontComponentDefaultConfigMap.set(FrontComponent.INSTRUMENT_COMPONENT_1, Instrument1DefaultConfig);
  152 +frontComponentDefaultConfigMap.set(FrontComponent.INSTRUMENT_COMPONENT_2, Instrument2DefaultConfig);
  153 +
  154 +frontComponentDefaultConfigMap.set(
  155 + FrontComponent.DIGITAL_DASHBOARD_COMPONENT,
  156 + DigitalComponentDefaultConfig
  157 +);
  158 +
  159 +export const getComponentDefaultConfig = (key: FrontComponent) => {
  160 + return frontComponentDefaultConfigMap.get(key) || {};
  161 +};
... ...
1   -import { Component } from 'vue';
2   -import IndicatorLight from '../cpns/IndicatorLight.vue';
3   -
4   -export const dashboardComponentMap = new Map<string, Component>();
5   -
6   -dashboardComponentMap.set('IndicatorLight', IndicatorLight);
... ... @@ -4,7 +4,19 @@ export enum MoreActionEvent {
4 4 DELETE = 'delete',
5 5 }
6 6
7   -// export enum
  7 +export enum VisualBoardPermission {
  8 + UPDATE = 'api:yt:data_board:update:update',
  9 + DELETE = 'api:yt:data_board:delete',
  10 + CREATE = '',
  11 + DETAIL = 'api:yt:data_component:list',
  12 +}
  13 +
  14 +export enum VisualComponentPermission {
  15 + UPDATE = 'api:yt:data_component:update:update',
  16 + DELETE = 'api:yt:data_component:delete',
  17 + COPY = 'api:yt:dataBoardDetail:copy',
  18 + CREATE = 'api:yt:data_component:add:post',
  19 +}
8 20
9 21 export const DEFAULT_MAX_COL = 24;
10 22 export const DEFAULT_WIDGET_WIDTH = 6;
... ...
  1 +export enum FrontComponentCategory {
  2 + TEXT = 'text',
  3 + PICTURE = 'picture',
  4 + INSTRUMENT = 'instrument',
  5 + CONTROL = 'control',
  6 + MAP = 'map',
  7 +}
  8 +
  9 +export const FrontComponentCategoryName = {
  10 + [FrontComponentCategory.TEXT]: '文本组件',
  11 + [FrontComponentCategory.INSTRUMENT]: '仪表组件',
  12 + [FrontComponentCategory.CONTROL]: '控制组件',
  13 + [FrontComponentCategory.PICTURE]: '图片组件',
  14 + [FrontComponentCategory.MAP]: '地图组件',
  15 +};
  16 +
  17 +export enum FrontComponent {
  18 + TEXT_COMPONENT_1 = 'text-component-1',
  19 + TEXT_COMPONENT_2 = 'text-component-2',
  20 + TEXT_COMPONENT_3 = 'text-component-3',
  21 + TEXT_COMPONENT_4 = 'text-component-4',
  22 + TEXT_COMPONENT_5 = 'text-component-5',
  23 + INSTRUMENT_COMPONENT_1 = 'instrument-component-1',
  24 + INSTRUMENT_COMPONENT_2 = 'instrument-component-2',
  25 + DIGITAL_DASHBOARD_COMPONENT = 'digital-dashboard-component',
  26 + PICTURE_COMPONENT_1 = 'picture-component-1',
  27 + CONTROL_COMPONENT_TOGGLE_SWITCH = 'control-component-toggle-switch',
  28 + CONTROL_COMPONENT_SWITCH_WITH_ICON = 'control-component-switch-with-icon',
  29 + CONTROL_COMPONENT_SLIDING_SWITCH = 'control-component-sliding-switch',
  30 + MAP_COMPONENT_TRACK = 'map-component-track',
  31 +}
  32 +
  33 +export enum Gradient {
  34 + FIRST = 'first',
  35 + SECOND = 'second',
  36 + THIRD = 'third',
  37 +}
  38 +export enum GradientColor {
  39 + FIRST = '#67e0e3',
  40 + SECOND = '#37a2da',
  41 + THIRD = '#fd666d',
  42 +}
  43 +
  44 +export enum visualOptionField {
  45 + FONT_COLOR = 'fontColor',
  46 + UNIT = 'unit',
  47 + ICON_COLOR = 'iconColor',
  48 + ICON = 'icon',
  49 + FIRST_PHASE_COLOR = 'firstPhaseColor',
  50 + SECOND_PHASE_COLOR = 'secondPhaseColor',
  51 + THIRD_PHASE_COLOR = 'thirdPhaseColor',
  52 + FIRST_PHASE_VALUE = 'firstPhaseValue',
  53 + SECOND_PHASE_VALUE = 'secondPhaseValue',
  54 + THIRD_PHASE_VALUE = 'thirdPhaseValue',
  55 +}
... ...
... ... @@ -2,17 +2,17 @@
2 2 import { CopyOutlined, DeleteOutlined, SettingOutlined } from '@ant-design/icons-vue';
3 3 import { Tooltip, Button } from 'ant-design-vue';
4 4 import { FormActionType, useForm } from '/@/components/Form';
5   - import { basicSchema, dataSourceSchema } from '../config/basicConfiguration';
  5 + import { basicSchema } from '../config/basicConfiguration';
6 6 import BasicForm from '/@/components/Form/src/BasicForm.vue';
7   - import { ref, shallowReactive, unref, nextTick, watch } from 'vue';
  7 + import { ref, shallowReactive, unref, nextTick, watch, computed } from 'vue';
8 8 import VisualOptionsModal from './VisualOptionsModal.vue';
9 9 import { useModal } from '/@/components/Modal';
10 10 import { buildUUID } from '/@/utils/uuid';
11 11 import type { ComponentInfo, DataSource } from '/@/api/dataBoard/model';
12 12 import { useMessage } from '/@/hooks/web/useMessage';
13 13 import { DataBoardLayoutInfo } from '../../types/type';
14   - import { FrontComponent } from '../config/help';
15   - import { computed } from '@vue/reactivity';
  14 + import { getDataSourceComponent } from './DataSourceForm/help';
  15 + import { FrontComponent } from '../../const/const';
16 16
17 17 type DataSourceFormEL = { [key: string]: Nullable<FormActionType> };
18 18
... ... @@ -20,7 +20,7 @@
20 20
21 21 const props = defineProps<{
22 22 record: DataBoardLayoutInfo;
23   - frontId?: string;
  23 + frontId?: FrontComponent;
24 24 defaultConfig?: Partial<ComponentInfo>;
25 25 }>();
26 26
... ... @@ -39,7 +39,7 @@
39 39 const dataSourceEl = shallowReactive<DataSourceFormEL>({} as unknown as DataSourceFormEL);
40 40
41 41 const setFormEl = (el: any, id: string) => {
42   - if (!dataSourceEl[id] && el) {
  42 + if (id && el) {
43 43 const { formActionType } = el as unknown as { formActionType: FormActionType };
44 44 dataSourceEl[id] = formActionType;
45 45 }
... ... @@ -112,8 +112,6 @@
112 112 return;
113 113 }
114 114
115   - // const defaultConfig = getComponentDefaultConfig(props.frontId as WidgetComponentType);
116   -
117 115 const componentInfo: ComponentInfo = {
118 116 ...(props.defaultConfig || {}),
119 117 ...(item.componentInfo || {}),
... ... @@ -177,6 +175,10 @@
177 175 ~index && (unref(dataSource)[index].componentInfo = value);
178 176 };
179 177
  178 + const dataSourceComponent = computed(() => {
  179 + return getDataSourceComponent(props.frontId as FrontComponent);
  180 + });
  181 +
180 182 defineExpose({
181 183 getAllDataSourceFieldValue,
182 184 validate,
... ... @@ -198,17 +200,8 @@
198 200 选择设备
199 201 </div>
200 202 <div class="pl-2 flex-auto">
201   - <BasicForm
202   - :ref="(el) => setFormEl(el, item.id)"
203   - :schemas="dataSourceSchema"
204   - class="w-full flex-1 data-source-form"
205   - :show-action-button-group="false"
206   - :row-props="{
207   - gutter: 10,
208   - }"
209   - layout="inline"
210   - :label-col="{ span: 0 }"
211   - />
  203 + <!-- <BasicDataSourceForm /> -->
  204 + <component :is="dataSourceComponent" :ref="(el) => setFormEl(el, item.id)" />
212 205 </div>
213 206 <div class="flex justify-center gap-3 w-24">
214 207 <Tooltip title="复制">
... ...
... ... @@ -12,7 +12,7 @@
12 12 import { decode } from '../../config/config';
13 13 import { ComponentInfo } from '/@/api/dataBoard/model';
14 14 import { useCalcGridLayout } from '../../hook/useCalcGridLayout';
15   - import { FrontComponent } from '../config/help';
  15 + import { FrontComponent } from '../../const/const';
16 16
17 17 interface DataComponentRouteParams extends RouteParams {
18 18 id: string;
... ... @@ -23,7 +23,6 @@
23 23 }>();
24 24
25 25 const emit = defineEmits(['update', 'create', 'register']);
26   -
27 26 const ROUTE = useRoute();
28 27
29 28 const { createMessage } = useMessage();
... ... @@ -62,11 +61,15 @@
62 61 };
63 62
64 63 const handleSubmit = async () => {
65   - const { getAllDataSourceFieldValue, validate } = unref(basicConfigurationEl)!;
66   - await validate();
67   - const value = getAllDataSourceFieldValue();
68   - unref(isEdit) ? handleUpdateComponent(value) : handleAddComponent(value);
69   - resetForm();
  64 + try {
  65 + const { getAllDataSourceFieldValue, validate } = unref(basicConfigurationEl)!;
  66 + await validate();
  67 + const value = getAllDataSourceFieldValue();
  68 + unref(isEdit) ? handleUpdateComponent(value) : handleAddComponent(value);
  69 + resetForm();
  70 + } catch (error: unknown) {
  71 + window.console.error(error);
  72 + }
70 73 };
71 74
72 75 const { calcLayoutInfo } = useCalcGridLayout();
... ... @@ -133,7 +136,7 @@
133 136 >
134 137 <section>
135 138 <Tabs type="card">
136   - <Tabs.TabPane key="1" tab="基础配置">
  139 + <Tabs.TabPane key="basicConfig" tab="基础配置">
137 140 <BasicConfiguration
138 141 ref="basicConfigurationEl"
139 142 :front-id="frontId"
... ... @@ -141,7 +144,7 @@
141 144 :defaultConfig="componentDefaultConfig"
142 145 />
143 146 </Tabs.TabPane>
144   - <Tabs.TabPane key="2" tab="可视化配置">
  147 + <Tabs.TabPane key="visualConfig" tab="可视化配置">
145 148 <VisualConfiguration v-model:value="frontId" @change="handleComponentCheckedChange" />
146 149 </Tabs.TabPane>
147 150 </Tabs>
... ...
  1 +<script lang="ts" setup>
  2 + import { ref } from 'vue';
  3 + import { dataSourceSchema } from '../../config/basicConfiguration';
  4 + import { FormActionType } from '/@/components/Form';
  5 + import BasicForm from '/@/components/Form/src/BasicForm.vue';
  6 + const formEl = ref<Nullable<FormActionType>>(null);
  7 +
  8 + defineExpose({ formActionType: formEl });
  9 +</script>
  10 +
  11 +<template>
  12 + <BasicForm
  13 + ref="formEl"
  14 + :schemas="dataSourceSchema"
  15 + class="w-full flex-1 data-source-form"
  16 + :show-action-button-group="false"
  17 + :row-props="{
  18 + gutter: 10,
  19 + }"
  20 + layout="inline"
  21 + :label-col="{ span: 0 }"
  22 + />
  23 +</template>
... ...
  1 +<script lang="ts" setup>
  2 + import { ref, unref } from 'vue';
  3 + import { BasicForm, FormActionType } from '/@/components/Form';
  4 + import { controlFormSchema } from '../../config/basicConfiguration';
  5 +
  6 + const formEl = ref<Nullable<FormActionType>>();
  7 +
  8 + const setFormEl = (el: any) => {
  9 + formEl.value = el;
  10 + };
  11 +
  12 + const getFieldsValue = () => {
  13 + return unref(formEl)!.getFieldsValue();
  14 + };
  15 +
  16 + const validate = async () => {
  17 + await unref(formEl)!.validate();
  18 + };
  19 +
  20 + const setFieldsValue = async (record: Recordable) => {
  21 + await unref(formEl)!.setFieldsValue(record);
  22 + };
  23 +
  24 + const clearValidate = async (name?: string | string[]) => {
  25 + await unref(formEl)!.clearValidate(name);
  26 + };
  27 + defineExpose({
  28 + formActionType: { getFieldsValue, validate, setFieldsValue, clearValidate },
  29 + });
  30 +</script>
  31 +
  32 +<template>
  33 + <div class="w-full flex-1">
  34 + <BasicForm
  35 + :ref="(el) => setFormEl(el)"
  36 + :schemas="controlFormSchema"
  37 + class="w-full flex-1 data-source-form"
  38 + :show-action-button-group="false"
  39 + :row-props="{
  40 + gutter: 10,
  41 + }"
  42 + layout="inline"
  43 + :label-col="{ span: 0 }"
  44 + />
  45 + </div>
  46 +</template>
... ...
  1 +import { Component } from 'vue';
  2 +import { FrontComponent } from '../../../const/const';
  3 +import BasicDataSourceForm from './BasicDataSourceForm.vue';
  4 +import ControlDataSourceForm from './ControlDataSourceForm.vue';
  5 +
  6 +const dataSourceComponentMap = new Map<FrontComponent, Component>();
  7 +
  8 +dataSourceComponentMap.set(FrontComponent.CONTROL_COMPONENT_TOGGLE_SWITCH, ControlDataSourceForm);
  9 +
  10 +export const getDataSourceComponent = (frontId: FrontComponent) => {
  11 + if (dataSourceComponentMap.has(frontId)) return dataSourceComponentMap.get(frontId)!;
  12 + return BasicDataSourceForm;
  13 +};
... ...
1 1 <script lang="ts" setup>
2 2 import { Tabs, List } from 'ant-design-vue';
3 3 import VisualWidgetSelect from './VisualWidgetSelect.vue';
4   - import TextComponent from '../../components/TextComponent/TextComponent.vue';
5   - import { textComponentConfig } from '../../components/TextComponent/config';
6   - import { instrumentComponentConfig } from '../../components/InstrumentComponent';
7   - import { pictureComponentList } from '../../components/PictureComponent';
8   - import { getComponentDefaultConfig } from '../config/help';
9   - import { WidgetComponentType } from '../config/visualOptions';
  4 + import { getComponentDefaultConfig } from '../../components/help';
  5 + import { frontComponentMap } from '../../components/help';
  6 + import { computed } from 'vue';
  7 + import {
  8 + FrontComponent,
  9 + FrontComponentCategory,
  10 + FrontComponentCategoryName,
  11 + } from '../../const/const';
  12 +
  13 + interface DataSource {
  14 + category: string;
  15 + categoryName: string;
  16 + list: Recordable[];
  17 + }
10 18 const props = defineProps<{
11 19 value: string;
12 20 }>();
... ... @@ -14,7 +22,25 @@
14 22
15 23 const grid = { gutter: 10, column: 1, xs: 1, sm: 2, md: 2, lg: 3, xl: 3, xxl: 4 };
16 24
17   - const handleCheck = (checked: WidgetComponentType) => {
  25 + const getDataSource = computed(() => {
  26 + const _dataSource = Array.from(frontComponentMap.values());
  27 + const category = new Map<FrontComponentCategory, DataSource>();
  28 + for (const item of _dataSource) {
  29 + if (category.has(item.ComponentCategory)) {
  30 + const value = category.get(item.ComponentCategory)!;
  31 + value.list.push(item);
  32 + continue;
  33 + }
  34 + category.set(item.ComponentCategory, {
  35 + category: item.ComponentCategory,
  36 + categoryName: FrontComponentCategoryName[item.ComponentCategory],
  37 + list: [item],
  38 + });
  39 + }
  40 + return Array.from(category.values());
  41 + });
  42 +
  43 + const handleCheck = (checked: FrontComponent) => {
18 44 const defaultConfig = getComponentDefaultConfig(checked);
19 45 emit('update:value', checked);
20 46 emit('change', defaultConfig);
... ... @@ -24,51 +50,25 @@
24 50 <template>
25 51 <section>
26 52 <Tabs>
27   - <Tabs.TabPane key="1" tab="文本组件">
28   - <List :grid="grid" :data-source="textComponentConfig">
29   - <template #renderItem="{ item }">
30   - <List.Item class="!flex !justify-center">
31   - <VisualWidgetSelect
32   - :checked-id="props.value"
33   - :control-id="item.id"
34   - @change="handleCheck"
35   - >
36   - <TextComponent :layout="item" :value="item.value" />
37   - </VisualWidgetSelect>
38   - </List.Item>
39   - </template>
40   - </List>
41   - </Tabs.TabPane>
42   - <Tabs.TabPane key="2" tab="图片组件">
43   - <List :grid="grid" :data-source="pictureComponentList">
44   - <template #renderItem="{ item }">
45   - <List.Item class="!flex !justify-center">
46   - <VisualWidgetSelect
47   - :checked-id="props.value"
48   - :control-id="item.id"
49   - @change="handleCheck"
50   - >
51   - <component :is="item.component" />
52   - </VisualWidgetSelect>
53   - </List.Item>
54   - </template>
55   - </List>
56   - </Tabs.TabPane>
57   - <Tabs.TabPane key="3" tab="仪表组件">
58   - <List :grid="grid" :data-source="instrumentComponentConfig">
  53 + <Tabs.TabPane
  54 + v-for="category in getDataSource"
  55 + :key="category.category"
  56 + :tab="category.categoryName"
  57 + >
  58 + <List :grid="grid" :data-source="category.list">
59 59 <template #renderItem="{ item }">
60 60 <List.Item class="!flex !justify-center">
61 61 <VisualWidgetSelect
62 62 :checked-id="props.value"
63   - :control-id="item.id"
  63 + :control-id="item.ComponentKey"
64 64 @change="handleCheck"
65 65 >
66   - <component
67   - :is="item.component"
68   - :random="true"
69   - :layout="item.layout"
70   - :value="item.value"
71   - />
  66 + <template #default>
  67 + <component :is="item.Component" :random="true" :layout="item.ComponentConfig" />
  68 + </template>
  69 + <template #description>
  70 + {{ item.ComponentName || '选择' }}
  71 + </template>
72 72 </VisualWidgetSelect>
73 73 </List.Item>
74 74 </template>
... ...
1 1 <script lang="ts" setup>
2 2 import { ref, unref } from 'vue';
3   - import {
4   - WidgetComponentType,
5   - schemasMap,
6   - VisualOptionParams,
7   - visualOptionField,
8   - Gradient,
9   - } from '../config/visualOptions';
  3 + import { schemasMap, VisualOptionParams } from '../config/visualOptions';
10 4 import { useForm, BasicForm } from '/@/components/Form';
11 5 import { BasicModal, useModalInner } from '/@/components/Modal';
12 6 import { ComponentInfo } from '/@/api/dataBoard/model';
13 7 import { computed } from '@vue/reactivity';
  8 + import { FrontComponent, Gradient, visualOptionField } from '../../const/const';
14 9
15 10 const emit = defineEmits(['close', 'register']);
16 11
... ... @@ -21,7 +16,7 @@
21 16 const recordId = ref('');
22 17
23 18 const getSchemas = computed(() => {
24   - return schemasMap.get((props.value as WidgetComponentType) || 'text-component-1');
  19 + return schemasMap.get((props.value as FrontComponent) || 'text-component-1');
25 20 });
26 21
27 22 const [registerForm, method] = useForm({
... ...
... ... @@ -30,16 +30,19 @@
30 30 <slot></slot>
31 31 </div>
32 32 <Card.Meta>
33   - <template #description> 选择 </template>
  33 + <template #description>
  34 + <slot name="description"></slot>
  35 + </template>
34 36 </Card.Meta>
35 37 </Card>
36 38 </template>
37 39
38 40 <style scoped>
39 41 .widget-select {
40   - box-shadow: 0px 1px 10px 0px rgba(0, 0, 0, 0.1);
  42 + box-shadow: 0 1px 10px 0 rgba(0, 0, 0, 0.1);
41 43 border-width: 2px;
42 44 }
  45 +
43 46 .widget-select:deep(.ant-card-body) {
44 47 /* height: 240px; */
45 48 width: 240px;
... ...
... ... @@ -217,3 +217,24 @@ export const dataSourceSchema: FormSchema[] = [
217 217 },
218 218 },
219 219 ];
  220 +
  221 +export const controlFormSchema: FormSchema[] = [
  222 + {
  223 + field: DataSourceField.DEVICE_RENAME,
  224 + component: 'Input',
  225 + label: '设备',
  226 + colProps: { span: 8 },
  227 + componentProps: {
  228 + placeholder: '设备重命名',
  229 + },
  230 + },
  231 + {
  232 + field: DataSourceField.ATTRIBUTE_RENAME,
  233 + component: 'Input',
  234 + label: '属性',
  235 + colProps: { span: 8 },
  236 + componentProps: {
  237 + placeholder: '属性重命名',
  238 + },
  239 + },
  240 +];
... ...
1   -import { Component } from 'vue';
2   -import TextComponent from '../../components/TextComponent/TextComponent.vue';
3   -import {
4   - TextComponent1Config,
5   - TextComponent2Config,
6   - TextComponent3Config,
7   - TextComponent4Config,
8   - TextComponent5Config,
9   - TextComponentDefaultConfig,
10   - transformTextComponentConfig,
11   -} from '../../components/TextComponent/config';
12   -import { ComponentInfo, DataComponentRecord, DataSource } from '/@/api/dataBoard/model';
13   -import DashBoardComponent from '../../components/InstrumentComponent/DashBoardComponent.vue';
14   -import PictureComponent from '../../components/PictureComponent/PictureComponent.vue';
15   -import { transformPictureConfig } from '../../components/PictureComponent/pictureComponent.config';
16   -import { WidgetComponentType } from './visualOptions';
17   -import {
18   - DashboardComponentLayout,
19   - Instrument1DefaultConfig,
20   - Instrument2DefaultConfig,
21   - instrumentComponent1,
22   - instrumentComponent2,
23   - transformDashboardComponentConfig,
24   -} from '../../components/InstrumentComponent/dashBoardComponent.config';
25   -import DigitalDashBoard from '../../components/InstrumentComponent/DigitalDashBoard.vue';
26   -import { DigitalComponentDefaultConfig } from '../../components/InstrumentComponent/digitalDashBoard.config';
27   -export enum FrontComponent {
28   - TEXT_COMPONENT_1 = 'text-component-1',
29   - TEXT_COMPONENT_2 = 'text-component-2',
30   - TEXT_COMPONENT_3 = 'text-component-3',
31   - TEXT_COMPONENT_4 = 'text-component-4',
32   - TEXT_COMPONENT_5 = 'text-component-5',
33   - INSTRUMENT_COMPONENT_1 = 'instrument-component-1',
34   - INSTRUMENT_COMPONENT_2 = 'instrument-component-2',
35   - DIGITAL_DASHBOARD_COMPONENT = 'digital-dashboard-component',
36   - PICTURE_COMPONENT_1 = 'picture-component-1',
37   -}
38   -
39   -export interface ComponentConfig {
40   - Component: Component;
41   - ComponentConfig: Recordable;
42   - transformConfig: (
43   - ComponentConfig: Recordable,
44   - record: DataComponentRecord,
45   - dataSourceRecord: DataSource
46   - ) => Recordable;
47   -}
48   -
49   -export const frontComponentDefaultConfigMap = new Map<
50   - WidgetComponentType,
51   - Partial<ComponentInfo>
52   ->();
53   -
54   -export const frontComponentMap = new Map<WidgetComponentType, ComponentConfig>();
55   -
56   -frontComponentMap.set(FrontComponent.TEXT_COMPONENT_1, {
57   - Component: TextComponent,
58   - ComponentConfig: TextComponent1Config,
59   - transformConfig: transformTextComponentConfig,
60   -});
61   -
62   -frontComponentMap.set(FrontComponent.TEXT_COMPONENT_2, {
63   - Component: TextComponent,
64   - ComponentConfig: TextComponent2Config,
65   - transformConfig: transformTextComponentConfig,
66   -});
67   -
68   -frontComponentMap.set(FrontComponent.TEXT_COMPONENT_3, {
69   - Component: TextComponent,
70   - ComponentConfig: TextComponent3Config,
71   - transformConfig: transformTextComponentConfig,
72   -});
73   -
74   -frontComponentMap.set(FrontComponent.TEXT_COMPONENT_4, {
75   - Component: TextComponent,
76   - ComponentConfig: TextComponent4Config,
77   - transformConfig: transformTextComponentConfig,
78   -});
79   -
80   -frontComponentMap.set(FrontComponent.TEXT_COMPONENT_5, {
81   - Component: TextComponent,
82   - ComponentConfig: TextComponent5Config,
83   - transformConfig: transformTextComponentConfig,
84   -});
85   -
86   -frontComponentMap.set(FrontComponent.INSTRUMENT_COMPONENT_1, {
87   - Component: DashBoardComponent,
88   - ComponentConfig: {
89   - chartOption: instrumentComponent1(),
90   - componentType: FrontComponent.INSTRUMENT_COMPONENT_1,
91   - } as DashboardComponentLayout,
92   - transformConfig: transformDashboardComponentConfig,
93   -});
94   -
95   -frontComponentMap.set(FrontComponent.INSTRUMENT_COMPONENT_2, {
96   - Component: DashBoardComponent,
97   - ComponentConfig: {
98   - chartOption: instrumentComponent2(),
99   - componentType: FrontComponent.INSTRUMENT_COMPONENT_2,
100   - } as DashboardComponentLayout,
101   - transformConfig: transformDashboardComponentConfig,
102   -});
103   -
104   -frontComponentMap.set(FrontComponent.DIGITAL_DASHBOARD_COMPONENT, {
105   - Component: DigitalDashBoard,
106   - ComponentConfig: {},
107   - transformConfig: transformDashboardComponentConfig,
108   -});
109   -
110   -frontComponentMap.set(FrontComponent.PICTURE_COMPONENT_1, {
111   - Component: PictureComponent,
112   - ComponentConfig: {},
113   - transformConfig: transformPictureConfig,
114   -});
115   -
116   -frontComponentDefaultConfigMap.set(FrontComponent.TEXT_COMPONENT_1, TextComponentDefaultConfig);
117   -frontComponentDefaultConfigMap.set(FrontComponent.TEXT_COMPONENT_2, TextComponentDefaultConfig);
118   -frontComponentDefaultConfigMap.set(FrontComponent.TEXT_COMPONENT_3, TextComponentDefaultConfig);
119   -frontComponentDefaultConfigMap.set(FrontComponent.TEXT_COMPONENT_4, TextComponentDefaultConfig);
120   -frontComponentDefaultConfigMap.set(FrontComponent.TEXT_COMPONENT_5, TextComponentDefaultConfig);
121   -
122   -frontComponentDefaultConfigMap.set(FrontComponent.INSTRUMENT_COMPONENT_1, Instrument1DefaultConfig);
123   -frontComponentDefaultConfigMap.set(FrontComponent.INSTRUMENT_COMPONENT_2, Instrument2DefaultConfig);
124   -
125   -frontComponentDefaultConfigMap.set(
126   - FrontComponent.DIGITAL_DASHBOARD_COMPONENT,
127   - DigitalComponentDefaultConfig
128   -);
129   -
130   -export const getComponentDefaultConfig = (key: WidgetComponentType) => {
131   - return frontComponentDefaultConfigMap.get(key) || {};
132   -};
  1 +import { dateUtil } from '/@/utils/dateUtil';
  2 +
1 3 export interface RadioRecord {
2 4 width: number;
3 5 height: number;
... ... @@ -16,6 +18,10 @@ export const DEFAULT_RADIO_RECORD: RadioRecord = {
16 18
17 19 export const DEFAULT_DATE_FORMAT = 'YYYY-MM-DD HH:mm:ss';
18 20
  21 +export const getUpdateTime = (updateTime?: string) => {
  22 + return updateTime ? dateUtil(updateTime).format(DEFAULT_DATE_FORMAT) : '暂无更新时间';
  23 +};
  24 +
19 25 export const calcScale = (
20 26 width: number,
21 27 height: number,
... ...
1   -import { InstrumentComponentType } from '../../components/InstrumentComponent/dashBoardComponent.config';
2   -import { DigitalDashBoardComponentType } from '../../components/InstrumentComponent/digitalDashBoard.config';
3   -import { PictureComponentType } from '../../components/PictureComponent/pictureComponent.config';
4   -import { TextComponentType } from '../../components/TextComponent/config';
  1 +import { FrontComponent, GradientColor } from '../../const/const';
5 2 import { FormSchema } from '/@/components/Form';
6 3
7   -export type WidgetComponentType =
8   - | TextComponentType
9   - | InstrumentComponentType
10   - | DigitalDashBoardComponentType
11   - | PictureComponentType;
12   -
13 4 export interface VisualOptionParams {
14 5 [visualOptionField.FONT_COLOR]: string;
15 6 [visualOptionField.UNIT]: string;
... ... @@ -23,17 +14,6 @@ export interface VisualOptionParams {
23 14 [visualOptionField.THIRD_PHASE_VALUE]: string;
24 15 }
25 16
26   -export enum Gradient {
27   - FIRST = 'first',
28   - SECOND = 'second',
29   - THIRD = 'third',
30   -}
31   -export enum GradientColor {
32   - FIRST = '#67e0e3',
33   - SECOND = '#37a2da',
34   - THIRD = '#fd666d',
35   -}
36   -
37 17 export enum visualOptionField {
38 18 FONT_COLOR = 'fontColor',
39 19 UNIT = 'unit',
... ... @@ -198,13 +178,13 @@ export const modeFour: FormSchema[] = [
198 178 },
199 179 ];
200 180
201   -export const schemasMap = new Map<WidgetComponentType, FormSchema[]>();
  181 +export const schemasMap = new Map<FrontComponent, FormSchema[]>();
202 182
203   -schemasMap.set('text-component-1', modeOne);
204   -schemasMap.set('text-component-2', modeOne);
205   -schemasMap.set('text-component-3', modeOne);
206   -schemasMap.set('text-component-4', modeTwo);
207   -schemasMap.set('text-component-5', modeTwo);
208   -schemasMap.set('instrument-component-1', modeOne);
209   -schemasMap.set('instrument-component-2', modeThree);
210   -schemasMap.set('digital-dashboard-component', modeFour);
  183 +schemasMap.set(FrontComponent.TEXT_COMPONENT_1, modeOne);
  184 +schemasMap.set(FrontComponent.TEXT_COMPONENT_2, modeOne);
  185 +schemasMap.set(FrontComponent.TEXT_COMPONENT_3, modeOne);
  186 +schemasMap.set(FrontComponent.TEXT_COMPONENT_4, modeTwo);
  187 +schemasMap.set(FrontComponent.TEXT_COMPONENT_5, modeTwo);
  188 +schemasMap.set(FrontComponent.INSTRUMENT_COMPONENT_1, modeOne);
  189 +schemasMap.set(FrontComponent.INSTRUMENT_COMPONENT_2, modeThree);
  190 +schemasMap.set(FrontComponent.DIGITAL_DASHBOARD_COMPONENT, modeFour);
... ...
... ... @@ -16,6 +16,7 @@
16 16 DEFAULT_WIDGET_WIDTH,
17 17 isBataBoardSharePage,
18 18 MoreActionEvent,
  19 + VisualComponentPermission,
19 20 } from '../config/config';
20 21 import {
21 22 addDataComponent,
... ... @@ -32,11 +33,10 @@
32 33 DataSource,
33 34 Layout,
34 35 } from '/@/api/dataBoard/model';
35   - import { frontComponentMap } from './config/help';
  36 + import { frontComponentMap } from '../components/help';
36 37 import { calcScale } from './config/util';
37 38 import { useMessage } from '/@/hooks/web/useMessage';
38 39 import { DataBoardLayoutInfo } from '../types/type';
39   - import { WidgetComponentType } from './config/visualOptions';
40 40 import Authority from '/@/components/Authority/src/Authority.vue';
41 41 import { useSocketConnect } from '../hook/useSocketConnect';
42 42 import { buildUUID } from '/@/utils/uuid';
... ... @@ -44,6 +44,7 @@
44 44 import trendIcon from '/@/assets/svg/trend.svg';
45 45 import backIcon from '/@/assets/images/back.png';
46 46 import { useCalcGridLayout } from '../hook/useCalcGridLayout';
  47 + import { FrontComponent } from '../const/const';
47 48
48 49 const ROUTE = useRoute();
49 50
... ... @@ -298,7 +299,7 @@
298 299
299 300 const getComponent = (record: DataComponentRecord) => {
300 301 const frontComponent = record.frontId;
301   - const component = frontComponentMap.get(frontComponent as WidgetComponentType);
  302 + const component = frontComponentMap.get(frontComponent as FrontComponent);
302 303 return component?.Component;
303 304 };
304 305
... ... @@ -307,8 +308,8 @@
307 308 dataSourceRecord: DataSource
308 309 ) => {
309 310 const frontComponent = record.frontId;
310   - const component = frontComponentMap.get(frontComponent as WidgetComponentType);
311   - return component?.transformConfig(component.ComponentConfig, record, dataSourceRecord);
  311 + const component = frontComponentMap.get(frontComponent as FrontComponent);
  312 + return component?.transformConfig(component.ComponentConfig || {}, record, dataSourceRecord);
312 313 };
313 314
314 315 const handleUpdate = async (id: string) => {
... ... @@ -360,9 +361,7 @@
360 361 await deleteDataComponent({ dataBoardId, ids: [id] });
361 362 createMessage.success('删除成功');
362 363 await getDataBoardComponent();
363   - } catch (error) {
364   - // createMessage.error('删除失败');
365   - }
  364 + } catch (error) {}
366 365 };
367 366
368 367 const [registerHistoryDataModal, historyDataModalMethod] = useModal();
... ... @@ -391,7 +390,7 @@
391 390 </div>
392 391 </template>
393 392 <template #extra>
394   - <Authority value="api:yt:data_component:add:post">
  393 + <Authority :value="VisualComponentPermission.CREATE">
395 394 <Button v-if="!getIsSharePage" type="primary" @click="handleOpenCreatePanel">
396 395 创建组件
397 396 </Button>
... ... @@ -439,7 +438,6 @@
439 438 :data-source="item.record.dataSource"
440 439 >
441 440 <template #header>
442   - <!-- <div>header</div> -->
443 441 <BaseWidgetHeader
444 442 :record="item.record.dataSource"
445 443 :id="item.record.id"
... ... @@ -448,11 +446,6 @@
448 446 >
449 447 <template #moreAction>
450 448 <Tooltip title="趋势">
451   - <!-- <LineChartOutlined
452   - v-if="!getIsSharePage"
453   - class="cursor-pointer mx-1"
454   - @click="handleOpenHistroyDataModal(item.record.dataSource)"
455   - /> -->
456 449 <img
457 450 :src="trendIcon"
458 451 v-if="!getIsSharePage"
... ... @@ -494,14 +487,18 @@
494 487 .vue-grid-item:not(.vue-grid-placeholder) {
495 488 background: #fff;
496 489 border: none !important;
  490 +
497 491 /* border: 1px solid black; */
498 492 }
  493 +
499 494 .vue-grid-item .resizing {
500 495 opacity: 0.9;
501 496 }
  497 +
502 498 .vue-grid-item .static {
503 499 background: #cce;
504 500 }
  501 +
505 502 .vue-grid-item .text {
506 503 font-size: 24px;
507 504 text-align: center;
... ... @@ -514,16 +511,20 @@
514 511 height: 100%;
515 512 width: 100%;
516 513 }
  514 +
517 515 .vue-grid-item .no-drag {
518 516 height: 100%;
519 517 width: 100%;
520 518 }
  519 +
521 520 .vue-grid-item .minMax {
522 521 font-size: 12px;
523 522 }
  523 +
524 524 .vue-grid-item .add {
525 525 cursor: pointer;
526 526 }
  527 +
527 528 .vue-draggable-handle {
528 529 position: absolute;
529 530 width: 20px;
... ... @@ -540,12 +541,6 @@
540 541 cursor: pointer;
541 542 }
542 543
543   - // .container {
544   - // display: grid;
545   - // grid-template-columns: 3;
546   - // grid-row: 3;
547   - // }
548   -
549 544 .grid-item-layout {
550 545 overflow: hidden;
551 546 border: 1px solid #eee !important;
... ...
... ... @@ -8,6 +8,10 @@ interface GapRecord {
8 8 endIndex: Nullable<number>;
9 9 }
10 10
  11 +/**
  12 + * @description calculate where to place the component
  13 + * @returns
  14 + */
11 15 export function useCalcGridLayout() {
12 16 const calcLayoutInfo = (
13 17 layoutInfo: Layout[],
... ...
... ... @@ -7,7 +7,7 @@
7 7 import { useMessage } from '/@/hooks/web/useMessage';
8 8 import Dropdown from '/@/components/Dropdown/src/Dropdown.vue';
9 9 import { DropMenu } from '/@/components/Dropdown';
10   - import { DATA_BOARD_SHARE_URL, MoreActionEvent } from './config/config';
  10 + import { DATA_BOARD_SHARE_URL, MoreActionEvent, VisualBoardPermission } from './config/config';
11 11 import { useModal } from '/@/components/Modal';
12 12 import PanelDetailModal from './components/PanelDetailModal.vue';
13 13 import { getDataBoardList, deleteDataBoard } from '/@/api/dataBoard';
... ... @@ -36,7 +36,7 @@
36 36 labelWidth: 80,
37 37 layout: 'inline',
38 38 submitButtonOptions: {
39   - loading: loading,
  39 + loading: loading as unknown as boolean,
40 40 },
41 41 submitFunc: async () => {
42 42 try {
... ... @@ -51,7 +51,7 @@
51 51 },
52 52 });
53 53
54   - //分页相关
  54 + // about pagination
55 55 const page = ref(1);
56 56 const pageSize = ref(10);
57 57 const total = ref(0);
... ... @@ -90,8 +90,8 @@
90 90
91 91 const { hasPermission } = usePermission();
92 92 const dropMenuList = computed<DropMenu[]>(() => {
93   - const hasUpdatePermission = hasPermission('api:yt:data_board:update:update');
94   - const hasDeletePermission = hasPermission('api:yt:data_board:delete');
  93 + const hasUpdatePermission = hasPermission(VisualBoardPermission.UPDATE);
  94 + const hasDeletePermission = hasPermission(VisualBoardPermission.DELETE);
95 95 const basicMenu: DropMenu[] = [];
96 96 if (hasUpdatePermission)
97 97 basicMenu.push({
... ... @@ -147,31 +147,21 @@
147 147 };
148 148
149 149 const handleRemove = async (record: DataBoardRecord) => {
150   - // TODO 删除确认
151 150 try {
152 151 await deleteDataBoard([record.id]);
153 152 createMessage.success('删除成功');
154 153 await getDatasource();
155   - } catch (error) {
156   - // createMessage.error('删除失败');
157   - }
  154 + } catch (error) {}
158 155 };
159 156
160 157 const [registerModal, { openModal }] = useModal();
161 158
162 159 const handleViewBoard = (record: DataBoardRecord) => {
163   - const hasDetailPermission = hasPermission('api:yt:data_component:list');
  160 + const hasDetailPermission = hasPermission(VisualBoardPermission.DETAIL);
164 161 if (hasDetailPermission) {
165 162 const boardId = encode(record.id);
166 163 const boardName = encode(record.name);
167 164 router.push(`/visual/board/detail/${boardId}/${boardName}`);
168   - // router.push({
169   - // name: 'visualBoardDetail'
170   - // params: {
171   - // boardId: encode(record.id),
172   - // boardName: encode(record.name),
173   - // },
174   - // });
175 165 } else createMessage.warning('没有权限');
176 166 };
177 167
... ... @@ -186,8 +176,6 @@
186 176 '.ant-spin-container'
187 177 ) as HTMLElement;
188 178 listContainerEl &&
189   - // (listContainerEl.style.minHeight = listContainerHeight + 'px') &&
190   - // (listContainerEl.style.maxHeight = listContainerHeight + 'px') &&
191 179 (listContainerEl.style.height = listContainerHeight + 'px') &&
192 180 (listContainerEl.style.overflowY = 'auto') &&
193 181 (listContainerEl.style.overflowX = 'hidden');
... ... @@ -210,7 +198,6 @@
210 198 <div class="bg-light-100 mb-6 w-full p-3 search-form">
211 199 <BasicForm class="flex-auto w-full" @register="searchFormRegister" />
212 200 </div>
213   - <!-- <div> </div> -->
214 201 <Spin :spinning="loading">
215 202 <List
216 203 ref="listEL"
... ... @@ -235,7 +222,6 @@
235 222 <MoreOutlined class="rotate-90 transform cursor-pointer" />
236 223 </Dropdown>
237 224 </template>
238   - <!-- <template #cover>title</template> -->
239 225 <section @click="handleViewBoard(item)">
240 226 <div class="flex data-card__info">
241 227 <div>
... ... @@ -247,16 +233,19 @@
247 233 </Statistic>
248 234 </div>
249 235 </div>
250   - <div class="flex justify-between mt-4 text-sm" style="color: #999999">
  236 + <div class="flex justify-between mt-4 text-sm" style="color: #999">
251 237 <div>
252 238 <span>
253 239 {{ item.viewType === ViewType.PRIVATE_VIEW ? '私有看板' : '公共看板' }}
254 240 </span>
255   - <!-- <span v-if="item.viewType === ViewType.PUBLIC_VIEW">
  241 + <span
  242 + style="display: none"
  243 + v-if="item.viewType === ViewType.PUBLIC_VIEW && false"
  244 + >
256 245 <Tooltip title="点击复制分享链接">
257 246 <ShareAltOutlined class="ml-2" @click.stop="handleCopyShareUrl(item)" />
258 247 </Tooltip>
259   - </span> -->
  248 + </span>
260 249 </div>
261 250 <div>{{ item.createTime }}</div>
262 251 </div>
... ... @@ -278,15 +267,17 @@
278 267 .data-card:deep(.ant-card-head-title) {
279 268 padding: 0;
280 269 }
  270 +
281 271 .data-card:deep(.ant-card-extra) {
282 272 padding: 0;
283 273 }
  274 +
284 275 .data-card:deep(.ant-card-body) {
285 276 padding: 20px;
286 277 }
287 278
288 279 .data-card__info {
289   - color: #666666;
  280 + color: #666;
290 281
291 282 &::before {
292 283 content: '';
... ... @@ -299,8 +290,10 @@
299 290
300 291 .search-form {
301 292 width: 100%;
  293 +
302 294 form {
303 295 width: 100%;
  296 +
304 297 :deep(.ant-row) {
305 298 width: 100%;
306 299 }
... ...
  1 +import { Component } from 'vue';
1 2 import { Layout } from 'vue3-grid-layout';
  3 +import { FrontComponent, FrontComponentCategory, visualOptionField } from '../const/const';
  4 +import { RadioRecord } from '../detail/config/util';
2 5 import { DataComponentRecord, DataSource } from '/@/api/dataBoard/model';
3 6
4 7 export type FrontDataSourceRecord = DataSource;
... ... @@ -8,3 +11,39 @@ export type DataBoardLayoutInfo = Layout & {
8 11 width?: number;
9 12 height?: number;
10 13 };
  14 +
  15 +export interface ComponentConfig {
  16 + Component: Component;
  17 + ComponentName?: string;
  18 + ComponentKey: FrontComponent;
  19 + ComponentConfig?: Recordable;
  20 + ComponentCategory: FrontComponentCategory;
  21 + transformConfig: (
  22 + componentConfig: Recordable,
  23 + record: DataComponentRecord,
  24 + dataSourceRecord: DataSource
  25 + ) => Recordable;
  26 +}
  27 +
  28 +export interface VisualOptionParams {
  29 + [visualOptionField.FONT_COLOR]: string;
  30 + [visualOptionField.UNIT]: string;
  31 + [visualOptionField.ICON_COLOR]: string;
  32 + [visualOptionField.ICON]: string;
  33 + [visualOptionField.FIRST_PHASE_COLOR]: string;
  34 + [visualOptionField.SECOND_PHASE_COLOR]: string;
  35 + [visualOptionField.THIRD_PHASE_COLOR]: string;
  36 + [visualOptionField.FIRST_PHASE_VALUE]: string;
  37 + [visualOptionField.SECOND_PHASE_VALUE]: string;
  38 + [visualOptionField.THIRD_PHASE_VALUE]: string;
  39 +}
  40 +
  41 +export interface VisualComponentProps<Layout = Recordable, Value = Recordable> {
  42 + value?: Value;
  43 + layout?: Layout;
  44 + radio?: RadioRecord;
  45 + random?: boolean;
  46 + add?: (key: string, method: Fn) => void;
  47 + update?: () => void;
  48 + remove?: (key: string) => void;
  49 +}
... ...