feat: 新增复制粘贴功能

This commit is contained in:
MTrun 2022-02-03 22:54:31 +08:00
parent 41711b174f
commit 47a7ce9d6e
22 changed files with 519 additions and 129 deletions

View File

@ -5,9 +5,9 @@ import { ConfigType, CreateComponentType } from '@/packages/index.d'
import omit from 'lodash/omit' import omit from 'lodash/omit'
export default class Config implements CreateComponentType { export default class Config implements CreateComponentType {
public id: string = getUUID() public id = getUUID()
public key: string = BarCommonConfig.key public key = BarCommonConfig.key
public rename = undefined
public chartData: Exclude<ConfigType, ['node']> = omit(BarCommonConfig, ['node']) public chartData: Exclude<ConfigType, ['node']> = omit(BarCommonConfig, ['node'])
public attr = { x: 0, y: 0, w: 500, h: 300 } public attr = { x: 0, y: 0, w: 500, h: 300 }

View File

@ -16,6 +16,7 @@ export type ConfigType = {
export interface CreateComponentType { export interface CreateComponentType {
id: string id: string
key: string key: string
rename?: string
attr: { x: number; y: number; w: number; h: number } attr: { x: number; y: number; w: number; h: number }
chartData: ConfigType chartData: ConfigType
option: object option: object

View File

@ -39,7 +39,9 @@ import {
Home as HomeIcon, Home as HomeIcon,
Card as CardIcon, Card as CardIcon,
ChevronUp as ChevronUpIcon, ChevronUp as ChevronUpIcon,
ChevronDown as ChevronDownIcon ChevronDown as ChevronDownIcon,
TimeOutline as TimeOutlineIcon,
ClipboardOutline as ClipboardOutlineIcon
} from '@vicons/ionicons5' } from '@vicons/ionicons5'
import { import {
@ -53,10 +55,11 @@ import {
DicomOverlay as DicomOverlayIcon, DicomOverlay as DicomOverlayIcon,
UpToTop as UpToTopIcon, UpToTop as UpToTopIcon,
DownToBottom as DownToBottomIcon, DownToBottom as DownToBottomIcon,
StackedMove as StackedMoveIcon
} from '@vicons/carbon' } from '@vicons/carbon'
const ionicons5 = { const ionicons5 = {
// 帮助 // 帮助(问号)
HelpOutlineIcon, HelpOutlineIcon,
// 添加 // 添加
DuplicateIcon, DuplicateIcon,
@ -137,6 +140,10 @@ const ionicons5 = {
ChevronUpIcon, ChevronUpIcon,
// 下移 // 下移
ChevronDownIcon, ChevronDownIcon,
// 时间
TimeOutlineIcon,
// 剪贴板
ClipboardOutlineIcon
} }
const carbon = { const carbon = {
@ -159,7 +166,9 @@ const carbon = {
// 置顶 // 置顶
UpToTopIcon, UpToTopIcon,
// 置底 // 置底
DownToBottomIcon DownToBottomIcon,
// 移动
StackedMoveIcon
} }
// https://www.xicons.org/#/ 还有很多 // https://www.xicons.org/#/ 还有很多

View File

@ -60,6 +60,7 @@ export enum ChartEditStoreEnum {
RIGHT_MENU_SHOW = 'rightMenuShow', RIGHT_MENU_SHOW = 'rightMenuShow',
MOUSE_POSITION = 'mousePosition', MOUSE_POSITION = 'mousePosition',
TARGET_CHART = 'targetChart', TARGET_CHART = 'targetChart',
RECORD_CHARTS = 'recordCharts',
COMPONENT_LIST = 'componentList' COMPONENT_LIST = 'componentList'
} }
@ -69,5 +70,6 @@ export interface chartEditStoreType {
[ChartEditStoreEnum.RIGHT_MENU_SHOW]: boolean [ChartEditStoreEnum.RIGHT_MENU_SHOW]: boolean
[ChartEditStoreEnum.MOUSE_POSITION]: MousePositionType [ChartEditStoreEnum.MOUSE_POSITION]: MousePositionType
[ChartEditStoreEnum.TARGET_CHART]: TargetChartType [ChartEditStoreEnum.TARGET_CHART]: TargetChartType
[ChartEditStoreEnum.RECORD_CHARTS]?: CreateComponentType | CreateComponentType[]
[ChartEditStoreEnum.COMPONENT_LIST]: CreateComponentType[] [ChartEditStoreEnum.COMPONENT_LIST]: CreateComponentType[]
} }

View File

@ -1,7 +1,8 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import debounce from 'lodash/debounce' import { getUUID, loadingStart, loadingFinish, loadingError } from '@/utils'
import { loadingStart, loadingFinish, loadingError } from '@/utils'
import { CreateComponentType } from '@/packages/index.d' import { CreateComponentType } from '@/packages/index.d'
import debounce from 'lodash/debounce'
import cloneDeep from 'lodash/cloneDeep'
import { import {
chartEditStoreType, chartEditStoreType,
EditCanvasType, EditCanvasType,
@ -9,6 +10,12 @@ import {
TargetChartType TargetChartType
} from './chartEditStore.d' } from './chartEditStore.d'
// 记录记录
import { useChartHistoryStoreStore } from '@/store/modules/chartHistoryStore/chartHistoryStore'
import { HistoryActionTypeEnum } from '@/store/modules/chartHistoryStore/chartHistoryStore.d'
const chartHistoryStoreStore = useChartHistoryStoreStore()
// 编辑区域内容 // 编辑区域内容
export const useChartEditStoreStore = defineStore({ export const useChartEditStoreStore = defineStore({
id: 'useChartEditStoreStore', id: 'useChartEditStoreStore',
@ -24,7 +31,7 @@ export const useChartEditStoreStore = defineStore({
height: 1080, height: 1080,
// 偏移量 // 偏移量
offset: 20, offset: 20,
// 系统控制缩放 // 系统控制缩放
scale: 1, scale: 1,
// 用户控制的缩放 // 用户控制的缩放
userScale: 1, userScale: 1,
@ -45,6 +52,8 @@ export const useChartEditStoreStore = defineStore({
hoverId: undefined, hoverId: undefined,
selectId: undefined selectId: undefined
}, },
// 记录临时数据(复制等)
recordCharts: undefined,
// 图表数组 // 图表数组
componentList: [] componentList: []
}), }),
@ -61,6 +70,9 @@ export const useChartEditStoreStore = defineStore({
getTargetChart():TargetChartType { getTargetChart():TargetChartType {
return this.targetChart return this.targetChart
}, },
getRecordCharts(): CreateComponentType | CreateComponentType[] | undefined {
return this.recordCharts
},
getComponentList(): CreateComponentType[] { getComponentList(): CreateComponentType[] {
return this.componentList return this.componentList
} }
@ -82,6 +94,10 @@ export const useChartEditStoreStore = defineStore({
setTargetSelectChart(selectId?:TargetChartType["selectId"]) { setTargetSelectChart(selectId?:TargetChartType["selectId"]) {
this.targetChart.selectId = selectId this.targetChart.selectId = selectId
}, },
// * 设置记录数据
setRecordCharts(item: CreateComponentType | CreateComponentType[] | undefined) {
this.recordCharts = cloneDeep(item)
},
// * 找到目标 id 数据下标位置 // * 找到目标 id 数据下标位置
fetchTargetIndex(): number { fetchTargetIndex(): number {
const index = this.componentList.findIndex(e => e.id === this.getTargetChart.selectId) const index = this.componentList.findIndex(e => e.id === this.getTargetChart.selectId)
@ -91,8 +107,17 @@ export const useChartEditStoreStore = defineStore({
} }
return index return index
}, },
// * 新增组件列表 /**
addComponentList(chartData: CreateComponentType, isEnd = false): void { * *
* @param chartData
* @param isEnd
* @param isHistory
* @returns
*/
addComponentList(chartData: CreateComponentType, isEnd = false, isHistory = false): void {
if(isHistory) {
chartHistoryStoreStore.createAddHistory(chartData)
}
if(isEnd) { if(isEnd) {
this.componentList.unshift(chartData) this.componentList.unshift(chartData)
return return
@ -105,6 +130,7 @@ export const useChartEditStoreStore = defineStore({
loadingStart() loadingStart()
const index = this.fetchTargetIndex() const index = this.fetchTargetIndex()
if (index !== -1) { if (index !== -1) {
chartHistoryStoreStore.createDeleteHistory(this.getComponentList[index])
this.componentList.splice(index, 1) this.componentList.splice(index, 1)
loadingFinish() loadingFinish()
return return
@ -118,6 +144,16 @@ export const useChartEditStoreStore = defineStore({
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>(
key: T,
value: any
): void {
const dom = this.getEditCanvas.editContentDom
if (dom) {
dom.style[key] = value
}
},
// * 移动组件列表位置到两端 // * 移动组件列表位置到两端
setBothEnds(isEnd = false): void { setBothEnds(isEnd = false): void {
try { try {
@ -136,6 +172,7 @@ export const useChartEditStoreStore = defineStore({
return return
} }
// 插入两端 // 插入两端
chartHistoryStoreStore.createLaryerHistory(this.getComponentList[index])
this.addComponentList(this.getComponentList[index], isEnd) this.addComponentList(this.getComponentList[index], isEnd)
this.getComponentList.splice(isEnd ? index + 1: index, 1) this.getComponentList.splice(isEnd ? index + 1: index, 1)
loadingFinish() loadingFinish()
@ -153,16 +190,6 @@ export const useChartEditStoreStore = defineStore({
setBottom(): void { setBottom(): void {
this.setBothEnds(true) this.setBothEnds(true)
}, },
// * 设置页面样式属性
setPageStyle<T extends keyof CSSStyleDeclaration>(
key: T,
value: any
): void {
const dom = this.getEditCanvas.editContentDom
if (dom) {
dom.style[key] = value
}
},
// * 互换图表位置 // * 互换图表位置
wrap(isDown = false) { wrap(isDown = false) {
try { try {
@ -186,8 +213,10 @@ export const useChartEditStoreStore = defineStore({
const targetItem = this.getComponentList[index] const targetItem = this.getComponentList[index]
const swapItem = this.getComponentList[swapIndex] const swapItem = this.getComponentList[swapIndex]
chartHistoryStoreStore.createLaryerHistory(targetItem)
this.updateComponentList(index, swapItem) this.updateComponentList(index, swapItem)
this.updateComponentList(swapIndex, targetItem) this.updateComponentList(swapIndex, targetItem)
loadingFinish() loadingFinish()
return return
} }
@ -203,6 +232,57 @@ export const useChartEditStoreStore = defineStore({
setDown() { setDown() {
this.wrap(true) this.wrap(true)
}, },
// * 复制
setCopy() {
try {
loadingStart()
const index:number = this.fetchTargetIndex()
if (index !== -1) {
this.setRecordCharts(this.getComponentList[index])
window['$message'].success('复制成功!')
loadingFinish()
}
} catch(value) {
loadingError()
}
},
// * 粘贴
setParse() {
try {
loadingStart()
const recordCharts = this.getRecordCharts
if (recordCharts === undefined) {
loadingFinish()
return
}
const parseHandle = (e: CreateComponentType) => {
e = cloneDeep(e)
// 生成新 id
e.id = getUUID()
// 偏移位置
e.attr.x = e.attr.x + 30
e.attr.y = e.attr.y + 30
return e
}
if (Array.isArray(recordCharts)) {
recordCharts.forEach((e: CreateComponentType) => {
console.log(parseHandle(e));
this.addComponentList(parseHandle(e), undefined, true)
})
loadingFinish()
return
}
this.addComponentList(parseHandle(recordCharts), undefined, true)
loadingFinish()
} catch(value) {
loadingError()
}
},
// * 设置鼠标位置
setMousePosition(x: number, y: number): void {
this.mousePosition.x = x
this.mousePosition.y = y
},
// * 设置页面变换时候的 Class // * 设置页面变换时候的 Class
setPageSizeClass(): void { setPageSizeClass(): void {
const dom = this.getEditCanvas.editContentDom const dom = this.getEditCanvas.editContentDom
@ -218,11 +298,6 @@ export const useChartEditStoreStore = defineStore({
this.setPageStyle('height', `${this.getEditCanvas.height}px`) this.setPageStyle('height', `${this.getEditCanvas.height}px`)
this.setPageStyle('width', `${this.getEditCanvas.width}px`) this.setPageStyle('width', `${this.getEditCanvas.width}px`)
}, },
// * 设置鼠标位置
setMousePosition(x: number, y: number): void {
this.mousePosition.x = x
this.mousePosition.y = y
},
// * 计算缩放 // * 计算缩放
computedScale() { computedScale() {
if (this.getEditCanvas.editLayoutDom) { if (this.getEditCanvas.editLayoutDom) {

View File

@ -0,0 +1,16 @@
import {
HistoryTargetTypeEnum,
HistoryActionTypeEnum
} from './chartHistoryStore.d'
export const historyActionTypeName = {
[HistoryActionTypeEnum.ADD]: '新增图表',
[HistoryActionTypeEnum.DELETE]: '删除图表',
[HistoryActionTypeEnum.UPDATE]: '修改属性',
[HistoryActionTypeEnum.MOVE]: '移动图表',
[HistoryActionTypeEnum.PASTE]: '粘贴图表',
[HistoryActionTypeEnum.LARYER]: '改变层级',
[HistoryActionTypeEnum.SELECT_HISTORY]: '选择记录',
[HistoryTargetTypeEnum.CANVAS]: '画布初始化'
}

View File

@ -1,28 +1,56 @@
import { CreateComponentType } from '@/packages/index.d' import { CreateComponentType } from '@/packages/index.d'
import { ChartLayoutType } from '@/store/modules/chartLayoutStore/chartLayoutStore.d'
// 操作类型枚举 // 操作类型枚举
export enum HistoryTypeEnum { export enum HistoryActionTypeEnum {
// 新增
ADD = 'add', ADD = 'add',
// 删除
DELETE = 'delete', DELETE = 'delete',
// 更新(位置,属性)
UPDATE = 'update',
// 移动
MOVE = 'move', MOVE = 'move',
// 粘贴
PASTE = 'paste',
// 改变层级
LARYER = 'laryer',
// 选择历史记录
SELECT_HISTORY = 'selectHistory' SELECT_HISTORY = 'selectHistory'
} }
// 对象类型
export enum HistoryTargetTypeEnum {
CANVAS = 'canvas',
CHART = 'chart'
}
// 历史栈 // 历史栈
export enum HistoryStackEnum { export enum HistoryStackEnum {
BACK_STACK= 'backStack', BACK_STACK = 'backStack',
FORWARD_STACK= 'forwardStack', FORWARD_STACK = 'forwardStack'
}
// 历史记录项
export enum HistoryStackItemEnum {
ID = 'id',
TARGET_TYPE = 'targetType',
ACTION_TYPE = 'actionType',
HISTORY_DATA = 'historyData'
} }
// 历史记录项类型 // 历史记录项类型
export interface HistoryItemType extends CreateComponentType { export interface HistoryItemType {
historyType: HistoryTypeEnum [HistoryStackItemEnum.ID]: string
[HistoryStackItemEnum.TARGET_TYPE]: HistoryTargetTypeEnum
[HistoryStackItemEnum.ACTION_TYPE]: HistoryActionTypeEnum
[HistoryStackItemEnum.HISTORY_DATA]: CreateComponentType | ChartLayoutType
} }
// 历史 Store 类型 // 历史 Store 类型
export interface ChartHistoryStoreType { export interface ChartHistoryStoreType {
// 后退栈 // 后退栈
[HistoryStackEnum.BACK_STACK]: Array<HistoryItemType>, [HistoryStackEnum.BACK_STACK]: Array<HistoryItemType>
// 前进栈 // 前进栈
[HistoryStackEnum.FORWARD_STACK]: Array<HistoryItemType>, [HistoryStackEnum.FORWARD_STACK]: Array<HistoryItemType>
} }

View File

@ -0,0 +1,105 @@
import { defineStore } from 'pinia'
import { CreateComponentType } from '@/packages/index.d'
import { ChartLayoutType } from '@/store/modules/chartLayoutStore/chartLayoutStore.d'
import { useChartLayoutStore } from '@/store/modules/chartLayoutStore/chartLayoutStore'
import {
HistoryStackEnum,
HistoryStackItemEnum,
HistoryActionTypeEnum,
HistoryTargetTypeEnum,
HistoryItemType,
ChartHistoryStoreType
} from './chartHistoryStore.d'
export const useChartHistoryStoreStore = defineStore({
id: 'useChartHistoryStore',
state: (): ChartHistoryStoreType => ({
// 后退栈(记录栈)
backStack: [],
// 前进栈
forwardStack: []
}),
getters: {
getBackStack(): Array<HistoryItemType> {
return this.backStack
},
getForwardStack(): Array<HistoryItemType> {
return this.forwardStack
}
},
actions: {
/**
* *
* @param item
* @param actionType
* @param targetType
*/
createStackItem(item: CreateComponentType | ChartLayoutType, actionType: HistoryActionTypeEnum, targetType: HistoryTargetTypeEnum = HistoryTargetTypeEnum.CHART) {
this.pushBackStackItem({
[HistoryStackItemEnum.ID]: new Date().getTime().toString(),
[HistoryStackItemEnum.HISTORY_DATA]: item,
[HistoryStackItemEnum.ACTION_TYPE]: actionType,
[HistoryStackItemEnum.TARGET_TYPE]: targetType,
})
},
// * 画布初始化
canvasInit(canvas: ChartLayoutType) {
this.createStackItem(canvas, HistoryActionTypeEnum.ADD, HistoryTargetTypeEnum.CANVAS)
},
// * 推入记录栈
pushBackStackItem(item: HistoryItemType | Array<HistoryItemType>): void {
if (item instanceof Array) this.backStack = [...this.backStack, ...item]
else this.backStack.push(item)
},
// * 推入前进栈
pushForwardStack(item: HistoryItemType | Array<HistoryItemType>): void {
if (item instanceof Array)
this.forwardStack = [...this.forwardStack, ...item]
else this.forwardStack.push(item)
},
// * 移出记录栈
popBackStackItem( index?: number ): HistoryItemType[] | HistoryItemType | undefined {
const length = this.backStack.length
if (index && length >= index) {
return this.backStack.splice(-index)
}
if (this.backStack.length > 0) {
return this.backStack.pop()
}
},
// * 移出前进栈
popForwardStack( index?: number ): HistoryItemType[] | HistoryItemType | undefined {
const length = this.forwardStack.length
if (index && length >= index) {
return this.forwardStack.splice(-index)
}
if (this.forwardStack.length > 0) {
return this.forwardStack.pop()
}
},
// * 新增组件记录
createAddHistory(item: CreateComponentType) {
this.createStackItem(item, HistoryActionTypeEnum.ADD, HistoryTargetTypeEnum.CHART)
},
// * 更新属性记录(大小、图表属性)
createUpdateHistory(item: CreateComponentType) {
this.createStackItem(item, HistoryActionTypeEnum.UPDATE, HistoryTargetTypeEnum.CHART)
},
// * 删除组件记录
createDeleteHistory(item: CreateComponentType) {
this.createStackItem(item, HistoryActionTypeEnum.DELETE, HistoryTargetTypeEnum.CHART)
},
// * 移动组件记录
createMoveHistory(item: CreateComponentType) {
this.createStackItem(item, HistoryActionTypeEnum.MOVE, HistoryTargetTypeEnum.CHART)
},
// * 改变层级组件记录
createLaryerHistory(item: CreateComponentType) {
this.createStackItem(item, HistoryActionTypeEnum.LARYER, HistoryTargetTypeEnum.CHART)
},
// * 粘贴组件记录
createPasteHistory(item: CreateComponentType) {
this.createStackItem(item, HistoryActionTypeEnum.PASTE, HistoryTargetTypeEnum.CHART)
},
}
})

View File

@ -1,62 +0,0 @@
import { defineStore } from 'pinia'
import {
HistoryStackEnum,
HistoryItemType,
ChartHistoryStoreType
} from './chartHistoryStore.d'
import { setLocalStorage, getLocalStorage } from '@/utils'
import { StorageEnum } from '@/enums/storageEnum'
export const useChartHistoryStoreStore = defineStore({
id: 'useChartHistoryStore',
state: (): ChartHistoryStoreType => ({
// 后退栈(记录栈)
backStack: [],
// 前进栈
forwardStack: []
}),
getters: {
getBackStack(): Array<HistoryItemType> {
return this.backStack
},
getForwardStack(): Array<HistoryItemType> {
return this.forwardStack
}
},
actions: {
// * 推入记录栈
addBackStackItem(item: HistoryItemType | Array<HistoryItemType>): void {
if(item instanceof Array) this.backStack = [...this.backStack, ...item]
else this.backStack.push(item)
},
// * 推入前进栈
addForwardStack(item: HistoryItemType | Array<HistoryItemType>): void {
if(item instanceof Array) this.forwardStack = [...this.forwardStack, ...item]
else this.forwardStack.push(item)
},
// * 移出记录栈
popBackStackItem(
index?: number
): HistoryItemType[] | HistoryItemType | undefined {
const length = this.backStack.length
if (index && length >= index) {
return this.backStack.splice(-index)
}
if (this.backStack.length > 0) {
return this.backStack.pop()
}
},
// * 移出前进栈
popForwardStack(
index?: number
): HistoryItemType[] | HistoryItemType | undefined {
const length = this.forwardStack.length
if (index && length >= index) {
return this.forwardStack.splice(-index)
}
if (this.forwardStack.length > 0) {
return this.forwardStack.pop()
}
}
}
})

View File

@ -8,9 +8,7 @@ const chartEditStore = useChartEditStoreStore()
const { GO_CHART_LAYOUT_STORE } = StorageEnum const { GO_CHART_LAYOUT_STORE } = StorageEnum
const storageChartLayout: ChartLayoutType = getLocalStorage( const storageChartLayout: ChartLayoutType = getLocalStorage( GO_CHART_LAYOUT_STORE)
GO_CHART_LAYOUT_STORE
)
// 编辑区域布局和静态设置 // 编辑区域布局和静态设置
export const useChartLayoutStore = defineStore({ export const useChartLayoutStore = defineStore({

View File

@ -18,6 +18,12 @@
text-align: center; text-align: center;
} }
.go-flex-items-center {
display: flex;
align-items: center;
text-align: center;
}
.go-flex-no-wrap { .go-flex-no-wrap {
flex-wrap: nowrap !important; flex-wrap: nowrap !important;
} }
@ -108,4 +114,4 @@
.go-px-0 { .go-px-0 {
@extend .go-pl-0; @extend .go-pl-0;
@extend .go-pr-0; @extend .go-pr-0;
} }

View File

@ -3,7 +3,6 @@ import { ResultEnum } from '@/enums/httpEnum'
import { ErrorPageNameMap, PageEnum } from '@/enums/pageEnum' import { ErrorPageNameMap, PageEnum } from '@/enums/pageEnum'
import router from '@/router' import router from '@/router'
import { docPath, giteeSourceCodePath } from '@/settings/pathConst' import { docPath, giteeSourceCodePath } from '@/settings/pathConst'
import { goDialog } from '@/utils/plugin'
/** /**
* * * *
@ -139,6 +138,6 @@ export const fetchRouteParams = () => {
* * * *
* @param confirm * @param confirm
*/ */
export const goHome = <T extends typeof goDialog>(confirm: boolean, params: T) => { export const goHome = () => {
routerTurnByName(PageEnum.BASE_HOME_NAME) routerTurnByName(PageEnum.BASE_HOME_NAME)
} }

View File

@ -1,7 +1,7 @@
import { h } from 'vue' import { h } from 'vue'
import { NIcon } from 'naive-ui' import { NIcon } from 'naive-ui'
import screenfull from 'screenfull' import screenfull from 'screenfull'
import debounce from 'lodash/debounce' import throttle from 'lodash/throttle'
/** /**
* * ID * * ID
@ -91,12 +91,18 @@ export const setDomAttribute = <K extends keyof CSSStyleDeclaration, V extends C
HTMLElement.style[key] = value HTMLElement.style[key] = value
} }
} }
/**
* * mac
* @returns boolean
*/
export const isMac = () => {
return /macintosh|mac os x/i.test(navigator.userAgent)
}
/** /**
* * * *
*/ */
export const goAddEventListener = <K extends keyof WindowEventMap>( export const addEventListener = <K extends keyof WindowEventMap>(
target: EventTarget, target: HTMLElement | Document,
type: K, type: K,
listener: any, listener: any,
options?: boolean | AddEventListenerOptions | undefined options?: boolean | AddEventListenerOptions | undefined
@ -104,7 +110,7 @@ export const goAddEventListener = <K extends keyof WindowEventMap>(
if (!target) return if (!target) return
target.addEventListener( target.addEventListener(
type, type,
debounce(listener, 300, { throttle(listener, 300, {
leading: true, leading: true,
trailing: false trailing: false
}), }),
@ -115,10 +121,10 @@ export const goAddEventListener = <K extends keyof WindowEventMap>(
/** /**
* * * *
*/ */
export const goRemoveEventListener = <K extends keyof WindowEventMap>( export const removeEventListener = <K extends keyof WindowEventMap>(
target: EventTarget, target: HTMLElement | Document,
type: K, type: K,
listener: EventListenerOrEventListenerObject listener: any
) => { ) => {
if (!target) return if (!target) return
target.removeEventListener(type, listener) target.removeEventListener(type, listener)

View File

@ -1,19 +1,17 @@
<template> <template>
<div class="go-edit-bottom"> <div class="go-edit-bottom">
<n-space> <History />
<n-text>
滤镜设置 <n-space class="bottom-ri">
</n-text>
<!-- 快捷键提示 --> <!-- 快捷键提示 -->
<n-popselect :options="shortcutKeyOptions" size="medium"> <n-popselect :options="shortcutKeyOptions" size="medium">
<n-button class="scale-btn" secondary size="mini"> <n-button class="scale-btn" quaternary size="mini">
<n-icon class="lock-icon" size="18" :depth="3"> <n-icon class="lock-icon" size="18" :depth="2">
<DicomOverlayIcon /> <DicomOverlayIcon />
</n-icon> </n-icon>
</n-button> </n-button>
</n-popselect> </n-popselect>
</n-space>
<n-space class="bottom-ri">
<!-- 缩放比例 --> <!-- 缩放比例 -->
<n-select <n-select
:disabled="lockScale" :disabled="lockScale"
@ -62,13 +60,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref, toRefs, watchEffect } from 'vue' import { reactive, ref, toRefs, watchEffect } from 'vue'
import { icon } from '@/plugins' import { icon } from '@/plugins'
import { History } from '../History/index'
import { useDesignStore } from '@/store/modules/designStore/designStore'
const { LockClosedOutlineIcon, LockOpenOutlineIcon } = icon.ionicons5 const { LockClosedOutlineIcon, LockOpenOutlineIcon } = icon.ionicons5
const { DicomOverlayIcon } = icon.carbon const { DicomOverlayIcon } = icon.carbon
import { import {
getChartEditStore, getChartEditStore,
getChartEditStoreEnum getChartEditStoreEnum
} from '../../hooks/useStore.hook' } from '../../hooks/useStore.hook'
import { useDesignStore } from '@/store/modules/designStore/designStore'
// //
const designStore = useDesignStore() const designStore = useDesignStore()
@ -141,9 +140,25 @@ const shortcutKeyOptions = [
value: '1' value: '1'
}, },
{ {
label: 'Ctrl + C 复制', label: 'Delete 删除',
value: '2' value: '2'
} },
{
label: 'Ctrl + C 复制',
value: '3'
},
{
label: 'Ctrl + X 剪切',
value: '4'
},
{
label: 'Ctrl + Z 后退',
value: '5'
},
{
label: 'Ctrl + Shift + Z 前进',
value: '6'
},
] ]
// scale // scale
@ -157,7 +172,7 @@ watchEffect(() => {
<style lang="scss" scoped> <style lang="scss" scoped>
@include go(edit-bottom) { @include go(edit-bottom) {
width: 100%; width: 100%;
padding: 0 20px; padding: 0 10px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;

View File

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

View File

@ -0,0 +1,129 @@
<template>
<div class="go-edit-history go-flex-items-center">
<n-dropdown
@select="handleSelect"
:show="showDropdownRef"
:options="options"
scrollable
size="small"
placement="top-start"
style="max-height: 100vh; overflow-y: auto;"
>
<n-button
class="mr-10"
secondary
size="small"
:disabled="options.length === 0"
@click="handleClick"
>
<span class="btn-text">历史记录</span>
<!-- <n-icon class="lock-icon" size="18" :depth="2">
<TimeOutlineIcon />
</n-icon> -->
</n-button>
</n-dropdown>
<n-tooltip trigger="hover">
<template #trigger>
<n-icon size="21" :depth="3">
<HelpOutlineIcon />
</n-icon>
</template>
<span>最多只保留 20 条记录</span>
</n-tooltip>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { icon } from '@/plugins'
import { renderIcon } from '@/utils'
import { useChartHistoryStoreStore } from '@/store/modules/chartHistoryStore/chartHistoryStore'
import { historyActionTypeName } from '@/store/modules/chartHistoryStore/chartHistoryDefine'
import { CreateComponentType } from '@/packages/index.d'
import {
HistoryItemType,
HistoryTargetTypeEnum,
HistoryActionTypeEnum
} from '@/store/modules/chartHistoryStore/chartHistoryStore.d'
const {
TimeOutlineIcon,
DesktopOutlineIcon,
PencilIcon,
TrashIcon,
CopyIcon,
LayersIcon,
DuplicateIcon,
HelpOutlineIcon
} = icon.ionicons5
const { StackedMoveIcon } = icon.carbon
const showDropdownRef = ref(false)
const chartHistoryStoreStore = useChartHistoryStoreStore()
//
const iconHandle = (e: HistoryItemType) => {
//
if (e.targetType === HistoryTargetTypeEnum.CANVAS) {
return renderIcon(DesktopOutlineIcon)
}
switch (e.actionType) {
case HistoryActionTypeEnum.UPDATE:
return renderIcon(PencilIcon)
case HistoryActionTypeEnum.DELETE:
return renderIcon(TrashIcon)
case HistoryActionTypeEnum.PASTE:
return renderIcon(CopyIcon)
case HistoryActionTypeEnum.LARYER:
return renderIcon(LayersIcon)
case HistoryActionTypeEnum.MOVE:
return renderIcon(StackedMoveIcon)
case HistoryActionTypeEnum.ADD:
return renderIcon(DuplicateIcon)
default:
return renderIcon(PencilIcon)
}
}
//
const labelHandle = (e: HistoryItemType) => {
//
if (e.targetType === HistoryTargetTypeEnum.CANVAS) {
return historyActionTypeName[HistoryTargetTypeEnum.CANVAS]
}
return `${historyActionTypeName[e.actionType]} - ${
(e.historyData as CreateComponentType).chartData.title
}`
}
const options = computed(() => {
const backStack: HistoryItemType[] = chartHistoryStoreStore.getBackStack
const options = backStack.map((e: HistoryItemType) => {
return {
label: labelHandle(e),
key: e.id,
icon: iconHandle(e)
}
})
return options
})
const handleClick = () => {
showDropdownRef.value = !showDropdownRef.value
}
const handleSelect = (key: string) => {}
</script>
<style lang="scss" scoped>
@include go(edit-history) {
max-height: 50vh;
.mr-10 {
margin-right: 10px;
}
.btn-text {
font-size: 12px;
margin-right: 3px;
}
}
</style>

View File

@ -29,7 +29,7 @@ export const handleDrop = async (e: DragEvent) => {
let newComponent:CreateComponentType = await createComponent(dropData) let newComponent:CreateComponentType = await createComponent(dropData)
newComponent.setPosition(e.offsetX - newComponent.attr.w / 2, e.offsetY - newComponent.attr.h / 2) newComponent.setPosition(e.offsetX - newComponent.attr.w / 2, e.offsetY - newComponent.attr.h / 2)
chartEditStore.addComponentList(newComponent) chartEditStore.addComponentList(newComponent, false, true)
chartEditStore.setTargetSelectChart(newComponent.id) chartEditStore.setTargetSelectChart(newComponent.id)
loadingFinish() loadingFinish()
} catch (error) { } catch (error) {

View File

@ -0,0 +1,36 @@
import { isMac, addEventListener, removeEventListener } from '@/utils'
import { getChartEditStore } from './useStore.hook'
const chartEditStore = getChartEditStore()
const KeyboardHandle = (e: KeyboardEvent) => {
const ismacRes = isMac()
// 暂不支持mac因为我没有😤👻
if(ismacRes) return
const key = e.key.toLowerCase()
if (key === 'delete') {
chartEditStore.removeComponentList()
return
}
if (e.ctrlKey) {
switch (key) {
// 复制
case 'c': chartEditStore.setCopy()
break;
// 粘贴
case 'v': chartEditStore.setParse()
break;
}
e.preventDefault()
}
}
export const useAddKeyboard = () => {
addEventListener(document, 'keyup', KeyboardHandle)
}
export const useRemoveKeyboard = () => {
removeEventListener(document, 'keyup', KeyboardHandle)
}

View File

@ -50,6 +50,7 @@ import { EditBottom } from './components/EditBottom'
import { ShapeBox } from './components/ShapeBox/index' import { ShapeBox } from './components/ShapeBox/index'
import { useLayout } from './hooks/useLayout.hook' import { useLayout } from './hooks/useLayout.hook'
import { useAddKeyboard, useRemoveKeyboard } from './hooks/useKeyboard.hook'
import { handleDrop, handleDragOver, useMouseHandle } from './hooks/useDrop.hook' import { handleDrop, handleDragOver, useMouseHandle } from './hooks/useDrop.hook'
import { useContextMenu } from '@/views/chart/hooks/useContextMenu.hook' import { useContextMenu } from '@/views/chart/hooks/useContextMenu.hook'
import { getChartEditStore } from './hooks/useStore.hook' import { getChartEditStore } from './hooks/useStore.hook'
@ -66,6 +67,12 @@ useLayout()
// //
const editRangeRef = ref<HTMLElement | null>(null) const editRangeRef = ref<HTMLElement | null>(null)
const { mouseenterHandle, mouseleaveHandle, mousedownHandle } = useMouseHandle() const { mouseenterHandle, mouseleaveHandle, mousedownHandle } = useMouseHandle()
//
onMounted(() => {
useAddKeyboard()
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -27,6 +27,7 @@ import { icon } from '@/plugins'
const { LayersIcon, BarChartIcon, PrismIcon, HomeIcon } = icon.ionicons5 const { LayersIcon, BarChartIcon, PrismIcon, HomeIcon } = icon.ionicons5
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 { useRemoveKeyboard } from '../ContentEdit/hooks/useKeyboard.hook'
const { setItem } = useChartLayoutStore() const { setItem } = useChartLayoutStore()
const { getLayers, getCharts, getDetails } = toRefs(useChartLayoutStore()) const { getLayers, getCharts, getDetails } = toRefs(useChartLayoutStore())
@ -76,7 +77,10 @@ const goHomeHandle = () => {
goDialog({ goDialog({
message: '返回将不会保存任何操作', message: '返回将不会保存任何操作',
isMaskClosable: true, isMaskClosable: true,
onPositiveCallback: goHome onPositiveCallback: () => {
goHome()
useRemoveKeyboard()
}
}) })
} }
</script> </script>

View File

@ -4,7 +4,7 @@ import { CreateComponentType } from '@/packages/index.d'
import { renderIcon, loadingError } from '@/utils' import { renderIcon, loadingError } from '@/utils'
import { icon } from '@/plugins' import { icon } from '@/plugins'
const { CopyIcon, TrashIcon, ChevronDownIcon, ChevronUpIcon } = icon.ionicons5 const { CopyIcon, ClipboardOutlineIcon, TrashIcon, ChevronDownIcon, ChevronUpIcon } = icon.ionicons5
const { UpToTopIcon, DownToBottomIcon } = icon.carbon const { UpToTopIcon, DownToBottomIcon } = icon.carbon
const chartEditStore = useChartEditStoreStore() const chartEditStore = useChartEditStoreStore()
@ -12,6 +12,7 @@ const chartEditStore = useChartEditStoreStore()
enum MenuEnum { enum MenuEnum {
DELETE = 'delete', DELETE = 'delete',
COPY = 'copy', COPY = 'copy',
PARSE = 'parse',
TOP = 'top', TOP = 'top',
BOTTOM = 'bottom', BOTTOM = 'bottom',
UP = 'up', UP = 'up',
@ -32,7 +33,13 @@ const defaultOptions: MenuOptionsItemType[] = [
label: '复制', label: '复制',
key: MenuEnum.COPY, key: MenuEnum.COPY,
icon: renderIcon(CopyIcon), icon: renderIcon(CopyIcon),
fnHandle: () => {} fnHandle: chartEditStore.setCopy
},
{
label: '粘贴',
key: MenuEnum.PARSE,
icon: renderIcon(ClipboardOutlineIcon),
fnHandle: chartEditStore.setParse
}, },
{ {
type: 'divider', type: 'divider',

View File

@ -39,6 +39,14 @@ import { loadAsyncComponent } from '@/utils'
import { HeaderPro } from '@/layout/components/HeaderPro' import { HeaderPro } from '@/layout/components/HeaderPro'
import { useContextMenu } from './hooks/useContextMenu.hook' import { useContextMenu } from './hooks/useContextMenu.hook'
import { useChartEditStoreStore } from '@/store/modules/chartEditStore/chartEditStore' import { useChartEditStoreStore } from '@/store/modules/chartEditStore/chartEditStore'
import { useChartLayoutStore } from '@/store/modules/chartLayoutStore/chartLayoutStore'
import { useChartHistoryStoreStore } from '@/store/modules/chartHistoryStore/chartHistoryStore'
const chartLayoutStore = useChartLayoutStore()
const chartHistoryStoreStore = useChartHistoryStoreStore()
//
chartHistoryStoreStore.canvasInit(chartLayoutStore)
const chartEditStore = useChartEditStoreStore() const chartEditStore = useChartEditStoreStore()
const HeaderLeftBtn = loadAsyncComponent(() => const HeaderLeftBtn = loadAsyncComponent(() =>
@ -47,9 +55,7 @@ const HeaderLeftBtn = loadAsyncComponent(() =>
const HeaderRightBtn = loadAsyncComponent(() => const HeaderRightBtn = loadAsyncComponent(() =>
import('./HeaderRightBtn/index.vue') import('./HeaderRightBtn/index.vue')
) )
const HeaderTitle = loadAsyncComponent(() => const HeaderTitle = loadAsyncComponent(() => import('./HeaderTitle/index.vue'))
import('./HeaderTitle/index.vue')
)
const ContentLayers = loadAsyncComponent(() => const ContentLayers = loadAsyncComponent(() =>
import('./ContentLayers/index.vue') import('./ContentLayers/index.vue')
) )