feat: 合并1.1.1

This commit is contained in:
奔跑的面条
2022-10-08 21:04:41 +08:00
73 changed files with 3154 additions and 6430 deletions
+4 -11
View File
@@ -10,14 +10,9 @@
<slot name="icon"></slot>
</div>
</n-space>
<n-space>
<n-space align="center" style="gap: 4px">
<slot name="top-right"></slot>
<n-icon
v-show="backIcon"
size="20"
class="go-cursor-pointer"
@click="backHandle"
>
<n-icon v-show="backIcon" size="20" class="go-cursor-pointer go-d-block" @click="backHandle">
<chevron-back-outline-icon></chevron-back-outline-icon>
</n-icon>
</n-space>
@@ -151,7 +146,7 @@ $topOrBottomHeight: 40px;
border-bottom: 1px solid;
@include fetch-border-color('background-color1');
}
.content {
height: calc(100vh - #{$--header-height});
overflow: hidden;
@@ -165,9 +160,7 @@ $topOrBottomHeight: 40px;
height: calc(100vh - #{$--header-height} - #{$topOrBottomHeight});
}
.content-height-show-both {
height: calc(
100vh - #{$--header-height} - #{$topOrBottomHeight} - #{$topOrBottomHeight}
);
height: calc(100vh - #{$--header-height} - #{$topOrBottomHeight} - #{$topOrBottomHeight});
}
}
</style>
@@ -30,17 +30,11 @@
:onBeforeUpload="beforeUploadHandle"
>
<n-upload-dragger>
<img
v-if="canvasConfig.backgroundImage"
class="upload-show"
:src="canvasConfig.backgroundImage"
alt="背景"
/>
<img v-if="canvasConfig.backgroundImage" class="upload-show" :src="canvasConfig.backgroundImage" alt="背景" />
<div class="upload-img" v-show="!canvasConfig.backgroundImage">
<img src="@/assets/images/canvas/noImage.png" />
<n-text class="upload-desc" depth="3">
背景图需小于 {{ backgroundImageSize }}M 格式为 png/jpg/gif
的文件
背景图需小于 {{ backgroundImageSize }}M 格式为 png/jpg/gif 的文件
</n-text>
</div>
</n-upload-dragger>
@@ -48,43 +42,52 @@
</n-card>
<n-space vertical :size="12">
<n-space>
<n-text>背景色</n-text>
<n-color-picker
style="width: 326px;"
:showPreview="true"
:swatches="swatchesColors"
v-model:value="canvasConfig.background"
></n-color-picker>
<n-text>背景</n-text>
<div class="picker-height">
<n-color-picker
v-if="!switchSelectColorLoading"
size="small"
style="width: 250px"
v-model:value="canvasConfig.background"
:showPreview="true"
:swatches="swatchesColors"
></n-color-picker>
</div>
</n-space>
<n-space>
<n-text>颜色应用</n-text>
<n-switch
<n-text>应用类型</n-text>
<n-select
size="small"
v-model:value="canvasConfig.selectColor"
:loading="switchSelectColorLoading"
:round="false"
style="width: 250px"
v-model:value="selectColorValue"
:disabled="!canvasConfig.backgroundImage"
:onUpdate="switchSelectColorHandle"
></n-switch>
:options="selectColorOptions"
@update:value="selectColorValueHandle"
/>
</n-space>
<n-space>
<n-text>背景控制</n-text>
<n-button size="small" :disabled="!canvasConfig.backgroundImage" @click="clearImage">清除背景图</n-button>
<n-button size="small" :disabled="!canvasConfig.background" @click="clearColor">清除颜色</n-button>
<n-button class="clear-btn" size="small" :disabled="!canvasConfig.backgroundImage" @click="clearImage">
清除背景
</n-button>
<n-button class="clear-btn" size="small" :disabled="!canvasConfig.background" @click="clearColor">
清除颜色
</n-button>
</n-space>
<n-space>
<n-text>预览方式</n-text>
<n-button-group>
<n-button
ghost
<n-button
v-for="item in previewTypeList"
:key="item.key"
:type="canvasConfig.previewScaleType === item.key ? 'primary' : 'tertiary'"
ghost
size="small"
@click="selectPreviewType(item.key)">
@click="selectPreviewType(item.key)"
>
<n-tooltip :show-arrow="false" trigger="hover">
<template #trigger>
<n-icon size="18">
<n-icon class="select-preview-icon" size="18">
<component :is="item.icon"></component>
</n-icon>
</template>
@@ -97,7 +100,7 @@
<!-- 滤镜 -->
<styles-setting :isCanvas="true" :chartStyles="canvasConfig"></styles-setting>
<n-divider style="margin: 10px 0;"></n-divider>
<n-divider style="margin: 10px 0"></n-divider>
<!-- 主题选择和全局配置 -->
<n-tabs class="tabs-box" size="small" type="segment">
@@ -123,7 +126,7 @@
</template>
<script setup lang="ts">
import { ref, nextTick } from 'vue'
import { ref, nextTick, watch } from 'vue'
import { backgroundImageSize } from '@/settings/designSetting'
import { FileTypeEnum } from '@/enums/fileTypeEnum'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
@@ -147,23 +150,25 @@ const editCanvas = chartEditStore.getEditCanvas
const uploadFileListRef = ref()
const switchSelectColorLoading = ref(false)
const selectColorValue = ref(0)
const ChartThemeColor = loadAsyncComponent(() =>
import('./components/ChartThemeColor/index.vue')
)
const ChartThemeColor = loadAsyncComponent(() => import('./components/ChartThemeColor/index.vue'))
// 北京默认展示颜色列表
const swatchesColors = [
'#232324',
'#2a2a2b',
'#313132',
'#373739',
'#757575',
'#e0e0e0',
'#eeeeee',
'#fafafa'
// 默认应用类型
const selectColorOptions = [
{
label: '应用颜色',
value: 0
},
{
label: '应用背景',
value: 1
}
]
// 默认展示颜色列表
const swatchesColors = ['#232324', '#2a2a2b', '#313132', '#373739', '#757575', '#e0e0e0', '#eeeeee', '#fafafa']
const globalTabList = [
{
key: 'ChartTheme',
@@ -197,9 +202,19 @@ const previewTypeList = [
title: '铺满',
icon: FitToScreenIcon,
desc: '强行拉伸画面,填充所有视图'
},
}
]
watch(
() => canvasConfig.selectColor,
newValue => {
selectColorValue.value = newValue ? 0 : 1
},
{
immediate: true
}
)
// 画布尺寸规则
const validator = (x: number) => x > 50
@@ -216,9 +231,7 @@ const beforeUploadHandle = async ({ file }) => {
const size = file.file.size
if (size > 1024 * 1024 * backgroundImageSize) {
window['$message'].warning(
`图片超出 ${backgroundImageSize}M 限制,请重新上传!`
)
window['$message'].warning(`图片超出 ${backgroundImageSize}M 限制,请重新上传!`)
return false
}
if (type !== FileTypeEnum.PNG && type !== FileTypeEnum.JPEG && type !== FileTypeEnum.GIF) {
@@ -228,38 +241,32 @@ const beforeUploadHandle = async ({ file }) => {
return true
}
// 应用颜色
const selectColorValueHandle = (value: number) => {
canvasConfig.selectColor = value == 0
}
// 清除背景
const clearImage = () => {
chartEditStore.setEditCanvasConfig(
EditCanvasConfigEnum.BACKGROUND_IMAGE,
undefined
)
chartEditStore.setEditCanvasConfig(
EditCanvasConfigEnum.SELECT_COLOR,
true
)
chartEditStore.setEditCanvasConfig(EditCanvasConfigEnum.BACKGROUND_IMAGE, undefined)
chartEditStore.setEditCanvasConfig(EditCanvasConfigEnum.SELECT_COLOR, true)
}
// 清除颜色
const clearColor = () => {
chartEditStore.setEditCanvasConfig(
EditCanvasConfigEnum.BACKGROUND,
undefined
)
if (canvasConfig.backgroundImage) {
chartEditStore.setEditCanvasConfig(
EditCanvasConfigEnum.SELECT_COLOR,
false
)
}
}
// 启用/关闭 颜色
// 启用/关闭 颜色(强制更新)
const switchSelectColorHandle = () => {
switchSelectColorLoading.value = true
setTimeout(() => {
switchSelectColorLoading.value = false
}, 1000)
})
}
// 清除颜色
const clearColor = () => {
chartEditStore.setEditCanvasConfig(EditCanvasConfigEnum.BACKGROUND, undefined)
if (canvasConfig.backgroundImage) {
chartEditStore.setEditCanvasConfig(EditCanvasConfigEnum.SELECT_COLOR, false)
}
switchSelectColorHandle()
}
// 自定义上传操作
@@ -306,8 +313,8 @@ const selectPreviewType = (key: PreviewScaleEnum) => {
</script>
<style lang="scss" scoped>
$updloadWidth: 326px;
$updloadHeight: 193px;
$uploadWidth: 326px;
$uploadHeight: 193px;
@include go(canvas-setting) {
padding-top: 20px;
.upload-box {
@@ -320,12 +327,12 @@ $updloadHeight: 193px;
}
.n-upload-dragger {
padding: 5px;
width: $updloadWidth;
width: $uploadWidth;
}
}
.upload-show {
width: -webkit-fill-available;
height: $updloadHeight;
height: $uploadHeight;
border-radius: 5px;
}
.upload-img {
@@ -343,6 +350,17 @@ $updloadHeight: 193px;
.icon-position {
padding-top: 2px;
}
.picker-height {
min-height: 35px;
}
.clear-btn {
padding-left: 2.25em;
padding-right: 2.25em;
}
.select-preview-icon {
padding-right: .68em;
padding-left: .68em;
}
.tabs-box {
margin-top: 20px;
}
@@ -41,7 +41,7 @@
@before-upload="beforeUpload"
>
<n-space>
<n-button v-if="!ajax" class="sourceBtn-item">
<n-button v-if="!ajax" class="sourceBtn-item" :disabled="noData">
<template #icon>
<n-icon>
<document-add-icon />
@@ -52,7 +52,7 @@
</n-space>
</n-upload>
<div>
<n-button class="sourceBtn-item" @click="download">
<n-button class="sourceBtn-item" :disabled="noData" @click="download">
<template #icon>
<n-icon>
<document-download-icon />
@@ -111,6 +111,7 @@ const { DocumentAddIcon, DocumentDownloadIcon } = icon.carbon
const source = ref()
const dimensions = ref()
const dimensionsAndSource = ref()
const noData = ref(false)
const { uploadFileListRef, customRequest, beforeUpload, download } = useFile(targetData)
@@ -180,6 +181,7 @@ watch(
dimensionsAndSource.value = null
source.value = newData
} else {
noData.value = true
source.value = '此组件无数据源'
}
if (isArray(newData)) {
@@ -5,7 +5,7 @@
<!-- 尺寸 -->
<size-setting :isGroup="targetData.isGroup" :chartAttr="targetData.attr"></size-setting>
<!-- 位置 -->
<position-setting :chartAttr="targetData.attr" :canvasConfig="chartEditStore.getEditCanvasConfig"/>
<position-setting :chartAttr="targetData.attr" :canvasConfig="chartEditStore.getEditCanvasConfig" />
<!-- 滤镜 -->
<styles-setting :isGroup="targetData.isGroup" :chartStyles="targetData.styles"></styles-setting>
<!-- 自定义配置项 -->
@@ -17,7 +17,6 @@
import { NameSetting, PositionSetting, SizeSetting, StylesSetting } from '@/components/Pages/ChartItemSetting'
import { useTargetData } from '../hooks/useTargetData.hook'
const { targetData, chartEditStore } = useTargetData()
</script>
<style lang="scss" scoped>
@@ -11,7 +11,8 @@
...useComponentStyle(groupData.attr, groupIndex),
...useSizeStyle(groupData.attr),
...getFilterStyle(groupData.styles),
...getTransformStyle(groupData.styles)
...getTransformStyle(groupData.styles),
...getBlendModeStyle(groupData.styles) as any
}"
@click="mouseClickHandle($event, groupData)"
@mousedown="mousedownHandle($event, groupData)"
@@ -55,7 +56,7 @@ 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 { animationsClass, getFilterStyle, getTransformStyle, getBlendModeStyle } from '@/utils'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { useContextMenu, divider } from '@/views/chart/hooks/useContextMenu.hook'
import { useMouseHandle } from '../../hooks/useDrag.hook'
@@ -85,26 +86,32 @@ const optionsHandle = (
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
return allList.filter(i => menulist.includes(i.key as MenuEnum))
}
// 多选处理
if (chartEditStore.getTargetChart.selectId.length > 1) {
return filter(moreMenuEnums)
return filter([MenuEnum.GROUP, MenuEnum.DELETE])
} else {
return [...filter(singleMenuEnums), divider(), ...targetList]
const statusMenuEnums: MenuEnum[] = []
if (targetInstance.status.lock) {
statusMenuEnums.push(MenuEnum.LOCK)
} else {
statusMenuEnums.push(MenuEnum.UNLOCK)
}
if (targetInstance.status.hide) {
statusMenuEnums.push(MenuEnum.HIDE)
} else {
statusMenuEnums.push(MenuEnum.SHOW)
}
// 单选
const singleMenuEnums = [MenuEnum.UN_GROUP]
return [
...filter(singleMenuEnums),
divider(),
...targetList.filter(i => !statusMenuEnums.includes(i.key as MenuEnum))
]
}
}
@@ -48,8 +48,19 @@ import {
HistoryActionTypeEnum
} from '@/store/modules/chartHistoryStore/chartHistoryStore.d'
const { DesktopOutlineIcon, PencilIcon, TrashIcon, CopyIcon, LayersIcon, DuplicateIcon, HelpOutlineIcon } =
icon.ionicons5
const {
DesktopOutlineIcon,
PencilIcon,
TrashIcon,
CopyIcon,
LayersIcon,
DuplicateIcon,
HelpOutlineIcon,
LockClosedOutlineIcon,
LockOpenOutlineIcon,
EyeOffOutlineIcon,
EyeOutlineIcon
} = icon.ionicons5
const { StackedMoveIcon, Carbon3DCursorIcon, Carbon3DSoftwareIcon } = icon.carbon
const chartHistoryStoreStore = useChartHistoryStore()
@@ -83,6 +94,14 @@ const iconHandle = (e: HistoryItemType) => {
return Carbon3DCursorIcon
case HistoryActionTypeEnum.UN_GROUP:
return Carbon3DSoftwareIcon
case HistoryActionTypeEnum.LOCK:
return LockClosedOutlineIcon
case HistoryActionTypeEnum.UNLOCK:
return LockOpenOutlineIcon
case HistoryActionTypeEnum.HIDE:
return EyeOffOutlineIcon
case HistoryActionTypeEnum.SHOW:
return EyeOutlineIcon
default:
return PencilIcon
}
@@ -109,9 +128,7 @@ const options = computed(() => {
}
})
return reverse(options.filter(item => {
return item.label
}))
return reverse(options.filter(item => item.label))
})
</script>
@@ -1,5 +1,5 @@
<template>
<div class="go-shape-box">
<div class="go-shape-box" :class="{ lock, hide }">
<slot></slot>
<!-- 锚点 -->
<template v-if="!hiddenPoint">
@@ -55,14 +55,26 @@ const themeColor = computed(() => {
// 计算当前选中目标
const hover = computed(() => {
if (props.item.status.lock) return false
return props.item.id === chartEditStore.getTargetChart.hoverId
})
// 兼容多值场景
const select = computed(() => {
const id = props.item.id
if (props.item.status.lock) return false
return chartEditStore.getTargetChart.selectId.find((e: string) => e === id)
})
// 锁定
const lock = computed(() => {
return props.item.status.lock
})
// 隐藏
const hide = computed(() => {
return props.item.status.hide
})
</script>
<style lang="scss" scoped>
@@ -70,6 +82,14 @@ const select = computed(() => {
position: absolute;
cursor: move;
&.lock {
cursor: default !important;
}
&.hide {
display: none;
}
/* 锚点 */
.shape-point {
z-index: 1;
@@ -63,6 +63,26 @@ const shortcutKeyOptions = [
win: `${WinKeyboard.CTRL.toUpperCase()} + ← `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + ← `
},
{
label: '锁定',
win: `${WinKeyboard.CTRL.toUpperCase()} + L `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + L `
},
{
label: '解锁',
win: `${WinKeyboard.CTRL.toUpperCase()} + ${WinKeyboard.SHIFT.toUpperCase()}+ L `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + ${MacKeyboard.SHIFT.toUpperCase()} + L `
},
{
label: '展示',
win: `${WinKeyboard.CTRL.toUpperCase()} + H `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + H `
},
{
label: '隐藏',
win: `${WinKeyboard.CTRL.toUpperCase()} + ${WinKeyboard.SHIFT.toUpperCase()} + H `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + ${MacKeyboard.SHIFT.toUpperCase()} + H `
},
{
label: '删除',
win: 'Delete'.toUpperCase(),
@@ -179,7 +179,8 @@ $asideBottom: 70px;
}
@include deep() {
.n-button__icon {
margin-right: 4px;
margin-right: 0;
margin-left: 0;
margin-bottom: 12px;
}
}
@@ -140,7 +140,9 @@ export const mousedownBoxSelect = (e: MouseEvent, item?: CreateComponentType | C
targetAttr.x1 - selectAttr.x1 >= 0 &&
targetAttr.y1 - selectAttr.y1 >= 0 &&
targetAttr.x2 - selectAttr.x2 <= 0 &&
targetAttr.y2 - selectAttr.y2 <= 0
targetAttr.y2 - selectAttr.y2 <= 0 &&
!item.status.lock &&
!item.status.hide
) {
isSelect = true
chartEditStore.setTargetSelectChart(item.id, true)
@@ -166,6 +168,7 @@ export const useMouseHandle = () => {
const mouseClickHandle = (e: MouseEvent, item: CreateComponentType | CreateComponentGroupType) => {
e.preventDefault()
e.stopPropagation()
if (item.status.lock) return
// 若此时按下了 CTRL, 表示多选
if (
window.$KeyboardActive?.has(WinKeyboard.CTRL_SOURCE_KEY) ||
@@ -185,6 +188,7 @@ export const useMouseHandle = () => {
const mousedownHandle = (e: MouseEvent, item: CreateComponentType | CreateComponentGroupType) => {
e.preventDefault()
e.stopPropagation()
if (item.status.lock) return
onClickOutSide()
// 按下左键 + CTRL
if (
+18 -17
View File
@@ -37,7 +37,10 @@
v-else
:data-id="item.id"
:index="index"
:style="useComponentStyle(item.attr, index)"
:style="{
...useComponentStyle(item.attr, index),
...getBlendModeStyle(item.styles) as any
}"
:item="item"
@click="mouseClickHandle($event, item)"
@mousedown="mousedownHandle($event, item)"
@@ -81,7 +84,7 @@ 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 { animationsClass, getFilterStyle, getTransformStyle, getBlendModeStyle } 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'
@@ -116,24 +119,22 @@ const optionsHandle = (
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 allList.filter(i => [MenuEnum.GROUP, MenuEnum.DELETE].includes(i.key as MenuEnum))
}
return singleMenuEnums
const statusMenuEnums: MenuEnum[] = []
if (targetInstance.status.lock) {
statusMenuEnums.push(MenuEnum.LOCK)
} else {
statusMenuEnums.push(MenuEnum.UNLOCK)
}
if (targetInstance.status.hide) {
statusMenuEnums.push(MenuEnum.HIDE)
} else {
statusMenuEnums.push(MenuEnum.SHOW)
}
return targetList.filter(i => !statusMenuEnums.includes(i.key as MenuEnum))
}
// 主题色
@@ -2,7 +2,7 @@
<div class="go-content-layers-group-list-item">
<div
class="root-item-content"
:class="{ hover: hover, select: select }"
:class="{ hover, select, 'list-mini': selectText }"
@click="clickHandle($event)"
@mousedown="groupMousedownHandle($event)"
@mouseenter="mouseenterHandle(componentGroupData)"
@@ -18,11 +18,12 @@
<folder-icon></folder-icon>
</template>
</n-icon>
<n-ellipsis>
<n-ellipsis style="margin-right: auto">
<n-text class="go-ml-2 list-text" :depth="2">
{{ componentGroupData.chartConfig.title }}
</n-text>
</n-ellipsis>
<layers-status :isGroup="false" :hover="hover" :status="status"></layers-status>
</div>
<div :class="{ 'select-modal': select }"></div>
</div>
@@ -31,6 +32,8 @@
v-for="element in componentGroupData.groupList"
:key="element.id"
:componentData="element"
:layer-mode="layerMode"
:isGroup="true"
@mousedown="mousedownHandle($event, element, componentGroupData.id)"
@mouseenter="mouseenterHandle(element)"
@mouseleave="mouseleaveHandle(element)"
@@ -48,15 +51,20 @@ 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 { LayerModeEnum } from '@/store/modules/chartLayoutStore/chartLayoutStore.d'
import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
import { LayersListItem } from '../LayersListItem'
import throttle from 'lodash/throttle'
import { LayersStatus } from '../LayersStatus/index'
import { icon } from '@/plugins'
const props = defineProps({
componentGroupData: {
type: Object as PropType<CreateComponentGroupType>,
required: true
},
layerMode: {
type: String as PropType<LayerModeEnum>,
default: LayerModeEnum.THUMBNAIL
}
})
@@ -77,6 +85,27 @@ const themeColor = computed(() => {
return designStore.getAppTheme
})
// 是否选中文本
const selectText = computed(() => {
return props.layerMode === LayerModeEnum.TEXT
})
// 计算当前选中目标
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 status = computed(() => {
return props.componentGroupData.status
})
// 右键
const optionsHandle = (
targetList: MenuOptionsItemType[],
@@ -84,20 +113,29 @@ const optionsHandle = (
targetInstance: CreateComponentType
) => {
const filter = (menulist: MenuEnum[]) => {
const list: MenuOptionsItemType[] = []
allList.forEach(item => {
if (menulist.includes(item.key as MenuEnum)) {
list.push(item)
}
})
return list
return allList.filter(i => menulist.includes(i.key as MenuEnum))
}
// 多选处理
if (chartEditStore.getTargetChart.selectId.length > 1) {
return filter([MenuEnum.GROUP])
} else {
return [...filter([MenuEnum.UN_GROUP]), divider(), ...targetList]
const statusMenuEnums: MenuEnum[] = []
if (targetInstance.status.lock) {
statusMenuEnums.push(MenuEnum.LOCK)
} else {
statusMenuEnums.push(MenuEnum.UNLOCK)
}
if (targetInstance.status.hide) {
statusMenuEnums.push(MenuEnum.HIDE)
} else {
statusMenuEnums.push(MenuEnum.SHOW)
}
return [
...filter([MenuEnum.UN_GROUP]),
divider(),
...targetList.filter(i => !statusMenuEnums.includes(i.key as MenuEnum))
]
}
}
@@ -114,17 +152,6 @@ const clickHandle = (e: MouseEvent) => {
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()
@@ -148,7 +175,11 @@ const groupMousedownHandle = (e: MouseEvent) => {
}
// 公共点击事件
const mousedownHandle = (e: MouseEvent, componentInstance: CreateComponentType | CreateComponentGroupType, id?: string) => {
const mousedownHandle = (
e: MouseEvent,
componentInstance: CreateComponentType | CreateComponentGroupType,
id?: string
) => {
e.preventDefault()
e.stopPropagation()
@@ -169,6 +200,7 @@ const mouseleaveHandle = (componentInstance: CreateComponentType | CreateCompone
<style lang="scss" scoped>
$centerHeight: 52px;
$centerMiniHeight: 28px;
$textSize: 10px;
@include go(content-layers-group-list-item) {
@@ -177,6 +209,20 @@ $textSize: 10px;
margin: 10px 5%;
margin-bottom: 5px;
@extend .go-transition-quick;
@include deep() {
.go-content-layers-list-item {
margin-right: 0 !important;
width: 95% !important;
}
}
&:hover {
@include deep() {
.icon-item {
opacity: 1;
}
}
}
.root-item-content {
height: $centerHeight;
@@ -196,6 +242,17 @@ $textSize: 10px;
border: 1px solid v-bind('themeColor') !important;
}
}
// mini样式
&.list-mini {
height: $centerMiniHeight;
.item-content {
height: calc(#{$centerMiniHeight} - 10px) !important;
}
.select-modal {
height: calc(#{$centerMiniHeight} + 2px) !important;
}
}
}
.select-modal,
.item-content {
@@ -220,5 +277,9 @@ $textSize: 10px;
padding-left: 6px;
font-size: $textSize;
}
.list-status-icon {
margin-left: 3px;
}
}
</style>
@@ -1,5 +1,5 @@
<template>
<div class="go-content-layers-list-item" :class="{ hover: hover, select: select }">
<div class="go-content-layers-list-item" :class="{ hover, select, 'list-mini': selectText }">
<div class="go-flex-center item-content">
<n-image
class="list-img"
@@ -8,54 +8,77 @@
:src="image"
:fallback-src="requireErrorImg()"
></n-image>
<n-ellipsis>
<n-ellipsis style="margin-right: auto">
<n-text class="list-text" :depth="2">
{{ props.componentData.chartConfig.title }}
</n-text>
</n-ellipsis>
<layers-status :isGroup="isGroup" :hover="hover" :status="status"></layers-status>
</div>
<div :class="{ 'select-modal': select }"></div>
</div>
</template>
<script setup lang="ts">
import { toRefs, computed } from 'vue'
import { computed, PropType } from 'vue'
import { requireErrorImg } from '@/utils'
import { useDesignStore } from '@/store/modules/designStore/designStore'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
// 全局颜色
const designStore = useDesignStore()
const chartEditStore = useChartEditStore()
// 颜色
const themeColor = computed(() => {
return designStore.getAppTheme
})
import { LayerModeEnum } from '@/store/modules/chartLayoutStore/chartLayoutStore.d'
import { LayersStatus } from '../LayersStatus/index'
const props = defineProps({
componentData: {
type: Object,
required: true
},
isGroup: {
type: Boolean,
default: false
},
layerMode: {
type: String as PropType<LayerModeEnum>,
default: LayerModeEnum.THUMBNAIL
}
})
// 全局颜色
const designStore = useDesignStore()
const chartEditStore = useChartEditStore()
// eslint-disable-next-line vue/no-setup-props-destructure
const { image } = props.componentData.chartConfig
// 颜色
const themeColor = computed(() => {
return designStore.getAppTheme
})
// 计算当前选中目标
const select = computed(() => {
const id = props.componentData.id
return chartEditStore.getTargetChart.selectId.find((e: string) => e === id)
})
// 悬浮对象
const hover = computed(() => {
return props.componentData.id === chartEditStore.getTargetChart.hoverId
})
// 组件状态 隐藏/锁定
const status = computed(() => {
return props.componentData.status
})
// 是否选中文本
const selectText = computed(() => {
return props.layerMode === LayerModeEnum.TEXT
})
</script>
<style lang="scss" scoped>
$centerHeight: 52px;
$centerMiniHeight: 28px;
$textSize: 10px;
@include go(content-layers-list-item) {
@@ -72,15 +95,14 @@ $textSize: 10px;
&: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;
&:hover {
@include deep() {
.icon-item {
opacity: 1;
}
}
}
.select-modal,
.item-content {
position: absolute;
@@ -94,24 +116,39 @@ $textSize: 10px;
width: calc(100% - 10px);
height: calc(100% - 10px);
}
.select-modal {
width: 100%;
height: 100%;
opacity: 0.3;
background-color: v-bind('themeColor');
}
.list-img {
flex-shrink: 0;
height: $centerHeight;
border-radius: 5px;
overflow: hidden;
border: 1px solid;
border: none !important;
padding: 2px;
@include hover-border-color('hover-border-color');
}
.list-text {
padding-left: 6px;
font-size: $textSize;
}
/* 选中样式 */
&.select {
border: 1px solid v-bind('themeColor');
/* 需要设置最高级,覆盖 hover 的颜色 */
background-color: rgba(0, 0, 0, 0);
}
// mini样式
&.list-mini {
height: $centerMiniHeight;
}
}
</style>
@@ -0,0 +1,3 @@
import LayersStatus from './index.vue'
export { LayersStatus }
@@ -0,0 +1,86 @@
<template>
<div class="icon-item-box" v-show="!isGroup">
<n-icon
class="go-ml-1 icon-item"
:class="{ active: status.lock }"
size="15"
:component="status.lock ? LockClosedOutlineIcon : LockOpenOutlineIcon"
@click="lockHandle"
/>
<n-icon
class="go-ml-1 icon-item"
:class="{ active: status.hide }"
size="15"
:component="status.hide ? EyeOffOutlineIcon : EyeOutlineIcon"
@click="showHandle"
/>
</div>
</template>
<script setup lang="ts">
import { computed, PropType } from 'vue'
import { useDesignStore } from '@/store/modules/designStore/designStore'
import { StatusType } from '@/packages/index.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { icon } from '@/plugins'
const props = defineProps({
isGroup: {
type: Boolean,
default: false
},
hover: {
type: Boolean,
default: false
},
status: {
type: Object as PropType<StatusType>,
default: () => ({
lock: false,
hide: false
})
}
})
const { LockClosedOutlineIcon, LockOpenOutlineIcon, EyeOutlineIcon, EyeOffOutlineIcon } = icon.ionicons5
const chartEditStore = useChartEditStore()
const designStore = useDesignStore()
// 颜色
const themeColor = computed(() => {
return designStore.getAppTheme
})
// 隐藏 / 展示
const showHandle = (e: MouseEvent) => {
e.stopPropagation()
props.status.hide ? chartEditStore.setShow() : chartEditStore.setHide()
}
// 锁定 / 解锁
const lockHandle = (e: MouseEvent) => {
e.stopPropagation()
props.status.lock ? chartEditStore.setUnLock() : chartEditStore.setLock()
}
</script>
<style lang="scss" scoped>
$activeColor: v-bind('themeColor');
.icon-item-box {
white-space: nowrap;
.icon-item {
opacity: 0;
padding-top: 5px;
@extend.go-transition;
&.active,
&:hover {
color: $activeColor;
}
&.active {
opacity: 1 !important;
}
}
}
</style>
+62 -16
View File
@@ -8,24 +8,49 @@
@mousedown="boxMousedownHandle($event)"
>
<template #icon>
<n-icon size="16" :depth="2">
<component :is="LayersIcon"></component>
</n-icon>
<n-icon size="16" :depth="2" :component="LayersIcon" />
</template>
<template #top-right>
<n-button-group style="display: flex">
<n-button
v-for="(item, index) in layerModeList"
:key="index"
ghost
size="small"
:type="layerMode === item.value ? 'primary' : 'tertiary'"
@click="changeLayerType(item.value)"
>
<n-tooltip :show-arrow="false" trigger="hover">
<template #trigger>
<n-icon size="14" :component="item.icon" />
</template>
{{ item.label }}
</n-tooltip>
</n-button>
</n-button-group>
</template>
<!-- 图层内容 -->
<n-space v-if="reverseList.length === 0" justify="center">
<n-text class="not-layer-text">暂无图层~</n-text>
</n-space>
<!-- https://github.com/SortableJS/vue.draggable.next -->
<draggable item-key="id" v-model="layerList" ghostClass="ghost" @change="onMoveCallback">
<template #item="{ element }">
<div class="go-content-layer-box">
<!-- 组合 -->
<layers-group-list-item v-if="element.isGroup" :componentGroupData="element"></layers-group-list-item>
<layers-group-list-item
v-if="element.isGroup"
:componentGroupData="element"
:layer-mode="layerMode"
></layers-group-list-item>
<!-- 单组件 -->
<layers-list-item
v-else
:componentData="element"
:layer-mode="layerMode"
@mousedown="mousedownHandle($event, element)"
@mouseenter="mouseenterHandle(element)"
@mouseleave="mouseleaveHandle(element)"
@@ -43,7 +68,7 @@ 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 { ChartLayoutStoreEnum, LayerModeEnum } from '@/store/modules/chartLayoutStore/chartLayoutStore.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
import { MenuOptionsItemType } from '@/views/chart/hooks/useContextMenu.hook.d'
@@ -55,12 +80,18 @@ import { LayersGroupListItem } from './components/LayersGroupListItem/index'
import { icon } from '@/plugins'
const { LayersIcon } = icon.ionicons5
const { LayersIcon, GridIcon, ListIcon } = icon.ionicons5
const chartLayoutStore = useChartLayoutStore()
const chartEditStore = useChartEditStore()
const { handleContextMenu, onClickOutSide } = useContextMenu()
const layerModeList = [
{ label: '缩略图', icon: GridIcon, value: LayerModeEnum.THUMBNAIL },
{ label: '文本列表', icon: ListIcon, value: LayerModeEnum.TEXT }
]
const layerList = ref<any>([])
const layerMode = ref<LayerModeEnum>(chartLayoutStore.getLayerType)
// 逆序展示
const reverseList = computed(() => {
@@ -83,16 +114,21 @@ const optionsHandle = (
) => {
// 多选处理
if (chartEditStore.getTargetChart.selectId.length > 1) {
const list: MenuOptionsItemType[] = []
targetList.forEach(item => {
// 成组
if (item.key === MenuEnum.GROUP) {
list.push(item)
}
})
return list
return targetList.filter(i => i.key === MenuEnum.GROUP)
}
return targetList
const statusMenuEnums: MenuEnum[] = []
// 处理锁定与隐藏
if (targetInstance.status.lock) {
statusMenuEnums.push(MenuEnum.LOCK)
} else {
statusMenuEnums.push(MenuEnum.UNLOCK)
}
if (targetInstance.status.hide) {
statusMenuEnums.push(MenuEnum.HIDE)
} else {
statusMenuEnums.push(MenuEnum.SHOW)
}
return targetList.filter(item => !statusMenuEnums.includes(item.key as MenuEnum))
}
// 缩小
@@ -156,10 +192,17 @@ const mouseenterHandle = (item: CreateComponentType) => {
const mouseleaveHandle = (item: CreateComponentType) => {
chartEditStore.setTargetHoverChart(undefined)
}
// 修改图层展示方式
const changeLayerType = (value: LayerModeEnum) => {
layerMode.value = value
chartLayoutStore.setItem(ChartLayoutStoreEnum.LAYER_TYPE, value)
}
</script>
<style lang="scss" scoped>
$wight: 170px;
$wight: 200px;
@include go(content-layers) {
width: $wight;
flex-shrink: 0;
@@ -177,5 +220,8 @@ $wight: 170px;
.ghost {
opacity: 0;
}
.go-layer-mode-active {
color: #51d6a9;
}
}
</style>
+46 -5
View File
@@ -7,7 +7,18 @@ 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 {
CopyIcon,
CutIcon,
ClipboardOutlineIcon,
TrashIcon,
ChevronDownIcon,
ChevronUpIcon,
LockOpenOutlineIcon,
LockClosedOutlineIcon,
EyeOutlineIcon,
EyeOffOutlineIcon
} = icon.ionicons5
const { UpToTopIcon, DownToBottomIcon, PaintBrushIcon, Carbon3DSoftwareIcon, Carbon3DCursorIcon } = icon.carbon
const chartEditStore = useChartEditStore()
@@ -17,7 +28,7 @@ const chartEditStore = useChartEditStore()
* @param {number} n > 2
* @returns
*/
export const divider = (n:number = 3) => {
export const divider = (n: number = 3) => {
return {
type: 'divider',
key: `d${n}`
@@ -26,6 +37,34 @@ export const divider = (n:number = 3) => {
// * 默认单组件选项
export const defaultOptions: MenuOptionsItemType[] = [
{
label: '锁定',
key: MenuEnum.LOCK,
icon: renderIcon(LockClosedOutlineIcon),
fnHandle: chartEditStore.setLock
},
{
label: '解锁',
key: MenuEnum.UNLOCK,
icon: renderIcon(LockOpenOutlineIcon),
fnHandle: chartEditStore.setUnLock
},
{
label: '隐藏',
key: MenuEnum.HIDE,
icon: renderIcon(EyeOffOutlineIcon),
fnHandle: chartEditStore.setHide
},
{
label: '显示',
key: MenuEnum.SHOW,
icon: renderIcon(EyeOutlineIcon),
fnHandle: chartEditStore.setShow
},
{
type: 'divider',
key: 'd0'
},
{
label: '复制',
key: MenuEnum.COPY,
@@ -61,13 +100,13 @@ export const defaultOptions: MenuOptionsItemType[] = [
fnHandle: chartEditStore.setBottom
},
{
label: '上移一层',
label: '上移',
key: MenuEnum.UP,
icon: renderIcon(ChevronUpIcon),
fnHandle: chartEditStore.setUp
},
{
label: '下移一层',
label: '下移',
key: MenuEnum.DOWN,
icon: renderIcon(ChevronDownIcon),
fnHandle: chartEditStore.setDown
@@ -160,7 +199,9 @@ const handleContextMenu = (
target = target.parentNode
}
// 展示列表
chartEditStore.setTargetSelectChart(targetInstance && targetInstance.id)
// 隐藏旧列表
chartEditStore.setRightMenuShow(false)
// * 多选默认选项
+38
View File
@@ -26,6 +26,10 @@ export const winKeyboardValue = {
[MenuEnum.SAVE]: winCtrlMerge('s'),
[MenuEnum.GROUP]: winCtrlMerge('g'),
[MenuEnum.UN_GROUP]: winCtrlMerge(winShiftMerge('g')),
[MenuEnum.LOCK]: winCtrlMerge('l'),
[MenuEnum.UNLOCK]: winCtrlMerge(winShiftMerge('l')),
[MenuEnum.HIDE]: winCtrlMerge('h'),
[MenuEnum.SHOW]: winCtrlMerge(winShiftMerge('h')),
}
// 这个 Ctrl 后面还是换成了 ⌘
@@ -48,6 +52,10 @@ export const macKeyboardValue = {
[MenuEnum.SAVE]: macCtrlMerge('s'),
[MenuEnum.GROUP]: macCtrlMerge('g'),
[MenuEnum.UN_GROUP]: macCtrlMerge(macShiftMerge('g')),
[MenuEnum.LOCK]: macCtrlMerge('l'),
[MenuEnum.UNLOCK]: macCtrlMerge(macShiftMerge('l')),
[MenuEnum.HIDE]: macCtrlMerge('h'),
[MenuEnum.SHOW]: macCtrlMerge(macShiftMerge('h')),
}
// Win 快捷键列表
@@ -68,6 +76,12 @@ const winKeyList: Array<string> = [
winKeyboardValue.save,
winKeyboardValue.group,
winKeyboardValue.unGroup,
winKeyboardValue.lock,
winKeyboardValue.unLock,
winKeyboardValue.hide,
winKeyboardValue.show,
]
// Mac 快捷键列表
@@ -88,6 +102,12 @@ const macKeyList: Array<string> = [
macKeyboardValue.save,
macKeyboardValue.group,
macKeyboardValue.unGroup,
macKeyboardValue.lock,
macKeyboardValue.unLock,
macKeyboardValue.hide,
macKeyboardValue.show,
]
// 处理键盘记录
@@ -162,6 +182,24 @@ export const useAddKeyboard = () => {
keymaster(e, throttle(() => { chartEditStore.setUnGroup(); return false }, throttleTime))
break;
// 锁定 ct+l
case keyboardValue.lock:
keymaster(e, throttle(() => { chartEditStore.setLock(); return false }, throttleTime))
break;
// 解除锁定 ct+sh+l
case keyboardValue.unLock:
keymaster(e, throttle(() => { chartEditStore.setUnLock(); return false }, throttleTime))
break;
// 锁定 ct+h
case keyboardValue.hide:
keymaster(e, throttle(() => { chartEditStore.setHide(); return false }, throttleTime))
break;
// 解除锁定 ct+sh+h
case keyboardValue.show:
keymaster(e, throttle(() => { chartEditStore.setShow(); return false }, throttleTime))
break;
// 保存 ct+s
case keyboardValue.save:
keymaster(e, throttle(() => { useSyncIns.dataSyncUpdate(); return false }, 200))