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

This commit is contained in:
陪伴是最长情的告白¹³¹⁴ 2022-07-21 09:29:07 +00:00 committed by Gitee
commit ce3e5d8f34
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
24 changed files with 611 additions and 38 deletions

View File

@ -13,6 +13,7 @@ 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"],

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
node_modules node_modules
.husky
.DS_Store .DS_Store
dist dist
dist-ssr dist-ssr

View File

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

View File

@ -9,23 +9,27 @@
"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-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",
@ -33,27 +37,25 @@
"vuedraggable": "^4.1.0" "vuedraggable": "^4.1.0"
}, },
"devDependencies": { "devDependencies": {
"@types/color": "^3.0.3",
"@types/crypto-js": "^4.1.1",
"@types/keymaster": "^1.6.30",
"@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/node": "^16.11.26",
"@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", "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",
@ -65,7 +67,6 @@
"vite-plugin-importer": "^0.2.5", "vite-plugin-importer": "^0.2.5",
"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"
} }
} }

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

@ -0,0 +1,38 @@
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 const CommonEventMap = new Map(
[
['forceUpdate', '强制更新'],
]
)

View File

@ -1,4 +1,5 @@
export * from '@/hooks/useTheme.hook' 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

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

@ -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'
export const BarCommonConfig: ConfigType = { export const BarCommonConfig: ConfigType = getComponentConfig({
key: 'BarCommon', key: 'BarCommon',
chartKey: 'VBarCommon',
conKey: 'VCBarCommon',
title: '柱状图', 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

@ -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,16 @@
import { mapToOptions } from '@/utils';
export enum TextCommonEventEnum {
TEST = 'test'
}
export const eventList = mapToOptions(new Map([
[TextCommonEventEnum.TEST, '测试内置方法'],
]))
export const TextConfig = {
key: 'TextCommon',
title: '文字',
eventList
}

View File

@ -1,14 +1,15 @@
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, 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,
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,16 @@ const props = defineProps({
} }
}) })
const listeners = convertEventBusListeners({
on: {
[TextCommonEventEnum.TEST]: () => {
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,9 +31,30 @@ export type ConfigType = {
categoryName: string categoryName: string
package: string package: string
chartFrame?: ChartFrameEnum chartFrame?: ChartFrameEnum
eventList?: Array<OptionsType>
image: string | (() => Promise<typeof import('*.png')>) image: string | (() => Promise<typeof import('*.png')>)
} }
export type EventList = Array<{
name: string,
event: string,
type: string,
code: string,
uid: string,
[key: string]: any
}>
export type EventConfigValue = Record<string, {
title: string,
eventList: EventList
}>
export type EventConfig = {
[key: EventType]: EventConfigValue
}
// 数据请求 // 数据请求
interface requestConfig { interface requestConfig {
request: RequestConfigType, request: RequestConfigType,
@ -88,6 +118,8 @@ export interface CreateComponentType extends PublicConfigType {
key: string key: string
chartConfig: ConfigType chartConfig: ConfigType
option: GlobalThemeJsonType option: GlobalThemeJsonType
eventList: Array<OptionsType>
eventConfig: EventConfig
} }
// 获取组件实例类中某个key对应value类型的方法 // 获取组件实例类中某个key对应value类型的方法

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,15 @@ 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,
} from '@vicons/carbon' } from '@vicons/carbon'
const ionicons5 = { const ionicons5 = {
// 新增
AddIcon,
// 新增2
AddCircleIcon,
// 帮助(问号) // 帮助(问号)
HelpOutlineIcon, HelpOutlineIcon,
// 添加 // 添加
@ -194,6 +202,8 @@ const ionicons5 = {
ArrowForwardIcon, ArrowForwardIcon,
// 狗爪 // 狗爪
PawIcon, PawIcon,
// 重新加载
ReloadIcon,
// 搜索(放大镜) // 搜索(放大镜)
SearchIcon, SearchIcon,
// 过滤器 // 过滤器
@ -207,6 +217,7 @@ const ionicons5 = {
} }
const carbon = { const carbon = {
EditIcon,
// 图表 // 图表
RoadmapIcon, RoadmapIcon,
// 信息 // 信息

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

@ -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'
/** /**
* * * *
@ -28,3 +29,12 @@ export const loadSkeletonAsyncComponent = (loader: AsyncComponentLoader<any>) =>
loadingComponent: AsyncSkeletonLoading, loadingComponent: AsyncSkeletonLoading,
delay: 20, delay: 20,
}) })
export const getComponentConfig = (options: Omit<ConfigType, 'chartKey' | 'conKey' | 'id'>): Partial<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

@ -0,0 +1,275 @@
<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)">
<component :is="AddCircleIcon"></component>
</n-icon>
</template>
<n-empty
v-if="!item.eventList.length"
:show-icon="false">
</n-empty>
<template v-else>
<n-data-table
:row-key="(rowData:any) => rowData.uid"
:columns="columns"
:data="item.eventList"
/>
</template>
</n-collapse-item>
</n-collapse>
<n-modal
v-model:show="showModal"
preset="card"
: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;()&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
})
// ,
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],
eventList: []
}
}
})
}, {
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 commEventList = mapToOptions(CommonEventMap)
const componentMethodOptions = computed(() => {
return [
...commEventList,
...(selectedComponent.value ? (selectedComponent.value.chartConfig.eventList 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]).eventList.splice(rowIndex, 1)
}
}, () => h(icon.ionicons5.RemoveIcon))
]
}
})))
}},
]
const onSubmit = () => {
formRef.value?.validate((errors) => {
if (!errors && operateCollapse) {
if(model.value.uid){
const index = operateCollapse.eventList
.findIndex((item:any) => item.uid === model.value.uid)
if(index > -1){
operateCollapse.eventList[index] = {...model.value}
}
}else{
operateCollapse.eventList.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

@ -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,90 @@
<template>
<component
:is="item.chartConfig.chartKey"
:chartConfig="item"
:themeSetting="themeSetting"
:themeColor="themeColor"
:style="{...getSizeStyle(item.attr)}"
v-on="useEvent ? getEventList(item.eventConfig) : {}"
></component>
</template>
<script lang='ts' setup>
import { PropType, toRefs, getCurrentInstance, ComponentInternalInstance } from 'vue'
import { useEventBus } from '@/hooks'
import { convertEventBusListeners } from '@/hooks/useEventBus.hook'
import { getSizeStyle } from '../../utils'
import omit from 'lodash/omit'
import { EventTriggerType, EventType } from '@/enums/eventEnum'
import { CreateComponentType, EventConfig } from '@/packages/index.d'
import { newFunctionHandle } from '@/utils'
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 instance = getCurrentInstance() as ComponentInternalInstance
const bus = useEventBus()
/**
* @return
* {
* click: [fn1, fn2],
* change: [fn1, fn2],
* }
*/
const getEventList = (eventConfig: EventConfig) => {
const res = Object.keys(omit(eventConfig, EventType.OTHER)) // other
.reduce((previousValue: EventConfig, currentValue: string) => {
// @ts-ignore
previousValue[currentValue] = eventConfig[currentValue].eventList.map((item: any) => {
if(item.type === EventTriggerType.JAVASCRIPT){
return (config: CreateComponentType) => {
try {
newFunctionHandle(config, item.code)
} catch (error) {
console.error(error, item.code)
throw error
}
}
}else{
return () => {
bus.emit(`${item.componentId}:${item.componentMethod}`)
}
}
})
return previousValue
}, {} as EventConfig)
return res;
}
const listeners = {
on: {
forceUpdate: () => {
instance.ctx.$forceUpdate()
}
}
}
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: {