feat: 新增事件系统

This commit is contained in:
yangmi 2022-07-21 10:33:40 +08:00
parent c2f9f449e8
commit e33bded469
21 changed files with 597 additions and 37 deletions

View File

@ -9,31 +9,32 @@
"postinstall": "husky install" "postinstall": "husky install"
}, },
"dependencies": { "dependencies": {
"@vicons/carbon": "^0.12.0",
"@vicons/ionicons5": "~0.11.0",
"@vueuse/core": "^7.7.1",
"animate.css": "^4.1.1", "animate.css": "^4.1.1",
"axios": "0.23.0", "axios": "0.23.0",
"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",
"vue3-sketch-ruler": "^1.3.3", "vue3-sketch-ruler": "^1.3.3",
"vuedraggable": "^4.1.0", "vuedraggable": "^4.1.0"
"@vueuse/core": "^7.7.1",
"@vicons/carbon": "^0.12.0",
"@vicons/ionicons5": "~0.11.0",
"echarts": "^5.3.2",
"vue-echarts": "^6.0.2",
"lodash": "~4.17.21"
}, },
"devDependencies": { "devDependencies": {
"@types/color": "^3.0.3", "@types/color": "^3.0.3",
@ -68,4 +69,4 @@
"vite-plugin-monaco-editor": "^1.1.0", "vite-plugin-monaco-editor": "^1.1.0",
"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,
} from '@vicons/ionicons5' } from '@vicons/ionicons5'
import { import {
@ -82,10 +85,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,
// 添加 // 添加
@ -198,6 +206,7 @@ const ionicons5 = {
} }
const carbon = { const carbon = {
EditIcon,
// 图表 // 图表
RoadmapIcon, RoadmapIcon,
// 信息 // 信息

View File

@ -126,6 +126,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

@ -29,7 +29,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

@ -1,13 +1,275 @@
<template> <template>
<div> <n-collapse :default-expanded-names="Object.values(EventType)">
事件 <!-- todo 暂时用any -->
</div> <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> </template>
<script setup> <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> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.func-keyword {
color: #b478cf;
}
</style> </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: {