Commit 2a1b7452e437bd10c2cd1f2eacbac6b143adf374
1 parent
ea305212
feat: 新增plopjs配置,为此项目快速生成组件模板,比如需要新加一个组件,直接快速生成配置代码
Showing
8 changed files
with
330 additions
and
0 deletions
@@ -12,6 +12,7 @@ | @@ -12,6 +12,7 @@ | ||
12 | "preview": "vite preview", | 12 | "preview": "vite preview", |
13 | "preview:alone": "vite preview --mode alone.prod", | 13 | "preview:alone": "vite preview --mode alone.prod", |
14 | "new": "plop --plopfile ./plop/plopfile.js", | 14 | "new": "plop --plopfile ./plop/plopfile.js", |
15 | + "newCom": "plop --plopfile ./plop/external/plopfile.js", | ||
15 | "postinstall": "husky install", | 16 | "postinstall": "husky install", |
16 | "lint": "eslint --ext .js,.jsx,.ts,.tsx,.vue src", | 17 | "lint": "eslint --ext .js,.jsx,.ts,.tsx,.vue src", |
17 | "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx,.vue src --fix" | 18 | "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx,.vue src --fix" |
1 | +import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public' | ||
2 | +import { {{name}}Config } 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 | +export const seriesItem = { | ||
10 | +} | ||
11 | + | ||
12 | +export const option = { | ||
13 | + dataset: { ...dataJson }, | ||
14 | + series: [seriesItem, seriesItem] | ||
15 | +} | ||
16 | + | ||
17 | +export default class Config extends PublicConfigClass implements CreateComponentType { | ||
18 | + public key = {{name}}Config.key | ||
19 | + public chartConfig = cloneDeep({{name}}Config) | ||
20 | + // 图表配置项 | ||
21 | + public option = echartOptionProfixHandle(option, includes) | ||
22 | +} |
1 | +<template> | ||
2 | + <!-- Echarts 全局设置 --> | ||
3 | + <global-setting :optionData="optionData"></global-setting> | ||
4 | + <CollapseItem name="xxx" :expanded="true"> | ||
5 | + <SettingItemBox name="xx"> | ||
6 | + <SettingItem name="xx"> | ||
7 | + </SettingItem> | ||
8 | + </SettingItemBox> | ||
9 | + </CollapseItem> | ||
10 | +</template> | ||
11 | + | ||
12 | +<script setup lang="ts"> | ||
13 | +import { PropType, computed } from 'vue' | ||
14 | +import { GlobalSetting, CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' | ||
15 | +import { GlobalThemeJsonType } from '@/settings/chartThemes/index' | ||
16 | + | ||
17 | +const props = defineProps({ | ||
18 | + optionData: { | ||
19 | + type: Object as PropType<GlobalThemeJsonType>, | ||
20 | + required: true | ||
21 | + } | ||
22 | +}) | ||
23 | + | ||
24 | +const seriesList = computed(() => { | ||
25 | + return props.optionData.series | ||
26 | +}) | ||
27 | +</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('{{name}}', true) | ||
6 | + | ||
7 | +export const {{name}}Config: ConfigType = { | ||
8 | + key, | ||
9 | + chartKey, | ||
10 | + conKey, | ||
11 | + title: 'xxx', | ||
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 { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' | ||
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 cloneDeep from 'lodash/cloneDeep' | ||
34 | +import { useAssembleDataHooks } from '@/hooks/external/useAssembleData.hook' | ||
35 | +import { SocketReceiveMessageType } from '@/store/external/modules/socketStore.d' | ||
36 | + | ||
37 | +const props = defineProps({ | ||
38 | + themeSetting: { | ||
39 | + type: Object, | ||
40 | + required: true | ||
41 | + }, | ||
42 | + themeColor: { | ||
43 | + type: Object, | ||
44 | + required: true | ||
45 | + }, | ||
46 | + chartConfig: { | ||
47 | + type: Object as PropType<config>, | ||
48 | + required: true | ||
49 | + } | ||
50 | +}) | ||
51 | + | ||
52 | +const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting) | ||
53 | + | ||
54 | +use([DatasetComponent, CanvasRenderer, BarChart, GridComponent, TooltipComponent, LegendComponent]) | ||
55 | + | ||
56 | +const chartEditStore = useChartEditStore() | ||
57 | + | ||
58 | +const replaceMergeArr = ref<string[]>() | ||
59 | + | ||
60 | +const option = computed(() => { | ||
61 | + return mergeTheme(props.chartConfig.option, props.themeSetting, includes) | ||
62 | +}) | ||
63 | + | ||
64 | + | ||
65 | +// dataset 无法变更条数的补丁 | ||
66 | +watch( | ||
67 | + () => props.chartConfig.option.dataset, | ||
68 | + (newData: { dimensions: any }, oldData) => { | ||
69 | + try { | ||
70 | + if (!isObject(newData) || !('dimensions' in newData)) return | ||
71 | + if (Array.isArray(newData?.dimensions)) { | ||
72 | + const seriesArr = [] | ||
73 | + // 对oldData进行判断,防止传入错误数据之后对旧维度判断产生干扰 | ||
74 | + // 此处计算的是dimensions的Y轴维度,若是dimensions.length为0或1,则默认为1,排除X轴维度干扰 | ||
75 | + const oldDimensions = | ||
76 | + Array.isArray(oldData?.dimensions) && oldData.dimensions.length >= 1 ? oldData.dimensions.length : 1 | ||
77 | + const newDimensions = newData.dimensions.length >= 1 ? newData.dimensions.length : 1 | ||
78 | + const dimensionsGap = newDimensions - oldDimensions | ||
79 | + if (dimensionsGap < 0) { | ||
80 | + props.chartConfig.option.series.splice(newDimensions - 1) | ||
81 | + } else if (dimensionsGap > 0) { | ||
82 | + if (!oldData || !oldData?.dimensions || !Array.isArray(oldData?.dimensions) || !oldData?.dimensions.length) { | ||
83 | + props.chartConfig.option.series = [] | ||
84 | + } | ||
85 | + for (let i = 0; i < dimensionsGap; i++) { | ||
86 | + seriesArr.push(cloneDeep(seriesItem)) | ||
87 | + } | ||
88 | + props.chartConfig.option.series.push(...seriesArr) | ||
89 | + } | ||
90 | + replaceMergeArr.value = ['series'] | ||
91 | + nextTick(() => { | ||
92 | + replaceMergeArr.value = [] | ||
93 | + }) | ||
94 | + } | ||
95 | + } catch (error) { | ||
96 | + console.log(error) | ||
97 | + } | ||
98 | + }, | ||
99 | + { | ||
100 | + deep: false | ||
101 | + } | ||
102 | +) | ||
103 | + | ||
104 | +//fix 修复v-chart图表绑定联动组件视图不更新问题 | ||
105 | +const updateVChart = async (newData: SocketReceiveMessageType) => { | ||
106 | + //区分是普通请求还是ws请求 | ||
107 | + if (!isObject(newData) || !('dimensions' in newData)) { | ||
108 | + const { data } = newData | ||
109 | + const { keys, record } = useAssembleDataHooks(data) | ||
110 | + vChartRef.value?.setOption({ | ||
111 | + dataset: { | ||
112 | + dimensions: ['ts', ...keys], | ||
113 | + source: [record] | ||
114 | + } | ||
115 | + }) | ||
116 | + } else { | ||
117 | + //异步更新,同步更新会造成联动组件控制,图表不及时更新 | ||
118 | + await nextTick().then(() => { | ||
119 | + vChartRef.value?.setOption( | ||
120 | + { | ||
121 | + ...option.value, | ||
122 | + dataset: newData | ||
123 | + }, | ||
124 | + { | ||
125 | + notMerge: true | ||
126 | + } | ||
127 | + ) | ||
128 | + }) | ||
129 | + } | ||
130 | +} | ||
131 | + | ||
132 | +const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore, newData => { | ||
133 | + //联动支持分组 | ||
134 | + /** | ||
135 | + * 修复多个分组,然后下拉框联动,会影响另一个组件 | ||
136 | + */ | ||
137 | + chartEditStore.getComponentList.forEach(targetItem => { | ||
138 | + if (targetItem.isGroup) { | ||
139 | + targetItem.groupList?.forEach(groupItem => { | ||
140 | + if (groupItem.id === props.chartConfig.id) { | ||
141 | + groupItem.option.dataset = newData | ||
142 | + } | ||
143 | + }) | ||
144 | + } else { | ||
145 | + if (targetItem.id === props.chartConfig.id) { | ||
146 | + targetItem.option.dataset = newData | ||
147 | + } | ||
148 | + } | ||
149 | + }) | ||
150 | + // | ||
151 | + updateVChart(newData) | ||
152 | +}) | ||
153 | +</script> |
plop/external/component-template/prompt.js
0 → 100644
1 | +module.exports = { | ||
2 | + description: | ||
3 | + 'create a component(在packages/components/external,一般是需要重写的组件,这里写的示例生成在src/packages/components/external/Charts/Bars目录下)', | ||
4 | + prompts: [ | ||
5 | + { | ||
6 | + type: 'input', | ||
7 | + name: 'name', | ||
8 | + message: 'Please enter component name,such as "OverrideComponentName":', | ||
9 | + validate(value) { | ||
10 | + if (!value || value.trim === '') { | ||
11 | + return 'component name is required' | ||
12 | + } | ||
13 | + return true | ||
14 | + } | ||
15 | + } | ||
16 | + ], | ||
17 | + actions: data => { | ||
18 | + const dataName = data.name | ||
19 | + | ||
20 | + const actions = [ | ||
21 | + { | ||
22 | + type: 'add', | ||
23 | + path: `${process.cwd()}/src/packages/components/external/Charts/Bars${dataName}/config.ts`, | ||
24 | + templateFile: './component-template/config.ts.hbs', | ||
25 | + data: { | ||
26 | + name: data.name | ||
27 | + } | ||
28 | + }, | ||
29 | + { | ||
30 | + type: 'add', | ||
31 | + path: `${process.cwd()}/src/packages/components/external/Charts/Bars${dataName}/config.vue`, | ||
32 | + templateFile: './component-template/config.vue.hbs', | ||
33 | + data: { | ||
34 | + name: data.name | ||
35 | + } | ||
36 | + }, | ||
37 | + { | ||
38 | + type: 'add', | ||
39 | + path: `${process.cwd()}/src/packages/components/external/Charts/Bars${dataName}/data.json`, | ||
40 | + templateFile: './component-template/data.json.hbs', | ||
41 | + data: { | ||
42 | + name: data.name | ||
43 | + } | ||
44 | + }, | ||
45 | + { | ||
46 | + type: 'add', | ||
47 | + path: `${process.cwd()}/src/packages/components/external/Charts/Bars${dataName}/index.ts`, | ||
48 | + templateFile: './component-template/index.ts.hbs', | ||
49 | + data: { | ||
50 | + name: data.name | ||
51 | + } | ||
52 | + }, | ||
53 | + { | ||
54 | + type: 'add', | ||
55 | + path: `${process.cwd()}/src/packages/components/external/Charts/Bars${dataName}/index.vue`, | ||
56 | + templateFile: './component-template/index.vue.hbs', | ||
57 | + data: { | ||
58 | + name: data.name | ||
59 | + } | ||
60 | + } | ||
61 | + ] | ||
62 | + | ||
63 | + return actions | ||
64 | + } | ||
65 | +} |