图标单击控制其他组件显示隐藏功能

zhufu
刘妍 2025-01-22 09:30:46 +08:00
parent 9af5bbdec2
commit 24e46f81e1
8 changed files with 452 additions and 186 deletions

View File

@ -36,8 +36,6 @@ export const useLifeHandler = (chartConfig: CreateComponentType | CreateComponen
generateFunc(fnStr, e)
}
}
console.log('baseEvent', baseEvent)
console.log('lifeEvents', lifeEvents)
return { ...baseEvent, ...lifeEvents }
}

View File

@ -1,31 +1,63 @@
<template>
<div class="go-icon-box">
<GoIconify :icon="((dataset || '') as string)" :color="color" :width="size" :rotate="rotate" />
<GoIconify
:icon="dataset || ''"
:color="color"
:width="size"
:rotate="rotate"
@click="clickBtn"
/>
</div>
</template>
<script setup lang="ts">
import { PropType, toRefs } from 'vue'
import { CreateComponentType } from '@/packages/index.d'
import { GoIconify } from '@/components/GoIconify'
import { PropType, toRefs } from 'vue';
import { CreateComponentType } from '@/packages/index.d';
import { GoIconify } from '@/components/GoIconify';
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore';
const props = defineProps({
chartConfig: {
type: Object as PropType<CreateComponentType>,
required: true
}
})
const chartEditStore = useChartEditStore();
const props = defineProps({
chartConfig: {
type: Object as PropType<CreateComponentType>,
required: true,
},
});
const { w, h } = toRefs(props.chartConfig.attr)
const { dataset, color, size, rotate } = toRefs(props.chartConfig.option)
const { w, h } = toRefs(props.chartConfig.attr);
const { dataset, color, size, rotate } = toRefs(props.chartConfig.option);
const clickBtn = () => {
const elementItem = props.chartConfig.events.interactConfigEvents.map((item: any) => {
if (item.type == 'click') {
return item;
}
});
var obj: any = {};
var index = 0;
for (let i = 0; i < chartEditStore.getComponentList.length; i++) {
for (let j = 0; j < elementItem.length; j++) {
if (chartEditStore.getComponentList[i].id == elementItem[j].elementId) {
obj = chartEditStore.getComponentList[i];
index = i;
//
if (elementItem[j].movement == 'reveal') {
obj.status.hide = false;
} else if (elementItem[j].movement == 'hidden') {
obj.status.hide = true;
}
chartEditStore.updateComponentList(index, obj);
}
}
}
};
</script>
<style lang="scss" scoped>
@include go('icon-box') {
display: flex;
align-items: center;
justify-content: center;
width: v-bind('`${w}px`');
height: v-bind('`${h}px`');
}
@include go('icon-box') {
display: flex;
align-items: center;
justify-content: center;
width: v-bind('`${w}px`');
height: v-bind('`${h}px`');
}
</style>

View File

@ -10,94 +10,97 @@
</template>
<script setup lang="ts">
import { computed, PropType, ref, shallowReactive, toRefs, watch } from 'vue'
import { CreateComponentType } from '@/packages/index.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { useChartInteract } from '@/hooks'
import { InteractEventOn } from '@/enums/eventEnum'
import {ComponentInteractEventEnum, ComponentInteractParamsEnum, DefaultTypeEnum} from './interact'
import dayjs, {ManipulateType} from 'dayjs'
import quarterOfYear from 'dayjs/plugin/quarterOfYear';
import { computed, PropType, ref, shallowReactive, toRefs, watch } from 'vue';
import { CreateComponentType } from '@/packages/index.d';
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore';
import { useChartInteract } from '@/hooks';
import { InteractEventOn } from '@/enums/eventEnum';
import {
ComponentInteractEventEnum,
ComponentInteractParamsEnum,
DefaultTypeEnum,
} from './interact';
import dayjs, { ManipulateType } from 'dayjs';
import quarterOfYear from 'dayjs/plugin/quarterOfYear';
const props = defineProps({
chartConfig: {
type: Object as PropType<CreateComponentType>,
required: true,
},
});
const props = defineProps({
chartConfig: {
type: Object as PropType<CreateComponentType>,
required: true
}
})
const { w, h } = toRefs(props.chartConfig.attr);
const rangeDate = ref<number | number[]>();
const { w, h } = toRefs(props.chartConfig.attr)
const rangeDate = ref<number | number[]>()
const option = shallowReactive({
dataset: props.chartConfig.option.dataset,
});
const option = shallowReactive({
dataset: props.chartConfig.option.dataset
})
const isRange = computed(() => {
return props.chartConfig.option.componentInteractEventKey.endsWith('range');
});
const isRange = computed(() => {
return props.chartConfig.option.componentInteractEventKey.endsWith('range')
})
//
const onChange = (v: number | number[] | null) => {
if (isRange.value) {
let dateStart = null
let dateEnd = null
let daterange = null
if(v instanceof Array){
dateStart = v[0]
dateEnd = v[1]
daterange = `${v[0]}-${v[1]}`
}
//
useChartInteract(
//
const onChange = (v: number | number[] | null) => {
if (isRange.value) {
let dateStart = null;
let dateEnd = null;
let daterange = null;
if (v instanceof Array) {
dateStart = v[0];
dateEnd = v[1];
daterange = `${v[0]}-${v[1]}`;
}
//
useChartInteract(
props.chartConfig,
useChartEditStore,
{
[ComponentInteractParamsEnum.DATE_START]: dateStart,
[ComponentInteractParamsEnum.DATE_END]: dateEnd,
[ComponentInteractParamsEnum.DATE_RANGE]: daterange
[ComponentInteractParamsEnum.DATE_RANGE]: daterange,
},
InteractEventOn.CHANGE
)
} else {
//
useChartInteract(
InteractEventOn.CHANGE,
);
} else {
//
useChartInteract(
props.chartConfig,
useChartEditStore,
{ [ComponentInteractParamsEnum.DATE]: v },
InteractEventOn.CHANGE
)
}
}
InteractEventOn.CHANGE,
);
}
};
const getDiffDate = (type: ComponentInteractEventEnum, date: dayjs.Dayjs) => {
// quarterOfYear
dayjs.extend(quarterOfYear)
switch (type) {
case ComponentInteractEventEnum.DATE:
case ComponentInteractEventEnum.DATE_RANGE:
date = date.startOf('day')
break
case ComponentInteractEventEnum.MONTH:
case ComponentInteractEventEnum.MONTH_RANGE:
date = date.startOf('month')
break
case ComponentInteractEventEnum.YEAR:
case ComponentInteractEventEnum.YEAR_RANGE:
date = date.startOf('year')
break
case ComponentInteractEventEnum.QUARTER:
case ComponentInteractEventEnum.QUARTER_RANGE:
date = date.startOf('quarter')
break
default:
break
}
return date
}
const getDiffDate = (type: ComponentInteractEventEnum, date: dayjs.Dayjs) => {
// quarterOfYear
dayjs.extend(quarterOfYear);
switch (type) {
case ComponentInteractEventEnum.DATE:
case ComponentInteractEventEnum.DATE_RANGE:
date = date.startOf('day');
break;
case ComponentInteractEventEnum.MONTH:
case ComponentInteractEventEnum.MONTH_RANGE:
date = date.startOf('month');
break;
case ComponentInteractEventEnum.YEAR:
case ComponentInteractEventEnum.YEAR_RANGE:
date = date.startOf('year');
break;
case ComponentInteractEventEnum.QUARTER:
case ComponentInteractEventEnum.QUARTER_RANGE:
date = date.startOf('quarter');
break;
default:
break;
}
return date;
};
watch(
watch(
() => {
return {
type: props.chartConfig.option.componentInteractEventKey as ComponentInteractEventEnum,
@ -113,18 +116,32 @@ watch(
const hasDifferValueChanged = newData.differValue !== oldData?.differValue;
const hasDifferUnitChanged = newData.differUnit !== oldData?.differUnit;
if (hasTypeChanged || hasDefaultTypeChanged || hasDifferValueChanged || hasDifferUnitChanged) {
if (
hasTypeChanged ||
hasDefaultTypeChanged ||
hasDifferValueChanged ||
hasDifferUnitChanged
) {
if (newData.defaultType === DefaultTypeEnum.NONE) {
props.chartConfig.option.dataset = null;
} else if (newData.defaultType === DefaultTypeEnum.DYNAMIC) {
let date = dayjs();
if (isRange.value) {
props.chartConfig.option.dataset = [
getDiffDate(newData.type,date.add(newData.differValue[0], newData.differUnit[0])).valueOf(),
getDiffDate(newData.type,date.add(newData.differValue[1], newData.differUnit[1])).valueOf(),
getDiffDate(
newData.type,
date.add(newData.differValue[0], newData.differUnit[0]),
).valueOf(),
getDiffDate(
newData.type,
date.add(newData.differValue[1], newData.differUnit[1]),
).valueOf(),
];
} else {
props.chartConfig.option.dataset = getDiffDate(newData.type,date.add(newData.differValue[0], newData.differUnit[0])).valueOf()
props.chartConfig.option.dataset = getDiffDate(
newData.type,
date.add(newData.differValue[0], newData.differUnit[0]),
).valueOf();
}
}
}
@ -133,16 +150,16 @@ watch(
},
{
immediate: true,
}
);
},
);
</script>
<style lang="scss" scoped>
@include deep() {
.n-input {
height: v-bind('h + "px"');
display: flex;
align-items: center;
@include deep() {
.n-input {
height: v-bind('h + "px"');
display: flex;
align-items: center;
}
}
}
</style>

View File

@ -1,6 +1,12 @@
import { BaseEvent, EventLife, InteractEvents, InteractEventOn, InteractActionsType } from '@/enums/eventEnum'
import type { GlobalThemeJsonType } from '@/settings/chartThemes/index'
import type { RequestConfigType } from '@/store/modules/chartEditStore/chartEditStore.d'
import {
BaseEvent,
EventLife,
InteractEvents,
InteractEventOn,
InteractActionsType,
} from '@/enums/eventEnum';
import type { GlobalThemeJsonType } from '@/settings/chartThemes/index';
import type { RequestConfigType } from '@/store/modules/chartEditStore/chartEditStore.d';
export enum ChartFrameEnum {
// 支持 dataset 的 echarts 框架
@ -12,56 +18,56 @@ export enum ChartFrameEnum {
// 自定义带数据组件
COMMON = 'common',
// 无数据变更
STATIC = 'static'
STATIC = 'static',
}
// 组件配置
export type ConfigType = {
// 组件 key
key: string
key: string;
// 画布组件 key
chartKey: string
chartKey: string;
// 右侧设置面板组件 key
conKey: string
conKey: string;
// 标题
title: string
title: string;
// 分类
category: string
category: string;
// 分类名称
categoryName: string
categoryName: string;
// 所属包
package: string
package: string;
// 归类
chartFrame?: ChartFrameEnum
chartFrame?: ChartFrameEnum;
// 预览图
image: string
image: string;
// 从指定路径创建创建该组件
redirectComponent?: string
redirectComponent?: string;
// 组件预设的 dataset 值(图片/图标)
dataset?: any
dataset?: any;
// 禁用 拖拽或双击生成组件
disabled?: boolean
disabled?: boolean;
// 图标
icon?: string
icon?: string;
// 事件
configEvents?: { [T: string]: Function }
}
configEvents?: { [T: string]: Function };
};
// 数据请求
interface requestConfig {
request: RequestConfigType
request: RequestConfigType;
}
// Echarts 数据类型
interface EchartsDataType {
dimensions: string[]
source: any[]
dimensions: string[];
source: any[];
}
// 组件状态
export interface StatusType {
lock: boolean
hide: boolean
lock: boolean;
hide: boolean;
}
// 滤镜/变换枚举
@ -90,7 +96,7 @@ export enum FilterEnum {
SKEW_Y = 'skewY',
// 混合模式
BLEND_MODE = 'blendMode'
BLEND_MODE = 'blendMode',
}
export const BlendModeEnumList = [
@ -109,68 +115,80 @@ export const BlendModeEnumList = [
{ label: '色相', value: 'hue' },
{ label: '饱和度', value: 'saturation' },
{ label: '颜色', value: 'color' },
{ label: '亮度', value: 'luminosity' }
]
{ label: '亮度', value: 'luminosity' },
];
// 组件实例类
export interface PublicConfigType {
id: string
isGroup: boolean
attr: { x: number; y: number; w: number; h: number; zIndex: number; offsetX: number; offsetY: number }
id: string;
isGroup: boolean;
attr: {
x: number;
y: number;
w: number;
h: number;
zIndex: number;
offsetX: number;
offsetY: number;
};
styles: {
[FilterEnum.FILTERS_SHOW]: boolean
[FilterEnum.OPACITY]: number
[FilterEnum.SATURATE]: number
[FilterEnum.CONTRAST]: number
[FilterEnum.HUE_ROTATE]: number
[FilterEnum.BRIGHTNESS]: number
[FilterEnum.FILTERS_SHOW]: boolean;
[FilterEnum.OPACITY]: number;
[FilterEnum.SATURATE]: number;
[FilterEnum.CONTRAST]: number;
[FilterEnum.HUE_ROTATE]: number;
[FilterEnum.BRIGHTNESS]: number;
[FilterEnum.ROTATE_Z]: number
[FilterEnum.ROTATE_X]: number
[FilterEnum.ROTATE_Y]: number
[FilterEnum.ROTATE_Z]: number;
[FilterEnum.ROTATE_X]: number;
[FilterEnum.ROTATE_Y]: number;
[FilterEnum.SKEW_X]: number
[FilterEnum.SKEW_Y]: number
[FilterEnum.BLEND_MODE]: string
[FilterEnum.SKEW_X]: number;
[FilterEnum.SKEW_Y]: number;
[FilterEnum.BLEND_MODE]: string;
// 动画
animations: string[]
}
animations: string[];
};
preview?: {
// 预览超出隐藏
overFlowHidden?: boolean
}
filter?: string
status: StatusType
interactActions?: InteractActionsType[]
overFlowHidden?: boolean;
};
filter?: string;
status: StatusType;
interactActions?: InteractActionsType[];
events: {
baseEvent: {
[K in BaseEvent]?: string
}
[K in BaseEvent]?: string;
};
advancedEvents: {
[K in EventLife]?: string
}
[K in EventLife]?: string;
};
interactEvents: {
[InteractEvents.INTERACT_ON]: InteractEventOn | undefined
[InteractEvents.INTERACT_COMPONENT_ID]: string | undefined
[InteractEvents.INTERACT_FN]: { [name: string]: string }
}[]
}
[InteractEvents.INTERACT_ON]: InteractEventOn | undefined;
[InteractEvents.INTERACT_COMPONENT_ID]: string | undefined;
[InteractEvents.INTERACT_FN]: { [name: string]: string };
}[];
interactConfigEvents: {}[];
};
}
export interface CreateComponentType extends PublicConfigType, requestConfig {
key: string
chartConfig: ConfigType
option: GlobalThemeJsonType
groupList?: Array<CreateComponentType>
key: string;
chartConfig: ConfigType;
option: GlobalThemeJsonType;
groupList?: Array<CreateComponentType>;
}
// 组件成组实例类
export interface CreateComponentGroupType extends CreateComponentType {
groupList: Array<CreateComponentType>
groupList: Array<CreateComponentType>;
}
// 获取组件实例类中某个key对应value类型的方法
export type PickCreateComponentType<T extends keyof CreateComponentType> = Pick<CreateComponentType, T>[T]
export type PickCreateComponentType<T extends keyof CreateComponentType> = Pick<
CreateComponentType,
T
>[T];
// 包分类枚举
export enum PackagesCategoryEnum {
@ -182,7 +200,7 @@ export enum PackagesCategoryEnum {
ICONS = 'Icons',
DECORATES = 'Decorates',
CUSTOM = 'Custom',
DIY = 'Diy'
DIY = 'Diy',
}
// 包分类名称
@ -195,24 +213,24 @@ export enum PackagesCategoryName {
ICONS = '图标',
DECORATES = '小组件',
CUSTOM = '预警信息',
DIY = 'DIY'
DIY = 'DIY',
}
// 获取组件
export enum FetchComFlagType {
VIEW,
CONFIG
CONFIG,
}
// 图表包类型
export type PackagesType = {
[PackagesCategoryEnum.CHARTS]: ConfigType[]
[PackagesCategoryEnum.VCHART]: ConfigType[]
[PackagesCategoryEnum.INFORMATIONS]: ConfigType[]
[PackagesCategoryEnum.TABLES]: ConfigType[]
[PackagesCategoryEnum.PHOTOS]: ConfigType[]
[PackagesCategoryEnum.ICONS]: ConfigType[]
[PackagesCategoryEnum.DECORATES]: ConfigType[]
[PackagesCategoryEnum.CUSTOM]: ConfigType[]
[PackagesCategoryEnum.DIY]: ConfigType[]
}
[PackagesCategoryEnum.CHARTS]: ConfigType[];
[PackagesCategoryEnum.VCHART]: ConfigType[];
[PackagesCategoryEnum.INFORMATIONS]: ConfigType[];
[PackagesCategoryEnum.TABLES]: ConfigType[];
[PackagesCategoryEnum.PHOTOS]: ConfigType[];
[PackagesCategoryEnum.ICONS]: ConfigType[];
[PackagesCategoryEnum.DECORATES]: ConfigType[];
[PackagesCategoryEnum.CUSTOM]: ConfigType[];
[PackagesCategoryEnum.DIY]: ConfigType[];
};

View File

@ -103,7 +103,8 @@ export class PublicConfigClass implements PublicConfigType {
[EventLife.VNODE_MOUNTED]: undefined,
[EventLife.VNODE_BEFORE_MOUNT]: undefined
},
interactEvents: []
interactEvents: [],
interactConfigEvents:[]
}
}

View File

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

View File

@ -0,0 +1,195 @@
<template>
<n-collapse-item title="组件交互事件配置" name="2">
<template #header-extra>
<n-button type="primary" tertiary size="small" @click.stop="addEvent">
<template #icon>
<n-icon>
<pencil-icon />
</n-icon>
</template>
编辑
</n-button>
</template>
<!-- 无数据 -->
<div v-if="!targetData.events.interactConfigEvents.length" class="no-data go-flex-center">
<img :src="noData" alt="暂无数据" />
<n-text :depth="3">暂无内容</n-text>
</div>
<n-card
v-for="(item, cardIndex) in targetData.events.interactConfigEvents"
:key="cardIndex"
class="n-card-shallow"
size="small"
>
<n-divider style="margin: 10px 0" />
<n-tag
:bordered="false"
type="primary"
closable
@click="editEvent(item)"
@close="evDeleteEventsFn(cardIndex)"
>
动作{{ cardIndex + 1 }}
</n-tag>
</n-card>
</n-collapse-item>
<!-- 弹窗 -->
<n-modal class="go-chart-data-monaco-editor" v-model:show="showModal" :mask-closable="false">
<n-card
:bordered="false"
role="dialog"
size="small"
aria-modal="true"
style="width: 1200px; height: 700px"
>
<template #header>
<n-space>
<n-text>交互编辑器</n-text>
</n-space>
</template>
<template #header-extra> </template>
<n-layout has-sider sider-placement="right">
<n-layout style="height: 580px; padding-right: 20px">
<setting-item-box name="类型" :alone="true">
<n-select v-model:value="interactConfigItem.type" :options="eventSelectOptions" />
</setting-item-box>
<setting-item-box name="执行动作" :alone="true">
<n-select
v-model:value="interactConfigItem.movement"
:options="movementSelectOptions"
/>
</setting-item-box>
<setting-item-box name="关联组件" :alone="true">
<n-select
v-model:value="interactConfigItem.elementId"
:options="elementSelectOptions"
/>
</setting-item-box>
</n-layout>
</n-layout>
<template #action>
<n-space justify="space-between">
<div class="go-flex-items-center">
<n-tag :bordered="false" type="primary">
<template #icon>
<n-icon :component="DocumentTextIcon" />
</template>
说明
</n-tag>
<n-text class="go-ml-2" depth="2">请在预览页面查看结果</n-text>
</div>
<n-space>
<n-button size="medium" @click="closeEvents"></n-button>
<n-button size="medium" type="primary" @click="saveEvents"></n-button>
</n-space>
</n-space>
</template>
</n-card>
</n-modal>
</template>
<script setup lang="ts">
import { ref, computed, watch, toRefs, toRaw } from 'vue';
import { MonacoEditor } from '@/components/Pages/MonacoEditor';
import { useTargetData } from '../../../hooks/useTargetData.hook';
import { BaseEvent } from '@/enums/eventEnum';
import { icon } from '@/plugins';
import { SettingItemBox } from '@/components/Pages/ChartItemSetting';
import noData from '@/assets/images/canvas/noData.png';
import { goDialog } from '@/utils';
const { targetData, chartEditStore } = useTargetData();
const { DocumentTextIcon, CloseIcon, PencilIcon } = icon.ionicons5;
const interactConfigItem: any = ref({
type: '',
movement: '',
elementId: '',
});
//
const eventSelectOptions = [
{
label: '单击',
value: 'click',
},
{
label: '双击',
value: 'dblclick',
},
];
const movementSelectOptions = [
{
label: '显示',
value: 'reveal',
},
{
label: '隐藏',
value: 'hidden',
},
];
console.log(chartEditStore.getComponentList);
const elementSelectOptions = ref(
chartEditStore.getComponentList.map((item) => {
return {
label: item.isGroup ? '分组-' + item.id : '组件-' + item.id,
value: item.id,
};
}),
);
//
const showModal = ref(false);
//
// events
let interactConfigEvents = ref({ ...targetData.value.events.interactConfigEvents });
//
//
const closeEvents = () => {
showModal.value = false;
};
//
const saveEvents = () => {
console.log(interactConfigItem.value);
targetData.value.events.interactConfigEvents.push({ ...interactConfigItem.value });
closeEvents();
};
watch(
() => showModal.value,
(newData: boolean) => {
if (newData) {
interactConfigEvents.value = { ...targetData.value.events.interactConfigEvents };
}
},
);
const addEvent = () => {
showModal.value = true;
interactConfigItem.value = {
type: '',
movement: '',
elementId: '',
};
};
const editEvent = (item: any) => {
showModal.value = true;
interactConfigItem.value = { ...item };
};
//
const evDeleteEventsFn = (index: number) => {
goDialog({
message: '是否删除此动作?',
onPositiveCallback: () => {
targetData.value.events.interactConfigEvents.splice(index, 1);
},
});
};
</script>
<style lang="scss" scoped>
@import '../index.scss';
</style>

View File

@ -5,14 +5,16 @@
组件 id
<n-text>{{ targetData.id }}</n-text>
</n-text>
<chart-event-interaction></chart-event-interaction>
<chart-event-base-handle></chart-event-base-handle>
<chart-event-advanced-handle></chart-event-advanced-handle>
<chart-event-interaction-configuration />
<chart-event-interaction />
<chart-event-base-handle />
<chart-event-advanced-handle />
</n-collapse>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { ChartEventInteractionConfiguration } from './components/ChartEventInteractionConfiguration';
import { ChartEventInteraction } from './components/ChartEventInteraction';
import { ChartEventAdvancedHandle } from './components/ChartEventAdvancedHandle';
import { ChartEventBaseHandle } from './components/ChartEventBaseHandle';