Commit a19d97cb02b201ca37963561e0cae8d9984c0343
Merge branch 'dev_by_ft' into 'main_dev'
feat(src/views/chart): 新增图标,可配置自定义内容弹窗和优化多个摄像头,可以自动切换也可以手动切换 See merge request yunteng/thingskit-view!177
Showing
8 changed files
with
331 additions
and
14 deletions
1 | +<template> | |
2 | + <div class="smallcircle2"></div> | |
3 | +</template> | |
4 | + | |
5 | +<script setup lang="ts"></script> | |
6 | + | |
7 | +<style lang="scss" scoped> | |
8 | +.smallcircle2 { | |
9 | + display: block; | |
10 | + width: 12px; | |
11 | + height: 12px; | |
12 | + border-radius: 50%; | |
13 | + opacity: 0.4; | |
14 | + background: radial-gradient(circle at center, red 0, blue, #2277b2 100%); | |
15 | +} | |
16 | +</style> | ... | ... |
... | ... | @@ -16,8 +16,34 @@ export interface IconOptions { |
16 | 16 | pointColor?: string |
17 | 17 | dynamicEffect?: IconDynamicEffectEnum[] |
18 | 18 | backgroundColor?: string |
19 | + popupConfig: PopupConfig | |
20 | + dataset: bodyItem[] | |
19 | 21 | } |
20 | 22 | |
23 | +interface bodyItem { | |
24 | + label: string | |
25 | + value: string | |
26 | +} | |
27 | + | |
28 | +interface PopupConfig { | |
29 | + borderWidth: number | |
30 | + borderHeight: number | |
31 | + borderColor: string | |
32 | + boxShadowColor: string | |
33 | + linearLeftColor: string | |
34 | + linearRightColor: string | |
35 | + arrowColor: string | |
36 | + lineColor: string | |
37 | + fontColor: string | |
38 | + fontSize: number | |
39 | + fontWeight: number | |
40 | + fontContent: string | |
41 | + labelColor: string | |
42 | + valueColor: string | |
43 | + placement: string | |
44 | +} | |
45 | + | |
46 | + | |
21 | 47 | export const option: IconOptions = { |
22 | 48 | icon: 'turangshuifen', |
23 | 49 | iconColor: '#1C9276', |
... | ... | @@ -28,7 +54,30 @@ export const option: IconOptions = { |
28 | 54 | pointSize: 4, |
29 | 55 | pointColor: '#9ADED7', |
30 | 56 | dynamicEffect: [], |
31 | - backgroundColor: '#082B2A' | |
57 | + backgroundColor: '#082B2A', | |
58 | + dataset: [ | |
59 | + { label: '设备:', value: 'xxxxxxxxx设备' }, | |
60 | + { label: '产品:', value: 'xxxxxxxxx产品' }, | |
61 | + { label: '位置:', value: 'xxxxxxxxx位置' }, | |
62 | + { label: '创建时间:', value: '2024-01-01' } | |
63 | + ], | |
64 | + popupConfig: { | |
65 | + borderWidth: 380, | |
66 | + borderHeight: 200, | |
67 | + borderColor: 'red', | |
68 | + boxShadowColor: '#356A82FF', | |
69 | + linearLeftColor: '#385391FF', | |
70 | + linearRightColor: '#385391FF', | |
71 | + arrowColor: '#427FB4', | |
72 | + lineColor: '#427FB4', | |
73 | + fontColor: '#ffffff', | |
74 | + fontSize: 16, | |
75 | + fontWeight: 500, | |
76 | + fontContent: '我是标题', | |
77 | + labelColor: '#3d6e9d', | |
78 | + valueColor: '#ffffff', | |
79 | + placement: 'top' | |
80 | + } | |
32 | 81 | } |
33 | 82 | |
34 | 83 | export default class Config extends PublicConfigClass implements CreateComponentType { | ... | ... |
... | ... | @@ -42,6 +42,95 @@ |
42 | 42 | </SettingItem> |
43 | 43 | </SettingItemBox> |
44 | 44 | </CollapseItem> |
45 | + <CollapseItem name="弹窗配置" expanded> | |
46 | + <SettingItemBox name="宽高"> | |
47 | + <SettingItem name="宽"> | |
48 | + <NInputNumber | |
49 | + v-model:value="optionData.popupConfig.borderWidth" | |
50 | + size="small" | |
51 | + :step="10" | |
52 | + :min="0" | |
53 | + ></NInputNumber> | |
54 | + </SettingItem> | |
55 | + <SettingItem name="高"> | |
56 | + <NInputNumber | |
57 | + v-model:value="optionData.popupConfig.borderHeight" | |
58 | + size="small" | |
59 | + :step="10" | |
60 | + :min="0" | |
61 | + ></NInputNumber> | |
62 | + </SettingItem> | |
63 | + </SettingItemBox> | |
64 | + <SettingItemBox name="位置"> | |
65 | + <SettingItem name=""> | |
66 | + <NSelect v-model:value="optionData.popupConfig.placement" size="small" :options="placementOptions"> </NSelect> | |
67 | + </SettingItem> | |
68 | + </SettingItemBox> | |
69 | + <SettingItemBox name="颜色"> | |
70 | + <SettingItem name="边框阴影"> | |
71 | + <NColorPicker | |
72 | + size="small" | |
73 | + :modes="['hex']" | |
74 | + :actions="['clear']" | |
75 | + v-model:value="optionData.popupConfig.boxShadowColor" | |
76 | + > | |
77 | + </NColorPicker> | |
78 | + </SettingItem> | |
79 | + <SettingItem name="背景线性渐变左"> | |
80 | + <NColorPicker size="small" v-model:value="optionData.popupConfig.linearLeftColor"> </NColorPicker> | |
81 | + </SettingItem> | |
82 | + <SettingItem name="背景线性渐变右"> | |
83 | + <NColorPicker size="small" v-model:value="optionData.popupConfig.linearRightColor"> </NColorPicker> | |
84 | + </SettingItem> | |
85 | + <SettingItem name="箭头颜色"> | |
86 | + <NColorPicker size="small" v-model:value="optionData.popupConfig.arrowColor"> </NColorPicker> | |
87 | + </SettingItem> | |
88 | + <SettingItem name="线条颜色"> | |
89 | + <NColorPicker size="small" v-model:value="optionData.popupConfig.lineColor"> </NColorPicker> | |
90 | + </SettingItem> | |
91 | + <SettingItem name="标题内容"> | |
92 | + <NInput v-model:value="optionData.popupConfig.fontContent"> </NInput> | |
93 | + </SettingItem> | |
94 | + <SettingItem name="标题颜色"> | |
95 | + <NColorPicker size="small" v-model:value="optionData.popupConfig.fontColor"> </NColorPicker> | |
96 | + </SettingItem> | |
97 | + <SettingItem name="标题加粗"> | |
98 | + <NInputNumber | |
99 | + v-model:value="optionData.popupConfig.fontWeight" | |
100 | + size="small" | |
101 | + :step="100" | |
102 | + :min="0" | |
103 | + ></NInputNumber> | |
104 | + </SettingItem> | |
105 | + <SettingItem name="内容键文本颜色"> | |
106 | + <NColorPicker size="small" v-model:value="optionData.popupConfig.labelColor"> </NColorPicker> | |
107 | + </SettingItem> | |
108 | + <SettingItem name="内容值文本颜色"> | |
109 | + <NColorPicker size="small" v-model:value="optionData.popupConfig.valueColor"> </NColorPicker> | |
110 | + </SettingItem> | |
111 | + </SettingItemBox> | |
112 | + <template v-for="(item, index) in optionData.dataset" :key="index"> | |
113 | + <setting-item-box name="内容键" :alone="true"> | |
114 | + <setting-item> | |
115 | + <NInput v-model:value="item.label"> </NInput> | |
116 | + </setting-item> | |
117 | + </setting-item-box> | |
118 | + <setting-item-box name="内容值" :alone="true"> | |
119 | + <setting-item> | |
120 | + <NInput v-model:value="item.value"> </NInput> | |
121 | + </setting-item> | |
122 | + </setting-item-box> | |
123 | + <n-button size="small" @click="optionData.dataset.splice(index, 1)"> - </n-button> | |
124 | + </template> | |
125 | + <n-button | |
126 | + style="margin-left: 10px" | |
127 | + v-if="optionData.dataset.length < 8" | |
128 | + size="small" | |
129 | + @click="optionData.dataset.push({ label: '', value: '' })" | |
130 | + > | |
131 | + + | |
132 | + </n-button> | |
133 | + </CollapseItem> | |
45 | 134 | </template> |
46 | 135 | |
47 | 136 | <script setup lang="ts"> |
... | ... | @@ -79,4 +168,24 @@ const getDynamicEffectOptions = computed<SelectOption[]>(() => { |
79 | 168 | ] |
80 | 169 | |
81 | 170 | }) |
171 | + | |
172 | +//native-ui 组件popover内置弹窗位置,不需要通过枚举方式 | |
173 | +const placementOptions: SelectOption[] = [ | |
174 | + { | |
175 | + label: '顶部', | |
176 | + value: 'top' | |
177 | + }, | |
178 | + { | |
179 | + label: '右边', | |
180 | + value: 'right' | |
181 | + }, | |
182 | + { | |
183 | + label: '左边', | |
184 | + value: 'left' | |
185 | + }, | |
186 | + { | |
187 | + label: '底部', | |
188 | + value: 'bottom' | |
189 | + } | |
190 | +] | |
82 | 191 | </script> | ... | ... |
1 | 1 | <script lang="ts" setup> |
2 | -import { computed, PropType } from 'vue' | |
2 | +import { computed, PropType, toRefs } from 'vue' | |
3 | 3 | import { CreateComponentType } from '@/packages/index.d' |
4 | 4 | import { option } from './config' |
5 | 5 | import SvgBorder from './SvgBorder.vue'; |
... | ... | @@ -17,14 +17,144 @@ const size = computed(() => { |
17 | 17 | return Math.min(w, h) / 2 |
18 | 18 | }) |
19 | 19 | |
20 | - | |
20 | +const { popupConfig, dataset } = toRefs(props.chartConfig.option) | |
21 | 21 | </script> |
22 | 22 | |
23 | 23 | <template> |
24 | - <section> | |
25 | - <SvgBorder :option="chartConfig.option"> | |
26 | - <SvgIcon :style="{ color: chartConfig.option.iconColor }" :size="size" :name="chartConfig.option.icon!" | |
27 | - prefix="iconfont" /> | |
28 | - </SvgBorder> | |
24 | + <section> | |
25 | + <n-popover :placement="popupConfig.placement" trigger="click" raw> | |
26 | + <template #trigger> | |
27 | + <SvgBorder :option="chartConfig.option"> | |
28 | + <SvgIcon | |
29 | + :style="{ color: chartConfig.option.iconColor }" | |
30 | + :size="size" | |
31 | + :name="chartConfig.option.icon!" | |
32 | + prefix="iconfont" | |
33 | + /> | |
34 | + </SvgBorder> | |
35 | + </template> | |
36 | + <div | |
37 | + style="transform-origin: inherit" | |
38 | + :style="`width:${popupConfig.borderWidth}px; | |
39 | + height: ${popupConfig.borderHeight}px; | |
40 | + box-shadow: 0 0 10px 10px ${popupConfig.boxShadowColor}; | |
41 | + background:linear-gradient(to right, ${popupConfig.linearLeftColor} , ${popupConfig.linearRightColor}); | |
42 | + `" | |
43 | + > | |
44 | + <div class="popup-body"> | |
45 | + <div class="popup-arrow-right" :style="`border-color:${popupConfig.arrowColor}`"></div> | |
46 | + <div class="popup-header-content"> | |
47 | + <p | |
48 | + class="header-title" | |
49 | + :style="`color:${popupConfig.fontColor};font-size:${popupConfig.fontSize}px;font-weight:${popupConfig.fontWeight}`" | |
50 | + > | |
51 | + {{ popupConfig.fontContent }} | |
52 | + </p> | |
53 | + <div class="header-content-graphical"> | |
54 | + <div class="graphical-circle-left"><Circle /></div> | |
55 | + <div class="graphical-line"> | |
56 | + <div class="line-left" :style="`background-color:${popupConfig.lineColor}`"></div> | |
57 | + <div class="line-center" :style="`background-color:${popupConfig.lineColor}`"></div> | |
58 | + <div class="line-right" :style="`background-color:${popupConfig.lineColor}`"></div> | |
59 | + </div> | |
60 | + <div class="graphical-circle-right"><Circle /></div> | |
61 | + </div> | |
62 | + </div> | |
63 | + </div> | |
64 | + <div class="content-body"> | |
65 | + <div class="body" v-for="(item, index) in dataset" :key="index"> | |
66 | + <span :style="`color:${popupConfig.labelColor};`">{{ item.label }}</span> | |
67 | + <span :style="`color:${popupConfig.valueColor};`">{{ item.value }}</span> | |
68 | + </div> | |
69 | + </div> | |
70 | + </div> | |
71 | + </n-popover> | |
29 | 72 | </section> |
30 | 73 | </template> |
74 | + | |
75 | +<style lang="scss" scoped> | |
76 | +@mixin base-text-ellipsis() { | |
77 | + overflow: hidden; | |
78 | + white-space: nowrap; | |
79 | + text-overflow: ellipsis; | |
80 | + -o-text-overflow: ellipsis; | |
81 | +} | |
82 | +.popup-body { | |
83 | + display: flex; | |
84 | + justify-content: center; | |
85 | + flex-direction: column; | |
86 | + .popup-arrow-right { | |
87 | + position: absolute; | |
88 | + top: 15px; | |
89 | + left: 10px; | |
90 | + border-right: 1px solid; | |
91 | + border-bottom: 1px solid; | |
92 | + width: 7px; | |
93 | + height: 7px; | |
94 | + transform: rotate(-45deg); | |
95 | + -o-transform: rotate(-45deg); | |
96 | + -webkit-transform: rotate(-45deg); | |
97 | + -moz-transform: rotate(-45deg); | |
98 | + -ms-transform: rotate(-45deg); | |
99 | + } | |
100 | + .popup-header-content { | |
101 | + margin: 23px; | |
102 | + display: flex; | |
103 | + justify-content: center; | |
104 | + flex-direction: column; | |
105 | + .header-title { | |
106 | + @include base-text-ellipsis; | |
107 | + } | |
108 | + .header-content-graphical { | |
109 | + display: flex; | |
110 | + align-items: center; | |
111 | + .graphical-circle-left { | |
112 | + position: relative; | |
113 | + left: -2px; | |
114 | + } | |
115 | + .graphical-line { | |
116 | + display: flex; | |
117 | + .line-left { | |
118 | + width: 115px; | |
119 | + height: 2px; | |
120 | + position: relative; | |
121 | + } | |
122 | + .line-center { | |
123 | + width: 35px; | |
124 | + height: 2px; | |
125 | + transform: rotateZ(145deg); | |
126 | + position: absolute; | |
127 | + top: 44px; | |
128 | + left: 146px; | |
129 | + } | |
130 | + .line-right { | |
131 | + width: 50px; | |
132 | + height: 2px; | |
133 | + position: absolute; | |
134 | + top: 34px; | |
135 | + left: 178px; | |
136 | + } | |
137 | + } | |
138 | + .graphical-circle-right { | |
139 | + position: absolute; | |
140 | + top: 29px; | |
141 | + left: 231px; | |
142 | + } | |
143 | + } | |
144 | + } | |
145 | +} | |
146 | +.content-body { | |
147 | + display: flex; | |
148 | + align-items: center; | |
149 | + flex-wrap: wrap; | |
150 | + margin: -10px 0; | |
151 | + .body { | |
152 | + display: flex; | |
153 | + align-items: center; | |
154 | + justify-content: flex-start; | |
155 | + gap: 27px; | |
156 | + margin-left: 15px; | |
157 | + margin-top: 1px; | |
158 | + } | |
159 | +} | |
160 | +</style> | ... | ... |
... | ... | @@ -9,6 +9,7 @@ export enum sourceTypeEnum { |
9 | 9 | } |
10 | 10 | |
11 | 11 | export const option = { |
12 | + autoSwitch: false, | |
12 | 13 | dataset: [ |
13 | 14 | { |
14 | 15 | byIdUrl: '', //通过接口获取的url |
... | ... | @@ -18,7 +19,7 @@ export const option = { |
18 | 19 | } |
19 | 20 | ] as any, |
20 | 21 | // 自动播放的间隔(ms) |
21 | - interval: 5000, | |
22 | + interval: 2000, | |
22 | 23 | autoplay: true, |
23 | 24 | effect: 'slide', |
24 | 25 | displayMode: 'singleGrid' | ... | ... |
1 | 1 | <template> |
2 | 2 | <CollapseItem name="播放器配置" :expanded="true"> |
3 | + <setting-item-box name="开启切换" :alone="true"> | |
4 | + <setting-item> | |
5 | + <n-switch v-model:value="optionData.autoSwitch" size="small"></n-switch> | |
6 | + </setting-item> | |
7 | + </setting-item-box> | |
8 | + <setting-item-box name="间隔时长" :alone="true"> | |
9 | + <setting-item> | |
10 | + <n-input-number v-model:value="optionData.interval" size="small"></n-input-number> | |
11 | + </setting-item> | |
12 | + </setting-item-box> | |
3 | 13 | <template v-for="(item, index) in optionData.dataset" :key="index"> |
4 | 14 | <setting-item-box name="源类型" :alone="true"> |
5 | 15 | <setting-item> | ... | ... |
... | ... | @@ -37,6 +37,8 @@ const isShowSvg = ref(false) |
37 | 37 | |
38 | 38 | const { w, h } = toRefs(props.chartConfig.attr) |
39 | 39 | |
40 | +const { autoSwitch, interval } = toRefs(props.chartConfig.option) | |
41 | + | |
40 | 42 | const option = shallowReactive({ |
41 | 43 | dataset: configOption.dataset |
42 | 44 | }) |
... | ... | @@ -45,8 +47,6 @@ const cameraRef = ref<InstanceType<typeof CameraItem>>() |
45 | 47 | |
46 | 48 | let initial = ref(0) |
47 | 49 | |
48 | -let interval = ref(2500) | |
49 | - | |
50 | 50 | const computedFunc = (initial: number, source: any) => { |
51 | 51 | if (initial < 0) initial = 0 |
52 | 52 | if (Array.isArray(source)) { |
... | ... | @@ -130,10 +130,12 @@ let root = ref(null) |
130 | 130 | |
131 | 131 | onMounted(() => { |
132 | 132 | clearInterval(timer) |
133 | - autoPlay() | |
134 | 133 | const box: any = root.value |
135 | 134 | box.onmouseenter = () => clearInterval(timer) |
136 | - box.onmouseleave = () => autoPlay() | |
135 | + if (autoSwitch.value) { | |
136 | + autoPlay() | |
137 | + box.onmouseleave = () => autoPlay() | |
138 | + } | |
137 | 139 | }) |
138 | 140 | |
139 | 141 | // 点击左右按钮切换图片 | ... | ... |