mirror of
https://gitee.com/dromara/go-view.git
synced 2025-10-15 23:06:33 +08:00
Pre Merge pull request !27 from 陪伴是最长情的告白¹³¹⁴/dev
This commit is contained in:
commit
ce3e5d8f34
@ -13,6 +13,7 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
env: {
|
||||
'vue/setup-compiler-macros': true,
|
||||
node: true,
|
||||
},
|
||||
extends: ["plugin:vue/vue3-essential", "eslint:recommended"],
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
node_modules
|
||||
.husky
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
|
@ -1,4 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
npx --no-install commitlint -e
|
21
package.json
21
package.json
@ -9,23 +9,27 @@
|
||||
"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",
|
||||
@ -33,27 +37,25 @@
|
||||
"vuedraggable": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/color": "^3.0.3",
|
||||
"@types/crypto-js": "^4.1.1",
|
||||
"@types/keymaster": "^1.6.30",
|
||||
"@commitlint/cli": "^17.0.2",
|
||||
"@commitlint/config-conventional": "^17.0.2",
|
||||
"@types/node": "^16.11.26",
|
||||
"@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",
|
||||
@ -65,7 +67,6 @@
|
||||
"vite-plugin-importer": "^0.2.5",
|
||||
"vite-plugin-mock": "^2.9.6",
|
||||
"vite-plugin-monaco-editor": "^1.1.0",
|
||||
"vue-echarts": "^6.0.2",
|
||||
"vue-tsc": "^0.28.10"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
38
src/enums/eventEnum.ts
Normal file
38
src/enums/eventEnum.ts
Normal 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', '强制更新'],
|
||||
]
|
||||
)
|
||||
|
@ -1,4 +1,5 @@
|
||||
export * from '@/hooks/useTheme.hook'
|
||||
export * from '@/hooks/usePreviewScale.hook'
|
||||
export * from '@/hooks/useCode.hook'
|
||||
export * from '@/hooks/useChartDataFetch.hook'
|
||||
export * from '@/hooks/useChartDataFetch.hook'
|
||||
export * from '@/hooks/useEventBus.hook'
|
67
src/hooks/useEventBus.hook.ts
Normal file
67
src/hooks/useEventBus.hook.ts
Normal 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
|
||||
}
|
@ -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'
|
||||
|
||||
export const BarCommonConfig: ConfigType = {
|
||||
export const BarCommonConfig: ConfigType = getComponentConfig({
|
||||
key: 'BarCommon',
|
||||
chartKey: 'VBarCommon',
|
||||
conKey: 'VCBarCommon',
|
||||
title: '柱状图',
|
||||
category: ChatCategoryEnum.BAR,
|
||||
categoryName: ChatCategoryEnumName.BAR,
|
||||
package: PackagesCategoryEnum.CHARTS,
|
||||
chartFrame: ChartFrameEnum.ECHARTS,
|
||||
image
|
||||
}
|
||||
})
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -1,14 +1,15 @@
|
||||
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, 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,
|
||||
eventList,
|
||||
image
|
||||
}
|
||||
})
|
@ -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,16 @@ const props = defineProps({
|
||||
}
|
||||
})
|
||||
|
||||
const listeners = convertEventBusListeners({
|
||||
on: {
|
||||
[TextCommonEventEnum.TEST]: () => {
|
||||
alert('这是我的内置方法')
|
||||
}
|
||||
}
|
||||
}, props.chartConfig.id)
|
||||
|
||||
useEventBus(listeners)
|
||||
|
||||
const { w, h } = toRefs(props.chartConfig.attr)
|
||||
const {
|
||||
dataset,
|
||||
|
32
src/packages/index.d.ts
vendored
32
src/packages/index.d.ts
vendored
@ -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,9 +31,30 @@ export type ConfigType = {
|
||||
categoryName: string
|
||||
package: string
|
||||
chartFrame?: ChartFrameEnum
|
||||
eventList?: Array<OptionsType>
|
||||
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 {
|
||||
request: RequestConfigType,
|
||||
@ -88,6 +118,8 @@ export interface CreateComponentType extends PublicConfigType {
|
||||
key: string
|
||||
chartConfig: ConfigType
|
||||
option: GlobalThemeJsonType
|
||||
eventList: Array<OptionsType>
|
||||
eventConfig: EventConfig
|
||||
}
|
||||
|
||||
// 获取组件实例类中某个key对应value类型的方法
|
||||
|
@ -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,15 @@ import {
|
||||
FitToHeight as FitToHeightIcon,
|
||||
FitToWidth as FitToWidthIcon,
|
||||
Filter as FilterIcon,
|
||||
FilterEdit as FilterEditIcon
|
||||
FilterEdit as FilterEditIcon,
|
||||
Edit as EditIcon,
|
||||
} from '@vicons/carbon'
|
||||
|
||||
const ionicons5 = {
|
||||
// 新增
|
||||
AddIcon,
|
||||
// 新增2
|
||||
AddCircleIcon,
|
||||
// 帮助(问号)
|
||||
HelpOutlineIcon,
|
||||
// 添加
|
||||
@ -194,6 +202,8 @@ const ionicons5 = {
|
||||
ArrowForwardIcon,
|
||||
// 狗爪
|
||||
PawIcon,
|
||||
// 重新加载
|
||||
ReloadIcon,
|
||||
// 搜索(放大镜)
|
||||
SearchIcon,
|
||||
// 过滤器
|
||||
@ -207,6 +217,7 @@ const ionicons5 = {
|
||||
}
|
||||
|
||||
const carbon = {
|
||||
EditIcon,
|
||||
// 图表
|
||||
RoadmapIcon,
|
||||
// 信息
|
||||
|
@ -131,6 +131,7 @@ export enum ChartEditStoreEnum {
|
||||
RECORD_CHART = 'recordChart',
|
||||
// 以下需要存储
|
||||
EDIT_CANVAS_CONFIG = 'editCanvasConfig',
|
||||
EVENT_CONFIG = 'eventConfig',
|
||||
REQUEST_GLOBAL_CONFIG = 'requestGlobalConfig',
|
||||
COMPONENT_LIST = 'componentList'
|
||||
}
|
||||
|
@ -30,7 +30,6 @@ import {
|
||||
RequestGlobalConfigType,
|
||||
EditCanvasConfigType
|
||||
} from './chartEditStore.d'
|
||||
|
||||
const chartHistoryStore = useChartHistoryStore()
|
||||
const settingStore = useSettingStore()
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { defineAsyncComponent, AsyncComponentLoader } from 'vue'
|
||||
import { AsyncLoading, AsyncSkeletonLoading } from '@/components/GoLoading'
|
||||
import { ConfigType } from '@/packages/index.d'
|
||||
|
||||
/**
|
||||
* * 动态注册组件
|
||||
@ -28,3 +29,12 @@ export const loadSkeletonAsyncComponent = (loader: AsyncComponentLoader<any>) =>
|
||||
loadingComponent: AsyncSkeletonLoading,
|
||||
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
6
src/utils/data.ts
Normal 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}
|
||||
});
|
@ -7,3 +7,4 @@ export * from '@/utils/plugin'
|
||||
export * from '@/utils/componets'
|
||||
export * from '@/utils/type'
|
||||
export * from '@/utils/file'
|
||||
export * from '@/utils/data'
|
@ -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> () {
|
||||
</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>
|
@ -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>
|
||||
|
@ -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(() => {
|
||||
|
@ -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>
|
@ -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: {
|
||||
|
Loading…
x
Reference in New Issue
Block a user