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: {
'vue/setup-compiler-macros': true,
node: true,
},
extends: ["plugin:vue/vue3-essential", "eslint:recommended"],
extends: [
"plugin:vue/vue3-essential",
"eslint:recommended",
"./.eslintrc-auto-import.json"
],
rules: {
"no-console": 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
.history
.husky
.DS_Store
dist
dist-ssr
*.local
.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",
"scripts": {
"dev": "vite --host",
"build": "vue-tsc --noEmit && vite build",
"build": "rimraf ./dist && npm run test && vite build",
"preview": "vite preview",
"new": "plop --plopfile ./plop/plopfile.js",
"test": "vue-tsc --noEmit",
"postinstall": "husky install"
},
"dependencies": {
"@types/color": "^3.0.3",
"@types/crypto-js": "^4.1.1",
"@types/keymaster": "^1.6.30",
"@vicons/carbon": "^0.12.0",
"@vicons/ionicons5": "~0.11.0",
"@vueuse/core": "^7.7.1",
"animate.css": "^4.1.1",
"axios": "^0.27.2",
"color": "^4.2.3",
"crypto-js": "^4.1.1",
"echarts": "^5.3.2",
"echarts-liquidfill": "^3.1.0",
"highlight.js": "^11.5.0",
"html2canvas": "^1.4.1",
"keymaster": "^1.6.2",
"lodash": "~4.17.21",
"monaco-editor": "^0.33.0",
"naive-ui": "2.30.3",
"pinia": "^2.0.13",
"screenfull": "^6.0.1",
"tiny-emitter": "^2.1.0",
"vue": "^3.2.31",
"vue-demi": "^0.13.1",
"vue-echarts": "^6.0.2",
"vue-i18n": "9.1.9",
"vue-router": "4.0.12",
"vue3-lazyload": "^0.2.5-beta",
@ -35,37 +39,35 @@
"devDependencies": {
"@commitlint/cli": "^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/parser": "^5.18.0",
"@vicons/carbon": "^0.12.0",
"@vicons/ionicons5": "~0.11.0",
"@vitejs/plugin-vue": "^1.10.2",
"@vitejs/plugin-vue-jsx": "^1.3.9",
"@vue/compiler-sfc": "^3.2.31",
"@vueuse/core": "^7.7.1",
"commitlint": "^17.0.2",
"default-passive-events": "^2.0.0",
"echarts": "^5.3.2",
"eslint": "^8.12.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.5.0",
"husky": "^8.0.1",
"lodash": "~4.17.21",
"mockjs": "^1.1.0",
"plop": "^3.0.5",
"prettier": "^2.6.2",
"rollup-plugin-visualizer": "^5.7.1",
"sass": "^1.49.11",
"sass-loader": "^12.6.0",
"typescript": "^4.6.3",
"unplugin-auto-import": "^0.10.1",
"unplugin-vue-components": "^0.21.1",
"vite": "2.9.5",
"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-monaco-editor": "^1.1.0",
"vue-echarts": "^6.0.2",
"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,7 +7,14 @@
size="small"
></n-switch>
</template>
<setting-item-box name="标题">
<setting-item-box name="属性" :alone="true">
<setting-item name="文本">
<n-input v-model:value="title.text" size="small" type="text"></n-input>
</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"
@ -21,8 +28,9 @@
size="small"
></n-input-number>
</setting-item>
</template>
</setting-item-box>
<setting-item-box name="副标题">
<setting-item-box name="副标题" v-if="title.subtextStyle">
<setting-item name="颜色">
<n-color-picker
size="small"
@ -374,4 +382,11 @@ const yAxis = computed(() => {
const legend = computed(() => {
return props.optionData.legend
})
const textAlignOptions = [
{label: '自动', value: 'auto'},
{label: '左对齐', value: 'left'},
{label: '右对齐', value: 'right'},
{label: '居中对齐', value: 'center'},
]
</script>

View File

@ -1,7 +1,6 @@
<template></template>
<script setup>
import * as monaco from 'monaco-editor'
import editorWorker from 'monaco-editor/esm/vs/editor/editor.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'

View File

@ -1,11 +1,11 @@
import { ref, onBeforeUnmount, nextTick } from 'vue'
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') => {
const designStore = useDesignStore()
let monacoEditor: monaco.editor.IStandaloneCodeEditor | null = null
let monacoEditor: editor.IStandaloneCodeEditor | null = null
let initReadOnly = false
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
const javascriptModel = monaco.editor.createModel('', language)
const javascriptModel = editor.createModel('', language)
initReadOnly = !!editorOption.readOnly
// 创建
monacoEditor = monaco.editor.create(el.value, {
monacoEditor = editor.create(el.value, {
model: javascriptModel,
// 是否启用预览图
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_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/useCode.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 { RequestDataTypeEnum } from '@/enums/httpEnum'
import { isPreview, newFunctionHandle, intervalUnitHandle } from '@/utils'
import { useIntervalFn } from '@vueuse/core'
// 获取类型
type ChartEditStoreType = typeof useChartEditStore
@ -21,11 +22,17 @@ export const useChartDataFetch = (
updateCallback?: (...args: any) => any
) => {
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 chartEditStore = useChartEditStore()
pauseFn = null
resumeFn = null
fetchFn = null
// 全局数据
const {
requestOriginUrl,
@ -55,9 +62,7 @@ export const useChartDataFetch = (
const completePath = requestOriginUrl && requestOriginUrl.value + requestUrl.value
if (!completePath) return
clearInterval(fetchInterval)
const fetchFn = async () => {
fetchFn = async (callback: () => any) => {
const res = await customizeHttp(toRaw(targetComponent.request), toRaw(chartEditStore.requestGlobalConfig))
if (res && res.data) {
try {
@ -73,6 +78,7 @@ export const useChartDataFetch = (
}
}
}
callback && callback()
} catch (error) {
console.error(error)
}
@ -87,11 +93,17 @@ export const useChartDataFetch = (
// 单位
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) {
console.error(error)
}
} catch (error) {}
}
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)
// 注册全局常用的 naive-ui 组件
setupNaive(app)
// setupNaive(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 { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
import { getComponentConfig } from '@/utils'
import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
import { config } from './enum'
export const BarCommonConfig: ConfigType = {
key: 'BarCommon',
chartKey: 'VBarCommon',
conKey: 'VCBarCommon',
title: '柱状图',
export const BarCommonConfig: ConfigType = getComponentConfig({
...config,
category: ChatCategoryEnum.BAR,
categoryName: ChatCategoryEnumName.BAR,
package: PackagesCategoryEnum.CHARTS,
chartFrame: ChartFrameEnum.ECHARTS,
image
}
})

View File

@ -49,5 +49,15 @@ const option = computed(() => {
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>

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>
<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>
<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>

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 { ConfigType, PackagesCategoryEnum } from '@/packages/index.d'
import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
export const FunnelConfig: ConfigType = {
export const FunnelConfig: ConfigType = getComponentConfig({
key: 'Funnel',
chartKey: 'VFunnel',
conKey: 'VCFunnel',
title: '漏斗图',
category: ChatCategoryEnum.MORE,
categoryName: ChatCategoryEnumName.MORE,
package: PackagesCategoryEnum.CHARTS,
image
}
})

View File

@ -1,10 +1,55 @@
<template>
<div>
水波
</div>
<v-chart ref="vChartRef" :theme="themeColor" :option="option" :manual-update="isPreview()" autoresize></v-chart>
</template>
<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>

View File

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

View File

@ -1,5 +1,5 @@
import { publicConfig } from '@/packages/public'
import { CreateComponentType } from '@/packages/index.d'
import { CreateComponentType, EventConfig, OptionsType } from '@/packages/index.d'
import { Decorates04Config } from './index'
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>
<script setup lang="ts">
import { PropType } from 'vue'
import { PropType, toRefs } from 'vue'
import { option, WritingModeEnum, WritingModeObject } from './config'
import {
CollapseItem,
@ -77,6 +77,8 @@ const props = defineProps({
}
})
const { optionData} = toRefs(props)
const verticalOptions = [{
label: 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 { ConfigType, PackagesCategoryEnum } from '@/packages/index.d'
import { ChatCategoryEnum,ChatCategoryEnumName } from '../../index.d'
import { TextConfig, methodList, eventList } from './enum'
export const TextCommonConfig: ConfigType = {
key: 'TextCommon',
chartKey: 'VTextCommon',
conKey: 'VCTextCommon',
title: '文字',
export const TextCommonConfig: ConfigType = getComponentConfig({
key: TextConfig.key,
title: TextConfig.title,
category: ChatCategoryEnum.TEXT,
categoryName: ChatCategoryEnumName.TEXT,
package: PackagesCategoryEnum.INFORMATIONS,
methodList,
eventList,
image
}
})

View File

@ -22,9 +22,10 @@
<script setup lang="ts">
import { PropType, toRefs, shallowReactive, watch } from 'vue'
import { CreateComponentType } from '@/packages/index.d'
import { useChartDataFetch } from '@/hooks'
import { useChartDataFetch, useEventBus, convertEventBusListeners } from '@/hooks'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { option as configOption } from './config'
import { TextCommonEventEnum } from './enum'
const props = defineProps({
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 {
dataset,

View File

@ -1,5 +1,7 @@
import type { GlobalThemeJsonType } from '@/settings/chartThemes/index'
import type { RequestConfigType } from '@/store/modules/chartEditStore/chartEditStore.d'
import { EventType } from '@/enums/eventEnum';
export enum ChartFrameEnum {
// echarts 框架
@ -12,8 +14,15 @@ export enum ChartFrameEnum {
STATIC = 'static'
}
export type OptionsType = {
label: string
value: string
[key: string]: string
}
// 组件配置
export type ConfigType = {
id?: string
key: string
chartKey: string
conKey: string
@ -22,7 +31,29 @@ export type ConfigType = {
categoryName: string
package: string
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
setPosition: Function
}
export interface dataCollectComponent {
componentId: string
field: string
[key: string]: any
}
export interface CreateComponentType extends PublicConfigType {
key: string
chartConfig: ConfigType
option: GlobalThemeJsonType
eventList?: Array<OptionsType>
methodList?: Array<OptionsType>
eventConfig?: EventConfig
dataCollectComponentList?: Array<dataCollectComponent>
}
// 获取组件实例类中某个key对应value类型的方法
@ -98,7 +138,8 @@ export enum PackagesCategoryEnum {
CHARTS = 'Charts',
TABLES = 'Tables',
INFORMATIONS = 'Informations',
DECORATES = 'Decorates'
DECORATES = 'Decorates',
FORM = 'Form',
}
// 包分类名称
@ -106,7 +147,8 @@ export enum PackagesCategoryName {
CHARTS = '图表',
TABLES = '列表',
INFORMATIONS = '信息',
DECORATES = '小组件'
DECORATES = '小组件',
FORM = '表单',
}
// 获取组件
@ -121,4 +163,5 @@ export type PackagesType = {
[PackagesCategoryEnum.INFORMATIONS]: ConfigType[]
[PackagesCategoryEnum.TABLES]: 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 { InformationList } from '@/packages/components/Informations/index'
import { TableList } from '@/packages/components/Tables/index'
import { FormList } from '@/packages/components/Form/index'
import {
PackagesCategoryEnum,
PackagesType,
@ -17,7 +18,8 @@ export let packagesList: PackagesType = {
[PackagesCategoryEnum.CHARTS]: ChartList,
[PackagesCategoryEnum.INFORMATIONS]: InformationList,
[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
* @param option
* @param themeSetting
* @param excludes
* @param includes
* @returns object
*/
export const mergeTheme = <T, U>(option: T, themeSetting: U, includes: string[]) => {

View File

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

View File

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

View File

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

View File

@ -30,7 +30,6 @@ import {
RequestGlobalConfigType,
EditCanvasConfigType
} from './chartEditStore.d'
const chartHistoryStore = useChartHistoryStore()
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 { AsyncLoading, AsyncSkeletonLoading } from '@/components/GoLoading'
import { ConfigType } from '@/packages/index.d'
/**
* *
@ -19,6 +20,11 @@ export const loadAsyncComponent = (loader: AsyncComponentLoader<any>) =>
defineAsyncComponent({
loader,
loadingComponent: AsyncLoading,
errorComponent: {
render(){
return '加载失败'
}
},
delay: 20,
})
@ -28,3 +34,12 @@ export const loadSkeletonAsyncComponent = (loader: AsyncComponentLoader<any>) =>
loadingComponent: AsyncSkeletonLoading,
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/type'
export * from '@/utils/file'
export * from '@/utils/data'

View File

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

View File

@ -13,6 +13,7 @@ const {
RoadmapIcon,
SpellCheckIcon,
GraphicalDataFlowIcon,
DataFormatIcon,
} = icon.carbon
@ -44,6 +45,10 @@ const packagesListObj = {
icon: renderIcon(GraphicalDataFlowIcon),
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-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>
</template>
@ -22,6 +25,7 @@ import { SettingItemBox } from '@/components/Pages/ChartItemSetting'
import { useTargetData } from '../hooks/useTargetData.hook'
import { ChartDataStatic } from './components/ChartDataStatic/index'
import { ChartDataAjax } from './components/ChartDataAjax/index'
import { ChartDataForeignKey } from './components/ChartDataForeignKey/index'
import { SelectCreateDataType, SelectCreateDataEnum } from './index.d'
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,
FlashIcon,
DesktopOutlineIcon,
LeafIcon
LeafIcon,
RocketIcon
} = icon.ionicons5
const ContentEdit = loadAsyncComponent(() => import('../ContentEdit/index.vue'))
@ -108,6 +109,9 @@ const ChartData = loadAsyncComponent(() =>
const ChartAnimation = loadAsyncComponent(() =>
import('./components/ChartAnimation/index.vue')
)
const ChartEvent = loadAsyncComponent(() =>
import('./components/ChartEvent/index.vue')
)
const collapsed = ref<boolean>(getDetails.value)
@ -164,6 +168,12 @@ const canvasTabList = [
title: '数据',
icon: FlashIcon,
render: ChartData
},
{
key: 'eventData',
title: '事件',
icon: RocketIcon,
render: ChartEvent
}
]
</script>

View File

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

View File

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

View File

@ -22,7 +22,7 @@
</template>
<script setup lang="ts">
import { ref, toRefs, computed } from 'vue'
import { ref, toRefs, computed,isRef } from 'vue'
import { requireErrorImg } from '@/utils'
import { useDesignStore } from '@/store/modules/designStore/designStore'
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(() => {

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

View File

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

View File

@ -5,12 +5,108 @@ import { OUTPUT_DIR, brotliSize, chunkSizeWarningLimit, terserOptions, rollupOpt
import viteCompression from 'vite-plugin-compression'
import { viteMockServe } from 'vite-plugin-mock'
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) {
return resolve(process.cwd(), '.', dir)
}
export default defineConfig({
const plugins = [
vue(),
monacoEditorPlugin({
languageWorkers: ['editorWorkerService', 'typescript', 'json', 'html']
}),
]
const devPlugins = [
AutoImport(
{
imports: [
'vue',
'vue-router',
{
'vue': ['PropType']
}
],
eslintrc: {
enabled: true
}
}
),
Components({
resolvers: [
NaiveUiResolver()
]
}),
viteMockServe({
mockPath: '/src/api/mock',
// 开发打包开关
localEnabled: true,
// 生产打包开关
prodEnabled: true,
// 打开后,可以读取 ts 文件模块。 请注意,打开后将无法监视.js 文件
supportTs: true,
// 监视文件更改
watchFiles: true
}),
]
const proPlugins = [
// 图片压缩
viteImagemin({
gifsicle: {
optimizationLevel: 7,
interlaced: false,
},
optipng: {
optimizationLevel: 7,
},
mozjpeg: {
quality: 20,
},
pngquant: {
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: {
@ -35,31 +131,7 @@ export default defineConfig({
}
}
},
plugins: [
vue(),
monacoEditorPlugin({
languageWorkers: ['editorWorkerService', 'typescript', 'json', 'html']
}),
viteMockServe({
mockPath: '/src/api/mock',
// 开发打包开关
localEnabled: true,
// 生产打包开关
prodEnabled: true,
// 打开后,可以读取 ts 文件模块。 请注意,打开后将无法监视.js 文件
supportTs: true,
// 监视文件更改
watchFiles: true
}),
// 压缩
viteCompression({
verbose: true,
disable: false,
threshold: 10240,
algorithm: 'gzip',
ext: '.gz'
})
],
plugins,
build: {
target: 'es2015',
outDir: OUTPUT_DIR,
@ -68,4 +140,5 @@ export default defineConfig({
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>