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

This commit is contained in:
奔跑的面条
2022-08-19 10:44:44 +08:00
55 changed files with 1746 additions and 641 deletions
@@ -45,7 +45,7 @@ const dragStartHandle = (e: DragEvent, item: ConfigType) => {
componentInstall(item.chartKey, fetchChartComponent(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)
}
@@ -28,7 +28,7 @@
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { computed } from 'vue'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { EditCanvasConfigEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
import {
@@ -46,8 +46,13 @@ const chartEditStore = useChartEditStore()
// 全局颜色
const designStore = useDesignStore()
const themeColor = ref(designStore.getAppTheme)
// 颜色
const themeColor = computed(() => {
return designStore.getAppTheme
})
// 选中名称
const selectName = computed(() => {
return chartEditStore.getEditCanvasConfig.chartThemeColor
})
@@ -96,7 +96,7 @@
</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>
<!-- 主题选择和全局配置 -->
@@ -34,7 +34,7 @@
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { ref, computed } from 'vue'
import { animations } from '@/settings/animations/index'
import { CollapseItem } from '@/components/Pages/ChartItemSetting'
import { useDesignStore } from '@/store/modules/designStore/designStore'
@@ -42,12 +42,16 @@ import { useTargetData } from '../hooks/useTargetData.hook'
// 全局颜色
const designStore = useDesignStore()
const themeColor = ref(designStore.getAppTheme)
const hoverPreviewAnimate = ref('')
const { targetData } = useTargetData()
// 颜色
const themeColor = computed(() => {
return designStore.getAppTheme
})
// * 选中的动画样式
const activeIndex = (value: string) => {
const selectValue = targetData.value.styles.animations
@@ -84,7 +84,7 @@
</template>
<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 { useDesignStore } from '@/store/modules/designStore/designStore'
import { SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
@@ -108,7 +108,6 @@ const {
requestIntervalUnit: GlobalRequestIntervalUnit
} = toRefs(chartEditStore.getRequestGlobalConfig)
const designStore = useDesignStore()
const themeColor = ref(designStore.getAppTheme)
// 是否展示数据分析
const loading = ref(false)
@@ -142,6 +141,11 @@ const sendHandle = async () => {
}
}
// 颜色
const themeColor = computed(() => {
return designStore.getAppTheme
})
watchEffect(() => {
const filter = targetData.value?.filter
if (lastFilter !== filter && firstFocus) {
@@ -65,7 +65,7 @@
</template>
<script setup lang="ts">
import { ref, toRefs } from 'vue'
import { ref, toRefs, computed } from 'vue'
import { useDesignStore } from '@/store/modules/designStore/designStore'
import { SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
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 designStore = useDesignStore()
const themeColor = ref(designStore.getAppTheme)
const showTable = ref(false)
// 颜色
const themeColor = computed(() => {
return designStore.getAppTheme
})
</script>
<style lang="scss" scoped>
@@ -15,7 +15,7 @@
<template #action>
<n-space justify="space-between">
<div>
<n-text> {{ chartConfig.categoryName || rename }} </n-text>
<n-text> {{ chartConfig.categoryName }} </n-text>
<n-text> </n-text>
<n-tag type="primary" :bordered="false" style="border-radius: 5px"> {{ requestContentTypeObj[requestContentType] }} </n-tag>
</div>
@@ -37,9 +37,8 @@ const emit = defineEmits(['update:modelShow'])
const { targetData } = useTargetData()
// 解构基础配置
const { chartConfig, rename } = toRefs(targetData.value)
const { chartConfig } = toRefs(targetData.value)
const { requestContentType } = toRefs(targetData.value.request)
const requestContentTypeObj = {
[RequestContentTypeEnum.DEFAULT]: '普通请求',
[RequestContentTypeEnum.SQL]: 'SQL 请求'
@@ -3,11 +3,11 @@
<!-- 名称 -->
<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"/>
<!-- 滤镜 -->
<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>
</div>
@@ -1,11 +1,11 @@
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'
// 获取当前对象数据
export const useTargetData = () => {
const chartEditStore = useChartEditStore()
const targetData: Ref<CreateComponentType> = computed(() => {
const targetData: Ref<CreateComponentType | CreateComponentGroupType> = computed(() => {
const list = chartEditStore.getComponentList
const targetIndex = chartEditStore.fetchTargetIndex()
return list[targetIndex]
+6
View File
@@ -0,0 +1,6 @@
export enum TabsEnum {
PAGE_SETTING = 'pageSetting',
CHART_SETTING = 'chartSetting',
CHART_ANIMATION = 'chartAnimation',
CHART_DATA = 'chartData',
}
+32 -49
View File
@@ -11,21 +11,12 @@
:collapsed="collapsed"
:native-scrollbar="false"
show-trigger="bar"
@collapse="collapsedHindle"
@expand="expandHindle"
@collapse="collapsedHandle"
@expand="expandHandle"
>
<content-box
class="go-content-layers go-boderbox"
:show-top="false"
:depth="2"
>
<content-box class="go-content-layers go-boderbox" :show-top="false" :depth="2">
<!-- 页面配置 -->
<n-tabs
v-show="!selectTarget"
class="tabs-box"
size="small"
type="segment"
>
<n-tabs v-if="!selectTarget" class="tabs-box" size="small" type="segment">
<n-tab-pane
v-for="item in globalTabList"
:key="item.key"
@@ -46,14 +37,9 @@
</n-tabs>
<!-- 编辑 -->
<n-tabs
v-show="selectTarget"
class="tabs-box"
size="small"
type="segment"
>
<n-tabs v-if="selectTarget" v-model:value="tabsSelect" class="tabs-box" size="small" type="segment">
<n-tab-pane
v-for="(item) in canvasTabList"
v-for="item in selectTarget.isGroup ? chartsDefaultTabList : chartsTabList"
:key="item.key"
:name="item.key"
size="small"
@@ -80,6 +66,7 @@ import { ref, toRefs, watch, computed } from 'vue'
import { icon } from '@/plugins'
import { loadAsyncComponent } from '@/utils'
import { ContentBox } from '../ContentBox/index'
import { TabsEnum } from './index.d'
import { useChartLayoutStore } from '@/store/modules/chartLayoutStore/chartLayoutStore'
import { ChartLayoutStoreEnum } from '@/store/modules/chartLayoutStore/chartLayoutStore.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
@@ -88,35 +75,23 @@ const { getDetails } = toRefs(useChartLayoutStore())
const { setItem } = useChartLayoutStore()
const chartEditStore = useChartEditStore()
const {
ConstructIcon,
FlashIcon,
DesktopOutlineIcon,
LeafIcon
} = icon.ionicons5
const { ConstructIcon, FlashIcon, DesktopOutlineIcon, LeafIcon } = icon.ionicons5
const ContentEdit = loadAsyncComponent(() => import('../ContentEdit/index.vue'))
const CanvasPage = loadAsyncComponent(() =>
import('./components/CanvasPage/index.vue')
)
const ChartSetting = loadAsyncComponent(() =>
import('./components/ChartSetting/index.vue')
)
const ChartData = loadAsyncComponent(() =>
import('./components/ChartData/index.vue')
)
const ChartAnimation = loadAsyncComponent(() =>
import('./components/ChartAnimation/index.vue')
)
const CanvasPage = loadAsyncComponent(() => import('./components/CanvasPage/index.vue'))
const ChartSetting = loadAsyncComponent(() => 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 tabsSelect = ref<TabsEnum>(TabsEnum.CHART_SETTING)
const collapsedHindle = () => {
const collapsedHandle = () => {
collapsed.value = true
setItem(ChartLayoutStoreEnum.DETAILS, true)
}
const expandHindle = () => {
const expandHandle = () => {
collapsed.value = false
setItem(ChartLayoutStoreEnum.DETAILS, false)
}
@@ -125,42 +100,50 @@ const selectTarget = computed(() => {
const selectId = chartEditStore.getTargetChart.selectId
// 排除多个
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 => {
if (newData) {
collapsedHindle()
collapsedHandle()
} else {
expandHindle()
expandHandle()
}
})
// 页面设置
const globalTabList = [
{
key: 'pageSetting',
key: TabsEnum.PAGE_SETTING,
title: '页面配置',
icon: DesktopOutlineIcon,
render: CanvasPage
}
]
const canvasTabList = [
const chartsDefaultTabList = [
{
key: 'ChartSetting',
key: TabsEnum.CHART_SETTING,
title: '定制',
icon: ConstructIcon,
render: ChartSetting
},
{
key: 'ChartAnimation',
key: TabsEnum.CHART_ANIMATION,
title: '动画',
icon: LeafIcon,
render: ChartAnimation
},
}
]
const chartsTabList = [
...chartsDefaultTabList,
{
key: 'ChartData',
key: TabsEnum.CHART_DATA,
title: '数据',
icon: FlashIcon,
render: ChartData
@@ -11,17 +11,16 @@
</template>
<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 { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { EditCanvasTypeEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
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 cloneDeep from 'lodash/cloneDeep'
// 全局颜色
const designStore = useDesignStore()
const themeColor = ref(designStore.getAppTheme)
const chartEditStore = useChartEditStore()
const settingStore = useSettingStore()
@@ -49,6 +48,11 @@ const useComponentStyle = (attr?: Partial<{ x: number; y: number }>) => {
return componentStyle
}
// 颜色
const themeColor = computed(() => {
return designStore.getAppTheme
})
// * 吸附距离
const minDistance = computed(() => {
return settingStore.getChartAlignRange
@@ -111,7 +115,7 @@ watch(
line.select.clear()
line.sorptioned.y = false
// 循环查询所有组件数据
const componentList = chartEditStore.getComponentList.map((e: CreateComponentType) => {
const componentList = chartEditStore.getComponentList.map((e: CreateComponentType | CreateComponentGroupType) => {
return {
id: e.id,
attr: e.attr
@@ -228,30 +232,6 @@ watch(
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),
@@ -267,7 +247,6 @@ watch(
if (!val) {
line.select.clear()
line.sorptioned.y = false
chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_DRAG, true)
}
}
)
@@ -0,0 +1,3 @@
import EditGroup from './index.vue'
export { EditGroup }
@@ -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>
@@ -1,21 +1,8 @@
<template>
<div class="go-flex-items-center">
<n-popover
class="edit-history-popover"
:show="showDropdownRef"
:show-arrow="false"
size="small"
trigger="click"
placement="top-start"
>
<n-popover class="edit-history-popover" :show-arrow="false" size="small" trigger="click" placement="top-start">
<template #trigger>
<n-button
class="go-mr-1"
secondary
size="small"
:disabled="options.length === 0"
@click="handleClick"
>
<n-button class="mr-10" secondary size="small" :disabled="options.length === 0">
<span class="btn-text">历史记录</span>
</n-button>
</template>
@@ -24,16 +11,11 @@
<n-scrollbar style="max-height: 500px">
<div
class="list-item go-flex-items-center go-ellipsis-1"
v-for="item in options"
:key="item.key"
v-for="(item, index) in options"
:key="index"
:title="item.label"
>
<n-icon
class="item-icon"
size="16"
:depth="2"
:component="item.icon"
/>
<n-icon class="item-icon" size="16" :depth="2" :component="item.icon" />
<n-text depth="2">{{ item.label }}</n-text>
</div>
</n-scrollbar>
@@ -55,7 +37,6 @@
<script setup lang="ts">
import { ref, computed } from 'vue'
import { icon } from '@/plugins'
import { renderIcon } from '@/utils'
import { useChartHistoryStore } from '@/store/modules/chartHistoryStore/chartHistoryStore'
import { historyActionTypeName } from '@/store/modules/chartHistoryStore/chartHistoryDefine'
import { CreateComponentType } from '@/packages/index.d'
@@ -64,20 +45,12 @@ import reverse from 'lodash/reverse'
import {
HistoryItemType,
HistoryTargetTypeEnum,
HistoryActionTypeEnum,
HistoryActionTypeEnum
} from '@/store/modules/chartHistoryStore/chartHistoryStore.d'
const {
DesktopOutlineIcon,
PencilIcon,
TrashIcon,
CopyIcon,
LayersIcon,
DuplicateIcon,
HelpOutlineIcon,
} = icon.ionicons5
const { StackedMoveIcon } = icon.carbon
const showDropdownRef = ref(false)
const { DesktopOutlineIcon, PencilIcon, TrashIcon, CopyIcon, LayersIcon, DuplicateIcon, HelpOutlineIcon } =
icon.ionicons5
const { StackedMoveIcon, Carbon3DCursorIcon, Carbon3DSoftwareIcon } = icon.carbon
const chartHistoryStoreStore = useChartHistoryStore()
@@ -106,6 +79,10 @@ const iconHandle = (e: HistoryItemType) => {
return StackedMoveIcon
case HistoryActionTypeEnum.ADD:
return DuplicateIcon
case HistoryActionTypeEnum.GROUP:
return Carbon3DCursorIcon
case HistoryActionTypeEnum.UN_GROUP:
return Carbon3DSoftwareIcon
default:
return PencilIcon
}
@@ -116,10 +93,11 @@ const labelHandle = (e: HistoryItemType) => {
// 画布编辑
if (e.targetType === 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(() => {
@@ -127,16 +105,14 @@ const options = computed(() => {
const options = backStack.map((e: HistoryItemType) => {
return {
label: labelHandle(e),
key: e.id,
icon: iconHandle(e),
icon: iconHandle(e)
}
})
return reverse(options)
})
const handleClick = () => {
showDropdownRef.value = !showDropdownRef.value
}
return reverse(options.filter(item => {
return item.label
}))
})
</script>
<style lang="scss" scoped>
@@ -1,5 +1,5 @@
<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>
<!-- 水印 -->
<edit-watermark></edit-watermark>
@@ -7,6 +7,8 @@
<edit-rule></edit-rule>
<!-- 拖拽时的辅助线 -->
<edit-align-line></edit-align-line>
<!-- 框选时的样式框 -->
<edit-select></edit-select>
<!-- 拖拽时的遮罩 -->
<div class="go-edit-range-model" :style="rangeModelStyle"></div>
</div>
@@ -15,11 +17,13 @@
<script setup lang="ts">
import { toRefs, computed } from 'vue'
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 { EditAlignLine } from '../EditAlignLine'
import { EditWatermark } from '../EditWatermark'
import { EditRule } from '../EditRule'
import { EditSelect } from '../EditSelect'
const chartEditStore = useChartEditStore()
@@ -11,13 +11,12 @@
</template>
<script setup lang="ts">
import { ref, toRefs } from 'vue'
import { toRefs, computed } from 'vue'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { useDesignStore } from '@/store/modules/designStore/designStore'
const chartEditStore = useChartEditStore()
const designStore = useDesignStore()
const themeColor = ref(designStore.getAppTheme)
const { width, height } = toRefs(chartEditStore.getEditCanvasConfig)
@@ -34,6 +33,12 @@ const lines = {
h: [],
v: []
}
// 颜色
const themeColor = computed(() => {
return designStore.getAppTheme
})
</script>
<style>
@@ -0,0 +1,3 @@
import EditSelect from './index.vue'
export { EditSelect }
@@ -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>
@@ -2,13 +2,15 @@
<div class="go-shape-box">
<slot></slot>
<!-- 锚点 -->
<div
:class="`shape-point ${point}`"
v-for="(point, index) in select ? pointList : []"
:key="index"
:style="usePointStyle(point, index, item.attr, cursorResize)"
@mousedown="useMousePointHandle($event, point, item.attr)"
></div>
<template v-if="!hiddenPoint">
<div
:class="`shape-point ${point}`"
v-for="(point, index) in select ? pointList : []"
:key="index"
:style="usePointStyle(point, index, item.attr, cursorResize)"
@mousedown="useMousePointHandle($event, point, item.attr)"
></div>
</template>
<!-- 选中 -->
<div class="shape-modal" :style="useSizeStyle(item.attr)">
@@ -19,23 +21,25 @@
</template>
<script setup lang="ts">
import { ref, computed, PropType, toRefs } from 'vue'
import { computed, PropType } from 'vue'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
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 { useMousePointHandle } from '../../hooks/useDrag.hook'
const props = defineProps({
item: {
type: Object as PropType<CreateComponentType>,
type: Object as PropType<CreateComponentType | CreateComponentGroupType>,
required: true
},
hiddenPoint: {
type: Boolean,
required: false
}
})
// 全局颜色
const designStore = useDesignStore()
const themeColor = ref(designStore.getAppTheme)
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 themeColor = computed(() => {
return designStore.getAppTheme
})
// 计算当前选中目标
const hover = computed(() => {
return props.item.id === chartEditStore.getTargetChart.hoverId
@@ -1,9 +1,5 @@
<template>
<n-modal
v-model:show="modelShow"
:mask-closable="true"
@afterLeave="closeHandle"
>
<n-modal v-model:show="modelShow" :mask-closable="true" @afterLeave="closeHandle">
<n-table class="model-content" :bordered="false" :single-line="false">
<thead>
<tr>
@@ -24,9 +20,7 @@
<td>{{ item.label }}</td>
<td>{{ item.win }}</td>
<td>
<n-gradient-text :size="22">{{
item.mac.substr(0, 1)
}}</n-gradient-text>
<n-gradient-text :size="22">{{ item.mac.substr(0, 1) }}</n-gradient-text>
+ {{ item.mac.substr(3) }}
</td>
</tr>
@@ -44,7 +38,7 @@ const { CloseIcon } = icon.ionicons5
const emit = defineEmits(['update:modelShow'])
defineProps({
modelShow: Boolean,
modelShow: Boolean
})
// 快捷键
@@ -52,58 +46,73 @@ const shortcutKeyOptions = [
{
label: '向上移动',
win: `${WinKeyboard.CTRL.toUpperCase()} + ↑ `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + ↑ `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + ↑ `
},
{
label: '向右移动',
win: `${WinKeyboard.CTRL.toUpperCase()} + → `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + → `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + → `
},
{
label: '向下移动',
win: `${WinKeyboard.CTRL.toUpperCase()} + ↓ `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + ↓ `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + ↓ `
},
{
label: '向左移动',
win: `${WinKeyboard.CTRL.toUpperCase()} + ← `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + ← `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + ← `
},
{
label: '删除',
win: 'Delete'.toUpperCase(),
mac: `${MacKeyboard.CTRL.toUpperCase()} + Backspace `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + Backspace `
},
{
label: '复制',
win: `${WinKeyboard.CTRL.toUpperCase()} + C `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + C `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + C `
},
{
label: '剪切',
win: `${WinKeyboard.CTRL.toUpperCase()} + X `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + X `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + X `
},
{
label: '粘贴',
win: `${WinKeyboard.CTRL.toUpperCase()} + V `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + V `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + V `
},
{
label: '后退',
win: `${WinKeyboard.CTRL.toUpperCase()} + Z `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + Z `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + Z `
},
{
label: '前进',
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: '保存',
win: `${WinKeyboard.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 = () => {
emit('update:modelShow', false)
@@ -120,4 +129,4 @@ const closeHandle = () => {
padding: 5px 10px;
}
}
</style>
</style>
@@ -31,15 +31,15 @@ export const useFile = () => {
negativeText: '覆盖(不可撤回)',
negativeButtonProps: { type: 'info', ghost: false },
// 新增
onNegativeCallback: async () => {
onPositiveCallback: async () => {
fileData = JSON.parse(fileData)
await updateComponent(fileData, true)
await updateComponent(fileData, false, true)
window['$message'].success('导入成功!')
},
// 覆盖
onPositiveCallback: async () => {
onNegativeCallback: async () => {
fileData = JSON.parse(fileData)
await updateComponent(fileData)
await updateComponent(fileData, true, true)
window['$message'].success('导入成功!')
}
})
+197 -50
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 { ConfigType } from '@/packages/index.d'
import {
CreateComponentType,
PickCreateComponentType,
} from '@/packages/index.d'
import { CreateComponentType, CreateComponentGroupType, PickCreateComponentType } from '@/packages/index.d'
import { useContextMenu } from '@/views/chart/hooks/useContextMenu.hook'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { EditCanvasTypeEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
@@ -22,7 +20,7 @@ export const dragHandle = async (e: DragEvent) => {
loadingStart()
// 获取拖拽数据
const drayDataString = e!.dataTransfer!.getData(DragKeyEnum.DROG_KEY)
const drayDataString = e!.dataTransfer!.getData(DragKeyEnum.DRAG_KEY)
if (!drayDataString) {
loadingFinish()
return
@@ -35,10 +33,7 @@ export const dragHandle = async (e: DragEvent) => {
// 创建新图表组件
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, false, true)
chartEditStore.setTargetSelectChart(newComponent.id)
loadingFinish()
@@ -57,10 +52,7 @@ export const dragoverHandle = (e: DragEvent) => {
}
// * 不拦截默认行为点击
export const mousedownHandleUnStop = (
e: MouseEvent,
item?: CreateComponentType
) => {
export const mousedownHandleUnStop = (e: MouseEvent, item?: CreateComponentType | CreateComponentGroupType) => {
if (item) {
chartEditStore.setTargetSelectChart(item.id)
return
@@ -68,56 +60,213 @@ export const mousedownHandleUnStop = (
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 = () => {
// 点击事件(包含移动事件)
const mousedownHandle = (e: MouseEvent, item: CreateComponentType) => {
// * Click 事件, 松开鼠标触发
const mouseClickHandle = (e: MouseEvent, item: CreateComponentType | CreateComponentGroupType) => {
e.preventDefault()
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()
// 按下左键 + 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)
// 按下右键
if (e.buttons === MouseEventButton.RIGHT) return
const scale = chartEditStore.getEditCanvas.scale
const width = chartEditStore.getEditCanvasConfig.width
const height = chartEditStore.getEditCanvasConfig.height
const canvasWidth = chartEditStore.getEditCanvasConfig.width
const canvasHeight = chartEditStore.getEditCanvasConfig.height
// 记录图表初始位置和大小
const itemAttrX = item.attr.x
const itemAttrY = item.attr.y
const itemAttrW = item.attr.w
const itemAttrH = item.attr.h
const targetMap = new Map()
chartEditStore.getTargetChart.selectId.forEach(id => {
const index = chartEditStore.fetchTargetIndex(id)
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 startY = e.screenY
// 记录初始位置
chartEditStore.setMousePosition(startX, startY)
// 计算偏移量(处理 scale 比例问题)
// 记录初始位置
chartEditStore.setMousePosition(undefined, undefined, startX, startY)
// 移动-计算偏移量
const mousemove = throttle((moveEvent: MouseEvent) => {
chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_DRAG, true)
chartEditStore.setMousePosition(moveEvent.screenX, moveEvent.screenY)
let currX = Math.round(itemAttrX + (moveEvent.screenX - startX) / scale)
let currY = Math.round(itemAttrY + (moveEvent.screenY - startY) / scale)
// 当前偏移量,处理 scale 比例问题
let offsetX = (moveEvent.screenX - startX) / scale
let offsetY = (moveEvent.screenY - startY) / scale
// 要预留的距离
const distance = 50
// 基于左上角位置检测
currX = currX < -itemAttrW + distance ? -itemAttrW + distance : currX
currY = currY < -itemAttrH + distance ? -itemAttrH + distance : currY
chartEditStore.getTargetChart.selectId.forEach(id => {
if (!targetMap.has(id)) return
// 基于右下角位置检测
currX = currX > width - distance ? width - distance : currX
currY = currY > height - distance ? height - distance : currY
const index = chartEditStore.fetchTargetIndex(id)
// 拿到初始位置数据
const { x, y, w, h } = targetMap.get(id)
const componentInstance = chartEditStore.getComponentList[index]
item.attr.x = currX
item.attr.y = currY
}, 30)
let currX = Math.round(x + offsetX)
let currY = Math.round(y + offsetY)
// 要预留的距离
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 = () => {
chartEditStore.setMousePosition(0, 0, 0, 0)
chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_DRAG, false)
chartEditStore.setMousePosition(0, 0)
document.removeEventListener('mousemove', mousemove)
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.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.stopPropagation()
chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_DRAG, false)
chartEditStore.setTargetHoverChart(undefined)
}
return { mousedownHandle, mouseenterHandle, mouseleaveHandle }
return { mouseClickHandle, mousedownHandle, mouseenterHandle, mouseleaveHandle }
}
// * 移动锚点
export const useMousePointHandle = (
e: MouseEvent,
point: string,
attr: PickCreateComponentType<'attr'>
) => {
export const useMousePointHandle = (e: MouseEvent, point: string, attr: PickCreateComponentType<'attr'>) => {
e.stopPropagation()
e.preventDefault()
@@ -191,7 +338,7 @@ export const useMousePointHandle = (
const mouseup = () => {
chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_DRAG, false)
chartEditStore.setMousePosition(0, 0)
chartEditStore.setMousePosition(0, 0, 0, 0)
document.removeEventListener('mousemove', mousemove)
document.removeEventListener('mouseup', mouseup)
}
+67 -29
View File
@@ -15,37 +15,45 @@
<!-- 展示 -->
<edit-range>
<!-- 滤镜预览 -->
<div :style="{
<div
:style="{
...getFilterStyle(chartEditStore.getEditCanvasConfig),
...rangeStyle
}">
}"
>
<!-- 图表 -->
<edit-shape-box
v-for="(item, index) in chartEditStore.getComponentList"
:key="item.id"
:data-id="item.id"
:index="index"
:style="useComponentStyle(item.attr, index)"
:item="item"
@mousedown="mousedownHandle($event, item)"
@mouseenter="mouseenterHandle($event, item)"
@mouseleave="mouseleaveHandle($event, item)"
@contextmenu="handleContextMenu($event, item)"
>
<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>
<div v-for="(item, index) in chartEditStore.getComponentList" :key="item.id">
<!-- 分组 -->
<edit-group v-if="item.isGroup" :groupData="(item as CreateComponentGroupType)" :groupIndex="index"></edit-group>
<!-- 单组件 -->
<edit-shape-box
v-else
:data-id="item.id"
:index="index"
:style="useComponentStyle(item.attr, index)"
:item="item"
@click="mouseClickHandle($event, item)"
@mousedown="mousedownHandle($event, item)"
@mouseenter="mouseenterHandle($event, item)"
@mouseleave="mouseleaveHandle($event, item)"
@contextmenu="handleContextMenu($event, item, optionsHandle)"
>
<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>
</div>
</div>
</edit-range>
</div>
@@ -65,8 +73,11 @@
<script lang="ts" setup>
import { onMounted, computed } from 'vue'
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 { useContextMenu } from '@/views/chart/hooks/useContextMenu.hook'
import { MenuOptionsItemType } from '@/views/chart/hooks/useContextMenu.hook.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
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 { ContentBox } from '../ContentBox/index'
import { EditGroup } from './components/EditGroup'
import { EditRange } from './components/EditRange'
import { EditBottom } from './components/EditBottom'
import { EditShapeBox } from './components/EditShapeBox'
@@ -89,7 +101,33 @@ const { dataSyncFetch, intervalDataSyncUpdate } = useSync()
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(() => {
@@ -0,0 +1,3 @@
import LayersGroupListItem from './index.vue'
export { LayersGroupListItem }
@@ -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>
@@ -22,16 +22,20 @@
</template>
<script setup lang="ts">
import { ref, toRefs, computed } from 'vue'
import { toRefs, computed } from 'vue'
import { requireErrorImg } from '@/utils'
import { useDesignStore } from '@/store/modules/designStore/designStore'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
// 全局颜色
const designStore = useDesignStore()
const themeColor = ref(designStore.getAppTheme)
const chartEditStore = useChartEditStore()
// 颜色
const themeColor = computed(() => {
return designStore.getAppTheme
})
const props = defineProps({
componentData: {
type: Object,
@@ -60,7 +64,7 @@ $textSize: 10px;
position: relative;
height: $centerHeight;
width: 90%;
margin: 10px 5%;
margin: 5px 5%;
margin-bottom: 5px;
border-radius: 5px;
cursor: pointer;
+68 -20
View File
@@ -5,6 +5,7 @@
title="图层"
:depth="2"
@back="backHandle"
@mousedown="boxMousedownHandle($event)"
>
<template #icon>
<n-icon size="16" :depth="2">
@@ -16,20 +17,21 @@
<n-text class="not-layer-text">暂无图层~</n-text>
</n-space>
<!-- https://github.com/SortableJS/vue.draggable.next -->
<draggable
item-key="id"
v-model="reverseList"
ghostClass="ghost"
@change="onMoveCallback"
>
<draggable item-key="id" v-model="reverseList" ghostClass="ghost" @change="onMoveCallback">
<template #item="{ element }">
<layers-list-item
:componentData="element"
@mousedown="mousedownHandle(element)"
@mouseenter="mouseenterHandle(element)"
@mouseleave="mouseleaveHandle(element)"
@contextmenu="handleContextMenu($event, element)"
></layers-list-item>
<div class="go-content-layer-box">
<!-- 组合 -->
<layers-group-list-item v-if="element.isGroup" :componentGroupData="element"></layers-group-list-item>
<!-- 单组件 -->
<layers-list-item
v-else
:componentData="element"
@mousedown="mousedownHandle($event, element)"
@mouseenter="mouseenterHandle(element)"
@mouseleave="mouseleaveHandle(element)"
@contextmenu="handleContextMenu($event, element, optionsHandle)"
></layers-list-item>
</div>
</template>
</draggable>
</content-box>
@@ -39,27 +41,49 @@
import { computed, toRaw } from 'vue'
import Draggable from 'vuedraggable'
import cloneDeep from 'lodash/cloneDeep'
import { ContentBox } from '../ContentBox/index'
import { useChartLayoutStore } from '@/store/modules/chartLayoutStore/chartLayoutStore'
import { ChartLayoutStoreEnum } from '@/store/modules/chartLayoutStore/chartLayoutStore.d'
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 { MenuEnum } from '@/enums/editPageEnum'
import { MenuEnum, MouseEventButton, WinKeyboard, MacKeyboard } from '@/enums/editPageEnum'
import { LayersListItem } from './components/LayersListItem/index'
import { LayersGroupListItem } from './components/LayersGroupListItem/index'
import { icon } from '@/plugins'
const { LayersIcon } = icon.ionicons5
const chartLayoutStore = useChartLayoutStore()
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 list: CreateComponentType[] = cloneDeep(chartEditStore.getComponentList)
const list: Array<CreateComponentType | CreateComponentGroupType> = cloneDeep(chartEditStore.getComponentList)
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) => {
chartEditStore.setTargetSelectChart(item.id)
const mousedownHandle = (e: MouseEvent, item: CreateComponentType) => {
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)
}
// 进入事件
+1 -12
View File
@@ -1,15 +1,4 @@
// 右键枚举
export enum MenuEnum {
DELETE = 'delete',
COPY = 'copy',
CUT = 'cut',
PARSE = 'parse',
TOP = 'top',
BOTTOM = 'bottom',
UP = 'up',
DOWN = 'down',
CLEAR = 'clear',
}
import { MenuEnum } from '@/enums/editPageEnum'
export interface MenuOptionsItemType {
type?: string
+77 -41
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 { CreateComponentType } from '@/packages/index.d'
import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
import { renderIcon, loadingError } from '@/utils'
import { icon } from '@/plugins'
import { MenuOptionsItemType } from './useContextMenu.hook.d'
import { MenuEnum } from '@/enums/editPageEnum'
import cloneDeep from 'lodash/cloneDeep'
const {
CopyIcon,
CutIcon,
ClipboardOutlineIcon,
TrashIcon,
ChevronDownIcon,
ChevronUpIcon,
} = icon.ionicons5
const { UpToTopIcon, DownToBottomIcon, PaintBrushIcon } = icon.carbon
const { CopyIcon, CutIcon, ClipboardOutlineIcon, TrashIcon, ChevronDownIcon, ChevronUpIcon } = icon.ionicons5
const { UpToTopIcon, DownToBottomIcon, PaintBrushIcon, Carbon3DSoftwareIcon, Carbon3DCursorIcon } = icon.carbon
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: '复制',
key: MenuEnum.COPY,
icon: renderIcon(CopyIcon),
fnHandle: chartEditStore.setCopy,
fnHandle: chartEditStore.setCopy
},
{
label: '剪切',
key: MenuEnum.CUT,
icon: renderIcon(CutIcon),
fnHandle: chartEditStore.setCut,
fnHandle: chartEditStore.setCut
},
{
label: '粘贴',
key: MenuEnum.PARSE,
icon: renderIcon(ClipboardOutlineIcon),
fnHandle: chartEditStore.setParse,
fnHandle: chartEditStore.setParse
},
{
type: 'divider',
key: 'd1',
key: 'd1'
},
{
label: '置顶',
key: MenuEnum.TOP,
icon: renderIcon(UpToTopIcon),
fnHandle: chartEditStore.setTop,
fnHandle: chartEditStore.setTop
},
{
label: '置底',
key: MenuEnum.BOTTOM,
icon: renderIcon(DownToBottomIcon),
fnHandle: chartEditStore.setBottom,
fnHandle: chartEditStore.setBottom
},
{
label: '上移一层',
key: MenuEnum.UP,
icon: renderIcon(ChevronUpIcon),
fnHandle: chartEditStore.setUp,
fnHandle: chartEditStore.setUp
},
{
label: '下移一层',
key: MenuEnum.DOWN,
icon: renderIcon(ChevronDownIcon),
fnHandle: chartEditStore.setDown,
fnHandle: chartEditStore.setDown
},
{
type: 'divider',
key: 'd2',
key: 'd2'
},
{
label: '清空剪贴板',
key: MenuEnum.CLEAR,
icon: renderIcon(PaintBrushIcon),
fnHandle: chartEditStore.setRecordChart,
fnHandle: chartEditStore.setRecordChart
},
{
label: '删除',
key: MenuEnum.DELETE,
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[]) => {
if (!pickList) return options
return options.filter((op: MenuOptionsItemType) => {
return pickList.findIndex((e: MenuEnum) => e === op.key) !== -1
const list: MenuOptionsItemType[] = []
pickList.forEach(e => {
list.push(...options.filter(op => op.key === e))
})
return list
}
/**
@@ -120,36 +144,49 @@ const menuOptions = ref<MenuOptionsItemType[]>([])
const handleContextMenu = (
e: MouseEvent,
// 右键对象
item?: CreateComponentType,
targetInstance?: CreateComponentType | CreateComponentGroupType,
// 判断函数
optionsHandle?: Function,
// 隐藏选项列表
hideOptionsList?: MenuEnum[],
// 挑选选项列表
pickOptionsList?: MenuEnum[],
pickOptionsList?: MenuEnum[]
) => {
e.stopPropagation()
e.preventDefault()
let target = e.target
while (target instanceof SVGElement) {
target = target.parentNode
}
// 展示列表
chartEditStore.setRightMenuShow(false)
// * 设置默认选项
menuOptions.value = defaultOptions
// * 多选默认选项
if (chartEditStore.getTargetChart.selectId.length > 1) {
menuOptions.value = defaultMultiSelectOptions
} else {
// * 单选默认选项
menuOptions.value = defaultOptions
}
if (!item) {
menuOptions.value = pickOption(menuOptions.value, defaultNoItemKeys)
if (!targetInstance) {
menuOptions.value = pickOption(toRaw(menuOptions.value), defaultNoItemKeys)
}
if (hideOptionsList) {
menuOptions.value = hideOption(menuOptions.value, hideOptionsList)
menuOptions.value = hideOption([...defaultMultiSelectOptions, divider(), ...defaultOptions], hideOptionsList)
}
if (pickOptionsList) {
menuOptions.value = hideOption(menuOptions.value, pickOptionsList)
menuOptions.value = pickOption([...defaultMultiSelectOptions, divider(), ...defaultOptions], pickOptionsList)
}
if (optionsHandle) {
menuOptions.value = optionsHandle(menuOptions.value)
// 自定义函数能够拿到当前选项和所有选项
menuOptions.value = optionsHandle(
cloneDeep(toRaw(menuOptions.value)),
[...defaultMultiSelectOptions, ...defaultOptions],
targetInstance
)
}
nextTick().then(() => {
chartEditStore.setMousePosition(e.clientX, e.clientY)
@@ -163,7 +200,6 @@ const handleContextMenu = (
* @returns
*/
export const useContextMenu = () => {
// 设置默认项
menuOptions.value = defaultOptions
@@ -175,9 +211,7 @@ export const useContextMenu = () => {
// * 事件处理
const handleMenuSelect = (key: string) => {
chartEditStore.setRightMenuShow(false)
const targetItem: MenuOptionsItemType[] = menuOptions.value.filter(
(e: MenuOptionsItemType) => e.key === key
)
const targetItem: MenuOptionsItemType[] = menuOptions.value.filter((e: MenuOptionsItemType) => e.key === key)
menuOptions.value.forEach((e: MenuOptionsItemType) => {
if (e.key === key) {
@@ -189,12 +223,14 @@ export const useContextMenu = () => {
}
})
}
return {
menuOptions,
defaultOptions,
defaultMultiSelectOptions,
handleContextMenu,
onClickOutSide,
handleMenuSelect,
mousePosition: chartEditStore.getMousePosition,
mousePosition: chartEditStore.getMousePosition
}
}
+37 -16
View File
@@ -24,6 +24,8 @@ export const winKeyboardValue = {
[MenuEnum.BACK]: winCtrlMerge('z'),
[MenuEnum.FORWORD]: winCtrlMerge(winShiftMerge('z')),
[MenuEnum.SAVE]: winCtrlMerge('s'),
[MenuEnum.GROUP]: winCtrlMerge('g'),
[MenuEnum.UN_GROUP]: winCtrlMerge(winShiftMerge('g')),
}
// 这个 Ctrl 后面还是换成了 ⌘
@@ -44,6 +46,8 @@ export const macKeyboardValue = {
[MenuEnum.BACK]: macCtrlMerge('z'),
[MenuEnum.FORWORD]: macCtrlMerge(macShiftMerge('z')),
[MenuEnum.SAVE]: macCtrlMerge('s'),
[MenuEnum.GROUP]: macCtrlMerge('g'),
[MenuEnum.UN_GROUP]: macCtrlMerge(macShiftMerge('g')),
}
// Win 快捷键列表
@@ -62,6 +66,8 @@ const winKeyList: Array<string> = [
winKeyboardValue.forward,
winKeyboardValue.save,
winKeyboardValue.group,
winKeyboardValue.unGroup,
]
// Mac 快捷键列表
@@ -80,65 +86,80 @@ const macKeyList: Array<string> = [
macKeyboardValue.forward,
macKeyboardValue.save,
macKeyboardValue.group,
macKeyboardValue.unGroup,
]
// 处理键盘记录
const keyRecordHandle = () => {
document.onkeydown = throttle((e: KeyboardEvent) => {
if(window.$KeyboardActive) window.$KeyboardActive.add(e.key.toLocaleLowerCase())
else window.$KeyboardActive = new Set([e.key])
}, 200)
// 初始化清空
if(window.$KeyboardActive) window.$KeyboardActive = new Set([])
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())
}, 200)
}
}
// 初始化监听事件
export const useAddKeyboard = () => {
const throttleTime = 50
const switchHandle = (keyboardValue: typeof winKeyboardValue, e: string) => {
switch (e) {
// ct+↑
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;
// ct+→
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;
// ct+↓
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;
// ct+←
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;
// 删除 delete
case keyboardValue.delete:
keymaster(e, debounce(() => { chartEditStore.removeComponentList(); return false }, 200))
keymaster(e, debounce(() => { chartEditStore.removeComponentList(); return false }, throttleTime))
break;
// 复制 ct+v
case keyboardValue.copy:
keymaster(e, debounce(() => { chartEditStore.setCopy(); return false }, 200))
keymaster(e, debounce(() => { chartEditStore.setCopy(); return false }, throttleTime))
break;
// 剪切 ct+x
case keyboardValue.cut:
keymaster(e, debounce(() => { chartEditStore.setCut(); return false }, 200))
keymaster(e, debounce(() => { chartEditStore.setCut(); return false }, throttleTime))
break;
// 粘贴 ct+v
case keyboardValue.parse:
keymaster(e, throttle(() => { chartEditStore.setParse(); return false }, 200))
keymaster(e, throttle(() => { chartEditStore.setParse(); return false }, throttleTime))
break;
// 撤回 ct+z
case keyboardValue.back:
keymaster(e, throttle(() => { chartEditStore.setBack(); return false }, 200))
keymaster(e, throttle(() => { chartEditStore.setBack(); return false }, throttleTime))
break;
// 前进 ct+sh+z
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;
// 保存 ct+s
+71 -26
View File
@@ -6,7 +6,6 @@ import { EditCanvasTypeEnum, ChartEditStoreEnum, ProjectInfoEnum, ChartEditStora
import { useChartHistoryStore } from '@/store/modules/chartHistoryStore/chartHistoryStore'
import { useSystemStore } from '@/store/modules/systemStore/systemStore'
import { fetchChartComponent, fetchConfigComponent, createComponent } from '@/packages/index'
import { CreateComponentType } from '@/packages/index.d'
import { saveInterval } from '@/settings/designSetting'
import throttle from 'lodash/throttle'
// 接口状态
@@ -15,6 +14,8 @@ import { ResultEnum } from '@/enums/httpEnum'
import { saveProjectApi, fetchProjectApi, uploadFile, updateProjectApi } from '@/api/path'
// 画布枚举
import { SyncEnum } from '@/enums/editPageEnum'
import { CreateComponentType, CreateComponentGroupType, ConfigType } from '@/packages/index.d'
import { PublicGroupConfigClass } from '@/packages/public/publicConfig'
// 请求处理
export const useSync = () => {
@@ -25,11 +26,11 @@ export const useSync = () => {
/**
* * 组件动态注册
* @param projectData 项目数据
* @param isSplace 是否替换数据
* @returns
* @param isReplace 是否替换数据
* @returns
*/
const updateComponent = async (projectData: ChartEditStorage, isSplace = false) => {
if (isSplace) {
const updateComponent = async (projectData: ChartEditStorage, isReplace = false, changeId = false) => {
if (isReplace) {
// 清除列表
chartEditStore.componentList = []
// 清除历史记录
@@ -37,16 +38,20 @@ export const useSync = () => {
chartHistoryStore.clearForwardStack()
}
// 列表组件注册
projectData.componentList.forEach(async (e: CreateComponentType) => {
if (!window['$vue'].component(e.chartConfig.chartKey)) {
window['$vue'].component(
e.chartConfig.chartKey,
fetchChartComponent(e.chartConfig)
)
window['$vue'].component(
e.chartConfig.conKey,
fetchConfigComponent(e.chartConfig)
)
projectData.componentList.forEach(async (e: CreateComponentType | CreateComponentGroupType) => {
const intComponent = (target: CreateComponentType) => {
if (!window['$vue'].component(target.chartConfig.chartKey)) {
window['$vue'].component(target.chartConfig.chartKey, fetchChartComponent(target.chartConfig))
window['$vue'].component(target.chartConfig.conKey, fetchConfigComponent(target.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) {
for (const comItem of projectData[key]) {
// 补充 class 上的方法
let newComponent: CreateComponentType = await createComponent(
comItem.chartConfig
)
chartEditStore.addComponentList(
Object.assign(newComponent, {...comItem, id: getUUID()}),
false,
true
)
// 重新创建是为了处理类种方法消失的问题
const create = async (
_componentInstance: CreateComponentType,
callBack?: (componentInstance: CreateComponentType) => void
) => {
// 补充 class 上的方法
let newComponent: CreateComponentType = await createComponent(_componentInstance.chartConfig)
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 {
// 非组件(顺便排除脏数据)
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,
intervalDataSyncUpdate
}
}
}