Commit a19d97cb02b201ca37963561e0cae8d9984c0343

Authored by xp.Huang
2 parents 11b68377 26a9cda3

Merge branch 'dev_by_ft' into 'main_dev'

feat(src/views/chart): 新增图标,可配置自定义内容弹窗和优化多个摄像头,可以自动切换也可以手动切换

See merge request yunteng/thingskit-view!177
  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>
... ...
... ... @@ -8,7 +8,7 @@ export const PickIconConfig: ConfigType = {
8 8 key,
9 9 chartKey,
10 10 conKey,
11   - title: '图标',
  11 + title: '图标(可配置弹窗)',
12 12 category: ChatCategoryEnum.MORE,
13 13 categoryName: ChatCategoryEnumName.MORE,
14 14 package: PackagesCategoryEnum.DECORATES,
... ...
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 // 点击左右按钮切换图片
... ...