feat: 合并多选功能,解决冲突,升级版本到2.0.4

This commit is contained in:
奔跑的面条 2022-08-19 10:44:44 +08:00
commit fa34300401
55 changed files with 1746 additions and 641 deletions

View File

@ -122,6 +122,6 @@ export const http = (type?: RequestHttpEnum) => {
QQ 群1030129384 QQ 群1030129384
![QQ群](readme/goView-QQ.png) ![QQ群](readme/go-view-qq.png)
![渲染海报](readme/logo-poster.png) ![渲染海报](readme/logo-poster.png)

View File

@ -1,6 +1,6 @@
{ {
"name": "go-view", "name": "go-view",
"version": "2.0.3", "version": "2.0.4",
"scripts": { "scripts": {
"dev": "vite --host", "dev": "vite --host",
"build": "vue-tsc --noEmit && vite build", "build": "vue-tsc --noEmit && vite build",

View File

Before

Width:  |  Height:  |  Size: 398 KiB

After

Width:  |  Height:  |  Size: 398 KiB

BIN
readme/go-view-color.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

BIN
readme/go-view-fetch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

BIN
readme/go-view-filter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -3,6 +3,7 @@
<n-input-number <n-input-number
v-model:value="chartAttr.w" v-model:value="chartAttr.w"
:min="50" :min="50"
:disabled="isGroup"
size="small" size="small"
placeholder="px" placeholder="px"
> >
@ -13,6 +14,7 @@
<n-input-number <n-input-number
v-model:value="chartAttr.h" v-model:value="chartAttr.h"
:min="50" :min="50"
:disabled="isGroup"
size="small" size="small"
placeholder="px" placeholder="px"
> >
@ -32,6 +34,10 @@ const props = defineProps({
chartAttr: { chartAttr: {
type: Object as PropType<Omit<PickCreateComponentType<'attr'>, 'node' | 'conNode'>>, type: Object as PropType<Omit<PickCreateComponentType<'attr'>, 'node' | 'conNode'>>,
required: true required: true
},
isGroup: {
type: Boolean,
required: false
} }
}) })
</script> </script>

View File

@ -1,4 +1,9 @@
<template> <template>
<div v-show="isGroup">
<n-divider n-divider style="margin: 10px 0"></n-divider>
<n-tag type="warning"> 解散分组 {{ isCanvas ? '滤镜' : '滤镜 / 变换' }} 也将消失!</n-tag>
</div>
<collapse-item :name="isCanvas ? '滤镜' : '滤镜 / 变换'"> <collapse-item :name="isCanvas ? '滤镜' : '滤镜 / 变换'">
<setting-item-box name="色相" :alone="true"> <setting-item-box name="色相" :alone="true">
<setting-item :name="`值:${chartStyles.hueRotate}deg`"> <setting-item :name="`值:${chartStyles.hueRotate}deg`">
@ -13,9 +18,7 @@
</setting-item> </setting-item>
</setting-item-box> </setting-item-box>
<setting-item-box name="饱和度" :alone="true"> <setting-item-box name="饱和度" :alone="true">
<setting-item <setting-item :name="`值:${(parseFloat(String(chartStyles.saturate)) * 100).toFixed(0)}%`">
:name="`值:${(parseFloat(String(chartStyles.saturate)) * 100).toFixed(0)}%`"
>
<!-- 透明度 --> <!-- 透明度 -->
<n-slider <n-slider
v-model:value="chartStyles.saturate" v-model:value="chartStyles.saturate"
@ -27,9 +30,7 @@
</setting-item> </setting-item>
</setting-item-box> </setting-item-box>
<setting-item-box name="对比度" :alone="true"> <setting-item-box name="对比度" :alone="true">
<setting-item <setting-item :name="`值:${(parseFloat(String(chartStyles.contrast)) * 100).toFixed(0)}%`">
:name="`值:${(parseFloat(String(chartStyles.contrast)) * 100).toFixed(0)}%`"
>
<!-- 透明度 --> <!-- 透明度 -->
<n-slider <n-slider
v-model:value="chartStyles.contrast" v-model:value="chartStyles.contrast"
@ -41,9 +42,7 @@
</setting-item> </setting-item>
</setting-item-box> </setting-item-box>
<setting-item-box name="亮度" :alone="true"> <setting-item-box name="亮度" :alone="true">
<setting-item <setting-item :name="`值:${(parseFloat(String(chartStyles.brightness)) * 100).toFixed(0)}%`">
:name="`值:${(parseFloat(String(chartStyles.brightness)) * 100).toFixed(0)}%`"
>
<!-- 透明度 --> <!-- 透明度 -->
<n-slider <n-slider
v-model:value="chartStyles.brightness" v-model:value="chartStyles.brightness"
@ -55,9 +54,7 @@
</setting-item> </setting-item>
</setting-item-box> </setting-item-box>
<setting-item-box name="透明度" :alone="true"> <setting-item-box name="透明度" :alone="true">
<setting-item <setting-item :name="`值:${(parseFloat(String(chartStyles.opacity)) * 100).toFixed(0)}%`">
:name="`值:${(parseFloat(String(chartStyles.opacity)) * 100).toFixed(0)}%`"
>
<!-- 透明度 --> <!-- 透明度 -->
<n-slider <n-slider
v-model:value="chartStyles.opacity" v-model:value="chartStyles.opacity"
@ -68,7 +65,7 @@
></n-slider> ></n-slider>
</setting-item> </setting-item>
</setting-item-box> </setting-item-box>
<!-- 变换 --> <!-- 变换 -->
<setting-item-box v-if="!isCanvas" name="旋转°"> <setting-item-box v-if="!isCanvas" name="旋转°">
<setting-item name="Z轴(平面) - 旋转"> <setting-item name="Z轴(平面) - 旋转">
@ -130,21 +127,21 @@
<script setup lang="ts"> <script setup lang="ts">
import { PropType } from 'vue' import { PropType } from 'vue'
import { PickCreateComponentType } from '@/packages/index.d' import { PickCreateComponentType } from '@/packages/index.d'
import { import { SettingItemBox, SettingItem, CollapseItem } from '@/components/Pages/ChartItemSetting'
SettingItemBox,
SettingItem,
CollapseItem,
} from '@/components/Pages/ChartItemSetting'
const props = defineProps({ const props = defineProps({
isGroup: {
type: Boolean,
required: false
},
isCanvas: { isCanvas: {
type: Boolean, type: Boolean,
default: false default: false
}, },
chartStyles: { chartStyles: {
type: Object as PropType<Omit<PickCreateComponentType<'styles'>, 'animations'>>, type: Object as PropType<Omit<PickCreateComponentType<'styles'>, 'animations'>>,
required: true, required: true
}, }
}) })
// persen // persen

View File

@ -1,23 +1,44 @@
// 页面拖拽键名 // 鼠标点击左右键
export enum DragKeyEnum { export enum MouseEventButton {
DROG_KEY = 'ChartData' LEFT = 1,
RIGHT = 2,
} }
// 右键枚举 // 页面拖拽键名
export enum DragKeyEnum {
DRAG_KEY = 'ChartData'
}
// 操作枚举
export enum MenuEnum { export enum MenuEnum {
// 移动
ARROW_UP = 'up', ARROW_UP = 'up',
ARROW_RIGHT = 'right', ARROW_RIGHT = 'right',
ARROW_DOWN = 'down', ARROW_DOWN = 'down',
ARROW_LEFT = 'left', ARROW_LEFT = 'left',
// 删除
DELETE = 'delete', DELETE = 'delete',
// 复制
COPY = 'copy', COPY = 'copy',
// 剪切
CUT = 'cut', CUT = 'cut',
// 粘贴
PARSE = 'parse', PARSE = 'parse',
// 置顶
TOP = 'top', TOP = 'top',
// 置底
BOTTOM = 'bottom', BOTTOM = 'bottom',
// 上移
UP = 'up', UP = 'up',
// 下移
DOWN = 'down', DOWN = 'down',
// 清空剪贴板
CLEAR = 'clear', CLEAR = 'clear',
// 成组
GROUP = 'group',
// 解组
UN_GROUP = 'unGroup',
// 后退
BACK = 'back', BACK = 'back',
FORWORD = 'forward', FORWORD = 'forward',
SAVE = 'save' SAVE = 'save'
@ -28,6 +49,9 @@ export enum WinKeyboard {
CTRL = 'ctrl', CTRL = 'ctrl',
SHIFT = 'shift', SHIFT = 'shift',
ALT = ' alt', ALT = ' alt',
CTRL_SOURCE_KEY = "control",
SHIFT_SOURCE_KEY = "shift",
ALT_SOURCE_KEY = "alt"
} }
// Mac 键盘枚举 // Mac 键盘枚举
@ -48,4 +72,4 @@ export enum SyncEnum {
SUCCESS, SUCCESS,
// 失败 // 失败
FAILURE FAILURE
} }

View File

@ -27,12 +27,12 @@ export type ConfigType = {
// 数据请求 // 数据请求
interface requestConfig { interface requestConfig {
request: RequestConfigType, request: RequestConfigType
} }
// Echarts 数据类型 // Echarts 数据类型
interface EchartsDataType { interface EchartsDataType {
dimensions: string[], dimensions: string[]
source: any[] source: any[]
} }
@ -56,27 +56,27 @@ export enum FilterEnum {
// 倾斜 // 倾斜
SKEW_X = 'skewX', SKEW_X = 'skewX',
SKEW_Y = 'skewY', SKEW_Y = 'skewY'
} }
// 组件实例类 // 组件实例类
export interface PublicConfigType extends requestConfig { export interface PublicConfigType {
id: string id: string
rename?: string isGroup: boolean
attr: { x: number; y: number; w: number; h: number; zIndex: number } attr: { x: number; y: number; w: number; h: number; zIndex: number }
styles: { styles: {
[FilterEnum.OPACITY]: number; [FilterEnum.OPACITY]: number
[FilterEnum.SATURATE]: number; [FilterEnum.SATURATE]: number
[FilterEnum.CONTRAST]: number; [FilterEnum.CONTRAST]: number
[FilterEnum.HUE_ROTATE]: number; [FilterEnum.HUE_ROTATE]: number
[FilterEnum.BRIGHTNESS]: number; [FilterEnum.BRIGHTNESS]: number
[FilterEnum.ROTATE_Z]: number; [FilterEnum.ROTATE_Z]: number
[FilterEnum.ROTATE_X]: number; [FilterEnum.ROTATE_X]: number
[FilterEnum.ROTATE_Y]: number; [FilterEnum.ROTATE_Y]: number
[FilterEnum.SKEW_X]: number; [FilterEnum.SKEW_X]: number
[FilterEnum.SKEW_Y]: number; [FilterEnum.SKEW_Y]: number
// 动画 // 动画
animations: string[] animations: string[]
} }
@ -84,12 +84,17 @@ export interface PublicConfigType extends requestConfig {
setPosition: Function setPosition: Function
} }
export interface CreateComponentType extends PublicConfigType { export interface CreateComponentType extends PublicConfigType, requestConfig {
key: string key: string
chartConfig: ConfigType chartConfig: ConfigType
option: GlobalThemeJsonType option: GlobalThemeJsonType
} }
// 组件成组实例类
export interface CreateComponentGroupType extends CreateComponentType {
groupList: Array<CreateComponentType>
}
// 获取组件实例类中某个key对应value类型的方法 // 获取组件实例类中某个key对应value类型的方法
export type PickCreateComponentType<T extends keyof CreateComponentType> = Pick<CreateComponentType, T>[T] export type PickCreateComponentType<T extends keyof CreateComponentType> = Pick<CreateComponentType, T>[T]

View File

@ -1,6 +1,7 @@
import { getUUID } from '@/utils' import { getUUID } from '@/utils'
import { PublicConfigType } from '@/packages/index.d' import { ChartFrameEnum, PublicConfigType, CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
import { RequestConfigType } from '@/store/modules/chartEditStore/chartEditStore.d' import { RequestConfigType } from '@/store/modules/chartEditStore/chartEditStore.d'
import { groupTitle } from '@/settings/designSetting'
import { import {
RequestHttpEnum, RequestHttpEnum,
RequestDataTypeEnum, RequestDataTypeEnum,
@ -10,6 +11,7 @@ import {
} from '@/enums/httpEnum' } from '@/enums/httpEnum'
import { chartInitConfig } from '@/settings/designSetting' import { chartInitConfig } from '@/settings/designSetting'
// 请求基础属性
const requestConfig: RequestConfigType = { const requestConfig: RequestConfigType = {
requestDataType: RequestDataTypeEnum.STATIC, requestDataType: RequestDataTypeEnum.STATIC,
requestHttpType: RequestHttpEnum.GET, requestHttpType: RequestHttpEnum.GET,
@ -33,10 +35,10 @@ const requestConfig: RequestConfigType = {
} }
} }
// 单实例类
export class publicConfig implements PublicConfigType { export class publicConfig implements PublicConfigType {
public id = getUUID() public id = getUUID()
// 重命名 public isGroup = false
public rename = undefined
// 基本信息 // 基本信息
public attr = { ...chartInitConfig, zIndex: -1 } public attr = { ...chartInitConfig, zIndex: -1 }
// 基本样式 // 基本样式
@ -75,3 +77,32 @@ export class publicConfig implements PublicConfigType {
this.attr.y = y this.attr.y = y
} }
} }
// 成组类 (部分属性不需要, 不继承 publicConfig)
export class PublicGroupConfigClass extends publicConfig implements CreateComponentGroupType {
// 成组
public isGroup = true
// 名称
public chartConfig = {
key: 'group',
chartKey: 'group',
conKey: 'group',
category: 'group',
categoryName: 'group',
package: 'group',
chartFrame: ChartFrameEnum.COMMON,
title: groupTitle,
image: ''
}
// 组成员列表
public groupList: Array<CreateComponentType> = []
// ---- 原有 ---
// key
public key = 'group'
// 配置
public option = {}
// 标识
public id = getUUID()
// 基本信息
public attr = { w: 0, h: 0, x: 0, y: 0, zIndex: -1 }
}

View File

@ -56,7 +56,9 @@ import {
Reload as ReloadIcon, Reload as ReloadIcon,
ChevronUpOutline as ChevronUpOutlineIcon, ChevronUpOutline as ChevronUpOutlineIcon,
ChevronDownOutline as ChevronDownOutlineIcon, ChevronDownOutline as ChevronDownOutlineIcon,
Pulse as PulseIcon Pulse as PulseIcon,
Folder as FolderIcon,
FolderOpen as FolderOpenIcon
} from '@vicons/ionicons5' } from '@vicons/ionicons5'
import { import {
@ -86,6 +88,8 @@ import {
FitToHeight as FitToHeightIcon, FitToHeight as FitToHeightIcon,
FitToWidth as FitToWidthIcon, FitToWidth as FitToWidthIcon,
Save as SaveIcon, Save as SaveIcon,
Carbon3DCursor as Carbon3DCursorIcon,
Carbon3DSoftware as Carbon3DSoftwareIcon,
Filter as FilterIcon, Filter as FilterIcon,
FilterEdit as FilterEditIcon FilterEdit as FilterEditIcon
} from '@vicons/carbon' } from '@vicons/carbon'
@ -207,7 +211,11 @@ const ionicons5 = {
// 向下 // 向下
ChevronDownOutlineIcon, ChevronDownOutlineIcon,
// 脉搏 // 脉搏
PulseIcon PulseIcon,
// 文件夹
FolderIcon,
// 文件夹打开
FolderOpenIcon
} }
const carbon = { const carbon = {
@ -254,6 +262,10 @@ const carbon = {
FitToWidthIcon, FitToWidthIcon,
// 保存 // 保存
SaveIcon, SaveIcon,
// 成组
Carbon3DCursorIcon,
// 解组
Carbon3DSoftwareIcon,
// 过滤器 // 过滤器
FilterIcon, FilterIcon,
FilterEditIcon FilterEditIcon

View File

@ -8,6 +8,9 @@ export const lang = LangEnum.ZH
// 水印文字 // 水印文字
export const watermarkText = "GoView 低代码平台" export const watermarkText = "GoView 低代码平台"
// 分组名称
export const groupTitle = "分组"
// 主题配置 // 主题配置
export const theme = { export const theme = {
// 默认是否开启深色主题 // 默认是否开启深色主题
@ -37,7 +40,7 @@ export const asideCollapsedWidth = 60
// 弹窗是否可以通过点击遮罩关闭 // 弹窗是否可以通过点击遮罩关闭
export const maskClosable = false export const maskClosable = false
// 修改边框圆角 // 全局边框圆角
export const borderRadius = '6px' export const borderRadius = '6px'
// 轮播间隔 // 轮播间隔
@ -59,4 +62,10 @@ export const saveInterval = 30
export const requestIntervalUnit = RequestHttpIntervalEnum.SECOND export const requestIntervalUnit = RequestHttpIntervalEnum.SECOND
// 工作区域历史记录存储最大数量 // 工作区域历史记录存储最大数量
export const editHistoryMax = 100 export const editHistoryMax = 100
// 拖拽时蒙层的 z-index需比所有图表高
export const canvasModelIndex = 9999
// 框选时蒙层的 z-index需比所有图表高
export const selectBoxIndex = canvasModelIndex + 10

View File

@ -1,4 +1,4 @@
import { CreateComponentType, FilterEnum } from '@/packages/index.d' import { CreateComponentType, CreateComponentGroupType, FilterEnum } from '@/packages/index.d'
import { HistoryActionTypeEnum } from '@/store/modules/chartHistoryStore/chartHistoryStore.d' import { HistoryActionTypeEnum } from '@/store/modules/chartHistoryStore/chartHistoryStore.d'
import { SyncEnum } from '@/enums/editPageEnum' import { SyncEnum } from '@/enums/editPageEnum'
import { import {
@ -41,9 +41,10 @@ export enum EditCanvasTypeEnum {
SCALE = 'scale', SCALE = 'scale',
USER_SCALE = 'userScale', USER_SCALE = 'userScale',
LOCK_SCALE = 'lockScale', LOCK_SCALE = 'lockScale',
SAVE_STATUS = 'saveStatus',
IS_CREATE = 'isCreate', IS_CREATE = 'isCreate',
IS_DRAG = 'isDrag', IS_DRAG = 'isDrag',
SAVE_STATUS = 'saveStatus' IS_SELECT = 'isSelect'
} }
// 编辑区域(临时) // 编辑区域(临时)
@ -65,6 +66,8 @@ export type EditCanvasType = {
[EditCanvasTypeEnum.IS_DRAG]: boolean [EditCanvasTypeEnum.IS_DRAG]: boolean
// 保存状态 // 保存状态
[EditCanvasTypeEnum.SAVE_STATUS]: SyncEnum [EditCanvasTypeEnum.SAVE_STATUS]: SyncEnum
// 框选中
[EditCanvasTypeEnum.IS_SELECT]: boolean
} }
// 画布数据/滤镜/背景色/宽高主题等 // 画布数据/滤镜/背景色/宽高主题等
@ -146,7 +149,7 @@ export type TargetChartType = {
// 数据记录 // 数据记录
export type RecordChartType = { export type RecordChartType = {
charts: CreateComponentType | CreateComponentType[] charts: CreateComponentType | CreateComponentGroupType | Array<CreateComponentType | CreateComponentGroupType>
type: HistoryActionTypeEnum.CUT | HistoryActionTypeEnum.COPY type: HistoryActionTypeEnum.CUT | HistoryActionTypeEnum.COPY
} }
@ -211,12 +214,12 @@ export interface ChartEditStoreType {
[ChartEditStoreEnum.TARGET_CHART]: TargetChartType [ChartEditStoreEnum.TARGET_CHART]: TargetChartType
[ChartEditStoreEnum.RECORD_CHART]?: RecordChartType [ChartEditStoreEnum.RECORD_CHART]?: RecordChartType
[ChartEditStoreEnum.REQUEST_GLOBAL_CONFIG]: RequestGlobalConfigType [ChartEditStoreEnum.REQUEST_GLOBAL_CONFIG]: RequestGlobalConfigType
[ChartEditStoreEnum.COMPONENT_LIST]: CreateComponentType[] [ChartEditStoreEnum.COMPONENT_LIST]: Array<CreateComponentType | CreateComponentGroupType>
} }
// 需要存储的数据内容 // 存储数据类型
export interface ChartEditStorage { export interface ChartEditStorage {
[ChartEditStoreEnum.EDIT_CANVAS_CONFIG]: EditCanvasConfigType [ChartEditStoreEnum.EDIT_CANVAS_CONFIG]: EditCanvasConfigType
[ChartEditStoreEnum.REQUEST_GLOBAL_CONFIG]: RequestGlobalConfigType [ChartEditStoreEnum.REQUEST_GLOBAL_CONFIG]: RequestGlobalConfigType
[ChartEditStoreEnum.COMPONENT_LIST]: CreateComponentType[] [ChartEditStoreEnum.COMPONENT_LIST]: Array<CreateComponentType | CreateComponentGroupType>
} }

View File

@ -1,10 +1,11 @@
import { toRaw } from 'vue'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { CreateComponentType } from '@/packages/index.d' import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
import { PublicGroupConfigClass } from '@/packages/public/publicConfig'
import debounce from 'lodash/debounce' import debounce from 'lodash/debounce'
import cloneDeep from 'lodash/cloneDeep' import cloneDeep from 'lodash/cloneDeep'
import { defaultTheme, globalThemeJson } from '@/settings/chartThemes/index' import { defaultTheme, globalThemeJson } from '@/settings/chartThemes/index'
import { requestInterval, previewScaleType, requestIntervalUnit } from '@/settings/designSetting' import { requestInterval, previewScaleType, requestIntervalUnit } from '@/settings/designSetting'
import { RequestBodyEnum } from '@/enums/httpEnum'
// 记录记录 // 记录记录
import { useChartHistoryStore } from '@/store/modules/chartHistoryStore/chartHistoryStore' import { useChartHistoryStore } from '@/store/modules/chartHistoryStore/chartHistoryStore'
// 全局设置 // 全局设置
@ -67,6 +68,8 @@ export const useChartEditStore = defineStore({
isCreate: false, isCreate: false,
// 拖拽中 // 拖拽中
isDrag: false, isDrag: false,
// 框选中
isSelect: false,
// 同步中 // 同步中
saveStatus: SyncEnum.PENDING saveStatus: SyncEnum.PENDING
}, },
@ -128,8 +131,8 @@ export const useChartEditStore = defineStore({
requestIntervalUnit: requestIntervalUnit, requestIntervalUnit: requestIntervalUnit,
requestParams: { requestParams: {
Body: { Body: {
"form-data": {}, 'form-data': {},
"x-www-form-urlencoded": {}, 'x-www-form-urlencoded': {},
json: '', json: '',
xml: '' xml: ''
}, },
@ -156,7 +159,7 @@ export const useChartEditStore = defineStore({
getEditCanvasConfig(): EditCanvasConfigType { getEditCanvasConfig(): EditCanvasConfigType {
return this.editCanvasConfig return this.editCanvasConfig
}, },
getTargetChart():TargetChartType { getTargetChart(): TargetChartType {
return this.targetChart return this.targetChart
}, },
getRecordChart(): RecordChartType | undefined { getRecordChart(): RecordChartType | undefined {
@ -165,7 +168,7 @@ export const useChartEditStore = defineStore({
getRequestGlobalConfig(): RequestGlobalConfigType { getRequestGlobalConfig(): RequestGlobalConfigType {
return this.requestGlobalConfig return this.requestGlobalConfig
}, },
getComponentList(): CreateComponentType[] { getComponentList(): Array<CreateComponentType | CreateComponentGroupType> {
return this.componentList return this.componentList
}, },
// 获取需要存储的数据项 // 获取需要存储的数据项
@ -183,11 +186,11 @@ export const useChartEditStore = defineStore({
this.projectInfo[key] = value this.projectInfo[key] = value
}, },
// * 设置 editCanvas 数据项 // * 设置 editCanvas 数据项
setEditCanvas<T extends keyof EditCanvasType, K extends EditCanvasType[T]>(key: T, value: K) { setEditCanvas<T extends keyof EditCanvasType, K extends EditCanvasType[T]>(key: T, value: K) {
this.editCanvas[key] = value this.editCanvas[key] = value
}, },
// * 设置 editCanvasConfig需保存后端 数据项 // * 设置 editCanvasConfig需保存后端 数据项
setEditCanvasConfig<T extends keyof EditCanvasConfigType, K extends EditCanvasConfigType[T]>(key: T, value: K) { setEditCanvasConfig<T extends keyof EditCanvasConfigType, K extends EditCanvasConfigType[T]>(key: T, value: K) {
this.editCanvasConfig[key] = value this.editCanvasConfig[key] = value
}, },
// * 设置右键菜单 // * 设置右键菜单
@ -195,39 +198,39 @@ export const useChartEditStore = defineStore({
this.rightMenuShow = value this.rightMenuShow = value
}, },
// * 设置目标数据 hover // * 设置目标数据 hover
setTargetHoverChart(hoverId?:TargetChartType["hoverId"]) { setTargetHoverChart(hoverId?: TargetChartType['hoverId']) {
this.targetChart.hoverId = hoverId this.targetChart.hoverId = hoverId
}, },
// * 设置目标数据 select // * 设置目标数据 select
setTargetSelectChart(selectId?: string | string[], push: boolean = false) { setTargetSelectChart(selectId?: string | string[], push: boolean = false) {
// 重复选中 // 重复选中
if(this.targetChart.selectId.find((e: string) => e === selectId)) return if (this.targetChart.selectId.find((e: string) => e === selectId)) return
// 无 id 清空 // 无 id 清空
if(!selectId) { if (!selectId) {
this.targetChart.selectId = [] this.targetChart.selectId = []
return return
} }
// 新增 // 多选
if(push) { if (push) {
// 字符串 // 字符串
if(isString(selectId)) { if (isString(selectId)) {
this.targetChart.selectId.push(selectId) this.targetChart.selectId.push(selectId)
return return
} }
// 数组 // 数组
if(isArray(selectId)) { if (isArray(selectId)) {
this.targetChart.selectId.push(...selectId) this.targetChart.selectId.push(...selectId)
return return
} }
} else { } else {
// 字符串 // 字符串
if(isString(selectId)) { if (isString(selectId)) {
this.targetChart.selectId = [selectId] this.targetChart.selectId = [selectId]
return return
} }
// 数组 // 数组
if(isArray(selectId)) { if (isArray(selectId)) {
this.targetChart.selectId = selectId this.targetChart.selectId = selectId
return return
} }
@ -239,66 +242,108 @@ export const useChartEditStore = defineStore({
}, },
// * 设置鼠标位置 // * 设置鼠标位置
setMousePosition(x?: number, y?: number, startX?: number, startY?: number): void { setMousePosition(x?: number, y?: number, startX?: number, startY?: number): void {
if (startX) this.mousePosition.startX = startX
if (startY) this.mousePosition.startY = startY
if (x) this.mousePosition.x = x if (x) this.mousePosition.x = x
if (y) this.mousePosition.y = y if (y) this.mousePosition.y = y
if (startX) this.mousePosition.startX = startX
if (startY) this.mousePosition.startY = startY
}, },
// * 找到目标 id 数据下标位置(无则返回-1 // * 找到目标 id 数据下标位置id可为父级或子集数组(无则返回-1
fetchTargetIndex(id?: string): number { fetchTargetIndex(id?: string): number {
const targetId = id || this.getTargetChart.selectId.length && this.getTargetChart.selectId[0] || undefined const targetId = id || (this.getTargetChart.selectId.length && this.getTargetChart.selectId[0]) || undefined
if(!targetId) { if (!targetId) {
loadingFinish() loadingFinish()
return -1 return -1
} }
const index = this.componentList.findIndex(e => e.id === targetId) const targetIndex = this.componentList.findIndex(e => e.id === targetId)
if (index === -1) {
loadingError() // 当前
if (targetIndex !== -1) {
return targetIndex
} else {
const length = this.getComponentList.length
for (let i = 0; i < length; i++) {
if (this.getComponentList[i].isGroup) {
for (const cItem of (this.getComponentList[i] as CreateComponentGroupType).groupList) {
if (cItem.id === targetId) {
return i
}
}
}
}
} }
return index return -1
},
// * 统一格式化处理入参 id
idPreFormat(id?: string | string[]) {
const idArr = []
if (!id) {
idArr.push(...this.getTargetChart.selectId)
return idArr
}
if (isString(id)) idArr.push(id)
if (isArray(id)) idArr.push(...id)
return idArr
}, },
/** /**
* * * *
* @param chartConfig * @param componentInstance
* @param isHead * @param isHead
* @param isHistory * @param isHistory
* @returns * @returns
*/ */
addComponentList(chartConfig: CreateComponentType, isHead = false, isHistory = false): void { addComponentList(
if (isHistory) { componentInstance:
chartHistoryStore.createAddHistory(chartConfig) | CreateComponentType
} | CreateComponentGroupType
if (isHead) { | Array<CreateComponentType | CreateComponentGroupType>,
this.componentList.unshift(chartConfig) isHead = false,
isHistory = false
): void {
if (componentInstance instanceof Array) {
componentInstance.forEach(item => {
this.addComponentList(item, isHead, isHistory)
})
return return
} }
this.componentList.push(chartConfig) if (isHistory) {
chartHistoryStore.createAddHistory([componentInstance])
}
if (isHead) {
this.componentList.unshift(componentInstance)
return
}
this.componentList.push(componentInstance)
}, },
// * 删除组件列表 // * 删除组件
removeComponentList(isHistory = true): void { removeComponentList(id?: string | string[], isHistory = true): void {
try { try {
const idArr = this.idPreFormat(id)
const history: Array<CreateComponentType | CreateComponentGroupType> = []
// 遍历所有对象
if (!idArr.length) return
loadingStart() loadingStart()
const index = this.fetchTargetIndex() idArr.forEach(ids => {
if (index !== -1) { const index = this.fetchTargetIndex(ids)
isHistory ? chartHistoryStore.createDeleteHistory(this.getComponentList[index]) : undefined if (index !== -1) {
this.componentList.splice(index, 1) history.push(this.getComponentList[index])
loadingFinish() this.componentList.splice(index, 1)
return }
} })
} catch(value) { isHistory && chartHistoryStore.createDeleteHistory(history)
loadingFinish()
return
} catch (value) {
loadingError() loadingError()
} }
}, },
// * 更新组件列表某一项的值 // * 更新组件列表某一项的值
updateComponentList(index: number, newData: CreateComponentType) { updateComponentList(index: number, newData: CreateComponentType | CreateComponentGroupType) {
if (index < 1 && index > this.getComponentList.length) return if (index < 1 && index > this.getComponentList.length) return
this.componentList[index] = newData this.componentList[index] = newData
}, },
// * 设置页面样式属性 // * 设置页面样式属性
setPageStyle<T extends keyof CSSStyleDeclaration>( setPageStyle<T extends keyof CSSStyleDeclaration>(key: T, value: any): void {
key: T,
value: any
): void {
const dom = this.getEditCanvas.editContentDom const dom = this.getEditCanvas.editContentDom
if (dom) { if (dom) {
dom.style[key] = value dom.style[key] = value
@ -307,6 +352,9 @@ export const useChartEditStore = defineStore({
// * 移动组件列表层级位置到两端 // * 移动组件列表层级位置到两端
setBothEnds(isEnd = false, isHistory = true): void { setBothEnds(isEnd = false, isHistory = true): void {
try { try {
// 暂不支持多选
if (this.getTargetChart.selectId.length > 1) return
loadingStart() loadingStart()
const length = this.getComponentList.length const length = this.getComponentList.length
if (length < 2) { if (length < 2) {
@ -314,18 +362,18 @@ export const useChartEditStore = defineStore({
return return
} }
const index = this.fetchTargetIndex() const index = this.fetchTargetIndex()
const targetData = this.getComponentList[index] const targetData = this.getComponentList[index]
if (index !== -1) { if (index !== -1) {
// 置底排除最底层, 置顶排除最顶层 // 置底排除最底层, 置顶排除最顶层
if ((isEnd && index === 0) || (!isEnd && index === length - 1 )) { if ((isEnd && index === 0) || (!isEnd && index === length - 1)) {
loadingFinish() loadingFinish()
return return
} }
// 记录原有位置 // 记录原有位置
const setIndex = (t:CreateComponentType, i:number) => { const setIndex = (componentInstance: CreateComponentType | CreateComponentGroupType, i: number) => {
const temp = cloneDeep(t) const temp = cloneDeep(componentInstance)
temp.attr.zIndex = i temp.attr.zIndex = i
return temp return temp
} }
@ -333,18 +381,18 @@ export const useChartEditStore = defineStore({
// 历史记录 // 历史记录
if (isHistory) { if (isHistory) {
chartHistoryStore.createLayerHistory( chartHistoryStore.createLayerHistory(
setIndex(targetData, index), [setIndex(targetData, index)],
isEnd ? HistoryActionTypeEnum.BOTTOM : HistoryActionTypeEnum.TOP isEnd ? HistoryActionTypeEnum.BOTTOM : HistoryActionTypeEnum.TOP
) )
} }
// 插入两端 // 插入两端
this.addComponentList(targetData, isEnd) this.addComponentList(targetData, isEnd)
this.getComponentList.splice(isEnd ? index + 1: index, 1) this.getComponentList.splice(isEnd ? index + 1 : index, 1)
loadingFinish() loadingFinish()
return return
} }
} catch(value) { } catch (value) {
loadingError() loadingError()
} }
}, },
@ -359,6 +407,9 @@ export const useChartEditStore = defineStore({
// * 上移/下移互换图表位置 // * 上移/下移互换图表位置
wrap(isDown = false, isHistory = true) { wrap(isDown = false, isHistory = true) {
try { try {
// 暂不支持多选
if (this.getTargetChart.selectId.length > 1) return
loadingStart() loadingStart()
const length = this.getComponentList.length const length = this.getComponentList.length
if (length < 2) { if (length < 2) {
@ -366,7 +417,7 @@ export const useChartEditStore = defineStore({
return return
} }
const index:number = this.fetchTargetIndex() const index: number = this.fetchTargetIndex()
if (index !== -1) { if (index !== -1) {
// 下移排除最底层, 上移排除最顶层 // 下移排除最底层, 上移排除最顶层
if ((isDown && index === 0) || (!isDown && index === length - 1)) { if ((isDown && index === 0) || (!isDown && index === length - 1)) {
@ -381,7 +432,7 @@ export const useChartEditStore = defineStore({
// 历史记录 // 历史记录
if (isHistory) { if (isHistory) {
chartHistoryStore.createLayerHistory( chartHistoryStore.createLayerHistory(
targetItem, [targetItem],
isDown ? HistoryActionTypeEnum.DOWN : HistoryActionTypeEnum.UP isDown ? HistoryActionTypeEnum.DOWN : HistoryActionTypeEnum.UP
) )
} }
@ -390,7 +441,7 @@ export const useChartEditStore = defineStore({
loadingFinish() loadingFinish()
return return
} }
} catch(value) { } catch (value) {
loadingError() loadingError()
} }
}, },
@ -405,18 +456,21 @@ export const useChartEditStore = defineStore({
// * 复制 // * 复制
setCopy(isCut = false) { setCopy(isCut = false) {
try { try {
// 暂不支持多选
if (this.getTargetChart.selectId.length > 1) return
loadingStart() loadingStart()
const index:number = this.fetchTargetIndex() const index: number = this.fetchTargetIndex()
if (index !== -1) { if (index !== -1) {
const copyData:RecordChartType = { const copyData: RecordChartType = {
charts :this.getComponentList[index], charts: this.getComponentList[index],
type: isCut ? HistoryActionTypeEnum.CUT : HistoryActionTypeEnum.COPY type: isCut ? HistoryActionTypeEnum.CUT : HistoryActionTypeEnum.COPY
} }
this.setRecordChart(copyData) this.setRecordChart(copyData)
window['$message'].success(isCut ? '剪切图表成功' : '复制图表成功!') window['$message'].success(isCut ? '剪切图表成功' : '复制图表成功!')
loadingFinish() loadingFinish()
} }
} catch(value) { } catch (value) {
loadingError() loadingError()
} }
}, },
@ -433,7 +487,7 @@ export const useChartEditStore = defineStore({
loadingFinish() loadingFinish()
return return
} }
const parseHandle = (e: CreateComponentType) => { const parseHandle = (e: CreateComponentType | CreateComponentGroupType) => {
e = cloneDeep(e) e = cloneDeep(e)
// 生成新 id // 生成新 id
e.id = getUUID() e.id = getUUID()
@ -449,7 +503,7 @@ export const useChartEditStore = defineStore({
// 剪切需删除原数据 // 剪切需删除原数据
if (isCut) { if (isCut) {
this.setTargetSelectChart(e.id) this.setTargetSelectChart(e.id)
this.removeComponentList(true) this.removeComponentList(undefined, true)
} }
}) })
if (isCut) this.setRecordChart(undefined) if (isCut) this.setRecordChart(undefined)
@ -464,50 +518,59 @@ export const useChartEditStore = defineStore({
this.setRecordChart(undefined) this.setRecordChart(undefined)
} }
loadingFinish() loadingFinish()
} catch(value) { } catch (value) {
loadingError() loadingError()
} }
}, },
// * 撤回/前进 目标处理 // * 撤回/前进 目标处理
setBackAndSetForwardHandle(item: HistoryItemType, isForward = false) { setBackAndSetForwardHandle(HistoryItem: HistoryItemType, isForward = false) {
// 处理画布 // 处理画布
if (item.targetType === HistoryTargetTypeEnum.CANVAS) { if (HistoryItem.targetType === HistoryTargetTypeEnum.CANVAS) {
this.editCanvas = item.historyData as EditCanvasType this.editCanvas = HistoryItem.historyData[0] as EditCanvasType
return return
} }
const historyData = item.historyData as CreateComponentType let historyData = HistoryItem.historyData as Array<CreateComponentType | CreateComponentGroupType>
if (isArray(historyData)) {
// 选中目标元素,支持多个
historyData.forEach((item: CreateComponentType | CreateComponentGroupType) => {
this.setTargetSelectChart(item.id, true)
})
}
// 处理新增类型 // 处理新增类型
const isAdd = item.actionType === HistoryActionTypeEnum.ADD const isAdd = HistoryItem.actionType === HistoryActionTypeEnum.ADD
const isDel = item.actionType === HistoryActionTypeEnum.DELETE const isDel = HistoryItem.actionType === HistoryActionTypeEnum.DELETE
this.setTargetSelectChart(historyData.id)
if (isAdd || isDel) { if (isAdd || isDel) {
if ((isAdd && isForward) || (isDel && !isForward)) { if ((isAdd && isForward) || (isDel && !isForward)) {
this.addComponentList(historyData) historyData.forEach(item => {
return this.addComponentList(item)
})
return
} }
this.removeComponentList(false) historyData.forEach(item => {
this.removeComponentList(item.id, false)
})
return return
} }
// 处理层级 // 处理层级
const isTop = item.actionType === HistoryActionTypeEnum.TOP const isTop = HistoryItem.actionType === HistoryActionTypeEnum.TOP
const isBottom = item.actionType === HistoryActionTypeEnum.BOTTOM const isBottom = HistoryItem.actionType === HistoryActionTypeEnum.BOTTOM
if (isTop || isBottom) { if (isTop || isBottom) {
if (!isForward) { if (!isForward) {
// 插入到原有位置 // 插入到原有位置
if (isTop) this.getComponentList.pop() if (isTop) this.getComponentList.pop()
if (isBottom) this.getComponentList.shift() if (isBottom) this.getComponentList.shift()
this.getComponentList.splice(historyData.attr.zIndex, 0, historyData) this.getComponentList.splice(historyData[0].attr.zIndex, 0, historyData[0])
return return
} }
if (isTop) this.setTop(false) if (isTop) this.setTop(false)
if (isBottom) this.setBottom(false) if (isBottom) this.setBottom(false)
} }
const isUp = item.actionType === HistoryActionTypeEnum.UP const isUp = HistoryItem.actionType === HistoryActionTypeEnum.UP
const isDown = item.actionType === HistoryActionTypeEnum.DOWN const isDown = HistoryItem.actionType === HistoryActionTypeEnum.DOWN
if (isUp || isDown) { if (isUp || isDown) {
if ((isUp && isForward) || (isDown && !isForward)) { if ((isUp && isForward) || (isDown && !isForward)) {
this.setUp(false) this.setUp(false)
@ -517,8 +580,32 @@ export const useChartEditStore = defineStore({
return return
} }
// 处理内容修改 // 处理分组
this.getComponentList[this.fetchTargetIndex()] = item.historyData as CreateComponentType const isGroup = HistoryItem.actionType === HistoryActionTypeEnum.GROUP
const isUnGroup = HistoryItem.actionType === HistoryActionTypeEnum.UN_GROUP
if (isGroup || isUnGroup) {
if ((isGroup && isForward) || (isUnGroup && !isForward)) {
const ids: string[] = []
if(historyData.length > 1) {
historyData.forEach(item => {
ids.push(item.id)
})
} else {
(historyData[0] as CreateComponentGroupType).groupList.forEach(item => {
ids.push(item.id)
})
}
this.setGroup(ids, false)
return
}
// 都需使用子组件的id去解组
if(historyData.length > 1) {
this.setUnGroup([(historyData[0] as CreateComponentType).id], undefined, false)
} else {
this.setUnGroup([(historyData[0] as CreateComponentGroupType).groupList[0].id], undefined, false)
}
return
}
}, },
// * 撤回 // * 撤回
setBack() { setBack() {
@ -529,17 +616,9 @@ export const useChartEditStore = defineStore({
loadingFinish() loadingFinish()
return return
} }
if (Array.isArray(targetData)) {
targetData.forEach((e: HistoryItemType) => {
this.setBackAndSetForwardHandle(e)
})
loadingFinish()
return
}
this.setBackAndSetForwardHandle(targetData) this.setBackAndSetForwardHandle(targetData)
loadingFinish() loadingFinish()
} catch (value) {
} catch(value) {
loadingError() loadingError()
} }
}, },
@ -552,39 +631,157 @@ export const useChartEditStore = defineStore({
loadingFinish() loadingFinish()
return return
} }
if (Array.isArray(targetData)) {
targetData.forEach((e: HistoryItemType) => {
this.setBackAndSetForwardHandle(e, true)
})
loadingFinish()
return
}
this.setBackAndSetForwardHandle(targetData, true) this.setBackAndSetForwardHandle(targetData, true)
loadingFinish() loadingFinish()
} catch (value) {
} catch(value) {
loadingError() loadingError()
} }
}, },
// * 移动位置 // * 移动位置
setMove(keyboardValue: MenuEnum) { setMove(keyboardValue: MenuEnum) {
const index = this.fetchTargetIndex() const index = this.fetchTargetIndex()
if(index === -1) return if (index === -1) return
const attr = this.getComponentList[index].attr const attr = this.getComponentList[index].attr
const distance = settingStore.getChartMoveDistance const distance = settingStore.getChartMoveDistance
switch (keyboardValue) { switch (keyboardValue) {
case MenuEnum.ARROW_UP: case MenuEnum.ARROW_UP:
attr.y -= distance attr.y -= distance
break; break
case MenuEnum.ARROW_RIGHT: case MenuEnum.ARROW_RIGHT:
attr.x += distance attr.x += distance
break; break
case MenuEnum.ARROW_DOWN: case MenuEnum.ARROW_DOWN:
attr.y += distance attr.y += distance
break; break
case MenuEnum.ARROW_LEFT: case MenuEnum.ARROW_LEFT:
attr.x -= distance attr.x -= distance
break; break
}
},
// * 创建分组
setGroup(id?: string | string[], isHistory = true) {
try {
const selectIds = this.idPreFormat(id) || this.getTargetChart.selectId
if (selectIds.length < 2) return
loadingStart()
const groupClass = new PublicGroupConfigClass()
// 记录整体坐标
const groupAttr = {
l: this.getEditCanvasConfig.width,
t: this.getEditCanvasConfig.height,
r: 0,
b: 0
}
const targetList: CreateComponentType[] = []
const historyList: CreateComponentType[] = []
// 若目标中有数组则先解组
const newSelectIds: string[] = []
selectIds.forEach((id: string) => {
const targetIndex = this.fetchTargetIndex(id)
if (targetIndex !== -1 && this.getComponentList[targetIndex].isGroup) {
this.setUnGroup(
[id],
(e: CreateComponentType[]) => {
e.forEach(e => {
this.addComponentList(e)
newSelectIds.push(e.id)
})
},
false
)
} else if (targetIndex !== -1) {
newSelectIds.push(id)
}
})
newSelectIds.forEach((id: string) => {
// 获取目标数据并从 list 中移除 (成组后不可再次成组, 断言处理)
const item = this.componentList.splice(this.fetchTargetIndex(id), 1)[0] as CreateComponentType
const { x, y, w, h } = item.attr
const { l, t, r, b } = groupAttr
// 左
groupAttr.l = l > x ? x : l
// 上
groupAttr.t = t > y ? y : t
// 宽
groupAttr.r = r < x + w ? x + w : r
// 高
groupAttr.b = b < y + h ? y + h : b
targetList.push(item)
historyList.push(toRaw(item))
})
// 修改原数据之前,先记录
if (isHistory) chartHistoryStore.createGroupHistory(historyList)
// 设置子组件的位置
targetList.forEach((item: CreateComponentType) => {
item.attr.x = item.attr.x - groupAttr.l
item.attr.y = item.attr.y - groupAttr.t
groupClass.groupList.push(item)
})
// 设置 group 属性
groupClass.attr.x = groupAttr.l
groupClass.attr.y = groupAttr.t
groupClass.attr.w = groupAttr.r - groupAttr.l
groupClass.attr.h = groupAttr.b - groupAttr.t
this.addComponentList(groupClass)
this.setTargetSelectChart(groupClass.id)
loadingFinish()
} catch (error) {
console.log(error)
window['$message'].error('创建分组失败,请联系管理员!')
loadingFinish()
}
},
// * 解除分组
setUnGroup(ids?: string[], callBack?: (e: CreateComponentType[]) => void, isHistory = true) {
try {
const selectGroupIdArr = ids || this.getTargetChart.selectId
if (selectGroupIdArr.length !== 1) return
loadingStart()
// 解组
const unGroup = (targetIndex: number) => {
const targetGroup = this.getComponentList[targetIndex] as CreateComponentGroupType
if (!targetGroup.isGroup) return
// 记录数据
if (isHistory) chartHistoryStore.createUnGroupHistory(cloneDeep([targetGroup]))
// 分离组件并还原位置属性
targetGroup.groupList.forEach(item => {
item.attr.x = item.attr.x + targetGroup.attr.x
item.attr.y = item.attr.y + targetGroup.attr.y
if (!callBack) {
this.addComponentList(item)
}
})
this.setTargetSelectChart(targetGroup.id)
// 删除分组
this.removeComponentList(targetGroup.id, false)
if (callBack) {
callBack(targetGroup.groupList)
}
}
const targetIndex = this.fetchTargetIndex(selectGroupIdArr[0])
// 判断目标是否为分组父级
if (targetIndex !== -1) {
unGroup(targetIndex)
}
loadingFinish()
} catch (error) {
console.log(error)
window['$message'].error('解除分组失败,请联系管理员!')
loadingFinish()
} }
}, },
// * 页面缩放设置----------------- // * 页面缩放设置-----------------
@ -597,32 +794,24 @@ export const useChartEditStore = defineStore({
computedScale() { computedScale() {
if (this.getEditCanvas.editLayoutDom) { if (this.getEditCanvas.editLayoutDom) {
// 现有展示区域 // 现有展示区域
const width = const width = this.getEditCanvas.editLayoutDom.clientWidth - this.getEditCanvas.offset * 2 - 5
this.getEditCanvas.editLayoutDom.clientWidth - this.getEditCanvas.offset * 2 - 5 const height = this.getEditCanvas.editLayoutDom.clientHeight - this.getEditCanvas.offset * 4
const height =
this.getEditCanvas.editLayoutDom.clientHeight - this.getEditCanvas.offset * 4
// 用户设定大小 // 用户设定大小
const editCanvasWidth = this.editCanvasConfig.width const editCanvasWidth = this.editCanvasConfig.width
const editCanvasHeight = this.editCanvasConfig.height const editCanvasHeight = this.editCanvasConfig.height
// 需保持的比例 // 需保持的比例
const baseProportion = parseFloat( const baseProportion = parseFloat((editCanvasWidth / editCanvasHeight).toFixed(5))
(editCanvasWidth / editCanvasHeight).toFixed(5)
)
const currentRate = parseFloat((width / height).toFixed(5)) const currentRate = parseFloat((width / height).toFixed(5))
if (currentRate > baseProportion) { if (currentRate > baseProportion) {
// 表示更宽 // 表示更宽
const scaleWidth = parseFloat( const scaleWidth = parseFloat(((height * baseProportion) / editCanvasWidth).toFixed(5))
((height * baseProportion) / editCanvasWidth).toFixed(5) this.setScale(scaleWidth > 1 ? 1 : scaleWidth)
)
this.setScale( scaleWidth > 1 ? 1 : scaleWidth)
} else { } else {
// 表示更高 // 表示更高
const scaleHeight = parseFloat( const scaleHeight = parseFloat((width / baseProportion / editCanvasHeight).toFixed(5))
(width / baseProportion / editCanvasHeight).toFixed(5)
)
this.setScale(scaleHeight > 1 ? 1 : scaleHeight) this.setScale(scaleHeight > 1 ? 1 : scaleHeight)
} }
} else { } else {
@ -655,4 +844,4 @@ export const useChartEditStore = defineStore({
} }
} }
} }
}) })

View File

@ -15,6 +15,8 @@ export const historyActionTypeName = {
[HistoryActionTypeEnum.BOTTOM]: '层级置底', [HistoryActionTypeEnum.BOTTOM]: '层级置底',
[HistoryActionTypeEnum.UP]: '层级上移', [HistoryActionTypeEnum.UP]: '层级上移',
[HistoryActionTypeEnum.DOWN]: '层级下移', [HistoryActionTypeEnum.DOWN]: '层级下移',
[HistoryActionTypeEnum.GROUP]: '创建分组',
[HistoryActionTypeEnum.UN_GROUP]: '解除分组',
[HistoryActionTypeEnum.SELECT_HISTORY]: '选择记录', [HistoryActionTypeEnum.SELECT_HISTORY]: '选择记录',
[HistoryTargetTypeEnum.CANVAS]: '画布初始化' [HistoryTargetTypeEnum.CANVAS]: '画布初始化'

View File

@ -1,4 +1,4 @@
import { CreateComponentType } from '@/packages/index.d' import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
import { EditCanvasType } from '@/store/modules/chartEditStore/chartEditStore.d' import { EditCanvasType } from '@/store/modules/chartEditStore/chartEditStore.d'
// 操作类型枚举 // 操作类型枚举
@ -25,6 +25,10 @@ export enum HistoryActionTypeEnum {
UP = 'up', UP = 'up',
// 下移 // 下移
DOWN = 'down', DOWN = 'down',
// 成组
GROUP = 'group',
// 解组
UN_GROUP = 'unGroup',
// 选择历史记录 // 选择历史记录
SELECT_HISTORY = 'selectHistory' SELECT_HISTORY = 'selectHistory'
} }
@ -51,10 +55,11 @@ export enum HistoryStackItemEnum {
// 历史记录项类型 // 历史记录项类型
export interface HistoryItemType { export interface HistoryItemType {
// 会有同时操作多个组件场景
[HistoryStackItemEnum.ID]: string [HistoryStackItemEnum.ID]: string
[HistoryStackItemEnum.TARGET_TYPE]: HistoryTargetTypeEnum [HistoryStackItemEnum.TARGET_TYPE]: HistoryTargetTypeEnum
[HistoryStackItemEnum.ACTION_TYPE]: HistoryActionTypeEnum [HistoryStackItemEnum.ACTION_TYPE]: HistoryActionTypeEnum
[HistoryStackItemEnum.HISTORY_DATA]: CreateComponentType | EditCanvasType [HistoryStackItemEnum.HISTORY_DATA]: CreateComponentType[] | CreateComponentGroupType[] | EditCanvasType[]
} }
// 历史 Store 类型 // 历史 Store 类型

View File

@ -1,5 +1,5 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { CreateComponentType } from '@/packages/index.d' import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
import { EditCanvasType } from '@/store/modules/chartEditStore/chartEditStore.d' import { EditCanvasType } from '@/store/modules/chartEditStore/chartEditStore.d'
import { loadingStart, loadingFinish, loadingError } from '@/utils' import { loadingStart, loadingFinish, loadingError } from '@/utils'
import { editHistoryMax } from '@/settings/designSetting' import { editHistoryMax } from '@/settings/designSetting'
@ -35,31 +35,26 @@ export const useChartHistoryStore = defineStore({
* @param targetType * @param targetType
*/ */
createStackItem( createStackItem(
item: CreateComponentType | EditCanvasType, item: CreateComponentType[] | CreateComponentGroupType[] | EditCanvasType[],
actionType: HistoryActionTypeEnum, actionType: HistoryActionTypeEnum,
targetType: HistoryTargetTypeEnum = HistoryTargetTypeEnum.CHART targetType: HistoryTargetTypeEnum = HistoryTargetTypeEnum.CHART
) { ) {
// 优化性能转为freeze // 优化性能转为 freeze
this.pushBackStackItem(Object.freeze({ this.pushBackStackItem(
[HistoryStackItemEnum.ID]: new Date().getTime().toString(), Object.freeze({
[HistoryStackItemEnum.HISTORY_DATA]: item, [HistoryStackItemEnum.ID]: new Date().getTime().toString(),
[HistoryStackItemEnum.ACTION_TYPE]: actionType, [HistoryStackItemEnum.HISTORY_DATA]: item,
[HistoryStackItemEnum.TARGET_TYPE]: targetType [HistoryStackItemEnum.ACTION_TYPE]: actionType,
} as const)) [HistoryStackItemEnum.TARGET_TYPE]: targetType
} as const)
)
}, },
// * 画布初始化 // * 画布初始化
canvasInit(canvas: EditCanvasType) { canvasInit(canvas: EditCanvasType) {
this.createStackItem( this.createStackItem([canvas], HistoryActionTypeEnum.ADD, HistoryTargetTypeEnum.CANVAS)
canvas,
HistoryActionTypeEnum.ADD,
HistoryTargetTypeEnum.CANVAS
)
}, },
// * 推入后退栈 // * 推入后退栈
pushBackStackItem( pushBackStackItem(item: HistoryItemType | Array<HistoryItemType>, notClear = false): void {
item: HistoryItemType | Array<HistoryItemType>,
notClear = false
): void {
if (item instanceof Array) this.backStack = [...this.backStack, ...item] if (item instanceof Array) this.backStack = [...this.backStack, ...item]
else this.backStack.push(item) else this.backStack.push(item)
this.backStack.splice(0, this.backStack.length - editHistoryMax) this.backStack.splice(0, this.backStack.length - editHistoryMax)
@ -69,30 +64,17 @@ export const useChartHistoryStore = defineStore({
}, },
// * 推入前进栈 // * 推入前进栈
pushForwardStack(item: HistoryItemType | Array<HistoryItemType>): void { pushForwardStack(item: HistoryItemType | Array<HistoryItemType>): void {
if (item instanceof Array) if (item instanceof Array) this.forwardStack = [...this.forwardStack, ...item]
this.forwardStack = [...this.forwardStack, ...item]
else this.forwardStack.push(item) else this.forwardStack.push(item)
}, },
// * 移出后退栈 // * 移出后退栈
popBackStackItem( popBackStackItem(): HistoryItemType | undefined {
index?: number
): HistoryItemType[] | HistoryItemType | undefined {
const length = this.backStack.length
if (index && length >= index) {
return this.backStack.splice(-index)
}
if (this.backStack.length > 0) { if (this.backStack.length > 0) {
return this.backStack.pop() return this.backStack.pop()
} }
}, },
// * 移出前进栈 // * 移出前进栈
popForwardStack( popForwardStack(): HistoryItemType | undefined {
index?: number
): HistoryItemType[] | HistoryItemType | undefined {
const length = this.forwardStack.length
if (index && length >= index) {
return this.forwardStack.splice(-index)
}
if (this.forwardStack.length > 0) { if (this.forwardStack.length > 0) {
return this.forwardStack.pop() return this.forwardStack.pop()
} }
@ -104,7 +86,7 @@ export const useChartHistoryStore = defineStore({
// * 清空后退栈(保留初始化) // * 清空后退栈(保留初始化)
clearBackStack() { clearBackStack() {
const canvasHistory = this.getBackStack[0] const canvasHistory = this.getBackStack[0]
this.backStack = [canvasHistory] this.backStack = [canvasHistory]
}, },
// * 撤回 // * 撤回
backAction() { backAction() {
@ -148,59 +130,43 @@ export const useChartHistoryStore = defineStore({
} }
}, },
// * 新增组件记录 // * 新增组件记录
createAddHistory(item: CreateComponentType) { createAddHistory(item: Array<CreateComponentType | CreateComponentGroupType>) {
this.createStackItem( this.createStackItem(item, HistoryActionTypeEnum.ADD, HistoryTargetTypeEnum.CHART)
item,
HistoryActionTypeEnum.ADD,
HistoryTargetTypeEnum.CHART
)
}, },
// * 更新属性记录(大小、图表属性) // * 更新属性记录(大小、图表属性)
createUpdateHistory(item: CreateComponentType) { createUpdateHistory(item: Array<CreateComponentType | CreateComponentGroupType>) {
this.createStackItem( this.createStackItem(item, HistoryActionTypeEnum.UPDATE, HistoryTargetTypeEnum.CHART)
item,
HistoryActionTypeEnum.UPDATE,
HistoryTargetTypeEnum.CHART
)
}, },
// * 删除组件记录 // * 删除组件记录
createDeleteHistory(item: CreateComponentType) { createDeleteHistory(item: Array<CreateComponentType | CreateComponentGroupType>) {
this.createStackItem( this.createStackItem(item, HistoryActionTypeEnum.DELETE, HistoryTargetTypeEnum.CHART)
item,
HistoryActionTypeEnum.DELETE,
HistoryTargetTypeEnum.CHART
)
}, },
// * 移动组件记录 // * 移动组件记录
createMoveHistory(item: CreateComponentType) { createMoveHistory(item: Array<CreateComponentType | CreateComponentGroupType>) {
this.createStackItem( this.createStackItem(item, HistoryActionTypeEnum.MOVE, HistoryTargetTypeEnum.CHART)
item,
HistoryActionTypeEnum.MOVE,
HistoryTargetTypeEnum.CHART
)
}, },
// * 改变层级组件记录 // * 改变层级组件记录
createLayerHistory( createLayerHistory(
item: CreateComponentType, item: Array<CreateComponentType | CreateComponentGroupType>,
type: type:
| HistoryActionTypeEnum.TOP | HistoryActionTypeEnum.TOP
| HistoryActionTypeEnum.DOWN | HistoryActionTypeEnum.DOWN
| HistoryActionTypeEnum.UP | HistoryActionTypeEnum.UP
| HistoryActionTypeEnum.BOTTOM | HistoryActionTypeEnum.BOTTOM
) { ) {
this.createStackItem( this.createStackItem(item, type, HistoryTargetTypeEnum.CHART)
item,
type,
HistoryTargetTypeEnum.CHART
)
}, },
// * 剪切组件记录 // * 剪切组件记录
createPasteHistory(item: CreateComponentType) { createPasteHistory(item: Array<CreateComponentType | CreateComponentGroupType>) {
this.createStackItem( this.createStackItem(item, HistoryActionTypeEnum.CUT, HistoryTargetTypeEnum.CHART)
item, },
HistoryActionTypeEnum.CUT, // * 创建分组
HistoryTargetTypeEnum.CHART createGroupHistory(item: Array<CreateComponentType | CreateComponentGroupType>) {
) this.createStackItem(item, HistoryActionTypeEnum.GROUP, HistoryTargetTypeEnum.CHART)
},
// * 解除分组
createUnGroupHistory(item: Array<CreateComponentType | CreateComponentGroupType>) {
this.createStackItem(item, HistoryActionTypeEnum.UN_GROUP, HistoryTargetTypeEnum.CHART)
} }
} }
}) })

View File

@ -45,7 +45,7 @@ const dragStartHandle = (e: DragEvent, item: ConfigType) => {
componentInstall(item.chartKey, fetchChartComponent(item)) componentInstall(item.chartKey, fetchChartComponent(item))
componentInstall(item.conKey, fetchConfigComponent(item)) componentInstall(item.conKey, fetchConfigComponent(item))
// //
e!.dataTransfer!.setData(DragKeyEnum.DROG_KEY, JSON.stringify(omit(item, ['image']))) e!.dataTransfer!.setData(DragKeyEnum.DRAG_KEY, JSON.stringify(omit(item, ['image'])))
// //
chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_CREATE, true) chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_CREATE, true)
} }

View File

@ -28,7 +28,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed } from 'vue' import { computed } from 'vue'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { EditCanvasConfigEnum } from '@/store/modules/chartEditStore/chartEditStore.d' import { EditCanvasConfigEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
import { import {
@ -46,8 +46,13 @@ const chartEditStore = useChartEditStore()
// //
const designStore = useDesignStore() const designStore = useDesignStore()
const themeColor = ref(designStore.getAppTheme)
//
const themeColor = computed(() => {
return designStore.getAppTheme
})
//
const selectName = computed(() => { const selectName = computed(() => {
return chartEditStore.getEditCanvasConfig.chartThemeColor return chartEditStore.getEditCanvasConfig.chartThemeColor
}) })

View File

@ -96,7 +96,7 @@
</n-space> </n-space>
<!-- 滤镜 --> <!-- 滤镜 -->
<styles-setting :is-canvas="true" :chartStyles="canvasConfig"></styles-setting> <styles-setting :isCanvas="true" :chartStyles="canvasConfig"></styles-setting>
<n-divider style="margin: 10px 0;"></n-divider> <n-divider style="margin: 10px 0;"></n-divider>
<!-- 主题选择和全局配置 --> <!-- 主题选择和全局配置 -->

View File

@ -34,7 +34,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue' import { ref, computed } from 'vue'
import { animations } from '@/settings/animations/index' import { animations } from '@/settings/animations/index'
import { CollapseItem } from '@/components/Pages/ChartItemSetting' import { CollapseItem } from '@/components/Pages/ChartItemSetting'
import { useDesignStore } from '@/store/modules/designStore/designStore' import { useDesignStore } from '@/store/modules/designStore/designStore'
@ -42,12 +42,16 @@ import { useTargetData } from '../hooks/useTargetData.hook'
// //
const designStore = useDesignStore() const designStore = useDesignStore()
const themeColor = ref(designStore.getAppTheme)
const hoverPreviewAnimate = ref('') const hoverPreviewAnimate = ref('')
const { targetData } = useTargetData() const { targetData } = useTargetData()
//
const themeColor = computed(() => {
return designStore.getAppTheme
})
// * // *
const activeIndex = (value: string) => { const activeIndex = (value: string) => {
const selectValue = targetData.value.styles.animations const selectValue = targetData.value.styles.animations

View File

@ -84,7 +84,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, toRefs, onBeforeUnmount, watchEffect, toRaw } from 'vue' import { ref, toRefs, computed, onBeforeUnmount, watchEffect, toRaw } from 'vue'
import { icon } from '@/plugins' import { icon } from '@/plugins'
import { useDesignStore } from '@/store/modules/designStore/designStore' import { useDesignStore } from '@/store/modules/designStore/designStore'
import { SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' import { SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
@ -108,7 +108,6 @@ const {
requestIntervalUnit: GlobalRequestIntervalUnit requestIntervalUnit: GlobalRequestIntervalUnit
} = toRefs(chartEditStore.getRequestGlobalConfig) } = toRefs(chartEditStore.getRequestGlobalConfig)
const designStore = useDesignStore() const designStore = useDesignStore()
const themeColor = ref(designStore.getAppTheme)
// //
const loading = ref(false) const loading = ref(false)
@ -142,6 +141,11 @@ const sendHandle = async () => {
} }
} }
//
const themeColor = computed(() => {
return designStore.getAppTheme
})
watchEffect(() => { watchEffect(() => {
const filter = targetData.value?.filter const filter = targetData.value?.filter
if (lastFilter !== filter && firstFocus) { if (lastFilter !== filter && firstFocus) {

View File

@ -65,7 +65,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, toRefs } from 'vue' import { ref, toRefs, computed } from 'vue'
import { useDesignStore } from '@/store/modules/designStore/designStore' import { useDesignStore } from '@/store/modules/designStore/designStore'
import { SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' import { SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import { useTargetData } from '@/views/chart/ContentConfigurations/components/hooks/useTargetData.hook' import { useTargetData } from '@/views/chart/ContentConfigurations/components/hooks/useTargetData.hook'
@ -79,9 +79,12 @@ const { requestOriginUrl, requestInterval, requestIntervalUnit } = toRefs(chartE
const editDisabled = ref(true) const editDisabled = ref(true)
const designStore = useDesignStore() const designStore = useDesignStore()
const themeColor = ref(designStore.getAppTheme)
const showTable = ref(false) const showTable = ref(false)
//
const themeColor = computed(() => {
return designStore.getAppTheme
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -15,7 +15,7 @@
<template #action> <template #action>
<n-space justify="space-between"> <n-space justify="space-between">
<div> <div>
<n-text> {{ chartConfig.categoryName || rename }} </n-text> <n-text> {{ chartConfig.categoryName }} </n-text>
<n-text> </n-text> <n-text> </n-text>
<n-tag type="primary" :bordered="false" style="border-radius: 5px"> {{ requestContentTypeObj[requestContentType] }} </n-tag> <n-tag type="primary" :bordered="false" style="border-radius: 5px"> {{ requestContentTypeObj[requestContentType] }} </n-tag>
</div> </div>
@ -37,9 +37,8 @@ const emit = defineEmits(['update:modelShow'])
const { targetData } = useTargetData() const { targetData } = useTargetData()
// //
const { chartConfig, rename } = toRefs(targetData.value) const { chartConfig } = toRefs(targetData.value)
const { requestContentType } = toRefs(targetData.value.request) const { requestContentType } = toRefs(targetData.value.request)
const requestContentTypeObj = { const requestContentTypeObj = {
[RequestContentTypeEnum.DEFAULT]: '普通请求', [RequestContentTypeEnum.DEFAULT]: '普通请求',
[RequestContentTypeEnum.SQL]: 'SQL 请求' [RequestContentTypeEnum.SQL]: 'SQL 请求'

View File

@ -3,11 +3,11 @@
<!-- 名称 --> <!-- 名称 -->
<name-setting :chartConfig="targetData.chartConfig"></name-setting> <name-setting :chartConfig="targetData.chartConfig"></name-setting>
<!-- 尺寸 --> <!-- 尺寸 -->
<size-setting :chartAttr="targetData.attr"></size-setting> <size-setting :isGroup="targetData.isGroup" :chartAttr="targetData.attr"></size-setting>
<!-- 位置 --> <!-- 位置 -->
<position-setting :chartAttr="targetData.attr" :canvasConfig="chartEditStore.getEditCanvasConfig"/> <position-setting :chartAttr="targetData.attr" :canvasConfig="chartEditStore.getEditCanvasConfig"/>
<!-- 滤镜 --> <!-- 滤镜 -->
<styles-setting :chartStyles="targetData.styles"></styles-setting> <styles-setting :isGroup="targetData.isGroup" :chartStyles="targetData.styles"></styles-setting>
<!-- 自定义配置项 --> <!-- 自定义配置项 -->
<component :is="targetData.chartConfig.conKey" :optionData="targetData.option"></component> <component :is="targetData.chartConfig.conKey" :optionData="targetData.option"></component>
</div> </div>

View File

@ -1,11 +1,11 @@
import { computed, Ref } from 'vue' import { computed, Ref } from 'vue'
import { CreateComponentType } from '@/packages/index.d' import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
// 获取当前对象数据 // 获取当前对象数据
export const useTargetData = () => { export const useTargetData = () => {
const chartEditStore = useChartEditStore() const chartEditStore = useChartEditStore()
const targetData: Ref<CreateComponentType> = computed(() => { const targetData: Ref<CreateComponentType | CreateComponentGroupType> = computed(() => {
const list = chartEditStore.getComponentList const list = chartEditStore.getComponentList
const targetIndex = chartEditStore.fetchTargetIndex() const targetIndex = chartEditStore.fetchTargetIndex()
return list[targetIndex] return list[targetIndex]

View File

@ -0,0 +1,6 @@
export enum TabsEnum {
PAGE_SETTING = 'pageSetting',
CHART_SETTING = 'chartSetting',
CHART_ANIMATION = 'chartAnimation',
CHART_DATA = 'chartData',
}

View File

@ -11,21 +11,12 @@
:collapsed="collapsed" :collapsed="collapsed"
:native-scrollbar="false" :native-scrollbar="false"
show-trigger="bar" show-trigger="bar"
@collapse="collapsedHindle" @collapse="collapsedHandle"
@expand="expandHindle" @expand="expandHandle"
> >
<content-box <content-box class="go-content-layers go-boderbox" :show-top="false" :depth="2">
class="go-content-layers go-boderbox"
:show-top="false"
:depth="2"
>
<!-- 页面配置 --> <!-- 页面配置 -->
<n-tabs <n-tabs v-if="!selectTarget" class="tabs-box" size="small" type="segment">
v-show="!selectTarget"
class="tabs-box"
size="small"
type="segment"
>
<n-tab-pane <n-tab-pane
v-for="item in globalTabList" v-for="item in globalTabList"
:key="item.key" :key="item.key"
@ -46,14 +37,9 @@
</n-tabs> </n-tabs>
<!-- 编辑 --> <!-- 编辑 -->
<n-tabs <n-tabs v-if="selectTarget" v-model:value="tabsSelect" class="tabs-box" size="small" type="segment">
v-show="selectTarget"
class="tabs-box"
size="small"
type="segment"
>
<n-tab-pane <n-tab-pane
v-for="(item) in canvasTabList" v-for="item in selectTarget.isGroup ? chartsDefaultTabList : chartsTabList"
:key="item.key" :key="item.key"
:name="item.key" :name="item.key"
size="small" size="small"
@ -80,6 +66,7 @@ import { ref, toRefs, watch, computed } from 'vue'
import { icon } from '@/plugins' import { icon } from '@/plugins'
import { loadAsyncComponent } from '@/utils' import { loadAsyncComponent } from '@/utils'
import { ContentBox } from '../ContentBox/index' import { ContentBox } from '../ContentBox/index'
import { TabsEnum } from './index.d'
import { useChartLayoutStore } from '@/store/modules/chartLayoutStore/chartLayoutStore' import { useChartLayoutStore } from '@/store/modules/chartLayoutStore/chartLayoutStore'
import { ChartLayoutStoreEnum } from '@/store/modules/chartLayoutStore/chartLayoutStore.d' import { ChartLayoutStoreEnum } from '@/store/modules/chartLayoutStore/chartLayoutStore.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
@ -88,35 +75,23 @@ const { getDetails } = toRefs(useChartLayoutStore())
const { setItem } = useChartLayoutStore() const { setItem } = useChartLayoutStore()
const chartEditStore = useChartEditStore() const chartEditStore = useChartEditStore()
const { const { ConstructIcon, FlashIcon, DesktopOutlineIcon, LeafIcon } = icon.ionicons5
ConstructIcon,
FlashIcon,
DesktopOutlineIcon,
LeafIcon
} = icon.ionicons5
const ContentEdit = loadAsyncComponent(() => import('../ContentEdit/index.vue')) const ContentEdit = loadAsyncComponent(() => import('../ContentEdit/index.vue'))
const CanvasPage = loadAsyncComponent(() => const CanvasPage = loadAsyncComponent(() => import('./components/CanvasPage/index.vue'))
import('./components/CanvasPage/index.vue') const ChartSetting = loadAsyncComponent(() => import('./components/ChartSetting/index.vue'))
) const ChartData = loadAsyncComponent(() => import('./components/ChartData/index.vue'))
const ChartSetting = loadAsyncComponent(() => const ChartAnimation = loadAsyncComponent(() => import('./components/ChartAnimation/index.vue'))
import('./components/ChartSetting/index.vue')
)
const ChartData = loadAsyncComponent(() =>
import('./components/ChartData/index.vue')
)
const ChartAnimation = loadAsyncComponent(() =>
import('./components/ChartAnimation/index.vue')
)
const collapsed = ref<boolean>(getDetails.value) const collapsed = ref<boolean>(getDetails.value)
const tabsSelect = ref<TabsEnum>(TabsEnum.CHART_SETTING)
const collapsedHindle = () => { const collapsedHandle = () => {
collapsed.value = true collapsed.value = true
setItem(ChartLayoutStoreEnum.DETAILS, true) setItem(ChartLayoutStoreEnum.DETAILS, true)
} }
const expandHindle = () => { const expandHandle = () => {
collapsed.value = false collapsed.value = false
setItem(ChartLayoutStoreEnum.DETAILS, false) setItem(ChartLayoutStoreEnum.DETAILS, false)
} }
@ -125,42 +100,50 @@ const selectTarget = computed(() => {
const selectId = chartEditStore.getTargetChart.selectId const selectId = chartEditStore.getTargetChart.selectId
// //
if (selectId.length !== 1) return undefined if (selectId.length !== 1) return undefined
return chartEditStore.componentList[chartEditStore.fetchTargetIndex()] const target = chartEditStore.componentList[chartEditStore.fetchTargetIndex()]
if (target?.isGroup) {
tabsSelect.value = TabsEnum.CHART_SETTING
}
return target
}) })
watch(getDetails, newData => { watch(getDetails, newData => {
if (newData) { if (newData) {
collapsedHindle() collapsedHandle()
} else { } else {
expandHindle() expandHandle()
} }
}) })
// //
const globalTabList = [ const globalTabList = [
{ {
key: 'pageSetting', key: TabsEnum.PAGE_SETTING,
title: '页面配置', title: '页面配置',
icon: DesktopOutlineIcon, icon: DesktopOutlineIcon,
render: CanvasPage render: CanvasPage
} }
] ]
const canvasTabList = [ const chartsDefaultTabList = [
{ {
key: 'ChartSetting', key: TabsEnum.CHART_SETTING,
title: '定制', title: '定制',
icon: ConstructIcon, icon: ConstructIcon,
render: ChartSetting render: ChartSetting
}, },
{ {
key: 'ChartAnimation', key: TabsEnum.CHART_ANIMATION,
title: '动画', title: '动画',
icon: LeafIcon, icon: LeafIcon,
render: ChartAnimation render: ChartAnimation
}, }
]
const chartsTabList = [
...chartsDefaultTabList,
{ {
key: 'ChartData', key: TabsEnum.CHART_DATA,
title: '数据', title: '数据',
icon: FlashIcon, icon: FlashIcon,
render: ChartData render: ChartData

View File

@ -11,17 +11,16 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, computed, watch } from 'vue' import { reactive, computed, watch } from 'vue'
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'
import { EditCanvasTypeEnum } from '@/store/modules/chartEditStore/chartEditStore.d' import { EditCanvasTypeEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
import { useSettingStore } from '@/store/modules/settingStore/settingStore' import { useSettingStore } from '@/store/modules/settingStore/settingStore'
import { CreateComponentType } from '@/packages/index.d' import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
import throttle from 'lodash/throttle' import throttle from 'lodash/throttle'
import cloneDeep from 'lodash/cloneDeep' import cloneDeep from 'lodash/cloneDeep'
// //
const designStore = useDesignStore() const designStore = useDesignStore()
const themeColor = ref(designStore.getAppTheme)
const chartEditStore = useChartEditStore() const chartEditStore = useChartEditStore()
const settingStore = useSettingStore() const settingStore = useSettingStore()
@ -49,6 +48,11 @@ const useComponentStyle = (attr?: Partial<{ x: number; y: number }>) => {
return componentStyle return componentStyle
} }
//
const themeColor = computed(() => {
return designStore.getAppTheme
})
// * // *
const minDistance = computed(() => { const minDistance = computed(() => {
return settingStore.getChartAlignRange return settingStore.getChartAlignRange
@ -111,7 +115,7 @@ watch(
line.select.clear() line.select.clear()
line.sorptioned.y = false line.sorptioned.y = false
// //
const componentList = chartEditStore.getComponentList.map((e: CreateComponentType) => { const componentList = chartEditStore.getComponentList.map((e: CreateComponentType | CreateComponentGroupType) => {
return { return {
id: e.id, id: e.id,
attr: e.attr attr: e.attr
@ -228,30 +232,6 @@ watch(
selectTarget.value.setPosition(componentRightX - selectW, selectTopY) selectTarget.value.setPosition(componentRightX - selectW, selectTopY)
} }
} }
/*
* 我也不知道为什么这个不行还没时间调
if(lineItem.includes('row')) {
selectY.forEach(sY => {
componentY.forEach(cY => {
if (isSorption(sY, cY)) {
line.select.set(lineItem, { y: cY })
}
})
})
return
}
if(lineItem.includes('col')) {
seletX.forEach(sX => {
componentX.forEach(cX => {
if (isSorption(sX, cX)) {
line.select.set(lineItem, { x: sX })
}
})
})
return
}
*/
}) })
}) })
}, 200), }, 200),
@ -267,7 +247,6 @@ watch(
if (!val) { if (!val) {
line.select.clear() line.select.clear()
line.sorptioned.y = false line.sorptioned.y = false
chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_DRAG, true)
} }
} }
) )

View File

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

View File

@ -0,0 +1,122 @@
<template>
<div class="go-edit-group-box">
<edit-shape-box
:key="groupData.id"
:data-id="groupData.id"
:index="groupIndex"
:item="groupData"
:hiddenPoint="true"
:class="animationsClass(groupData.styles.animations)"
:style="{
...useComponentStyle(groupData.attr, groupIndex),
...useSizeStyle(groupData.attr),
...getFilterStyle(groupData.styles),
...getTransformStyle(groupData.styles)
}"
@click="mouseClickHandle($event, groupData)"
@mousedown="mousedownHandle($event, groupData)"
@mouseenter="mouseenterHandle($event, groupData)"
@mouseleave="mouseleaveHandle($event, groupData)"
@contextmenu="handleContextMenu($event, groupData, optionsHandle)"
>
<!-- 组合组件 -->
<edit-shape-box
v-for="item in groupData.groupList"
:key="item.id"
:data-id="item.id"
:index="groupIndex"
:item="item"
:hiddenPoint="true"
:style="{
...useComponentStyle(item.attr, groupIndex)
}"
>
<component
class="edit-content-chart"
:class="animationsClass(item.styles.animations)"
:is="item.chartConfig.chartKey"
:chartConfig="item"
:themeSetting="themeSetting"
:themeColor="themeColor"
:style="{
...useSizeStyle(item.attr),
...getFilterStyle(item.styles),
...getTransformStyle(item.styles)
}"
></component>
</edit-shape-box>
</edit-shape-box>
</div>
</template>
<script setup lang="ts">
import { computed, PropType } from 'vue'
import { MenuEnum } from '@/enums/editPageEnum'
import { chartColors } from '@/settings/chartThemes/index'
import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
import { MenuOptionsItemType } from '@/views/chart/hooks/useContextMenu.hook.d'
import { animationsClass, getFilterStyle, getTransformStyle } from '@/utils'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { useContextMenu, divider } from '@/views/chart/hooks/useContextMenu.hook'
import { useMouseHandle } from '../../hooks/useDrag.hook'
import { useComponentStyle, useSizeStyle } from '../../hooks/useStyle.hook'
import { EditShapeBox } from '../../components/EditShapeBox'
const props = defineProps({
groupData: {
type: Object as PropType<CreateComponentGroupType>,
required: true
},
groupIndex: {
type: Number,
required: true
}
})
const chartEditStore = useChartEditStore()
const { handleContextMenu } = useContextMenu()
//
const { mouseenterHandle, mouseleaveHandle, mousedownHandle, mouseClickHandle } = useMouseHandle()
//
const optionsHandle = (
targetList: MenuOptionsItemType[],
allList: MenuOptionsItemType[],
targetInstance: CreateComponentType
) => {
//
const moreMenuEnums = [MenuEnum.GROUP, MenuEnum.DELETE]
//
const singleMenuEnums = [MenuEnum.UN_GROUP]
const filter = (menulist: MenuEnum[]) => {
const list: MenuOptionsItemType[] = []
allList.forEach(item => {
if (menulist.includes(item.key as MenuEnum)) {
list.push(item)
}
})
return list
}
//
if (chartEditStore.getTargetChart.selectId.length > 1) {
return filter(moreMenuEnums)
} else {
return [...filter(singleMenuEnums), divider(), ...targetList]
}
}
//
const themeColor = computed(() => {
const chartThemeColor = chartEditStore.getEditCanvasConfig.chartThemeColor
return chartColors[chartThemeColor]
})
//
const themeSetting = computed(() => {
const chartThemeSetting = chartEditStore.getEditCanvasConfig.chartThemeSetting
return chartThemeSetting
})
</script>

View File

@ -1,21 +1,8 @@
<template> <template>
<div class="go-flex-items-center"> <div class="go-flex-items-center">
<n-popover <n-popover class="edit-history-popover" :show-arrow="false" size="small" trigger="click" placement="top-start">
class="edit-history-popover"
:show="showDropdownRef"
:show-arrow="false"
size="small"
trigger="click"
placement="top-start"
>
<template #trigger> <template #trigger>
<n-button <n-button class="mr-10" secondary size="small" :disabled="options.length === 0">
class="go-mr-1"
secondary
size="small"
:disabled="options.length === 0"
@click="handleClick"
>
<span class="btn-text">历史记录</span> <span class="btn-text">历史记录</span>
</n-button> </n-button>
</template> </template>
@ -24,16 +11,11 @@
<n-scrollbar style="max-height: 500px"> <n-scrollbar style="max-height: 500px">
<div <div
class="list-item go-flex-items-center go-ellipsis-1" class="list-item go-flex-items-center go-ellipsis-1"
v-for="item in options" v-for="(item, index) in options"
:key="item.key" :key="index"
:title="item.label" :title="item.label"
> >
<n-icon <n-icon class="item-icon" size="16" :depth="2" :component="item.icon" />
class="item-icon"
size="16"
:depth="2"
:component="item.icon"
/>
<n-text depth="2">{{ item.label }}</n-text> <n-text depth="2">{{ item.label }}</n-text>
</div> </div>
</n-scrollbar> </n-scrollbar>
@ -55,7 +37,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed } from 'vue' import { ref, computed } from 'vue'
import { icon } from '@/plugins' import { icon } from '@/plugins'
import { renderIcon } from '@/utils'
import { useChartHistoryStore } from '@/store/modules/chartHistoryStore/chartHistoryStore' import { useChartHistoryStore } from '@/store/modules/chartHistoryStore/chartHistoryStore'
import { historyActionTypeName } from '@/store/modules/chartHistoryStore/chartHistoryDefine' import { historyActionTypeName } from '@/store/modules/chartHistoryStore/chartHistoryDefine'
import { CreateComponentType } from '@/packages/index.d' import { CreateComponentType } from '@/packages/index.d'
@ -64,20 +45,12 @@ import reverse from 'lodash/reverse'
import { import {
HistoryItemType, HistoryItemType,
HistoryTargetTypeEnum, HistoryTargetTypeEnum,
HistoryActionTypeEnum, HistoryActionTypeEnum
} from '@/store/modules/chartHistoryStore/chartHistoryStore.d' } from '@/store/modules/chartHistoryStore/chartHistoryStore.d'
const { const { DesktopOutlineIcon, PencilIcon, TrashIcon, CopyIcon, LayersIcon, DuplicateIcon, HelpOutlineIcon } =
DesktopOutlineIcon, icon.ionicons5
PencilIcon, const { StackedMoveIcon, Carbon3DCursorIcon, Carbon3DSoftwareIcon } = icon.carbon
TrashIcon,
CopyIcon,
LayersIcon,
DuplicateIcon,
HelpOutlineIcon,
} = icon.ionicons5
const { StackedMoveIcon } = icon.carbon
const showDropdownRef = ref(false)
const chartHistoryStoreStore = useChartHistoryStore() const chartHistoryStoreStore = useChartHistoryStore()
@ -106,6 +79,10 @@ const iconHandle = (e: HistoryItemType) => {
return StackedMoveIcon return StackedMoveIcon
case HistoryActionTypeEnum.ADD: case HistoryActionTypeEnum.ADD:
return DuplicateIcon return DuplicateIcon
case HistoryActionTypeEnum.GROUP:
return Carbon3DCursorIcon
case HistoryActionTypeEnum.UN_GROUP:
return Carbon3DSoftwareIcon
default: default:
return PencilIcon return PencilIcon
} }
@ -116,10 +93,11 @@ const labelHandle = (e: HistoryItemType) => {
// //
if (e.targetType === HistoryTargetTypeEnum.CANVAS) { if (e.targetType === HistoryTargetTypeEnum.CANVAS) {
return historyActionTypeName[HistoryTargetTypeEnum.CANVAS] return historyActionTypeName[HistoryTargetTypeEnum.CANVAS]
} else if (e.actionType === HistoryActionTypeEnum.GROUP || e.actionType === HistoryActionTypeEnum.UN_GROUP) {
return `${historyActionTypeName[e.actionType]}`
} else if (e.historyData.length) {
return `${historyActionTypeName[e.actionType]} - ${(e.historyData[0] as CreateComponentType).chartConfig.title}`
} }
return `${historyActionTypeName[e.actionType]} - ${
(e.historyData as CreateComponentType).chartConfig.title
}`
} }
const options = computed(() => { const options = computed(() => {
@ -127,16 +105,14 @@ const options = computed(() => {
const options = backStack.map((e: HistoryItemType) => { const options = backStack.map((e: HistoryItemType) => {
return { return {
label: labelHandle(e), label: labelHandle(e),
key: e.id, icon: iconHandle(e)
icon: iconHandle(e),
} }
}) })
return reverse(options)
})
const handleClick = () => { return reverse(options.filter(item => {
showDropdownRef.value = !showDropdownRef.value return item.label
} }))
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="go-edit-range go-transition" :style="rangeStyle" @mousedown="mousedownHandleUnStop($event, undefined)"> <div class="go-edit-range go-transition" :style="rangeStyle" @mousedown="mousedownBoxSelect($event, undefined)">
<slot></slot> <slot></slot>
<!-- 水印 --> <!-- 水印 -->
<edit-watermark></edit-watermark> <edit-watermark></edit-watermark>
@ -7,6 +7,8 @@
<edit-rule></edit-rule> <edit-rule></edit-rule>
<!-- 拖拽时的辅助线 --> <!-- 拖拽时的辅助线 -->
<edit-align-line></edit-align-line> <edit-align-line></edit-align-line>
<!-- 框选时的样式框 -->
<edit-select></edit-select>
<!-- 拖拽时的遮罩 --> <!-- 拖拽时的遮罩 -->
<div class="go-edit-range-model" :style="rangeModelStyle"></div> <div class="go-edit-range-model" :style="rangeModelStyle"></div>
</div> </div>
@ -15,11 +17,13 @@
<script setup lang="ts"> <script setup lang="ts">
import { toRefs, computed } from 'vue' import { toRefs, computed } from 'vue'
import { useSizeStyle } from '../../hooks/useStyle.hook' import { useSizeStyle } from '../../hooks/useStyle.hook'
import { mousedownHandleUnStop } from '../../hooks/useDrag.hook' import { canvasModelIndex } from '@/settings/designSetting'
import { mousedownBoxSelect } from '../../hooks/useDrag.hook'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { EditAlignLine } from '../EditAlignLine' import { EditAlignLine } from '../EditAlignLine'
import { EditWatermark } from '../EditWatermark' import { EditWatermark } from '../EditWatermark'
import { EditRule } from '../EditRule' import { EditRule } from '../EditRule'
import { EditSelect } from '../EditSelect'
const chartEditStore = useChartEditStore() const chartEditStore = useChartEditStore()

View File

@ -11,13 +11,12 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, toRefs } from 'vue' import { toRefs, computed } from 'vue'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { useDesignStore } from '@/store/modules/designStore/designStore' import { useDesignStore } from '@/store/modules/designStore/designStore'
const chartEditStore = useChartEditStore() const chartEditStore = useChartEditStore()
const designStore = useDesignStore() const designStore = useDesignStore()
const themeColor = ref(designStore.getAppTheme)
const { width, height } = toRefs(chartEditStore.getEditCanvasConfig) const { width, height } = toRefs(chartEditStore.getEditCanvasConfig)
@ -34,6 +33,12 @@ const lines = {
h: [], h: [],
v: [] v: []
} }
//
const themeColor = computed(() => {
return designStore.getAppTheme
})
</script> </script>
<style> <style>

View File

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

View File

@ -0,0 +1,111 @@
<template>
<div class="go-edit-select" v-if="isSelect" :style="positionStyle">
<div class="select-background"></div>
<div class="select-border"></div>
</div>
</template>
<script setup lang="ts">
import { ref, toRefs, watch, computed } from 'vue'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { useDesignStore } from '@/store/modules/designStore/designStore'
import { useSizeStyle, useComponentStyle } from '../../hooks/useStyle.hook'
import { selectBoxIndex } from '@/settings/designSetting'
//
const designStore = useDesignStore()
const chartEditStore = useChartEditStore()
const { isSelect, scale } = toRefs(chartEditStore.getEditCanvas)
const themeColor = computed(() => {
return designStore.getAppTheme
})
//
const positionStyle = ref()
watch(
() => chartEditStore.getMousePosition,
positionInfo => {
if (!isSelect.value) return
// x,y
const { startX, startY, x, y } = positionInfo
const attr = {
zIndex: selectBoxIndex,
// left
x: 0,
// top
y: 0,
//
w: 0,
//
h: 0
}
//
if (x > startX && y > startY) {
//
attr.x = startX
attr.y = startY
attr.w = Math.round((x - startX) / scale.value)
attr.h = Math.round((y - startY) / scale.value)
} else if (x > startX && y < startY) {
//
attr.x = startX
attr.w = Math.round((x - startX) / scale.value)
attr.h = Math.round((startY - y) / scale.value)
attr.y = startY - attr.h
} else if (x < startX && y > startY) {
//
attr.y = startY
attr.w = Math.round((startX - x) / scale.value)
attr.h = Math.round((y - startY) / scale.value)
attr.x = startX - attr.w
} else {
//
attr.w = Math.round((startX - x) / scale.value)
attr.h = Math.round((startY - y) / scale.value)
attr.x = startX - attr.w
attr.y = startY - attr.h
}
positionStyle.value = {
...useComponentStyle(attr, selectBoxIndex),
...useSizeStyle(attr)
}
},
{
deep: true
}
)
</script>
<style lang="scss" scoped>
@include go('edit-select') {
position: absolute;
.select-border,
.select-background {
position: absolute;
width: 100%;
height: 100%;
border-radius: 10px;
overflow: hidden;
}
.select-border {
left: 0;
top: 0;
opacity: 0.5;
border-width: 2px;
border-style: solid;
border-color: v-bind('themeColor');
}
.select-background {
top: 2px;
left: 2px;
opacity: 0.03;
background-color: v-bind('themeColor');
}
}
</style>

View File

@ -2,13 +2,15 @@
<div class="go-shape-box"> <div class="go-shape-box">
<slot></slot> <slot></slot>
<!-- 锚点 --> <!-- 锚点 -->
<div <template v-if="!hiddenPoint">
:class="`shape-point ${point}`" <div
v-for="(point, index) in select ? pointList : []" :class="`shape-point ${point}`"
:key="index" v-for="(point, index) in select ? pointList : []"
:style="usePointStyle(point, index, item.attr, cursorResize)" :key="index"
@mousedown="useMousePointHandle($event, point, item.attr)" :style="usePointStyle(point, index, item.attr, cursorResize)"
></div> @mousedown="useMousePointHandle($event, point, item.attr)"
></div>
</template>
<!-- 选中 --> <!-- 选中 -->
<div class="shape-modal" :style="useSizeStyle(item.attr)"> <div class="shape-modal" :style="useSizeStyle(item.attr)">
@ -19,23 +21,25 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, PropType, toRefs } from 'vue' import { computed, PropType } from 'vue'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { useDesignStore } from '@/store/modules/designStore/designStore' import { useDesignStore } from '@/store/modules/designStore/designStore'
import { CreateComponentType } from '@/packages/index.d' import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
import { useSizeStyle, usePointStyle } from '../../hooks/useStyle.hook' import { useSizeStyle, usePointStyle } from '../../hooks/useStyle.hook'
import { useMousePointHandle } from '../../hooks/useDrag.hook' import { useMousePointHandle } from '../../hooks/useDrag.hook'
const props = defineProps({ const props = defineProps({
item: { item: {
type: Object as PropType<CreateComponentType>, type: Object as PropType<CreateComponentType | CreateComponentGroupType>,
required: true required: true
},
hiddenPoint: {
type: Boolean,
required: false
} }
}) })
//
const designStore = useDesignStore() const designStore = useDesignStore()
const themeColor = ref(designStore.getAppTheme)
const chartEditStore = useChartEditStore() const chartEditStore = useChartEditStore()
// //
@ -44,6 +48,11 @@ const pointList = ['t', 'r', 'b', 'l', 'lt', 'rt', 'lb', 'rb']
// //
const cursorResize = ['n', 'e', 's', 'w', 'nw', 'ne', 'sw', 'se'] const cursorResize = ['n', 'e', 's', 'w', 'nw', 'ne', 'sw', 'se']
//
const themeColor = computed(() => {
return designStore.getAppTheme
})
// //
const hover = computed(() => { const hover = computed(() => {
return props.item.id === chartEditStore.getTargetChart.hoverId return props.item.id === chartEditStore.getTargetChart.hoverId

View File

@ -1,9 +1,5 @@
<template> <template>
<n-modal <n-modal v-model:show="modelShow" :mask-closable="true" @afterLeave="closeHandle">
v-model:show="modelShow"
:mask-closable="true"
@afterLeave="closeHandle"
>
<n-table class="model-content" :bordered="false" :single-line="false"> <n-table class="model-content" :bordered="false" :single-line="false">
<thead> <thead>
<tr> <tr>
@ -24,9 +20,7 @@
<td>{{ item.label }}</td> <td>{{ item.label }}</td>
<td>{{ item.win }}</td> <td>{{ item.win }}</td>
<td> <td>
<n-gradient-text :size="22">{{ <n-gradient-text :size="22">{{ item.mac.substr(0, 1) }}</n-gradient-text>
item.mac.substr(0, 1)
}}</n-gradient-text>
+ {{ item.mac.substr(3) }} + {{ item.mac.substr(3) }}
</td> </td>
</tr> </tr>
@ -44,7 +38,7 @@ const { CloseIcon } = icon.ionicons5
const emit = defineEmits(['update:modelShow']) const emit = defineEmits(['update:modelShow'])
defineProps({ defineProps({
modelShow: Boolean, modelShow: Boolean
}) })
// //
@ -52,58 +46,73 @@ const shortcutKeyOptions = [
{ {
label: '向上移动', label: '向上移动',
win: `${WinKeyboard.CTRL.toUpperCase()} + ↑ `, win: `${WinKeyboard.CTRL.toUpperCase()} + ↑ `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + ↑ `, mac: `${MacKeyboard.CTRL.toUpperCase()} + ↑ `
}, },
{ {
label: '向右移动', label: '向右移动',
win: `${WinKeyboard.CTRL.toUpperCase()} + → `, win: `${WinKeyboard.CTRL.toUpperCase()} + → `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + → `, mac: `${MacKeyboard.CTRL.toUpperCase()} + → `
}, },
{ {
label: '向下移动', label: '向下移动',
win: `${WinKeyboard.CTRL.toUpperCase()} + ↓ `, win: `${WinKeyboard.CTRL.toUpperCase()} + ↓ `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + ↓ `, mac: `${MacKeyboard.CTRL.toUpperCase()} + ↓ `
}, },
{ {
label: '向左移动', label: '向左移动',
win: `${WinKeyboard.CTRL.toUpperCase()} + ← `, win: `${WinKeyboard.CTRL.toUpperCase()} + ← `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + ← `, mac: `${MacKeyboard.CTRL.toUpperCase()} + ← `
}, },
{ {
label: '删除', label: '删除',
win: 'Delete'.toUpperCase(), win: 'Delete'.toUpperCase(),
mac: `${MacKeyboard.CTRL.toUpperCase()} + Backspace `, mac: `${MacKeyboard.CTRL.toUpperCase()} + Backspace `
}, },
{ {
label: '复制', label: '复制',
win: `${WinKeyboard.CTRL.toUpperCase()} + C `, win: `${WinKeyboard.CTRL.toUpperCase()} + C `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + C `, mac: `${MacKeyboard.CTRL.toUpperCase()} + C `
}, },
{ {
label: '剪切', label: '剪切',
win: `${WinKeyboard.CTRL.toUpperCase()} + X `, win: `${WinKeyboard.CTRL.toUpperCase()} + X `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + X `, mac: `${MacKeyboard.CTRL.toUpperCase()} + X `
}, },
{ {
label: '粘贴', label: '粘贴',
win: `${WinKeyboard.CTRL.toUpperCase()} + V `, win: `${WinKeyboard.CTRL.toUpperCase()} + V `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + V `, mac: `${MacKeyboard.CTRL.toUpperCase()} + V `
}, },
{ {
label: '后退', label: '后退',
win: `${WinKeyboard.CTRL.toUpperCase()} + Z `, win: `${WinKeyboard.CTRL.toUpperCase()} + Z `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + Z `, mac: `${MacKeyboard.CTRL.toUpperCase()} + Z `
}, },
{ {
label: '前进', label: '前进',
win: `${WinKeyboard.CTRL.toUpperCase()} + ${WinKeyboard.SHIFT.toUpperCase()} + Z `, win: `${WinKeyboard.CTRL.toUpperCase()} + ${WinKeyboard.SHIFT.toUpperCase()} + Z `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + ${MacKeyboard.SHIFT.toUpperCase()} + Z `, mac: `${MacKeyboard.CTRL.toUpperCase()} + ${MacKeyboard.SHIFT.toUpperCase()} + Z `
}, },
{ {
label: '保存', label: '保存',
win: `${WinKeyboard.CTRL.toUpperCase()} + S `, win: `${WinKeyboard.CTRL.toUpperCase()} + S `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + S `, mac: `${MacKeyboard.CTRL.toUpperCase()} + S `,
}, },
{
label: '多选',
win: `${WinKeyboard.CTRL.toUpperCase()} + 🖱️ `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + 🖱️ `
},
{
label: '创建分组',
win: `${WinKeyboard.CTRL.toUpperCase()} + G / 🖱️ `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + G / 🖱️`
},
{
label: '解除分组',
win: `${WinKeyboard.CTRL.toUpperCase()} + ${WinKeyboard.SHIFT.toUpperCase()} + G `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + ${WinKeyboard.SHIFT.toUpperCase()} + G `
}
] ]
const closeHandle = () => { const closeHandle = () => {
emit('update:modelShow', false) emit('update:modelShow', false)
@ -120,4 +129,4 @@ const closeHandle = () => {
padding: 5px 10px; padding: 5px 10px;
} }
} }
</style> </style>

View File

@ -31,15 +31,15 @@ export const useFile = () => {
negativeText: '覆盖(不可撤回)', negativeText: '覆盖(不可撤回)',
negativeButtonProps: { type: 'info', ghost: false }, negativeButtonProps: { type: 'info', ghost: false },
// 新增 // 新增
onNegativeCallback: async () => { onPositiveCallback: async () => {
fileData = JSON.parse(fileData) fileData = JSON.parse(fileData)
await updateComponent(fileData, true) await updateComponent(fileData, false, true)
window['$message'].success('导入成功!') window['$message'].success('导入成功!')
}, },
// 覆盖 // 覆盖
onPositiveCallback: async () => { onNegativeCallback: async () => {
fileData = JSON.parse(fileData) fileData = JSON.parse(fileData)
await updateComponent(fileData) await updateComponent(fileData, true, true)
window['$message'].success('导入成功!') window['$message'].success('导入成功!')
} }
}) })

View File

@ -1,10 +1,8 @@
import { DragKeyEnum } from '@/enums/editPageEnum' import { toRaw } from 'vue'
import { DragKeyEnum, MouseEventButton, WinKeyboard, MacKeyboard } from '@/enums/editPageEnum'
import { createComponent } from '@/packages' import { createComponent } from '@/packages'
import { ConfigType } from '@/packages/index.d' import { ConfigType } from '@/packages/index.d'
import { import { CreateComponentType, CreateComponentGroupType, PickCreateComponentType } from '@/packages/index.d'
CreateComponentType,
PickCreateComponentType,
} from '@/packages/index.d'
import { useContextMenu } from '@/views/chart/hooks/useContextMenu.hook' import { useContextMenu } from '@/views/chart/hooks/useContextMenu.hook'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { EditCanvasTypeEnum } from '@/store/modules/chartEditStore/chartEditStore.d' import { EditCanvasTypeEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
@ -22,7 +20,7 @@ export const dragHandle = async (e: DragEvent) => {
loadingStart() loadingStart()
// 获取拖拽数据 // 获取拖拽数据
const drayDataString = e!.dataTransfer!.getData(DragKeyEnum.DROG_KEY) const drayDataString = e!.dataTransfer!.getData(DragKeyEnum.DRAG_KEY)
if (!drayDataString) { if (!drayDataString) {
loadingFinish() loadingFinish()
return return
@ -35,10 +33,7 @@ export const dragHandle = async (e: DragEvent) => {
// 创建新图表组件 // 创建新图表组件
let newComponent: CreateComponentType = await createComponent(dropData) let newComponent: CreateComponentType = await createComponent(dropData)
newComponent.setPosition( newComponent.setPosition(e.offsetX - newComponent.attr.w / 2, e.offsetY - newComponent.attr.h / 2)
e.offsetX - newComponent.attr.w / 2,
e.offsetY - newComponent.attr.h / 2
)
chartEditStore.addComponentList(newComponent, false, true) chartEditStore.addComponentList(newComponent, false, true)
chartEditStore.setTargetSelectChart(newComponent.id) chartEditStore.setTargetSelectChart(newComponent.id)
loadingFinish() loadingFinish()
@ -57,10 +52,7 @@ export const dragoverHandle = (e: DragEvent) => {
} }
// * 不拦截默认行为点击 // * 不拦截默认行为点击
export const mousedownHandleUnStop = ( export const mousedownHandleUnStop = (e: MouseEvent, item?: CreateComponentType | CreateComponentGroupType) => {
e: MouseEvent,
item?: CreateComponentType
) => {
if (item) { if (item) {
chartEditStore.setTargetSelectChart(item.id) chartEditStore.setTargetSelectChart(item.id)
return return
@ -68,56 +60,213 @@ export const mousedownHandleUnStop = (
chartEditStore.setTargetSelectChart(undefined) chartEditStore.setTargetSelectChart(undefined)
} }
// * 移动图表 // * 框选
export const mousedownBoxSelect = (e: MouseEvent, item?: CreateComponentType | CreateComponentGroupType) => {
mousedownHandleUnStop(e)
// 记录点击初始位置
const startOffsetX = e.offsetX
const startOffsetY = e.offsetY
const startScreenX = e.screenX
const startScreenY = e.screenY
// 记录缩放
const scale = chartEditStore.getEditCanvas.scale
chartEditStore.setMousePosition(undefined, undefined, startOffsetX, startOffsetY)
// 移动框选
const mousemove = throttle((moveEvent: MouseEvent) => {
// 取消当前选中
chartEditStore.setTargetSelectChart()
chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_SELECT, true)
// 这里先把相对值算好,不然组件无法获取 startScreenX 和 startScreenY 的值
const currX = startOffsetX + moveEvent.screenX - startScreenX
const currY = startOffsetY + moveEvent.screenY - startScreenY
chartEditStore.setMousePosition(currX, currY)
// 计算框选的左上角和右下角
const selectAttr = {
// 左上角
x1: 0,
y1: 0,
// 右下角
x2: 0,
y2: 0
}
if (currX > startOffsetX && currY > startOffsetY) {
// 右下方向
selectAttr.x1 = startOffsetX
selectAttr.y1 = startOffsetY
selectAttr.x2 = Math.round(startOffsetX + (moveEvent.screenX - startScreenX) / scale)
selectAttr.y2 = Math.round(startOffsetY + (moveEvent.screenY - startScreenY) / scale)
} else if (currX > startOffsetX && currY < startOffsetY) {
// 右上方向
selectAttr.x1 = startOffsetX
selectAttr.y1 = Math.round(startOffsetY - (startScreenY - moveEvent.screenY) / scale)
selectAttr.x2 = Math.round(startOffsetX + (moveEvent.screenX - startScreenX) / scale)
selectAttr.y2 = startOffsetY
} else if (currX < startOffsetX && currY > startOffsetY) {
selectAttr.x1 = Math.round(startOffsetX - (startScreenX - moveEvent.screenX) / scale)
selectAttr.y1 = startOffsetY
selectAttr.x2 = startOffsetX
selectAttr.y2 = Math.round(startOffsetY + (moveEvent.screenY - startScreenY ) / scale)
// 左下方向
} else {
// 左上方向
selectAttr.x1 = Math.round(startOffsetX - (startScreenX - moveEvent.screenX) / scale)
selectAttr.y1 = Math.round(startOffsetY - (startScreenY - moveEvent.screenY) / scale)
selectAttr.x2 = startOffsetX
selectAttr.y2 = startOffsetY
}
// 遍历组件
chartEditStore.getComponentList.forEach(item => {
if (!chartEditStore.getTargetChart.selectId.includes(item.id)) {
// 处理左上角
let isSelect = false
const { x, y, w, h } = item.attr
const targetAttr = {
// 左上角
x1: x,
y1: y,
// 右下角
x2: x + w,
y2: y + h
}
// 全包含则选中
if (
targetAttr.x1 - selectAttr.x1 >= 0 &&
targetAttr.y1 - selectAttr.y1 >= 0 &&
targetAttr.x2 - selectAttr.x2 <= 0 &&
targetAttr.y2 - selectAttr.y2 <= 0
) {
isSelect = true
chartEditStore.setTargetSelectChart(item.id, true)
}
}
})
}, 20)
// 鼠标抬起
const mouseup = () => {
chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_SELECT, false)
chartEditStore.setMousePosition(0, 0, 0, 0)
document.removeEventListener('mousemove', mousemove)
document.removeEventListener('mouseup', mouseup)
}
document.addEventListener('mousemove', mousemove)
document.addEventListener('mouseup', mouseup)
}
// * 鼠标事件
export const useMouseHandle = () => { export const useMouseHandle = () => {
// 点击事件(包含移动事件) // * Click 事件, 松开鼠标触发
const mousedownHandle = (e: MouseEvent, item: CreateComponentType) => { const mouseClickHandle = (e: MouseEvent, item: CreateComponentType | CreateComponentGroupType) => {
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
// 若此时按下了 CTRL, 表示多选
if (
window.$KeyboardActive?.has(WinKeyboard.CTRL_SOURCE_KEY) ||
window.$KeyboardActive?.has(MacKeyboard.CTRL_SOURCE_KEY)
) {
// 若已选中,则去除
if (chartEditStore.targetChart.selectId.includes(item.id)) {
const exList = chartEditStore.targetChart.selectId.filter(e => e !== item.id)
chartEditStore.setTargetSelectChart(exList)
} else {
chartEditStore.setTargetSelectChart(item.id, true)
}
}
}
// * 按下事件(包含移动事件)
const mousedownHandle = (e: MouseEvent, item: CreateComponentType | CreateComponentGroupType) => {
e.preventDefault()
e.stopPropagation()
onClickOutSide() onClickOutSide()
// 按下左键 + CTRL
if (
e.buttons === MouseEventButton.LEFT &&
(window.$KeyboardActive?.has(WinKeyboard.CTRL_SOURCE_KEY) ||
window.$KeyboardActive?.has(MacKeyboard.CTRL_SOURCE_KEY))
)
return
// 按下右键 + 选中多个 + 目标元素是多选子元素
const selectId = chartEditStore.getTargetChart.selectId
if (e.buttons === MouseEventButton.RIGHT && selectId.length > 1 && selectId.includes(item.id)) return
// 选中当前目标组件
chartEditStore.setTargetSelectChart(item.id) chartEditStore.setTargetSelectChart(item.id)
// 按下右键
if (e.buttons === MouseEventButton.RIGHT) return
const scale = chartEditStore.getEditCanvas.scale const scale = chartEditStore.getEditCanvas.scale
const width = chartEditStore.getEditCanvasConfig.width const canvasWidth = chartEditStore.getEditCanvasConfig.width
const height = chartEditStore.getEditCanvasConfig.height const canvasHeight = chartEditStore.getEditCanvasConfig.height
// 记录图表初始位置和大小 // 记录图表初始位置和大小
const itemAttrX = item.attr.x const targetMap = new Map()
const itemAttrY = item.attr.y chartEditStore.getTargetChart.selectId.forEach(id => {
const itemAttrW = item.attr.w const index = chartEditStore.fetchTargetIndex(id)
const itemAttrH = item.attr.h if (index !== -1) {
const { x, y, w, h } = toRaw(chartEditStore.getComponentList[index]).attr
targetMap.set(id, { x, y, w, h })
}
})
// 记录点击初始位置 // 记录点击初始位置
const startX = e.screenX const startX = e.screenX
const startY = e.screenY const startY = e.screenY
// 记录初始位置
chartEditStore.setMousePosition(startX, startY)
// 计算偏移量(处理 scale 比例问题) // 记录初始位置
chartEditStore.setMousePosition(undefined, undefined, startX, startY)
// 移动-计算偏移量
const mousemove = throttle((moveEvent: MouseEvent) => { const mousemove = throttle((moveEvent: MouseEvent) => {
chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_DRAG, true) chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_DRAG, true)
chartEditStore.setMousePosition(moveEvent.screenX, moveEvent.screenY) chartEditStore.setMousePosition(moveEvent.screenX, moveEvent.screenY)
let currX = Math.round(itemAttrX + (moveEvent.screenX - startX) / scale) // 当前偏移量,处理 scale 比例问题
let currY = Math.round(itemAttrY + (moveEvent.screenY - startY) / scale) let offsetX = (moveEvent.screenX - startX) / scale
let offsetY = (moveEvent.screenY - startY) / scale
// 要预留的距离 chartEditStore.getTargetChart.selectId.forEach(id => {
const distance = 50 if (!targetMap.has(id)) return
// 基于左上角位置检测
currX = currX < -itemAttrW + distance ? -itemAttrW + distance : currX
currY = currY < -itemAttrH + distance ? -itemAttrH + distance : currY
// 基于右下角位置检测 const index = chartEditStore.fetchTargetIndex(id)
currX = currX > width - distance ? width - distance : currX // 拿到初始位置数据
currY = currY > height - distance ? height - distance : currY const { x, y, w, h } = targetMap.get(id)
const componentInstance = chartEditStore.getComponentList[index]
item.attr.x = currX let currX = Math.round(x + offsetX)
item.attr.y = currY let currY = Math.round(y + offsetY)
}, 30)
// 要预留的距离
const distance = 50
// 基于左上角位置检测
currX = currX < -w + distance ? -w + distance : currX
currY = currY < -h + distance ? -h + distance : currY
// 基于右下角位置检测
currX = currX > canvasWidth - distance ? canvasWidth - distance : currX
currY = currY > canvasHeight - distance ? canvasHeight - distance : currY
componentInstance.attr = Object.assign(componentInstance.attr, {
x: currX,
y: currY
})
})
return
}, 20)
const mouseup = () => { const mouseup = () => {
chartEditStore.setMousePosition(0, 0, 0, 0)
chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_DRAG, false) chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_DRAG, false)
chartEditStore.setMousePosition(0, 0)
document.removeEventListener('mousemove', mousemove) document.removeEventListener('mousemove', mousemove)
document.removeEventListener('mouseup', mouseup) document.removeEventListener('mouseup', mouseup)
} }
@ -127,29 +276,27 @@ export const useMouseHandle = () => {
} }
// * 进入事件 // * 进入事件
const mouseenterHandle = (e: MouseEvent, item: CreateComponentType) => { const mouseenterHandle = (e: MouseEvent, item: CreateComponentType | CreateComponentGroupType) => {
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
chartEditStore.setTargetHoverChart(item.id) if (!chartEditStore.getEditCanvas.isSelect) {
chartEditStore.setTargetHoverChart(item.id)
}
} }
// * 移出事件 // * 移出事件
const mouseleaveHandle = (e: MouseEvent, item: CreateComponentType) => { const mouseleaveHandle = (e: MouseEvent, item: CreateComponentType | CreateComponentGroupType) => {
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_DRAG, false) chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_DRAG, false)
chartEditStore.setTargetHoverChart(undefined) chartEditStore.setTargetHoverChart(undefined)
} }
return { mousedownHandle, mouseenterHandle, mouseleaveHandle } return { mouseClickHandle, mousedownHandle, mouseenterHandle, mouseleaveHandle }
} }
// * 移动锚点 // * 移动锚点
export const useMousePointHandle = ( export const useMousePointHandle = (e: MouseEvent, point: string, attr: PickCreateComponentType<'attr'>) => {
e: MouseEvent,
point: string,
attr: PickCreateComponentType<'attr'>
) => {
e.stopPropagation() e.stopPropagation()
e.preventDefault() e.preventDefault()
@ -191,7 +338,7 @@ export const useMousePointHandle = (
const mouseup = () => { const mouseup = () => {
chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_DRAG, false) chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_DRAG, false)
chartEditStore.setMousePosition(0, 0) chartEditStore.setMousePosition(0, 0, 0, 0)
document.removeEventListener('mousemove', mousemove) document.removeEventListener('mousemove', mousemove)
document.removeEventListener('mouseup', mouseup) document.removeEventListener('mouseup', mouseup)
} }

View File

@ -15,37 +15,45 @@
<!-- 展示 --> <!-- 展示 -->
<edit-range> <edit-range>
<!-- 滤镜预览 --> <!-- 滤镜预览 -->
<div :style="{ <div
:style="{
...getFilterStyle(chartEditStore.getEditCanvasConfig), ...getFilterStyle(chartEditStore.getEditCanvasConfig),
...rangeStyle ...rangeStyle
}"> }"
>
<!-- 图表 --> <!-- 图表 -->
<edit-shape-box <div v-for="(item, index) in chartEditStore.getComponentList" :key="item.id">
v-for="(item, index) in chartEditStore.getComponentList" <!-- 分组 -->
:key="item.id" <edit-group v-if="item.isGroup" :groupData="(item as CreateComponentGroupType)" :groupIndex="index"></edit-group>
:data-id="item.id"
:index="index" <!-- 单组件 -->
:style="useComponentStyle(item.attr, index)" <edit-shape-box
:item="item" v-else
@mousedown="mousedownHandle($event, item)" :data-id="item.id"
@mouseenter="mouseenterHandle($event, item)" :index="index"
@mouseleave="mouseleaveHandle($event, item)" :style="useComponentStyle(item.attr, index)"
@contextmenu="handleContextMenu($event, item)" :item="item"
> @click="mouseClickHandle($event, item)"
<component @mousedown="mousedownHandle($event, item)"
class="edit-content-chart" @mouseenter="mouseenterHandle($event, item)"
:class="animationsClass(item.styles.animations)" @mouseleave="mouseleaveHandle($event, item)"
:is="item.chartConfig.chartKey" @contextmenu="handleContextMenu($event, item, optionsHandle)"
:chartConfig="item" >
:themeSetting="themeSetting" <component
:themeColor="themeColor" class="edit-content-chart"
:style="{ :class="animationsClass(item.styles.animations)"
...useSizeStyle(item.attr), :is="item.chartConfig.chartKey"
...getFilterStyle(item.styles), :chartConfig="item"
...getTransformStyle(item.styles), :themeSetting="themeSetting"
}" :themeColor="themeColor"
></component> :style="{
</edit-shape-box> ...useSizeStyle(item.attr),
...getFilterStyle(item.styles),
...getTransformStyle(item.styles)
}"
></component>
</edit-shape-box>
</div>
</div> </div>
</edit-range> </edit-range>
</div> </div>
@ -65,8 +73,11 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, computed } from 'vue' import { onMounted, computed } from 'vue'
import { chartColors } from '@/settings/chartThemes/index' import { chartColors } from '@/settings/chartThemes/index'
import { MenuEnum } from '@/enums/editPageEnum'
import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
import { animationsClass, getFilterStyle, getTransformStyle } from '@/utils' import { animationsClass, getFilterStyle, getTransformStyle } from '@/utils'
import { useContextMenu } from '@/views/chart/hooks/useContextMenu.hook' import { useContextMenu } from '@/views/chart/hooks/useContextMenu.hook'
import { MenuOptionsItemType } from '@/views/chart/hooks/useContextMenu.hook.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { useLayout } from './hooks/useLayout.hook' import { useLayout } from './hooks/useLayout.hook'
@ -76,6 +87,7 @@ import { dragHandle, dragoverHandle, useMouseHandle } from './hooks/useDrag.hook
import { useComponentStyle, useSizeStyle } from './hooks/useStyle.hook' import { useComponentStyle, useSizeStyle } from './hooks/useStyle.hook'
import { ContentBox } from '../ContentBox/index' import { ContentBox } from '../ContentBox/index'
import { EditGroup } from './components/EditGroup'
import { EditRange } from './components/EditRange' import { EditRange } from './components/EditRange'
import { EditBottom } from './components/EditBottom' import { EditBottom } from './components/EditBottom'
import { EditShapeBox } from './components/EditShapeBox' import { EditShapeBox } from './components/EditShapeBox'
@ -89,7 +101,33 @@ const { dataSyncFetch, intervalDataSyncUpdate } = useSync()
useLayout() useLayout()
// //
const { mouseenterHandle, mouseleaveHandle, mousedownHandle } = useMouseHandle() const { mouseenterHandle, mouseleaveHandle, mousedownHandle, mouseClickHandle } = useMouseHandle()
//
const optionsHandle = (
targetList: MenuOptionsItemType[],
allList: MenuOptionsItemType[],
targetInstance: CreateComponentType
) => {
//
const moreMenuEnums = [MenuEnum.GROUP, MenuEnum.DELETE]
//
const singleMenuEnums = targetList
//
if (chartEditStore.getTargetChart.selectId.length > 1) {
const list: MenuOptionsItemType[] = []
allList.forEach(item => {
//
if (moreMenuEnums.includes(item.key as MenuEnum)) {
list.push(item)
}
})
return list
}
return singleMenuEnums
}
// //
const themeSetting = computed(() => { const themeSetting = computed(() => {

View File

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

View File

@ -0,0 +1,224 @@
<template>
<div class="go-content-layers-group-list-item">
<div
class="root-item-content"
:class="{ hover: hover, select: select }"
@click="clickHandle($event)"
@mousedown="groupMousedownHandle($event)"
@mouseenter="mouseenterHandle(componentGroupData)"
@mouseleave="mouseleaveHandle(componentGroupData)"
@contextmenu="handleContextMenu($event, componentGroupData, optionsHandle)"
>
<div class="go-flex-items-center item-content">
<n-icon size="20" class="go-ml-1">
<template v-if="expend">
<folder-open-icon></folder-open-icon>
</template>
<template v-else>
<folder-icon></folder-icon>
</template>
</n-icon>
<n-ellipsis>
<n-text class="go-ml-2 list-text" :depth="2">
{{ componentGroupData.chartConfig.title }}
</n-text>
</n-ellipsis>
</div>
<div :class="{ 'select-modal': select }"></div>
</div>
<n-collapse-transition :show="expend">
<LayersListItem
v-for="element in componentGroupData.groupList"
:key="element.id"
:componentData="element"
@mousedown="mousedownHandle($event, element, componentGroupData.id)"
@mouseenter="mouseenterHandle(element)"
@mouseleave="mouseleaveHandle(element)"
@contextmenu="handleContextMenu($event, componentGroupData, optionsHandle)"
></LayersListItem>
</n-collapse-transition>
</div>
</template>
<script setup lang="ts">
import { ref, computed, PropType } from 'vue'
import { MouseEventButton, WinKeyboard, MacKeyboard } from '@/enums/editPageEnum'
import { MenuEnum } from '@/enums/editPageEnum'
import { useDesignStore } from '@/store/modules/designStore/designStore'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { useContextMenu, divider } from '@/views/chart/hooks/useContextMenu.hook'
import { MenuOptionsItemType } from '@/views/chart/hooks/useContextMenu.hook.d'
import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
import { LayersListItem } from '../LayersListItem'
import throttle from 'lodash/throttle'
import { icon } from '@/plugins'
const props = defineProps({
componentGroupData: {
type: Object as PropType<CreateComponentGroupType>,
required: true
}
})
//
const pickOptionsList = [MenuEnum.UN_GROUP]
//
const designStore = useDesignStore()
const { FolderIcon, FolderOpenIcon } = icon.ionicons5
const chartEditStore = useChartEditStore()
const { handleContextMenu, onClickOutSide } = useContextMenu()
const expend = ref(false)
//
const themeColor = computed(() => {
return designStore.getAppTheme
})
//
const optionsHandle = (
targetList: MenuOptionsItemType[],
allList: MenuOptionsItemType[],
targetInstance: CreateComponentType
) => {
const filter = (menulist: MenuEnum[]) => {
const list: MenuOptionsItemType[] = []
allList.forEach(item => {
if (menulist.includes(item.key as MenuEnum)) {
list.push(item)
}
})
return list
}
//
if (chartEditStore.getTargetChart.selectId.length > 1) {
return filter([MenuEnum.GROUP])
} else {
return [...filter([MenuEnum.UN_GROUP]), divider(), ...targetList]
}
}
//
const clickHandle = (e: MouseEvent) => {
// + CTRL
if (
window.$KeyboardActive?.has(WinKeyboard.CTRL_SOURCE_KEY) ||
window.$KeyboardActive?.has(MacKeyboard.CTRL_SOURCE_KEY)
)
return
//
expend.value = !expend.value
mousedownHandle(e, props.componentGroupData)
}
//
const select = computed(() => {
const id = props.componentGroupData.id
return chartEditStore.getTargetChart.selectId.find((e: string) => e === id)
})
//
const hover = computed(() => {
return props.componentGroupData.id === chartEditStore.getTargetChart.hoverId
})
//
const groupMousedownHandle = (e: MouseEvent) => {
onClickOutSide()
// CTRL,
const id = props.componentGroupData.id
if (
e.buttons === MouseEventButton.LEFT &&
(window.$KeyboardActive?.has(WinKeyboard.CTRL_SOURCE_KEY) ||
window.$KeyboardActive?.has(MacKeyboard.CTRL_SOURCE_KEY))
) {
//
if (chartEditStore.targetChart.selectId.includes(id)) {
const exList = chartEditStore.targetChart.selectId.filter(e => e !== id)
chartEditStore.setTargetSelectChart(exList)
} else {
chartEditStore.setTargetSelectChart(id, true)
}
return
}
chartEditStore.setTargetSelectChart(id)
}
//
const mousedownHandle = (e: MouseEvent, componentInstance: CreateComponentType | CreateComponentGroupType, id?: string) => {
e.preventDefault()
e.stopPropagation()
onClickOutSide()
chartEditStore.setTargetSelectChart(id || componentInstance.id)
}
//
const mouseenterHandle = (componentInstance: CreateComponentType | CreateComponentGroupType) => {
chartEditStore.setTargetHoverChart(componentInstance.id)
}
//
const mouseleaveHandle = (componentInstance: CreateComponentType | CreateComponentGroupType) => {
chartEditStore.setTargetHoverChart(undefined)
}
</script>
<style lang="scss" scoped>
$centerHeight: 52px;
$textSize: 10px;
@include go(content-layers-group-list-item) {
position: relative;
width: 90%;
margin: 10px 5%;
margin-bottom: 5px;
@extend .go-transition-quick;
.root-item-content {
height: $centerHeight;
cursor: pointer;
border-radius: 5px;
border: 1px solid rgba(0, 0, 0, 0);
&.hover,
&:hover {
@include fetch-bg-color('background-color4');
}
/* 选中 */
&.select {
border: 1px solid v-bind('themeColor');
/* 需要设置最高级,覆盖 hover 的颜色 */
background-color: rgba(0, 0, 0, 0);
.list-img {
border: 1px solid v-bind('themeColor') !important;
}
}
}
.select-modal,
.item-content {
position: absolute;
top: 0;
left: 0;
}
.item-content {
z-index: 1;
padding: 6px 5px;
justify-content: start !important;
width: calc(100% - 10px);
height: calc(#{$centerHeight} - 10px);
}
.select-modal {
width: 100%;
height: calc(#{$centerHeight} + 2px);
opacity: 0.3;
background-color: v-bind('themeColor');
}
.list-text {
padding-left: 6px;
font-size: $textSize;
}
}
</style>

View File

@ -22,16 +22,20 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, toRefs, computed } from 'vue' import { toRefs, computed } 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'
// //
const designStore = useDesignStore() const designStore = useDesignStore()
const themeColor = ref(designStore.getAppTheme)
const chartEditStore = useChartEditStore() const chartEditStore = useChartEditStore()
//
const themeColor = computed(() => {
return designStore.getAppTheme
})
const props = defineProps({ const props = defineProps({
componentData: { componentData: {
type: Object, type: Object,
@ -60,7 +64,7 @@ $textSize: 10px;
position: relative; position: relative;
height: $centerHeight; height: $centerHeight;
width: 90%; width: 90%;
margin: 10px 5%; margin: 5px 5%;
margin-bottom: 5px; margin-bottom: 5px;
border-radius: 5px; border-radius: 5px;
cursor: pointer; cursor: pointer;

View File

@ -5,6 +5,7 @@
title="图层" title="图层"
:depth="2" :depth="2"
@back="backHandle" @back="backHandle"
@mousedown="boxMousedownHandle($event)"
> >
<template #icon> <template #icon>
<n-icon size="16" :depth="2"> <n-icon size="16" :depth="2">
@ -16,20 +17,21 @@
<n-text class="not-layer-text">暂无图层~</n-text> <n-text class="not-layer-text">暂无图层~</n-text>
</n-space> </n-space>
<!-- https://github.com/SortableJS/vue.draggable.next --> <!-- https://github.com/SortableJS/vue.draggable.next -->
<draggable <draggable item-key="id" v-model="reverseList" ghostClass="ghost" @change="onMoveCallback">
item-key="id"
v-model="reverseList"
ghostClass="ghost"
@change="onMoveCallback"
>
<template #item="{ element }"> <template #item="{ element }">
<layers-list-item <div class="go-content-layer-box">
:componentData="element" <!-- 组合 -->
@mousedown="mousedownHandle(element)" <layers-group-list-item v-if="element.isGroup" :componentGroupData="element"></layers-group-list-item>
@mouseenter="mouseenterHandle(element)" <!-- 单组件 -->
@mouseleave="mouseleaveHandle(element)" <layers-list-item
@contextmenu="handleContextMenu($event, element)" v-else
></layers-list-item> :componentData="element"
@mousedown="mousedownHandle($event, element)"
@mouseenter="mouseenterHandle(element)"
@mouseleave="mouseleaveHandle(element)"
@contextmenu="handleContextMenu($event, element, optionsHandle)"
></layers-list-item>
</div>
</template> </template>
</draggable> </draggable>
</content-box> </content-box>
@ -39,27 +41,49 @@
import { computed, toRaw } from 'vue' import { computed, toRaw } from 'vue'
import Draggable from 'vuedraggable' import Draggable from 'vuedraggable'
import cloneDeep from 'lodash/cloneDeep' import cloneDeep from 'lodash/cloneDeep'
import { ContentBox } from '../ContentBox/index' import { ContentBox } from '../ContentBox/index'
import { useChartLayoutStore } from '@/store/modules/chartLayoutStore/chartLayoutStore' import { useChartLayoutStore } from '@/store/modules/chartLayoutStore/chartLayoutStore'
import { ChartLayoutStoreEnum } from '@/store/modules/chartLayoutStore/chartLayoutStore.d' import { ChartLayoutStoreEnum } from '@/store/modules/chartLayoutStore/chartLayoutStore.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { CreateComponentType } from '@/packages/index.d' import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
import { MenuOptionsItemType } from '@/views/chart/hooks/useContextMenu.hook.d'
import { useContextMenu } from '@/views/chart/hooks/useContextMenu.hook' import { useContextMenu } from '@/views/chart/hooks/useContextMenu.hook'
import { MenuEnum } from '@/enums/editPageEnum' import { MenuEnum, MouseEventButton, WinKeyboard, MacKeyboard } from '@/enums/editPageEnum'
import { LayersListItem } from './components/LayersListItem/index' import { LayersListItem } from './components/LayersListItem/index'
import { LayersGroupListItem } from './components/LayersGroupListItem/index'
import { icon } from '@/plugins' import { icon } from '@/plugins'
const { LayersIcon } = icon.ionicons5 const { LayersIcon } = icon.ionicons5
const chartLayoutStore = useChartLayoutStore() const chartLayoutStore = useChartLayoutStore()
const chartEditStore = useChartEditStore() const chartEditStore = useChartEditStore()
const { handleContextMenu } = useContextMenu() const { handleContextMenu, onClickOutSide } = useContextMenu()
//
const optionsHandle = (
targetList: MenuOptionsItemType[],
allList: MenuOptionsItemType[],
targetInstance: CreateComponentType
) => {
//
if (chartEditStore.getTargetChart.selectId.length > 1) {
const list: MenuOptionsItemType[] = []
targetList.forEach(item => {
//
if (item.key === MenuEnum.GROUP) {
list.push(item)
}
})
return list
}
return targetList
}
// //
const reverseList = computed(() => { const reverseList = computed(() => {
const list: CreateComponentType[] = cloneDeep(chartEditStore.getComponentList) const list: Array<CreateComponentType | CreateComponentGroupType> = cloneDeep(chartEditStore.getComponentList)
return list.reverse() return list.reverse()
}) })
@ -87,9 +111,33 @@ const onMoveCallback = (val: any) => {
} }
} }
const boxMousedownHandle = (e: MouseEvent) => {
const box = document.querySelector('.go-content-layer-box')
if ((e.target as any).contains(box)) {
chartEditStore.setTargetSelectChart()
}
}
// //
const mousedownHandle = (item: CreateComponentType) => { const mousedownHandle = (e: MouseEvent, item: CreateComponentType) => {
chartEditStore.setTargetSelectChart(item.id) onClickOutSide()
// CTRL,
const id = item.id
if (
e.buttons === MouseEventButton.LEFT &&
(window.$KeyboardActive?.has(WinKeyboard.CTRL_SOURCE_KEY) ||
window.$KeyboardActive?.has(MacKeyboard.CTRL_SOURCE_KEY))
) {
//
if (chartEditStore.targetChart.selectId.includes(id)) {
const exList = chartEditStore.targetChart.selectId.filter(e => e !== id)
chartEditStore.setTargetSelectChart(exList)
} else {
chartEditStore.setTargetSelectChart(id, true)
}
return
}
chartEditStore.setTargetSelectChart(id)
} }
// //

View File

@ -1,15 +1,4 @@
// 右键枚举 import { MenuEnum } from '@/enums/editPageEnum'
export enum MenuEnum {
DELETE = 'delete',
COPY = 'copy',
CUT = 'cut',
PARSE = 'parse',
TOP = 'top',
BOTTOM = 'bottom',
UP = 'up',
DOWN = 'down',
CLEAR = 'clear',
}
export interface MenuOptionsItemType { export interface MenuOptionsItemType {
type?: string type?: string

View File

@ -1,87 +1,109 @@
import { ref, nextTick } from 'vue' import { ref, nextTick, toRaw } from 'vue'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { CreateComponentType } from '@/packages/index.d' import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
import { renderIcon, loadingError } from '@/utils' import { renderIcon, loadingError } from '@/utils'
import { icon } from '@/plugins' import { icon } from '@/plugins'
import { MenuOptionsItemType } from './useContextMenu.hook.d' import { MenuOptionsItemType } from './useContextMenu.hook.d'
import { MenuEnum } from '@/enums/editPageEnum' import { MenuEnum } from '@/enums/editPageEnum'
import cloneDeep from 'lodash/cloneDeep'
const { const { CopyIcon, CutIcon, ClipboardOutlineIcon, TrashIcon, ChevronDownIcon, ChevronUpIcon } = icon.ionicons5
CopyIcon, const { UpToTopIcon, DownToBottomIcon, PaintBrushIcon, Carbon3DSoftwareIcon, Carbon3DCursorIcon } = icon.carbon
CutIcon,
ClipboardOutlineIcon,
TrashIcon,
ChevronDownIcon,
ChevronUpIcon,
} = icon.ionicons5
const { UpToTopIcon, DownToBottomIcon, PaintBrushIcon } = icon.carbon
const chartEditStore = useChartEditStore() const chartEditStore = useChartEditStore()
// * 默认选项 /**
const defaultOptions: MenuOptionsItemType[] = [ * 线
* @param {number} n > 2
* @returns
*/
export const divider = (n:number = 3) => {
return {
type: 'divider',
key: `d${n}`
}
}
// * 默认单组件选项
export const defaultOptions: MenuOptionsItemType[] = [
{ {
label: '复制', label: '复制',
key: MenuEnum.COPY, key: MenuEnum.COPY,
icon: renderIcon(CopyIcon), icon: renderIcon(CopyIcon),
fnHandle: chartEditStore.setCopy, fnHandle: chartEditStore.setCopy
}, },
{ {
label: '剪切', label: '剪切',
key: MenuEnum.CUT, key: MenuEnum.CUT,
icon: renderIcon(CutIcon), icon: renderIcon(CutIcon),
fnHandle: chartEditStore.setCut, fnHandle: chartEditStore.setCut
}, },
{ {
label: '粘贴', label: '粘贴',
key: MenuEnum.PARSE, key: MenuEnum.PARSE,
icon: renderIcon(ClipboardOutlineIcon), icon: renderIcon(ClipboardOutlineIcon),
fnHandle: chartEditStore.setParse, fnHandle: chartEditStore.setParse
}, },
{ {
type: 'divider', type: 'divider',
key: 'd1', key: 'd1'
}, },
{ {
label: '置顶', label: '置顶',
key: MenuEnum.TOP, key: MenuEnum.TOP,
icon: renderIcon(UpToTopIcon), icon: renderIcon(UpToTopIcon),
fnHandle: chartEditStore.setTop, fnHandle: chartEditStore.setTop
}, },
{ {
label: '置底', label: '置底',
key: MenuEnum.BOTTOM, key: MenuEnum.BOTTOM,
icon: renderIcon(DownToBottomIcon), icon: renderIcon(DownToBottomIcon),
fnHandle: chartEditStore.setBottom, fnHandle: chartEditStore.setBottom
}, },
{ {
label: '上移一层', label: '上移一层',
key: MenuEnum.UP, key: MenuEnum.UP,
icon: renderIcon(ChevronUpIcon), icon: renderIcon(ChevronUpIcon),
fnHandle: chartEditStore.setUp, fnHandle: chartEditStore.setUp
}, },
{ {
label: '下移一层', label: '下移一层',
key: MenuEnum.DOWN, key: MenuEnum.DOWN,
icon: renderIcon(ChevronDownIcon), icon: renderIcon(ChevronDownIcon),
fnHandle: chartEditStore.setDown, fnHandle: chartEditStore.setDown
}, },
{ {
type: 'divider', type: 'divider',
key: 'd2', key: 'd2'
}, },
{ {
label: '清空剪贴板', label: '清空剪贴板',
key: MenuEnum.CLEAR, key: MenuEnum.CLEAR,
icon: renderIcon(PaintBrushIcon), icon: renderIcon(PaintBrushIcon),
fnHandle: chartEditStore.setRecordChart, fnHandle: chartEditStore.setRecordChart
}, },
{ {
label: '删除', label: '删除',
key: MenuEnum.DELETE, key: MenuEnum.DELETE,
icon: renderIcon(TrashIcon), icon: renderIcon(TrashIcon),
fnHandle: chartEditStore.removeComponentList, fnHandle: chartEditStore.removeComponentList
}
]
// * 默认多选组件选项
export const defaultMultiSelectOptions: MenuOptionsItemType[] = [
{
label: '创建分组',
key: MenuEnum.GROUP,
icon: renderIcon(Carbon3DSoftwareIcon),
fnHandle: chartEditStore.setGroup
}, },
{
label: '解除分组',
key: MenuEnum.UN_GROUP,
icon: renderIcon(Carbon3DCursorIcon),
fnHandle: chartEditStore.setUnGroup
}
] ]
// * 无数据传递拥有的选项 // * 无数据传递拥有的选项
@ -95,9 +117,11 @@ const defaultNoItemKeys = [MenuEnum.PARSE, MenuEnum.CLEAR]
*/ */
const pickOption = (options: MenuOptionsItemType[], pickList?: MenuEnum[]) => { const pickOption = (options: MenuOptionsItemType[], pickList?: MenuEnum[]) => {
if (!pickList) return options if (!pickList) return options
return options.filter((op: MenuOptionsItemType) => { const list: MenuOptionsItemType[] = []
return pickList.findIndex((e: MenuEnum) => e === op.key) !== -1 pickList.forEach(e => {
list.push(...options.filter(op => op.key === e))
}) })
return list
} }
/** /**
@ -120,36 +144,49 @@ const menuOptions = ref<MenuOptionsItemType[]>([])
const handleContextMenu = ( const handleContextMenu = (
e: MouseEvent, e: MouseEvent,
// 右键对象 // 右键对象
item?: CreateComponentType, targetInstance?: CreateComponentType | CreateComponentGroupType,
// 判断函数 // 判断函数
optionsHandle?: Function, optionsHandle?: Function,
// 隐藏选项列表 // 隐藏选项列表
hideOptionsList?: MenuEnum[], hideOptionsList?: MenuEnum[],
// 挑选选项列表 // 挑选选项列表
pickOptionsList?: MenuEnum[], pickOptionsList?: MenuEnum[]
) => { ) => {
e.stopPropagation() e.stopPropagation()
e.preventDefault() e.preventDefault()
let target = e.target let target = e.target
while (target instanceof SVGElement) { while (target instanceof SVGElement) {
target = target.parentNode target = target.parentNode
} }
// 展示列表
chartEditStore.setRightMenuShow(false) chartEditStore.setRightMenuShow(false)
// * 设置默认选项 // * 多选默认选项
menuOptions.value = defaultOptions if (chartEditStore.getTargetChart.selectId.length > 1) {
menuOptions.value = defaultMultiSelectOptions
} else {
// * 单选默认选项
menuOptions.value = defaultOptions
}
if (!item) { if (!targetInstance) {
menuOptions.value = pickOption(menuOptions.value, defaultNoItemKeys) menuOptions.value = pickOption(toRaw(menuOptions.value), defaultNoItemKeys)
} }
if (hideOptionsList) { if (hideOptionsList) {
menuOptions.value = hideOption(menuOptions.value, hideOptionsList) menuOptions.value = hideOption([...defaultMultiSelectOptions, divider(), ...defaultOptions], hideOptionsList)
} }
if (pickOptionsList) { if (pickOptionsList) {
menuOptions.value = hideOption(menuOptions.value, pickOptionsList) menuOptions.value = pickOption([...defaultMultiSelectOptions, divider(), ...defaultOptions], pickOptionsList)
} }
if (optionsHandle) { if (optionsHandle) {
menuOptions.value = optionsHandle(menuOptions.value) // 自定义函数能够拿到当前选项和所有选项
menuOptions.value = optionsHandle(
cloneDeep(toRaw(menuOptions.value)),
[...defaultMultiSelectOptions, ...defaultOptions],
targetInstance
)
} }
nextTick().then(() => { nextTick().then(() => {
chartEditStore.setMousePosition(e.clientX, e.clientY) chartEditStore.setMousePosition(e.clientX, e.clientY)
@ -163,7 +200,6 @@ const handleContextMenu = (
* @returns * @returns
*/ */
export const useContextMenu = () => { export const useContextMenu = () => {
// 设置默认项 // 设置默认项
menuOptions.value = defaultOptions menuOptions.value = defaultOptions
@ -175,9 +211,7 @@ export const useContextMenu = () => {
// * 事件处理 // * 事件处理
const handleMenuSelect = (key: string) => { const handleMenuSelect = (key: string) => {
chartEditStore.setRightMenuShow(false) chartEditStore.setRightMenuShow(false)
const targetItem: MenuOptionsItemType[] = menuOptions.value.filter( const targetItem: MenuOptionsItemType[] = menuOptions.value.filter((e: MenuOptionsItemType) => e.key === key)
(e: MenuOptionsItemType) => e.key === key
)
menuOptions.value.forEach((e: MenuOptionsItemType) => { menuOptions.value.forEach((e: MenuOptionsItemType) => {
if (e.key === key) { if (e.key === key) {
@ -189,12 +223,14 @@ export const useContextMenu = () => {
} }
}) })
} }
return { return {
menuOptions, menuOptions,
defaultOptions,
defaultMultiSelectOptions,
handleContextMenu, handleContextMenu,
onClickOutSide, onClickOutSide,
handleMenuSelect, handleMenuSelect,
mousePosition: chartEditStore.getMousePosition, mousePosition: chartEditStore.getMousePosition
} }
} }

View File

@ -24,6 +24,8 @@ export const winKeyboardValue = {
[MenuEnum.BACK]: winCtrlMerge('z'), [MenuEnum.BACK]: winCtrlMerge('z'),
[MenuEnum.FORWORD]: winCtrlMerge(winShiftMerge('z')), [MenuEnum.FORWORD]: winCtrlMerge(winShiftMerge('z')),
[MenuEnum.SAVE]: winCtrlMerge('s'), [MenuEnum.SAVE]: winCtrlMerge('s'),
[MenuEnum.GROUP]: winCtrlMerge('g'),
[MenuEnum.UN_GROUP]: winCtrlMerge(winShiftMerge('g')),
} }
// 这个 Ctrl 后面还是换成了 ⌘ // 这个 Ctrl 后面还是换成了 ⌘
@ -44,6 +46,8 @@ export const macKeyboardValue = {
[MenuEnum.BACK]: macCtrlMerge('z'), [MenuEnum.BACK]: macCtrlMerge('z'),
[MenuEnum.FORWORD]: macCtrlMerge(macShiftMerge('z')), [MenuEnum.FORWORD]: macCtrlMerge(macShiftMerge('z')),
[MenuEnum.SAVE]: macCtrlMerge('s'), [MenuEnum.SAVE]: macCtrlMerge('s'),
[MenuEnum.GROUP]: macCtrlMerge('g'),
[MenuEnum.UN_GROUP]: macCtrlMerge(macShiftMerge('g')),
} }
// Win 快捷键列表 // Win 快捷键列表
@ -62,6 +66,8 @@ const winKeyList: Array<string> = [
winKeyboardValue.forward, winKeyboardValue.forward,
winKeyboardValue.save, winKeyboardValue.save,
winKeyboardValue.group,
winKeyboardValue.unGroup,
] ]
// Mac 快捷键列表 // Mac 快捷键列表
@ -80,65 +86,80 @@ const macKeyList: Array<string> = [
macKeyboardValue.forward, macKeyboardValue.forward,
macKeyboardValue.save, macKeyboardValue.save,
macKeyboardValue.group,
macKeyboardValue.unGroup,
] ]
// 处理键盘记录 // 处理键盘记录
const keyRecordHandle = () => { const keyRecordHandle = () => {
document.onkeydown = throttle((e: KeyboardEvent) => { // 初始化清空
if(window.$KeyboardActive) window.$KeyboardActive.add(e.key.toLocaleLowerCase()) if(window.$KeyboardActive) window.$KeyboardActive = new Set([])
else window.$KeyboardActive = new Set([e.key])
}, 200)
document.onkeyup = throttle((e: KeyboardEvent) => { document.onkeydown = (e: KeyboardEvent) => {
if(window.$KeyboardActive) window.$KeyboardActive.add(e.key.toLocaleLowerCase())
else window.$KeyboardActive = new Set([e.key.toLocaleLowerCase()])
}
document.onkeyup = (e: KeyboardEvent) => {
if(window.$KeyboardActive) window.$KeyboardActive.delete(e.key.toLocaleLowerCase()) if(window.$KeyboardActive) window.$KeyboardActive.delete(e.key.toLocaleLowerCase())
}, 200) }
} }
// 初始化监听事件 // 初始化监听事件
export const useAddKeyboard = () => { export const useAddKeyboard = () => {
const throttleTime = 50
const switchHandle = (keyboardValue: typeof winKeyboardValue, e: string) => { const switchHandle = (keyboardValue: typeof winKeyboardValue, e: string) => {
switch (e) { switch (e) {
// ct+↑ // ct+↑
case keyboardValue.up: case keyboardValue.up:
keymaster(e, throttle(() => { chartEditStore.setMove(MenuEnum.ARROW_UP); return false }, 200)) keymaster(e, throttle(() => { chartEditStore.setMove(MenuEnum.ARROW_UP); return false }, throttleTime))
break; break;
// ct+→ // ct+→
case keyboardValue.right: case keyboardValue.right:
keymaster(e, throttle(() => { chartEditStore.setMove(MenuEnum.ARROW_RIGHT); return false }, 200)) keymaster(e, throttle(() => { chartEditStore.setMove(MenuEnum.ARROW_RIGHT); return false }, throttleTime))
break; break;
// ct+↓ // ct+↓
case keyboardValue.down: case keyboardValue.down:
keymaster(e, throttle(() => { chartEditStore.setMove(MenuEnum.ARROW_DOWN); return false }, 200)) keymaster(e, throttle(() => { chartEditStore.setMove(MenuEnum.ARROW_DOWN); return false }, throttleTime))
break; break;
// ct+← // ct+←
case keyboardValue.left: case keyboardValue.left:
keymaster(e, throttle(() => { chartEditStore.setMove(MenuEnum.ARROW_LEFT); return false }, 200)) keymaster(e, throttle(() => { chartEditStore.setMove(MenuEnum.ARROW_LEFT); return false }, throttleTime))
break; break;
// 删除 delete // 删除 delete
case keyboardValue.delete: case keyboardValue.delete:
keymaster(e, debounce(() => { chartEditStore.removeComponentList(); return false }, 200)) keymaster(e, debounce(() => { chartEditStore.removeComponentList(); return false }, throttleTime))
break; break;
// 复制 ct+v // 复制 ct+v
case keyboardValue.copy: case keyboardValue.copy:
keymaster(e, debounce(() => { chartEditStore.setCopy(); return false }, 200)) keymaster(e, debounce(() => { chartEditStore.setCopy(); return false }, throttleTime))
break; break;
// 剪切 ct+x // 剪切 ct+x
case keyboardValue.cut: case keyboardValue.cut:
keymaster(e, debounce(() => { chartEditStore.setCut(); return false }, 200)) keymaster(e, debounce(() => { chartEditStore.setCut(); return false }, throttleTime))
break; break;
// 粘贴 ct+v // 粘贴 ct+v
case keyboardValue.parse: case keyboardValue.parse:
keymaster(e, throttle(() => { chartEditStore.setParse(); return false }, 200)) keymaster(e, throttle(() => { chartEditStore.setParse(); return false }, throttleTime))
break; break;
// 撤回 ct+z // 撤回 ct+z
case keyboardValue.back: case keyboardValue.back:
keymaster(e, throttle(() => { chartEditStore.setBack(); return false }, 200)) keymaster(e, throttle(() => { chartEditStore.setBack(); return false }, throttleTime))
break; break;
// 前进 ct+sh+z // 前进 ct+sh+z
case keyboardValue.forward: case keyboardValue.forward:
keymaster(e, throttle(() => { chartEditStore.setForward(); return false }, 200)) keymaster(e, throttle(() => { chartEditStore.setForward(); return false }, throttleTime))
break;
// 创建分组 ct+g
case keyboardValue.group:
keymaster(e, throttle(() => { chartEditStore.setGroup(); return false }, throttleTime))
break;
// 解除分组 ct+sh+g
case keyboardValue.unGroup:
keymaster(e, throttle(() => { chartEditStore.setUnGroup(); return false }, throttleTime))
break; break;
// 保存 ct+s // 保存 ct+s

View File

@ -6,7 +6,6 @@ import { EditCanvasTypeEnum, ChartEditStoreEnum, ProjectInfoEnum, ChartEditStora
import { useChartHistoryStore } from '@/store/modules/chartHistoryStore/chartHistoryStore' import { useChartHistoryStore } from '@/store/modules/chartHistoryStore/chartHistoryStore'
import { useSystemStore } from '@/store/modules/systemStore/systemStore' import { useSystemStore } from '@/store/modules/systemStore/systemStore'
import { fetchChartComponent, fetchConfigComponent, createComponent } from '@/packages/index' import { fetchChartComponent, fetchConfigComponent, createComponent } from '@/packages/index'
import { CreateComponentType } from '@/packages/index.d'
import { saveInterval } from '@/settings/designSetting' import { saveInterval } from '@/settings/designSetting'
import throttle from 'lodash/throttle' import throttle from 'lodash/throttle'
// 接口状态 // 接口状态
@ -15,6 +14,8 @@ import { ResultEnum } from '@/enums/httpEnum'
import { saveProjectApi, fetchProjectApi, uploadFile, updateProjectApi } from '@/api/path' import { saveProjectApi, fetchProjectApi, uploadFile, updateProjectApi } from '@/api/path'
// 画布枚举 // 画布枚举
import { SyncEnum } from '@/enums/editPageEnum' import { SyncEnum } from '@/enums/editPageEnum'
import { CreateComponentType, CreateComponentGroupType, ConfigType } from '@/packages/index.d'
import { PublicGroupConfigClass } from '@/packages/public/publicConfig'
// 请求处理 // 请求处理
export const useSync = () => { export const useSync = () => {
@ -25,11 +26,11 @@ export const useSync = () => {
/** /**
* * * *
* @param projectData * @param projectData
* @param isSplace * @param isReplace
* @returns * @returns
*/ */
const updateComponent = async (projectData: ChartEditStorage, isSplace = false) => { const updateComponent = async (projectData: ChartEditStorage, isReplace = false, changeId = false) => {
if (isSplace) { if (isReplace) {
// 清除列表 // 清除列表
chartEditStore.componentList = [] chartEditStore.componentList = []
// 清除历史记录 // 清除历史记录
@ -37,16 +38,20 @@ export const useSync = () => {
chartHistoryStore.clearForwardStack() chartHistoryStore.clearForwardStack()
} }
// 列表组件注册 // 列表组件注册
projectData.componentList.forEach(async (e: CreateComponentType) => { projectData.componentList.forEach(async (e: CreateComponentType | CreateComponentGroupType) => {
if (!window['$vue'].component(e.chartConfig.chartKey)) { const intComponent = (target: CreateComponentType) => {
window['$vue'].component( if (!window['$vue'].component(target.chartConfig.chartKey)) {
e.chartConfig.chartKey, window['$vue'].component(target.chartConfig.chartKey, fetchChartComponent(target.chartConfig))
fetchChartComponent(e.chartConfig) window['$vue'].component(target.chartConfig.conKey, fetchConfigComponent(target.chartConfig))
) }
window['$vue'].component( }
e.chartConfig.conKey,
fetchConfigComponent(e.chartConfig) if (e.isGroup) {
) ;(e as CreateComponentGroupType).groupList.forEach(groupItem => {
intComponent(groupItem)
})
} else {
intComponent(e as CreateComponentType)
} }
}) })
// 数据赋值 // 数据赋值
@ -54,20 +59,60 @@ export const useSync = () => {
// 组件 // 组件
if (key === ChartEditStoreEnum.COMPONENT_LIST) { if (key === ChartEditStoreEnum.COMPONENT_LIST) {
for (const comItem of projectData[key]) { for (const comItem of projectData[key]) {
// 补充 class 上的方法 // 重新创建是为了处理类种方法消失的问题
let newComponent: CreateComponentType = await createComponent( const create = async (
comItem.chartConfig _componentInstance: CreateComponentType,
) callBack?: (componentInstance: CreateComponentType) => void
chartEditStore.addComponentList( ) => {
Object.assign(newComponent, {...comItem, id: getUUID()}), // 补充 class 上的方法
false, let newComponent: CreateComponentType = await createComponent(_componentInstance.chartConfig)
true if (callBack) {
) if (changeId) {
callBack(Object.assign(newComponent, { ..._componentInstance, id: getUUID() }))
} else {
callBack(Object.assign(newComponent))
}
} else {
if (changeId) {
chartEditStore.addComponentList(
Object.assign(newComponent, { ..._componentInstance, id: getUUID() }),
false,
true
)
} else {
chartEditStore.addComponentList(Object.assign(newComponent), false, true)
}
}
}
if (comItem.isGroup) {
// 创建分组
let groupClass = new PublicGroupConfigClass()
if (changeId) {
groupClass = Object.assign(groupClass, { ...comItem, id: getUUID() })
} else {
groupClass = Object.assign(groupClass, { ...comItem })
}
// 注册子应用
const targetList: CreateComponentType[] = []
;(comItem as CreateComponentGroupType).groupList.forEach(groupItem => {
create(groupItem, e => {
targetList.push(e)
})
})
groupClass.groupList = targetList
// 分组插入到列表
chartEditStore.addComponentList(groupClass, false, true)
} else {
create(comItem as CreateComponentType)
}
} }
} else { } else {
// 非组件(顺便排除脏数据) // 非组件(顺便排除脏数据)
if (key !== 'editCanvasConfig' && key !== 'requestGlobalConfig') return if (key !== 'editCanvasConfig' && key !== 'requestGlobalConfig') return
Object.assign((chartEditStore as any)[key], projectData[key]) Object.assign(chartEditStore[key], projectData[key])
} }
} }
} }
@ -187,4 +232,4 @@ export const useSync = () => {
dataSyncUpdate, dataSyncUpdate,
intervalDataSyncUpdate intervalDataSyncUpdate
} }
} }

View File

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

View File

@ -0,0 +1,53 @@
<template>
<div
class="chart-item"
v-for="item in groupData.groupList"
:class="animationsClass(item.styles.animations)"
:key="item.id"
:style="{
...getComponentAttrStyle(item.attr, groupIndex),
...getFilterStyle(item.styles),
...getTransformStyle(item.styles)
}"
>
<component
:is="item.chartConfig.chartKey"
:chartConfig="item"
:themeSetting="themeSetting"
:themeColor="themeColor"
:style="{...getSizeStyle(item.attr)}"
></component>
</div>
</template>
<script setup lang="ts">
import { PropType } from 'vue'
import { CreateComponentGroupType } from '@/packages/index.d'
import { animationsClass, getFilterStyle, getTransformStyle } from '@/utils'
import { getSizeStyle, getComponentAttrStyle } from '../../utils'
const props = defineProps({
groupData: {
type: Object as PropType<CreateComponentGroupType>,
required: true
},
themeSetting: {
type: Object,
required: true
},
themeColor: {
type: Object,
required: true
},
groupIndex: {
type: Number,
required: true
}
})
</script>
<style lang="scss" scoped>
.chart-item {
position: absolute;
}
</style>

View File

@ -1,21 +1,32 @@
<template> <template>
<div <div
class="chart-item" class="chart-item"
:class="animationsClass(item.styles.animations)"
v-for="(item, index) in localStorageInfo.componentList" v-for="(item, index) in localStorageInfo.componentList"
:class="animationsClass(item.styles.animations)"
:key="item.id" :key="item.id"
:style="{ :style="{
...getComponentAttrStyle(item.attr, index), ...getComponentAttrStyle(item.attr, index),
...getFilterStyle(item.styles), ...getFilterStyle(item.styles),
...getTransformStyle(item.styles) ...getTransformStyle(item.styles)
}" }"
> >
<!-- 分组 -->
<preview-render-group
v-if="item.isGroup"
:groupData="(item as CreateComponentGroupType)"
:groupIndex="index"
:themeSetting="themeSetting"
:themeColor="themeColor"
></preview-render-group>
<!-- 单组件 -->
<component <component
v-else
:is="item.chartConfig.chartKey" :is="item.chartConfig.chartKey"
:chartConfig="item" :chartConfig="item"
:themeSetting="themeSetting" :themeSetting="themeSetting"
:themeColor="themeColor" :themeColor="themeColor"
:style="{...getSizeStyle(item.attr)}" :style="{ ...getSizeStyle(item.attr) }"
></component> ></component>
</div> </div>
</template> </template>
@ -23,6 +34,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { PropType, computed } from 'vue' import { PropType, computed } from 'vue'
import { ChartEditStorageType } from '../../index.d' import { ChartEditStorageType } from '../../index.d'
import { PreviewRenderGroup } from '../PreviewRenderGroup/index'
import { CreateComponentGroupType } from '@/packages/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'
@ -45,7 +58,6 @@ const themeColor = computed(() => {
const chartThemeColor = props.localStorageInfo.editCanvasConfig.chartThemeColor const chartThemeColor = props.localStorageInfo.editCanvasConfig.chartThemeColor
return chartColors[chartThemeColor] return chartColors[chartThemeColor]
}) })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -1,6 +1,6 @@
import { ref } from 'vue' import { ref } from 'vue'
import { ChartEditStorageType } from '../index.d' import { ChartEditStorageType } from '../index.d'
import { CreateComponentType } from '@/packages/index.d' import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
import { fetchChartComponent } from '@/packages/index' import { fetchChartComponent } from '@/packages/index'
export const useComInstall = (localStorageInfo: ChartEditStorageType) => { export const useComInstall = (localStorageInfo: ChartEditStorageType) => {
@ -10,12 +10,20 @@ export const useComInstall = (localStorageInfo: ChartEditStorageType) => {
const intervalTiming = setInterval(() => { const intervalTiming = setInterval(() => {
if (window['$vue']?.component) { if (window['$vue']?.component) {
clearInterval(intervalTiming) clearInterval(intervalTiming)
localStorageInfo.componentList.forEach(async (e: CreateComponentType) => {
if (!window['$vue'].component(e.chartConfig.chartKey)) { const intComponent = (target: CreateComponentType) => {
window['$vue'].component( if (!window['$vue'].component(target.chartConfig.chartKey)) {
e.chartConfig.chartKey, window['$vue'].component(target.chartConfig.chartKey, fetchChartComponent(target.chartConfig))
fetchChartComponent(e.chartConfig) }
) }
localStorageInfo.componentList.forEach(async (e: CreateComponentType | CreateComponentGroupType) => {
if (e.isGroup) {
(e as CreateComponentGroupType).groupList.forEach(groupItem => {
intComponent(groupItem)
})
} else {
intComponent(e as CreateComponentType)
} }
}) })
show.value = true show.value = true