Commit ac4f27b6ac5acf57dfa042d73c7a5130287cf478
Merge branch 'ft' into 'main_dev'
feat(packages/external): 重写部分柱状图和部分折线图,新增开启关闭动画效果和全屏效果 See merge request yunteng/thingskit-view!66
Showing
37 changed files
with
1909 additions
and
65 deletions
1 | +import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public' | ||
2 | +import { OverrideBarCommonConfig } from './index' | ||
3 | +import { CreateComponentType } from '@/packages/index.d' | ||
4 | +import cloneDeep from 'lodash/cloneDeep' | ||
5 | +import dataJson from './data.json' | ||
6 | + | ||
7 | +export const includes = ['legend', 'xAxis', 'yAxis', 'grid'] | ||
8 | +// 其它配置项比如新增(动画) | ||
9 | +const otherConfig = { | ||
10 | + // 轮播动画 | ||
11 | + isCarousel: false | ||
12 | +} | ||
13 | +export const seriesItem = { | ||
14 | + type: 'bar', | ||
15 | + barWidth: 15, | ||
16 | + label: { | ||
17 | + show: true, | ||
18 | + position: 'top', | ||
19 | + color: '#fff', | ||
20 | + fontSize: 12 | ||
21 | + }, | ||
22 | + itemStyle: { | ||
23 | + color: null, | ||
24 | + borderRadius: 2 | ||
25 | + } | ||
26 | +} | ||
27 | +export const option = { | ||
28 | + ...otherConfig, | ||
29 | + tooltip: { | ||
30 | + show: true, | ||
31 | + trigger: 'axis', | ||
32 | + axisPointer: { | ||
33 | + show: true, | ||
34 | + type: 'shadow' | ||
35 | + } | ||
36 | + }, | ||
37 | + xAxis: { | ||
38 | + show: true, | ||
39 | + type: 'category' | ||
40 | + }, | ||
41 | + yAxis: { | ||
42 | + show: true, | ||
43 | + type: 'value' | ||
44 | + }, | ||
45 | + dataset: { ...dataJson }, | ||
46 | + series: [seriesItem, seriesItem] | ||
47 | +} | ||
48 | + | ||
49 | +export default class Config extends PublicConfigClass implements CreateComponentType { | ||
50 | + public key = OverrideBarCommonConfig.key | ||
51 | + public chartConfig = cloneDeep(OverrideBarCommonConfig) | ||
52 | + // 图表配置项 | ||
53 | + public option = echartOptionProfixHandle(option, includes) | ||
54 | +} |
1 | +<template> | ||
2 | + <!-- Echarts 全局设置 --> | ||
3 | + <global-setting :optionData="optionData"></global-setting> | ||
4 | + <CollapseItem v-for="(item, index) in seriesList" :key="index" :name="`柱状图-${index + 1}`" :expanded="true"> | ||
5 | + <SettingItemBox name="图形"> | ||
6 | + <SettingItem name="宽度"> | ||
7 | + <n-input-number | ||
8 | + v-model:value="item.barWidth" | ||
9 | + :min="1" | ||
10 | + :max="100" | ||
11 | + size="small" | ||
12 | + placeholder="自动计算" | ||
13 | + ></n-input-number> | ||
14 | + </SettingItem> | ||
15 | + <SettingItem name="圆角"> | ||
16 | + <n-input-number v-model:value="item.itemStyle.borderRadius" :min="0" size="small"></n-input-number> | ||
17 | + </SettingItem> | ||
18 | + </SettingItemBox> | ||
19 | + <SettingItemBox name="动画" :alone="true"> | ||
20 | + <SettingItem> | ||
21 | + <n-space> | ||
22 | + <n-switch v-model:value="optionData.isCarousel" size="small"></n-switch> | ||
23 | + <n-text>开启<n-text :depth="3">(将自动隐藏图例)</n-text></n-text> | ||
24 | + </n-space> | ||
25 | + </SettingItem> | ||
26 | + <SettingItem> | ||
27 | + <n-text :depth="3">无鼠标点击图例场景时,可强行打开图例</n-text> | ||
28 | + </SettingItem> | ||
29 | + </SettingItemBox> | ||
30 | + <setting-item-box name="标签"> | ||
31 | + <setting-item> | ||
32 | + <n-space> | ||
33 | + <n-switch v-model:value="item.label.show" size="small" /> | ||
34 | + <n-text>展示标签</n-text> | ||
35 | + </n-space> | ||
36 | + </setting-item> | ||
37 | + <setting-item name="大小"> | ||
38 | + <n-input-number v-model:value="item.label.fontSize" size="small" :min="1"></n-input-number> | ||
39 | + </setting-item> | ||
40 | + <setting-item name="颜色"> | ||
41 | + <n-color-picker size="small" :modes="['hex']" v-model:value="item.label.color"></n-color-picker> | ||
42 | + </setting-item> | ||
43 | + <setting-item name="位置"> | ||
44 | + <n-select | ||
45 | + v-model:value="item.label.position" | ||
46 | + :options="[ | ||
47 | + { label: 'top', value: 'top' }, | ||
48 | + { label: 'left', value: 'left' }, | ||
49 | + { label: 'right', value: 'right' }, | ||
50 | + { label: 'bottom', value: 'bottom' } | ||
51 | + ]" | ||
52 | + /> | ||
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 { GlobalSetting, CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' | ||
61 | +import { GlobalThemeJsonType } from '@/settings/chartThemes/index' | ||
62 | + | ||
63 | +const props = defineProps({ | ||
64 | + optionData: { | ||
65 | + type: Object as PropType<GlobalThemeJsonType>, | ||
66 | + required: true | ||
67 | + } | ||
68 | +}) | ||
69 | + | ||
70 | +const seriesList = computed(() => { | ||
71 | + return props.optionData.series | ||
72 | +}) | ||
73 | +</script> |
1 | +{ | ||
2 | + "dimensions": ["product", "data1", "data2"], | ||
3 | + "source": [ | ||
4 | + { | ||
5 | + "product": "Mon", | ||
6 | + "data1": 120, | ||
7 | + "data2": 130 | ||
8 | + }, | ||
9 | + { | ||
10 | + "product": "Tue", | ||
11 | + "data1": 200, | ||
12 | + "data2": 130 | ||
13 | + }, | ||
14 | + { | ||
15 | + "product": "Wed", | ||
16 | + "data1": 150, | ||
17 | + "data2": 312 | ||
18 | + }, | ||
19 | + { | ||
20 | + "product": "Thu", | ||
21 | + "data1": 80, | ||
22 | + "data2": 268 | ||
23 | + }, | ||
24 | + { | ||
25 | + "product": "Fri", | ||
26 | + "data1": 70, | ||
27 | + "data2": 155 | ||
28 | + }, | ||
29 | + { | ||
30 | + "product": "Sat", | ||
31 | + "data1": 110, | ||
32 | + "data2": 117 | ||
33 | + }, | ||
34 | + { | ||
35 | + "product": "Sun", | ||
36 | + "data1": 130, | ||
37 | + "data2": 160 | ||
38 | + } | ||
39 | + ] | ||
40 | +} |
1 | +import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d' | ||
2 | +import { ChatCategoryEnum, ChatCategoryEnumName } from '@/packages/components/Charts/index.d' | ||
3 | +import { useWidgetKey } from '@/packages/external/useWidgetKey' | ||
4 | + | ||
5 | +const { key, conKey, chartKey } = useWidgetKey('OverrideBarCommon', true) | ||
6 | + | ||
7 | +export const OverrideBarCommonConfig: ConfigType = { | ||
8 | + key, | ||
9 | + chartKey, | ||
10 | + conKey, | ||
11 | + title: '柱状图动画', | ||
12 | + category: ChatCategoryEnum.BAR, | ||
13 | + categoryName: ChatCategoryEnumName.BAR, | ||
14 | + package: PackagesCategoryEnum.CHARTS, | ||
15 | + chartFrame: ChartFrameEnum.ECHARTS, | ||
16 | + image: 'bar_x.png' | ||
17 | +} |
1 | +<template> | ||
2 | + <v-chart | ||
3 | + ref="vChartRef" | ||
4 | + :init-options="initOptions" | ||
5 | + :theme="themeColor" | ||
6 | + :option="option" | ||
7 | + :manual-update="isPreview()" | ||
8 | + :update-options="{ | ||
9 | + replaceMerge: replaceMergeArr | ||
10 | + }" | ||
11 | + autoresize | ||
12 | + @mouseover="handleHighlight" | ||
13 | + @mouseout="handleDownplay" | ||
14 | + > | ||
15 | + </v-chart> | ||
16 | +</template> | ||
17 | + | ||
18 | +<script setup lang="ts"> | ||
19 | +import { ref, nextTick, computed, watch, PropType, onMounted } from 'vue' | ||
20 | +import VChart from 'vue-echarts' | ||
21 | +import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook' | ||
22 | +import { use } from 'echarts/core' | ||
23 | +import { CanvasRenderer } from 'echarts/renderers' | ||
24 | +import { BarChart } from 'echarts/charts' | ||
25 | +import config, { includes, seriesItem } from './config' | ||
26 | +import { mergeTheme } from '@/packages/public/chart' | ||
27 | +import { useChartDataFetch } from '@/hooks' | ||
28 | +import { CreateComponentType } from '@/packages/index.d' | ||
29 | +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' | ||
30 | +import { isPreview } from '@/utils' | ||
31 | +import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components' | ||
32 | +import isObject from 'lodash/isObject' | ||
33 | +import dataJson from './data.json' | ||
34 | +import { isFullScreen } from '../../utls/isFullScreen' | ||
35 | + | ||
36 | +const props = defineProps({ | ||
37 | + themeSetting: { | ||
38 | + type: Object, | ||
39 | + required: true | ||
40 | + }, | ||
41 | + themeColor: { | ||
42 | + type: Object, | ||
43 | + required: true | ||
44 | + }, | ||
45 | + chartConfig: { | ||
46 | + type: Object as PropType<config>, | ||
47 | + required: true | ||
48 | + } | ||
49 | +}) | ||
50 | + | ||
51 | +const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting) | ||
52 | + | ||
53 | +use([DatasetComponent, CanvasRenderer, BarChart, GridComponent, TooltipComponent, LegendComponent]) | ||
54 | + | ||
55 | +const replaceMergeArr = ref<string[]>() | ||
56 | + | ||
57 | +const option = computed(() => { | ||
58 | + return mergeTheme(props.chartConfig.option, props.themeSetting, includes) | ||
59 | +}) | ||
60 | + | ||
61 | +const toolBoxOption = { | ||
62 | + show: true, | ||
63 | + right: 20, | ||
64 | + feature: { | ||
65 | + myFullButton: { | ||
66 | + show: true, | ||
67 | + title: '全屏查看', | ||
68 | + icon: 'path://M733.549304 0l116.434359 116.23452-226.402521 226.40252 57.053835 57.068109 226.459617-226.445342 120.616689 120.41685V0H733.549304zM689.513507 619.855586l-57.068108 57.068109 224.232847 224.232847-122.64362 122.843458h293.676657V729.838022l-114.007751 114.207588-224.190025-224.190024zM338.197775 404.144414l57.068109-57.068109L171.033037 122.843458 293.676657 0H0v294.161978l114.022025-114.207588 224.17575 224.190024zM347.076305 624.294851L120.616689 850.754468 0 730.323343v293.676657h294.161978l-116.420084-116.23452 226.40252-226.40252-57.068109-57.068109z', | ||
69 | + onclick: () => { | ||
70 | + const getEchartDom = vChartRef.value?.getDom() | ||
71 | + const domName = document.getElementById(getEchartDom.id) as any | ||
72 | + const htmlName = document.querySelector('html') as any | ||
73 | + isFullScreen(domName, htmlName) | ||
74 | + } | ||
75 | + } | ||
76 | + } | ||
77 | +} | ||
78 | +props.chartConfig.option = { | ||
79 | + ...props.chartConfig.option, | ||
80 | + ...{ toolbox: toolBoxOption } | ||
81 | +} | ||
82 | + | ||
83 | +// dataset 无法变更条数的补丁 | ||
84 | +watch( | ||
85 | + () => props.chartConfig.option.dataset, | ||
86 | + (newData: { dimensions: any }, oldData) => { | ||
87 | + try { | ||
88 | + if (!isObject(newData) || !('dimensions' in newData)) return | ||
89 | + if (Array.isArray(newData?.dimensions)) { | ||
90 | + const seriesArr = [] | ||
91 | + for (let i = 0; i < newData.dimensions.length - 1; i++) { | ||
92 | + seriesArr.push(seriesItem) | ||
93 | + } | ||
94 | + replaceMergeArr.value = ['series'] | ||
95 | + props.chartConfig.option.series = seriesArr | ||
96 | + nextTick(() => { | ||
97 | + replaceMergeArr.value = [] | ||
98 | + }) | ||
99 | + } | ||
100 | + } catch (error) { | ||
101 | + console.log(error) | ||
102 | + } | ||
103 | + }, | ||
104 | + { | ||
105 | + deep: false | ||
106 | + } | ||
107 | +) | ||
108 | + | ||
109 | +let seriesDataNum = -1 | ||
110 | +let seriesDataMaxLength = 0 | ||
111 | +let intervalInstance: any = null | ||
112 | +//轮播时长 | ||
113 | +const duration = 1500 | ||
114 | + | ||
115 | +// 会重新选择需要选中和展示的数据 | ||
116 | +const handleSeriesData = () => { | ||
117 | + if (seriesDataNum > -1) { | ||
118 | + vChartRef.value?.dispatchAction({ | ||
119 | + type: 'downplay', | ||
120 | + dataIndex: seriesDataNum | ||
121 | + }) | ||
122 | + } | ||
123 | + seriesDataNum = seriesDataNum >= seriesDataMaxLength - 1 ? 0 : seriesDataNum + 1 | ||
124 | + vChartRef.value?.dispatchAction({ | ||
125 | + type: 'showTip', | ||
126 | + seriesIndex: 0, | ||
127 | + dataIndex: seriesDataNum | ||
128 | + }) | ||
129 | +} | ||
130 | + | ||
131 | +// 新增轮播 | ||
132 | +const addPieInterval = (newData?: typeof dataJson, skipPre = false) => { | ||
133 | + if (!skipPre && !Array.isArray(newData?.source)) return | ||
134 | + if (!skipPre) seriesDataMaxLength = newData?.source.length || 0 | ||
135 | + clearInterval(intervalInstance) | ||
136 | + intervalInstance = setInterval(() => { | ||
137 | + handleSeriesData() | ||
138 | + }, duration) | ||
139 | +} | ||
140 | + | ||
141 | +// 取消轮播 | ||
142 | +const clearPieInterval = () => { | ||
143 | + vChartRef.value?.dispatchAction({ | ||
144 | + type: 'hideTip', | ||
145 | + seriesIndex: 0, | ||
146 | + dataIndex: seriesDataNum | ||
147 | + }) | ||
148 | + vChartRef.value?.dispatchAction({ | ||
149 | + type: 'downplay', | ||
150 | + dataIndex: seriesDataNum | ||
151 | + }) | ||
152 | + clearInterval(intervalInstance) | ||
153 | + intervalInstance = null | ||
154 | +} | ||
155 | + | ||
156 | +// 处理鼠标聚焦高亮内容 | ||
157 | +const handleHighlight = () => { | ||
158 | + clearPieInterval() | ||
159 | +} | ||
160 | + | ||
161 | +// 处理鼠标取消悬浮 | ||
162 | +const handleDownplay = () => { | ||
163 | + if (props.chartConfig.option.isCarousel && !intervalInstance) { | ||
164 | + // 恢复轮播 | ||
165 | + addPieInterval(undefined, true) | ||
166 | + } | ||
167 | +} | ||
168 | + | ||
169 | +watch( | ||
170 | + () => props.chartConfig.option.isCarousel, | ||
171 | + newData => { | ||
172 | + if (newData) { | ||
173 | + addPieInterval(undefined, true) | ||
174 | + props.chartConfig.option.legend.show = false | ||
175 | + } else { | ||
176 | + props.chartConfig.option.legend.show = true | ||
177 | + clearPieInterval() | ||
178 | + } | ||
179 | + } | ||
180 | +) | ||
181 | + | ||
182 | +const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore, (newData: typeof dataJson) => { | ||
183 | + // addPieInterval(newData) | ||
184 | +}) | ||
185 | + | ||
186 | +onMounted(() => { | ||
187 | + seriesDataMaxLength = dataJson.source.length | ||
188 | + if (props.chartConfig.option.isCarousel) { | ||
189 | + addPieInterval(undefined, true) | ||
190 | + } | ||
191 | +}) | ||
192 | +</script> |
1 | +import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public' | ||
2 | +import { OverrideLineCommonConfig } from './index' | ||
3 | +import { CreateComponentType } from '@/packages/index.d' | ||
4 | +import cloneDeep from 'lodash/cloneDeep' | ||
5 | +import dataJson from './data.json' | ||
6 | + | ||
7 | +export const includes = ['legend', 'xAxis', 'yAxis', 'grid'] | ||
8 | +export const seriesItem = { | ||
9 | + type: 'line', | ||
10 | + label: { | ||
11 | + show: true, | ||
12 | + position: 'top', | ||
13 | + color: '#fff', | ||
14 | + fontSize: 12 | ||
15 | + }, | ||
16 | + symbolSize: 5, //设定实心点的大小 | ||
17 | + itemStyle: { | ||
18 | + color: null, | ||
19 | + borderRadius: 0 | ||
20 | + }, | ||
21 | + lineStyle: { | ||
22 | + type: 'solid', | ||
23 | + width: 3, | ||
24 | + color: null | ||
25 | + } | ||
26 | +} | ||
27 | +// 其它配置项比如新增(动画) | ||
28 | +const otherConfig = { | ||
29 | + // 轮播动画 | ||
30 | + isCarousel: false, | ||
31 | +} | ||
32 | +export const option = { | ||
33 | + ...otherConfig, | ||
34 | + tooltip: { | ||
35 | + show: true, | ||
36 | + trigger: 'axis', | ||
37 | + axisPointer: { | ||
38 | + type: 'line' | ||
39 | + } | ||
40 | + }, | ||
41 | + xAxis: { | ||
42 | + show: true, | ||
43 | + type: 'category' | ||
44 | + }, | ||
45 | + yAxis: { | ||
46 | + show: true, | ||
47 | + type: 'value' | ||
48 | + }, | ||
49 | + dataset: { ...dataJson }, | ||
50 | + series: [seriesItem, seriesItem] | ||
51 | +} | ||
52 | + | ||
53 | +export default class Config extends PublicConfigClass implements CreateComponentType { | ||
54 | + public key: string = OverrideLineCommonConfig.key | ||
55 | + public chartConfig = cloneDeep(OverrideLineCommonConfig) | ||
56 | + // 图表配置项 | ||
57 | + public option = echartOptionProfixHandle(option, includes) | ||
58 | +} |
1 | +<template> | ||
2 | + <!-- Echarts 全局设置 --> | ||
3 | + <global-setting :optionData="optionData"></global-setting> | ||
4 | + <CollapseItem v-for="(item, index) in seriesList" :key="index" :name="`折线图-${index + 1}`" :expanded="true"> | ||
5 | + <SettingItemBox name="线条"> | ||
6 | + <SettingItem name="宽度"> | ||
7 | + <n-input-number | ||
8 | + v-model:value="item.lineStyle.width" | ||
9 | + :min="1" | ||
10 | + :max="100" | ||
11 | + size="small" | ||
12 | + placeholder="自动计算" | ||
13 | + ></n-input-number> | ||
14 | + </SettingItem> | ||
15 | + <SettingItem name="类型"> | ||
16 | + <n-select v-model:value="item.lineStyle.type" size="small" :options="lineConf.lineStyle.type"></n-select> | ||
17 | + </SettingItem> | ||
18 | + </SettingItemBox> | ||
19 | + <SettingItemBox name="动画" :alone="true"> | ||
20 | + <SettingItem> | ||
21 | + <n-space> | ||
22 | + <n-switch v-model:value="optionData.isCarousel" size="small"></n-switch> | ||
23 | + <n-text>开启<n-text :depth="3">(将自动隐藏图例)</n-text></n-text> | ||
24 | + </n-space> | ||
25 | + </SettingItem> | ||
26 | + <SettingItem> | ||
27 | + <n-text :depth="3">无鼠标点击图例场景时,可强行打开图例</n-text> | ||
28 | + </SettingItem> | ||
29 | + </SettingItemBox> | ||
30 | + <SettingItemBox name="实心点"> | ||
31 | + <SettingItem name="大小"> | ||
32 | + <n-input-number | ||
33 | + v-model:value="item.symbolSize" | ||
34 | + :min="1" | ||
35 | + :max="100" | ||
36 | + size="small" | ||
37 | + placeholder="自动计算" | ||
38 | + ></n-input-number> | ||
39 | + </SettingItem> | ||
40 | + </SettingItemBox> | ||
41 | + <setting-item-box name="标签"> | ||
42 | + <setting-item> | ||
43 | + <n-space> | ||
44 | + <n-switch v-model:value="item.label.show" size="small" /> | ||
45 | + <n-text>展示标签</n-text> | ||
46 | + </n-space> | ||
47 | + </setting-item> | ||
48 | + <setting-item name="大小"> | ||
49 | + <n-input-number v-model:value="item.label.fontSize" size="small" :min="1"></n-input-number> | ||
50 | + </setting-item> | ||
51 | + <setting-item name="颜色"> | ||
52 | + <n-color-picker size="small" :modes="['hex']" v-model:value="item.label.color"></n-color-picker> | ||
53 | + </setting-item> | ||
54 | + <setting-item name="位置"> | ||
55 | + <n-select | ||
56 | + v-model:value="item.label.position" | ||
57 | + :options="[ | ||
58 | + { label: 'top', value: 'top' }, | ||
59 | + { label: 'left', value: 'left' }, | ||
60 | + { label: 'right', value: 'right' }, | ||
61 | + { label: 'bottom', value: 'bottom' } | ||
62 | + ]" | ||
63 | + /> | ||
64 | + </setting-item> | ||
65 | + </setting-item-box> | ||
66 | + </CollapseItem> | ||
67 | +</template> | ||
68 | + | ||
69 | +<script setup lang="ts"> | ||
70 | +import { PropType, computed } from 'vue' | ||
71 | +import { lineConf } from '@/packages/chartConfiguration/echarts/index' | ||
72 | +import { GlobalThemeJsonType } from '@/settings/chartThemes/index' | ||
73 | +import { GlobalSetting, CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' | ||
74 | + | ||
75 | +const props = defineProps({ | ||
76 | + optionData: { | ||
77 | + type: Object as PropType<GlobalThemeJsonType>, | ||
78 | + required: true | ||
79 | + } | ||
80 | +}) | ||
81 | + | ||
82 | +const seriesList = computed(() => { | ||
83 | + return props.optionData.series | ||
84 | +}) | ||
85 | +</script> |
1 | +{ | ||
2 | + "dimensions": ["product", "data1", "data2"], | ||
3 | + "source": [ | ||
4 | + { | ||
5 | + "product": "Mon", | ||
6 | + "data1": 120, | ||
7 | + "data2": 130 | ||
8 | + }, | ||
9 | + { | ||
10 | + "product": "Tue", | ||
11 | + "data1": 200, | ||
12 | + "data2": 130 | ||
13 | + }, | ||
14 | + { | ||
15 | + "product": "Wed", | ||
16 | + "data1": 150, | ||
17 | + "data2": 312 | ||
18 | + }, | ||
19 | + { | ||
20 | + "product": "Thu", | ||
21 | + "data1": 80, | ||
22 | + "data2": 268 | ||
23 | + }, | ||
24 | + { | ||
25 | + "product": "Fri", | ||
26 | + "data1": 70, | ||
27 | + "data2": 155 | ||
28 | + }, | ||
29 | + { | ||
30 | + "product": "Sat", | ||
31 | + "data1": 110, | ||
32 | + "data2": 117 | ||
33 | + }, | ||
34 | + { | ||
35 | + "product": "Sun", | ||
36 | + "data1": 130, | ||
37 | + "data2": 160 | ||
38 | + } | ||
39 | + ] | ||
40 | +} |
1 | +import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d' | ||
2 | +import { ChatCategoryEnum, ChatCategoryEnumName } from '@/packages/components/Charts/index.d' | ||
3 | +import { useWidgetKey } from '@/packages/external/useWidgetKey' | ||
4 | + | ||
5 | +const { key, conKey, chartKey } = useWidgetKey('OverrideLineCommon', true) | ||
6 | + | ||
7 | +export const OverrideLineCommonConfig: ConfigType = { | ||
8 | + key, | ||
9 | + chartKey, | ||
10 | + conKey, | ||
11 | + title: '折线图动画', | ||
12 | + category: ChatCategoryEnum.LINE, | ||
13 | + categoryName: ChatCategoryEnumName.LINE, | ||
14 | + package: PackagesCategoryEnum.CHARTS, | ||
15 | + chartFrame: ChartFrameEnum.ECHARTS, | ||
16 | + image: 'line.png' | ||
17 | +} |
1 | +<template> | ||
2 | + <v-chart | ||
3 | + ref="vChartRef" | ||
4 | + :init-options="initOptions" | ||
5 | + :theme="themeColor" | ||
6 | + :option="option" | ||
7 | + :manual-update="isPreview()" | ||
8 | + :update-options="{ | ||
9 | + replaceMerge: replaceMergeArr | ||
10 | + }" | ||
11 | + autoresize | ||
12 | + @mouseover="handleHighlight" | ||
13 | + @mouseout="handleDownplay" | ||
14 | + > | ||
15 | + </v-chart> | ||
16 | +</template> | ||
17 | + | ||
18 | +<script setup lang="ts"> | ||
19 | +import { PropType, computed, watch, ref, nextTick, onMounted } from 'vue' | ||
20 | +import VChart from 'vue-echarts' | ||
21 | +import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook' | ||
22 | +import { use } from 'echarts/core' | ||
23 | +import { CanvasRenderer } from 'echarts/renderers' | ||
24 | +import { LineChart } from 'echarts/charts' | ||
25 | +import config, { includes, seriesItem } from './config' | ||
26 | +import { mergeTheme } from '@/packages/public/chart' | ||
27 | +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' | ||
28 | +import { useChartDataFetch } from '@/hooks' | ||
29 | +import { isPreview } from '@/utils' | ||
30 | +import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components' | ||
31 | +import isObject from 'lodash/isObject' | ||
32 | +import dataJson from './data.json' | ||
33 | +import { isFullScreen } from '../../utls/isFullScreen' | ||
34 | + | ||
35 | +const props = defineProps({ | ||
36 | + themeSetting: { | ||
37 | + type: Object, | ||
38 | + required: true | ||
39 | + }, | ||
40 | + themeColor: { | ||
41 | + type: Object, | ||
42 | + required: true | ||
43 | + }, | ||
44 | + chartConfig: { | ||
45 | + type: Object as PropType<config>, | ||
46 | + required: true | ||
47 | + } | ||
48 | +}) | ||
49 | + | ||
50 | +const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting) | ||
51 | + | ||
52 | +use([DatasetComponent, CanvasRenderer, LineChart, GridComponent, TooltipComponent, LegendComponent]) | ||
53 | + | ||
54 | +const replaceMergeArr = ref<string[]>() | ||
55 | + | ||
56 | +const option = computed(() => { | ||
57 | + return mergeTheme(props.chartConfig.option, props.themeSetting, includes) | ||
58 | +}) | ||
59 | + | ||
60 | +const toolBoxOption = { | ||
61 | + show: true, | ||
62 | + right: 20, | ||
63 | + feature: { | ||
64 | + myFullButton: { | ||
65 | + show: true, | ||
66 | + title: '全屏查看', | ||
67 | + icon: 'path://M733.549304 0l116.434359 116.23452-226.402521 226.40252 57.053835 57.068109 226.459617-226.445342 120.616689 120.41685V0H733.549304zM689.513507 619.855586l-57.068108 57.068109 224.232847 224.232847-122.64362 122.843458h293.676657V729.838022l-114.007751 114.207588-224.190025-224.190024zM338.197775 404.144414l57.068109-57.068109L171.033037 122.843458 293.676657 0H0v294.161978l114.022025-114.207588 224.17575 224.190024zM347.076305 624.294851L120.616689 850.754468 0 730.323343v293.676657h294.161978l-116.420084-116.23452 226.40252-226.40252-57.068109-57.068109z', | ||
68 | + onclick: () => { | ||
69 | + const getEchartDom = vChartRef.value?.getDom() | ||
70 | + const domName = document.getElementById(getEchartDom.id) as any | ||
71 | + const htmlName = document.querySelector('html') as any | ||
72 | + isFullScreen(domName, htmlName) | ||
73 | + } | ||
74 | + } | ||
75 | + } | ||
76 | +} | ||
77 | +props.chartConfig.option = { | ||
78 | + ...props.chartConfig.option, | ||
79 | + ...{ toolbox: toolBoxOption } | ||
80 | +} | ||
81 | + | ||
82 | +// dataset 无法变更条数的补丁 | ||
83 | +watch( | ||
84 | + () => props.chartConfig.option.dataset, | ||
85 | + (newData: { dimensions: any }, oldData) => { | ||
86 | + try { | ||
87 | + if (!isObject(newData) || !('dimensions' in newData)) return | ||
88 | + if (Array.isArray(newData?.dimensions)) { | ||
89 | + const seriesArr = [] | ||
90 | + for (let i = 0; i < newData.dimensions.length - 1; i++) { | ||
91 | + seriesArr.push(seriesItem) | ||
92 | + } | ||
93 | + replaceMergeArr.value = ['series'] | ||
94 | + props.chartConfig.option.series = seriesArr | ||
95 | + nextTick(() => { | ||
96 | + replaceMergeArr.value = [] | ||
97 | + }) | ||
98 | + } | ||
99 | + } catch (error) { | ||
100 | + console.log(error) | ||
101 | + } | ||
102 | + }, | ||
103 | + { | ||
104 | + deep: false | ||
105 | + } | ||
106 | +) | ||
107 | + | ||
108 | +let seriesDataNum = -1 | ||
109 | +let seriesDataMaxLength = 0 | ||
110 | +let intervalInstance: any = null | ||
111 | +const duration = 1500 | ||
112 | + | ||
113 | +// 会重新选择需要选中和展示的数据 | ||
114 | +const handleSeriesData = () => { | ||
115 | + if (seriesDataNum > -1) { | ||
116 | + vChartRef.value?.dispatchAction({ | ||
117 | + type: 'downplay', | ||
118 | + dataIndex: seriesDataNum | ||
119 | + }) | ||
120 | + } | ||
121 | + seriesDataNum = seriesDataNum >= seriesDataMaxLength - 1 ? 0 : seriesDataNum + 1 | ||
122 | + vChartRef.value?.dispatchAction({ | ||
123 | + type: 'showTip', | ||
124 | + seriesIndex: 0, | ||
125 | + dataIndex: seriesDataNum | ||
126 | + }) | ||
127 | +} | ||
128 | + | ||
129 | +// 新增轮播 | ||
130 | +const addPieInterval = (newData?: typeof dataJson, skipPre = false) => { | ||
131 | + if (!skipPre && !Array.isArray(newData?.source)) return | ||
132 | + if (!skipPre) seriesDataMaxLength = newData?.source.length || 0 | ||
133 | + clearInterval(intervalInstance) | ||
134 | + intervalInstance = setInterval(() => { | ||
135 | + handleSeriesData() | ||
136 | + }, duration) | ||
137 | +} | ||
138 | + | ||
139 | +// 取消轮播 | ||
140 | +const clearPieInterval = () => { | ||
141 | + vChartRef.value?.dispatchAction({ | ||
142 | + type: 'hideTip', | ||
143 | + seriesIndex: 0, | ||
144 | + dataIndex: seriesDataNum | ||
145 | + }) | ||
146 | + vChartRef.value?.dispatchAction({ | ||
147 | + type: 'downplay', | ||
148 | + dataIndex: seriesDataNum | ||
149 | + }) | ||
150 | + clearInterval(intervalInstance) | ||
151 | + intervalInstance = null | ||
152 | +} | ||
153 | + | ||
154 | +// 处理鼠标聚焦高亮内容 | ||
155 | +const handleHighlight = () => { | ||
156 | + clearPieInterval() | ||
157 | +} | ||
158 | + | ||
159 | +// 处理鼠标取消悬浮 | ||
160 | +const handleDownplay = () => { | ||
161 | + if (props.chartConfig.option.isCarousel && !intervalInstance) { | ||
162 | + // 恢复轮播 | ||
163 | + addPieInterval(undefined, true) | ||
164 | + } | ||
165 | +} | ||
166 | + | ||
167 | +watch( | ||
168 | + () => props.chartConfig.option.isCarousel, | ||
169 | + newData => { | ||
170 | + if (newData) { | ||
171 | + addPieInterval(undefined, true) | ||
172 | + props.chartConfig.option.legend.show = false | ||
173 | + } else { | ||
174 | + props.chartConfig.option.legend.show = true | ||
175 | + clearPieInterval() | ||
176 | + } | ||
177 | + } | ||
178 | +) | ||
179 | + | ||
180 | +const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore, (newData: typeof dataJson) => { | ||
181 | + // addPieInterval(newData) | ||
182 | +}) | ||
183 | + | ||
184 | +onMounted(() => { | ||
185 | + seriesDataMaxLength = dataJson.source.length | ||
186 | + if (props.chartConfig.option.isCarousel) { | ||
187 | + addPieInterval(undefined, true) | ||
188 | + } | ||
189 | +}) | ||
190 | +</script> |
1 | +import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public' | ||
2 | +import { OverrideLineGradientsConfig } from './index' | ||
3 | +import { CreateComponentType } from '@/packages/index.d' | ||
4 | +import { graphic } from 'echarts/core' | ||
5 | +import { defaultTheme, chartColorsSearch } from '@/settings/chartThemes/index' | ||
6 | +import cloneDeep from 'lodash/cloneDeep' | ||
7 | +import dataJson from './data.json' | ||
8 | + | ||
9 | +export const includes = ['legend', 'xAxis', 'yAxis', 'grid'] | ||
10 | + | ||
11 | +// 其它配置项比如新增(动画) | ||
12 | +const otherConfig = { | ||
13 | + // 轮播动画 | ||
14 | + isCarousel: false, | ||
15 | +} | ||
16 | +const option = { | ||
17 | + ...otherConfig, | ||
18 | + tooltip: { | ||
19 | + show: true, | ||
20 | + trigger: 'axis', | ||
21 | + axisPointer: { | ||
22 | + type: 'line' | ||
23 | + } | ||
24 | + }, | ||
25 | + xAxis: { | ||
26 | + show: true, | ||
27 | + type: 'category' | ||
28 | + }, | ||
29 | + yAxis: { | ||
30 | + show: true, | ||
31 | + type: 'value' | ||
32 | + }, | ||
33 | + dataset: { ...dataJson }, | ||
34 | + series: [ | ||
35 | + { | ||
36 | + type: 'line', | ||
37 | + smooth: false, | ||
38 | + symbolSize: 5, //设定实心点的大小 | ||
39 | + label: { | ||
40 | + show: true, | ||
41 | + position: 'top', | ||
42 | + color: '#fff', | ||
43 | + fontSize: 12 | ||
44 | + }, | ||
45 | + lineStyle: { | ||
46 | + width: 3, | ||
47 | + type: 'solid' | ||
48 | + }, | ||
49 | + areaStyle: { | ||
50 | + opacity: 0.8, | ||
51 | + color: new graphic.LinearGradient(0, 0, 0, 1, [ | ||
52 | + { | ||
53 | + offset: 0, | ||
54 | + color: chartColorsSearch[defaultTheme][3] | ||
55 | + }, | ||
56 | + { | ||
57 | + offset: 1, | ||
58 | + color: 'rgba(0,0,0,0)' | ||
59 | + } | ||
60 | + ]) | ||
61 | + } | ||
62 | + }, | ||
63 | + { | ||
64 | + type: 'line', | ||
65 | + smooth: false, | ||
66 | + label: { | ||
67 | + show: true, | ||
68 | + position: 'top', | ||
69 | + color: '#fff', | ||
70 | + fontSize: 12 | ||
71 | + }, | ||
72 | + lineStyle: { | ||
73 | + width: 3, | ||
74 | + type: 'solid' | ||
75 | + }, | ||
76 | + areaStyle: { | ||
77 | + opacity: 0.8, | ||
78 | + color: new graphic.LinearGradient(0, 0, 0, 1, [ | ||
79 | + { | ||
80 | + offset: 0, | ||
81 | + color: chartColorsSearch[defaultTheme][4] | ||
82 | + }, | ||
83 | + { | ||
84 | + offset: 1, | ||
85 | + color: 'rgba(0,0,0,0)' | ||
86 | + } | ||
87 | + ]) | ||
88 | + } | ||
89 | + } | ||
90 | + ] | ||
91 | +} | ||
92 | + | ||
93 | +export default class Config extends PublicConfigClass implements CreateComponentType { | ||
94 | + public key: string = OverrideLineGradientsConfig.key | ||
95 | + public chartConfig = cloneDeep(OverrideLineGradientsConfig) | ||
96 | + // 图表配置项 | ||
97 | + public option = echartOptionProfixHandle(option, includes) | ||
98 | +} |
1 | +<template> | ||
2 | + <!-- Echarts 全局设置 --> | ||
3 | + <global-setting :optionData="optionData"></global-setting> | ||
4 | + <CollapseItem | ||
5 | + v-for="(item, index) in seriesList" | ||
6 | + :key="index" | ||
7 | + name="单折线面积图" | ||
8 | + :expanded="true" | ||
9 | + > | ||
10 | + <SettingItemBox name="线条"> | ||
11 | + <SettingItem name="宽度"> | ||
12 | + <n-input-number | ||
13 | + v-model:value="item.lineStyle.width" | ||
14 | + :min="1" | ||
15 | + size="small" | ||
16 | + placeholder="自动计算" | ||
17 | + ></n-input-number> | ||
18 | + </SettingItem> | ||
19 | + <SettingItem name="类型"> | ||
20 | + <n-select | ||
21 | + v-model:value="item.lineStyle.type" | ||
22 | + size="small" | ||
23 | + :options="lineConf.lineStyle.type" | ||
24 | + ></n-select> | ||
25 | + </SettingItem> | ||
26 | + </SettingItemBox> | ||
27 | + <SettingItemBox name="动画" :alone="true"> | ||
28 | + <SettingItem> | ||
29 | + <n-space> | ||
30 | + <n-switch v-model:value="optionData.isCarousel" size="small"></n-switch> | ||
31 | + <n-text>开启<n-text :depth="3">(将自动隐藏图例)</n-text></n-text> | ||
32 | + </n-space> | ||
33 | + </SettingItem> | ||
34 | + <SettingItem> | ||
35 | + <n-text :depth="3">无鼠标点击图例场景时,可强行打开图例</n-text> | ||
36 | + </SettingItem> | ||
37 | + </SettingItemBox> | ||
38 | + <SettingItemBox name="实心点"> | ||
39 | + <SettingItem name="大小"> | ||
40 | + <n-input-number | ||
41 | + v-model:value="item.symbolSize" | ||
42 | + :min="1" | ||
43 | + :max="100" | ||
44 | + size="small" | ||
45 | + placeholder="自动计算" | ||
46 | + ></n-input-number> | ||
47 | + </SettingItem> | ||
48 | + </SettingItemBox> | ||
49 | + <setting-item-box name="标签"> | ||
50 | + <setting-item> | ||
51 | + <n-space> | ||
52 | + <n-switch v-model:value="item.label.show" size="small" /> | ||
53 | + <n-text>展示标签</n-text> | ||
54 | + </n-space> | ||
55 | + </setting-item> | ||
56 | + <setting-item name="大小"> | ||
57 | + <n-input-number | ||
58 | + v-model:value="item.label.fontSize" | ||
59 | + size="small" | ||
60 | + :min="1" | ||
61 | + ></n-input-number> | ||
62 | + </setting-item> | ||
63 | + <setting-item name="颜色"> | ||
64 | + <n-color-picker | ||
65 | + size="small" | ||
66 | + :modes="['hex']" | ||
67 | + v-model:value="item.label.color" | ||
68 | + ></n-color-picker> | ||
69 | + </setting-item> | ||
70 | + <setting-item name="位置"> | ||
71 | + <n-select | ||
72 | + v-model:value="item.label.position" | ||
73 | + :options="[ | ||
74 | + { label: 'top', value: 'top' }, | ||
75 | + { label: 'left', value: 'left' }, | ||
76 | + { label: 'right', value: 'right' }, | ||
77 | + { label: 'bottom', value: 'bottom' }, | ||
78 | + ]" | ||
79 | + /> | ||
80 | + </setting-item> | ||
81 | + </setting-item-box> | ||
82 | + </CollapseItem> | ||
83 | +</template> | ||
84 | + | ||
85 | +<script setup lang="ts"> | ||
86 | +import { PropType, computed } from 'vue' | ||
87 | +import { lineConf } from '@/packages/chartConfiguration/echarts/index' | ||
88 | +import { GlobalThemeJsonType } from '@/settings/chartThemes/index' | ||
89 | +import { | ||
90 | + GlobalSetting, | ||
91 | + CollapseItem, | ||
92 | + SettingItemBox, | ||
93 | + SettingItem | ||
94 | +} from '@/components/Pages/ChartItemSetting' | ||
95 | + | ||
96 | +const props = defineProps({ | ||
97 | + optionData: { | ||
98 | + type: Object as PropType<GlobalThemeJsonType>, | ||
99 | + required: true | ||
100 | + }, | ||
101 | +}) | ||
102 | + | ||
103 | +const seriesList = computed(() => { | ||
104 | + return props.optionData.series | ||
105 | +}) | ||
106 | +</script> |
1 | +{ | ||
2 | + "dimensions": ["product", "data1", "data2"], | ||
3 | + "source": [ | ||
4 | + { | ||
5 | + "product": "Mon", | ||
6 | + "data1": 120, | ||
7 | + "data2": 130 | ||
8 | + }, | ||
9 | + { | ||
10 | + "product": "Tue", | ||
11 | + "data1": 200, | ||
12 | + "data2": 130 | ||
13 | + }, | ||
14 | + { | ||
15 | + "product": "Wed", | ||
16 | + "data1": 150, | ||
17 | + "data2": 312 | ||
18 | + }, | ||
19 | + { | ||
20 | + "product": "Thu", | ||
21 | + "data1": 80, | ||
22 | + "data2": 268 | ||
23 | + }, | ||
24 | + { | ||
25 | + "product": "Fri", | ||
26 | + "data1": 70, | ||
27 | + "data2": 155 | ||
28 | + }, | ||
29 | + { | ||
30 | + "product": "Sat", | ||
31 | + "data1": 110, | ||
32 | + "data2": 117 | ||
33 | + }, | ||
34 | + { | ||
35 | + "product": "Sun", | ||
36 | + "data1": 130, | ||
37 | + "data2": 160 | ||
38 | + } | ||
39 | + ] | ||
40 | +} |
1 | +import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d' | ||
2 | +import { ChatCategoryEnum, ChatCategoryEnumName } from '@/packages/components/Charts/index.d' | ||
3 | +import { useWidgetKey } from '@/packages/external/useWidgetKey' | ||
4 | + | ||
5 | +const { key, conKey, chartKey } = useWidgetKey('OverrideLineGradients', true) | ||
6 | + | ||
7 | +export const OverrideLineGradientsConfig: ConfigType = { | ||
8 | + key, | ||
9 | + chartKey, | ||
10 | + conKey, | ||
11 | + title: '双折线渐变面积图动画', | ||
12 | + category: ChatCategoryEnum.LINE, | ||
13 | + categoryName: ChatCategoryEnumName.LINE, | ||
14 | + package: PackagesCategoryEnum.CHARTS, | ||
15 | + chartFrame: ChartFrameEnum.ECHARTS, | ||
16 | + image: 'line_gradient.png' | ||
17 | +} |
1 | +<template> | ||
2 | + <v-chart | ||
3 | + ref="vChartRef" | ||
4 | + :init-options="initOptions" | ||
5 | + :theme="themeColor" | ||
6 | + :option="option.value" | ||
7 | + :manual-update="isPreview()" | ||
8 | + autoresize | ||
9 | + @mouseover="handleHighlight" | ||
10 | + @mouseout="handleDownplay" | ||
11 | + ></v-chart> | ||
12 | +</template> | ||
13 | + | ||
14 | +<script setup lang="ts"> | ||
15 | +import { reactive, watch, PropType, onMounted } from 'vue' | ||
16 | +import VChart from 'vue-echarts' | ||
17 | +import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook' | ||
18 | +import { use, graphic } from 'echarts/core' | ||
19 | +import { CanvasRenderer } from 'echarts/renderers' | ||
20 | +import { LineChart } from 'echarts/charts' | ||
21 | +import config, { includes } from './config' | ||
22 | +import { mergeTheme } from '@/packages/public/chart' | ||
23 | +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' | ||
24 | +import { chartColorsSearch, defaultTheme } from '@/settings/chartThemes/index' | ||
25 | +import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components' | ||
26 | +import { useChartDataFetch } from '@/hooks' | ||
27 | +import { isPreview, colorGradientCustomMerge } from '@/utils' | ||
28 | +import dataJson from './data.json' | ||
29 | +import { isFullScreen } from '../../utls/isFullScreen' | ||
30 | + | ||
31 | +const props = defineProps({ | ||
32 | + themeSetting: { | ||
33 | + type: Object, | ||
34 | + required: true | ||
35 | + }, | ||
36 | + themeColor: { | ||
37 | + type: Object, | ||
38 | + required: true | ||
39 | + }, | ||
40 | + chartConfig: { | ||
41 | + type: Object as PropType<config>, | ||
42 | + required: true | ||
43 | + } | ||
44 | +}) | ||
45 | + | ||
46 | +const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting) | ||
47 | + | ||
48 | +use([DatasetComponent, CanvasRenderer, LineChart, GridComponent, TooltipComponent, LegendComponent]) | ||
49 | +const chartEditStore = useChartEditStore() | ||
50 | + | ||
51 | +const option = reactive({ | ||
52 | + value: {} | ||
53 | +}) | ||
54 | +const toolBoxOption = { | ||
55 | + show: true, | ||
56 | + right: 20, | ||
57 | + feature: { | ||
58 | + myFullButton: { | ||
59 | + show: true, | ||
60 | + title: '全屏查看', | ||
61 | + icon: 'path://M733.549304 0l116.434359 116.23452-226.402521 226.40252 57.053835 57.068109 226.459617-226.445342 120.616689 120.41685V0H733.549304zM689.513507 619.855586l-57.068108 57.068109 224.232847 224.232847-122.64362 122.843458h293.676657V729.838022l-114.007751 114.207588-224.190025-224.190024zM338.197775 404.144414l57.068109-57.068109L171.033037 122.843458 293.676657 0H0v294.161978l114.022025-114.207588 224.17575 224.190024zM347.076305 624.294851L120.616689 850.754468 0 730.323343v293.676657h294.161978l-116.420084-116.23452 226.40252-226.40252-57.068109-57.068109z', | ||
62 | + onclick: () => { | ||
63 | + const getEchartDom = vChartRef.value?.getDom() | ||
64 | + const domName = document.getElementById(getEchartDom.id) as any | ||
65 | + const htmlName = document.querySelector('html') as any | ||
66 | + isFullScreen(domName, htmlName) | ||
67 | + } | ||
68 | + } | ||
69 | + } | ||
70 | +} | ||
71 | +props.chartConfig.option = { | ||
72 | + ...props.chartConfig.option, | ||
73 | + ...{ toolbox: toolBoxOption } | ||
74 | +} | ||
75 | + | ||
76 | +// 渐变色处理 | ||
77 | +watch( | ||
78 | + () => chartEditStore.getEditCanvasConfig.chartThemeColor, | ||
79 | + (newColor: keyof typeof chartColorsSearch) => { | ||
80 | + try { | ||
81 | + if (!isPreview()) { | ||
82 | + const themeColor = | ||
83 | + colorGradientCustomMerge(chartEditStore.getEditCanvasConfig.chartCustomThemeColorInfo)[newColor] || | ||
84 | + colorGradientCustomMerge(chartEditStore.getEditCanvasConfig.chartCustomThemeColorInfo)[defaultTheme] | ||
85 | + props.chartConfig.option.series.forEach((value: any, index: number) => { | ||
86 | + value.areaStyle.color = new graphic.LinearGradient(0, 0, 0, 1, [ | ||
87 | + { | ||
88 | + offset: 0, | ||
89 | + color: themeColor[3 + index] | ||
90 | + }, | ||
91 | + { | ||
92 | + offset: 1, | ||
93 | + color: 'rgba(0,0,0, 0)' | ||
94 | + } | ||
95 | + ]) | ||
96 | + }) | ||
97 | + } | ||
98 | + option.value = mergeTheme(props.chartConfig.option, props.themeSetting, includes) | ||
99 | + props.chartConfig.option = option.value | ||
100 | + } catch (error) { | ||
101 | + console.log(error) | ||
102 | + } | ||
103 | + }, | ||
104 | + { | ||
105 | + immediate: true | ||
106 | + } | ||
107 | +) | ||
108 | + | ||
109 | +watch( | ||
110 | + () => props.chartConfig.option.dataset, | ||
111 | + () => { | ||
112 | + option.value = props.chartConfig.option | ||
113 | + } | ||
114 | +) | ||
115 | +let seriesDataNum = -1 | ||
116 | +let seriesDataMaxLength = 0 | ||
117 | +let intervalInstance: any = null | ||
118 | +const duration = 1500 | ||
119 | + | ||
120 | +// 会重新选择需要选中和展示的数据 | ||
121 | +const handleSeriesData = () => { | ||
122 | + if (seriesDataNum > -1) { | ||
123 | + vChartRef.value?.dispatchAction({ | ||
124 | + type: 'downplay', | ||
125 | + dataIndex: seriesDataNum | ||
126 | + }) | ||
127 | + } | ||
128 | + seriesDataNum = seriesDataNum >= seriesDataMaxLength - 1 ? 0 : seriesDataNum + 1 | ||
129 | + vChartRef.value?.dispatchAction({ | ||
130 | + type: 'showTip', | ||
131 | + seriesIndex: 0, | ||
132 | + dataIndex: seriesDataNum | ||
133 | + }) | ||
134 | +} | ||
135 | + | ||
136 | +// 新增轮播 | ||
137 | +const addPieInterval = (newData?: typeof dataJson, skipPre = false) => { | ||
138 | + if (!skipPre && !Array.isArray(newData?.source)) return | ||
139 | + if (!skipPre) seriesDataMaxLength = newData?.source.length || 0 | ||
140 | + clearInterval(intervalInstance) | ||
141 | + intervalInstance = setInterval(() => { | ||
142 | + handleSeriesData() | ||
143 | + }, duration) | ||
144 | +} | ||
145 | + | ||
146 | +// 取消轮播 | ||
147 | +const clearPieInterval = () => { | ||
148 | + vChartRef.value?.dispatchAction({ | ||
149 | + type: 'hideTip', | ||
150 | + seriesIndex: 0, | ||
151 | + dataIndex: seriesDataNum | ||
152 | + }) | ||
153 | + vChartRef.value?.dispatchAction({ | ||
154 | + type: 'downplay', | ||
155 | + dataIndex: seriesDataNum | ||
156 | + }) | ||
157 | + clearInterval(intervalInstance) | ||
158 | + intervalInstance = null | ||
159 | +} | ||
160 | + | ||
161 | +// 处理鼠标聚焦高亮内容 | ||
162 | +const handleHighlight = () => { | ||
163 | + clearPieInterval() | ||
164 | +} | ||
165 | + | ||
166 | +// 处理鼠标取消悬浮 | ||
167 | +const handleDownplay = () => { | ||
168 | + if (props.chartConfig.option.isCarousel && !intervalInstance) { | ||
169 | + // 恢复轮播 | ||
170 | + addPieInterval(undefined, true) | ||
171 | + } | ||
172 | +} | ||
173 | + | ||
174 | +watch( | ||
175 | + () => props.chartConfig.option.isCarousel, | ||
176 | + newData => { | ||
177 | + if (newData) { | ||
178 | + addPieInterval(undefined, true) | ||
179 | + props.chartConfig.option.legend.show = false | ||
180 | + } else { | ||
181 | + props.chartConfig.option.legend.show = true | ||
182 | + clearPieInterval() | ||
183 | + } | ||
184 | + } | ||
185 | +) | ||
186 | + | ||
187 | +const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore, (newData: typeof dataJson) => { | ||
188 | + // addPieInterval(newData) | ||
189 | +}) | ||
190 | + | ||
191 | +onMounted(() => { | ||
192 | + seriesDataMaxLength = dataJson.source.length | ||
193 | + if (props.chartConfig.option.isCarousel) { | ||
194 | + addPieInterval(undefined, true) | ||
195 | + } | ||
196 | +}) | ||
197 | +</script> |
1 | +export const isFullScreen = (domName: any, htmlName: any) => { | ||
2 | + const isFullScreen = document.fullscreenElement | ||
3 | + const currentDatkTheme = htmlName.getAttribute('data-theme') | ||
4 | + | ||
5 | + if (isFullScreen) { | ||
6 | + console.log('退出全屏') | ||
7 | + if (document.exitFullscreen) { | ||
8 | + document.exitFullscreen() | ||
9 | + domName.style.background = '' | ||
10 | + } | ||
11 | + } else { | ||
12 | + console.log('进入全屏') | ||
13 | + if (domName.requestFullscreen) { | ||
14 | + domName.requestFullscreen() | ||
15 | + domName.style.background = currentDatkTheme === 'light' ? 'white' : '#18181c' | ||
16 | + } else if (domName.mozRequestFullScreen) { | ||
17 | + domName.mozRequestFullScreen() | ||
18 | + domName.style.background = currentDatkTheme === 'light' ? 'white' : '#18181c' | ||
19 | + } else if (domName.webkitRequestFullscreen) { | ||
20 | + domName.webkitRequestFullscreen() | ||
21 | + domName.style.background = currentDatkTheme === 'light' ? 'white' : '#18181c' | ||
22 | + } else if (domName.msRequestFullscreen) { | ||
23 | + domName.msRequestFullscreen() | ||
24 | + domName.style.background = currentDatkTheme === 'light' ? 'white' : '#18181c' | ||
25 | + } | ||
26 | + } | ||
27 | +} |
@@ -13,11 +13,6 @@ | @@ -13,11 +13,6 @@ | ||
13 | </n-button> | 13 | </n-button> |
14 | </setting-item> | 14 | </setting-item> |
15 | </setting-item-box> | 15 | </setting-item-box> |
16 | - <setting-item-box name="排布"> | ||
17 | - <setting-item> | ||
18 | - <n-select v-model:value="optionData.displayMode" size="small" :options="displayModeOptions"></n-select> | ||
19 | - </setting-item> | ||
20 | - </setting-item-box> | ||
21 | </CollapseItem> | 16 | </CollapseItem> |
22 | </template> | 17 | </template> |
23 | 18 | ||
@@ -32,20 +27,4 @@ defineProps({ | @@ -32,20 +27,4 @@ defineProps({ | ||
32 | required: true | 27 | required: true |
33 | } | 28 | } |
34 | }) | 29 | }) |
35 | - | ||
36 | -// 旋转方式 | ||
37 | -const displayModeOptions = [ | ||
38 | - { | ||
39 | - value: 'singleGrid', | ||
40 | - label: '默认' | ||
41 | - }, | ||
42 | - { | ||
43 | - value: 'fourGrid', | ||
44 | - label: '四宫格' | ||
45 | - }, | ||
46 | - { | ||
47 | - value: 'nineGrid', | ||
48 | - label: '九宫格' | ||
49 | - } | ||
50 | -] | ||
51 | </script> | 30 | </script> |
@@ -8,7 +8,7 @@ export const CameraConfig: ConfigType = { | @@ -8,7 +8,7 @@ export const CameraConfig: ConfigType = { | ||
8 | key, | 8 | key, |
9 | chartKey, | 9 | chartKey, |
10 | conKey, | 10 | conKey, |
11 | - title: '摄像头', | 11 | + title: '多个摄像头', |
12 | category: ChatCategoryEnum.MORE, | 12 | category: ChatCategoryEnum.MORE, |
13 | categoryName: ChatCategoryEnumName.MORE, | 13 | categoryName: ChatCategoryEnumName.MORE, |
14 | package: EPackagesCategoryEnum.COMPOSES, | 14 | package: EPackagesCategoryEnum.COMPOSES, |
1 | +<template> | ||
2 | + <video | ||
3 | + crossOrigin="anonymous" | ||
4 | + :id="`my-player${index}`" | ||
5 | + ref="videoRef" | ||
6 | + class="video-js my-video vjs-theme-city vjs-big-play-centered" | ||
7 | + > | ||
8 | + <source :src="sourceSrc" /> | ||
9 | + </video> | ||
10 | +</template> | ||
11 | +<script setup lang="ts"> | ||
12 | +import { onMounted, ref, onUnmounted, watch } from 'vue' | ||
13 | +import videojs from 'video.js' | ||
14 | +import type { VideoJsPlayerOptions } from 'video.js' | ||
15 | +import 'video.js/dist/video-js.min.css' | ||
16 | + | ||
17 | +const props = defineProps({ | ||
18 | + sourceSrc: { | ||
19 | + type: String | ||
20 | + }, | ||
21 | + name: { | ||
22 | + type: String | ||
23 | + }, | ||
24 | + avatar: { | ||
25 | + type: String | ||
26 | + }, | ||
27 | + index: { | ||
28 | + type: Number | ||
29 | + } | ||
30 | +}) | ||
31 | + | ||
32 | +// video标签 | ||
33 | +const videoRef = ref<HTMLElement | null>(null) | ||
34 | + | ||
35 | +// video实例对象 | ||
36 | +let videoPlayer: videojs.Player | null = null | ||
37 | + | ||
38 | +//options配置 | ||
39 | +const options: VideoJsPlayerOptions = { | ||
40 | + language: 'zh-CN', // 设置语言 | ||
41 | + controls: true, // 是否显示控制条 | ||
42 | + preload: 'auto', // 预加载 | ||
43 | + autoplay: true, // 是否自动播放 | ||
44 | + fluid: false, // 自适应宽高 | ||
45 | + poster: props?.avatar || '', | ||
46 | + src: props?.sourceSrc || '', // 要嵌入的视频源的源 URL | ||
47 | + muted: true, | ||
48 | + userActions: { | ||
49 | + hotkeys: true | ||
50 | + } | ||
51 | +} | ||
52 | + | ||
53 | +// 初始化videojs | ||
54 | +const initVideo = () => { | ||
55 | + if (videoRef.value) { | ||
56 | + // 创建 video 实例 | ||
57 | + videoPlayer = videojs(videoRef.value, options) | ||
58 | + } | ||
59 | +} | ||
60 | + | ||
61 | +watch( | ||
62 | + () => props.sourceSrc, | ||
63 | + (newData: any) => { | ||
64 | + // props.sourceSrc = newData | ||
65 | + videoPlayer?.src(newData) as any | ||
66 | + videoPlayer?.play() | ||
67 | + }, | ||
68 | + { | ||
69 | + immediate: true | ||
70 | + } | ||
71 | +) | ||
72 | + | ||
73 | +onMounted(() => { | ||
74 | + initVideo() | ||
75 | +}) | ||
76 | + | ||
77 | +onUnmounted(() => { | ||
78 | + handleVideoDispose() | ||
79 | +}) | ||
80 | + | ||
81 | +//播放 | ||
82 | +const handleVideoPlay = () => videoPlayer?.play() | ||
83 | + | ||
84 | +const handleVideoDispose = () => videoPlayer?.dispose() && videoPlayer?.pause() | ||
85 | +//暂停 | ||
86 | +defineExpose({ | ||
87 | + handleVideoPlay, | ||
88 | + handleVideoDispose | ||
89 | +}) | ||
90 | +</script> | ||
91 | + | ||
92 | +<style lang="scss" scoped> | ||
93 | +.my-video { | ||
94 | + width: 100%; | ||
95 | + height: 100%; | ||
96 | +} | ||
97 | +</style> |
1 | +import { PublicConfigClass } from '@/packages/public' | ||
2 | +import { CreateComponentType } from '@/packages/index.d' | ||
3 | +import { SingleCameraConfig } from './index' | ||
4 | +import cloneDeep from 'lodash/cloneDeep' | ||
5 | + | ||
6 | +export const option = { | ||
7 | + dataset: [ | ||
8 | + { | ||
9 | + url: '' | ||
10 | + } | ||
11 | + ] as any, | ||
12 | + // 自动播放的间隔(ms) | ||
13 | + interval: 5000, | ||
14 | + autoplay: true, | ||
15 | + effect: 'slide', | ||
16 | + displayMode: 'singleGrid' | ||
17 | +} | ||
18 | + | ||
19 | +export default class Config extends PublicConfigClass implements CreateComponentType { | ||
20 | + public key = SingleCameraConfig.key | ||
21 | + public chartConfig = cloneDeep(SingleCameraConfig) | ||
22 | + public option = cloneDeep(option) | ||
23 | +} |
1 | +<template> | ||
2 | + <CollapseItem name="播放器配置" :expanded="true"> | ||
3 | + <setting-item-box name="源地址" :alone="true"> | ||
4 | + <setting-item v-for="(item, index) in optionData.dataset" :key="index"> | ||
5 | + <n-input-group> | ||
6 | + <n-input v-model:value="item.url" size="small" placeholder="请输入源地址"></n-input> | ||
7 | + </n-input-group> | ||
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 { 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 | + | ||
25 | +</script> |
1 | +import { ChartFrameEnum, ConfigType } from '@/packages/index.d' | ||
2 | +import { EPackagesCategoryEnum } from '@/packages/components/external/types' | ||
3 | +import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d' | ||
4 | +import { useWidgetKey } from '@/packages/external/useWidgetKey' | ||
5 | + | ||
6 | +const { key, chartKey, conKey } = useWidgetKey('SingleCamera') | ||
7 | +export const SingleCameraConfig: ConfigType = { | ||
8 | + key, | ||
9 | + chartKey, | ||
10 | + conKey, | ||
11 | + title: '单个摄像头', | ||
12 | + category: ChatCategoryEnum.MORE, | ||
13 | + categoryName: ChatCategoryEnumName.MORE, | ||
14 | + package: EPackagesCategoryEnum.COMPOSES, | ||
15 | + chartFrame: ChartFrameEnum.NAIVE_UI, | ||
16 | + image: 'camera.png' | ||
17 | +} |
1 | +<template> | ||
2 | + <div class="banner-box" ref="root"> | ||
3 | + <n-grid x-gap="12" :y-gap="12" :cols="computedCols"> | ||
4 | + <n-gi v-for="(item, index) in option.dataset" :key="index + item"> | ||
5 | + <div class="camera-container"> | ||
6 | + <CameraItem | ||
7 | + ref="cameraRef" | ||
8 | + :name="item.name" | ||
9 | + :avatar="item.avatar" | ||
10 | + :key="item + index" | ||
11 | + :sourceSrc="item.url" | ||
12 | + :index="index" | ||
13 | + /> | ||
14 | + </div> | ||
15 | + </n-gi> | ||
16 | + </n-grid> | ||
17 | + </div> | ||
18 | +</template> | ||
19 | +<script setup lang="ts"> | ||
20 | +import { PropType, toRefs, watch, shallowReactive, ref, computed } from 'vue' | ||
21 | +import { CreateComponentType } from '@/packages/index.d' | ||
22 | +import 'video.js/dist/video-js.min.css' | ||
23 | +import { option as configOption } from './config' | ||
24 | +import { CameraItem } from './components' | ||
25 | + | ||
26 | +const props = defineProps({ | ||
27 | + chartConfig: { | ||
28 | + type: Object as PropType<CreateComponentType>, | ||
29 | + required: true | ||
30 | + } | ||
31 | +}) | ||
32 | + | ||
33 | +const { h } = toRefs(props.chartConfig.attr) | ||
34 | + | ||
35 | +const responsiveComputeValue = ref(0) | ||
36 | + | ||
37 | +const option = shallowReactive({ | ||
38 | + dataset: configOption.dataset | ||
39 | +}) | ||
40 | + | ||
41 | +const computedCols = computed(() => { | ||
42 | + if (option.dataset.length <= 1) return 1 | ||
43 | + if (option.dataset.length <= 4) return 2 | ||
44 | + return 3 | ||
45 | +}) | ||
46 | + | ||
47 | +const cameraRef = ref<InstanceType<typeof CameraItem>>() | ||
48 | + | ||
49 | +const responsive = (value: number) => { | ||
50 | + responsiveComputeValue.value = value | ||
51 | + if (option.dataset.length <= 2) responsiveComputeValue.value = value | ||
52 | + if (option.dataset.length > 2 && option.dataset.length <= 4) responsiveComputeValue.value = value / 2.03 | ||
53 | + if (option.dataset.length > 4 && option.dataset.length <= 9) responsiveComputeValue.value = value / 3.1 | ||
54 | +} | ||
55 | + | ||
56 | +watch( | ||
57 | + () => props.chartConfig.option.dataset, | ||
58 | + newData => { | ||
59 | + option.dataset = newData | ||
60 | + responsive(h.value) | ||
61 | + }, | ||
62 | + { | ||
63 | + immediate: true, | ||
64 | + deep: true | ||
65 | + } | ||
66 | +) | ||
67 | + | ||
68 | +watch( | ||
69 | + () => h.value, | ||
70 | + newData => responsive(newData), | ||
71 | + { | ||
72 | + immediate: true | ||
73 | + } | ||
74 | +) | ||
75 | +</script> | ||
76 | + | ||
77 | +<style lang="scss" scoped> | ||
78 | +.banner-box { | ||
79 | + .camera-container { | ||
80 | + height: v-bind('`${responsiveComputeValue}px`'); | ||
81 | + } | ||
82 | +} | ||
83 | +</style> |
@@ -2,6 +2,7 @@ import { Title1Config } from './Title1/index' | @@ -2,6 +2,7 @@ import { Title1Config } from './Title1/index' | ||
2 | import { Title2Config } from './Title2/index' | 2 | import { Title2Config } from './Title2/index' |
3 | import { Title3Config } from './Title3/index' | 3 | import { Title3Config } from './Title3/index' |
4 | import { CameraConfig } from './Camera/index' | 4 | import { CameraConfig } from './Camera/index' |
5 | +import { SingleCameraConfig } from './SingleCamera/index' | ||
5 | import { ThreeDimensionalConfig } from './ThreeDimensional/index' | 6 | import { ThreeDimensionalConfig } from './ThreeDimensional/index' |
6 | 7 | ||
7 | -export default [Title1Config, Title2Config, Title3Config, CameraConfig, ThreeDimensionalConfig] | 8 | +export default [Title1Config, Title2Config, Title3Config, CameraConfig, SingleCameraConfig, ThreeDimensionalConfig] |
@@ -23,19 +23,19 @@ export const enum areaEnum { | @@ -23,19 +23,19 @@ export const enum areaEnum { | ||
23 | export const weatherTextMapImg = [ | 23 | export const weatherTextMapImg = [ |
24 | { | 24 | { |
25 | text: '晴', | 25 | text: '晴', |
26 | - img: '/large-designer/src/assets/external/weather/clearDay.png' | 26 | + img: 'src/assets/external/weather/clearDay.png' |
27 | }, | 27 | }, |
28 | { | 28 | { |
29 | text: '多云', | 29 | text: '多云', |
30 | - img: '/large-designer/src/assets/external/weather/cloudy.png' | 30 | + img: 'src/assets/external/weather/cloudy.png' |
31 | }, | 31 | }, |
32 | { | 32 | { |
33 | text: '阴', | 33 | text: '阴', |
34 | - img: '/large-designer/src/assets/external/weather/cloudyDay.png' | 34 | + img: 'src/assets/external/weather/cloudyDay.png' |
35 | }, | 35 | }, |
36 | { | 36 | { |
37 | text: '小雨', | 37 | text: '小雨', |
38 | - img: '/large-designer/src/assets/external/weather/lightRain.png' | 38 | + img: 'src/assets/external/weather/lightRain.png' |
39 | } | 39 | } |
40 | ] | 40 | ] |
41 | 41 |
@@ -4,7 +4,7 @@ export const useUtils = () => { | @@ -4,7 +4,7 @@ export const useUtils = () => { | ||
4 | const loadWeatherImg = (text: string) => { | 4 | const loadWeatherImg = (text: string) => { |
5 | return ( | 5 | return ( |
6 | weatherTextMapImg.find((item: any) => item.text === text)?.img || | 6 | weatherTextMapImg.find((item: any) => item.text === text)?.img || |
7 | - '/large-designer/src/assets/external/weather/clearDay.png' | 7 | + '/src/assets/external/weather/clearDay.png' |
8 | ) | 8 | ) |
9 | } | 9 | } |
10 | 10 |
1 | +import { PublicConfigClass } from '@/packages/public' | ||
2 | +import { CreateComponentType } from '@/packages/index.d' | ||
3 | +import { OverrideTextCommonConfig } from './index' | ||
4 | +import cloneDeep from 'lodash/cloneDeep' | ||
5 | + | ||
6 | +export enum WritingModeEnum { | ||
7 | + HORIZONTAL = '水平', | ||
8 | + VERTICAL = '垂直' | ||
9 | +} | ||
10 | + | ||
11 | +export const WritingModeObject = { | ||
12 | + [WritingModeEnum.HORIZONTAL]: 'horizontal-tb', | ||
13 | + [WritingModeEnum.VERTICAL]: 'vertical-rl' | ||
14 | +} | ||
15 | + | ||
16 | +export enum FontWeightEnum { | ||
17 | + NORMAL = '常规', | ||
18 | + BOLD = '加粗' | ||
19 | +} | ||
20 | + | ||
21 | +export const FontWeightObject = { | ||
22 | + [FontWeightEnum.NORMAL]: 'normal', | ||
23 | + [FontWeightEnum.BOLD]: 'bold' | ||
24 | +} | ||
25 | + | ||
26 | +export const option = { | ||
27 | + link: '', | ||
28 | + linkHead: 'http://', | ||
29 | + dataset: '我是文本', | ||
30 | + fontSize: 20, | ||
31 | + fontColor: '#ffffff', | ||
32 | + paddingX: 10, | ||
33 | + paddingY: 10, | ||
34 | + textAlign: 'center', // 水平对齐方式 | ||
35 | + fontWeight: 'normal', | ||
36 | + | ||
37 | + // 边框 | ||
38 | + borderWidth: 0, | ||
39 | + borderColor: '#ffffff', | ||
40 | + borderRadius: 5, | ||
41 | + | ||
42 | + // 字间距 | ||
43 | + letterSpacing: 5, | ||
44 | + writingMode: 'horizontal-tb', | ||
45 | + backgroundColor: '#00000000', | ||
46 | + | ||
47 | + //跳转方式 | ||
48 | + linkMethod: 'default' | ||
49 | +} | ||
50 | + | ||
51 | +export default class Config extends PublicConfigClass implements CreateComponentType { | ||
52 | + public key = OverrideTextCommonConfig.key | ||
53 | + public chartConfig = cloneDeep(OverrideTextCommonConfig) | ||
54 | + public option = cloneDeep(option) | ||
55 | +} |
1 | +<template> | ||
2 | + <collapse-item name="信息" :expanded="true"> | ||
3 | + <setting-item-box name="文字" :alone="true"> | ||
4 | + <setting-item> | ||
5 | + <n-input v-model:value="optionData.dataset" size="small"></n-input> | ||
6 | + </setting-item> | ||
7 | + </setting-item-box> | ||
8 | + <setting-item-box name="链接" :alone="true"> | ||
9 | + <setting-item> | ||
10 | + <n-input-group> | ||
11 | + <n-select | ||
12 | + v-model:value="optionData.linkHead" | ||
13 | + size="small" | ||
14 | + :style="{ width: '80%' }" | ||
15 | + :options="linkHeadOptions" | ||
16 | + /> | ||
17 | + <n-input v-model:value="optionData.link" size="small"></n-input> | ||
18 | + </n-input-group> | ||
19 | + </setting-item> | ||
20 | + </setting-item-box> | ||
21 | + <setting-item-box name="跳转方式" :alone="true"> | ||
22 | + <setting-item> | ||
23 | + <n-input-group> | ||
24 | + <n-select | ||
25 | + v-model:value="optionData.linkMethod" | ||
26 | + size="small" | ||
27 | + :style="{ width: '80%' }" | ||
28 | + :options="linkMethodOptions" | ||
29 | + /> | ||
30 | + <n-button | ||
31 | + :disabled="!optionData.linkMethod" | ||
32 | + secondary | ||
33 | + size="small" | ||
34 | + @click="handleLinkClick(optionData.linkMethod)" | ||
35 | + >跳转</n-button | ||
36 | + > | ||
37 | + </n-input-group> | ||
38 | + </setting-item> | ||
39 | + </setting-item-box> | ||
40 | + </collapse-item> | ||
41 | + | ||
42 | + <collapse-item name="样式" :expanded="true"> | ||
43 | + <setting-item-box name="文字"> | ||
44 | + <setting-item name="颜色"> | ||
45 | + <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.fontColor"></n-color-picker> | ||
46 | + </setting-item> | ||
47 | + <setting-item name="字体大小"> | ||
48 | + <n-input-number v-model:value="optionData.fontSize" size="small" placeholder="字体大小"></n-input-number> | ||
49 | + </setting-item> | ||
50 | + <setting-item name="字体粗细"> | ||
51 | + <n-select v-model:value="optionData.fontWeight" size="small" :options="fontWeightOptions" /> | ||
52 | + </setting-item> | ||
53 | + <setting-item name="X轴内边距"> | ||
54 | + <n-input-number v-model:value="optionData.paddingX" size="small" placeholder="输入内边距"></n-input-number> | ||
55 | + </setting-item> | ||
56 | + <setting-item name="Y轴内边距"> | ||
57 | + <n-input-number v-model:value="optionData.paddingY" size="small" placeholder="输入内边距"></n-input-number> | ||
58 | + </setting-item> | ||
59 | + | ||
60 | + <setting-item name="水平对齐"> | ||
61 | + <n-select v-model:value="optionData.textAlign" size="small" :options="textAlignOptions" /> | ||
62 | + </setting-item> | ||
63 | + <setting-item name="文本方向"> | ||
64 | + <n-select v-model:value="optionData.writingMode" size="small" :options="verticalOptions" /> | ||
65 | + </setting-item> | ||
66 | + | ||
67 | + <setting-item name="字间距"> | ||
68 | + <n-input-number v-model:value="optionData.letterSpacing" size="small" placeholder="输入字间距"></n-input-number> | ||
69 | + </setting-item> | ||
70 | + </setting-item-box> | ||
71 | + | ||
72 | + <setting-item-box name="边框"> | ||
73 | + <setting-item name="宽度"> | ||
74 | + <n-input-number | ||
75 | + v-model:value="optionData.borderWidth" | ||
76 | + size="small" | ||
77 | + :min="0" | ||
78 | + placeholder="宽度" | ||
79 | + ></n-input-number> | ||
80 | + </setting-item> | ||
81 | + <setting-item name="颜色"> | ||
82 | + <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.borderColor"></n-color-picker> | ||
83 | + </setting-item> | ||
84 | + <setting-item name="圆角"> | ||
85 | + <n-input-number | ||
86 | + v-model:value="optionData.borderRadius" | ||
87 | + size="small" | ||
88 | + :min="0" | ||
89 | + placeholder="圆角" | ||
90 | + ></n-input-number> | ||
91 | + </setting-item> | ||
92 | + </setting-item-box> | ||
93 | + | ||
94 | + <setting-item-box name="背景" :alone="true"> | ||
95 | + <setting-item name="背景颜色"> | ||
96 | + <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.backgroundColor"></n-color-picker> | ||
97 | + </setting-item> | ||
98 | + </setting-item-box> | ||
99 | + </collapse-item> | ||
100 | +</template> | ||
101 | + | ||
102 | +<script setup lang="ts"> | ||
103 | +import { PropType } from 'vue' | ||
104 | +import { option, WritingModeEnum, WritingModeObject, FontWeightEnum, FontWeightObject } from './config' | ||
105 | +import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' | ||
106 | +const props = defineProps({ | ||
107 | + optionData: { | ||
108 | + type: Object as PropType<typeof option>, | ||
109 | + required: true | ||
110 | + } | ||
111 | +}) | ||
112 | + | ||
113 | +const textAlignOptions = [ | ||
114 | + { label: '左对齐', value: 'start' }, | ||
115 | + { label: '居中', value: 'center' }, | ||
116 | + { label: '右对齐', value: 'end' } | ||
117 | +] | ||
118 | + | ||
119 | +const linkMethodOptions = [ | ||
120 | + { label: '默认', value: 'default' }, | ||
121 | + { label: '新开窗口', value: 'open' } | ||
122 | +] | ||
123 | + | ||
124 | +const verticalOptions = [ | ||
125 | + { | ||
126 | + label: WritingModeEnum.HORIZONTAL, | ||
127 | + value: WritingModeObject[WritingModeEnum.HORIZONTAL] | ||
128 | + }, | ||
129 | + { | ||
130 | + label: WritingModeEnum.VERTICAL, | ||
131 | + value: WritingModeObject[WritingModeEnum.VERTICAL] | ||
132 | + } | ||
133 | +] | ||
134 | +const fontWeightOptions = [ | ||
135 | + { | ||
136 | + label: FontWeightEnum.NORMAL, | ||
137 | + value: FontWeightObject[FontWeightEnum.NORMAL] | ||
138 | + }, | ||
139 | + { | ||
140 | + label: FontWeightEnum.BOLD, | ||
141 | + value: FontWeightObject[FontWeightEnum.BOLD] | ||
142 | + } | ||
143 | +] | ||
144 | +const handleLinkClick = (target: string) => { | ||
145 | + const hrefStr = props.optionData.linkHead + props.optionData.link | ||
146 | + if (target === 'open') window.open(hrefStr) | ||
147 | + else window.location.href = hrefStr | ||
148 | +} | ||
149 | +const linkHeadOptions = [ | ||
150 | + { label: 'http://', value: 'http://' }, | ||
151 | + { label: 'https://', value: 'https://' } | ||
152 | +] | ||
153 | +</script> |
1 | +import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d' | ||
2 | +import { ChatCategoryEnum, ChatCategoryEnumName } from '@/packages/components/Informations/index.d' | ||
3 | +import { useWidgetKey } from '@/packages/external/useWidgetKey' | ||
4 | + | ||
5 | +const { key, conKey, chartKey } = useWidgetKey('OverrideTextCommon', true) | ||
6 | + | ||
7 | +export const OverrideTextCommonConfig: ConfigType = { | ||
8 | + key, | ||
9 | + chartKey, | ||
10 | + conKey, | ||
11 | + title: '自定义文字', | ||
12 | + category: ChatCategoryEnum.MORE, | ||
13 | + categoryName: ChatCategoryEnumName.MORE, | ||
14 | + package: PackagesCategoryEnum.INFORMATIONS, | ||
15 | + chartFrame: ChartFrameEnum.COMMON, | ||
16 | + image: 'text_static.png' | ||
17 | +} |
1 | +<template> | ||
2 | + <div class="go-text-box"> | ||
3 | + <div class="content"> | ||
4 | + <span style="cursor: pointer" v-if="link" @click="click">{{ option.dataset }}</span> | ||
5 | + <span v-else>{{ option.dataset }}</span> | ||
6 | + </div> | ||
7 | + </div> | ||
8 | +</template> | ||
9 | + | ||
10 | +<script setup lang="ts"> | ||
11 | +import { PropType, toRefs, shallowReactive, watch } from 'vue' | ||
12 | +import { CreateComponentType } from '@/packages/index.d' | ||
13 | +import { useChartDataFetch } from '@/hooks' | ||
14 | +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' | ||
15 | +import { option as configOption } from './config' | ||
16 | + | ||
17 | +const props = defineProps({ | ||
18 | + chartConfig: { | ||
19 | + type: Object as PropType<CreateComponentType & typeof option>, | ||
20 | + required: true | ||
21 | + } | ||
22 | +}) | ||
23 | + | ||
24 | +const { | ||
25 | + linkHead, | ||
26 | + link, | ||
27 | + fontColor, | ||
28 | + fontSize, | ||
29 | + letterSpacing, | ||
30 | + paddingY, | ||
31 | + paddingX, | ||
32 | + textAlign, | ||
33 | + borderWidth, | ||
34 | + borderColor, | ||
35 | + borderRadius, | ||
36 | + writingMode, | ||
37 | + backgroundColor, | ||
38 | + fontWeight, | ||
39 | + linkMethod | ||
40 | +} = toRefs(props.chartConfig.option) | ||
41 | + | ||
42 | +const option = shallowReactive({ | ||
43 | + dataset: configOption.dataset | ||
44 | +}) | ||
45 | + | ||
46 | +// 手动更新 | ||
47 | +watch( | ||
48 | + () => props.chartConfig.option.dataset, | ||
49 | + (newData: any) => { | ||
50 | + option.dataset = newData | ||
51 | + }, | ||
52 | + { | ||
53 | + immediate: true, | ||
54 | + deep: false | ||
55 | + } | ||
56 | +) | ||
57 | + | ||
58 | +// 预览更新 | ||
59 | +useChartDataFetch(props.chartConfig, useChartEditStore, (newData: string) => { | ||
60 | + option.dataset = newData | ||
61 | +}) | ||
62 | + | ||
63 | +//打开链接 | ||
64 | +const click = () => { | ||
65 | + const hrefStr = linkHead.value + link.value | ||
66 | + if (linkMethod.value === 'open') window.open(hrefStr) | ||
67 | + else window.location.href = hrefStr | ||
68 | +} | ||
69 | +</script> | ||
70 | + | ||
71 | +<style lang="scss" scoped> | ||
72 | +@include go('text-box') { | ||
73 | + display: flex; | ||
74 | + align-items: center; | ||
75 | + justify-content: v-bind('textAlign'); | ||
76 | + | ||
77 | + .content { | ||
78 | + color: v-bind('fontColor'); | ||
79 | + padding: v-bind('`${paddingY}px ${paddingX}px`'); | ||
80 | + font-size: v-bind('fontSize + "px"'); | ||
81 | + letter-spacing: v-bind('letterSpacing + "px"'); | ||
82 | + writing-mode: v-bind('writingMode'); | ||
83 | + font-weight: v-bind('fontWeight'); | ||
84 | + border-style: solid; | ||
85 | + border-width: v-bind('borderWidth + "px"'); | ||
86 | + border-radius: v-bind('borderRadius + "px"'); | ||
87 | + border-color: v-bind('borderColor'); | ||
88 | + | ||
89 | + background-color: v-bind('backgroundColor'); | ||
90 | + } | ||
91 | +} | ||
92 | +</style> |
@@ -8,6 +8,10 @@ import { OverrideCarouselConfig } from '@/packages/components/external/Informati | @@ -8,6 +8,10 @@ import { OverrideCarouselConfig } from '@/packages/components/external/Informati | ||
8 | import { OverrideSelectConfig } from '@/packages/components/external/Informations/Mores/OverrideSelect' | 8 | import { OverrideSelectConfig } from '@/packages/components/external/Informations/Mores/OverrideSelect' |
9 | import { OverrideInputsDateConfig } from '@/packages/components/external/Informations/Mores/OverrideInputsDate' | 9 | import { OverrideInputsDateConfig } from '@/packages/components/external/Informations/Mores/OverrideInputsDate' |
10 | import { OverrideInputsTabConfig } from '@/packages/components/external/Informations/Mores/OverrideInputsTab' | 10 | import { OverrideInputsTabConfig } from '@/packages/components/external/Informations/Mores/OverrideInputsTab' |
11 | +import { OverrideTextCommonConfig } from '@/packages/components/external/Informations/Mores/OverrideTextCommon' | ||
12 | +import { OverrideBarCommonConfig } from '@/packages/components/external/Charts/Bars/OverrideBarCommon' | ||
13 | +import { OverrideLineCommonConfig } from '@/packages/components/external/Charts/Lines/OverrideLineCommon' | ||
14 | +import { OverrideLineGradientsConfig } from '@/packages/components/external/Charts/Lines/OverrideLineGradients' | ||
11 | 15 | ||
12 | export function useInjectLib(packagesList: EPackagesType) { | 16 | export function useInjectLib(packagesList: EPackagesType) { |
13 | 17 | ||
@@ -20,6 +24,10 @@ export function useInjectLib(packagesList: EPackagesType) { | @@ -20,6 +24,10 @@ export function useInjectLib(packagesList: EPackagesType) { | ||
20 | addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.INFORMATIONS, OverrideSelectConfig) | 24 | addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.INFORMATIONS, OverrideSelectConfig) |
21 | addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.INFORMATIONS, OverrideInputsDateConfig) | 25 | addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.INFORMATIONS, OverrideInputsDateConfig) |
22 | addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.INFORMATIONS, OverrideInputsTabConfig) | 26 | addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.INFORMATIONS, OverrideInputsTabConfig) |
27 | + addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.INFORMATIONS, OverrideTextCommonConfig) | ||
28 | + addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.CHARTS, OverrideBarCommonConfig) | ||
29 | + addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.CHARTS, OverrideLineCommonConfig) | ||
30 | + addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.CHARTS, OverrideLineGradientsConfig) | ||
23 | } | 31 | } |
24 | 32 | ||
25 | /** | 33 | /** |
@@ -69,10 +69,17 @@ export const useSocketStore = defineStore({ | @@ -69,10 +69,17 @@ export const useSocketStore = defineStore({ | ||
69 | }) | 69 | }) |
70 | } else { | 70 | } else { |
71 | const keysRecord: Record<string, KeyBoundComponentList[]> = {} | 71 | const keysRecord: Record<string, KeyBoundComponentList[]> = {} |
72 | - | ||
73 | - keys.forEach(key => { | 72 | + /**这里修改自定义tab切换传的单个属性问题 |
73 | + * ft | ||
74 | + * 源代码 keys.forEach | ||
75 | + * 修改代码 const overrideKeys = typeof keys==="string"?[keys]: keys overrideKeys.forEach | ||
76 | + */ | ||
77 | + const overrideKeys = typeof keys==="string"?[keys]: keys | ||
78 | + | ||
79 | + overrideKeys.forEach(key => { | ||
74 | Reflect.set(keysRecord, key, [{ componentId }]) | 80 | Reflect.set(keysRecord, key, [{ componentId }]) |
75 | }) | 81 | }) |
82 | + //ft | ||
76 | Reflect.set(this.connectionPool, entityId, keysRecord) | 83 | Reflect.set(this.connectionPool, entityId, keysRecord) |
77 | } | 84 | } |
78 | return this.refreshSubscribedMessage(entityId) | 85 | return this.refreshSubscribedMessage(entityId) |
@@ -177,15 +184,22 @@ export const useSocketStore = defineStore({ | @@ -177,15 +184,22 @@ export const useSocketStore = defineStore({ | ||
177 | */ | 184 | */ |
178 | getNeedUpdateComponentsIdBySubscribeId(subscribeId: number, keys: string[]) { | 185 | getNeedUpdateComponentsIdBySubscribeId(subscribeId: number, keys: string[]) { |
179 | const entityId = this.subscribePool.find(item => item.subscribeId === subscribeId)?.entityId | 186 | const entityId = this.subscribePool.find(item => item.subscribeId === subscribeId)?.entityId |
187 | + /**这里修改自定义tab切换传的单个属性问题 | ||
188 | + * ft | ||
189 | + * 源代码 keys.map(key => keysRecord[key]) | ||
190 | + * 修改代码 const overrideKeys = typeof keys==="string"?[keys]: keys overrideKeys.map(key => keysRecord[key]) | ||
191 | + */ | ||
192 | + const overrideKeys = typeof keys==="string"?[keys]: keys | ||
180 | 193 | ||
181 | if (entityId) { | 194 | if (entityId) { |
182 | const keysRecord = Reflect.get(this.connectionPool, entityId) | 195 | const keysRecord = Reflect.get(this.connectionPool, entityId) |
183 | - const needUpdateComponents = keys.map(key => keysRecord[key]) | 196 | + const needUpdateComponents = overrideKeys.map(key => keysRecord[key]) |
184 | const ids = needUpdateComponents | 197 | const ids = needUpdateComponents |
185 | .reduce((prev, next) => [...prev, ...next], []) | 198 | .reduce((prev, next) => [...prev, ...next], []) |
186 | .map((item: KeyBoundComponentList) => item.componentId) | 199 | .map((item: KeyBoundComponentList) => item.componentId) |
187 | return [...new Set(ids)] | 200 | return [...new Set(ids)] |
188 | } | 201 | } |
202 | + //ft | ||
189 | }, | 203 | }, |
190 | 204 | ||
191 | /** | 205 | /** |
@@ -198,7 +212,15 @@ export const useSocketStore = defineStore({ | @@ -198,7 +212,15 @@ export const useSocketStore = defineStore({ | ||
198 | const { request: { requestParams } } = targetComponent | 212 | const { request: { requestParams } } = targetComponent |
199 | const { Params } = requestParams | 213 | const { Params } = requestParams |
200 | const { keys = [] } = Params | 214 | const { keys = [] } = Params |
201 | - const targetComponentBindKeys = keys as unknown as string[] | 215 | + /**这里修改自定义tab切换传的单个属性问题 |
216 | + * ft | ||
217 | + * 源代码 keys as unknown as string[] | ||
218 | + * 修改代码 const overrideKeys = typeof keys==="string"?[keys]: keys overrideKeys as unknown as string[] | ||
219 | + */ | ||
220 | + const overrideKeys = typeof keys==="string"?[keys]: keys | ||
221 | + | ||
222 | + const targetComponentBindKeys = overrideKeys as unknown as string[] | ||
223 | + //ft | ||
202 | 224 | ||
203 | const _value = cloneDeep(value) || { data: {}, latestValues: {} } | 225 | const _value = cloneDeep(value) || { data: {}, latestValues: {} } |
204 | _value.data = targetComponentBindKeys.reduce((prev, next) => { | 226 | _value.data = targetComponentBindKeys.reduce((prev, next) => { |
@@ -43,7 +43,22 @@ | @@ -43,7 +43,22 @@ | ||
43 | </n-button> | 43 | </n-button> |
44 | </div> | 44 | </div> |
45 | </template> | 45 | </template> |
46 | - <span>保存</span> | 46 | + <span>保存内容</span> |
47 | + </n-tooltip> | ||
48 | + <!-- 保存缩略图 --> | ||
49 | + <n-tooltip v-if="!isCustomerUser" placement="bottom" trigger="hover"> | ||
50 | + <template #trigger> | ||
51 | + <div class="save-btn"> | ||
52 | + <n-button size="small" type="primary" ghost @click="thumbnailSyncUpdate()"> | ||
53 | + <template #icon> | ||
54 | + <n-icon> | ||
55 | + <Awake /> | ||
56 | + </n-icon> | ||
57 | + </template> | ||
58 | + </n-button> | ||
59 | + </div> | ||
60 | + </template> | ||
61 | + <span>保存缩略图</span> | ||
47 | </n-tooltip> | 62 | </n-tooltip> |
48 | </n-space> | 63 | </n-space> |
49 | </n-space> | 64 | </n-space> |
@@ -53,7 +68,7 @@ | @@ -53,7 +68,7 @@ | ||
53 | import { toRefs, Ref, reactive, computed } from 'vue' | 68 | import { toRefs, Ref, reactive, computed } from 'vue' |
54 | import { renderIcon, goDialog, goHome } from '@/utils' | 69 | import { renderIcon, goDialog, goHome } from '@/utils' |
55 | import { icon } from '@/plugins' | 70 | import { icon } from '@/plugins' |
56 | -import { Save } from '@vicons/carbon' | 71 | +import { Save, Awake } from '@vicons/carbon' |
57 | import { useRemoveKeyboard } from '../../../hooks/useKeyboard.hook' | 72 | import { useRemoveKeyboard } from '../../../hooks/useKeyboard.hook' |
58 | 73 | ||
59 | import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' | 74 | import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' |
@@ -71,7 +86,7 @@ const { setItem } = useChartLayoutStore() | @@ -71,7 +86,7 @@ const { setItem } = useChartLayoutStore() | ||
71 | const { getLayers, getCharts, getDetails } = toRefs(useChartLayoutStore()) | 86 | const { getLayers, getCharts, getDetails } = toRefs(useChartLayoutStore()) |
72 | const chartEditStore = useChartEditStore() | 87 | const chartEditStore = useChartEditStore() |
73 | const chartHistoryStore = useChartHistoryStore() | 88 | const chartHistoryStore = useChartHistoryStore() |
74 | -const { dataSyncUpdate } = useSyncRemote() | 89 | +const { dataSyncUpdate ,thumbnailSyncUpdate } = useSyncRemote() |
75 | const { isCustomerUser } = useRole() | 90 | const { isCustomerUser } = useRole() |
76 | 91 | ||
77 | interface ItemType<T> { | 92 | interface ItemType<T> { |
@@ -70,22 +70,47 @@ export const useSyncRemote = () => { | @@ -70,22 +70,47 @@ export const useSyncRemote = () => { | ||
70 | } | 70 | } |
71 | } | 71 | } |
72 | 72 | ||
73 | - // 数据保存 | ||
74 | - const dataSyncUpdate = throttle(async (updateImg = true) => { | 73 | + /** |
74 | + * 数据保存和缩略图保存逻辑拆分 | ||
75 | + */ | ||
76 | + | ||
77 | + //dataSyncUpdate 数据保存 | ||
78 | + const dataSyncUpdate = throttle(async () => { | ||
75 | if (!fetchRouteParamsLocation()) return | 79 | if (!fetchRouteParamsLocation()) return |
76 | 80 | ||
77 | // 客户角色只有查看权限 | 81 | // 客户角色只有查看权限 |
78 | if (unref(isCustomerUser)) return | 82 | if (unref(isCustomerUser)) return |
79 | 83 | ||
80 | - const { dataViewId, state, organizationId, dataViewName, dataViewContent } = projectInfoStore.getProjectInfo | 84 | + const { dataViewId, dataViewName, dataViewContent } = projectInfoStore.getProjectInfo |
81 | 85 | ||
82 | if (dataViewId === null || dataViewId === '') { | 86 | if (dataViewId === null || dataViewId === '') { |
83 | window['$message'].error('数据初未始化成功,请刷新页面!') | 87 | window['$message'].error('数据初未始化成功,请刷新页面!') |
84 | return | 88 | return |
85 | } | 89 | } |
86 | projectInfoStore.setSaveStatus(SyncEnum.START) | 90 | projectInfoStore.setSaveStatus(SyncEnum.START) |
87 | - // 异常处理:缩略图上传失败不影响JSON的保存 | ||
88 | - try { | 91 | + // 保存数据 |
92 | + const saveContent = { | ||
93 | + dataViewContent: { | ||
94 | + id: dataViewContent.id, | ||
95 | + content: JSONStringify(chartEditStore.getStorageInfo || {}) | ||
96 | + }, | ||
97 | + dataViewName, | ||
98 | + dataViewId | ||
99 | + } | ||
100 | + await contentUpdateApi(saveContent as unknown as BaseUpdateContentParams) | ||
101 | + window['$message'].success('保存成功!') | ||
102 | + // 成功状态 | ||
103 | + setTimeout(() => { | ||
104 | + projectInfoStore.setSaveStatus(SyncEnum.SUCCESS) | ||
105 | + }, 1000) | ||
106 | + return | ||
107 | + // 失败状态 | ||
108 | + // chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.FAILURE) | ||
109 | + }, 3000) | ||
110 | + | ||
111 | + //thumbnailSyncUpdate 缩略图保存 | ||
112 | + const thumbnailSyncUpdate = throttle(async(updateImg = true)=>{ | ||
113 | + const { state, organizationId, dataViewName } = projectInfoStore.getProjectInfo | ||
89 | if (updateImg) { | 114 | if (updateImg) { |
90 | // 获取缩略图片 | 115 | // 获取缩略图片 |
91 | const range = document.querySelector('.go-edit-range') as HTMLElement | 116 | const range = document.querySelector('.go-edit-range') as HTMLElement |
@@ -96,7 +121,6 @@ export const useSyncRemote = () => { | @@ -96,7 +121,6 @@ export const useSyncRemote = () => { | ||
96 | useCORS: true, | 121 | useCORS: true, |
97 | logging: false | 122 | logging: false |
98 | }) | 123 | }) |
99 | - | ||
100 | // 上传预览图 | 124 | // 上传预览图 |
101 | const uploadParams = new FormData() | 125 | const uploadParams = new FormData() |
102 | uploadParams.append( | 126 | uploadParams.append( |
@@ -104,7 +128,6 @@ export const useSyncRemote = () => { | @@ -104,7 +128,6 @@ export const useSyncRemote = () => { | ||
104 | base64toFile(canvasImage.toDataURL(), `${fetchRouteParamsLocation()}_index_preview.png`) | 128 | base64toFile(canvasImage.toDataURL(), `${fetchRouteParamsLocation()}_index_preview.png`) |
105 | ) | 129 | ) |
106 | const uploadRes = await uploadFile(uploadParams) | 130 | const uploadRes = await uploadFile(uploadParams) |
107 | - | ||
108 | // 保存预览图 | 131 | // 保存预览图 |
109 | if (uploadRes) { | 132 | if (uploadRes) { |
110 | await saveDataViewList({ | 133 | await saveDataViewList({ |
@@ -114,30 +137,10 @@ export const useSyncRemote = () => { | @@ -114,30 +137,10 @@ export const useSyncRemote = () => { | ||
114 | id: fetchRouteParamsLocation(), | 137 | id: fetchRouteParamsLocation(), |
115 | thumbnail: `${uploadRes.fileStaticUri}` | 138 | thumbnail: `${uploadRes.fileStaticUri}` |
116 | }) | 139 | }) |
140 | + window['$message'].success('保存缩略图成功!') | ||
117 | } | 141 | } |
118 | } | 142 | } |
119 | - } catch (e) { | ||
120 | - console.log(e) | ||
121 | - } | ||
122 | - // 保存数据 | ||
123 | - const saveContent = { | ||
124 | - dataViewContent: { | ||
125 | - id: dataViewContent.id, | ||
126 | - content: JSONStringify(chartEditStore.getStorageInfo || {}) | ||
127 | - }, | ||
128 | - dataViewName, | ||
129 | - dataViewId | ||
130 | - } | ||
131 | - await contentUpdateApi(saveContent as unknown as BaseUpdateContentParams) | ||
132 | - window['$message'].success('保存成功!') | ||
133 | - // 成功状态 | ||
134 | - setTimeout(() => { | ||
135 | - projectInfoStore.setSaveStatus(SyncEnum.SUCCESS) | ||
136 | - }, 1000) | ||
137 | - return | ||
138 | - // 失败状态 | ||
139 | - // chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.FAILURE) | ||
140 | - }, 3000) | 143 | + }) |
141 | 144 | ||
142 | // * 定时处理 | 145 | // * 定时处理 |
143 | const intervalDataSyncUpdate = () => { | 146 | const intervalDataSyncUpdate = () => { |
@@ -145,7 +148,6 @@ export const useSyncRemote = () => { | @@ -145,7 +148,6 @@ export const useSyncRemote = () => { | ||
145 | // const syncTiming = setInterval(() => { | 148 | // const syncTiming = setInterval(() => { |
146 | // dataSyncUpdate() | 149 | // dataSyncUpdate() |
147 | // }, saveInterval * 1000) | 150 | // }, saveInterval * 1000) |
148 | - | ||
149 | // // 销毁 | 151 | // // 销毁 |
150 | // onUnmounted(() => { | 152 | // onUnmounted(() => { |
151 | // clearInterval(syncTiming) | 153 | // clearInterval(syncTiming) |
@@ -154,6 +156,7 @@ export const useSyncRemote = () => { | @@ -154,6 +156,7 @@ export const useSyncRemote = () => { | ||
154 | return { | 156 | return { |
155 | dataSyncFetch, | 157 | dataSyncFetch, |
156 | dataSyncUpdate, | 158 | dataSyncUpdate, |
159 | + thumbnailSyncUpdate, | ||
157 | intervalDataSyncUpdate | 160 | intervalDataSyncUpdate |
158 | } | 161 | } |
159 | } | 162 | } |