Commit 078c671ee2ab485976c6f230cd89c4c3e77f773b

Authored by xp.Huang
2 parents 11b68377 cef35d66

Merge branch 'main_dev' into 'main'

Main dev

See merge request yunteng/thingskit-view!218
Showing 72 changed files with 3470 additions and 467 deletions

Too many changes to show.

To preserve performance only 72 of 153 files are displayed.

1 1 import { defHttp } from '@/utils/external/http/axios'
2 2 import { ConfigurationItemType, DictItem, OrganizationListItem, UploadResponse } from './model'
3 3 import { PaginationResult } from '/#/external/axios'
  4 +import { isShareMode } from '@/views/share/hook'
4 5
5 6 enum Api {
6 7 GET_DICT = '/dict_item',
... ... @@ -114,10 +115,12 @@ export const getVideoUrl = (id: string) =>
114 115 })
115 116
116 117 //获取行政区域
117   -export const getGeoJsonMap = (code: number | string, level: string) =>
118   - defHttp.get({
  118 +export const getGeoJsonMap = (code: number | string, level: string) => {
  119 + return defHttp.get({
119 120 url: `${Api.GEOJSONURL}${code}/${level}`
120   - })
  121 + }, { withShareToken: isShareMode() })
  122 +}
  123 +
121 124
122 125 // 获取设备详情
123 126 export const getDeviceDetail = (id: string) =>
... ... @@ -133,11 +136,11 @@ export const getAttribute = (deviceProfileId: string) =>
133 136
134 137 // 获取设备最新数据
135 138 export const getDeviceLatest = (tbDeviceId: string) =>
136   -defHttp.get({
137   - url: `${Api.GET_DEVICE_LATEST}${tbDeviceId}/values/timeseries`
138   -}, {
139   - joinPrefix: false
140   -})
  139 + defHttp.get({
  140 + url: `${Api.GET_DEVICE_LATEST}${tbDeviceId}/values/timeseries`
  141 + }, {
  142 + joinPrefix: false
  143 + })
141 144
142 145 //获取产品属性
143 146 export const getProfileAttrs = (params: { deviceProfileId: string; dataType?: string }) => {
... ...
... ... @@ -94,13 +94,15 @@ const extraValue = (object: Recordable) => {
94 94
95 95 const handleParams = (Params: Recordable) => {
96 96 if (Params.keys && Params?.keys?.length) {
  97 + // 过滤无效参数
  98 + Reflect.deleteProperty(Params, 'attrName')
97 99 /** ft 修改select联动下拉框选择了属性(单个)报错问题
98 100 * 源代码 Params.keys = (Params.keys || [] as any).join(',')
99 101 */
100   - if(!Array.isArray(Params.keys)){
101   - Params.keys = ([Params.keys] || [] as any).join(',')
102   - }else{
103   - Params.keys = (Params.keys || [] as any).join(',')
  102 + if (!Array.isArray(Params.keys)) {
  103 + Params.keys = ([Params.keys] || [] as any).join(',')
  104 + } else {
  105 + Params.keys = (Params.keys || [] as any).join(',')
104 106 }
105 107 //ft
106 108 }
... ... @@ -116,12 +118,12 @@ const handleParams = (Params: Recordable) => {
116 118 }
117 119
118 120 //post请求动态追加query参数
119   -const objConvertQuery= (data:Recordable)=> {
  121 +const objConvertQuery = (data: Recordable) => {
120 122 const _result = [];
121 123 for (const key in data) {
122 124 const value = data[key];
123 125 if (value.constructor == Array) {
124   - value.forEach(function(_value) {
  126 + value.forEach(function (_value) {
125 127 _result.push(key + "=" + _value);
126 128 });
127 129 } else {
... ... @@ -152,11 +154,12 @@ export const customRequest = async (request: RequestConfigType) => {
152 154 * 修改后代码 requestHttpType === RequestHttpEnum.GET.toUpperCase() ? requestUrl: `${requestUrl}?${objConvertQuery(Params)}
153 155 */
154 156 Params = handleParams(Params)
  157 +
155 158 return customHttp.request<any>({
156   - url: requestHttpType === RequestHttpEnum.GET.toUpperCase() ? requestUrl: `${requestUrl}?${objConvertQuery(Params)}`,
  159 + url: requestHttpType === RequestHttpEnum.GET.toUpperCase() ? requestUrl : `${requestUrl}?${objConvertQuery(Params)}`,
157 160 baseURL: getOriginUrl(requestOriginUrl!),
158 161 method: requestHttpType,
159   - params: requestHttpType === RequestHttpEnum.GET.toUpperCase() ? Params: null,
  162 + params: requestHttpType === RequestHttpEnum.GET.toUpperCase() ? Params : null,
160 163 data: body,
161 164 headers: extraValue(Header)
162 165 }, {
... ...
... ... @@ -2,7 +2,8 @@ import { defHttp } from "@/utils/external/http/axios";
2 2 import { useGlobSetting } from '@/hooks/external/setting';
3 3 enum Api {
4 4 OPEN_FLV = '/rtsp/openFlv',
5   - CLOSE_FLV = '/rtsp/closeFlv'
  5 + CLOSE_FLV = '/rtsp/closeFlv',
  6 + GET_VIDEO_CONTROL_START = '/video/control/start',
6 7 }
7 8
8 9 export const getOpenFlvPlayUrl = (url: string, browserId: string) => {
... ... @@ -19,3 +20,17 @@ export const closeFlvPlay = (url: string, browserId: string) => {
19 20 }
20 21 });
21 22 };
  23 +
  24 +//gbt28181,获取flv地址
  25 +export const getVideoControlStart = ({
  26 + deviceId,
  27 + channelId,
  28 +}: Record<'deviceId' | 'channelId', string>) => {
  29 + return defHttp.get<Recordable>(
  30 + {
  31 + url: `${Api.GET_VIDEO_CONTROL_START}/${deviceId}/${channelId}`,
  32 + timeout: 30 * 1000,
  33 + },
  34 + {}
  35 + );
  36 +};
... ...
  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>
... ...
  1 +export interface PopupConfigInterface {
  2 + borderWidth: number
  3 + borderHeight: number
  4 + borderColor: string
  5 + boxShadowColor: string
  6 + linearLeftColor: string
  7 + linearRightColor: string
  8 + arrowColor: string
  9 + lineColor: string
  10 + fontColor: string
  11 + fontSize: number
  12 + fontWeight: number
  13 + fontContent: string
  14 + labelColor: string
  15 + valueColor: string
  16 + placement: string
  17 +}
  18 +export interface PopupConfigData {
  19 + label: string
  20 + value: string
  21 +}
... ...
  1 +import TKDialog from './index.vue';
  2 +
  3 +export { TKDialog };
... ...
  1 +<template>
  2 + <n-popover
  3 + :disabled="disabled"
  4 + :placement="popupConfig.placement"
  5 + trigger="click"
  6 + raw
  7 + @update:show="handleUpdateShow"
  8 + >
  9 + <template #trigger>
  10 + <slot />
  11 + </template>
  12 + <div
  13 + style="transform-origin: inherit"
  14 + :style="`width:${popupConfig.borderWidth}px;
  15 + height: ${popupConfig.borderHeight}px;
  16 + box-shadow: 0 0 10px 10px ${popupConfig.boxShadowColor};
  17 + background:linear-gradient(to right, ${popupConfig.linearLeftColor} , ${popupConfig.linearRightColor});
  18 + `"
  19 + >
  20 + <div class="popup-body">
  21 + <div class="popup-arrow-right" :style="`border-color:${popupConfig.arrowColor}`"></div>
  22 + <div class="popup-header-content">
  23 + <p
  24 + class="header-title"
  25 + :style="`color:${popupConfig.fontColor};font-size:${popupConfig.fontSize}px;font-weight:${popupConfig.fontWeight}`"
  26 + >
  27 + {{ popupConfig.fontContent }}
  28 + </p>
  29 + <div class="header-content-graphical">
  30 + <div class="graphical-circle-left"><Circle /></div>
  31 + <div class="graphical-line">
  32 + <div class="line-left" :style="`background-color:${popupConfig.lineColor}`"></div>
  33 + <div class="line-center" :style="`background-color:${popupConfig.lineColor}`"></div>
  34 + <div class="line-right" :style="`background-color:${popupConfig.lineColor}`"></div>
  35 + </div>
  36 + <div class="graphical-circle-right"><Circle /></div>
  37 + </div>
  38 + </div>
  39 + </div>
  40 + <div class="content-body">
  41 + <div class="body" v-for="(item, index) in popupConfigData" :key="index">
  42 + <span :style="`color:${popupConfig.labelColor};`">{{ item.label }}</span>
  43 + <span :style="`color:${popupConfig.valueColor};`">{{ item.value }}</span>
  44 + </div>
  45 + </div>
  46 + </div>
  47 + </n-popover>
  48 +</template>
  49 +
  50 +<script lang="ts" setup name="TKDialog">
  51 +import { PropType } from 'vue'
  52 +import { PopupConfigInterface, PopupConfigData } from './index.d'
  53 +import Circle from './components/Circle.vue'
  54 +
  55 +defineProps({
  56 + popupConfig: {
  57 + type: Object as PropType<PopupConfigInterface>,
  58 + required: true
  59 + },
  60 + popupConfigData: {
  61 + type: Array as PropType<PopupConfigData[]>
  62 + },
  63 + w: Number,
  64 + h: Number,
  65 + disabled: {
  66 + type: Boolean,
  67 + default: false
  68 + }
  69 +})
  70 +
  71 +const emits = defineEmits(['updateShow'])
  72 +
  73 +const handleUpdateShow = (show: boolean) => {
  74 + console.log(show)
  75 + emits('updateShow', show)
  76 +}
  77 +</script>
  78 +
  79 +<style lang="scss" scoped>
  80 +@mixin base-text-ellipsis() {
  81 + overflow: hidden;
  82 + white-space: nowrap;
  83 + text-overflow: ellipsis;
  84 + -o-text-overflow: ellipsis;
  85 +}
  86 +.popup-body {
  87 + display: flex;
  88 + justify-content: center;
  89 + flex-direction: column;
  90 + .popup-arrow-right {
  91 + position: absolute;
  92 + top: 15px;
  93 + left: 10px;
  94 + border-right: 1px solid;
  95 + border-bottom: 1px solid;
  96 + width: 7px;
  97 + height: 7px;
  98 + transform: rotate(-45deg);
  99 + -o-transform: rotate(-45deg);
  100 + -webkit-transform: rotate(-45deg);
  101 + -moz-transform: rotate(-45deg);
  102 + -ms-transform: rotate(-45deg);
  103 + }
  104 + .popup-header-content {
  105 + margin: 23px;
  106 + display: flex;
  107 + justify-content: center;
  108 + flex-direction: column;
  109 + .header-title {
  110 + @include base-text-ellipsis;
  111 + }
  112 + .header-content-graphical {
  113 + display: flex;
  114 + align-items: center;
  115 + .graphical-circle-left {
  116 + position: relative;
  117 + left: -2px;
  118 + }
  119 + .graphical-line {
  120 + display: flex;
  121 + position: relative;
  122 + .line-left {
  123 + width: 115px;
  124 + height: 2px;
  125 + position: relative;
  126 + }
  127 + .line-center {
  128 + width: 35px;
  129 + height: 2px;
  130 + transform: rotateZ(145deg);
  131 + position: absolute;
  132 + top: -10px;
  133 + left: 112px;
  134 + }
  135 + .line-right {
  136 + width: 50px;
  137 + height: 2px;
  138 + position: absolute;
  139 + top: -20px;
  140 + left: 143px;
  141 + }
  142 + }
  143 + .graphical-circle-right {
  144 + position: absolute;
  145 + top: 29px;
  146 + left: 231px;
  147 + }
  148 + }
  149 + }
  150 +}
  151 +.content-body {
  152 + display: flex;
  153 + flex-direction: column;
  154 + gap: 4px;
  155 + width: v-bind('w+"px"');
  156 + margin: 0 15px;
  157 + height: v-bind('h+"px"');
  158 +}
  159 +</style>
... ...
  1 +
  2 +
  3 +// 动画时间函数枚举
  4 +export enum AnimationTimingFunctionNameEnum {
  5 + // 动画从头到尾的速度是相同的
  6 + LINEAR = '匀速',
  7 + // 默认值:动画以低速开始,然后加快,在结束前变慢。
  8 + EASE = '缓速',
  9 + // 动画以低速开始。
  10 + EASEIN = '低速开始',
  11 + // 动画以低速结束。
  12 + EASEOUT = '低速结束',
  13 + // 动画以低速开始和结束。
  14 + EASEINOUT = '低速开始和结束'
  15 +}
  16 +
  17 +export enum AnimationTimingFunctionEnum {
  18 + // 动画从头到尾的速度是相同的
  19 + LINEAR = 'linear',
  20 + // 默认值:动画以低速开始,然后加快,在结束前变慢。
  21 + EASE = 'ease',
  22 + // 动画以低速开始。
  23 + EASEIN = 'ease-in',
  24 + // 动画以低速结束。
  25 + EASEOUT = 'ease-out',
  26 + // 动画以低速开始和结束。
  27 + EASEINOUT = 'ease-in-out'
  28 +}
  29 +
  30 +// 动画执行状态枚举
  31 +export enum AnimationPlayStateNameEnum {
  32 + // 暂停
  33 + PAUSED = '暂停',
  34 + // 运行
  35 + RUNNING = '运行'
  36 +}
  37 +
  38 +export enum AnimationPlayStateEnum {
  39 + // 暂停
  40 + PAUSED = 'paused',
  41 + // 运行
  42 + RUNNING = 'running'
  43 +}
  44 +
  45 +// 动画执行次数枚举
  46 +export enum AnimationIterationCountNameEnum {
  47 + // 暂停
  48 + ITERATIONCOUNT = '无限次',
  49 +}
  50 +
  51 +export enum AnimationIterationCountEnum {
  52 + // 暂停
  53 + ITERATIONCOUNT = 'infinite',
  54 +}
... ...
  1 +// 三维地图类型枚举
  2 +export enum ThreeMapEnum {
  3 + MAP3D = 'map3D',
  4 + SCATTER3D = 'scatter3D',
  5 + BAR3D = 'bar3D'
  6 +}
... ...
1   -import { toRefs } from 'vue'
2 1 import { CreateComponentType } from '@/packages/index.d'
3 2 import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
4 3 import { PageChartEditStoreType } from '@/store/modules/chartEditStore/chartEditStore.d'
... ...
... ... @@ -41,6 +41,10 @@ const getSocketInstance = (request: ExtraRequestConfigType) => {
41 41 const socketUrl = `${getOriginUrl(requestOriginUrl || '')}${requestUrl}?token=${token}`
42 42
43 43 const instance = useWebSocket(socketUrl, {
  44 + autoReconnect: {
  45 + retries: 20,
  46 + delay: 1000 * 30
  47 + },
44 48 onMessage() {
45 49 const { data: originData } = instance
46 50 const value = parse(unref(originData)) as SocketReceiveMessageType
... ... @@ -121,7 +125,7 @@ export const useChartDataSocket = () => {
121 125 return {
122 126 initial,
123 127 sendMessage,
124   - disconnectWs
  128 + disconnectWs,
125 129 }
126 130 }
127 131
... ...
  1 +/**
  2 + * 此hook的作用是针对echarts图表类型,legend图例,映射成物模型中文
  3 + */
  4 +
  5 +export const useEchartsMapLegend = (chartConfig: Recordable, seriesArr: Recordable[]) => {
  6 + const { request } = chartConfig
  7 + const {
  8 + requestParams: {
  9 + Params: { attrName }
  10 + }
  11 + } = request || {}
  12 + seriesArr?.forEach((item: Recordable, index: number) => {
  13 + item.name = attrName?.[index]
  14 + })
  15 +}
... ...
... ... @@ -27,6 +27,7 @@ import { isPreview } from '@/utils'
27 27 import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
28 28 import isObject from 'lodash/isObject'
29 29 import cloneDeep from 'lodash/cloneDeep'
  30 +import { useEchartsMapLegend } from '@/hooks/external/useEchartLegendMapChinese.hook'
30 31
31 32 const props = defineProps({
32 33 themeSetting: {
... ... @@ -64,6 +65,7 @@ watch(
64 65 for (let i = 0; i < newData.dimensions.length - 1; i++) {
65 66 seriesArr.push(cloneDeep(seriesItem))
66 67 }
  68 + useEchartsMapLegend(props.chartConfig, seriesArr)
67 69 replaceMergeArr.value = ['series']
68 70 props.chartConfig.option.series = seriesArr
69 71 nextTick(() => {
... ...
... ... @@ -5,6 +5,9 @@
5 5 :theme="themeColor"
6 6 :option="option"
7 7 :manual-update="isPreview()"
  8 + :update-options="{
  9 + replaceMerge: replaceMergeArr
  10 + }"
8 11 autoresize
9 12 ></v-chart>
10 13 </template>
... ... @@ -23,6 +26,11 @@ import { useChartDataFetch } from '@/hooks'
23 26 import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
24 27 import { isPreview } from '@/utils'
25 28 import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
  29 +import { SocketReceiveMessageType } from '@/store/external/modules/socketStore.d'
  30 +import isObject from 'lodash/isObject'
  31 +import { useAssembleDataHooks } from '@/hooks/external/useAssembleData.hook'
  32 +import { useEchartsMapLegend } from '@/hooks/external/useEchartLegendMapChinese.hook'
  33 +import cloneDeep from 'lodash/cloneDeep'
26 34
27 35 const props = defineProps({
28 36 themeSetting: {
... ... @@ -43,25 +51,34 @@ const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSe
43 51
44 52 use([DatasetComponent, CanvasRenderer, BarChart, LineChart, GridComponent, TooltipComponent, LegendComponent])
45 53
  54 +const chartEditStore = useChartEditStore()
  55 +
46 56 const replaceMergeArr = ref<string[]>()
47 57
48 58 const option = computed(() => {
49 59 return mergeTheme(props.chartConfig.option, props.themeSetting, includes)
50 60 })
51 61
  62 +// dataset 无法变更条数的补丁
52 63 watch(
53 64 () => props.chartConfig.option.dataset,
54   - (newData, oldData) => {
55   - if (newData.dimensions.length !== oldData.dimensions.length) {
56   - const seriesArr = []
57   - for (let i = 0; i < newData.dimensions.length - 1; i++) {
58   - seriesArr.push(barSeriesItem, lineSeriesItem)
  65 + (newData: { dimensions: any }, oldData) => {
  66 + try {
  67 + if (!isObject(newData) || !('dimensions' in newData)) return
  68 + if (Array.isArray(newData?.dimensions)) {
  69 + const seriesArr = []
  70 + for (let i = 0; i < newData.dimensions.length - 1; i++) {
  71 + seriesArr.push(cloneDeep(barSeriesItem),cloneDeep(lineSeriesItem))
  72 + }
  73 + useEchartsMapLegend(props.chartConfig, seriesArr)
  74 + replaceMergeArr.value = ['series']
  75 + props.chartConfig.option.series = seriesArr
  76 + nextTick(() => {
  77 + replaceMergeArr.value = []
  78 + })
59 79 }
60   - replaceMergeArr.value = ['series']
61   - props.chartConfig.option.series = seriesArr
62   - nextTick(() => {
63   - replaceMergeArr.value = []
64   - })
  80 + } catch (error) {
  81 + console.log(error)
65 82 }
66 83 },
67 84 {
... ... @@ -69,5 +86,53 @@ watch(
69 86 }
70 87 )
71 88
72   -const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore)
  89 +//fix 修复v-chart图表绑定联动组件视图不更新问题
  90 +const updateVChart =async (newData:SocketReceiveMessageType) => {
  91 + //区分是普通请求还是ws请求
  92 + if (!isObject(newData) || !('dimensions' in newData)) {
  93 + const { data } = newData
  94 + const { keys, record } = useAssembleDataHooks(data)
  95 + vChartRef.value?.setOption({
  96 + dataset: {
  97 + dimensions: ['ts', ...keys],
  98 + source: [record]
  99 + }
  100 + })
  101 + } else {
  102 + //异步更新,同步更新会造成联动组件控制,图表不及时更新
  103 + await nextTick().then(()=>{
  104 + vChartRef.value?.setOption(
  105 + {
  106 + ...option.value,
  107 + dataset: newData
  108 + },
  109 + {
  110 + notMerge: true
  111 + }
  112 + )
  113 + })
  114 + }
  115 +}
  116 +
  117 +const {vChartRef} = useChartDataFetch(props.chartConfig, useChartEditStore, (newData) => {
  118 + //联动支持分组
  119 + /**
  120 + * 修复多个分组,然后下拉框联动,会影响另一个组件
  121 + */
  122 + chartEditStore.getComponentList.forEach(targetItem => {
  123 + if (targetItem.isGroup) {
  124 + targetItem.groupList?.forEach(groupItem => {
  125 + if (groupItem.id === props.chartConfig.id) {
  126 + groupItem.option.dataset = newData
  127 + }
  128 + })
  129 + } else {
  130 + if (targetItem.id === props.chartConfig.id) {
  131 + targetItem.option.dataset = newData
  132 + }
  133 + }
  134 + })
  135 + //
  136 + updateVChart(newData)
  137 +})
73 138 </script>
... ...
... ... @@ -17,6 +17,7 @@ import { chartColorsSearch, defaultTheme } from '@/settings/chartThemes/index'
17 17 import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
18 18 import { useChartDataFetch } from '@/hooks'
19 19 import { isPreview, colorGradientCustomMerge} from '@/utils'
  20 +import { useEchartsMapLegend } from '@/hooks/external/useEchartLegendMapChinese.hook'
20 21
21 22 const props = defineProps({
22 23 themeSetting: {
... ... @@ -79,6 +80,9 @@ watch(
79 80 () => props.chartConfig.option.dataset,
80 81 () => {
81 82 option.value = props.chartConfig.option
  83 + useEchartsMapLegend(props.chartConfig, props.chartConfig.option.series)
  84 + },{
  85 + deep: false
82 86 }
83 87 )
84 88
... ...
... ... @@ -17,6 +17,7 @@ import { chartColorsSearch, defaultTheme } from '@/settings/chartThemes/index'
17 17 import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
18 18 import { useChartDataFetch } from '@/hooks'
19 19 import { isPreview, colorGradientCustomMerge } from '@/utils'
  20 +import { useEchartsMapLegend } from '@/hooks/external/useEchartLegendMapChinese.hook'
20 21
21 22 const props = defineProps({
22 23 themeSetting: {
... ... @@ -73,6 +74,7 @@ watch(
73 74 () => props.chartConfig.option.dataset,
74 75 () => {
75 76 option.value = props.chartConfig.option
  77 + useEchartsMapLegend(props.chartConfig, props.chartConfig.option.series)
76 78 },
77 79 {
78 80 deep: false
... ...
1 1 <template>
2 2 <n-space class="go-decorates-flipper-number" :size="flipperGap" align="center" justify="center">
3   - <flipper
4   - :count="item"
5   - :width="flipperWidth"
6   - :height="flipperHeight"
7   - :front-color="flipperTextColor"
8   - :back-color="flipperBgColor"
9   - :radius="flipperRadius"
10   - :flip-type="flipperType"
11   - :duration="flipperSpeed"
12   - :border-width="flipperBorderWidth"
13   - v-for="(item, index) in flipperData"
14   - :key="index"
15   - class="go-d-block"
16   - />
  3 + <flipper :count="item" :width="flipperWidth" :height="flipperHeight" :front-color="flipperTextColor"
  4 + :back-color="flipperBgColor" :radius="flipperRadius" :flip-type="flipperType" :duration="flipperSpeed"
  5 + :border-width="flipperBorderWidth" v-for="(item, index) in flipperData" :key="index" class="go-d-block" />
17 6 </n-space>
18 7 </template>
19 8
20 9 <script setup lang="ts">
21   -import { PropType, toRefs, watch, ref } from 'vue'
  10 +import { PropType, toRefs, watch, ref, computed, unref } from 'vue'
22 11 import { CreateComponentType } from '@/packages/index.d'
23 12 import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
24 13 import { useChartDataFetch } from '@/hooks'
25 14 import { Flipper } from '@/components/Pages/Flipper'
26 15 import { OptionType } from './config'
  16 +import { RequestContentTypeEnum } from '@/enums/external/httpEnum'
  17 +import { useTargetData } from '@/views/chart/ContentConfigurations/components/hooks/useTargetData.hook'
27 18
28 19 const props = defineProps({
29 20 chartConfig: {
... ... @@ -34,6 +25,37 @@ const props = defineProps({
34 25
35 26 const { w, h } = toRefs(props.chartConfig.attr)
36 27
  28 +const { targetData, chartEditStore } = useTargetData()
  29 +
  30 +const isWebsocket = computed(() => {
  31 + const result = query(chartEditStore.getComponentList)
  32 + if (result === false) return false
  33 +
  34 + if (result.id === targetData.value.id)
  35 + return targetData.value.request.requestContentType as RequestContentTypeEnum === RequestContentTypeEnum.WEB_SOCKET
  36 + else {
  37 + return result.request.requestContentType as RequestContentTypeEnum === RequestContentTypeEnum.WEB_SOCKET
  38 + }
  39 +})
  40 +
  41 +function query(list: CreateComponentType[]) {
  42 + if (!list || !list?.length) return false
  43 +
  44 + for (const item of list) {
  45 + if (item.id === targetData.value.id) {
  46 + return item
  47 + }
  48 + if (item.groupList && item.groupList?.length) {
  49 + const flag = query(list)
  50 + if (flag) {
  51 + return item
  52 + }
  53 + }
  54 + }
  55 +
  56 + return false
  57 +}
  58 +
37 59 const {
38 60 flipperLength,
39 61 flipperBgColor,
... ... @@ -75,6 +97,7 @@ watch(
75 97 )
76 98
77 99 useChartDataFetch(props.chartConfig, useChartEditStore, (newVal: string | number) => {
  100 + if (unref(isWebsocket)) return
78 101 updateDatasetHandler(newVal)
79 102 })
80 103 </script>
... ...
... ... @@ -10,5 +10,5 @@ export const InputsInputConfig: ConfigType = {
10 10 categoryName: ChatCategoryEnumName.INPUTS,
11 11 package: PackagesCategoryEnum.INFORMATIONS,
12 12 chartFrame: ChartFrameEnum.STATIC,
13   - image: 'inputs_select.png'
  13 + image: 'inputs_input.png'
14 14 }
\ No newline at end of file
... ...
... ... @@ -8,15 +8,19 @@ export const option = {
8 8 header: ['列1', '列2', '列3'],
9 9 dataset: dataJson,
10 10 index: true,
11   - columnWidth: [30, 100, 100],
12   - align: ['center', 'right', 'right', 'right'],
  11 + columnWidth: [100, 300, 300, 300],
  12 + align: ['center', 'center', 'center', 'center'],
13 13 rowNum: 5,
14 14 waitTime: 2,
15 15 headerHeight: 35,
16 16 carousel: 'single',
17 17 headerBGC: '#00BAFF',
18 18 oddRowBGC: '#003B51',
19   - evenRowBGC: '#0A2732'
  19 + evenRowBGC: '#0A2732',
  20 + ceilSpanColor: '#FFFFFF',
  21 + ceilSpanFontSize: 16,
  22 + headerSpanColor: '#FFFFFF',
  23 + headerSpanFontSize: 16
20 24 }
21 25
22 26 export default class Config extends PublicConfigClass implements CreateComponentType {
... ...
... ... @@ -45,12 +45,37 @@
45 45 v-model:value="optionData.carousel"
46 46 :options="[
47 47 { label: '单条轮播', value: 'single' },
48   - { label: '整页轮播', value: 'page' },
  48 + { label: '整页轮播', value: 'page' }
49 49 ]"
50 50 />
51 51 </SettingItem>
52 52 </SettingItemBox>
53   -
  53 + <SettingItemBox name="表头字体">
  54 + <SettingItem name="颜色">
  55 + <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.headerSpanColor"></n-color-picker>
  56 + </SettingItem>
  57 + <SettingItem name="大小">
  58 + <n-input-number
  59 + v-model:value="optionData.headerSpanFontSize"
  60 + :min="1"
  61 + size="small"
  62 + placeholder="请输入"
  63 + ></n-input-number>
  64 + </SettingItem>
  65 + </SettingItemBox>
  66 + <SettingItemBox name="内容字体">
  67 + <SettingItem name="颜色">
  68 + <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.ceilSpanColor"></n-color-picker>
  69 + </SettingItem>
  70 + <SettingItem name="大小">
  71 + <n-input-number
  72 + v-model:value="optionData.ceilSpanFontSize"
  73 + :min="1"
  74 + size="small"
  75 + placeholder="请输入"
  76 + ></n-input-number>
  77 + </SettingItem>
  78 + </SettingItemBox>
54 79 <SettingItemBox name="样式">
55 80 <SettingItem name="表头背景色">
56 81 <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.headerBGC"></n-color-picker>
... ...
... ... @@ -6,13 +6,15 @@
6 6 :style="`background-color: ${status.mergedConfig.headerBGC};`"
7 7 >
8 8 <div
9   - class="header-item"
  9 + class="header-item singe-line"
10 10 v-for="(headerItem, i) in status.header"
11 11 :key="`${headerItem}${i}`"
12 12 :style="`
13 13 height: ${status.mergedConfig.headerHeight}px;
14 14 line-height: ${status.mergedConfig.headerHeight}px;
15 15 width: ${status.widths[i]}px;
  16 + color:${headerSpanColor};
  17 + font-size:${headerSpanFontSize}px;
16 18 `"
17 19 :align="status.aligns[i]"
18 20 v-html="headerItem"
... ... @@ -24,30 +26,32 @@
24 26 class="rows"
25 27 :style="`height: ${h - (status.header.length ? status.mergedConfig.headerHeight : 0)}px;`"
26 28 >
27   - <div v-if="status.rows.length">
28   - <div
29   - class="row-item"
30   - v-for="(row, ri) in status.rows"
31   - :key="`${row.toString()}${row.scroll}`"
32   - :style="`
  29 + <div v-if="status.rows.length">
  30 + <div
  31 + class="row-item"
  32 + v-for="(row, ri) in status.rows"
  33 + :key="`${row.toString()}${row.scroll}`"
  34 + :style="`
33 35 height: ${status.heights[ri]}px;
34 36 line-height: ${status.heights[ri]}px;
35 37 background-color: ${status.mergedConfig[row.rowIndex % 2 === 0 ? 'evenRowBGC' : 'oddRowBGC']};
36 38 `"
37   - >
38   - <div
39   - class="ceil"
40   - v-for="(ceil, ci) in row.ceils"
41   - :key="`${ceil}${ri}${ci}`"
42   - :style="`width: ${status.widths[ci]}px;`"
43   - :align="status.aligns[ci]"
44   - v-html="ceil"
45   - />
  39 + >
  40 + <div
  41 + class="ceil singe-line"
  42 + v-for="(ceil, ci) in row.ceils"
  43 + :key="`${ceil}${ri}${ci}`"
  44 + :style="`
  45 + width: ${status.widths[ci]}px;
  46 + color:${ceilSpanColor};
  47 + font-size:${ceilSpanFontSize}px;
  48 + `"
  49 + :align="status.aligns[ci]"
  50 + v-html="ceil"
  51 + />
  52 + </div>
46 53 </div>
47   - </div>
48   - <div v-else class="nullData">
49   - 暂无数据
50   - </div>
  54 + <div v-else class="nullData">暂无数据</div>
51 55 </div>
52 56 </div>
53 57 </template>
... ... @@ -70,7 +74,7 @@ const props = defineProps({
70 74 // 这里能拿到图表宽高等
71 75 const { w, h } = toRefs(props.chartConfig.attr)
72 76 // 这里能拿到上面 config.ts 里的 option 数据
73   -// const { rowNum, headerHeight, index, backgroundColor } = toRefs(props.chartConfig.option)
  77 +const { ceilSpanColor, ceilSpanFontSize, headerSpanColor, headerSpanFontSize } = toRefs(props.chartConfig.option)
74 78
75 79 const status = reactive({
76 80 defaultConfig: {
... ... @@ -355,6 +359,12 @@ onUnmounted(() => {
355 359 </script>
356 360
357 361 <style lang="scss" scoped>
  362 +.singe-line {
  363 + text-overflow: ellipsis;
  364 + overflow: hidden;
  365 + word-break: break-all;
  366 + white-space: nowrap;
  367 +}
358 368 .dv-scroll-board {
359 369 position: relative;
360 370 width: 100%;
... ... @@ -389,11 +399,11 @@ onUnmounted(() => {
389 399 overflow: hidden;
390 400 }
391 401 }
392   - .nullData{
  402 + .nullData {
393 403 display: flex;
394 404 justify-content: center;
395 405 align-items: center;
396   - color:white;
  406 + color: white;
397 407 height: 100%;
398 408 width: 100%;
399 409 background: #356b80;
... ...
... ... @@ -35,6 +35,7 @@ import cloneDeep from 'lodash/cloneDeep'
35 35 import { useAssembleDataHooks } from '@/hooks/external/useAssembleData.hook'
36 36 import { SocketReceiveMessageType } from '@/store/external/modules/socketStore.d'
37 37 import { CreateComponentGroupType, CreateComponentType } from '@/packages/index.d'
  38 +import { useEchartsMapLegend } from '@/hooks/external/useEchartLegendMapChinese.hook'
38 39
39 40 const props = defineProps({
40 41 themeSetting: {
... ... @@ -112,6 +113,7 @@ watch(
112 113 }
113 114 replaceMergeArr.value = ['series']
114 115 nextTick(() => {
  116 + useEchartsMapLegend(props.chartConfig, props.chartConfig.option.series)
115 117 replaceMergeArr.value = []
116 118 })
117 119 }
... ... @@ -244,6 +246,7 @@ const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore, ne
244 246 }
245 247 })
246 248 //
  249 + addPieInterval(newData)
247 250 updateVChart(newData)
248 251 })
249 252
... ...
... ... @@ -35,6 +35,7 @@ import { useFullScreen } from '../../utls/fullScreen'
35 35 import { useAssembleDataHooks } from '@/hooks/external/useAssembleData.hook'
36 36 import { SocketReceiveMessageType } from '@/store/external/modules/socketStore.d'
37 37 import {CreateComponentGroupType, CreateComponentType} from '@/packages/index.d'
  38 +import { useEchartsMapLegend } from '@/hooks/external/useEchartLegendMapChinese.hook'
38 39
39 40 const props = defineProps({
40 41 themeSetting: {
... ... @@ -112,6 +113,7 @@ watch(
112 113 }
113 114 replaceMergeArr.value = ['series']
114 115 nextTick(() => {
  116 + useEchartsMapLegend(props.chartConfig, props.chartConfig.option.series)
115 117 replaceMergeArr.value = []
116 118 })
117 119 }
... ... @@ -243,10 +245,10 @@ const {vChartRef} = useChartDataFetch(props.chartConfig, useChartEditStore, (new
243 245 }
244 246 })
245 247 //
  248 + addPieInterval(newData)
246 249 updateVChart(newData)
247 250 })
248 251
249   -
250 252 onMounted(() => {
251 253 seriesDataMaxLength = dataJson.source.length
252 254 if (props.chartConfig.option.isCarousel) {
... ...
... ... @@ -41,6 +41,7 @@ import { useAssembleDataHooks } from '@/hooks/external/useAssembleData.hook'
41 41 import { SocketReceiveMessageType } from '@/store/external/modules/socketStore.d'
42 42 import { useChartInteract } from '@/hooks/external/useChartSelectDeviceInteract.hook'
43 43 import { getPacketIntervalByRange } from './helper'
  44 +import { useEchartsMapLegend } from '@/hooks/external/useEchartLegendMapChinese.hook'
44 45
45 46 const props = defineProps({
46 47 themeSetting: {
... ... @@ -122,6 +123,7 @@ watch(
122 123 }
123 124 replaceMergeArr.value = ['series']
124 125 nextTick(() => {
  126 + useEchartsMapLegend(props.chartConfig, props.chartConfig.option.series)
125 127 replaceMergeArr.value = []
126 128 })
127 129 }
... ... @@ -254,6 +256,7 @@ const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore, (n
254 256 }
255 257 })
256 258 //
  259 + addPieInterval(newData)
257 260 updateVChart(newData)
258 261 })
259 262
... ...
... ... @@ -35,6 +35,7 @@ import cloneDeep from 'lodash/cloneDeep'
35 35 import { useAssembleDataHooks } from '@/hooks/external/useAssembleData.hook'
36 36 import { SocketReceiveMessageType } from '@/store/external/modules/socketStore.d'
37 37 import {CreateComponentGroupType, CreateComponentType} from '@/packages/index.d'
  38 +import { useEchartsMapLegend } from '@/hooks/external/useEchartLegendMapChinese.hook'
38 39
39 40 const props = defineProps({
40 41 themeSetting: {
... ... @@ -214,6 +215,7 @@ watch(
214 215 }
215 216 replaceMergeArr.value = ['series']
216 217 nextTick(() => {
  218 + useEchartsMapLegend(props.chartConfig, props.chartConfig.option.series)
217 219 replaceMergeArr.value = []
218 220 })
219 221 }
... ... @@ -273,6 +275,7 @@ const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore, ne
273 275 }
274 276 })
275 277 //
  278 + addPieInterval(newData)
276 279 updateVChart(newData)
277 280 })
278 281
... ...
... ... @@ -8,7 +8,7 @@ export const includes = ['legend', 'xAxis', 'yAxis', 'grid']
8 8 export const seriesItem = {
9 9 type: 'line',
10 10 label: {
11   - show: true,
  11 + show: false,
12 12 position: 'top',
13 13 color: '#fff',
14 14 fontSize: 12
... ...
1 1 <template>
2   - <v-chart
3   - ref="vChartRef"
4   - :init-options="initOptions"
5   - :theme="themeColor"
6   - :option="option"
7   - :manual-update="isPreview()"
  2 + <v-chart ref="vChartRef" :init-options="initOptions" :theme="themeColor" :option="option" :manual-update="isPreview()"
8 3 :update-options="{
9 4 replaceMerge: replaceMergeArr
10   - }"
11   - autoresize
12   - @mouseover="handleHighlight"
13   - @mouseout="handleDownplay"
14   - >
  5 + }" autoresize @mouseover="handleHighlight" @mouseout="handleDownplay">
15 6 </v-chart>
16 7 </template>
17 8
... ... @@ -186,6 +177,12 @@ watch(
186 177 for (let i = 0; i < dimensionsGap; i++) {
187 178 seriesArr.push(cloneDeep(seriesItem))
188 179 }
  180 +
  181 + const { request } = props.chartConfig
  182 + const { requestParams: { Params: { attrName } } } = request || {}
  183 + seriesArr.forEach((item: any, index: number) => {
  184 + item.name = attrName?.[index]
  185 + })
189 186 props.chartConfig.option.series.push(...seriesArr)
190 187 }
191 188 replaceMergeArr.value = ['series']
... ... @@ -205,23 +202,29 @@ watch(
205 202 //fix 修复v-chart图表绑定联动组件视图不更新问题
206 203 const updateVChart = (newData: SocketReceiveMessageType) => {
207 204 if (!newData) return
208   - const { option } = props.chartConfig
  205 + const { option, request } = props.chartConfig
  206 + const { requestParams: { Params: { attrName } } } = request || {}
209 207 const { dataset: overrideDataset } = option
210 208 const { dimensions } = overrideDataset
211 209 if (!Array.isArray(dimensions)) return
212 210 const { data } = newData
213   - const { keys, record } = useAssembleDataHooks(data,dimensions)
  211 + const { record } = useAssembleDataHooks(data, dimensions, (attrName as any))
214 212 if (unref(realTimeList).length >= chartMaxDataPoint.value) {
215 213 unref(realTimeList).splice(0, 1)
216 214 }
217 215 realTimeList.value.push(record)
218 216 const dataset = {
219   - dimensions: ['ts', ...keys],
  217 + dimensions: ['ts', ...attrName],
220 218 source: toRaw(unref(realTimeList))
221 219 }
  220 + option.series.forEach((item: any, index: number) => {
  221 + item.name = attrName?.[index]
  222 + })
  223 +
222 224 vChartRef.value?.setOption({
223   - ...option.value,
224   - dataset
  225 + ...option,
  226 + dataset,
  227 + legend: { data: attrName || [] }
225 228 })
226 229 }
227 230 const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore, newData => {
... ...
... ... @@ -3,9 +3,10 @@
3 3 * @param data {'wendu':[[xxxxxx,xxxx]]}
4 4 * @returns keys:[xx,xx,xx] record:{'x':'xx'}
5 5 */
  6 +import { isNullOrUnDef } from '@/utils/external/is'
6 7 import dayjs from 'dayjs'
7 8
8   -export const useAssembleDataHooks = (data: Record<string, string | [number, string]>, dimensions: string[]) => {
  9 +export const useAssembleDataHooks = (data: Record<string, string | [number, string]>, dimensions: string[],attrName?:string[]) => {
9 10 const formatValueToNumber = (value: string | number, defaultValue = 0) =>
10 11 isNaN(value as number) ? defaultValue : Number(value)
11 12 const tempObj: Recordable = {}
... ... @@ -17,11 +18,12 @@ export const useAssembleDataHooks = (data: Record<string, string | [number, stri
17 18 })
18 19 })
19 20 const keys = Object.keys(tempObj)
20   - const record = keys.reduce((prev, next) => {
  21 + const record = keys.reduce((prev, next,index) => {
21 22 const [latest] = data[next] || []
  23 + if (isNullOrUnDef(latest)) return prev
22 24 const [ts, value] = latest as unknown as string[]
23 25 //把值转为number类型 wendu:"23" 转为 wendu:23
24   - return { ...prev, ts: dayjs(ts).format('YYYY-MM-DD HH:mm:ss'), [next]: formatValueToNumber(value) }
  26 + return { ...prev, ts: dayjs(ts).format('YYYY-MM-DD HH:mm:ss'),[ attrName![index]]: formatValueToNumber(value) }
25 27 }, {})
26 28
27 29 return {
... ...
... ... @@ -136,6 +136,7 @@ const stopWatch = watch(
136 136 // 预览
137 137 useChartDataFetch(props.chartConfig, useChartEditStore, newData => {
138 138 const { data } = newData
  139 + // 不是结构体
139 140 if (Reflect.get(data, 'longitude') && Reflect.get(data, 'latitude')) {
140 141 //必须有经纬度
141 142 for (let _ in data) {
... ... @@ -143,6 +144,13 @@ useChartDataFetch(props.chartConfig, useChartEditStore, newData => {
143 144 viewControlPaths.value.push([Number(data['longitude'][0][1]), Number(data['latitude'][0][1])])
144 145 }
145 146 renderLocaLayerLine(viewControlPaths.value)
  147 + } else {
  148 + // 序列化获取里面的经纬度
  149 + const values = Object.values(data) as string[][]
  150 + const serializeValue = JSON.parse(values[0][0][1])
  151 + const { longitude, latitude } = serializeValue
  152 + viewControlPaths.value.push([Number(longitude), Number(latitude)])
  153 + renderLocaLayerLine(viewControlPaths.value)
146 154 }
147 155 stopWatch()
148 156 })
... ...
1 1 <script lang="ts" setup name="SelectCity">
2   -import { onMounted, reactive } from 'vue'
  2 +import { onMounted, reactive, nextTick, ref } from 'vue'
3 3 import { getAreaList } from '@/api/external/common/index'
4   -import { areaEnum } from '../config'
  4 +import { areaEnum, ifSpecialCity } from '../config'
5 5
6 6 const props = defineProps({
7 7 drillingIn: {
... ... @@ -25,45 +25,67 @@ const selectValues = reactive({
25 25 provinceValue: 'china',
26 26 cityValue: null,
27 27 countyValue: null,
28   - levelStr: areaEnum.COUNTRY
  28 + levelStr: areaEnum.COUNTRY,
  29 + areaName: ''
29 30 })
30 31
31 32 const getAreaLists = async (level = areaEnum.PROVINCE, parentId = 1) => {
32 33 const resp = await getAreaList({
33 34 level,
34   - parentId
  35 + parentId:(parentId as any)==='china'?1:parentId
35 36 })
36 37 if (!resp) return []
37   - return resp.map((item: any) => ({ label: item.name, value: item.code }))
  38 + return resp.map((item: Recordable) => ({ label: item.name, value: item.code,parentId:item.parentId }))
38 39 }
39 40
40 41 onMounted(async () => {
41 42 selectOptions.provinceOptions = await getAreaLists()
42   - ;(selectOptions.provinceOptions as never as any).unshift({
  43 + ;(selectOptions.provinceOptions as never as Recordable[]).unshift({
43 44 label: '中国',
44 45 value: 'china'
45 46 })
46   - onHandleSelectProvince(props.optionData?.mapRegion.saveSelect['provinceValue'])
  47 + onHandleSelectProvince(props.optionData?.mapRegion.saveSelect['provinceValue'], {})
47 48 for (let i in selectValues) Reflect.set(selectValues, i, props.optionData?.mapRegion.saveSelect[i])
48 49 })
49 50
50   -const onHandleSelectProvince = async (value: number | string) => {
51   - selectValues.cityValue = null
  51 +
  52 +
  53 +const disabledCity = ref<boolean>(false)//直辖市禁用下面省份选择
  54 +const onHandleSelectProvince = async (value: number | string, options: Recordable) => {
  55 + selectValues.cityValue = null
52 56 selectValues.countyValue = null
53   - if (value === 'china') return (selectValues.levelStr = areaEnum.COUNTRY)
54   - selectOptions.cityOptions = await getAreaLists(areaEnum.CITY, value as any)
  57 + if (value === 'china') {
  58 + disabledCity.value = false
  59 + selectValues.provinceValue = 'china'
  60 + selectOptions.cityOptions = []
  61 + selectValues.areaName = ''
  62 + selectValues.levelStr= areaEnum.COUNTRY
  63 + return
  64 + }
  65 + const cityOptions = await getAreaLists(areaEnum.CITY, value as number)
  66 + selectOptions.cityOptions = cityOptions
55 67 selectValues.levelStr = areaEnum.PROVINCE
  68 + selectValues.areaName = options.label
  69 + if(ifSpecialCity(value)){//直辖市的话就不能跟省份的逻辑一样了
  70 + selectOptions.cityOptions = cityOptions.map((item:any)=>({...item,value:item.parentId}))
  71 + disabledCity.value = true
  72 + return
  73 + }
  74 + disabledCity.value = false
56 75 }
57 76
58   -const onHandleSelectCity = async (value: number) => {
  77 +const onHandleSelectCity = async (value: number, options: Recordable) => {
59 78 selectValues.countyValue = null
60 79 selectOptions.countryOptions = await getAreaLists(areaEnum.COUNTY, value)
61 80 selectValues.levelStr = areaEnum.CITY
  81 + selectValues.areaName = options.label
62 82 }
63 83
64   -const onHandleSubmit = () => {
  84 +const onHandleSubmit = async () => {
  85 + await nextTick()
65 86 emits('submit', selectValues)
66 87 }
  88 +
67 89 const resetValue = () => {
68 90 selectValues.provinceValue = 'china'
69 91 selectValues.cityValue = null
... ... @@ -72,6 +94,7 @@ const resetValue = () => {
72 94 selectOptions.cityOptions = []
73 95 selectOptions.countryOptions = []
74 96 }
  97 +
75 98 defineExpose({
76 99 resetValue
77 100 })
... ... @@ -87,6 +110,7 @@ defineExpose({
87 110 />
88 111 <n-select
89 112 v-if="!props.drillingIn"
  113 + :disabled="disabledCity"
90 114 @change="onHandleSelectCity"
91 115 placeholder="请选择城市"
92 116 v-model:value="selectValues.cityValue"
... ...
... ... @@ -4,6 +4,7 @@ import { chartInitConfig } from '@/settings/designSetting'
4 4 import { CreateComponentType } from '@/packages/index.d'
5 5 import cloneDeep from 'lodash/cloneDeep'
6 6 import dataMaps from './data.json'
  7 +import { getAreaList } from '@/api/external/common'
7 8
8 9 //省市区枚举
9 10 export const enum areaEnum {
... ... @@ -16,19 +17,20 @@ export const enum areaEnum {
16 17 }
17 18
18 19 export interface regionInfo {
19   - provinceValue:string
20   - cityValue: string|null
21   - countyValue: string|null
22   - levelStr:areaEnum
  20 + provinceValue: string
  21 + cityValue: string | null
  22 + countyValue: string | null
  23 + levelStr: areaEnum
  24 + areaName: string
23 25 }
24 26
25 27 type itemOption = {
26   - label:string
27   - value:string
  28 + label: string
  29 + value: string
28 30 }
29   -export interface regionOption{
30   - provinceOptions: itemOption[],
31   - cityOptions: itemOption[],
  31 +export interface regionOption {
  32 + provinceOptions: itemOption[]
  33 + cityOptions: itemOption[]
32 34 countryOptions: itemOption[]
33 35 }
34 36
... ... @@ -36,18 +38,22 @@ export interface regionOption{
36 38 export interface historyParentType {
37 39 adcode: number
38 40 level: string
  41 + areaName: string
39 42 }
40 43
41   -export interface backMapLevel{
42   - (levelStr:string): boolean
43   - (level:string): boolean
44   - (): void
  44 +export interface backMapLevel {
  45 + (str: string): boolean
45 46 (): void
46 47 }
47 48
  49 +export interface levelFunc {
  50 + (str: string): boolean
  51 +}
  52 +
48 53 //数据源接口
49 54 export interface dataPointI {
50 55 name: string
  56 + city_name: string
51 57 value: number[]
52 58 adcode: number
53 59 height: number
... ... @@ -59,83 +65,128 @@ export interface dataPointI {
59 65 }
60 66 }
61 67
  68 +//地区上级对应配置
  69 +export const regionMapParentArea = {
  70 + PROVINCE: areaEnum.COUNTRY, //省份的上一级 中国
  71 + CITY: areaEnum.PROVINCE, //城市的上一级 省份
  72 + COUNTY: areaEnum.CITY, //县或者区的上一级 城市
  73 + TOWN: areaEnum.COUNTY //镇的上一级 县或者区
  74 +}
  75 +
  76 +
  77 +
62 78 export const includes = []
63 79
  80 +// 特殊处理安徽省的下钻
  81 +export const specialTreatmentAnhui = [
  82 + '合肥市',
  83 + '马鞍山市',
  84 + '淮北市',
  85 + '宿州市',
  86 + '阜阳市',
  87 + '蚌埠市',
  88 + '淮南市',
  89 + '滁州市',
  90 + '六安市',
  91 + '巢湖市',
  92 + '芜湖市',
  93 + '亳州市',
  94 + '安庆市',
  95 + '池州市',
  96 + '铜陵市',
  97 + '宣城市',
  98 + '黄山市'
  99 +]
  100 +
64 101 export const option = {
65 102 iconColor: 'black',
66 103 showIcon: false,
67 104 iconDistanceRight: 20,
68 105 iconDistanceTop: 20,
69   - drillingIn: false,
  106 + drillingIn: true,
70 107 dataset: dataMaps,
  108 + isShowExecute:false,
71 109 saveClickRegion: {
72 110 level: ''
73 111 },
74 112 mapRegion: {
75 113 adcode: 'china',
76 114 showHainanIsLands: true,
  115 + areaName: '',
77 116 saveSelect: {
78 117 levelStr: areaEnum.COUNTRY,
79   - cityValue:null,
80   - countyValue:null,
81   - provinceValue:'china'
  118 + cityValue: null,
  119 + countyValue: null,
  120 + provinceValue: 'china',
  121 + areaName: ''
82 122 }
83 123 },
84 124 tooltip: {
85 125 show: true
86 126 },
  127 + //三维地图有两种,一种是geo3D,另一种是map3D,但是如果使用geo3D,地图点击获取不到点击区域name
87 128 geo3D: {
88 129 show: false, // 隐藏该层,为true时会导致出现两个地图
89   - map: 'centerMap',
  130 + map: '',
90 131 roam: true,
91   - regionHeight: 0,
92   - emphasis: {
93   - label: {
94   - show: true,
95   - formatter: function (params: Recordable) {
96   - return params.data.name ? params.data.name : ' '
97   - },
98   - textStyle: {
99   - color: '#000',
100   - fontSize: 14
101   - }
102   - },
103   - itemStyle: {
104   - color: '#ff0'
105   - }
  132 + viewControl:{
  133 + distance:100
106 134 }
107 135 },
108 136 series: [
109 137 {
110 138 type: 'map3D',
111   - map: 'centerMap',
112   - name: 'centerMap',
113   - regionHeight: 3,
  139 + map: '',
  140 + name: '',
  141 + regionHeight: 0,
114 142 label: {
115 143 show: true,
116 144 formatter: function (params: Recordable) {
117 145 return params.data.name ? params.data.name : ' '
118 146 },
119 147 textStyle: {
120   - color: '#fff',
  148 + color: '#ffffffff',
121 149 fontSize: 14
122 150 }
123 151 },
124 152 itemStyle: {
125   - color: 'green',
  153 + color: '#3c7effff', //背景颜色
  154 + opacity: 1,
126 155 borderWidth: 0.8,
127   - borderColor: 'blue'
  156 + borderColor: '#51d6a9FF'
128 157 },
129   - data: []
  158 + emphasis: {
  159 + // 鼠标hover 高亮时图形和标签的样式 (当鼠标放上去时 label和itemStyle 的样式)
  160 + label: {
  161 + // label高亮时的配置
  162 + show: true,
  163 + textStyle: {
  164 + color: '#57c3c2ff',
  165 + fontSize: 14
  166 + }
  167 + },
  168 + itemStyle: {
  169 + color: '#1ba784ff'
  170 + }
  171 + },
  172 + data: [],
  173 + viewControl: {
  174 + projection: 'perspective'
  175 + }
130 176 },
131 177 {
132   - name: 'scatter3D',
133   - type: 'scatter3D',
  178 + name: 'bar3D',
  179 + type: 'bar3D',
134 180 coordinateSystem: 'geo3D',
135   - symbol: 'circle',
136   - symbolSize: 20,
137   - animation: true,
138   - data: dataMaps
  181 + // 倒角尺寸
  182 + bevelSize: 0,
  183 + minHeight: 5,
  184 + shading: 'lambert',
  185 + barSize: 1,
  186 + itemStyle: {
  187 + color: '#4482B1FF'
  188 + },
  189 + data: []
139 190 }
140 191 ]
141 192 }
... ... @@ -149,3 +200,544 @@ export default class Config extends PublicConfigClass implements CreateComponent
149 200 public chartConfig = cloneDeep(AddThreeDimensionalMapConfig)
150 201 public option = echartOptionProfixHandle(option, includes)
151 202 }
  203 +
  204 +export const ifSpecialCity = (value:string|number) => {
  205 + if(value==110000 || value ==120000 || value ==500000 || value==310000 || value==810000 || value==820000){//直辖市的话就不能跟省份的逻辑一样了
  206 + return true
  207 + }
  208 + return false
  209 +}
  210 +
  211 +
  212 +
  213 +//循环获取直辖市下面得区县数据
  214 +
  215 +export const getAreaLists = async (level = areaEnum.PROVINCE as any, parentId = 1) => {
  216 + const resp = await getAreaList({
  217 + level,
  218 + parentId:(parentId as any)=='china'?1:parentId
  219 + })
  220 + if (!resp) return []
  221 + return resp.map((item: Recordable) => ({ label: item.name, value: item.name, adcode: item.code }))
  222 +}
  223 +
  224 +export const allFetch = (arr:any,items:string) => {
  225 + return Promise.all(
  226 + arr.map(async(item:any)=>{
  227 + try{
  228 + const values = await getAreaLists(areaEnum.COUNTY, item[items] as any)
  229 + return {...values}
  230 + }catch(err){
  231 + console.log(err,'err')
  232 + return
  233 + }
  234 + })
  235 + )
  236 +}
  237 +
  238 +
  239 +// 缩放配置文件
  240 +export const setScale = (adcode: string | number) => {
  241 + switch (adcode) {
  242 + case 'china':
  243 + return { distance: 100 }
  244 + case '110000':
  245 + return { distance: 150 }
  246 + case '120000':
  247 + return { distance: 190 }
  248 + case '130000':
  249 + return { distance: 165 }
  250 + case '130200':
  251 + return { distance: 135 }
  252 + case '130300':
  253 + return { distance: 135 }
  254 + case '130400':
  255 + return { distance: 130 }
  256 + case '130500':
  257 + return { distance: 130 }
  258 + case '130700':
  259 + return { distance: 160 }
  260 + case '131000':
  261 + return { distance: 200 }
  262 + case '131100':
  263 + return { distance: 135 }
  264 + case '140000':
  265 + return { distance: 216 }
  266 + case '140200':
  267 + return { distance: 140 }
  268 + case '140300':
  269 + return { distance: 150 }
  270 + case '140400':
  271 + return { distance: 150 }
  272 + case '140600':
  273 + return { distance: 135 }
  274 + case '140700':
  275 + return { distance: 135 }
  276 + case '140800':
  277 + return { distance: 145 }
  278 + case '141000':
  279 + return { distance: 140 }
  280 + case '141100':
  281 + return { distance: 165 }
  282 + case '150000':
  283 + return { distance: 130 }
  284 + case '150100':
  285 + return { distance: 150 }
  286 + case '150300':
  287 + return { distance: 240 }
  288 + case '150400':
  289 + return { distance: 130 }
  290 + case '150500':
  291 + return { distance: 130 }
  292 + case '150600':
  293 + return { distance: 130 }
  294 + case '210000':
  295 + return { distance: 130 }
  296 + case '210100':
  297 + return { distance: 165 }
  298 + case '210200':
  299 + return { distance: 135 }
  300 + case '210300':
  301 + return { distance: 155 }
  302 + case '210600':
  303 + return { distance: 145 }
  304 + case '210800':
  305 + return { distance: 150 }
  306 + case '211200':
  307 + return { distance: 150 }
  308 + case '211300':
  309 + return { distance: 150 }
  310 + case '220100':
  311 + return { distance: 130 }
  312 + case '220200':
  313 + return { distance: 145 }
  314 + case '220400':
  315 + return { distance: 145 }
  316 + case '220500':
  317 + return { distance: 225 }
  318 + case '220600':
  319 + return { distance: 155 }
  320 + case '230600':
  321 + return { distance: 195 }
  322 + case '230700':
  323 + return { distance: 155 }
  324 + case '231000':
  325 + return { distance: 160 }
  326 + case '310000':
  327 + return { distance: 135 }
  328 + case '320000':
  329 + return { distance: 145 }
  330 + case '320100':
  331 + return { distance: 240 }
  332 + case '320200':
  333 + return { distance: 155 }
  334 + case '320400':
  335 + return { distance: 145 }
  336 + case '320500':
  337 + return { distance: 145 }
  338 + case '320600':
  339 + return { distance: 145 }
  340 + case '320800':
  341 + return { distance: 160 }
  342 + case '320900':
  343 + return { distance: 180 }
  344 + case '321000':
  345 + return { distance: 200 }
  346 + case '321100':
  347 + return { distance: 135 }
  348 + case '321200':
  349 + return { distance: 200 }
  350 + case '321300':
  351 + return { distance: 160 }
  352 + case '330000':
  353 + return { distance: 135 }
  354 + case '330100':
  355 + return { distance: 135 }
  356 + case '330200':
  357 + return { distance: 135 }
  358 + case '330300':
  359 + return { distance: 140 }
  360 + case '330400':
  361 + return { distance: 140 }
  362 + case '330500':
  363 + return { distance: 135 }
  364 + case '330600':
  365 + return { distance: 145 }
  366 + case '330800':
  367 + return { distance: 150 }
  368 + case '331100':
  369 + return { distance: 135 }
  370 + case '340000':
  371 + return { distance: 170 }
  372 + case '340100':
  373 + return { distance: 175 }
  374 + case '340300':
  375 + return { distance: 130 }
  376 + case '340400':
  377 + return { distance: 190 }
  378 + case '340600':
  379 + return { distance: 220 }
  380 + case '340800':
  381 + return { distance: 160 }
  382 + case '341200':
  383 + return { distance: 135 }
  384 + case '341300':
  385 + return { distance: 130 }
  386 + case '341500':
  387 + return { distance: 145 }
  388 + case '341600':
  389 + return { distance: 160 }
  390 + case '341700':
  391 + return { distance: 155 }
  392 + case '350000':
  393 + return { distance: 150}
  394 + case '350200':
  395 + return { distance: 140}
  396 + case '350500':
  397 + return { distance: 135}
  398 + case '350600':
  399 + return { distance: 190}
  400 + case '350900':
  401 + return { distance: 140}
  402 + case '360000':
  403 + return { distance: 190}
  404 + case '360100':
  405 + return { distance: 145}
  406 + case '360200':
  407 + return { distance: 225}
  408 + case '360300':
  409 + return { distance: 215}
  410 + case '360500':
  411 + return { distance: 135}
  412 + case '360600':
  413 + return { distance: 175}
  414 + case '360700':
  415 + return { distance: 175}
  416 + case '360800':
  417 + return { distance: 145}
  418 + case '360900':
  419 + return { distance: 135}
  420 + case '361000':
  421 + return { distance: 170}
  422 + case '361100':
  423 + return { distance: 140}
  424 + case '370000':
  425 + return { distance: 135 }
  426 + case '370100':
  427 + return { distance: 165 }
  428 + case '370200':
  429 + return { distance: 165 }
  430 + case '370300':
  431 + return { distance: 210 }
  432 + case '370400':
  433 + return { distance: 150 }
  434 + case '370500':
  435 + return { distance: 150 }
  436 + case '370800':
  437 + return { distance: 135 }
  438 + case '371100':
  439 + return { distance: 140 }
  440 + case '371300':
  441 + return { distance: 150 }
  442 + case '371400':
  443 + return { distance: 130 }
  444 + case '371500':
  445 + return { distance: 150 }
  446 + case '371600':
  447 + return { distance: 200 }
  448 + case '371700':
  449 + return { distance: 180 }
  450 + case '410100':
  451 + return { distance: 135 }
  452 + case '410200':
  453 + return { distance: 140 }
  454 + case '410300':
  455 + return { distance: 140 }
  456 + case '410400':
  457 + return { distance: 155 }
  458 + case '410500':
  459 + return { distance: 145 }
  460 + case '410800':
  461 + return { distance: 140 }
  462 + case '410900':
  463 + return { distance: 145 }
  464 + case '411000':
  465 + return { distance: 140 }
  466 + case '411100':
  467 + return { distance: 155 }
  468 + case '411200':
  469 + return { distance: 140 }
  470 + case '411300':
  471 + return { distance: 140 }
  472 + case '411400':
  473 + return { distance: 135 }
  474 + case '411700':
  475 + return { distance: 130 }
  476 + case '420000':
  477 + return { distance: 145 }
  478 + case '420100':
  479 + return { distance: 160 }
  480 + case '420300':
  481 + return { distance: 130 }
  482 + case '420500':
  483 + return { distance: 155 }
  484 + case '420700':
  485 + return { distance: 170 }
  486 + case '420900':
  487 + return { distance: 180 }
  488 + case '421100':
  489 + return { distance: 180 }
  490 + case '421200':
  491 + return { distance: 150 }
  492 + case '421300':
  493 + return { distance: 165 }
  494 + case '422800':
  495 + return { distance: 150 }
  496 + case '430000':
  497 + return { distance: 155 }
  498 + case '430200':
  499 + return { distance: 250 }
  500 + case '430600':
  501 + return { distance: 155 }
  502 + case '430700':
  503 + return { distance: 155 }
  504 + case '430900':
  505 + return { distance: 145 }
  506 + case '431000':
  507 + return { distance: 150 }
  508 + case '431100':
  509 + return { distance: 235 }
  510 + case '431200':
  511 + return { distance: 195 }
  512 + case '431300':
  513 + return { distance: 135 }
  514 + case '433100':
  515 + return { distance: 220 }
  516 + case '440000':
  517 + return { distance: 165 }
  518 + case '440100':
  519 + return { distance: 185 }
  520 + case '440300':
  521 + return { distance: 135 }
  522 + case '440400':
  523 + return { distance: 135 }
  524 + case '440500':
  525 + return { distance: 140 }
  526 + case '440600':
  527 + return { distance: 180 }
  528 + case '440700':
  529 + return { distance: 150 }
  530 + case '440800':
  531 + return { distance: 190 }
  532 + case '440900':
  533 + return { distance: 160 }
  534 + case '441200':
  535 + return { distance: 165 }
  536 + case '441400':
  537 + return { distance: 160 }
  538 + case '441600':
  539 + return { distance: 185 }
  540 + case '441700':
  541 + return { distance: 180 }
  542 + case '445100':
  543 + return { distance: 170 }
  544 + case '445200':
  545 + return { distance: 160 }
  546 + case '445300':
  547 + return { distance: 130 }
  548 + case '450100':
  549 + return { distance: 135 }
  550 + case '450200':
  551 + return { distance: 195 }
  552 + case '450300':
  553 + return { distance: 175 }
  554 + case '450400':
  555 + return { distance: 195 }
  556 + case '450600':
  557 + return { distance: 155 }
  558 + case '450800':
  559 + return { distance: 165 }
  560 + case '450900':
  561 + return { distance: 165 }
  562 + case '451000':
  563 + return { distance: 135 }
  564 + case '451100':
  565 + return { distance: 145 }
  566 + case '451400':
  567 + return { distance: 165 }
  568 + case '460100':
  569 + return { distance: 155 }
  570 + case '500000':
  571 + return { distance: 140 }
  572 + case '510000':
  573 + return { distance: 115 }
  574 + case '510100':
  575 + return { distance: 135 }
  576 + case '510300':
  577 + return { distance: 145 }
  578 + case '510400':
  579 + return { distance: 165 }
  580 + case '510500':
  581 + return { distance: 195 }
  582 + case '510600':
  583 + return { distance: 155 }
  584 + case '510700':
  585 + return { distance: 170 }
  586 + case '510800':
  587 + return { distance: 115 }
  588 + case '510900':
  589 + return { distance: 160 }
  590 + case '511000':
  591 + return { distance: 145 }
  592 + case '511100':
  593 + return { distance: 165 }
  594 + case '511300':
  595 + return { distance: 135 }
  596 + case '511400':
  597 + return { distance: 140 }
  598 + case '511500':
  599 + return { distance: 140 }
  600 + case '511700':
  601 + return { distance: 155 }
  602 + case '511800':
  603 + return { distance: 215 }
  604 + case '511900':
  605 + return { distance: 160 }
  606 + case '512000':
  607 + return { distance: 135 }
  608 + case '513200':
  609 + return { distance: 105 }
  610 + case '513300':
  611 + return { distance: 175 }
  612 + case '520000':
  613 + return { distance: 135 }
  614 + case '520100':
  615 + return { distance: 145 }
  616 + case '520200':
  617 + return { distance: 165 }
  618 + case '520300':
  619 + return { distance: 148 }
  620 + case '520400':
  621 + return { distance: 145 }
  622 + case '522300':
  623 + return { distance: 145 }
  624 + case '522600':
  625 + return { distance: 139 }
  626 + case '522700':
  627 + return { distance: 175 }
  628 + case '530000':
  629 + return { distance: 145 }
  630 + case '530100':
  631 + return { distance: 205 }
  632 + case '530300':
  633 + return { distance: 228 }
  634 + case '530500':
  635 + return { distance: 135 }
  636 + case '530600':
  637 + return { distance: 155 }
  638 + case '530700':
  639 + return { distance: 150 }
  640 + case '530800':
  641 + return { distance: 165 }
  642 + case '530900':
  643 + return { distance: 165 }
  644 + case '532300':
  645 + return { distance:205 }
  646 + case '532500':
  647 + return { distance: 165 }
  648 + case '532800':
  649 + return { distance: 160 }
  650 + case '532900':
  651 + return { distance: 140 }
  652 + case '533100':
  653 + return { distance: 175 }
  654 + case '533300':
  655 + return { distance: 275 }
  656 + case '533400':
  657 + return { distance: 200 }
  658 + case '540000':
  659 + return { distance: 140 }
  660 + case '540100':
  661 + return { distance: 145 }
  662 + case '542500':
  663 + return { distance: 155 }
  664 + case '610000':
  665 + return { distance: 210 }
  666 + case '610100':
  667 + return { distance: 145 }
  668 + case '610200':
  669 + return { distance: 140 }
  670 + case '610300':
  671 + return { distance: 145 }
  672 + case '610400':
  673 + return { distance: 135 }
  674 + case '610500':
  675 + return { distance: 155 }
  676 + case '610600':
  677 + return { distance: 135 }
  678 + case '610700':
  679 + return { distance: 140 }
  680 + case '610800':
  681 + return { distance: 155 }
  682 + case '610900':
  683 + return { distance: 160}
  684 + case '611000':
  685 + return { distance: 150}
  686 + case '620000':
  687 + return { distance: 135 }
  688 + case '620300':
  689 + return { distance: 140 }
  690 + case '620400':
  691 + return { distance: 165 }
  692 + case '620500':
  693 + return { distance: 135 }
  694 + case '620600':
  695 + return { distance: 175 }
  696 + case '620700':
  697 + return { distance: 135 }
  698 + case '620900':
  699 + return { distance: 135 }
  700 + case '621000':
  701 + return { distance: 155 }
  702 + case '621100':
  703 + return { distance: 145 }
  704 + case '622900':
  705 + return { distance: 165 }
  706 + case '623000':
  707 + return { distance: 145 }
  708 + case '630100':
  709 + return { distance: 185 }
  710 + case '632200':
  711 + return { distance: 130 }
  712 + case '632300':
  713 + return { distance: 180 }
  714 + case '632500':
  715 + return { distance: 135 }
  716 + case '632600':
  717 + return { distance: 135 }
  718 + case '632800':
  719 + return { distance: 150 }
  720 + case '640000':
  721 + return { distance: 195 }
  722 + case '640100':
  723 + return { distance: 175 }
  724 + case '640500':
  725 + return { distance: 135 }
  726 + case '650000':
  727 + return { distance: 135 }
  728 + case '650100':
  729 + return { distance: 155 }
  730 + case '652900':
  731 + return { distance: 135 }
  732 + case '653100':
  733 + return { distance: 138 }
  734 + case '710000':
  735 + return { distance: 135 }
  736 + case '810000':
  737 + return { distance: 145 }
  738 + case '820000':
  739 + return { distance: 240 }
  740 + default:
  741 + return { distance: 125}
  742 + }
  743 +}
... ...
... ... @@ -19,127 +19,159 @@
19 19 </SettingItemBox>
20 20 <SettingItemBox name="图标距离">
21 21 <SettingItem name="距右">
22   - <n-input-number
23   - v-model:value="optionData.iconDistanceRight"
24   - :min="1"
25   - size="small"
26   - placeholder="请输入"
27   - ></n-input-number>
  22 + <n-input-number v-model:value="optionData.iconDistanceRight" :min="1" size="small"
  23 + placeholder="请输入"></n-input-number>
28 24 </SettingItem>
29 25 <SettingItem name="距上">
30   - <n-input-number
31   - v-model:value="optionData.iconDistanceTop"
32   - :min="1"
33   - size="small"
34   - placeholder="请输入"
35   - ></n-input-number>
  26 + <n-input-number v-model:value="optionData.iconDistanceTop" :min="1" size="small"
  27 + placeholder="请输入"></n-input-number>
36 28 </SettingItem>
37 29 </SettingItemBox>
38   - <SelectCity
39   - ref="SelectCityRef"
40   - :optionData="optionData"
41   - :drillingIn="optionData.drillingIn"
42   - @submit="onHandleSelectValues"
43   - />
44   - <SettingItemBox name="颜色">
  30 + <SelectCity ref="SelectCityRef" :optionData="optionData" :drillingIn="optionData.drillingIn"
  31 + @submit="onHandleSelectValues" />
  32 + <div style="height: 30px"></div>
  33 + <n-tag type="primary">若配置无响应,请在预览页面查看效果</n-tag>
  34 + <SettingItemBox name="地图配置">
45 35 <SettingItem name="区域颜色">
46 36 <n-color-picker size="small" :modes="['hex']" v-model:value="seriesList[0].itemStyle.color"></n-color-picker>
47 37 </SettingItem>
48 38 <SettingItem name="边框颜色">
49   - <n-color-picker
50   - size="small"
51   - :modes="['hex']"
52   - v-model:value="seriesList[0].itemStyle.borderColor"
53   - ></n-color-picker>
  39 + <n-color-picker size="small" :modes="['hex']"
  40 + v-model:value="seriesList[0].itemStyle.borderColor"></n-color-picker>
54 41 </SettingItem>
55 42 <SettingItem name="边框大小">
56   - <n-input-number
57   - v-model:value="seriesList[0].itemStyle.borderWidth"
58   - :min="0"
59   - size="small"
60   - placeholder="请输入"
61   - ></n-input-number>
  43 + <n-input-number v-model:value="seriesList[0].itemStyle.borderWidth" :min="0" size="small"
  44 + placeholder="请输入"></n-input-number>
  45 + </SettingItem>
  46 + <SettingItem name="透明度">
  47 + <n-input-number v-model:value="seriesList[0].itemStyle.opacity" :min="0" size="small"
  48 + placeholder="请输入"></n-input-number>
62 49 </SettingItem>
63 50 <SettingItem name="厚度">
64   - <n-input-number
65   - v-model:value="seriesList[0].regionHeight"
66   - :min="0"
67   - size="small"
68   - placeholder="请输入"
69   - ></n-input-number>
  51 + <n-input-number v-model:value="seriesList[0].regionHeight" :min="0" size="small"
  52 + placeholder="请输入"></n-input-number>
70 53 </SettingItem>
71 54 </SettingItemBox>
72   - <SettingItemBox name="标题">
  55 + <SettingItemBox name="标题配置">
73 56 <SettingItem name="是否显示">
74 57 <n-switch v-model:value="seriesList[0].label.show" size="small"></n-switch>
75 58 </SettingItem>
76 59 <SettingItem name="颜色">
77   - <n-color-picker
78   - size="small"
79   - :modes="['hex']"
80   - v-model:value="seriesList[0].label.textStyle.color"
81   - ></n-color-picker>
  60 + <n-color-picker size="small" :modes="['hex']"
  61 + v-model:value="seriesList[0].label.textStyle.color"></n-color-picker>
82 62 </SettingItem>
83 63 <SettingItem name="大小">
84   - <n-input-number
85   - v-model:value="seriesList[0].label.textStyle.fontSize"
86   - :min="0"
87   - size="small"
88   - placeholder="请输入"
89   - ></n-input-number>
  64 + <n-input-number v-model:value="seriesList[0].label.textStyle.fontSize" :min="0" size="small"
  65 + placeholder="请输入"></n-input-number>
90 66 </SettingItem>
91 67 </SettingItemBox>
92   - <SettingItemBox name="高亮">
  68 + <SettingItemBox name="高亮配置">
93 69 <SettingItem name="标题显示">
94   - <n-switch v-model:value="optionData.geo3D.emphasis.label.show" size="small"></n-switch>
  70 + <n-switch v-model:value="seriesList[0].emphasis.label.show" size="small"></n-switch>
95 71 </SettingItem>
96 72 <SettingItem name="颜色">
97   - <n-color-picker
98   - size="small"
99   - :modes="['hex']"
100   - v-model:value="optionData.geo3D.emphasis.label.textStyle.color"
101   - ></n-color-picker>
  73 + <n-color-picker size="small" :modes="['hex']"
  74 + v-model:value="seriesList[0].emphasis.label.textStyle.color"></n-color-picker>
102 75 </SettingItem>
103 76 <SettingItem name="大小">
104   - <n-input-number
105   - v-model:value="optionData.geo3D.emphasis.label.textStyle.fontSize"
106   - :min="0"
107   - size="small"
108   - placeholder="请输入"
109   - ></n-input-number>
  77 + <n-input-number v-model:value="seriesList[0].emphasis.label.textStyle.fontSize" :min="0" size="small"
  78 + placeholder="请输入"></n-input-number>
110 79 </SettingItem>
111 80 <SettingItem name="区块颜色">
112   - <n-color-picker
113   - size="small"
114   - :modes="['hex']"
115   - v-model:value="optionData.geo3D.emphasis.itemStyle.color"
116   - ></n-color-picker>
  81 + <n-color-picker size="small" :modes="['hex']"
  82 + v-model:value="seriesList[0].emphasis.itemStyle.color"></n-color-picker>
117 83 </SettingItem>
118 84 </SettingItemBox>
119   - <SettingItemBox name="标记">
  85 + <SettingItemBox name="柱状配置">
  86 + <SettingItem name="最小高度">
  87 + <n-input-number v-model:value="seriesList[1].minHeight" :min="0" :step="1" size="small"
  88 + placeholder="请输入"></n-input-number>
  89 + </SettingItem>
120 90 <SettingItem name="大小">
121   - <n-input-number
122   - v-model:value="seriesList[1].symbolSize"
123   - :min="0"
124   - :step="10"
125   - size="small"
126   - placeholder="请输入"
127   - ></n-input-number>
  91 + <n-input-number v-model:value="seriesList[1].barSize" :min="0" :step="1" size="small"
  92 + placeholder="请输入"></n-input-number>
128 93 </SettingItem>
129   - <SettingItem name="形状">
130   - <n-select :options="symbolOption" v-model:value="seriesList[1].symbol"></n-select>
  94 + <SettingItem name="倒角尺寸">
  95 + <n-input-number v-model:value="seriesList[1].bevelSize" :min="0" :max="1" :step="0.1" size="small"
  96 + placeholder="请输入"></n-input-number>
131 97 </SettingItem>
132 98 </SettingItemBox>
133 99 </CollapseItem>
  100 + <CollapseItem name="地区配置" :expanded="true">
  101 + <SettingItemBox name="地区配置" :alone="true">
  102 + <template v-for="(item, map3DIndex) in optionData.dataset.map3D" :key="map3DIndex">
  103 + <setting-item name="省份名称" v-if="mapRegionCache.adcode == 'china'">
  104 + <n-select
  105 + @change="(v: number, o: Recordable, w: Recordable, s1: number) => onHandleSelectProvince(v, o, item, map3DIndex)"
  106 + placeholder="请选择省份" v-model:value="item.name" :options="item.provinceOptions" />
  107 + </setting-item>
  108 + <setting-item name="市/区/县名称">
  109 + <n-select placeholder="请选择市/区/县" v-model:value="item.city_name" :options="item.cityOptions" />
  110 + </setting-item>
  111 + <setting-item name="区块厚度">
  112 + <n-input-number v-model:value="item.height"> </n-input-number>
  113 + </setting-item>
  114 + <setting-item name="区块颜色">
  115 + <n-color-picker size="small" :modes="['hex']" v-model:value="item.itemStyle.color"></n-color-picker>
  116 + </setting-item>
  117 + <setting-item name="区块透明度">
  118 + <n-input-number v-model:value="item.itemStyle.opacity"> </n-input-number>
  119 + </setting-item>
  120 + <setting-item></setting-item>
  121 + <setting-item>
  122 + <n-button size="small" @click="optionData.dataset.map3D.splice(map3DIndex, 1)"> - </n-button>
  123 + </setting-item>
  124 + </template>
  125 + <div class="h-space"></div>
  126 + <n-button size="small" @click="handleAddRegion"> + </n-button>
  127 + <div class="h-space"></div>
  128 + <n-button type="primary" @click="handleAreaSubmit">确定</n-button>
  129 + </SettingItemBox>
  130 + </CollapseItem>
  131 + <CollapseItem name="柱状配置" :expanded="true">
  132 + <SettingItemBox name="柱状配置" :alone="true">
  133 + <template v-for="(item, barIndex) in optionData.dataset.bar3D" :key="barIndex">
  134 + <setting-item name="经度">
  135 + <n-input-number v-model:value="item.value[0]"> </n-input-number>
  136 + </setting-item>
  137 + <setting-item name="纬度">
  138 + <n-input-number v-model:value="item.value[1]"> </n-input-number>
  139 + </setting-item>
  140 + <setting-item name="离地高度">
  141 + <n-input-number v-model:value="item.height"> </n-input-number>
  142 + </setting-item>
  143 + <setting-item name="柱状颜色">
  144 + <n-color-picker size="small" :modes="['hex']" v-model:value="item.itemStyle.color"></n-color-picker>
  145 + </setting-item>
  146 + <setting-item name="柱状透明度">
  147 + <n-input-number v-model:value="item.itemStyle.opacity"> </n-input-number>
  148 + </setting-item>
  149 + <setting-item>
  150 + <n-button size="small" @click="optionData.dataset.bar3D.splice(barIndex, 1)"> - </n-button>
  151 + </setting-item>
  152 + </template>
  153 + <div class="h-space"></div>
  154 + <n-button style="float: right" size="small"
  155 + @click="optionData.dataset.bar3D.push(cloneDeep(STATIC_SCATTER_CONFIG))">
  156 + +
  157 + </n-button>
  158 + <div class="h-space"></div>
  159 + <n-button type="primary" @click="handleAreaSubmit">确定</n-button>
  160 + </SettingItemBox>
  161 + </CollapseItem>
134 162 </template>
135 163
136 164 <script setup lang="ts">
137   -import { PropType, computed, ref } from 'vue'
  165 +import { PropType, computed, ref, onMounted } from 'vue'
138 166 import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
139 167 import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
140 168 import { GlobalSetting } from '@/components/Pages/ChartItemSetting'
141 169 import SelectCity from './components/SelectCity.vue'
142   -import { regionInfo } from './config'
  170 +import { allFetch, getAreaLists, ifSpecialCity, regionInfo } from './config'
  171 +import { cloneDeep } from 'lodash'
  172 +
  173 +import { areaEnum } from '../../../Decorates/Mores/Weather/config'
  174 +import { unref } from 'vue'
143 175
144 176 const props = defineProps({
145 177 optionData: {
... ... @@ -152,56 +184,133 @@ const seriesList = computed(() => {
152 184 return props.optionData.series
153 185 })
154 186
155   -const symbolOption = ref([
156   - {
157   - label: 'circle',
158   - value: 'circle'
159   - },
160   - {
161   - label: 'rect',
162   - value: 'rect'
163   - },
164   - {
165   - label: 'roundRect',
166   - value: 'roundRect'
167   - },
168   - {
169   - label: 'triangle',
170   - value: 'triangle'
171   - },
172   - {
173   - label: 'diamond',
174   - value: 'diamond'
175   - },
176   - {
177   - label: 'pin',
178   - value: 'pin'
179   - },
180   - {
181   - label: 'arrow',
182   - value: 'arrow'
183   - },
184   - {
185   - label: 'none',
186   - value: 'none'
  187 +const datasetMap3DList = computed(() => {
  188 + return props.optionData.dataset['map3D']
  189 +})
  190 +
  191 +const STATIC_SCATTER_CONFIG = {
  192 + name: null,
  193 + adcode: 510000,
  194 + city_name: null,
  195 + value: [0, 0, 0],
  196 + height: 2,
  197 + itemStyle: {
  198 + color: '#4482B1FF',
  199 + opacity: 1
187 200 }
188   -])
  201 +}
189 202
190 203 const SelectCityRef = ref<InstanceType<typeof SelectCity>>()
191 204
192   -const onHandleSelectValues = (values: regionInfo) => {
193   - const { cityValue, countyValue, provinceValue } = values
194   - props.optionData.mapRegion.saveSelect = values
195   - props.optionData.mapRegion.adcode = countyValue
  205 +
  206 +
  207 +onMounted(async () => {
  208 + const {saveSelect} = unref(mapRegionCache) || {}
  209 + const {levelStr} = saveSelect || {}
  210 + datasetMap3DList.value.forEach(async (item: Recordable) => {
  211 + item.provinceOptions = await getAreaLists()
  212 + const adcode = !item.adcode ? mapRegionCache.value.adcode : item.adcode
  213 + const cityOptions = await getAreaLists(levelStr===areaEnum.CITY?areaEnum.COUNTY:areaEnum.CITY, adcode )
  214 + item.adcode = adcode
  215 + if(ifSpecialCity(adcode)){//直辖市获取区县配置的数据不一样
  216 + const values = await allFetch(cityOptions,'adcode') || []
  217 + item.cityOptions = values.flatMap((obj:any) => Object.values(obj))
  218 + return
  219 + }
  220 + item.cityOptions = cityOptions
  221 + })
  222 +})
  223 +
  224 +const onHandleSelectProvince = async (value: number, option: Recordable, item: Recordable, mapIndex: number) => {
  225 + const findIndex = datasetMap3DList.value.findIndex((findItem: Recordable) => findItem.name === item.name)
  226 + datasetMap3DList.value[findIndex].city_name = null
  227 + datasetMap3DList.value[findIndex].adcode = option.adcode
  228 + datasetMap3DList.value[findIndex].cityOptions = await getAreaLists(areaEnum.CITY, option.adcode)
  229 +}
  230 +
  231 +const handleAddRegion =async () => {
  232 + props.optionData.dataset.map3D.push(cloneDeep(STATIC_SCATTER_CONFIG))
  233 + if (mapRegionCache.value.adcode !== 'china') {
  234 + const { adcode, areaName,saveSelect } = unref(mapRegionCache) || {}
  235 + const {levelStr} = saveSelect || {}
  236 + const cityOptions = await getAreaLists(levelStr===areaEnum.CITY?areaEnum.COUNTY:areaEnum.CITY, adcode)
  237 + // 循环 push 城市数据
  238 + datasetMap3DList.value.forEach((item: any) => {
  239 + item.name = areaName
  240 + item.value = null
  241 + item.cityOptions = cityOptions && cityOptions.length ? cityOptions : [{ adcode, label: areaName, value: areaName }]
  242 + })
  243 + return
  244 + }
  245 + datasetMap3DList.value.forEach(async (item: Recordable) => {
  246 + item.provinceOptions = await getAreaLists()
  247 + })
  248 +}
  249 +
  250 +const handleAreaSubmit = () => {
  251 + props.optionData.isShowExecute = !props.optionData?.isShowExecute
  252 +}
  253 +
  254 +const mapRegionCache = computed(() => {
  255 + return props.optionData.mapRegion
  256 +})
  257 +
  258 +const onHandleSelectValues = async (values: regionInfo) => {
  259 + const { cityValue, countyValue, provinceValue, areaName } = values
  260 + mapRegionCache.value.areaName = areaName
  261 + mapRegionCache.value.saveSelect = values
  262 + mapRegionCache.value.adcode = countyValue
196 263 ? countyValue
197 264 : cityValue
198   - ? cityValue
199   - : provinceValue === 'china'
200   - ? 'china'
201   - : provinceValue
  265 + ? cityValue
  266 + : provinceValue === 'china'
  267 + ? 'china'
  268 + : provinceValue
  269 + props.optionData.mapRegion = mapRegionCache.value
  270 + // if (mapRegionCache.value.adcode !== 'china') {
  271 + //清空区块配置和柱状配置
  272 + props.optionData.dataset.map3D = [cloneDeep(STATIC_SCATTER_CONFIG)]
  273 + props.optionData.dataset.bar3D = [cloneDeep(STATIC_SCATTER_CONFIG)]
  274 + setDatasetArea()
  275 + // }
202 276 }
203 277
  278 +
  279 +const mdutcgValues = ref<any>([])//直辖市的区县数据
  280 +
  281 +const setDatasetArea = async () => {
  282 + const { adcode, areaName,saveSelect } = unref(mapRegionCache) || {}
  283 + const {levelStr} = saveSelect || {}
  284 + const cityOptions = await getAreaLists(levelStr===areaEnum.CITY?areaEnum.COUNTY:areaEnum.CITY, adcode)
  285 + let provinceOptions:any = []
  286 + if(adcode==='china'){
  287 + provinceOptions = await getAreaLists()
  288 + }
  289 + mdutcgValues.value = cityOptions
  290 + if(adcode==110000 || adcode==120000 || adcode==500000 || adcode==310000 || adcode==810000 || adcode==820000){//直辖市
  291 + const values = await allFetch(cityOptions,'adcode') || []
  292 + mdutcgValues.value = values.flatMap((obj:any) => Object.values(obj))//讲获取到的多维转换成单一纬度
  293 + }
  294 + // 循环 push 城市数据
  295 + datasetMap3DList.value.forEach((item: any) => {
  296 + item.name = areaName
  297 + item.city_name = null
  298 + item.adcode = null,
  299 + item.value = null
  300 + item.provinceOptions=provinceOptions
  301 + item.cityOptions = unref(mdutcgValues) && unref(mdutcgValues).length ? unref(mdutcgValues) : [{ adcode, label: areaName, value: areaName }]
  302 + })
  303 +}
204 304 const handleChangeDrillingIn = () => {
205 305 SelectCityRef.value?.resetValue()
  306 + props.optionData.mapRegion.adcode = 'china'
  307 + props.optionData.mapRegion.areaName = ''
  308 + props.optionData.mapRegion.saveSelect.areaName = ''
206 309 }
207 310 </script>
  311 +
  312 +<style scoped>
  313 +.h-space {
  314 + height: 10px;
  315 +}
  316 +</style>
... ...
1   -[
2   - {
3   - "name": "四川省",
4   - "value": [104.10068024609373, 30.580525329665175, 20000],
5   - "adcode": 510000,
6   - "height": 5,
7   - "itemStyle": {
8   - "color": "pink",
9   - "opacity": 1,
10   - "borderWidth": 0.4,
11   - "borderColor": "#5F9EA0"
  1 +{
  2 + "map3D": [
  3 + {
  4 + "name": "四川省",
  5 + "adcode": 510000,
  6 + "city_name": "成都市",
  7 + "height": 2,
  8 + "itemStyle": {
  9 + "color": "#4482B1FF",
  10 + "opacity": 1,
  11 + "borderWidth": 0.4,
  12 + "borderColor": "#5F9EA0"
  13 + }
12 14 }
13   - },
14   - {
15   - "name": "湖南省",
16   - "value": [111.73068512890623, 27.86754509366569, 20000],
17   - "adcode": 430000,
18   - "height": 4,
19   - "itemStyle": {
20   - "color": "blue",
21   - "opacity": 1,
22   - "borderWidth": 0.4,
23   - "borderColor": "#5F9EA0"
  15 + ],
  16 + "bar3D": [
  17 + {
  18 + "value": [
  19 + 117.283042,
  20 + 31.86119,
  21 + 20000
  22 + ],
  23 + "height": 2,
  24 + "itemStyle": {
  25 + "color": "#4482B1FF",
  26 + "opacity": 1,
  27 + "borderWidth": 0.4,
  28 + "borderColor": "#5F9EA0"
  29 + }
24 30 }
25   - },
26   - {
27   - "name": "吉林省",
28   - "value": [126.45236481640623, 43.7943407914815, 20000],
29   - "adcode": 220000,
30   - "height": 5,
31   - "itemStyle": {
32   - "color": "yellow",
33   - "opacity": 1,
34   - "borderWidth": 0.4,
35   - "borderColor": "#5F9EA0"
36   - }
37   - },
38   - {
39   - "name": "山东省",
40   - "value": [118.67404450390623, 36.16387465872037, 20000],
41   - "adcode": 370000,
42   - "height": 6,
43   - "itemStyle": {
44   - "color": "orange",
45   - "opacity": 1,
46   - "borderWidth": 0.4,
47   - "borderColor": "#5F9EA0"
48   - }
49   - }
50   -]
  31 + ]
  32 +}
... ...
... ... @@ -9,12 +9,23 @@
9 9
10 10 <script setup lang="ts">
11 11 import { onMounted, ref, nextTick, PropType, toRefs, watch, reactive } from 'vue'
12   -import * as echarts from 'echarts'
13   -import { registerMap } from 'echarts/core'
14 12 import 'echarts-gl'
15   -import config, { areaEnum, dataPointI, optionType, historyParentType, backMapLevel } from './config'
  13 +import { registerMap, init } from 'echarts/core'
  14 +import type { EChartsType } from 'echarts/core'
  15 +import config, {
  16 + areaEnum,
  17 + dataPointI,
  18 + optionType,
  19 + historyParentType,
  20 + backMapLevel,
  21 + levelFunc,
  22 + regionMapParentArea,
  23 + specialTreatmentAnhui,
  24 + setScale
  25 +} from './config'
16 26 import { getGeoJsonMap } from '@/api/external/common'
17   -import dataMaps from './data.json'
  27 +import { ThreeMapEnum } from '@/enums/external/mapEnum'
  28 +import cloneDeep from 'lodash/cloneDeep'
18 29
19 30 const props = defineProps({
20 31 chartConfig: {
... ... @@ -23,15 +34,18 @@ const props = defineProps({
23 34 }
24 35 })
25 36
26   -const backIcon = 'path://M853.333333 245.333333H245.333333l93.866667-93.866666c12.8-12.8 12.8-34.133333 0-46.933334-12.8-12.8-34.133333-12.8-46.933333 0l-145.066667 145.066667c-12.8 12.8-12.8 34.133333 0 46.933333l145.066667 145.066667c6.4 6.4 14.933333 10.666667 23.466666 10.666667s17.066667-4.266667 23.466667-10.666667c12.8-12.8 12.8-34.133333 0-46.933333L256 311.466667h597.333333c6.4 0 10.666667 4.266667 10.666667 10.666666v426.666667c0 6.4-4.266667 10.666667-10.666667 10.666667H170.666667c-17.066667 0-32 14.933333-32 32s14.933333 32 32 32h682.666666c40.533333 0 74.666667-34.133333 74.666667-74.666667V320c0-40.533333-34.133333-74.666667-74.666667-74.666667z'
  37 +const backIcon =
  38 + 'path://M853.333333 245.333333H245.333333l93.866667-93.866666c12.8-12.8 12.8-34.133333 0-46.933334-12.8-12.8-34.133333-12.8-46.933333 0l-145.066667 145.066667c-12.8 12.8-12.8 34.133333 0 46.933333l145.066667 145.066667c6.4 6.4 14.933333 10.666667 23.466666 10.666667s17.066667-4.266667 23.466667-10.666667c12.8-12.8 12.8-34.133333 0-46.933333L256 311.466667h597.333333c6.4 0 10.666667 4.266667 10.666667 10.666666v426.666667c0 6.4-4.266667 10.666667-10.666667 10.666667H170.666667c-17.066667 0-32 14.933333-32 32s14.933333 32 32 32h682.666666c40.533333 0 74.666667-34.133333 74.666667-74.666667V320c0-40.533333-34.133333-74.666667-74.666667-74.666667z'
27 39
28 40 const { w, h } = toRefs(props.chartConfig.attr)
29 41
30   -const map3DRef = ref()
  42 +const { mapRegion, dataset, drillingIn, saveClickRegion, geo3D, series } = toRefs(props.chartConfig.option)
  43 +
  44 +const map3DRef = ref<Nullable<HTMLElement>>()
31 45
32 46 const show = ref(true)
33 47
34   -const chartInstance = ref()
  48 +const chartInstance = ref<Nullable<EChartsType>>()
35 49
36 50 const toolBoxOption = ref({
37 51 show: true,
... ... @@ -50,38 +64,39 @@ const toolBoxOption = ref({
50 64 }
51 65 })
52 66
53   -const excludeCountryLevels = ['PROVINCE','CITY'] //如果从右侧配置选择全中国
  67 +const excludeCountryLevels = ['PROVINCE', 'CITY'] //如果从右侧配置选择全中国
54 68
55 69 const includeCityLevels = ['CITY'] //如果从右侧配置选择省份
56 70
57 71 //元组 优化if elseif else分支 隐藏返回图标
58   -const backIconMappingLevels: any[][] =[
  72 +const backIconMappingLevels: levelFunc[][] = [
59 73 [
60   - (levelStr:string)=>levelStr===areaEnum.COUNTRY,
61   - (level:string)=>excludeCountryLevels.includes(level),
62   - ()=>toolBoxOption.value.feature.myFullButton.show=true,
63   - ()=>toolBoxOption.value.feature.myFullButton.show=false
  74 + (levelStr: string) => levelStr === areaEnum.COUNTRY,
  75 + (level: string) => excludeCountryLevels.includes(level),
  76 + () => (toolBoxOption.value.feature.myFullButton.show = true),
  77 + () => (toolBoxOption.value.feature.myFullButton.show = false)
64 78 ],
65 79 [
66   - (levelStr:string)=>levelStr===areaEnum.PROVINCE,
67   - (level:string)=>includeCityLevels.includes(level),
68   - ()=>toolBoxOption.value.feature.myFullButton.show=true,
69   - ()=>toolBoxOption.value.feature.myFullButton.show=false
70   - ],
  80 + (levelStr: string) => levelStr === areaEnum.PROVINCE,
  81 + (level: string) => includeCityLevels.includes(level),
  82 + () => (toolBoxOption.value.feature.myFullButton.show = true),
  83 + () => (toolBoxOption.value.feature.myFullButton.show = false)
  84 + ]
71 85 ]
72 86
73   -
74 87 watch(
75 88 () => props.chartConfig.option,
76   - (newData:optionType) => {
  89 + (newData: optionType) => {
77 90 const { iconColor, iconDistanceRight, iconDistanceTop, mapRegion } = newData
78   - const { saveSelect }=mapRegion
79   - const { levelStr }=saveSelect
80   - const findBackLevel = backIconMappingLevels.find((backLevelItem: backMapLevel[])=>backLevelItem[0](levelStr)) as backMapLevel[]
81   - if(findBackLevel){
82   - if(findBackLevel[0]){
  91 + const { saveSelect } = mapRegion
  92 + const { levelStr } = saveSelect
  93 + const findBackLevel = backIconMappingLevels.find((backLevelItem: levelFunc[]) =>
  94 + backLevelItem[0](levelStr)
  95 + ) as backMapLevel[]
  96 + if (findBackLevel) {
  97 + if (findBackLevel[0]) {
83 98 const findLevel = findBackLevel[1](saveLevelStr.level)
84   - if(findLevel)findBackLevel[2]()
  99 + if (findLevel) findBackLevel[2]()
85 100 else findBackLevel[3]()
86 101 }
87 102 }
... ... @@ -103,14 +118,14 @@ props.chartConfig.option = {
103 118 //地图点击返回
104 119 const handleBack = async () => {
105 120 stopWatch()
106   - if (props.chartConfig.option.drillingIn) {
  121 + if (drillingIn.value) {
107 122 //如果是从右边配置里设置的,比如点击四川省,然后点击返回
108 123 const savePopParent = saveHistoryParent.value.pop()
109 124 let saveAdcode = savePopParent?.adcode as string | number
110 125 saveLevelStr.level = savePopParent?.level as string
111 126 if (!savePopParent) {
112   - saveAdcode = getParentAdcode(props.chartConfig.option.mapRegion.adcode)
113   - saveLevelStr.level = (regionMapParentArea as Recordable)[props.chartConfig.option.mapRegion.saveSelect.levelStr]
  127 + saveAdcode = getParentAdcode(mapRegion.value.adcode).adcodeNum
  128 + saveLevelStr.level = (regionMapParentArea as Recordable)[mapRegion.value.saveSelect.levelStr]
114 129 }
115 130 if (saveAdcode === 0) {
116 131 saveAdcode = 'china'
... ... @@ -118,50 +133,48 @@ const handleBack = async () => {
118 133 }
119 134 const exist = await getGeojson(saveAdcode)
120 135 const adcode = saveAdcode === 100000 ? 'china' : saveAdcode
121   - props.chartConfig.option.saveClickRegion.level = saveLevelStr.level
  136 + saveClickRegion.value.level = saveLevelStr.level
122 137 if (exist) {
123   - //fix解决点击下钻返回后页面为空问题
124   - props.chartConfig.option.mapRegion.adcode = adcode
  138 + mapRegion.value.areaName = getParentAdcode(mapRegion.value.adcode).areaName
  139 + //fix 解决点击下钻返回后页面为空问题
  140 + mapRegion.value.adcode = adcode
125 141 }
126 142 }
127 143 }
128 144
129   -//地区上级对应配置
130   -const regionMapParentArea = {
131   - PROVINCE: areaEnum.COUNTRY, //省份的上一级 中国
132   - CITY: areaEnum.PROVINCE, //城市的上一级 省份
133   - COUNTY: areaEnum.CITY, //县或者区的上一级 城市
134   - TOWN: areaEnum.COUNTY //镇的上一级 县或者区
135   -}
136   -
137 145 //地图点击
138 146 const handleMap3DClick = async (params: Recordable) => {
139   - if (props.chartConfig.option.drillingIn) {
  147 + if (drillingIn.value) {
140 148 const { name } = params
141   - saveGeojson.value?.features.forEach((item: Recordable) => {
  149 + const geoJson = JSON.parse(saveGeojson.value?.geoJson)
  150 + geoJson?.features.forEach((item: Recordable) => {
142 151 if (item.properties.name === name) {
143 152 const level = item.properties.level.toUpperCase()
144 153 const adcode = item.properties.adcode
  154 + const areaName = item.properties.name
145 155 if (level === 'DISTRICT') return //下钻暂且不支持地区
146 156 if (String(adcode).startsWith('15') && level === areaEnum.CITY) return //特殊处理地区码15开头的
147   - props.chartConfig.option.mapRegion.adcode = adcode
148   - props.chartConfig.option.saveClickRegion.level = level
  157 + mapRegion.value.adcode = adcode
  158 + mapRegion.value.areaName = areaName
  159 + saveClickRegion.value.level = level
149 160 saveLevelStr.level = level
150   - handleDataPoint(adcode)
151 161 saveHistoryParent.value.push({
152   - adcode: item.properties.parent.adcode,
153   - level: (regionMapParentArea as Recordable)[level]
  162 + adcode: specialTreatmentAnhui.includes(item.properties.name)
  163 + ? JSON.parse(item.properties.parent)?.adcode
  164 + : item.properties.parent.adcode,
  165 + level: (regionMapParentArea as Recordable)[level],
  166 + areaName: saveGeojson.value.name
154 167 })
155 168 }
156 169 })
157 170 }
158 171 }
159 172
160   -const saveGeojson: Recordable = ref({}) // 保存geojson
  173 +const saveGeojson: Recordable = ref({}) // 保存一份服务端返回的geojson
161 174
162 175 const chinaDefaultRegionId = ref(100000) //如果是china则adcode为100000
163 176
164   -const saveLevelStr = reactive<{level:historyParentType["level"]}>({
  177 +const saveLevelStr = reactive<{ level: historyParentType['level'] }>({
165 178 // 地区级别
166 179 level: ''
167 180 })
... ... @@ -172,155 +185,194 @@ const saveHistoryParent = ref<historyParentType[]>([])
172 185 const getGeojson = (regionId: number | string) => {
173 186 try {
174 187 return new Promise<boolean>(resolve => {
175   - const { levelStr } = props.chartConfig.option.mapRegion.saveSelect //右侧配置项获取的行政级别
  188 + const { levelStr } = mapRegion.value.saveSelect //右侧配置项获取的行政级别
176 189 getGeoJsonMap(
177 190 regionId === 'china' ? chinaDefaultRegionId.value : regionId,
178 191 !saveLevelStr.level ? levelStr : saveLevelStr.level //没有则获取右侧配置的行政级别
179 192 ).then(res => {
180   - const { geoJson, name, code, level } = res.data
  193 + saveGeojson.value = res.data //保存一份服务端返回的数据
  194 + const { geoJson, name, level, code } = res.data
181 195 const geoJsonFile = JSON.parse(geoJson)
182 196 if (!geoJsonFile) return
183   - saveGeojson.value = geoJsonFile//保存一份服务端返回的geojson
184   - const nameChina = name === '中国' ? 'china' : name
185   - registerMap(level === areaEnum.COUNTRY ? nameChina : code, { geoJSON: geoJsonFile, specialAreas: {} })
186   - show.value = false
  197 + const nameChina = name === '中国' ? 'china' : name //为中国的话,registerMap第一个必须是china,否则显示不出来
  198 + /**
  199 + * 主要注意的点,registerMap中的第一个参数需要和series中的map匹配,否则渲染不出地图,
  200 + * 比如map: '北京市' echarts.registerMap('北京市', beijingGeoJSON);
  201 + */
  202 + registerMap(level === areaEnum.COUNTRY ? nameChina : !mapRegion.value.areaName ? code : name, {
  203 + geoJSON: geoJsonFile,
  204 + specialAreas: {}
  205 + }) //注册geoJSON
187 206 resolve(true)
  207 + show.value = false
  208 + changeOption.value = true
188 209 })
189 210 })
190 211 } catch (error) {
191 212 show.value = false
192   - console.error('注册地图出错', error)
  213 + console.error('注册三维地图出错,出错原因->', error)
193 214 //注册出错则注册空的,不然在选择正确的adcode,则视图无法更新
194   - registerMap(props.chartConfig.option.mapRegion.adcode, { geoJSON: {} as any, specialAreas: {} })
  215 + registerMap(mapRegion.value.adcode, { geoJSON: {} as any, specialAreas: {} })
195 216 }
196 217 }
197 218
198 219 //异步时先注册空的 保证初始化不报错
199   -registerMap(props.chartConfig.option.mapRegion.adcode, { geoJSON: {} as any, specialAreas: {} })
  220 +registerMap(mapRegion.value.adcode, { geoJSON: {} as any, specialAreas: {} })
200 221
201 222 //传adcode 获取上级
202 223 const getParentAdcode = (adcode: number) => {
203 224 let adcodeNum = 100000
204   - saveGeojson.value?.features.forEach((item: Recordable) => {
  225 + let areaName = ''
  226 + const geoJson = JSON.parse(saveGeojson.value?.geoJson)
  227 + geoJson.features.forEach((item: Recordable) => {
205 228 if (item.properties.adcode === adcode) {
206 229 adcodeNum = item.properties.parent.adcode
  230 + areaName = saveGeojson.value.name
207 231 }
208 232 })
209   - return adcodeNum
  233 + return { adcodeNum, areaName }
210 234 }
211 235
212   -watch(
213   - () => w.value,
214   - (value: number) => {
215   - chartInstance.value.resize({
216   - width: value + 'px',
217   - height: h.value + 'px'
218   - })
219   - }
220   -)
221   -
222   -const initMap = async () => {
223   - chartInstance.value = echarts.init(map3DRef.value)
  236 +// 初始化三维地图
  237 +const initMap3D = async () => {
  238 + chartInstance.value = init(map3DRef.value as HTMLElement) as any as Nullable<EChartsType>
224 239 await nextTick()
225   - await getGeojson(props.chartConfig.option.mapRegion.adcode)
  240 + await getGeojson(mapRegion.value.adcode)
226 241 await nextTick().then(() => {
227   - handleSetOption(chartInstance.value, props.chartConfig.option)
  242 + handleRegisterMapNameAndData(mapRegion.value.adcode, dataset.value, 'china')
228 243 })
229   - chartInstance.value.on('click', (e: Recordable) => {
  244 + chartInstance.value?.on('click', (e: Recordable) => {
  245 + if (!e) return
230 246 handleMap3DClick(e)
231 247 })
232 248 }
233 249
234   -// 手动触发渲染
235   -const handleSetOption = (instance: any, option: Recordable) => {
  250 +onMounted(() => initMap3D())
  251 +
  252 +// 动态注册 series中的map必须和registerMap的第一个参数匹配,否则渲染不出
  253 +const handleRegisterMapNameAndData = (adcode: string | number, data: Recordable, areaName: string) => {
  254 + geo3D.value.map = !areaName ? adcode : areaName // coordinateSystem使用了geo3D,不能删除这一行
  255 + series.value.forEach((item: Recordable) => {
  256 + if (item.type === ThreeMapEnum.MAP3D) {
  257 + item.map = !areaName ? adcode : areaName
  258 + item.data = data[ThreeMapEnum.MAP3D]
  259 + }
  260 + if (item.type === ThreeMapEnum.BAR3D) {
  261 + item.data = data[ThreeMapEnum.BAR3D]
  262 + }
  263 + })
  264 +}
  265 +
  266 +// 动态触发渲染
  267 +const handleSetOption = (instance: EChartsType, option: Recordable) => {
236 268 if (!instance) return
237 269 try {
238   - instance.clear()
239   - instance.setOption(option)
  270 + instance && instance.clear()
  271 + instance && instance.setOption(option)
240 272 } catch (error) {
241   - console.error('触发渲染出错', error)
  273 + console.error('动态触发渲染出错,出错原因->', error)
242 274 }
243 275 }
244 276
245   -onMounted(() => {
246   - initMap()
247   -})
  277 +watch(
  278 + () => [w.value, h.value],
  279 + async (newValue: number[]) => {
  280 + await nextTick()
  281 + chartInstance.value?.resize({
  282 + width: newValue.at(-2) + 'px',
  283 + height: newValue.at(-1) + 'px'
  284 + } as Recordable)
  285 + }
  286 +)
248 287
249 288 //处理数据标点
250   -const handleDataPoint = (newData: string | number) => {
  289 +const handleDataPoint = (newData: string | number, areaName: string) => {
251 290 if (newData === 'china') {
252   - props.chartConfig.option.dataset = dataMaps
253   - props.chartConfig.option.series.forEach((item: Recordable) => {
254   - if (item.type === 'scatter3D') {
255   - item.data = dataMaps
256   - }
257   - })
  291 + // 全国则展示所有的标点
  292 + handleRegisterMapNameAndData(newData, dataset.value, 'china')
258 293 } else {
259   - props.chartConfig.option.dataset = dataMaps.filter((item: dataPointI) => item.adcode === newData)
260   - props.chartConfig.option.series.forEach((item: Recordable) => {
261   - if (item.type === 'scatter3D') {
262   - item.data = dataMaps.filter((item: dataPointI) => item.adcode === newData)
  294 + // 展示对应区域的标点
  295 + series.value.forEach((item: Recordable) => {
  296 + if (item.type === ThreeMapEnum.MAP3D) {
  297 + item.map = !areaName ? newData : areaName
  298 + item.data = dataset.value[ThreeMapEnum.MAP3D].filter((dataItem: dataPointI) => {
  299 + if (String(dataItem.adcode) === String(!areaName ? newData : areaName)) {
  300 + return dataItem
  301 + } else if (dataItem.name === String(!areaName ? newData : areaName)) {
  302 + return dataItem
  303 + }
  304 + })
  305 + const cloneDeepData = cloneDeep(item.data)
  306 + cloneDeepData.forEach((item: dataPointI) => {
  307 + item.name = item.city_name
  308 + })
  309 + item.data = cloneDeepData.filter((item: Recordable) => item.name !== null) || []
  310 + }
  311 + if (item.type === ThreeMapEnum.BAR3D) {
  312 + item.data = dataset.value[ThreeMapEnum.BAR3D]
263 313 }
264 314 })
265 315 }
266 316 }
  317 +const changeOption = ref(false)
267 318
268   -//监听地图展示区域发生变化
  319 +// 监听地图展示区域发生变化
269 320 watch(
270 321 () => `${props.chartConfig.option.mapRegion.adcode}`,
271   - async (newData: string | number) => {
  322 + async (newData: number | string) => {
272 323 try {
273 324 await getGeojson(newData)
274   - props.chartConfig.option.geo3D.map = newData
275   - props.chartConfig.option.series.forEach((item: Recordable) => {
  325 + const { distance} = setScale(String(newData))
  326 + const option = props.chartConfig.option
  327 + // 修复缩放
  328 + const { series,geo3D } = option || {}
  329 +
  330 + series?.forEach((item: Recordable) => {
276 331 if (item.type === 'map3D') {
277   - item.map = newData
278   - item.data = props.chartConfig.option.dataset
  332 + item.viewControl = {
  333 + ...item?.viewControl,
  334 + distance,
  335 + }
279 336 }
280 337 })
281   - handleSetOption(chartInstance.value, props.chartConfig.option)
282   - handleDataPoint(newData)
  338 + handleRegisterMapNameAndData(newData, dataset.value, mapRegion.value.areaName)
  339 + handleDataPoint(newData, mapRegion.value.areaName)
  340 + changeOption.value = true
  341 + handleSetOption(chartInstance.value!, { ...option, series ,geo3D:{...geo3D,viewControl:{distance:distance}}})
283 342 } catch (error) {
284   - console.log('展示区域发生变化出错', error)
  343 + console.error('展示区域发生变化出错,出错原因->', error)
285 344 }
286 345 },
287 346 {
288   - immediate: true
  347 + immediate: true,
  348 + deep: true
289 349 }
290 350 )
291 351
292   -// 监听地图右侧配置项变化
  352 +// 实时监听地图右侧配置项变化
293 353 const stopWatch = watch(
294 354 props.chartConfig.option,
295 355 async newData => {
296 356 try {
297   - handleSetOption(chartInstance.value, newData)
298   - } catch (error) {
299   - console.log(error)
300   - }
301   - },
302   - {
303   - deep: true
304   - }
305   -)
306   -
307   -// 监听地图dataset配置项变化
308   -watch(
309   - () => props.chartConfig.option.dataset,
310   - newData => {
311   - try {
312   - props.chartConfig.option.series.forEach((item: Recordable) => {
313   - if (item.type === 'map3D') {
314   - item.data = newData
315   - }
316   - })
317   - handleSetOption(chartInstance.value, props.chartConfig.option)
  357 + if (changeOption.value) {
  358 + // handleSetOption(chartInstance.value!, newData)
  359 + }
318 360 } catch (error) {
319   - console.log(error)
  361 + console.error('监听地图右侧配置项变化,出错原因->', error)
320 362 }
321 363 },
322 364 {
323 365 deep: true
324 366 }
325 367 )
  368 +watch(()=>props.chartConfig.option.isShowExecute,async()=>{
  369 + const {adcode,areaName} = props.chartConfig.option.mapRegion || {}
  370 + handleRegisterMapNameAndData(adcode,dataset.value,mapRegion.value.areaName)
  371 + handleDataPoint(adcode,areaName)
  372 +
  373 + const { distance } = setScale(String(adcode))
  374 + const option = props.chartConfig.option
  375 + const { series,geo3D } = option || {}
  376 + handleSetOption(chartInstance.value!, { ...option, series ,geo3D:{...geo3D,viewControl:{distance:distance}}})
  377 +})
326 378 </script>
... ...
... ... @@ -27,7 +27,6 @@ import { getDeviceActiveTime } from '@/api/external/common/index'
27 27 import dayjs from 'dayjs'
28 28 import DeviceLatestTable from './components/DeviceLatestTable.vue'
29 29 import { getDeviceLatest, getProfileAttrs } from '@/api/external/common'
30   -import { NButton } from 'naive-ui'
31 30
32 31 const props = defineProps({
33 32 chartConfig: {
... ...
... ... @@ -15,7 +15,7 @@
15 15 <n-input-number :min="0" v-model:value="optionData.value.min" size="small"></n-input-number>
16 16 </SettingItem>
17 17 <setting-item name="最大值">
18   - <n-input-number v-model:value="optionData.value.max" size="small"></n-input-number>
  18 + <n-input-number v-model:value="optionData.value.max" size="small" :min="100"></n-input-number>
19 19 </setting-item>
20 20 </SettingItemBox>
21 21 <SettingItemBox name="轨道">
... ...
... ... @@ -3,7 +3,7 @@
3 3 :type="type"
4 4 :height="h"
5 5 :processing="processing"
6   - :percentage="dataset"
  6 + :percentage="percentage"
7 7 :indicator-placement="indicatorPlacement"
8 8 :color="color"
9 9 :rail-color="railColor"
... ... @@ -21,11 +21,12 @@
21 21 </template>
22 22
23 23 <script setup lang="ts">
24   -import { PropType, toRefs, watch } from 'vue'
  24 +import { PropType, computed, ref, toRefs, watch } from 'vue'
25 25 import { useChartDataFetch } from '@/hooks'
26 26 import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
27 27 import config from './config'
28 28 import { toNumber } from '@/utils'
  29 +import { unref } from 'vue'
29 30
30 31 const props = defineProps({
31 32 chartConfig: {
... ... @@ -46,25 +47,38 @@ const {
46 47 indicatorPlacement,
47 48 indicatorTextSize,
48 49 offsetDegree,
49   - dataset
  50 + dataset,
50 51 } = toRefs(props.chartConfig.option)
51 52
  53 +const max = computed(()=>{//获取最新的最大值
  54 + const {value:{max}} = props.chartConfig.option
  55 + return max
  56 +})
  57 +const percentage = ref<number>(unref(dataset) * (100/max.value))//计算当设置的最大值大于100的时候
52 58 // 手动更新
53 59 watch(
54   - () => props.chartConfig.option.dataset,
55   - (newData: any) => {
  60 + () => {props.chartConfig.option.dataset,props.chartConfig.option.value.max},
  61 + () => {
56 62 try {
57   - dataset.value = toNumber(newData, 2)
  63 + if(max.value!==100){
  64 + const newValue = unref(dataset) * (100/max.value)//计算进度条的位置
  65 + percentage.value = toNumber(newValue,2)
  66 + dataset.value = toNumber((unref(dataset)), 2)
  67 + return
  68 + }
  69 + percentage.value = toNumber(unref(dataset), 2)
  70 + dataset.value = toNumber((unref(dataset)), 2)
58 71 } catch (error) {
59 72 console.log(error)
60 73 }
61 74 },
62 75 {
63   - deep: false
  76 + deep: true
64 77 }
65 78 )
66 79 // 预览更新
67 80 useChartDataFetch(props.chartConfig, useChartEditStore, (newData: number) => {
  81 + percentage.value = toNumber(newData*(100/max.value), 2)
68 82 dataset.value = toNumber(newData, 2)
69 83 })
70 84 </script>
... ...
... ... @@ -8,7 +8,6 @@ export const option = {
8 8 dataset: '',
9 9 attribute: {
10 10 bgColor1:'#00e0db',
11   - bgColor2:'#66ffff',
12 11 }
13 12 }
14 13
... ...
... ... @@ -8,14 +8,6 @@
8 8 <n-button size="small" @click="optionData.attribute.bgColor1 = '#00e0db'"> 恢复默认 </n-button>
9 9 </SettingItem>
10 10 </SettingItemBox>
11   - <SettingItemBox :name="`装饰2`">
12   - <SettingItem name="颜色">
13   - <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.attribute.bgColor2"></n-color-picker>
14   - </SettingItem>
15   - <SettingItem>
16   - <n-button size="small" @click="optionData.attribute.bgColor2 = '#66ffff'"> 恢复默认 </n-button>
17   - </SettingItem>
18   - </SettingItemBox>
19 11 </CollapseItem>
20 12 </template>
21 13
... ...
... ... @@ -32,7 +32,6 @@
32 32 <path
33 33 id="矩形"
34 34 fill-rule="evenodd"
35   - :style="{fill: attribute.bgColor2}"
36 35 opacity="0"
37 36 d="M0 87.26L87.26 87.26L87.26 0L0 0L0 87.26Z"
38 37 />
... ...
  1 +import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public'
  2 +import { Decorates13Config } from './index'
  3 +import { CreateComponentType } from '@/packages/index.d'
  4 +import cloneDeep from 'lodash/cloneDeep'
  5 +
  6 +export const includes = ['legend', 'xAxis', 'yAxis', 'grid']
  7 +
  8 +export const option = {
  9 + dataset: 66,
  10 + unitStr: '人',
  11 + grid: {
  12 + top: 200,
  13 + bottom: 300
  14 + },
  15 + xAxis: {
  16 + data: [],
  17 + axisTick: {
  18 + show: false
  19 + },
  20 + axisLine: {
  21 + show: false
  22 + }
  23 + },
  24 + yAxis: {
  25 + splitLine: {
  26 + show: false
  27 + },
  28 + axisTick: {
  29 + show: false
  30 + },
  31 + axisLine: {
  32 + show: false
  33 + },
  34 + axisLabel: {
  35 + show: false
  36 + }
  37 + },
  38 + series: [
  39 + {
  40 + name: '',
  41 + type: 'pictorialBar',
  42 + symbolSize: [100, 45],
  43 + symbolOffset: [-10, -20],
  44 + z: 12,
  45 + data: [
  46 + {
  47 + name: '',
  48 + value: 66,
  49 + symbolPosition: 'end',
  50 + itemStyle: {
  51 + normal: {
  52 + color: 'rgba(2, 163, 243,0.5)' //圆柱顶部颜色
  53 + }
  54 + }
  55 + }
  56 + ]
  57 + },
  58 + {
  59 + name: '',
  60 + type: 'pictorialBar',
  61 + symbolSize: [100, 45],
  62 + symbolOffset: [-10, 24],
  63 + z: 12,
  64 + data: [
  65 + {
  66 + name: '',
  67 + value: 66,
  68 + itemStyle: {
  69 + normal: {
  70 + color: 'rgba(2, 163, 243, 1)' //圆柱底部颜色
  71 + }
  72 + }
  73 + }
  74 + ]
  75 + },
  76 + {
  77 + type: 'bar',
  78 + barWidth: 100,
  79 + data: [
  80 + {
  81 + name: '',
  82 + value: 66,
  83 + label: {
  84 + normal: {
  85 + show: true,
  86 + formatter: '{c}' + '人',
  87 + position: 'top',
  88 + textStyle: {
  89 + color: 'rgba(2, 163, 243, 1)', //柱子对应数值颜色
  90 + fontSize: 40,
  91 + fontWeight: 600
  92 + }
  93 + }
  94 + },
  95 + itemStyle: {
  96 + normal: {
  97 + color: {
  98 + x: 0,
  99 + y: 0,
  100 + x2: 0,
  101 + y2: 1,
  102 + type: 'linear',
  103 + global: false,
  104 + colorStops: [
  105 + {
  106 + offset: 0,
  107 + color: 'rgba(18, 246, 255, 0)'
  108 + },
  109 + {
  110 + offset: 1,
  111 + color: 'rgba(2, 163, 243, 1)' //底部渐变颜色
  112 + }
  113 + ]
  114 + }
  115 + }
  116 + }
  117 + }
  118 + ]
  119 + },
  120 + //往上是内部柱状图
  121 + //往下是外部柱状图
  122 + {
  123 + name: '',
  124 + type: 'pictorialBar',
  125 + symbolSize: [340, 45],
  126 + symbolOffset: [-10, -20],
  127 + z: 12,
  128 + data: [
  129 + {
  130 + name: '',
  131 + value: '100',
  132 + symbolPosition: 'end',
  133 + itemStyle: {
  134 + normal: {
  135 + color: 'rgba(0, 255, 136, 0)' //圆柱顶部颜色
  136 + }
  137 + }
  138 + }
  139 + ]
  140 + },
  141 + {
  142 + name: '',
  143 + type: 'pictorialBar',
  144 + symbolSize: [150, 75],
  145 + symbolOffset: [-10, 41],
  146 + z: 12,
  147 + data: [
  148 + {
  149 + name: '',
  150 + value: '100',
  151 + itemStyle: {
  152 + normal: {
  153 + color: 'rgba(2, 163, 243, .1)' //圆柱底部颜色
  154 + }
  155 + }
  156 + }
  157 + ]
  158 + },
  159 + {
  160 + name: '',
  161 + type: 'pictorialBar',
  162 + symbolSize: [150, 75],
  163 + symbolOffset: [-10, 55],
  164 + z: 11,
  165 + data: [
  166 + {
  167 + name: '',
  168 + value: '100',
  169 + itemStyle: {
  170 + normal: {
  171 + color: 'transparent',
  172 + borderColor: 'rgba(2, 163, 243, 1)', //底部内圆圈颜色
  173 + borderWidth: 30
  174 + }
  175 + }
  176 + }
  177 + ]
  178 + },
  179 + {
  180 + name: '',
  181 + type: 'pictorialBar',
  182 + symbolSize: [200, 100],
  183 + symbolOffset: [-10, 62],
  184 + z: 10,
  185 + data: [
  186 + {
  187 + name: '关井数',
  188 + value: '100',
  189 + itemStyle: {
  190 + normal: {
  191 + color: 'transparent',
  192 + borderColor: 'rgba(2, 163, 243, 1)', //底部外圆圈颜色
  193 + borderType: 'dashed',
  194 + borderWidth: 2
  195 + }
  196 + }
  197 + }
  198 + ]
  199 + },
  200 + {
  201 + type: 'bar',
  202 + silent: true,
  203 + barWidth: 140,
  204 + barGap: '-120%',
  205 + data: [
  206 + {
  207 + name: '',
  208 + value: '100',
  209 + label: {
  210 + normal: {
  211 + show: false
  212 + }
  213 + },
  214 + itemStyle: {
  215 + normal: {
  216 + color: {
  217 + x: 1,
  218 + y: 1,
  219 + x2: 1,
  220 + y2: 0,
  221 + type: 'linear',
  222 + global: false,
  223 + colorStops: [
  224 + {
  225 + offset: 0,
  226 + color: 'rgba(0, 255, 136, 0)'
  227 + },
  228 + {
  229 + offset: 0.3,
  230 + color: 'rgba(0, 255, 136, .1)'
  231 + },
  232 + {
  233 + offset: 0.5,
  234 + color: 'rgba(0, 255, 136, .1)'
  235 + },
  236 + {
  237 + offset: 0.8,
  238 + color: 'rgba(0, 255, 136, .1)'
  239 + },
  240 + {
  241 + offset: 1,
  242 + color: 'rgba(0, 255, 136, 0)' //底部渐变颜色
  243 + }
  244 + ]
  245 + }
  246 + }
  247 + }
  248 + }
  249 + ]
  250 + }
  251 + ]
  252 +}
  253 +
  254 +export default class Config extends PublicConfigClass implements CreateComponentType {
  255 + public key: string = Decorates13Config.key
  256 + public chartConfig = cloneDeep(Decorates13Config)
  257 + // 图表配置项
  258 + public option = echartOptionProfixHandle(option, includes)
  259 +}
... ...
  1 +<template>
  2 + <!-- Echarts 全局设置 -->
  3 + <global-setting :optionData="optionData"></global-setting>
  4 + <CollapseItem name="配置" :expanded="true">
  5 + <setting-item-box name="数据点配置">
  6 + <setting-item name="数据">
  7 + <n-input-number v-model:value="optionData.dataset"></n-input-number>
  8 + </setting-item>
  9 + <setting-item name="单位">
  10 + <n-input v-model:value="optionData.unitStr"></n-input>
  11 + </setting-item>
  12 + </setting-item-box>
  13 + <setting-item-box name="grid配置">
  14 + <setting-item name="顶部">
  15 + <n-input-number v-model:value="optionData.grid.top"></n-input-number>
  16 + </setting-item>
  17 + <setting-item name="底部">
  18 + <n-input-number v-model:value="optionData.grid.bottom"></n-input-number>
  19 + </setting-item>
  20 + </setting-item-box>
  21 + <setting-item-box name="内部圆柱">
  22 + <setting-item name="顶部颜色">
  23 + <n-color-picker size="small" v-model:value="seriesList[0].data[0].itemStyle.normal.color"></n-color-picker>
  24 + </setting-item>
  25 + <setting-item name="底部颜色">
  26 + <n-color-picker size="small" v-model:value="seriesList[1].data[0].itemStyle.normal.color"></n-color-picker>
  27 + </setting-item>
  28 + <setting-item name="数字颜色">
  29 + <n-color-picker
  30 + size="small"
  31 + v-model:value="seriesList[2].data[0].label.normal.textStyle.color"
  32 + ></n-color-picker>
  33 + </setting-item>
  34 + <setting-item name="底部渐变色1">
  35 + <n-color-picker
  36 + size="small"
  37 + v-model:value="seriesList[2].data[0].itemStyle.normal.color.colorStops[0].color"
  38 + ></n-color-picker>
  39 + </setting-item>
  40 + <setting-item name="底部渐变色1">
  41 + <n-color-picker
  42 + size="small"
  43 + v-model:value="seriesList[2].data[0].itemStyle.normal.color.colorStops[1].color"
  44 + ></n-color-picker>
  45 + </setting-item>
  46 + </setting-item-box>
  47 + <setting-item-box name="外部圆柱">
  48 + <setting-item name="顶部颜色">
  49 + <n-color-picker size="small" v-model:value="seriesList[3].data[0].itemStyle.normal.color"></n-color-picker>
  50 + </setting-item>
  51 + <setting-item name="底部颜色">
  52 + <n-color-picker size="small" v-model:value="seriesList[4].data[0].itemStyle.normal.color"></n-color-picker>
  53 + </setting-item>
  54 + <setting-item name="底部内圆圈颜色">
  55 + <n-color-picker
  56 + size="small"
  57 + v-model:value="seriesList[5].data[0].itemStyle.normal.borderColor"
  58 + ></n-color-picker>
  59 + </setting-item>
  60 + <setting-item name="底部外圆圈颜色">
  61 + <n-color-picker
  62 + size="small"
  63 + v-model:value="seriesList[6].data[0].itemStyle.normal.borderColor"
  64 + ></n-color-picker>
  65 + </setting-item>
  66 + <setting-item name="底部渐变色1">
  67 + <n-color-picker
  68 + size="small"
  69 + v-model:value="seriesList[7].data[0].itemStyle.normal.color.colorStops[0].color"
  70 + ></n-color-picker>
  71 + </setting-item>
  72 + <setting-item name="底部渐变色2">
  73 + <n-color-picker
  74 + size="small"
  75 + v-model:value="seriesList[7].data[0].itemStyle.normal.color.colorStops[1].color"
  76 + ></n-color-picker>
  77 + </setting-item>
  78 + <setting-item name="底部渐变色3">
  79 + <n-color-picker
  80 + size="small"
  81 + v-model:value="seriesList[7].data[0].itemStyle.normal.color.colorStops[2].color"
  82 + ></n-color-picker>
  83 + </setting-item>
  84 + <setting-item name="底部渐变色4">
  85 + <n-color-picker
  86 + size="small"
  87 + v-model:value="seriesList[7].data[0].itemStyle.normal.color.colorStops[3].color"
  88 + ></n-color-picker>
  89 + </setting-item>
  90 + <setting-item name="底部渐变色5">
  91 + <n-color-picker
  92 + size="small"
  93 + v-model:value="seriesList[7].data[0].itemStyle.normal.color.colorStops[4].color"
  94 + ></n-color-picker>
  95 + </setting-item>
  96 + </setting-item-box>
  97 + </CollapseItem>
  98 +</template>
  99 +
  100 +<script setup lang="ts">
  101 +import { PropType, computed } from 'vue'
  102 +import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
  103 +import { GlobalSetting, CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
  104 +
  105 +const props = defineProps({
  106 + optionData: {
  107 + type: Object as PropType<GlobalThemeJsonType> & PropType<any>,
  108 + required: true
  109 + }
  110 +})
  111 +
  112 +const seriesList = computed(() => {
  113 + return props.optionData.series
  114 +})
  115 +</script>
... ...
  1 +import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
  2 +import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
  3 +import { useWidgetKey } from '@/packages/external/useWidgetKey'
  4 +
  5 +const { key, chartKey, conKey } = useWidgetKey('Decorates13',true)
  6 +
  7 +export const Decorates13Config: ConfigType = {
  8 + key,
  9 + chartKey,
  10 + conKey,
  11 + title: '装饰13',
  12 + category: ChatCategoryEnum.DECORATE,
  13 + categoryName: ChatCategoryEnumName.DECORATE,
  14 + package: PackagesCategoryEnum.DECORATES,
  15 + chartFrame: ChartFrameEnum.COMMON,
  16 + image: 'decorates_13.png',
  17 +}
... ...
  1 +<template>
  2 + <v-chart :theme="themeColor" :init-options="initOptions" :option="option.value" autoresize> </v-chart>
  3 +</template>
  4 +
  5 +<script setup lang="ts">
  6 +import { PropType, watch, reactive } from 'vue'
  7 +import VChart from 'vue-echarts'
  8 +import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
  9 +import { use } from 'echarts/core'
  10 +import { CanvasRenderer } from 'echarts/renderers'
  11 +import { LineChart } from 'echarts/charts'
  12 +import config, { includes } from './config'
  13 +import { mergeTheme } from '@/packages/public/chart'
  14 +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
  15 +import { useChartDataFetch } from '@/hooks'
  16 +import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
  17 +
  18 +const props = defineProps({
  19 + themeSetting: {
  20 + type: Object,
  21 + required: true
  22 + },
  23 + themeColor: {
  24 + type: Object,
  25 + required: true
  26 + },
  27 + chartConfig: {
  28 + type: Object as PropType<config>,
  29 + required: true
  30 + }
  31 +})
  32 +
  33 +const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
  34 +
  35 +use([DatasetComponent, CanvasRenderer, LineChart, GridComponent, TooltipComponent, LegendComponent])
  36 +
  37 +const option = reactive({
  38 + value: {}
  39 +})
  40 +
  41 +const dataHandle = (newData: number) => {
  42 + let config = props.chartConfig.option
  43 + config.series[2].data[0].value = newData
  44 + config.series[2].data[0].label.normal.formatter = '{c}' + config.unitStr
  45 + option.value = mergeTheme(props.chartConfig.option, props.themeSetting, includes)
  46 + option.value = { ...props.chartConfig.option, ...config }
  47 +}
  48 +
  49 +// 配置时
  50 +watch(
  51 + () => props.chartConfig.option.dataset,
  52 + (newData: number) => {
  53 + try {
  54 + dataHandle(newData)
  55 + } catch (error) {
  56 + console.log(error)
  57 + }
  58 + },
  59 + {
  60 + immediate: true,
  61 + }
  62 +)
  63 +// 预览时
  64 +useChartDataFetch(props.chartConfig, useChartEditStore, (resData: number) => {
  65 + // @ts-ignore
  66 + option.value.series[2].data[0].value = resData
  67 +})
  68 +</script>
... ...
  1 +import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public'
  2 +import { Decorates14Config } from './index'
  3 +import { CreateComponentType } from '@/packages/index.d'
  4 +import cloneDeep from 'lodash/cloneDeep'
  5 +
  6 +export const includes = ['legend', 'xAxis', 'yAxis', 'grid']
  7 +
  8 +const ydata = ['A2'] //y轴
  9 +
  10 +export const option = {
  11 + dataset: 60,
  12 + backgroundColor: 'rgba(0,0,0,1)',
  13 + grid: {
  14 + left: '10%',
  15 + top: 10,
  16 + bottom: 10
  17 + },
  18 + tooltip: {
  19 + show: false
  20 + },
  21 + xAxis: {
  22 + max: 100,
  23 + splitLine: {
  24 + show: false
  25 + },
  26 + axisLine: {
  27 + show: false
  28 + },
  29 + axisLabel: {
  30 + show: false
  31 + },
  32 + axisTick: {
  33 + show: false
  34 + }
  35 + },
  36 + yAxis: [
  37 + {
  38 + type: 'category',
  39 + inverse: false,
  40 + data: ydata,
  41 + axisLine: {
  42 + show: false
  43 + },
  44 + axisTick: {
  45 + show: false
  46 + },
  47 + axisLabel: {
  48 + show: false
  49 + }
  50 + }
  51 + ],
  52 + series: [
  53 + {
  54 + //内
  55 + type: 'bar',
  56 + barWidth: 60,
  57 + legendHoverLink: false,
  58 + silent: true,
  59 + itemStyle: {
  60 + color: {
  61 + type: 'linear',
  62 + x: 0,
  63 + y: 0,
  64 + x2: 1,
  65 + y2: 0,
  66 + colorStops: [
  67 + {
  68 + offset: 0,
  69 + color: 'rgba(156,224,99,1)' // 0% 处的颜色
  70 + },
  71 + {
  72 + offset: 1,
  73 + color: 'rgba(12,245,243,1)' // 100% 处的颜色
  74 + }
  75 + ],
  76 + globalCoord: false // 缺省为 false
  77 + } //底色
  78 + },
  79 + label: {
  80 + normal: {
  81 + show: true,
  82 + textStyle: {
  83 + color: '#fff',
  84 + fontSize: 20
  85 + },
  86 + position: 'right',
  87 + formatter: function (params: Recordable) {
  88 + return '{white|' + params.value + '}'
  89 + },
  90 + verticalAlign: 'bottom',
  91 + rich: {
  92 + white: {
  93 + // backgroundColor: {
  94 + // image:
  95 + // 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADYAAAAZCAYAAAB6v90+AAAA2klEQVRYhe2YMUoDQRhG32zAwsKkyRGCHmE9hE3uuSkNSqogaOEBcgzXDVg+i2xhEdKYn2GWefDX33vlDCjoCu3QHrXQ68eGFUpC74EPYME0+ALahHbAOrfNldkktAfucptcmWNCzW0RQZNbIIoaVho1rDRqWGnUsNKoYaUx6bDv3BIBHBtgl9sigNeEPgDvTOsF/dgAB6AFNsCQVel/DJwaWuDA+JkTcTfo9sLnS4fOwvYDw0Bv0f2ZqJcxPG47OAx0jn7+iXobg0N306kunCXwDPwAT0AfPfgLAvYRIEVmrDQAAAAASUVORK5CYII='
  96 + // },
  97 + padding: [5, 0, 5, 5],
  98 + align: 'center',
  99 + fontSize: 16,
  100 + color: 'black'
  101 + }
  102 + }
  103 + }
  104 + },
  105 + data: [60],
  106 + z: 100
  107 + },
  108 + {
  109 + //外
  110 + type: 'bar',
  111 + barWidth: 61,
  112 + barGap: '-100%',
  113 + label: {
  114 + normal: {
  115 + show: false
  116 + }
  117 + },
  118 + legendHoverLink: false,
  119 + silent: true,
  120 + data: [100],
  121 + itemStyle: {
  122 + color: 'rgba(45, 46, 48,0.5)',
  123 + borderWidth: 1,
  124 + borderColor: '#fff'
  125 + },
  126 + z: 98
  127 + },
  128 + {
  129 + //分隔
  130 + type: 'pictorialBar',
  131 + animationDuration: 0,
  132 + itemStyle: {
  133 + color: 'rgba(0,0,0,0.7)'
  134 + },
  135 + symbolRepeat: 'fixed',
  136 + symbolMargin: '8',
  137 + symbol: 'rect',
  138 + symbolClip: true,
  139 + symbolSize: [4, 60],
  140 + symbolPosition: 'start',
  141 + symbolOffset: [0, 0],
  142 + data: [60],
  143 + z: 101
  144 + }
  145 + ]
  146 +}
  147 +
  148 +export default class Config extends PublicConfigClass implements CreateComponentType {
  149 + public key: string = Decorates14Config.key
  150 + public chartConfig = cloneDeep(Decorates14Config)
  151 + // 图表配置项
  152 + public option = echartOptionProfixHandle(option, includes)
  153 +}
... ...
  1 +<template>
  2 + <!-- Echarts 全局设置 -->
  3 + <global-setting :optionData="optionData"></global-setting>
  4 + <CollapseItem name="配置" :expanded="true">
  5 + <setting-item-box name="数据点配置">
  6 + <setting-item name="数据">
  7 + <n-input-number v-model:value="optionData.dataset"></n-input-number>
  8 + </setting-item>
  9 + </setting-item-box>
  10 + <setting-item-box name="grid配置">
  11 + <setting-item name="顶部">
  12 + <n-input-number v-model:value="optionData.grid.top"></n-input-number>
  13 + </setting-item>
  14 + <setting-item name="底部">
  15 + <n-input-number v-model:value="optionData.grid.bottom"></n-input-number>
  16 + </setting-item>
  17 + </setting-item-box>
  18 + <setting-item-box name="内外bar和中间分隔高度">
  19 + <setting-item name="内">
  20 + <n-input-number v-model:value="seriesList[0].barWidth"></n-input-number>
  21 + </setting-item>
  22 + <setting-item name="外">
  23 + <n-input-number v-model:value="seriesList[1].barWidth"></n-input-number>
  24 + </setting-item>
  25 + <setting-item name="分隔">
  26 + <n-input-number v-model:value="seriesList[2].symbolSize[1]"></n-input-number>
  27 + </setting-item>
  28 + </setting-item-box>
  29 + <setting-item-box name="数值">
  30 + <setting-item name="颜色">
  31 + <n-color-picker v-model:value="seriesList[0].label.normal.rich.white.color"></n-color-picker>
  32 + </setting-item>
  33 + <setting-item name="大小">
  34 + <n-input-number v-model:value="seriesList[0].label.normal.rich.white.fontSize"></n-input-number>
  35 + </setting-item>
  36 + </setting-item-box>
  37 + <setting-item-box name="内部bar">
  38 + <setting-item name="渐变色1">
  39 + <n-color-picker size="small" v-model:value="seriesList[0].itemStyle.color.colorStops[0].color"></n-color-picker>
  40 + </setting-item>
  41 + <setting-item name="渐变色2">
  42 + <n-color-picker size="small" v-model:value="seriesList[0].itemStyle.color.colorStops[1].color"></n-color-picker>
  43 + </setting-item>
  44 + </setting-item-box>
  45 + <setting-item-box name="外部bar">
  46 + <setting-item name="颜色">
  47 + <n-color-picker size="small" v-model:value="seriesList[1].itemStyle.color"></n-color-picker>
  48 + </setting-item>
  49 + </setting-item-box>
  50 + <setting-item-box name="分隔">
  51 + <setting-item name="颜色">
  52 + <n-color-picker size="small" v-model:value="seriesList[2].itemStyle.color"></n-color-picker>
  53 + </setting-item>
  54 + </setting-item-box>
  55 + </CollapseItem>
  56 +</template>
  57 +
  58 +<script setup lang="ts">
  59 +import { PropType, computed } from 'vue'
  60 +import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
  61 +import { GlobalSetting, CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
  62 +
  63 +const props = defineProps({
  64 + optionData: {
  65 + type: Object as PropType<GlobalThemeJsonType> & PropType<any>,
  66 + required: true
  67 + }
  68 +})
  69 +
  70 +const seriesList = computed(() => {
  71 + return props.optionData.series
  72 +})
  73 +</script>
... ...
  1 +import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
  2 +import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
  3 +import { useWidgetKey } from '@/packages/external/useWidgetKey'
  4 +
  5 +const { key, chartKey, conKey } = useWidgetKey('Decorates14',true)
  6 +
  7 +export const Decorates14Config: ConfigType = {
  8 + key,
  9 + chartKey,
  10 + conKey,
  11 + title: '装饰14',
  12 + category: ChatCategoryEnum.DECORATE,
  13 + categoryName: ChatCategoryEnumName.DECORATE,
  14 + package: PackagesCategoryEnum.DECORATES,
  15 + chartFrame: ChartFrameEnum.COMMON,
  16 + image: 'decorates14.png',
  17 +}
... ...
  1 +<template>
  2 + <v-chart :theme="themeColor" :init-options="initOptions" :option="option.value" autoresize> </v-chart>
  3 +</template>
  4 +
  5 +<script setup lang="ts">
  6 +import { PropType, watch, reactive, onMounted } from 'vue'
  7 +import VChart from 'vue-echarts'
  8 +import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
  9 +import { use } from 'echarts/core'
  10 +import { CanvasRenderer } from 'echarts/renderers'
  11 +import { LineChart } from 'echarts/charts'
  12 +import config, { includes } from './config'
  13 +import { mergeTheme } from '@/packages/public/chart'
  14 +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
  15 +import { useChartDataFetch } from '@/hooks'
  16 +import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
  17 +
  18 +const props = defineProps({
  19 + themeSetting: {
  20 + type: Object,
  21 + required: true
  22 + },
  23 + themeColor: {
  24 + type: Object,
  25 + required: true
  26 + },
  27 + chartConfig: {
  28 + type: Object as PropType<config>,
  29 + required: true
  30 + }
  31 +})
  32 +
  33 +const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
  34 +
  35 +use([DatasetComponent, CanvasRenderer, LineChart, GridComponent, TooltipComponent, LegendComponent])
  36 +
  37 +const option = reactive<{ value: Recordable }>({
  38 + value: {}
  39 +})
  40 +
  41 +onMounted(() => {
  42 + option.value = { ...props.chartConfig.option }
  43 +})
  44 +
  45 +const dataHandle = (newData: number) => {
  46 + let config = props.chartConfig.option
  47 + config.series[0].data = [newData]
  48 + config.series[2].data = [newData]
  49 + option.value = mergeTheme(props.chartConfig.option, props.themeSetting, includes)
  50 + option.value = { ...props.chartConfig.option, ...config }
  51 +}
  52 +
  53 +// 配置时
  54 +watch(
  55 + () => props.chartConfig.option.dataset,
  56 + (newData: number) => {
  57 + try {
  58 + dataHandle(newData)
  59 + } catch (error) {
  60 + console.log(error)
  61 + }
  62 + },
  63 + {
  64 + immediate: true
  65 + }
  66 +)
  67 +// 预览时
  68 +useChartDataFetch(props.chartConfig, useChartEditStore, (resData: number) => {
  69 + option.value.series[0].data = [resData]
  70 + option.value.series[2].data = [resData]
  71 +})
  72 +</script>
... ...
  1 +import { PublicConfigClass } from '@/packages/public'
  2 +import { Decorates15Config } from './index'
  3 +import { CreateComponentType } from '@/packages/index.d'
  4 +import cloneDeep from 'lodash/cloneDeep'
  5 +import { chartInitConfig } from '@/settings/designSetting'
  6 +export const includes = ['legend', 'xAxis', 'yAxis', 'grid']
  7 +
  8 +export const option = {
  9 + styleConfig: {
  10 + scale: 1
  11 + }
  12 +}
  13 +
  14 +export default class Config extends PublicConfigClass implements CreateComponentType {
  15 + public key = Decorates15Config.key
  16 + public attr = { ...chartInitConfig, w: 300, h: 300, zIndex: -1 }
  17 + public chartConfig = cloneDeep(Decorates15Config)
  18 + public option = cloneDeep(option)
  19 +}
... ...
  1 +<template>
  2 + <!-- Echarts 全局设置 -->
  3 + <global-setting :optionData="optionData"></global-setting>
  4 + <CollapseItem name="配置" :expanded="true">
  5 + <setting-item-box name="样式配置">
  6 + <setting-item name="缩放">
  7 + <n-input-number :min="0" v-model:value="optionData.styleConfig.scale"></n-input-number>
  8 + </setting-item>
  9 + </setting-item-box>
  10 + </CollapseItem>
  11 +</template>
  12 +
  13 +<script setup lang="ts">
  14 +import { PropType } from 'vue'
  15 +import { option } from './config'
  16 +import { GlobalSetting, CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
  17 +
  18 +defineProps({
  19 + optionData: {
  20 + type: Object as PropType<typeof option>,
  21 + required: true
  22 + }
  23 +})
  24 +</script>
... ...
  1 +import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
  2 +import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
  3 +import { useWidgetKey } from '@/packages/external/useWidgetKey'
  4 +
  5 +const { key, chartKey, conKey } = useWidgetKey('Decorates15',true)
  6 +
  7 +export const Decorates15Config: ConfigType = {
  8 + key,
  9 + chartKey,
  10 + conKey,
  11 + title: '装饰15',
  12 + category: ChatCategoryEnum.DECORATE,
  13 + categoryName: ChatCategoryEnumName.DECORATE,
  14 + package: PackagesCategoryEnum.DECORATES,
  15 + chartFrame: ChartFrameEnum.COMMON,
  16 + image: 'decorates15.png',
  17 +}
... ...
  1 +<template>
  2 + <div style="position: fixed" :style="{ width: `${w}px`, height: `${h}px` }">
  3 + <div :style="{ transform: `scale(${styleConfig.scale})` }" class="arc_reactor">
  4 + <div class="case_container">
  5 + <div class="e7">
  6 + <div class="semi_arc_3 e5_1">
  7 + <div class="semi_arc_3 e5_2">
  8 + <div class="semi_arc_3 e5_3">
  9 + <div class="semi_arc_3 e5_4"></div>
  10 + </div>
  11 + </div>
  12 + </div>
  13 + <div class="core2"></div>
  14 + </div>
  15 + <ul class="marks">
  16 + <li></li>
  17 + <li></li>
  18 + <li></li>
  19 + <li></li>
  20 + <li></li>
  21 + <li></li>
  22 + <li></li>
  23 + <li></li>
  24 + <li></li>
  25 + <li></li>
  26 + <li></li>
  27 + <li></li>
  28 + <li></li>
  29 + <li></li>
  30 + <li></li>
  31 + <li></li>
  32 + <li></li>
  33 + <li></li>
  34 + <li></li>
  35 + <li></li>
  36 + <li></li>
  37 + <li></li>
  38 + <li></li>
  39 + <li></li>
  40 + <li></li>
  41 + <li></li>
  42 + <li></li>
  43 + <li></li>
  44 + <li></li>
  45 + <li></li>
  46 + <li></li>
  47 + <li></li>
  48 + <li></li>
  49 + <li></li>
  50 + <li></li>
  51 + <li></li>
  52 + <li></li>
  53 + <li></li>
  54 + <li></li>
  55 + <li></li>
  56 + <li></li>
  57 + <li></li>
  58 + <li></li>
  59 + <li></li>
  60 + <li></li>
  61 + <li></li>
  62 + <li></li>
  63 + <li></li>
  64 + <li></li>
  65 + <li></li>
  66 + <li></li>
  67 + <li></li>
  68 + <li></li>
  69 + <li></li>
  70 + <li></li>
  71 + <li></li>
  72 + <li></li>
  73 + <li></li>
  74 + <li></li>
  75 + <li></li>
  76 + </ul>
  77 + </div>
  78 + </div>
  79 + </div>
  80 +</template>
  81 +
  82 +<script setup lang="ts">
  83 +import { PropType, toRefs, watch } from 'vue'
  84 +import { CreateComponentType } from '@/packages/index.d'
  85 +import { option } from './config'
  86 +
  87 +const props = defineProps({
  88 + chartConfig: {
  89 + type: Object as PropType<CreateComponentType & typeof option>,
  90 + required: true
  91 + }
  92 +})
  93 +const { w, h } = toRefs(props.chartConfig.attr)
  94 +
  95 +const { styleConfig } = toRefs(props.chartConfig.option)
  96 +
  97 +watch(
  98 + () => styleConfig.value,
  99 + (newValue: Recordable) => {
  100 + styleConfig.value.scale = newValue.scale
  101 + },
  102 + {
  103 + immediate: true,
  104 + deep: true
  105 + }
  106 +)
  107 +</script>
  108 +
  109 +<style scoped>
  110 +body {
  111 + color: #02feff;
  112 + overflow: hidden;
  113 +}
  114 +
  115 +.core2 {
  116 + background: #cedce0;
  117 + width: 100px;
  118 + height: 100px;
  119 + -moz-border-radius: 50%;
  120 + -webkit-border-radius: 50%;
  121 + border-radius: 50%;
  122 + border: 10px rgba(2, 255, 255, 0.15) solid;
  123 + animation: flicker2 0.2s infinite;
  124 + margin-left: auto;
  125 + margin-right: auto;
  126 + margin-top: 40px;
  127 +}
  128 +
  129 +.big_core {
  130 + background: #cedce0;
  131 + width: 200px;
  132 + height: 200px;
  133 + -moz-border-radius: 50%;
  134 + -webkit-border-radius: 50%;
  135 + border-radius: 50%;
  136 + border: 10px rgba(2, 255, 255, 0.15) solid;
  137 + animation: big_flicker 0.2s infinite;
  138 +}
  139 +
  140 +.c_ease {
  141 + animation: colour_ease 3s infinite ease-in-out;
  142 +}
  143 +
  144 +.counterspin5 {
  145 + animation: rotate_anti 5s linear infinite;
  146 +}
  147 +
  148 +.counterspin4 {
  149 + animation: rotate_anti 4s linear infinite;
  150 +}
  151 +
  152 +.semi_arc {
  153 + width: 100px;
  154 + height: 100px;
  155 + border: 6px solid #02feff;
  156 + background: rgba(2, 254, 255, 0.2);
  157 + -moz-border-radius: 50%;
  158 + -webkit-border-radius: 50%;
  159 + border-radius: 50%;
  160 + transform: rotateZ(0deg);
  161 + transition: box-shadow 3s ease;
  162 + text-align: center;
  163 + line-height: 100px;
  164 +}
  165 +
  166 +.semi_arc:hover {
  167 + box-shadow: 0px 0px 30px rgba(2, 254, 255, 0.8);
  168 + transition: 0.3s;
  169 +}
  170 +
  171 +.semi_arc_2 {
  172 + content: '';
  173 + position: absolute;
  174 + width: 94%;
  175 + height: 94%;
  176 + left: 3%;
  177 + top: 3%;
  178 + border: 5px solid #02feff;
  179 + -moz-border-radius: 50%;
  180 + -webkit-border-radius: 50%;
  181 + border-radius: 50%;
  182 + -moz-box-sizing: border-box;
  183 + -webkit-box-sizing: border-box;
  184 + box-sizing: border-box;
  185 + animation: rotate 4s linear infinite;
  186 + text-align: center;
  187 + line-height: 129px;
  188 +}
  189 +
  190 +.semi_arc_2:after {
  191 + content: '';
  192 + position: absolute;
  193 + width: 94%;
  194 + height: 94%;
  195 + left: 3%;
  196 + top: 3%;
  197 + border: 4px solid #02feff;
  198 + -moz-border-radius: 50%;
  199 + -webkit-border-radius: 50%;
  200 + border-radius: 50%;
  201 + -moz-box-sizing: border-box;
  202 + -webkit-box-sizing: border-box;
  203 + box-sizing: border-box;
  204 + animation: rotate_anti 2s linear infinite;
  205 +}
  206 +
  207 +.semi_arc_3 {
  208 + content: '';
  209 + position: absolute;
  210 + width: 94%;
  211 + height: 94%;
  212 + left: 3%;
  213 + top: 3%;
  214 + border: 5px solid #02feff;
  215 + -moz-border-radius: 50%;
  216 + -webkit-border-radius: 50%;
  217 + border-radius: 50%;
  218 + -moz-box-sizing: border-box;
  219 + -webkit-box-sizing: border-box;
  220 + box-sizing: border-box;
  221 + animation: rotate 4s linear infinite;
  222 + text-align: center;
  223 + line-height: 129px;
  224 +}
  225 +
  226 +.arc {
  227 + width: 100px;
  228 + height: 100px;
  229 + border: 6px solid #02feff;
  230 + background: rgba(2, 254, 255, 0.2);
  231 + -moz-border-radius: 50%;
  232 + -webkit-border-radius: 50%;
  233 + border-radius: 50%;
  234 + -moz-transform: rotateY(-30deg) translateZ(-200px);
  235 + -ms-transform: rotateY(-30deg) translateZ(-200px);
  236 + -webkit-transform: rotateY(-30deg) translateZ(-200px);
  237 + transform: rotateY(-30deg) translateZ(-200px);
  238 + transform: rotateZ(0deg);
  239 + transition: box-shadow 3s ease;
  240 + text-align: center;
  241 + line-height: 100px;
  242 +}
  243 +
  244 +.arc:hover {
  245 + box-shadow: 0px 0px 30px rgba(2, 254, 255, 0.8);
  246 + transition: 0.3s;
  247 +}
  248 +
  249 +.arc:after {
  250 + content: '';
  251 + position: absolute;
  252 + width: 94%;
  253 + height: 94%;
  254 + left: 3%;
  255 + top: 3%;
  256 + border: 4px solid #02feff;
  257 + -moz-border-radius: 50%;
  258 + -webkit-border-radius: 50%;
  259 + border-radius: 50%;
  260 + -moz-box-sizing: border-box;
  261 + -webkit-box-sizing: border-box;
  262 + box-sizing: border-box;
  263 + animation: rotate 4s linear infinite;
  264 +}
  265 +
  266 +.e1:after {
  267 + border-color: rgba(2, 255, 255, 0.6);
  268 + border-left: 5px solid transparent;
  269 + border-right: 5px solid transparent;
  270 +}
  271 +
  272 +.e2:after {
  273 + border-color: rgba(2, 255, 255, 0.6);
  274 + border-left: 5px solid transparent;
  275 + border-right: 5px solid transparent;
  276 + border-bottom: 5px solid transparent;
  277 +}
  278 +
  279 +.e3 {
  280 + border-left: 6px solid transparent;
  281 + border-right: 6px solid transparent;
  282 + animation: rotate 5s linear infinite;
  283 +}
  284 +
  285 +.e3:after {
  286 + border-color: rgba(2, 255, 255, 0.6);
  287 + border-top: 5px solid transparent;
  288 + border-bottom: 5px solid transparent;
  289 +}
  290 +
  291 +.e4 {
  292 + width: 150px;
  293 + height: 150px;
  294 +}
  295 +
  296 +.e4_1 {
  297 + border-color: rgba(2, 255, 255, 0.3);
  298 + border-left: 5px solid transparent;
  299 + border-right: 5px solid transparent;
  300 +}
  301 +
  302 +.e4_1:after {
  303 + border-color: rgba(2, 255, 255, 0.6);
  304 + border-top: 4px solid transparent;
  305 + border-bottom: 4px solid transparent;
  306 +}
  307 +
  308 +.e5 {
  309 + width: 200px;
  310 + height: 200px;
  311 +}
  312 +
  313 +.e5_1 {
  314 + color: rgba(2, 255, 255, 0.15);
  315 + border: 2px solid;
  316 + border-left: 2px solid transparent;
  317 + animation: rotate 5s linear infinite;
  318 +}
  319 +
  320 +.e5_2 {
  321 + color: rgba(2, 255, 255, 0.7);
  322 + border: 4px solid;
  323 + border-left: 4px solid transparent;
  324 + border-right: 4px solid transparent;
  325 + animation: rotate_anti 4s linear infinite;
  326 +}
  327 +
  328 +.e5_3 {
  329 + color: rgba(2, 255, 255, 0.5);
  330 + border: 2px solid;
  331 + border-left: 2px solid transparent;
  332 + border-right: 2px solid transparent;
  333 + animation: rotate 3s linear infinite;
  334 +}
  335 +
  336 +.e5_4 {
  337 + color: rgba(2, 255, 255, 0.15);
  338 + border: 4px solid;
  339 + border-left: 4px solid transparent;
  340 + border-right: 4px solid transparent;
  341 + border-bottom: 4px solid transparent;
  342 + animation: rotate_anti 2s linear infinite;
  343 +}
  344 +
  345 +.e6 {
  346 + border-color: transparent;
  347 + background: rgba(255, 255, 255, 0);
  348 + width: 200px;
  349 + height: 200px;
  350 +}
  351 +
  352 +@keyframes rotate {
  353 + 0% {
  354 + transform: rotateZ(0deg);
  355 + }
  356 + 100% {
  357 + transform: rotateZ(360deg);
  358 + }
  359 +}
  360 +@keyframes rotate_anti {
  361 + 0% {
  362 + transform: rotateZ(360deg);
  363 + }
  364 + 100% {
  365 + transform: rotateZ(0deg);
  366 + }
  367 +}
  368 +@keyframes colour_ease {
  369 + 0% {
  370 + border-color: #02feff;
  371 + }
  372 + 50% {
  373 + border-color: rgba(2, 254, 255, 0.5);
  374 + }
  375 + 100% {
  376 + border-color: #02feff;
  377 + }
  378 +}
  379 +@keyframes flicker {
  380 + 0% {
  381 + box-shadow: 0px 0px 16px 8px rgba(150, 255, 255, 0.5), inset 0px 1px 4px 2px rgba(21, 211, 233, 0.3);
  382 + }
  383 + 40% {
  384 + box-shadow: 0px 0px 16px 8px rgba(150, 255, 255, 0.5), inset 0px 1px 4px 2px rgba(21, 211, 233, 0.3);
  385 + }
  386 + 50% {
  387 + box-shadow: 0px 0px 16px 6px rgba(150, 255, 255, 0.5), inset 0px 1px 100px 2px rgba(21, 211, 233, 0.3);
  388 + }
  389 + 60% {
  390 + box-shadow: 0px 0px 16px 8px rgba(150, 255, 255, 0.5), inset 0px 1px 4px 2px rgba(21, 211, 233, 0.3);
  391 + }
  392 + 100% {
  393 + box-shadow: 0px 0px 16px 8px rgba(150, 255, 255, 0.5), inset 0px 1px 4px 2px rgba(21, 211, 233, 0.3);
  394 + }
  395 +}
  396 +@keyframes flicker2 {
  397 + 0% {
  398 + box-shadow: 0px 0px 60px 25px rgba(150, 255, 255, 0.5), inset 0px 1px 4px 2px rgba(21, 211, 233, 0.3);
  399 + }
  400 + 40% {
  401 + box-shadow: 0px 0px 60px 25px rgba(150, 255, 255, 0.5), inset 0px 1px 4px 2px rgba(21, 211, 233, 0.3);
  402 + }
  403 + 50% {
  404 + box-shadow: 0px 0px 50px 17px rgba(150, 255, 255, 0.5), inset 0px 1px 100px 2px rgba(21, 211, 233, 0.3);
  405 + }
  406 + 60% {
  407 + box-shadow: 0px 0px 60px 25px rgba(150, 255, 255, 0.5), inset 0px 1px 4px 2px rgba(21, 211, 233, 0.3);
  408 + }
  409 + 100% {
  410 + box-shadow: 0px 0px 60px 25px rgba(150, 255, 255, 0.5), inset 0px 1px 4px 2px rgba(21, 211, 233, 0.3);
  411 + }
  412 +}
  413 +@keyframes big_flicker {
  414 + 0% {
  415 + box-shadow: 0px 0px 40px 20px rgba(150, 255, 255, 0.5), inset 0px 1px 30px 15px rgba(21, 211, 233, 0.3);
  416 + }
  417 + 40% {
  418 + box-shadow: 0px 0px 40px 20px rgba(150, 255, 255, 0.5), inset 0px 1px 30px 15px rgba(21, 211, 233, 0.3);
  419 + }
  420 + 50% {
  421 + box-shadow: 0px 0px 35px 17px rgba(150, 255, 255, 0.5), inset 0px 1px 50px 40px rgba(21, 211, 233, 0.3);
  422 + }
  423 + 60% {
  424 + box-shadow: 0px 0px 40px 20px rgba(150, 255, 255, 0.5), inset 0px 1px 30px 15px rgba(21, 211, 233, 0.3);
  425 + }
  426 + 100% {
  427 + box-shadow: 0px 0px 40px 20px rgba(150, 255, 255, 0.5), inset 0px 1px 30px 15px rgba(21, 211, 233, 0.3);
  428 + }
  429 +}
  430 +html,
  431 +body {
  432 + height: 100%;
  433 +}
  434 +
  435 +ul {
  436 + list-style: none;
  437 + margin: 0;
  438 + padding: 0;
  439 +}
  440 +
  441 +.arc_reactor {
  442 + position: relative;
  443 + top: 50%;
  444 + margin-top: -125px;
  445 + margin-left: auto;
  446 + margin-right: auto;
  447 + width: 250px;
  448 + height: 250px;
  449 + border-radius: 50%;
  450 + box-shadow: 0px 0px 50px 15px rgba(2, 255, 255, 0.3), inset 0px 0px 50px 15px rgba(2, 255, 255, 0.3);
  451 +}
  452 +
  453 +.core2 {
  454 + background: #cedce0;
  455 + width: 110px;
  456 + height: 110px;
  457 + -moz-border-radius: 50%;
  458 + -webkit-border-radius: 50%;
  459 + border-radius: 50%;
  460 + border: 5px solid rgba(2, 255, 255, 0.15);
  461 + animation: flicker2 0.2s infinite;
  462 + margin-left: auto;
  463 + margin-right: auto;
  464 + margin-top: 40px;
  465 +}
  466 +
  467 +.e7 {
  468 + width: 95.25%;
  469 + height: 95.25%;
  470 + left: 2.5475%;
  471 + right: 2.5475%;
  472 + border: 6px solid transparent;
  473 + background: transparent;
  474 + -moz-border-radius: 50%;
  475 + -webkit-border-radius: 50%;
  476 + border-radius: 50%;
  477 + transform: rotateZ(0deg);
  478 + transition: box-shadow 3s ease;
  479 + text-align: center;
  480 + line-height: 100px;
  481 +}
  482 +
  483 +.case_container {
  484 + width: 210px;
  485 + height: 210px;
  486 + border-radius: 50%;
  487 + position: absolute;
  488 + margin-left: 20px;
  489 + margin-top: 20px;
  490 +}
  491 +
  492 +.marks li {
  493 + display: block;
  494 + width: 3px;
  495 + height: 11px;
  496 + background: rgba(2, 254, 255, 0.8);
  497 + position: absolute;
  498 + margin-left: 105px;
  499 + margin-top: -110px;
  500 + animation: colour_ease2 3s infinite ease-in-out;
  501 +}
  502 +
  503 +@keyframes colour_ease2 {
  504 + 0% {
  505 + background: #02feff;
  506 + }
  507 + 50% {
  508 + background: rgba(2, 254, 255, 0.3);
  509 + }
  510 + 100% {
  511 + background: #02feff;
  512 + }
  513 +}
  514 +.marks li:first-child {
  515 + transform: rotate(6deg) translateY(125px);
  516 +}
  517 +
  518 +.marks li:nth-child(2) {
  519 + transform: rotate(12deg) translateY(125px);
  520 +}
  521 +
  522 +.marks li:nth-child(3) {
  523 + transform: rotate(18deg) translateY(125px);
  524 +}
  525 +
  526 +.marks li:nth-child(4) {
  527 + transform: rotate(24deg) translateY(125px);
  528 +}
  529 +
  530 +.marks li:nth-child(5) {
  531 + transform: rotate(30deg) translateY(125px);
  532 +}
  533 +
  534 +.marks li:nth-child(6) {
  535 + transform: rotate(36deg) translateY(125px);
  536 +}
  537 +
  538 +.marks li:nth-child(7) {
  539 + transform: rotate(42deg) translateY(125px);
  540 +}
  541 +
  542 +.marks li:nth-child(8) {
  543 + transform: rotate(48deg) translateY(125px);
  544 +}
  545 +
  546 +.marks li:nth-child(9) {
  547 + transform: rotate(54deg) translateY(125px);
  548 +}
  549 +
  550 +.marks li:nth-child(10) {
  551 + transform: rotate(60deg) translateY(125px);
  552 +}
  553 +
  554 +.marks li:nth-child(11) {
  555 + transform: rotate(66deg) translateY(125px);
  556 +}
  557 +
  558 +.marks li:nth-child(12) {
  559 + transform: rotate(72deg) translateY(125px);
  560 +}
  561 +
  562 +.marks li:nth-child(13) {
  563 + transform: rotate(78deg) translateY(125px);
  564 +}
  565 +
  566 +.marks li:nth-child(14) {
  567 + transform: rotate(84deg) translateY(125px);
  568 +}
  569 +
  570 +.marks li:nth-child(15) {
  571 + transform: rotate(90deg) translateY(125px);
  572 +}
  573 +
  574 +.marks li:nth-child(16) {
  575 + transform: rotate(96deg) translateY(125px);
  576 +}
  577 +
  578 +.marks li:nth-child(17) {
  579 + transform: rotate(102deg) translateY(125px);
  580 +}
  581 +
  582 +.marks li:nth-child(18) {
  583 + transform: rotate(108deg) translateY(125px);
  584 +}
  585 +
  586 +.marks li:nth-child(19) {
  587 + transform: rotate(114deg) translateY(125px);
  588 +}
  589 +
  590 +.marks li:nth-child(20) {
  591 + transform: rotate(120deg) translateY(125px);
  592 +}
  593 +
  594 +.marks li:nth-child(21) {
  595 + transform: rotate(126deg) translateY(125px);
  596 +}
  597 +
  598 +.marks li:nth-child(22) {
  599 + transform: rotate(132deg) translateY(125px);
  600 +}
  601 +
  602 +.marks li:nth-child(23) {
  603 + transform: rotate(138deg) translateY(125px);
  604 +}
  605 +
  606 +.marks li:nth-child(24) {
  607 + transform: rotate(144deg) translateY(125px);
  608 +}
  609 +
  610 +.marks li:nth-child(25) {
  611 + transform: rotate(150deg) translateY(125px);
  612 +}
  613 +
  614 +.marks li:nth-child(26) {
  615 + transform: rotate(156deg) translateY(125px);
  616 +}
  617 +
  618 +.marks li:nth-child(27) {
  619 + transform: rotate(162deg) translateY(125px);
  620 +}
  621 +
  622 +.marks li:nth-child(28) {
  623 + transform: rotate(168deg) translateY(125px);
  624 +}
  625 +
  626 +.marks li:nth-child(29) {
  627 + transform: rotate(174deg) translateY(125px);
  628 +}
  629 +
  630 +.marks li:nth-child(30) {
  631 + transform: rotate(180deg) translateY(125px);
  632 +}
  633 +
  634 +.marks li:nth-child(31) {
  635 + transform: rotate(186deg) translateY(125px);
  636 +}
  637 +
  638 +.marks li:nth-child(32) {
  639 + transform: rotate(192deg) translateY(125px);
  640 +}
  641 +
  642 +.marks li:nth-child(33) {
  643 + transform: rotate(198deg) translateY(125px);
  644 +}
  645 +
  646 +.marks li:nth-child(34) {
  647 + transform: rotate(204deg) translateY(125px);
  648 +}
  649 +
  650 +.marks li:nth-child(35) {
  651 + transform: rotate(210deg) translateY(125px);
  652 +}
  653 +
  654 +.marks li:nth-child(36) {
  655 + transform: rotate(216deg) translateY(125px);
  656 +}
  657 +
  658 +.marks li:nth-child(37) {
  659 + transform: rotate(222deg) translateY(125px);
  660 +}
  661 +
  662 +.marks li:nth-child(38) {
  663 + transform: rotate(228deg) translateY(125px);
  664 +}
  665 +
  666 +.marks li:nth-child(39) {
  667 + transform: rotate(234deg) translateY(125px);
  668 +}
  669 +
  670 +.marks li:nth-child(40) {
  671 + transform: rotate(240deg) translateY(125px);
  672 +}
  673 +
  674 +.marks li:nth-child(41) {
  675 + transform: rotate(246deg) translateY(125px);
  676 +}
  677 +
  678 +.marks li:nth-child(42) {
  679 + transform: rotate(252deg) translateY(125px);
  680 +}
  681 +
  682 +.marks li:nth-child(43) {
  683 + transform: rotate(258deg) translateY(125px);
  684 +}
  685 +
  686 +.marks li:nth-child(44) {
  687 + transform: rotate(264deg) translateY(125px);
  688 +}
  689 +
  690 +.marks li:nth-child(45) {
  691 + transform: rotate(270deg) translateY(125px);
  692 +}
  693 +
  694 +.marks li:nth-child(46) {
  695 + transform: rotate(276deg) translateY(125px);
  696 +}
  697 +
  698 +.marks li:nth-child(47) {
  699 + transform: rotate(282deg) translateY(125px);
  700 +}
  701 +
  702 +.marks li:nth-child(48) {
  703 + transform: rotate(288deg) translateY(125px);
  704 +}
  705 +
  706 +.marks li:nth-child(49) {
  707 + transform: rotate(294deg) translateY(125px);
  708 +}
  709 +
  710 +.marks li:nth-child(50) {
  711 + transform: rotate(300deg) translateY(125px);
  712 +}
  713 +
  714 +.marks li:nth-child(51) {
  715 + transform: rotate(306deg) translateY(125px);
  716 +}
  717 +
  718 +.marks li:nth-child(52) {
  719 + transform: rotate(312deg) translateY(125px);
  720 +}
  721 +
  722 +.marks li:nth-child(53) {
  723 + transform: rotate(318deg) translateY(125px);
  724 +}
  725 +
  726 +.marks li:nth-child(54) {
  727 + transform: rotate(324deg) translateY(125px);
  728 +}
  729 +
  730 +.marks li:nth-child(55) {
  731 + transform: rotate(330deg) translateY(125px);
  732 +}
  733 +
  734 +.marks li:nth-child(56) {
  735 + transform: rotate(336deg) translateY(125px);
  736 +}
  737 +
  738 +.marks li:nth-child(57) {
  739 + transform: rotate(342deg) translateY(125px);
  740 +}
  741 +
  742 +.marks li:nth-child(58) {
  743 + transform: rotate(348deg) translateY(125px);
  744 +}
  745 +
  746 +.marks li:nth-child(59) {
  747 + transform: rotate(354deg) translateY(125px);
  748 +}
  749 +
  750 +.marks li:nth-child(60) {
  751 + transform: rotate(360deg) translateY(125px);
  752 +}
  753 +</style>
... ...
  1 +import { PublicConfigClass } from '@/packages/public'
  2 +import { Decorates16Config } from './index'
  3 +import { CreateComponentType } from '@/packages/index.d'
  4 +import cloneDeep from 'lodash/cloneDeep'
  5 +import { chartInitConfig } from '@/settings/designSetting'
  6 +export const includes = ['legend', 'xAxis', 'yAxis', 'grid']
  7 +
  8 +export const option = {
  9 + dataset: 20,
  10 + unit: '台',
  11 + mainCicleColor: '#03A6E0CC',
  12 + subCicleColor: '#03A6E07F',
  13 + textColor:'green'
  14 +}
  15 +
  16 +export default class Config extends PublicConfigClass implements CreateComponentType {
  17 + public key = Decorates16Config.key
  18 + public attr = { ...chartInitConfig, w: 150, h: 120, zIndex: -1 }
  19 + public chartConfig = cloneDeep(Decorates16Config)
  20 + public option = cloneDeep(option)
  21 +}
... ...
  1 +<template>
  2 + <!-- Echarts 全局设置 -->
  3 + <global-setting :optionData="optionData"></global-setting>
  4 + <CollapseItem name="配置" :expanded="true">
  5 + <setting-item-box name="数据">
  6 + <setting-item name="数据源">
  7 + <n-input-number :min="0" v-model:value="optionData.dataset"></n-input-number>
  8 + </setting-item>
  9 + <setting-item name="单位">
  10 + <n-input v-model:value="optionData.unit"></n-input>
  11 + </setting-item>
  12 + </setting-item-box>
  13 + <setting-item-box name="颜色">
  14 + <setting-item name="颜色1">
  15 + <n-color-picker v-model:value="optionData.mainCicleColor"></n-color-picker>
  16 + </setting-item>
  17 + <setting-item name="颜色2">
  18 + <n-color-picker v-model:value="optionData.subCicleColor"></n-color-picker>
  19 + </setting-item>
  20 + <setting-item name="文字颜色">
  21 + <n-color-picker v-model:value="optionData.textColor"></n-color-picker>
  22 + </setting-item>
  23 + </setting-item-box>
  24 + </CollapseItem>
  25 +</template>
  26 +
  27 +<script setup lang="ts">
  28 +import { PropType } from 'vue'
  29 +import { option } from './config'
  30 +import { GlobalSetting, CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
  31 +
  32 +defineProps({
  33 + optionData: {
  34 + type: Object as PropType<typeof option>,
  35 + required: true
  36 + }
  37 +})
  38 +</script>
... ...
  1 +import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
  2 +import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
  3 +import { useWidgetKey } from '@/packages/external/useWidgetKey'
  4 +
  5 +const { key, chartKey, conKey } = useWidgetKey('Decorates16',true)
  6 +
  7 +export const Decorates16Config: ConfigType = {
  8 + key,
  9 + chartKey,
  10 + conKey,
  11 + title: '装饰16',
  12 + category: ChatCategoryEnum.DECORATE,
  13 + categoryName: ChatCategoryEnumName.DECORATE,
  14 + package: PackagesCategoryEnum.DECORATES,
  15 + chartFrame: ChartFrameEnum.COMMON,
  16 + image: 'decorates16.png',
  17 +}
... ...
  1 +<template>
  2 + <div class="go-content-box">
  3 + <svg
  4 + xmlns="http://www.w3.org/2000/svg"
  5 + xmlns:xlink="http://www.w3.org/1999/xlink"
  6 + :width="w"
  7 + :height="h"
  8 + viewBox="0 0 180 180"
  9 + >
  10 + <g opacity="0.6" transform="translate(11 14) scale(1.6)">
  11 + <defs>
  12 + <polygon :id="polygonId" points="15, 46.5, 21, 47.5, 21, 52.5, 15, 53.5" />
  13 + </defs>
  14 + <circle
  15 + cx="50"
  16 + cy="50"
  17 + r="45"
  18 + fill="transparent"
  19 + :stroke="mainCicleColor || defaultColor[0]"
  20 + stroke-width="10"
  21 + stroke-dasharray="80, 100, 30, 100"
  22 + >
  23 + <animateTransform
  24 + attributeName="transform"
  25 + type="rotate"
  26 + values="0 50 50;360 50 50"
  27 + :dur="`${dur}s`"
  28 + repeatCount="indefinite"
  29 + />
  30 + </circle>
  31 + <circle
  32 + cx="50"
  33 + cy="50"
  34 + r="45"
  35 + fill="transparent"
  36 + :stroke="subCicleColor || defaultColor[1]"
  37 + stroke-width="6"
  38 + stroke-dasharray="50, 66, 100, 66"
  39 + >
  40 + <animateTransform
  41 + attributeName="transform"
  42 + type="rotate"
  43 + values="0 50 50;-360 50 50"
  44 + :dur="`${dur}s`"
  45 + repeatCount="indefinite"
  46 + />
  47 + </circle>
  48 + <circle
  49 + cx="50"
  50 + cy="50"
  51 + r="38"
  52 + fill="transparent"
  53 + :stroke="subCicleColor || defaultColor[1]"
  54 + stroke-width="1"
  55 + stroke-dasharray="5, 1"
  56 + />
  57 + <use
  58 + v-for="(foo, i) in new Array(20).fill(0)"
  59 + :key="i"
  60 + :xlink:href="`#${polygonId}`"
  61 + :stroke="mainCicleColor || defaultColor[0]"
  62 + :fill="Math.random() > 0.4 ? 'transparent' : mainCicleColor"
  63 + >
  64 + <animateTransform
  65 + attributeName="transform"
  66 + type="rotate"
  67 + values="0 50 50;360 50 50"
  68 + :dur="`${dur}s`"
  69 + :begin="`${(i * dur) / 20}s`"
  70 + repeatCount="indefinite"
  71 + />
  72 + </use>
  73 + <circle
  74 + cx="50"
  75 + cy="50"
  76 + r="26"
  77 + fill="transparent"
  78 + :stroke="subCicleColor || defaultColor[1]"
  79 + stroke-width="1"
  80 + stroke-dasharray="5, 1"
  81 + />
  82 + <text x="50" y="55" text-anchor="middle" :style="{ fill: textColor, opacity: 1 }" font-size="14">
  83 + {{ dataset + unit }}
  84 + </text>
  85 + </g>
  86 + </svg>
  87 + </div>
  88 +</template>
  89 +<script setup lang="ts">
  90 +import { PropType, toRefs, ref } from 'vue'
  91 +import { CreateComponentType } from '@/packages/index.d'
  92 +import { option } from './config'
  93 +
  94 +const props = defineProps({
  95 + chartConfig: {
  96 + type: Object as PropType<CreateComponentType & typeof option>,
  97 + required: true
  98 + }
  99 +})
  100 +const { w, h } = toRefs(props.chartConfig.attr)
  101 +
  102 +const { mainCicleColor, subCicleColor, dataset, unit, textColor } = toRefs(props.chartConfig.option)
  103 +
  104 +const id = Number(Math.random().toString().substring(2, 10) + Date.now()).toString(36)
  105 +
  106 +const dur = ref(3)
  107 +
  108 +const polygonId = ref(`decoration-9-polygon-${id}`)
  109 +
  110 +const defaultColor = ref(['rgba(3, 166, 224, 0.8)', 'rgba(3, 166, 224, 0.5)'])
  111 +</script>
  112 +
  113 +<style lang="scss" scoped>
  114 +.go-content-box {
  115 + width: v-bind('w+"px"');
  116 + height: v-bind('h+"px"');
  117 + display: flex;
  118 + align-items: center;
  119 + justify-content: center;
  120 +}
  121 +</style>
... ...