Commit eebc69c2231fbd01f7aaeaff777eb912bf863370
Merge branch 'ft' into 'main_dev'
feat: 新增plopjs配置,为此项目快速生成组件模板,比如需要新加一个组件,直接快速生成配置代码 See merge request yunteng/thingskit-view!132
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 | +} |