Pre Merge pull request !28 from 陪伴是最长情的告白¹³¹⁴/dev

This commit is contained in:
陪伴是最长情的告白¹³¹⁴ 2022-08-10 08:05:58 +00:00 committed by Gitee
commit 4c502fd393
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
78 changed files with 5849 additions and 1277 deletions

View File

@ -13,9 +13,14 @@ module.exports = {
}, },
}, },
env: { env: {
'vue/setup-compiler-macros': true,
node: true, node: true,
}, },
extends: ["plugin:vue/vue3-essential", "eslint:recommended"], extends: [
"plugin:vue/vue3-essential",
"eslint:recommended",
"./.eslintrc-auto-import.json"
],
rules: { rules: {
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off", "no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off", "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",

6
.gitignore vendored
View File

@ -1,6 +1,12 @@
node_modules node_modules
.history
.husky
.DS_Store .DS_Store
dist dist
dist-ssr dist-ssr
*.local *.local
.vscode .vscode
stats.html
auto-imports.d.ts
.eslintrc-auto-import.json
components.d.ts

View File

@ -1,4 +0,0 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no-install commitlint -e

View File

@ -3,29 +3,33 @@
"version": "1.0.6", "version": "1.0.6",
"scripts": { "scripts": {
"dev": "vite --host", "dev": "vite --host",
"build": "vue-tsc --noEmit && vite build", "build": "rimraf ./dist && npm run test && vite build",
"preview": "vite preview", "preview": "vite preview",
"new": "plop --plopfile ./plop/plopfile.js", "new": "plop --plopfile ./plop/plopfile.js",
"test": "vue-tsc --noEmit",
"postinstall": "husky install" "postinstall": "husky install"
}, },
"dependencies": { "dependencies": {
"@types/color": "^3.0.3", "@vicons/carbon": "^0.12.0",
"@types/crypto-js": "^4.1.1", "@vicons/ionicons5": "~0.11.0",
"@types/keymaster": "^1.6.30", "@vueuse/core": "^7.7.1",
"animate.css": "^4.1.1", "animate.css": "^4.1.1",
"axios": "^0.27.2", "axios": "^0.27.2",
"color": "^4.2.3", "color": "^4.2.3",
"crypto-js": "^4.1.1", "crypto-js": "^4.1.1",
"echarts": "^5.3.2",
"echarts-liquidfill": "^3.1.0", "echarts-liquidfill": "^3.1.0",
"highlight.js": "^11.5.0", "highlight.js": "^11.5.0",
"html2canvas": "^1.4.1", "html2canvas": "^1.4.1",
"keymaster": "^1.6.2", "keymaster": "^1.6.2",
"lodash": "~4.17.21",
"monaco-editor": "^0.33.0", "monaco-editor": "^0.33.0",
"naive-ui": "2.30.3", "naive-ui": "2.30.3",
"pinia": "^2.0.13", "pinia": "^2.0.13",
"screenfull": "^6.0.1", "screenfull": "^6.0.1",
"tiny-emitter": "^2.1.0",
"vue": "^3.2.31", "vue": "^3.2.31",
"vue-demi": "^0.13.1", "vue-echarts": "^6.0.2",
"vue-i18n": "9.1.9", "vue-i18n": "9.1.9",
"vue-router": "4.0.12", "vue-router": "4.0.12",
"vue3-lazyload": "^0.2.5-beta", "vue3-lazyload": "^0.2.5-beta",
@ -35,37 +39,35 @@
"devDependencies": { "devDependencies": {
"@commitlint/cli": "^17.0.2", "@commitlint/cli": "^17.0.2",
"@commitlint/config-conventional": "^17.0.2", "@commitlint/config-conventional": "^17.0.2",
"@types/node": "^16.11.26", "@types/color": "^3.0.3",
"@types/crypto-js": "^4.1.1",
"@types/keymaster": "^1.6.30",
"@typescript-eslint/eslint-plugin": "^5.18.0", "@typescript-eslint/eslint-plugin": "^5.18.0",
"@typescript-eslint/parser": "^5.18.0", "@typescript-eslint/parser": "^5.18.0",
"@vicons/carbon": "^0.12.0",
"@vicons/ionicons5": "~0.11.0",
"@vitejs/plugin-vue": "^1.10.2", "@vitejs/plugin-vue": "^1.10.2",
"@vitejs/plugin-vue-jsx": "^1.3.9", "@vitejs/plugin-vue-jsx": "^1.3.9",
"@vue/compiler-sfc": "^3.2.31", "@vue/compiler-sfc": "^3.2.31",
"@vueuse/core": "^7.7.1",
"commitlint": "^17.0.2", "commitlint": "^17.0.2",
"default-passive-events": "^2.0.0",
"echarts": "^5.3.2",
"eslint": "^8.12.0", "eslint": "^8.12.0",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0", "eslint-plugin-import": "^2.26.0",
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.5.0", "eslint-plugin-vue": "^8.5.0",
"husky": "^8.0.1", "husky": "^8.0.1",
"lodash": "~4.17.21",
"mockjs": "^1.1.0", "mockjs": "^1.1.0",
"plop": "^3.0.5", "plop": "^3.0.5",
"prettier": "^2.6.2", "prettier": "^2.6.2",
"rollup-plugin-visualizer": "^5.7.1",
"sass": "^1.49.11", "sass": "^1.49.11",
"sass-loader": "^12.6.0", "sass-loader": "^12.6.0",
"typescript": "^4.6.3", "typescript": "^4.6.3",
"unplugin-auto-import": "^0.10.1",
"unplugin-vue-components": "^0.21.1",
"vite": "2.9.5", "vite": "2.9.5",
"vite-plugin-compression": "^0.5.1", "vite-plugin-compression": "^0.5.1",
"vite-plugin-importer": "^0.2.5", "vite-plugin-imagemin": "^0.6.1",
"vite-plugin-mock": "^2.9.6", "vite-plugin-mock": "^2.9.6",
"vite-plugin-monaco-editor": "^1.1.0", "vite-plugin-monaco-editor": "^1.1.0",
"vue-echarts": "^6.0.2",
"vue-tsc": "^0.28.10" "vue-tsc": "^0.28.10"
} }
} }

View File

@ -0,0 +1,14 @@
import { CreateComponentType } from '@/packages/index.d';
import { publicConfig } from '@/packages/public/publicConfig';
import { ComponentConfig } from './index'
import cloneDeep from 'lodash/cloneDeep'
export const option = {
}
export default class Config extends publicConfig implements CreateComponentType
{
public key = ComponentConfig.key
public chartConfig = cloneDeep(ComponentConfig)
public option = cloneDeep(option)
}

View File

@ -0,0 +1,27 @@
<template>
<CollapseItem>
<SettingItem>
<SettingItemBox></SettingItemBox>
</SettingItem>
</CollapseItem>
</template>
<script setup lang="ts">
import { PropType } from 'vue'
import {
CollapseItem,
SettingItemBox,
SettingItem
} from '@/components/Pages/ChartItemSetting'
import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
const props = defineProps({
optionData: {
type: Object as PropType<GlobalThemeJsonType>,
required: true
}
})
</script>
<style></style>

View File

@ -0,0 +1,13 @@
import { FormCategoryEnum, FormCategoryEnumName } from './../../index.d';
import { PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d';
import { getComponentConfig } from '@/utils/componets';
export const ComponentConfig = getComponentConfig({
key: 'InputCommon',
title: '输入框',
category: FormCategoryEnum.INPUT,
categoryName: FormCategoryEnumName.INPUT,
package: PackagesCategoryEnum.FORM,
chartFrame: ChartFrameEnum.COMMON
})

View File

@ -0,0 +1,18 @@
<template>
<div>your component</div>
</template>
<script setup lang="ts">
import { PropType } from 'vue'
import { CreateComponentType } from '@/packages/index.d'
const props = defineProps({
chartConfig: {
type: Object as PropType<CreateComponentType>,
required: true
}
})
</script>
<style></style>

5189
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

BIN
readme/event-design.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 KiB

View File

@ -7,22 +7,30 @@
size="small" size="small"
></n-switch> ></n-switch>
</template> </template>
<setting-item-box name="标题"> <setting-item-box name="属性" :alone="true">
<setting-item name="颜色"> <setting-item name="文本">
<n-color-picker <n-input v-model:value="title.text" size="small" type="text"></n-input>
v-model:value="title.textStyle.color"
size="small"
></n-color-picker>
</setting-item>
<setting-item name="大小">
<n-input-number
v-model:value="title.textStyle.fontSize"
:min="1"
size="small"
></n-input-number>
</setting-item> </setting-item>
<!-- <setting-item name="textAlign">
<n-select v-model:value="title.textAlign" size="small" :options="textAlignOptions" />
</setting-item> -->
<template v-if="title.textStyle">
<setting-item name="颜色">
<n-color-picker
v-model:value="title.textStyle.color"
size="small"
></n-color-picker>
</setting-item>
<setting-item name="大小">
<n-input-number
v-model:value="title.textStyle.fontSize"
:min="1"
size="small"
></n-input-number>
</setting-item>
</template>
</setting-item-box> </setting-item-box>
<setting-item-box name="副标题"> <setting-item-box name="副标题" v-if="title.subtextStyle">
<setting-item name="颜色"> <setting-item name="颜色">
<n-color-picker <n-color-picker
size="small" size="small"
@ -374,4 +382,11 @@ const yAxis = computed(() => {
const legend = computed(() => { const legend = computed(() => {
return props.optionData.legend return props.optionData.legend
}) })
const textAlignOptions = [
{label: '自动', value: 'auto'},
{label: '左对齐', value: 'left'},
{label: '右对齐', value: 'right'},
{label: '居中对齐', value: 'center'},
]
</script> </script>

View File

@ -1,7 +1,6 @@
<template></template> <template></template>
<script setup> <script setup>
import * as monaco from 'monaco-editor'
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker' import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker' import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'
import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker' import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'

View File

@ -1,11 +1,11 @@
import { ref, onBeforeUnmount, nextTick } from 'vue' import { ref, onBeforeUnmount, nextTick } from 'vue'
import { useDesignStore } from '@/store/modules/designStore/designStore' import { useDesignStore } from '@/store/modules/designStore/designStore'
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js' import { editor } from 'monaco-editor/esm/vs/editor/editor.api.js'
export const useMonacoEditor = (language = 'javascript') => { export const useMonacoEditor = (language = 'javascript') => {
const designStore = useDesignStore() const designStore = useDesignStore()
let monacoEditor: monaco.editor.IStandaloneCodeEditor | null = null let monacoEditor: editor.IStandaloneCodeEditor | null = null
let initReadOnly = false let initReadOnly = false
const el = ref<HTMLElement | null>(null) const el = ref<HTMLElement | null>(null)
@ -25,12 +25,12 @@ const designStore = useDesignStore()
} }
// 创建实例 // 创建实例
const createEditor = (editorOption: monaco.editor.IStandaloneEditorConstructionOptions = {}) => { const createEditor = (editorOption: editor.IStandaloneEditorConstructionOptions = {}) => {
if (!el.value) return if (!el.value) return
const javascriptModel = monaco.editor.createModel('', language) const javascriptModel = editor.createModel('', language)
initReadOnly = !!editorOption.readOnly initReadOnly = !!editorOption.readOnly
// 创建 // 创建
monacoEditor = monaco.editor.create(el.value, { monacoEditor = editor.create(el.value, {
model: javascriptModel, model: javascriptModel,
// 是否启用预览图 // 是否启用预览图
minimap: { enabled: false }, minimap: { enabled: false },

View File

@ -0,0 +1,13 @@
export enum COMPONENT_SIZE_ENUM {
TINY = 'tiny',
SMALL = 'small',
MEDIUM = 'medium',
LARGE = 'large'
}
export const componentSizeMap = new Map([
[COMPONENT_SIZE_ENUM.TINY, '迷你'],
[COMPONENT_SIZE_ENUM.SMALL, '小'],
[COMPONENT_SIZE_ENUM.MEDIUM, '中'],
[COMPONENT_SIZE_ENUM.LARGE, '大'],
])

54
src/enums/eventEnum.ts Normal file
View File

@ -0,0 +1,54 @@
export enum EventType {
CLICK = 'click',
DBCLICK = 'dblclick',
CHANGE = 'change',
// MOUSE_ENTER = 'mouseenter',
// MOUSE_LEAVE = 'mouseleave',
MOUNTED = 'vnodeMounted',
// OTHER = 'other'
}
export const EventTypeTitle = {
[EventType.CLICK]: '点击',
[EventType.DBCLICK]: '双击',
[EventType.CHANGE]: '值变化',
// [EventType.MOUSE_ENTER]: '鼠标进入',
// [EventType.MOUSE_LEAVE]: '鼠标移开',
[EventType.MOUNTED]: '渲染完成',
// [EventType.OTHER]: '其它',
}
export enum EventTriggerType {
COMPONENT = 'component',
JAVASCRIPT = 'javascript'
}
export const EventTriggerTypeMap = new Map(
[
[EventTriggerType.COMPONENT, '组件联动'],
[EventTriggerType.JAVASCRIPT, '自定义js'],
]
)
// 数据组件事件
export enum DATA_COMPONENT_EVENT_ENUM {
LOAD_DATA ='loadData'
}
export const dataComponentEventMap = new Map(
[
[DATA_COMPONENT_EVENT_ENUM.LOAD_DATA, '加载数据'],
]
)
// 公共事件
export enum COMMON_EVENT_ENUM {
FORCE_UPDATE ='forceUpdate'
}
export const CommonEventMap = new Map(
[
[COMMON_EVENT_ENUM.FORCE_UPDATE, '强制更新'],
]
)

View File

@ -12,5 +12,7 @@ export enum StorageEnum {
// 工作台布局配置 // 工作台布局配置
GO_CHART_LAYOUT_STORE = 'GO_CHART_LAYOUT', GO_CHART_LAYOUT_STORE = 'GO_CHART_LAYOUT',
// 工作台需要保存的数据 // 工作台需要保存的数据
GO_CHART_STORAGE_LIST = 'GO_CHART_STORAGE_LIST' GO_CHART_STORAGE_LIST = 'GO_CHART_STORAGE_LIST',
// 数据收集
GO_DATA_COLLECT = 'GO_DATA_COLLECT'
} }

View File

@ -2,3 +2,4 @@ export * from '@/hooks/useTheme.hook'
export * from '@/hooks/usePreviewScale.hook' export * from '@/hooks/usePreviewScale.hook'
export * from '@/hooks/useCode.hook' export * from '@/hooks/useCode.hook'
export * from '@/hooks/useChartDataFetch.hook' export * from '@/hooks/useChartDataFetch.hook'
export * from '@/hooks/useEventBus.hook'

View File

@ -5,6 +5,7 @@ import { CreateComponentType, ChartFrameEnum } from '@/packages/index.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { RequestDataTypeEnum } from '@/enums/httpEnum' import { RequestDataTypeEnum } from '@/enums/httpEnum'
import { isPreview, newFunctionHandle, intervalUnitHandle } from '@/utils' import { isPreview, newFunctionHandle, intervalUnitHandle } from '@/utils'
import { useIntervalFn } from '@vueuse/core'
// 获取类型 // 获取类型
type ChartEditStoreType = typeof useChartEditStore type ChartEditStoreType = typeof useChartEditStore
@ -21,11 +22,17 @@ export const useChartDataFetch = (
updateCallback?: (...args: any) => any updateCallback?: (...args: any) => any
) => { ) => {
const vChartRef = ref<typeof VChart | null>(null) const vChartRef = ref<typeof VChart | null>(null)
let fetchInterval: any = 0 let pauseFn: any = null
let resumeFn: any = null
let fetchFn: any = null
const requestIntervalFn = () => { const requestIntervalFn = () => {
const chartEditStore = useChartEditStore() const chartEditStore = useChartEditStore()
pauseFn = null
resumeFn = null
fetchFn = null
// 全局数据 // 全局数据
const { const {
requestOriginUrl, requestOriginUrl,
@ -55,9 +62,7 @@ export const useChartDataFetch = (
const completePath = requestOriginUrl && requestOriginUrl.value + requestUrl.value const completePath = requestOriginUrl && requestOriginUrl.value + requestUrl.value
if (!completePath) return if (!completePath) return
clearInterval(fetchInterval) fetchFn = async (callback: () => any) => {
const fetchFn = async () => {
const res = await customizeHttp(toRaw(targetComponent.request), toRaw(chartEditStore.requestGlobalConfig)) const res = await customizeHttp(toRaw(targetComponent.request), toRaw(chartEditStore.requestGlobalConfig))
if (res && res.data) { if (res && res.data) {
try { try {
@ -73,6 +78,7 @@ export const useChartDataFetch = (
} }
} }
} }
callback && callback()
} catch (error) { } catch (error) {
console.error(error) console.error(error)
} }
@ -87,11 +93,17 @@ export const useChartDataFetch = (
// 单位 // 单位
const unit = targetInterval && targetInterval.value ? targetUnit.value : globalUnit.value const unit = targetInterval && targetInterval.value ? targetUnit.value : globalUnit.value
// 开启轮询 // 开启轮询
if (time) fetchInterval = setInterval(fetchFn, intervalUnitHandle(time, unit)) if (time) {
const { pause, resume, isActive } = useIntervalFn(fetchFn, intervalUnitHandle(time, unit))
pauseFn = pause
resumeFn = resume
}
} }
} catch (error) {} } catch (error) {
console.error(error)
}
} }
isPreview() && requestIntervalFn() isPreview() && requestIntervalFn()
return { vChartRef } return { vChartRef, pauseFn, resumeFn, fetchFn }
} }

View File

@ -0,0 +1,67 @@
import Emitter from 'tiny-emitter'
import { onBeforeUnmount } from 'vue'
/**
* {
* on: {
* [event]: []
* },
* }
*/
type EventBusListeners = {
[key: string]: () => any
};
export type EventBusOptions = {
on?: EventBusListeners
once?: EventBusListeners
}
//@ts-ignore
const bus = new Emitter()
const addListeners = (listeners: EventBusListeners | undefined, isOnce = false): void => {
if(!listeners) return
Object.keys(listeners).forEach(key => {
console.info('监听事件:', key)
bus[isOnce ? 'once' : 'on'](key, listeners[key])
onBeforeUnmount(() => {
bus.off(key, listeners[key])
})
})
}
// 转换事件名
const convertListeners = (listeners: EventBusListeners, dst: object, prefix = 'prefix'): void => {
Object.keys(listeners).forEach((key: string) => {
// @ts-ignore
dst[`${prefix}:${key}`] = listeners[key]
})
}
export const convertEventBusListeners = (listeners: EventBusOptions, prefix: string): EventBusOptions => {
const res = {
on: {},
once: {},
}
if(listeners.on) {
convertListeners(listeners.on, res.on, prefix)
}
if(listeners.once) {
convertListeners(listeners.once, res.once, prefix)
}
return res
}
export const useEventBus = (listeners: EventBusOptions = {}) => {
addListeners(listeners.on);
addListeners(listeners.once, true)
return bus
}

View File

@ -20,7 +20,7 @@ async function appInit() {
const app = createApp(App) const app = createApp(App)
// 注册全局常用的 naive-ui 组件 // 注册全局常用的 naive-ui 组件
setupNaive(app) // setupNaive(app)
// 注册全局自定义指令 // 注册全局自定义指令
setupDirectives(app) setupDirectives(app)

View File

@ -0,0 +1,13 @@
import { dataComponentEventMap } from '@/enums/eventEnum';
import { OptionsType } from '@/packages/index.d';
import { mapToOptions } from '@/utils';
//内置方法
export const methodList = mapToOptions(dataComponentEventMap) as Array<OptionsType>
export const config = {
key: 'BarCommon',
title: '柱状图',
methodList
}

View File

@ -1,15 +1,14 @@
import image from '@/assets/images/chart/charts/bar_x.png' import image from '@/assets/images/chart/charts/bar_x.png'
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d' import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
import { getComponentConfig } from '@/utils'
import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d' import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
import { config } from './enum'
export const BarCommonConfig: ConfigType = { export const BarCommonConfig: ConfigType = getComponentConfig({
key: 'BarCommon', ...config,
chartKey: 'VBarCommon',
conKey: 'VCBarCommon',
title: '柱状图',
category: ChatCategoryEnum.BAR, category: ChatCategoryEnum.BAR,
categoryName: ChatCategoryEnumName.BAR, categoryName: ChatCategoryEnumName.BAR,
package: PackagesCategoryEnum.CHARTS, package: PackagesCategoryEnum.CHARTS,
chartFrame: ChartFrameEnum.ECHARTS, chartFrame: ChartFrameEnum.ECHARTS,
image image
} })

View File

@ -49,5 +49,15 @@ const option = computed(() => {
return mergeTheme(props.chartConfig.option, props.themeSetting, includes) return mergeTheme(props.chartConfig.option, props.themeSetting, includes)
}) })
const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore) const { vChartRef, pauseFn, resumeFn, fetchFn } = useChartDataFetch(props.chartConfig, useChartEditStore)
defineExpose({
loadData: async () => {
if(fetchFn){
pauseFn()
await fetchFn()
resumeFn()
}
}
})
</script> </script>

View File

@ -0,0 +1,41 @@
import { FunnelConfig } from './index'
import dataJson from './data.json'
import { echartOptionProfixHandle, publicConfig } from '@/packages/public'
import { CreateComponentType } from '@/packages/index.d'
import cloneDeep from 'lodash/cloneDeep'
export const includes = ['legend']
export const option = {
title: {
textStyle: {},
},
legend: {},
color: [
'#142f53', '#13407e', '#0f62d4', '#0c73ff'
],
tooltip: {
show: true,
trigger: 'item',
},
dataset: {
...dataJson
},
series: {
sort: 'descending',
orient: 'vertical',
type: 'funnel',
label: {
show: true,
position: 'inside'
}
},
}
export default class Config extends publicConfig implements CreateComponentType {
public key = FunnelConfig.key
public chartConfig = cloneDeep(FunnelConfig)
// 图表配置项
public option = echartOptionProfixHandle(option, includes)
}

View File

@ -1,6 +1,64 @@
<template> <template>
<CollapseItem
name="朝向">
<template #header>
<n-switch
checked-value="vertical"
unchecked-value="horizontal"
v-model:value="props.optionData.series.orient"
>
<template #checked>
垂直
</template>
<template #unchecked>
水平
</template>
</n-switch>
</template>
</CollapseItem>
<CollapseItem
name="排序">
<template #header>
<n-switch
checked-value="descending"
unchecked-value="ascending"
v-model:value="props.optionData.series.sort"
>
<template #checked>
降序
</template>
<template #unchecked>
升序
</template>
</n-switch>
</template>
</CollapseItem>
<CollapseItem
name="间隔"
:expanded="true">
<n-slider v-model:value="props.optionData.series.gap" />
</CollapseItem>
<!-- Echarts 全局设置 -->
<global-setting :optionData="optionData" :in-chart="true"></global-setting>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { PropType } from 'vue'
import {
GlobalSetting,
CollapseItem,
SettingItemBox,
SettingItem
} from '@/components/Pages/ChartItemSetting'
import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
const props = defineProps({
optionData: {
type: Object as PropType<GlobalThemeJsonType>,
required: true
}
})
</script> </script>

View File

@ -0,0 +1,9 @@
{
"source": [
["name","value"],
["Visit", 20],
["Inquiry", 40],
["Order", 60],
["Click", 80]
]
}

View File

@ -1,14 +1,14 @@
import { getComponentConfig } from './../../../../../utils/componets';
import image from '@/assets/images/chart/charts/funnel.png' import image from '@/assets/images/chart/charts/funnel.png'
import { ConfigType, PackagesCategoryEnum } from '@/packages/index.d' import { ConfigType, PackagesCategoryEnum } from '@/packages/index.d'
import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d' import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
export const FunnelConfig: ConfigType = { export const FunnelConfig: ConfigType = getComponentConfig({
key: 'Funnel', key: 'Funnel',
chartKey: 'VFunnel',
conKey: 'VCFunnel',
title: '漏斗图', title: '漏斗图',
category: ChatCategoryEnum.MORE, category: ChatCategoryEnum.MORE,
categoryName: ChatCategoryEnumName.MORE, categoryName: ChatCategoryEnumName.MORE,
package: PackagesCategoryEnum.CHARTS, package: PackagesCategoryEnum.CHARTS,
image image
} })

View File

@ -1,10 +1,55 @@
<template> <template>
<div> <v-chart ref="vChartRef" :theme="themeColor" :option="option" :manual-update="isPreview()" autoresize></v-chart>
水波
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, PropType } from 'vue'
import VChart from 'vue-echarts'
import { use } from 'echarts/core'
import { FunnelChart } from 'echarts/charts'
import {
DatasetComponent,
LegendComponent,
TitleComponent,
TooltipComponent
} from 'echarts/components'
import { useChartDataFetch } from '@/hooks'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { mergeTheme } from '@/packages/public/chart'
import { isPreview } from '@/utils'
import { CreateComponentType } from '@/packages/index.d'
import { includes } from './config'
const props = defineProps({
themeSetting: {
type: Object,
required: true
},
themeColor: {
type: Object,
required: true
},
chartConfig: {
type: Object as PropType<CreateComponentType>,
required: true
}
})
use([
DatasetComponent,
LegendComponent,
TitleComponent,
TooltipComponent,
FunnelChart
])
const option = computed(() => {
return mergeTheme(props.chartConfig.option, props.themeSetting, includes)
})
const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore)
</script> </script>

View File

@ -5,7 +5,7 @@ import cloneDeep from 'lodash/cloneDeep'
export const option = { export const option = {
colors: ['#1089ff', '#0000ff'], colors: ['#1089ff', '#0000ff'],
backgroundColor: '#00000000' backgroundColor: '#000000'
} }
export default class Config extends publicConfig implements CreateComponentType { export default class Config extends publicConfig implements CreateComponentType {

View File

@ -1,5 +1,5 @@
import { publicConfig } from '@/packages/public' import { publicConfig } from '@/packages/public'
import { CreateComponentType } from '@/packages/index.d' import { CreateComponentType, EventConfig, OptionsType } from '@/packages/index.d'
import { Decorates04Config } from './index' import { Decorates04Config } from './index'
import cloneDeep from 'lodash/cloneDeep' import cloneDeep from 'lodash/cloneDeep'

View File

@ -0,0 +1,14 @@
import { CreateComponentType } from '@/packages/index.d';
import { publicConfig } from '@/packages/public/publicConfig';
import { DatePickerCommonConfig } from './index'
import cloneDeep from 'lodash/cloneDeep'
export const option = {
}
export default class Config extends publicConfig implements CreateComponentType
{
public key = DatePickerCommonConfig.key
public chartConfig = cloneDeep(DatePickerCommonConfig)
public option = cloneDeep(option)
}

View File

@ -0,0 +1,7 @@
<template>
<div>config</div>
</template>
<script setup lang="ts"></script>
<style></style>

View File

@ -0,0 +1,13 @@
import { FormCategoryEnum, FormCategoryEnumName } from '../../index.d';
import { PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d';
import { getComponentConfig } from '@/utils/componets';
export const DatePickerCommonConfig = getComponentConfig({
key: 'DatePickerCommon',
title: '日期选择',
category: FormCategoryEnum.DATE_PICKER,
categoryName: FormCategoryEnumName.DATE_PICKER,
package: PackagesCategoryEnum.FORM,
chartFrame: ChartFrameEnum.COMMON
})

View File

@ -0,0 +1,13 @@
<template>
<div>
<span>DATE_PICKER</span>
</div>
</template>
<script setup lang='ts'>
defineProps({})
</script>
<style>
</style>

View File

@ -0,0 +1,3 @@
import { DatePickerCommonConfig } from './DatePickerCommon/index'
export default [ DatePickerCommonConfig ]

View File

@ -0,0 +1,24 @@
import { CreateComponentType } from '@/packages/index.d';
import { publicConfig } from '@/packages/public/publicConfig';
import { InputCommonConfig } from './index'
import cloneDeep from 'lodash/cloneDeep'
import { COMPONENT_SIZE_ENUM } from '@/enums/componentEnum';
export const option = {
// 参考 https://www.naiveui.com/zh-CN/os-theme/components/input
inputOption: {
clearable: true,
maxlength: 20,
placeholder: '',
round: false,
showCount: false,
size: COMPONENT_SIZE_ENUM.MEDIUM
}
}
export default class Config extends publicConfig implements CreateComponentType
{
public key = InputCommonConfig.key
public chartConfig = cloneDeep(InputCommonConfig)
public option = cloneDeep(option)
}

View File

@ -0,0 +1,48 @@
<template>
<CollapseItem name="属性配置" :expanded="true">
<n-form label-placement="left" label-align="right" label-width="auto">
<n-form-item label="可清空">
<n-switch v-model:value="inputOption.clearable"></n-switch>
</n-form-item>
<n-form-item label="最大长度">
<n-input-number v-model:value="inputOption.maxlength" :min="0" :max="200" :precision="0"/>
</n-form-item>
<n-form-item label="placeholder">
<n-input v-model:value="inputOption.placeholder"/>
</n-form-item>
<n-form-item label="圆角">
<n-switch v-model:value="inputOption.round"></n-switch>
</n-form-item>
<n-form-item label="显示字数统计">
<n-switch v-model:value="inputOption.showCount"></n-switch>
</n-form-item>
<n-form-item label="尺寸">
<n-select v-model:value="inputOption.size" :options="mapToOptions(componentSizeMap)"></n-select>
</n-form-item>
</n-form>
</CollapseItem>
</template>
<script setup lang="ts">
import { PropType, toRefs } from 'vue'
import {
CollapseItem,
SettingItemBox,
SettingItem
} from '@/components/Pages/ChartItemSetting'
import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
import { mapToOptions } from '@/utils';
import { componentSizeMap } from '@/enums/componentEnum'
const props = defineProps({
optionData: {
type: Object as PropType<GlobalThemeJsonType>,
required: true
}
})
const { inputOption } = toRefs(props.optionData)
</script>
<style></style>

View File

@ -0,0 +1,13 @@
import { FormCategoryEnum, FormCategoryEnumName } from './../../index.d';
import { PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d';
import { getComponentConfig } from '@/utils/componets';
export const InputCommonConfig = getComponentConfig({
key: 'InputCommon',
title: '输入框',
category: FormCategoryEnum.INPUT,
categoryName: FormCategoryEnumName.INPUT,
package: PackagesCategoryEnum.FORM,
chartFrame: ChartFrameEnum.COMMON
})

View File

@ -0,0 +1,23 @@
<template>
<n-form-item>
<n-input v-bind="inputOption" v-model:value="val"/>
</n-form-item>
</template>
<script setup lang="ts">
import { PropType, computed, ref } from 'vue'
import { CreateComponentType } from '@/packages/index.d'
const props = defineProps({
chartConfig: {
type: Object as PropType<CreateComponentType>,
required: true
}
})
const inputOption = computed(() => props.chartConfig.option.inputOption)
const val = ref('')
</script>
<style></style>

View File

@ -0,0 +1,3 @@
import { InputCommonConfig } from './InputCommon/index'
export default [ InputCommonConfig ]

View File

@ -0,0 +1,14 @@
import { CreateComponentType } from '@/packages/index.d';
import { publicConfig } from '@/packages/public/publicConfig';
import { SelectCommonConfig } from './index'
import cloneDeep from 'lodash/cloneDeep'
export const option = {
}
export default class Config extends publicConfig implements CreateComponentType
{
public key = SelectCommonConfig.key
public chartConfig = cloneDeep(SelectCommonConfig)
public option = cloneDeep(option)
}

View File

@ -0,0 +1,7 @@
<template>
<div>config</div>
</template>
<script setup lang="ts"></script>
<style></style>

View File

@ -0,0 +1,13 @@
import { FormCategoryEnum, FormCategoryEnumName } from './../../index.d';
import { PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d';
import { getComponentConfig } from '@/utils/componets';
export const SelectCommonConfig = getComponentConfig({
key: 'SelectCommon',
title: '下拉框',
category: FormCategoryEnum.SELECT,
categoryName: FormCategoryEnumName.SELECT,
package: PackagesCategoryEnum.FORM,
chartFrame: ChartFrameEnum.COMMON
})

View File

@ -0,0 +1,13 @@
<template>
<div>
select
</div>
</template>
<script setup lang='ts'>
defineProps({})
</script>
<style>
</style>

View File

@ -0,0 +1,3 @@
import { SelectCommonConfig } from './SelectCommon/index'
export default [ SelectCommonConfig ]

13
src/packages/components/Form/index.d.ts vendored Normal file
View File

@ -0,0 +1,13 @@
export enum FormCategoryEnum {
INPUT = 'Inputs',
SELECT = 'Selects',
DATE_PICKER = 'DatePickers',
MORE = 'Mores'
}
export enum FormCategoryEnumName {
INPUT = '输入框',
SELECT = '下拉框',
DATE_PICKER = '日期选择',
MORE = '更多'
}

View File

@ -0,0 +1,5 @@
import Inputs from './Inputs'
import DatePickers from './DatePickers'
import Selects from './Selects'
export const FormList = [...Inputs, ...DatePickers, ...Selects]

View File

@ -62,7 +62,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { PropType } from 'vue' import { PropType, toRefs } from 'vue'
import { option, WritingModeEnum, WritingModeObject } from './config' import { option, WritingModeEnum, WritingModeObject } from './config'
import { import {
CollapseItem, CollapseItem,
@ -77,6 +77,8 @@ const props = defineProps({
} }
}) })
const { optionData} = toRefs(props)
const verticalOptions = [{ const verticalOptions = [{
label: WritingModeEnum.HORIZONTAL, label: WritingModeEnum.HORIZONTAL,
value: WritingModeObject[WritingModeEnum.HORIZONTAL] value: WritingModeObject[WritingModeEnum.HORIZONTAL]

View File

@ -0,0 +1,25 @@
import { OptionsType } from '@/packages/index.d';
import { mapToOptions } from '@/utils';
// 内置方法
export enum TextCommonEventEnum {
FOO = 'foo',
BAR = 'bar'
}
//内置事件
export const methodList = mapToOptions(new Map([
[TextCommonEventEnum.FOO, '内置方法'],
])) as Array<OptionsType>
export const eventList = mapToOptions(new Map([
[TextCommonEventEnum.BAR, 'setup'],
])) as Array<OptionsType>
export const TextConfig = {
key: 'TextCommon',
title: '文字',
methodList
}

View File

@ -1,14 +1,16 @@
import { getComponentConfig } from '@/utils';
import image from '@/assets/images/chart/informations/text_static.png' import image from '@/assets/images/chart/informations/text_static.png'
import { ConfigType, PackagesCategoryEnum } from '@/packages/index.d' import { ConfigType, PackagesCategoryEnum } from '@/packages/index.d'
import { ChatCategoryEnum,ChatCategoryEnumName } from '../../index.d' import { ChatCategoryEnum,ChatCategoryEnumName } from '../../index.d'
import { TextConfig, methodList, eventList } from './enum'
export const TextCommonConfig: ConfigType = { export const TextCommonConfig: ConfigType = getComponentConfig({
key: 'TextCommon', key: TextConfig.key,
chartKey: 'VTextCommon', title: TextConfig.title,
conKey: 'VCTextCommon',
title: '文字',
category: ChatCategoryEnum.TEXT, category: ChatCategoryEnum.TEXT,
categoryName: ChatCategoryEnumName.TEXT, categoryName: ChatCategoryEnumName.TEXT,
package: PackagesCategoryEnum.INFORMATIONS, package: PackagesCategoryEnum.INFORMATIONS,
methodList,
eventList,
image image
} })

View File

@ -22,9 +22,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { PropType, toRefs, shallowReactive, watch } from 'vue' import { PropType, toRefs, shallowReactive, watch } from 'vue'
import { CreateComponentType } from '@/packages/index.d' import { CreateComponentType } from '@/packages/index.d'
import { useChartDataFetch } from '@/hooks' import { useChartDataFetch, useEventBus, convertEventBusListeners } from '@/hooks'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { option as configOption } from './config' import { option as configOption } from './config'
import { TextCommonEventEnum } from './enum'
const props = defineProps({ const props = defineProps({
chartConfig: { chartConfig: {
@ -33,6 +34,20 @@ const props = defineProps({
} }
}) })
const emits = defineEmits([TextCommonEventEnum.BAR])
emits(TextCommonEventEnum.BAR, 'setup event')
const listeners = convertEventBusListeners({
on: {
[TextCommonEventEnum.FOO]: () => {
alert('触发方法')
}
}
}, props.chartConfig.id)
useEventBus(listeners)
const { w, h } = toRefs(props.chartConfig.attr) const { w, h } = toRefs(props.chartConfig.attr)
const { const {
dataset, dataset,

View File

@ -1,5 +1,7 @@
import type { GlobalThemeJsonType } from '@/settings/chartThemes/index' import type { GlobalThemeJsonType } from '@/settings/chartThemes/index'
import type { RequestConfigType } from '@/store/modules/chartEditStore/chartEditStore.d' import type { RequestConfigType } from '@/store/modules/chartEditStore/chartEditStore.d'
import { EventType } from '@/enums/eventEnum';
export enum ChartFrameEnum { export enum ChartFrameEnum {
// echarts 框架 // echarts 框架
@ -12,8 +14,15 @@ export enum ChartFrameEnum {
STATIC = 'static' STATIC = 'static'
} }
export type OptionsType = {
label: string
value: string
[key: string]: string
}
// 组件配置 // 组件配置
export type ConfigType = { export type ConfigType = {
id?: string
key: string key: string
chartKey: string chartKey: string
conKey: string conKey: string
@ -22,7 +31,29 @@ export type ConfigType = {
categoryName: string categoryName: string
package: string package: string
chartFrame?: ChartFrameEnum chartFrame?: ChartFrameEnum
image: string | (() => Promise<typeof import('*.png')>) methodList?: Array<OptionsType>
eventList?: Array<OptionsType>
image?: string | (() => Promise<typeof import('*.png')>)
}
export type MethodList = Array<{
name: string,
event: string,
type: string,
code: string,
uid: string,
[key: string]: any
}>
export type EventConfigValue = Record<string, {
title: string,
methodList: MethodList
}>
export type EventConfig = {
[key: EventType]: EventConfigValue
} }
// 数据请求 // 数据请求
@ -83,11 +114,20 @@ export interface PublicConfigType extends requestConfig {
filter?: string filter?: string
setPosition: Function setPosition: Function
} }
export interface dataCollectComponent {
componentId: string
field: string
[key: string]: any
}
export interface CreateComponentType extends PublicConfigType { export interface CreateComponentType extends PublicConfigType {
key: string key: string
chartConfig: ConfigType chartConfig: ConfigType
option: GlobalThemeJsonType option: GlobalThemeJsonType
eventList?: Array<OptionsType>
methodList?: Array<OptionsType>
eventConfig?: EventConfig
dataCollectComponentList?: Array<dataCollectComponent>
} }
// 获取组件实例类中某个key对应value类型的方法 // 获取组件实例类中某个key对应value类型的方法
@ -98,7 +138,8 @@ export enum PackagesCategoryEnum {
CHARTS = 'Charts', CHARTS = 'Charts',
TABLES = 'Tables', TABLES = 'Tables',
INFORMATIONS = 'Informations', INFORMATIONS = 'Informations',
DECORATES = 'Decorates' DECORATES = 'Decorates',
FORM = 'Form',
} }
// 包分类名称 // 包分类名称
@ -106,7 +147,8 @@ export enum PackagesCategoryName {
CHARTS = '图表', CHARTS = '图表',
TABLES = '列表', TABLES = '列表',
INFORMATIONS = '信息', INFORMATIONS = '信息',
DECORATES = '小组件' DECORATES = '小组件',
FORM = '表单',
} }
// 获取组件 // 获取组件
@ -121,4 +163,5 @@ export type PackagesType = {
[PackagesCategoryEnum.INFORMATIONS]: ConfigType[] [PackagesCategoryEnum.INFORMATIONS]: ConfigType[]
[PackagesCategoryEnum.TABLES]: ConfigType[] [PackagesCategoryEnum.TABLES]: ConfigType[]
[PackagesCategoryEnum.DECORATES]: ConfigType[] [PackagesCategoryEnum.DECORATES]: ConfigType[]
[PackagesCategoryEnum.FORM]: ConfigType[]
} }

View File

@ -2,6 +2,7 @@ import { ChartList } from '@/packages/components/Charts/index'
import { DecorateList } from '@/packages/components/Decorates/index' import { DecorateList } from '@/packages/components/Decorates/index'
import { InformationList } from '@/packages/components/Informations/index' import { InformationList } from '@/packages/components/Informations/index'
import { TableList } from '@/packages/components/Tables/index' import { TableList } from '@/packages/components/Tables/index'
import { FormList } from '@/packages/components/Form/index'
import { import {
PackagesCategoryEnum, PackagesCategoryEnum,
PackagesType, PackagesType,
@ -17,7 +18,8 @@ export let packagesList: PackagesType = {
[PackagesCategoryEnum.CHARTS]: ChartList, [PackagesCategoryEnum.CHARTS]: ChartList,
[PackagesCategoryEnum.INFORMATIONS]: InformationList, [PackagesCategoryEnum.INFORMATIONS]: InformationList,
[PackagesCategoryEnum.TABLES]: TableList, [PackagesCategoryEnum.TABLES]: TableList,
[PackagesCategoryEnum.DECORATES]: DecorateList [PackagesCategoryEnum.DECORATES]: DecorateList,
[PackagesCategoryEnum.FORM]: FormList,
} }
/** /**

View File

@ -7,7 +7,7 @@ import { globalThemeJson } from '@/settings/chartThemes/index'
* * color * * color
* @param option * @param option
* @param themeSetting * @param themeSetting
* @param excludes * @param includes
* @returns object * @returns object
*/ */
export const mergeTheme = <T, U>(option: T, themeSetting: U, includes: string[]) => { export const mergeTheme = <T, U>(option: T, themeSetting: U, includes: string[]) => {

View File

@ -53,6 +53,9 @@ import {
ArrowForward as ArrowForwardIcon, ArrowForward as ArrowForwardIcon,
Planet as PawIcon, Planet as PawIcon,
Search as SearchIcon, Search as SearchIcon,
Reload as ReloadIcon,
Add as AddIcon,
AddCircle as AddCircleIcon,
ChevronUpOutline as ChevronUpOutlineIcon, ChevronUpOutline as ChevronUpOutlineIcon,
ChevronDownOutline as ChevronDownOutlineIcon, ChevronDownOutline as ChevronDownOutlineIcon,
Pulse as PulseIcon Pulse as PulseIcon
@ -85,10 +88,16 @@ import {
FitToHeight as FitToHeightIcon, FitToHeight as FitToHeightIcon,
FitToWidth as FitToWidthIcon, FitToWidth as FitToWidthIcon,
Filter as FilterIcon, Filter as FilterIcon,
FilterEdit as FilterEditIcon FilterEdit as FilterEditIcon,
Edit as EditIcon,
DataFormat as DataFormatIcon
} from '@vicons/carbon' } from '@vicons/carbon'
const ionicons5 = { const ionicons5 = {
// 新增
AddIcon,
// 新增2
AddCircleIcon,
// 帮助(问号) // 帮助(问号)
HelpOutlineIcon, HelpOutlineIcon,
// 添加 // 添加
@ -194,6 +203,8 @@ const ionicons5 = {
ArrowForwardIcon, ArrowForwardIcon,
// 狗爪 // 狗爪
PawIcon, PawIcon,
// 重新加载
ReloadIcon,
// 搜索(放大镜) // 搜索(放大镜)
SearchIcon, SearchIcon,
// 过滤器 // 过滤器
@ -207,6 +218,8 @@ const ionicons5 = {
} }
const carbon = { const carbon = {
EditIcon,
DataFormatIcon,
// 图表 // 图表
RoadmapIcon, RoadmapIcon,
// 信息 // 信息

View File

@ -1,5 +1,6 @@
{ {
"title": { "title": {
"text": "",
"show": true, "show": true,
"textStyle": { "textStyle": {
"color": "#BFBFBF", "color": "#BFBFBF",

View File

@ -131,6 +131,7 @@ export enum ChartEditStoreEnum {
RECORD_CHART = 'recordChart', RECORD_CHART = 'recordChart',
// 以下需要存储 // 以下需要存储
EDIT_CANVAS_CONFIG = 'editCanvasConfig', EDIT_CANVAS_CONFIG = 'editCanvasConfig',
EVENT_CONFIG = 'eventConfig',
REQUEST_GLOBAL_CONFIG = 'requestGlobalConfig', REQUEST_GLOBAL_CONFIG = 'requestGlobalConfig',
COMPONENT_LIST = 'componentList' COMPONENT_LIST = 'componentList'
} }

View File

@ -30,7 +30,6 @@ import {
RequestGlobalConfigType, RequestGlobalConfigType,
EditCanvasConfigType EditCanvasConfigType
} from './chartEditStore.d' } from './chartEditStore.d'
const chartHistoryStore = useChartHistoryStore() const chartHistoryStore = useChartHistoryStore()
const settingStore = useSettingStore() const settingStore = useSettingStore()

View File

@ -0,0 +1,7 @@
export enum DataCollectStoreEnums {
}
export interface DataCollectStoreType {
model: Record<string, number | string | Array<string | number>>,
mountedComponentSet: Set<string | number>
}

View File

@ -0,0 +1,24 @@
import { defineStore } from 'pinia'
import { DataCollectStoreType, DataCollectStoreEnums } from './dataCollectStore.d'
// 全局设置
export const useDataCollectStore = defineStore({
id: 'useDataCollectStore',
state: (): DataCollectStoreType => {
return {
mountedComponentSet: new Set(),
model: {}
}
},
getters: {
},
actions: {
clearAll(){
this.mountedComponentSet.clear()
},
recordMountedComponent(id: string){
this.mountedComponentSet.add(id)
}
}
})

View File

@ -1,5 +1,6 @@
import { defineAsyncComponent, AsyncComponentLoader } from 'vue' import { defineAsyncComponent, AsyncComponentLoader } from 'vue'
import { AsyncLoading, AsyncSkeletonLoading } from '@/components/GoLoading' import { AsyncLoading, AsyncSkeletonLoading } from '@/components/GoLoading'
import { ConfigType } from '@/packages/index.d'
/** /**
* * * *
@ -19,6 +20,11 @@ export const loadAsyncComponent = (loader: AsyncComponentLoader<any>) =>
defineAsyncComponent({ defineAsyncComponent({
loader, loader,
loadingComponent: AsyncLoading, loadingComponent: AsyncLoading,
errorComponent: {
render(){
return '加载失败'
}
},
delay: 20, delay: 20,
}) })
@ -28,3 +34,12 @@ export const loadSkeletonAsyncComponent = (loader: AsyncComponentLoader<any>) =>
loadingComponent: AsyncSkeletonLoading, loadingComponent: AsyncSkeletonLoading,
delay: 20, delay: 20,
}) })
export const getComponentConfig = (options: Omit<ConfigType, 'chartKey' | 'conKey' | 'id'>): ConfigType => {
return {
...options,
chartKey: `V${options.key}`,
conKey: `VC${options.key}`,
}
}

6
src/utils/data.ts Normal file
View File

@ -0,0 +1,6 @@
export const mapToOptions = <K extends string = 'key', V extends string = 'value'>(map: Map<string, string>, options = { k: 'label', v: 'value'} as { k: K; v: V }) => Array.from(map, item => {
return {
[options.k]: item[1],
[options.v]: item[0],
} as {[key in K | V]: string}
});

View File

@ -7,3 +7,4 @@ export * from '@/utils/plugin'
export * from '@/utils/componets' export * from '@/utils/componets'
export * from '@/utils/type' export * from '@/utils/type'
export * from '@/utils/file' export * from '@/utils/file'
export * from '@/utils/data'

View File

@ -204,7 +204,7 @@ export const newFunctionHandle = (
try { try {
if (!funcStr) return data if (!funcStr) return data
const fn = new Function('data', funcStr) const fn = new Function('data', funcStr)
const fnRes = fn(cloneDeep(data)) const fnRes = fn(data)
const resHandle = isToString ? toString(fnRes) : fnRes const resHandle = isToString ? toString(fnRes) : fnRes
// 成功回调 // 成功回调
successCallBack && successCallBack(resHandle) successCallBack && successCallBack(resHandle)

View File

@ -13,6 +13,7 @@ const {
RoadmapIcon, RoadmapIcon,
SpellCheckIcon, SpellCheckIcon,
GraphicalDataFlowIcon, GraphicalDataFlowIcon,
DataFormatIcon,
} = icon.carbon } = icon.carbon
@ -44,6 +45,10 @@ const packagesListObj = {
icon: renderIcon(GraphicalDataFlowIcon), icon: renderIcon(GraphicalDataFlowIcon),
label: PackagesCategoryName.DECORATES, label: PackagesCategoryName.DECORATES,
}, },
[PackagesCategoryEnum.FORM]: {
icon: renderIcon(DataFormatIcon),
label: PackagesCategoryName.FORM,
},
} }
// 处理列表 // 处理列表

View File

@ -0,0 +1,3 @@
import ChartDataForeignKey from './index.vue'
export { ChartDataForeignKey }

View File

@ -0,0 +1,89 @@
<template>
<CollapseItem name="关联表单组件" :expanded="true">
<template #header>
<n-icon size="24" @click="onAdd">
<component :is="AddCircleIcon"></component>
</n-icon>
</template>
<n-data-table
:columns="columns"
:data="data"
/>
</CollapseItem>
</template>
<script setup lang="ts">
import {
CollapseItem
} from '@/components/Pages/ChartItemSetting'
import { icon } from '@/plugins/icon'
import { FormInst, NSpace as Space, NIcon as Icon } from 'naive-ui'
import { ref, watch, h, reactive } from 'vue'
import { useTargetData } from '../../../hooks/useTargetData.hook'
const { targetData } = useTargetData();
const { AddCircleIcon } = icon.ionicons5
const showModal = ref(false)
const model = ref({})
let dataCollectComponentList: any
watch(targetData, () => {
if(targetData.value.dataCollectComponentList){
dataCollectComponentList = targetData.value.dataCollectComponentList
}else{
dataCollectComponentList = reactive([])
}
})
const columnIconAttr = {
size: 18,
style: {
cursor: 'pointer'
}
}
const onAdd = () => {
model.value = {}
showModal.value = true
}
const onEdit = (rowData: Record<string, any>) => {
model.value = {
...rowData
}
showModal.value = true
}
const columns = [
{title: '组件名称', key: 'componentName'},
// {title: 'Id', key: 'componentId'},
{title: '绑定字段', field: 'field'},
{ title: '操作', render(rowData: any){
return h(Space, () => (h({
render(){
return [
h(Icon, {
...columnIconAttr,
title: '编辑',
onClick(){
onEdit(rowData)
}
}, () => h(icon.carbon.EditIcon)),
h(Icon, {
...columnIconAttr,
title: '删除',
onClick(){
}
}, () => h(icon.ionicons5.RemoveIcon))
]
}
})))
}},
]
const data: Array<any> = []
</script>
<style></style>

View File

@ -13,7 +13,10 @@
></chart-data-static> ></chart-data-static>
<!-- 动态 --> <!-- 动态 -->
<chart-data-ajax v-else></chart-data-ajax> <template v-else>
<chart-data-ajax></chart-data-ajax>
<chart-data-foreign-key></chart-data-foreign-key>
</template>
</div> </div>
</template> </template>
@ -22,6 +25,7 @@ import { SettingItemBox } from '@/components/Pages/ChartItemSetting'
import { useTargetData } from '../hooks/useTargetData.hook' import { useTargetData } from '../hooks/useTargetData.hook'
import { ChartDataStatic } from './components/ChartDataStatic/index' import { ChartDataStatic } from './components/ChartDataStatic/index'
import { ChartDataAjax } from './components/ChartDataAjax/index' import { ChartDataAjax } from './components/ChartDataAjax/index'
import { ChartDataForeignKey } from './components/ChartDataForeignKey/index'
import { SelectCreateDataType, SelectCreateDataEnum } from './index.d' import { SelectCreateDataType, SelectCreateDataEnum } from './index.d'
import { RequestDataTypeEnum } from '@/enums/httpEnum' import { RequestDataTypeEnum } from '@/enums/httpEnum'

View File

@ -0,0 +1,287 @@
<template>
<n-collapse :default-expanded-names="Object.values(EventType)">
<!-- todo 暂时用any -->
<n-collapse-item
v-for="(item, key) in targetData.eventConfig as any"
:key="key"
:title="item.title"
:name="key">
<template #header-extra>
<n-icon size="24" @click.stop="onAddEvent(item, key as unknown as EventType)">
<component :is="AddCircleIcon"></component>
</n-icon>
</template>
<n-empty
v-if="!item.methodList.length"
:show-icon="false">
</n-empty>
<template v-else>
<n-data-table
:row-key="(rowData:any) => rowData.uid"
:columns="columns"
:data="item.methodList"
/>
</template>
</n-collapse-item>
</n-collapse>
<n-modal
v-model:show="showModal"
title="事件"
type="info"
preset="dialog"
:mask-closable="false"
:on-after-leave="onModalClosed">
<n-form
ref="formRef"
label-placement="left"
:rules="rules"
:model="model"
>
<n-form-item label="名称" path="name">
<n-input v-model:value="model.name" />
</n-form-item>
<n-form-item label="类型" path="type">
<n-select
v-model:value="model.type"
placeholder="类型"
:options="typeOptions"
/>
</n-form-item>
<template v-if="model.type === EventTriggerType.COMPONENT">
<n-form-item label="选择组件" path="componentId">
<n-select
v-model:value="model.componentId"
placeholder="请选择组件"
:options="componentListOptions"
/>
</n-form-item>
<n-form-item label="触发方法" path="componentMethod">
<n-select
v-model:value="model.componentMethod"
placeholder="请选择触发方法"
:options="componentMethodOptions"
/>
</n-form-item>
</template>
<template v-else-if="model.type === EventTriggerType.JAVASCRIPT">
<n-form-item label="自定义js" path="code">
<n-space vertical :style="{width: '100%'}">
<n-tag type="info">
<span class="func-keyword">function</span>&nbsp;&nbsp;(data)&nbsp;&nbsp;{
</n-tag>
<monaco-editor v-model:modelValue="model.code" language="javascript" height="500px"/>
<n-tag type="info">}</n-tag>
</n-space>
</n-form-item>
</template>
<div style="display: flex; justify-content: center">
<n-space>
<n-button round type="primary" @click="onSubmit">
确认
</n-button>
<n-button round type="primary" @click="onCancel">
取消
</n-button>
</n-space>
</div>
</n-form>
</n-modal>
</template>
<script setup lang="ts">
import {reactive, ref, h, watch, computed, unref, toRaw, markRaw} from 'vue'
import { icon } from '@/plugins/icon'
import { MonacoEditor } from '@/components/Pages/MonacoEditor'
import { EventType, EventTypeTitle, EventTriggerType, EventTriggerTypeMap, CommonEventMap } from '@/enums/eventEnum'
import { FormInst, NSpace as Space, NIcon as Icon } from 'naive-ui'
import { getUUID, mapToOptions } from '@/utils'
import { useTargetData } from '../hooks/useTargetData.hook'
import { CreateComponentType, OptionsType, EventConfig, EventConfigValue } from '@/packages/index.d'
const { targetData, chartEditStore } = useTargetData();
//
const eventConfig = computed<EventConfig>(() => {
return targetData.value?.eventConfig as EventConfig
})
// ,
watch(targetData, (newVal) => {
if(!newVal)return
if(!eventConfig.value){
newVal.eventConfig = reactive({})
}
//
Object.keys(EventTypeTitle).forEach((key: string) => {
if(!(key in eventConfig.value)){
(newVal.eventConfig as any)[key] = {
title: EventTypeTitle[key as EventType],
methodList: []
}
}
})
//
newVal.chartConfig.eventList?.map((item: OptionsType) => {
if(!(item.value in eventConfig.value)){
(newVal.eventConfig as any)[item.value] = {
title: item.label,
methodList: []
}
}
})
}, {
immediate: true
})
const { AddCircleIcon } = icon.ionicons5
const showModal = ref(false)
let eventType: EventType = EventType.CLICK
let operateCollapse: any = null
const formRef = ref<FormInst | null>(null)
const model = ref<Record<string, string>>({
uid: '',
name: '',
type: EventTriggerType.JAVASCRIPT,
code: '',
componentId: ''
});
const defaultModel: Record<string, string> = {
...markRaw(toRaw(unref(model)))
}
const typeOptions = [
{label: EventTriggerTypeMap.get(EventTriggerType.COMPONENT), value: EventTriggerType.COMPONENT},
{label: EventTriggerTypeMap.get(EventTriggerType.JAVASCRIPT), value: EventTriggerType.JAVASCRIPT},
]
const componentListOptions = computed(() => {
return chartEditStore.componentList.map(item => {
return {
disabled: item.id === targetData.value.id,
label: item.chartConfig.title,
value: item.id
}
})
})
const selectedComponent = computed((): CreateComponentType | void => {
return chartEditStore.componentList.find(item => Object.is(item.id, model.value.componentId))
})
const commMethodList = mapToOptions(CommonEventMap)
const componentMethodOptions = computed(() => {
return [
...commMethodList,
...(selectedComponent.value ? (selectedComponent.value.chartConfig.methodList as Array<OptionsType>) : [])
]
})
const rules = {
name: { required: true, message: '必填项不能为空' },
type: { required: true, message: '必填项不能为空' },
componentId: { required: true, message: '必填项不能为空' },
componentMethod: { required: true, message: '必填项不能为空' },
}
const onAddEvent = (item: any, type: EventType) => {
eventType = type
operateCollapse = item
showModal.value = true
}
const onEdit = (rowData: Record<string, any>) => {
model.value = {
...rowData
}
eventType = rowData.eventType
// @ts-ignore
operateCollapse = targetData.value?.eventConfig[eventType]
showModal.value = true
}
const columnIconAttr = {
size: 18,
style: {
cursor: 'pointer'
}
}
const columns = [
{ title: '名称', key: 'name'},
{ title: '类型', key: 'type', render(rowData: any){
return EventTriggerTypeMap.get(rowData.type)
}},
{ title: '操作', render(rowData: any, rowIndex: number){
return h(Space, () => (h({
render(){
return [
h(Icon, {
...columnIconAttr,
title: '编辑',
onClick(){
onEdit(rowData)
}
}, () => h(icon.carbon.EditIcon)),
h(Icon, {
...columnIconAttr,
title: '删除',
onClick(){
((eventConfig.value[rowData.eventType as keyof EventConfig]) as EventConfigValue[string]).methodList.splice(rowIndex, 1)
}
}, () => h(icon.ionicons5.RemoveIcon))
]
}
})))
}},
]
const onSubmit = () => {
formRef.value?.validate((errors) => {
if (!errors && operateCollapse) {
if(model.value.uid){
const index = operateCollapse.methodList
.findIndex((item:any) => item.uid === model.value.uid)
if(index > -1){
operateCollapse.methodList[index] = {...model.value}
}
}else{
operateCollapse.methodList.push({
...model.value,
eventType,
uid: getUUID(),
})
}
showModal.value = false
}
})
}
const onCancel = () => {
showModal.value = false
}
const onModalClosed = () => {
Object.keys(model.value).forEach(key => {
if(key in defaultModel){
model.value[key] = defaultModel[key]
}else{
model.value[key] = ''
}
})
}
</script>
<style lang="scss" scoped>
.func-keyword {
color: #b478cf;
}
</style>

View File

@ -92,7 +92,8 @@ const {
ConstructIcon, ConstructIcon,
FlashIcon, FlashIcon,
DesktopOutlineIcon, DesktopOutlineIcon,
LeafIcon LeafIcon,
RocketIcon
} = icon.ionicons5 } = icon.ionicons5
const ContentEdit = loadAsyncComponent(() => import('../ContentEdit/index.vue')) const ContentEdit = loadAsyncComponent(() => import('../ContentEdit/index.vue'))
@ -108,6 +109,9 @@ const ChartData = loadAsyncComponent(() =>
const ChartAnimation = loadAsyncComponent(() => const ChartAnimation = loadAsyncComponent(() =>
import('./components/ChartAnimation/index.vue') import('./components/ChartAnimation/index.vue')
) )
const ChartEvent = loadAsyncComponent(() =>
import('./components/ChartEvent/index.vue')
)
const collapsed = ref<boolean>(getDetails.value) const collapsed = ref<boolean>(getDetails.value)
@ -164,6 +168,12 @@ const canvasTabList = [
title: '数据', title: '数据',
icon: FlashIcon, icon: FlashIcon,
render: ChartData render: ChartData
},
{
key: 'eventData',
title: '事件',
icon: RocketIcon,
render: ChartEvent
} }
] ]
</script> </script>

View File

@ -70,6 +70,7 @@ const select = computed(() => {
border-radius: 5px; border-radius: 5px;
background-color: #fff; background-color: #fff;
transform: translate(-40%, -30%); transform: translate(-40%, -30%);
cursor: col-resize;
&.t { &.t {
width: 30px; width: 30px;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);

View File

@ -127,6 +127,12 @@ onMounted(() => {
}) })
</script> </script>
<script lang="ts">
export default {
name: 'ContentEdit'
}
</script>
<style lang="scss" scoped> <style lang="scss" scoped>
@include goId('chart-edit-layout') { @include goId('chart-edit-layout') {
position: relative; position: relative;

View File

@ -22,7 +22,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, toRefs, computed } from 'vue' import { ref, toRefs, computed,isRef } from 'vue'
import { requireErrorImg } from '@/utils' import { requireErrorImg } from '@/utils'
import { useDesignStore } from '@/store/modules/designStore/designStore' import { useDesignStore } from '@/store/modules/designStore/designStore'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
@ -39,7 +39,10 @@ const props = defineProps({
} }
}) })
const { image } = toRefs(props.componentData.chartConfig) //
const { image } = isRef(props.componentData.chartConfig) ?
toRefs(props.componentData.chartConfig)
: props.componentData.chartConfig
// //
const select = computed(() => { const select = computed(() => {

View File

@ -0,0 +1,113 @@
<template>
<component
ref="componentRef"
:is="item.chartConfig.chartKey"
:chartConfig="item"
:themeSetting="themeSetting"
:themeColor="themeColor"
:style="{...getSizeStyle(item.attr)}"
v-on="useEvent ? getEventList(item.eventConfig as EventConfig) : {}"
></component>
</template>
<script lang='ts' setup>
import { PropType, ref, toRefs, getCurrentInstance, ComponentInternalInstance, onMounted } from 'vue'
import { useEventBus } from '@/hooks'
import { convertEventBusListeners } from '@/hooks/useEventBus.hook'
import { getSizeStyle } from '../../utils'
import { EventTriggerType } from '@/enums/eventEnum'
import { CreateComponentType, EventConfig, PackagesCategoryEnum } from '@/packages/index.d'
import { newFunctionHandle } from '@/utils'
import isObject from 'lodash/isObject'
import { COMMON_EVENT_ENUM, DATA_COMPONENT_EVENT_ENUM } from '@/enums/eventEnum'
import { useDataCollectStore } from '@/store/modules/dataCollectStore/dataCollectStore'
const props = defineProps({
item: {
type: Object as PropType<CreateComponentType>,
required: true
},
themeSetting: {
type: Object,
required: true
},
themeColor: {
type: Object,
required: true
},
useEvent: {
type: Boolean,
default: false
}
})
const { item, themeSetting, themeColor, useEvent } = toRefs(props);
const componentRef = ref<any>(null)
const instance = getCurrentInstance() as ComponentInternalInstance
const bus = useEventBus()
/**
* @return
* {
* click: [fn1, fn2],
* change: [fn1, fn2],
* }
*/
const getEventList = (eventConfig: EventConfig) => {
if(!isObject(eventConfig)) return {}
const res = Object.keys(eventConfig)
.reduce((previousValue: EventConfig, currentValue: string) => {
// @ts-ignore
previousValue[currentValue] = eventConfig[currentValue].methodList.map((item: any) => {
if(item.type === EventTriggerType.JAVASCRIPT){
return (e: any) => {
try {
newFunctionHandle(e, item.code)
} catch (error) {
console.error(error, item.code)
throw error
}
}
}else{
return (data: any) => {
bus.emit(`${item.componentId}:${item.componentMethod}`, data)
}
}
})
return previousValue
}, {} as EventConfig)
return res;
}
const listeners: Record<string, any> = {
on: {
[COMMON_EVENT_ENUM.FORCE_UPDATE]: () => {
instance.proxy?.$forceUpdate()
}
}
}
//
if( item.value.chartConfig.package === PackagesCategoryEnum.CHARTS ||
item.value.chartConfig.package === PackagesCategoryEnum.TABLES){
//
listeners.on[DATA_COMPONENT_EVENT_ENUM.LOAD_DATA] = () => {
componentRef.value?.loadData()
}
}
//
if(item.value.chartConfig.package === PackagesCategoryEnum.FORM){
const dataCollectStore = useDataCollectStore()
//
onMounted(() => {
dataCollectStore.recordMountedComponent(item.value.id)
})
}
useEventBus(convertEventBusListeners(listeners, item.value.id))
</script>
<style lang='less' scoped>
</style>

View File

@ -10,13 +10,12 @@
...getTransformStyle(item.styles) ...getTransformStyle(item.styles)
}" }"
> >
<component <PreViewRenderItem
:is="item.chartConfig.chartKey" :use-event="true"
:chartConfig="item" :item="item"
:themeSetting="themeSetting" :themeSetting="themeSetting"
:themeColor="themeColor" :themeColor="themeColor">
:style="{...getSizeStyle(item.attr)}" </PreViewRenderItem>
></component>
</div> </div>
</template> </template>
@ -26,6 +25,8 @@ import { ChartEditStorageType } from '../../index.d'
import { chartColors } from '@/settings/chartThemes/index' import { chartColors } from '@/settings/chartThemes/index'
import { animationsClass, getFilterStyle, getTransformStyle } from '@/utils' import { animationsClass, getFilterStyle, getTransformStyle } from '@/utils'
import { getSizeStyle, getComponentAttrStyle } from '../../utils' import { getSizeStyle, getComponentAttrStyle } from '../../utils'
import PreViewRenderItem from './PreViewRenderItem.vue'
const props = defineProps({ const props = defineProps({
localStorageInfo: { localStorageInfo: {

View File

@ -28,7 +28,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue' import { computed } from 'vue'
import { PreviewRenderList } from './components/PreviewRenderList' import { PreviewRenderList } from './components/PreviewRenderList/index'
import { getFilterStyle } from '@/utils' import { getFilterStyle } from '@/utils'
import { getEditCanvasConfigStyle, getSessionStorageInfo } from './utils' import { getEditCanvasConfigStyle, getSessionStorageInfo } from './utils'
import { useComInstall } from './hooks/useComInstall.hook' import { useComInstall } from './hooks/useComInstall.hook'

View File

@ -5,67 +5,140 @@ import { OUTPUT_DIR, brotliSize, chunkSizeWarningLimit, terserOptions, rollupOpt
import viteCompression from 'vite-plugin-compression' import viteCompression from 'vite-plugin-compression'
import { viteMockServe } from 'vite-plugin-mock' import { viteMockServe } from 'vite-plugin-mock'
import monacoEditorPlugin from 'vite-plugin-monaco-editor' import monacoEditorPlugin from 'vite-plugin-monaco-editor'
import { visualizer } from "rollup-plugin-visualizer";
import viteImagemin from 'vite-plugin-imagemin'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { NaiveUiResolver
} from 'unplugin-vue-components/resolvers'
function pathResolve(dir: string) { function pathResolve(dir: string) {
return resolve(process.cwd(), '.', dir) return resolve(process.cwd(), '.', dir)
} }
export default defineConfig({ const plugins = [
base: '/', vue(),
// 路径重定向 monacoEditorPlugin({
resolve: { languageWorkers: ['editorWorkerService', 'typescript', 'json', 'html']
alias: [ }),
{ ]
find: /\/#\//,
replacement: pathResolve('types') + '/' const devPlugins = [
}, AutoImport(
{ {
find: '@', imports: [
replacement: pathResolve('src') + '/' 'vue',
} 'vue-router',
], {
dedupe: ['vue'] 'vue': ['PropType']
}, }
// 全局 css 注册 ],
css: { eslintrc: {
preprocessorOptions: { enabled: true
scss: {
javascriptEnabled: true,
additionalData: `@import "src/styles/common/style.scss";`
} }
} }
}, ),
plugins: [ Components({
vue(), resolvers: [
monacoEditorPlugin({ NaiveUiResolver()
languageWorkers: ['editorWorkerService', 'typescript', 'json', 'html'] ]
}), }),
viteMockServe({ viteMockServe({
mockPath: '/src/api/mock', mockPath: '/src/api/mock',
// 开发打包开关 // 开发打包开关
localEnabled: true, localEnabled: true,
// 生产打包开关 // 生产打包开关
prodEnabled: true, prodEnabled: true,
// 打开后,可以读取 ts 文件模块。 请注意,打开后将无法监视.js 文件 // 打开后,可以读取 ts 文件模块。 请注意,打开后将无法监视.js 文件
supportTs: true, supportTs: true,
// 监视文件更改 // 监视文件更改
watchFiles: true watchFiles: true
}), }),
// 压缩 ]
viteCompression({ const proPlugins = [
verbose: true, // 图片压缩
disable: false, viteImagemin({
threshold: 10240, gifsicle: {
algorithm: 'gzip', optimizationLevel: 7,
ext: '.gz' interlaced: false,
}) },
], optipng: {
build: { optimizationLevel: 7,
target: 'es2015', },
outDir: OUTPUT_DIR, mozjpeg: {
terserOptions: terserOptions, quality: 20,
rollupOptions: rollupOptions, },
brotliSize: brotliSize, pngquant: {
chunkSizeWarningLimit: chunkSizeWarningLimit quality: [0.8, 0.9],
speed: 4,
},
svgo: {
plugins: [
{
name: 'removeViewBox',
},
{
name: 'removeEmptyAttrs',
active: false,
},
],
},
}),
// 压缩
viteCompression({
verbose: true,
disable: false,
threshold: 10240,
algorithm: 'gzip',
ext: '.gz'
}),
// 打包分析
visualizer({
open: true
})
]
export default defineConfig(({ mode }) => {
if(mode === 'development'){
plugins.push(...devPlugins)
}else{
plugins.push(...proPlugins)
}
return {
base: '/',
// 路径重定向
resolve: {
alias: [
{
find: /\/#\//,
replacement: pathResolve('types') + '/'
},
{
find: '@',
replacement: pathResolve('src') + '/'
}
],
dedupe: ['vue']
},
// 全局 css 注册
css: {
preprocessorOptions: {
scss: {
javascriptEnabled: true,
additionalData: `@import "src/styles/common/style.scss";`
}
}
},
plugins,
build: {
target: 'es2015',
outDir: OUTPUT_DIR,
terserOptions: terserOptions,
rollupOptions: rollupOptions,
brotliSize: brotliSize,
chunkSizeWarningLimit: chunkSizeWarningLimit
}
} }
}) })

View File

@ -0,0 +1,240 @@
<mxfile host="65bd71144e">
<diagram id="tYnlZV8h0JO72zglXhLP" name="Page-1">
<mxGraphModel dx="1032" dy="528" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="8" style="edgeStyle=none;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="2" target="3" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="38" value="组件Id&lt;br&gt;fieldKey" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="8" vertex="1" connectable="0">
<mxGeometry x="0.0869" y="2" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="9" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="2" target="4" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="13" value="同上" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="9" vertex="1" connectable="0">
<mxGeometry x="0.1013" y="1" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="10" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="2" target="5" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="14" value="同上" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="10" vertex="1" connectable="0">
<mxGeometry x="0.0923" y="2" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="11" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="2" target="6" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="15" value="同上" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="11" vertex="1" connectable="0">
<mxGeometry x="0.085" y="1" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="31" value="" style="edgeStyle=none;html=1;" parent="1" source="2" target="30" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="2" value="数据组件" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="134" y="250" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="20" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="3" target="16" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="760" y="220"/>
<mxPoint x="760" y="50"/>
</Array>
</mxGeometry>
</mxCell>
<mxCell id="57" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="3" target="51" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="760" y="220"/>
<mxPoint x="760" y="150"/>
</Array>
</mxGeometry>
</mxCell>
<mxCell id="3" value="表单组件1" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="447" y="210" width="120" height="20" as="geometry"/>
</mxCell>
<mxCell id="24" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="4" target="16" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="760" y="260"/>
<mxPoint x="760" y="50"/>
</Array>
</mxGeometry>
</mxCell>
<mxCell id="58" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="4" target="51" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="760" y="260"/>
<mxPoint x="760" y="150"/>
</Array>
</mxGeometry>
</mxCell>
<mxCell id="4" value="表单组件2" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="447" y="250" width="120" height="20" as="geometry"/>
</mxCell>
<mxCell id="26" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="5" target="16" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="760" y="300"/>
<mxPoint x="760" y="50"/>
</Array>
</mxGeometry>
</mxCell>
<mxCell id="59" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="5" target="51" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="760" y="300"/>
<mxPoint x="760" y="150"/>
</Array>
</mxGeometry>
</mxCell>
<mxCell id="5" value="..." style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="447" y="290" width="120" height="20" as="geometry"/>
</mxCell>
<mxCell id="27" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="6" target="16" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="760" y="340"/>
<mxPoint x="760" y="50"/>
</Array>
</mxGeometry>
</mxCell>
<mxCell id="61" value="修改组件渲染状态" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="27" vertex="1" connectable="0">
<mxGeometry x="0.6751" y="-2" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="60" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="6" target="51" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="760" y="340"/>
<mxPoint x="760" y="150"/>
</Array>
</mxGeometry>
</mxCell>
<mxCell id="62" value="双向绑定" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="60" vertex="1" connectable="0">
<mxGeometry x="0.6167" y="-2" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="6" value="表单组件n" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="447" y="330" width="120" height="20" as="geometry"/>
</mxCell>
<mxCell id="16" value="Store&lt;br&gt;[&quot;组件Id1&quot;,&quot;组件Id2&quot;]" style="ellipse;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="330" y="10" width="120" height="80" as="geometry"/>
</mxCell>
<mxCell id="33" value="" style="edgeStyle=none;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" parent="1" source="30" target="32" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="37" value="Y" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="33" vertex="1" connectable="0">
<mxGeometry x="-0.2626" y="1" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="35" value="" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="30" target="34" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="414" y="420"/>
</Array>
</mxGeometry>
</mxCell>
<mxCell id="39" value="N" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="35" vertex="1" connectable="0">
<mxGeometry x="-0.5169" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="30" value="渲染完成,检查关联组件是否渲染完成" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="134" y="390" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="41" value="" style="edgeStyle=none;html=1;" parent="1" source="32" target="40" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="32" value="收集数据" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="134" y="520" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="46" style="edgeStyle=none;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="34" target="32" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="47" value="Y" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="46" vertex="1" connectable="0">
<mxGeometry x="0.2239" y="1" relative="1" as="geometry">
<mxPoint x="19" as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="48" style="edgeStyle=none;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="34" target="34" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="414" y="510" as="targetPoint"/>
<Array as="points">
<mxPoint x="414" y="640"/>
<mxPoint x="634" y="640"/>
<mxPoint x="634" y="550"/>
</Array>
</mxGeometry>
</mxCell>
<mxCell id="50" value="N" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="48" vertex="1" connectable="0">
<mxGeometry x="-0.9351" relative="1" as="geometry">
<mxPoint y="9" as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="34" value="监听Store变化判断关联组件是否渲染完成" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="354" y="520" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="43" value="" style="edgeStyle=none;html=1;" parent="1" source="40" target="42" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="40" value="格式化数据" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="134" y="660" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="45" value="" style="edgeStyle=none;html=1;" parent="1" source="42" target="44" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="42" value="发送请求" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="134" y="800" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="70" value="" style="edgeStyle=none;html=1;" parent="1" source="44" target="69" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="44" value="根据配置的过滤函数处理返回结果" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="134" y="940" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="51" value="Store&lt;br&gt;{&lt;br&gt;&quot;组件Id1&quot;: value,&lt;br&gt;&quot;组件Id2&quot;:value,&lt;br&gt;}" style="ellipse;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="330" y="110" width="120" height="80" as="geometry"/>
</mxCell>
<mxCell id="63" value="" style="endArrow=classic;startArrow=classic;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="32" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="50" y="560" as="sourcePoint"/>
<mxPoint x="330" y="150" as="targetPoint"/>
<Array as="points">
<mxPoint x="80" y="550"/>
<mxPoint x="80" y="150"/>
</Array>
</mxGeometry>
</mxCell>
<mxCell id="64" value="根据关联组件Id获取源数据" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="63" vertex="1" connectable="0">
<mxGeometry x="-0.1051" y="1" relative="1" as="geometry">
<mxPoint y="61" as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="66" value="比如日期范围,&lt;br&gt;绑定值[2022-08-08,2022-08-09],&lt;br&gt;需要格式化为开始时间、结束时间两个字段" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="327" y="665" width="240" height="50" as="geometry"/>
</mxCell>
<mxCell id="68" value="" style="endArrow=none;dashed=1;html=1;" parent="1" target="66" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="260" y="690" as="sourcePoint"/>
<mxPoint x="320" y="670" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="69" value="渲染视图" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="134" y="1080" width="120" height="60" as="geometry"/>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>