feat: 新增自定义背景图

This commit is contained in:
MTrun 2022-02-06 21:35:38 +08:00
parent 688ce50c58
commit 8fb8b9328d
18 changed files with 297 additions and 51 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 KiB

View File

@ -0,0 +1,5 @@
<template>
<div>
<Skeleton repeat="3" :show="true"/>
</div>
</template>

View File

@ -1,6 +1,7 @@
import type { App } from 'vue' import type { App } from 'vue'
import LoadingComponent from './index.vue' import LoadingComponent from './index.vue'
import AsyncLoading from './index.vue' import AsyncLoading from './index.vue'
import AsyncSkeletonLoading from './Skeleton.vue'
// 正常组件 // 正常组件
export { LoadingComponent } export { LoadingComponent }
@ -9,4 +10,8 @@ export { LoadingComponent }
AsyncLoading.install = (app: App): void => { AsyncLoading.install = (app: App): void => {
app.component('AsyncLoading', AsyncLoading) app.component('AsyncLoading', AsyncLoading)
} }
export { AsyncLoading }
AsyncSkeletonLoading.install = (app: App): void => {
app.component('AsyncSkeletonLoading', AsyncSkeletonLoading)
}
export { AsyncLoading, AsyncSkeletonLoading }

View File

@ -101,7 +101,7 @@ const ionicons5 = {
PencilIcon, PencilIcon,
// 编辑2锤子 // 编辑2锤子
HammerIcon, HammerIcon,
// 预览 // 电脑
DesktopOutlineIcon, DesktopOutlineIcon,
// 下载 // 下载
DownloadIcon, DownloadIcon,
@ -115,7 +115,7 @@ const ionicons5 = {
GridIcon, GridIcon,
// 电脑1 // 电脑1
TvOutlineIcon, TvOutlineIcon,
// 浏览器 // 预览,浏览器
BrowsersOutlineIcon, BrowsersOutlineIcon,
// 文档 // 文档
DocumentTextIcon, DocumentTextIcon,

View File

@ -84,6 +84,7 @@ import {
NPopselect, NPopselect,
NCollapse, NCollapse,
NCollapseItem, NCollapseItem,
NColorPicker,
NCollapseTransition NCollapseTransition
} from 'naive-ui'; } from 'naive-ui';
@ -172,6 +173,7 @@ const naive = create({
NPopselect, NPopselect,
NCollapse, NCollapse,
NCollapseItem, NCollapseItem,
NColorPicker,
NCollapseTransition NCollapseTransition
], ],
}); });

View File

@ -5,13 +5,10 @@ import { HistoryActionTypeEnum } from '@/store/modules/chartHistoryStore/chartHi
export enum EditCanvasTypeEnum { export enum EditCanvasTypeEnum {
EDIT_LAYOUT_DOM = 'editLayoutDom', EDIT_LAYOUT_DOM = 'editLayoutDom',
EDIT_CONTENT_DOM = 'editContentDom', EDIT_CONTENT_DOM = 'editContentDom',
WIDTH = 'width',
HEIGHT = 'height',
OFFSET = 'offset', OFFSET = 'offset',
SCALE = 'scale', SCALE = 'scale',
USER_SCALE = 'userScale', USER_SCALE = 'userScale',
LOCK_SCALE = 'lockScale', LOCK_SCALE = 'lockScale',
BACKGROUND = 'background'
} }
// 编辑区域 // 编辑区域
@ -30,33 +27,42 @@ export type EditCanvasType = {
} }
// 滤镜 // 滤镜
export enum EditCanvasFilterEnum { export enum EditCanvasConfigEnum {
WIDTH = 'width',
HEIGHT = 'height',
HUE_ROTATE = 'hueRotate', HUE_ROTATE = 'hueRotate',
SATURATE = 'saturate', SATURATE = 'saturate',
BRIGHTNESS = 'brightness', BRIGHTNESS = 'brightness',
CONTRAST = 'contrast', CONTRAST = 'contrast',
UN_OPACITY = 'unOpacity', UN_OPACITY = 'unOpacity',
CHART_THEME = 'chartTheme', CHART_THEME = 'chartTheme',
BACKGROUND = 'background',
BACKGROUND_IAMGE = 'backgroundImage',
SELECT_COLOR = 'selectColor'
} }
export interface EditCanvasConfigType { export interface EditCanvasConfigType {
// 大屏宽度 // 大屏宽度
[EditCanvasTypeEnum.WIDTH]: number [EditCanvasConfigEnum.WIDTH]: number
// 大屏高度 // 大屏高度
[EditCanvasTypeEnum.HEIGHT]: number [EditCanvasConfigEnum.HEIGHT]: number
// 色相 // 色相
[EditCanvasFilterEnum.HUE_ROTATE]: number [EditCanvasConfigEnum.HUE_ROTATE]: number
// 饱和度 // 饱和度
[EditCanvasFilterEnum.SATURATE]: number [EditCanvasConfigEnum.SATURATE]: number
// 亮度 // 亮度
[EditCanvasFilterEnum.BRIGHTNESS]: number [EditCanvasConfigEnum.BRIGHTNESS]: number
// 对比度 // 对比度
[EditCanvasFilterEnum.CONTRAST]: number [EditCanvasConfigEnum.CONTRAST]: number
// 不透明度 // 不透明度
[EditCanvasFilterEnum.UN_OPACITY]: number [EditCanvasConfigEnum.UN_OPACITY]: number
// 背景色 // 背景色
[EditCanvasTypeEnum.BACKGROUND]?: string [EditCanvasConfigEnum.BACKGROUND]?: string
[EditCanvasConfigEnum.BACKGROUND_IAMGE]?: string | ArrayBuffer | null
// 图表主题颜色 // 图表主题颜色
[EditCanvasFilterEnum.CHART_THEME]: string [EditCanvasConfigEnum.CHART_THEME]: string
// 图表主题颜色
[EditCanvasConfigEnum.SELECT_COLOR]: boolean
} }
// 坐标轴信息 // 坐标轴信息

View File

@ -54,6 +54,9 @@ export const useChartEditStoreStore = defineStore({
unOpacity: 100, unOpacity: 100,
// 默认背景色 // 默认背景色
background: undefined, background: undefined,
backgroundImage: undefined,
// 是否使用纯颜色
selectColor: true,
// chart 主题色 // chart 主题色
chartTheme: defaultTheme || 'dark' chartTheme: defaultTheme || 'dark'
}, },

View File

@ -1,5 +1,5 @@
import { defineAsyncComponent, AsyncComponentLoader } from 'vue' import { defineAsyncComponent, AsyncComponentLoader } from 'vue'
import { AsyncLoading } from '@/components/LoadingComponent' import { AsyncLoading, AsyncSkeletonLoading } from '@/components/LoadingComponent'
/** /**
* * * *
@ -12,3 +12,10 @@ export const loadAsyncComponent = (loader: AsyncComponentLoader<any>) =>
loadingComponent: AsyncLoading, loadingComponent: AsyncLoading,
delay: 20, delay: 20,
}) })
export const loadSkeletonAsyncComponent = (loader: AsyncComponentLoader<any>) =>
defineAsyncComponent({
loader,
loadingComponent: AsyncSkeletonLoading,
delay: 20,
})

View File

@ -91,6 +91,7 @@ export const setDomAttribute = <K extends keyof CSSStyleDeclaration, V extends C
HTMLElement.style[key] = value HTMLElement.style[key] = value
} }
} }
/** /**
* * mac * * mac
* @returns boolean * @returns boolean
@ -98,6 +99,21 @@ export const setDomAttribute = <K extends keyof CSSStyleDeclaration, V extends C
export const isMac = () => { export const isMac = () => {
return /macintosh|mac os x/i.test(navigator.userAgent) return /macintosh|mac os x/i.test(navigator.userAgent)
} }
/**
* * file转base64
*/
export const fileTobase64 = (file:File, callback: Function) => {
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function (e: ProgressEvent<FileReader>) {
if(e.target) {
let base64 = e.target.result;
callback(base64)
}
};
};
/** /**
* * * *
*/ */

View File

@ -34,7 +34,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed } from 'vue' import { ref, computed } from 'vue'
import { useChartEditStoreStore } from '@/store/modules/chartEditStore/chartEditStore' import { useChartEditStoreStore } from '@/store/modules/chartEditStore/chartEditStore'
import { EditCanvasFilterEnum } from '@/store/modules/chartEditStore/chartEditStore.d' import { EditCanvasConfigEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
import { import {
chartColors, chartColors,
chartColorsName, chartColorsName,
@ -61,7 +61,7 @@ const fetchShowColors = (colors: Array<string>) => {
} }
const selectTheme = (theme: string) => { const selectTheme = (theme: string) => {
chartEditStoreStore.setCanvasConfig(EditCanvasFilterEnum.CHART_THEME, theme) chartEditStoreStore.setCanvasConfig(EditCanvasConfigEnum.CHART_THEME, theme)
} }
</script> </script>

View File

@ -1,16 +1,218 @@
<template> <template>
<div class="go-canvas-setting"> <div class="go-canvas-setting">
<n-form inline :label-width="45" size="small" label-placement="left">
<n-form-item label="宽度">
<!-- 尺寸选择 -->
<n-input-number
size="small"
v-model:value="canvasConfig.width"
:validator="validator"
@update:value="chartEditStoreStore.computedScale"
/>
</n-form-item>
<n-form-item label="高度">
<n-input-number
size="small"
v-model:value="canvasConfig.height"
:validator="validator"
@update:value="chartEditStoreStore.computedScale"
/>
</n-form-item>
</n-form>
<n-card class="upload-box">
<n-upload
v-model:file-list="uploadFileListRef"
:show-file-list="false"
:customRequest="customRequest"
:onBeforeUpload="beforeUploadHandle"
>
<n-upload-dragger>
<img
class="upload-show"
v-if="canvasConfig.backgroundImage"
: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">
背景图需小于 2M 格式为 png/jpg/gif 的文件
</n-text>
</div>
</n-upload-dragger>
</n-upload>
</n-card>
<n-space vertical :size="12">
<n-space>
<n-text>背景色</n-text>
<n-color-picker
style="width: 326px;"
:showPreview="true"
:swatches="[
'#232324',
'#2a2a2b',
'#313132',
'#373739',
'#757575',
'#e0e0e0',
'#eeeeee',
'#fafafa'
]"
v-model:value="canvasConfig.background"
/>
</n-space>
<n-space>
<n-text>使用颜色</n-text>
<n-switch
size="small"
v-model:value="canvasConfig.selectColor"
:loading="switchSelectColorLoading"
:round="false"
:disabled="!canvasConfig.backgroundImage"
:onUpdate="switchSelectColorHandle"
/>
</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-space>
</n-space>
<n-divider />
<!-- 主题选择 -->
<ChartTheme /> <ChartTheme />
</div> </div>
</template> </template>
<script setup> <script setup lang="ts">
import { ref, nextTick, onMounted } from 'vue'
import { useChartEditStoreStore } from '@/store/modules/chartEditStore/chartEditStore' import { useChartEditStoreStore } from '@/store/modules/chartEditStore/chartEditStore'
const chartEditStoreStore = useChartEditStoreStore() import { EditCanvasConfigEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
import { UploadCustomRequestOptions, UploadFileInfo } from 'naive-ui'
import { ChartTheme } from './components/ChartTheme/index' import { ChartTheme } from './components/ChartTheme/index'
import { fileTobase64 } from '@/utils'
const chartEditStoreStore = useChartEditStoreStore()
const canvasConfig = chartEditStoreStore.getEditCanvasConfig
const uploadFileListRef = ref()
const switchSelectColorLoading = ref(false)
//
const validator = (x: number) => x > 50
//
//@ts-ignore
const beforeUploadHandle = async ({ file }) => {
uploadFileListRef.value = []
const type = file.file.type
const size = file.file.size
if (size > 1024 * 1024 * 2) {
window['$message'].warning('图片超出 2M 限制,请重新上传!')
return false
}
if (type !== 'image/png' && type !== 'image/jpeg' && type !== 'image/gif') {
window['$message'].warning('文件格式不符合,请重新上传!')
return false
}
return true
}
//
const clearImage = () => {
chartEditStoreStore.setCanvasConfig(
EditCanvasConfigEnum.BACKGROUND_IAMGE,
undefined
)
}
//
const clearColor = () => {
chartEditStoreStore.setCanvasConfig(
EditCanvasConfigEnum.BACKGROUND,
undefined
)
}
//
const switchSelectColorHandle = () => {
switchSelectColorLoading.value = true
setTimeout(() => {
switchSelectColorLoading.value = false
}, 1000)
}
//
const customRequest = (options: UploadCustomRequestOptions) => {
const {
file,
data,
headers,
withCredentials,
action,
onFinish,
onError,
onProgress
} = options
nextTick(() => {
fileTobase64(file.file as File, (e: string | ArrayBuffer | null) => {
chartEditStoreStore.setCanvasConfig(
EditCanvasConfigEnum.BACKGROUND_IAMGE,
e
)
})
})
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@include go(canvas-setting) { @include go(canvas-setting) {
padding-top: 20px;
.upload-box {
cursor: pointer;
margin-bottom: 20px;
@include deep() {
.n-card__content {
padding: 0px;
overflow: hidden;
}
}
.upload-show {
display: block;
width: 326px;
height: 193px;
margin-bottom: -7px;
border-radius: 5px;
}
.upload-img {
display: flex;
flex-direction: column;
align-items: center;
width: 326px;
img {
height: 150px;
}
.upload-desc {
padding: 10px 0;
}
}
}
} }
</style> </style>

View File

@ -31,7 +31,7 @@
<n-space> <n-space>
<span> 页面设置 </span> <span> 页面设置 </span>
<n-icon size="16" class="icon-position"> <n-icon size="16" class="icon-position">
<BrowsersOutlineIcon /> <DesktopOutlineIcon />
</n-icon> </n-icon>
</n-space> </n-space>
</template> </template>
@ -72,7 +72,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { shallowRef, ref, toRefs, watch, computed, reactive } from 'vue' import { shallowRef, ref, toRefs, watch, computed, reactive } from 'vue'
import { icon } from '@/plugins' import { icon } from '@/plugins'
import { loadAsyncComponent } from '@/utils' import { loadAsyncComponent, loadSkeletonAsyncComponent } from '@/utils'
import { ContentBox } from '../ContentBox/index' import { ContentBox } from '../ContentBox/index'
import { useChartLayoutStore } from '@/store/modules/chartLayoutStore/chartLayoutStore' import { useChartLayoutStore } from '@/store/modules/chartLayoutStore/chartLayoutStore'
import { ChartLayoutStoreEnum } from '@/store/modules/chartLayoutStore/chartLayoutStore.d' import { ChartLayoutStoreEnum } from '@/store/modules/chartLayoutStore/chartLayoutStore.d'
@ -82,17 +82,12 @@ const { getDetails } = toRefs(useChartLayoutStore())
const { setItem } = useChartLayoutStore() const { setItem } = useChartLayoutStore()
const chartEditStoreStore = useChartEditStoreStore() const chartEditStoreStore = useChartEditStoreStore()
const { ConstructIcon, FlashIcon, BrowsersOutlineIcon } = icon.ionicons5 const { ConstructIcon, FlashIcon, DesktopOutlineIcon } = icon.ionicons5
const ContentEdit = loadAsyncComponent(() => import('../ContentEdit/index.vue')) const ContentEdit = loadAsyncComponent(() => import('../ContentEdit/index.vue'))
const CanvasPage = loadAsyncComponent(() => const CanvasPage = loadSkeletonAsyncComponent(() =>import('./components/CanvasPage/index.vue'))
import('./components/CanvasPage/index.vue') const Setting = loadSkeletonAsyncComponent(() =>import('./components/Setting/index.vue'))
) const Behind = loadSkeletonAsyncComponent(() => import('./components/Behind/index.vue'))
const Setting = loadAsyncComponent(() =>
import('./components/Setting/index.vue')
)
const Behind = loadAsyncComponent(() => import('./components/Behind/index.vue'))
const collapsed = ref<boolean>(getDetails.value) const collapsed = ref<boolean>(getDetails.value)

View File

@ -9,30 +9,32 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed } from 'vue' import { toRefs, computed } from 'vue'
import { useChartEditStoreStore } from '@/store/modules/chartEditStore/chartEditStore' import { useChartEditStoreStore } from '@/store/modules/chartEditStore/chartEditStore'
import { useSizeStyle } from '../../hooks/useStyle.hook' import { useSizeStyle } from '../../hooks/useStyle.hook'
import { mousedownHandleUnStop } from '../../hooks/useDrop.hook' import { mousedownHandleUnStop } from '../../hooks/useDrop.hook'
const chartEditStoreStore = useChartEditStoreStore() const chartEditStoreStore = useChartEditStoreStore()
const canvasConfig = ref(chartEditStoreStore.getEditCanvasConfig) const { getEditCanvasConfig } = toRefs(chartEditStoreStore)
const size = computed(() => { const size = computed(() => {
return { return {
w: canvasConfig.value.width, w: getEditCanvasConfig.value.width,
h: canvasConfig.value.height h: getEditCanvasConfig.value.height
} }
}) })
const background = computed(() => {
const background = canvasConfig.value.background
return background ? background : '#232324'
})
const style = computed(() => { const style = computed(() => {
const background = getEditCanvasConfig.value.background
const backgroundImage = getEditCanvasConfig.value.backgroundImage
const selectColor = getEditCanvasConfig.value.selectColor
const backgroundColor = background ? background : null
const computed = selectColor
? { background: backgroundColor }
: { background: `url(${backgroundImage}) no-repeat center/100% !important` }
// @ts-ignore // @ts-ignore
return { ...useSizeStyle(size.value), background: background.value } return { ...useSizeStyle(size.value), ...computed }
}) })
</script> </script>
@ -41,7 +43,7 @@ const style = computed(() => {
position: relative; position: relative;
border: 1px solid; border: 1px solid;
border-radius: 15px; border-radius: 15px;
@include filter-bg-color('background-color2'); background: url('@/assets/images/canvas/pageBg.png');
@include fetch-theme('box-shadow'); @include fetch-theme('box-shadow');
@include filter-border-color('hover-border-color'); @include filter-border-color('hover-border-color');
@include fetch-theme-custom('border-color', 'background-color4'); @include fetch-theme-custom('border-color', 'background-color4');

View File

@ -4,7 +4,6 @@
@select="handleSelect" @select="handleSelect"
:show="showDropdownRef" :show="showDropdownRef"
:options="options" :options="options"
scrollable
size="small" size="small"
placement="top-start" placement="top-start"
style="max-height: 100vh; overflow-y: auto;" style="max-height: 100vh; overflow-y: auto;"

View File

@ -19,9 +19,13 @@ export const handleDrop = async (e: DragEvent) => {
try { try {
loadingStart() loadingStart()
// 获取拖拽数据 // 获取拖拽数据
const drayDataString = e!.dataTransfer!.getData(DragKeyEnum.DROG_KEY) const drayDataString = e!.dataTransfer!.getData(DragKeyEnum.DROG_KEY)
if (!drayDataString) {
loadingFinish()
return
}
const dropData: Exclude<ConfigType, ['node', 'image']> = JSON.parse( const dropData: Exclude<ConfigType, ['node', 'image']> = JSON.parse(
drayDataString drayDataString
) )
@ -67,8 +71,8 @@ export const useMouseHandle = () => {
onClickoutside() onClickoutside()
chartEditStore.setTargetSelectChart(item.id) chartEditStore.setTargetSelectChart(item.id)
const scale = chartEditStore.getEditCanvas.scale const scale = chartEditStore.getEditCanvas.scale
const width = chartEditStore.getEditCanvas.width const width = chartEditStore.getEditCanvasConfig.width
const height = chartEditStore.getEditCanvas.height const height = chartEditStore.getEditCanvasConfig.height
// 获取编辑区域 Dom // 获取编辑区域 Dom
const editcontentDom = chartEditStore.getEditCanvas.editContentDom const editcontentDom = chartEditStore.getEditCanvas.editContentDom

View File

@ -15,13 +15,13 @@
import { reactive } from 'vue' import { reactive } from 'vue'
import { renderIcon } from '@/utils' import { renderIcon } from '@/utils'
import { icon } from '@/plugins' import { icon } from '@/plugins'
const { DesktopOutlineIcon, SendIcon } = icon.ionicons5 const { BrowsersOutlineIcon, SendIcon } = icon.ionicons5
const btnList = reactive([ const btnList = reactive([
{ {
select: true, select: true,
title: '预览', title: '预览',
icon: renderIcon(DesktopOutlineIcon) icon: renderIcon(BrowsersOutlineIcon)
}, },
{ {
select: true, select: true,

View File

@ -92,7 +92,7 @@ const {
CopyIcon, CopyIcon,
TrashIcon, TrashIcon,
PencilIcon, PencilIcon,
DesktopOutlineIcon, BrowsersOutlineIcon,
DownloadIcon, DownloadIcon,
HammerIcon, HammerIcon,
SendIcon SendIcon
@ -122,7 +122,7 @@ const selectOptions = ref([
{ {
label: renderLang('global.r_preview'), label: renderLang('global.r_preview'),
key: 'preview', key: 'preview',
icon: renderIcon(DesktopOutlineIcon) icon: renderIcon(BrowsersOutlineIcon)
}, },
{ {
label: renderLang('global.r_copy'), label: renderLang('global.r_copy'),