mirror of
https://gitee.com/dromara/go-view.git
synced 2025-02-25 00:33:00 +08:00
feat: 新增导入导出功能😍
This commit is contained in:
parent
aef57f13f0
commit
16bf72ac24
@ -22,12 +22,12 @@ export let packagesList: PackagesType = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * 获取目标拖拽组件配置信息
|
* * 获取目标组件配置信息
|
||||||
* @param dropData
|
* @param targetData
|
||||||
*/
|
*/
|
||||||
export const createComponent = async (dropData: ConfigType) => {
|
export const createComponent = async (targetData: ConfigType) => {
|
||||||
const { category, key } = dropData
|
const { category, key } = targetData
|
||||||
const chart = await import(`./components/${dropData.package}/${category}/${key}/config.ts`)
|
const chart = await import(`./components/${targetData.package}/${category}/${key}/config.ts`)
|
||||||
return new chart.default()
|
return new chart.default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ import debounce from 'lodash/debounce'
|
|||||||
import cloneDeep from 'lodash/cloneDeep'
|
import cloneDeep from 'lodash/cloneDeep'
|
||||||
import { defaultTheme, globalThemeJson } from '@/settings/chartThemes/index'
|
import { defaultTheme, globalThemeJson } from '@/settings/chartThemes/index'
|
||||||
import { requestInterval } from '@/settings/designSetting'
|
import { requestInterval } from '@/settings/designSetting'
|
||||||
import { chartMoveDistance } from '@/settings/systemSetting'
|
|
||||||
// 记录记录
|
// 记录记录
|
||||||
import { useChartHistoryStore } from '@/store/modules/chartHistoryStore/chartHistoryStore'
|
import { useChartHistoryStore } from '@/store/modules/chartHistoryStore/chartHistoryStore'
|
||||||
// 全局设置
|
// 全局设置
|
||||||
@ -63,6 +62,7 @@ export const useChartEditStore = defineStore({
|
|||||||
},
|
},
|
||||||
// 记录临时数据(复制等)
|
// 记录临时数据(复制等)
|
||||||
recordChart: undefined,
|
recordChart: undefined,
|
||||||
|
// -----------------------
|
||||||
// 画布属性(需存储给后端)
|
// 画布属性(需存储给后端)
|
||||||
editCanvasConfig: {
|
editCanvasConfig: {
|
||||||
// 默认宽度
|
// 默认宽度
|
||||||
|
@ -100,6 +100,11 @@ export const useChartHistoryStore = defineStore({
|
|||||||
clearForwardStack() {
|
clearForwardStack() {
|
||||||
this.forwardStack = []
|
this.forwardStack = []
|
||||||
},
|
},
|
||||||
|
// * 清空后退栈(保留初始化)
|
||||||
|
clearBackStack() {
|
||||||
|
const canvasHistory = this.getBackStack[0]
|
||||||
|
this.backStack = [canvasHistory]
|
||||||
|
},
|
||||||
// * 撤回
|
// * 撤回
|
||||||
backAction() {
|
backAction() {
|
||||||
try {
|
try {
|
||||||
|
@ -121,7 +121,7 @@ const ChartDataSetting = loadAsyncComponent(() =>
|
|||||||
import('./components/ChartDataSetting/index.vue')
|
import('./components/ChartDataSetting/index.vue')
|
||||||
)
|
)
|
||||||
|
|
||||||
// 页面设置
|
// 展示颜色列表
|
||||||
const swatchesColors = [
|
const swatchesColors = [
|
||||||
'#232324',
|
'#232324',
|
||||||
'#2a2a2b',
|
'#2a2a2b',
|
||||||
|
@ -0,0 +1,107 @@
|
|||||||
|
import { ref, nextTick } from 'vue'
|
||||||
|
import { UploadCustomRequestOptions } from 'naive-ui'
|
||||||
|
import { FileTypeEnum } from '@/enums/fileTypeEnum'
|
||||||
|
import { fetchChartComponent } from '@/packages/index'
|
||||||
|
import { CreateComponentType } from '@/packages/index.d'
|
||||||
|
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
|
||||||
|
import { ChartEditStoreEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
|
||||||
|
import { useChartHistoryStore } from '@/store/modules/chartHistoryStore/chartHistoryStore'
|
||||||
|
import { readFile, goDialog } from '@/utils'
|
||||||
|
import { createComponent } from '@/packages'
|
||||||
|
|
||||||
|
// 更新函数
|
||||||
|
const updateComponent = async (fileData: any, isSplace = false) => {
|
||||||
|
const chartEditStore = useChartEditStore()
|
||||||
|
const chartHistoryStore = useChartHistoryStore()
|
||||||
|
if (isSplace) {
|
||||||
|
// 清除列表
|
||||||
|
chartEditStore.componentList = []
|
||||||
|
// 清除历史记录
|
||||||
|
chartHistoryStore.clearBackStack()
|
||||||
|
chartHistoryStore.clearForwardStack()
|
||||||
|
}
|
||||||
|
// 列表组件注册
|
||||||
|
fileData.componentList.forEach(async (e: CreateComponentType) => {
|
||||||
|
if (!window['$vue'].component(e.chartConfig.chartKey)) {
|
||||||
|
window['$vue'].component(
|
||||||
|
e.chartConfig.chartKey,
|
||||||
|
fetchChartComponent(e.chartConfig)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 数据赋值
|
||||||
|
for (const key in fileData) {
|
||||||
|
// 组件
|
||||||
|
if (key === ChartEditStoreEnum.COMPONENT_LIST) {
|
||||||
|
for (const comItem of fileData[key]) {
|
||||||
|
// 补充 class 上的方法
|
||||||
|
let newComponent: CreateComponentType = await createComponent(
|
||||||
|
comItem.chartConfig
|
||||||
|
)
|
||||||
|
// 不保存到记录
|
||||||
|
chartEditStore.addComponentList(
|
||||||
|
Object.assign(newComponent, comItem),
|
||||||
|
false,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 非组件
|
||||||
|
Object.assign((chartEditStore as any)[key], fileData[key])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useFile = () => {
|
||||||
|
const importUploadFileListRef = ref()
|
||||||
|
const chartEditStore = useChartEditStore()
|
||||||
|
|
||||||
|
// 上传-前置
|
||||||
|
//@ts-ignore
|
||||||
|
const importBeforeUpload = ({ file }) => {
|
||||||
|
importUploadFileListRef.value = []
|
||||||
|
const type = file.file.type
|
||||||
|
if (type !== FileTypeEnum.JSON && type !== FileTypeEnum.TXT) {
|
||||||
|
window['$message'].warning('仅支持上传 【JSON】 格式文件,请重新上传!')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 上传-导入
|
||||||
|
const importCustomRequest = (options: UploadCustomRequestOptions) => {
|
||||||
|
const { file } = options
|
||||||
|
nextTick(() => {
|
||||||
|
if (file.file) {
|
||||||
|
readFile(file.file).then((fileData: any) => {
|
||||||
|
goDialog({
|
||||||
|
message: '请选择导入方式:',
|
||||||
|
positiveText: '新增(可撤回)',
|
||||||
|
negativeText: '覆盖(不可撤回)',
|
||||||
|
negativeButtonProps: { type: 'info', ghost: false },
|
||||||
|
// 新增
|
||||||
|
onNegativeCallback: async () => {
|
||||||
|
fileData = JSON.parse(fileData)
|
||||||
|
await updateComponent(fileData, true)
|
||||||
|
window['$message'].success('导入成功!')
|
||||||
|
},
|
||||||
|
// 覆盖
|
||||||
|
onPositiveCallback: async () => {
|
||||||
|
fileData = JSON.parse(fileData)
|
||||||
|
await updateComponent(fileData)
|
||||||
|
window['$message'].success('导入成功!')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
window['$message'].error('导入失败,请检查数据或联系管理员!')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
importUploadFileListRef,
|
||||||
|
importBeforeUpload,
|
||||||
|
importCustomRequest
|
||||||
|
}
|
||||||
|
}
|
12
src/views/chart/ContentEdit/components/EditTools/index.d.ts
vendored
Normal file
12
src/views/chart/ContentEdit/components/EditTools/index.d.ts
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
export enum TypeEnum {
|
||||||
|
BOTTON = 'bottom',
|
||||||
|
IMPORTUPLOAD = 'importUpload'
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BtnListType = {
|
||||||
|
key: string
|
||||||
|
type: TypeEnum
|
||||||
|
name: string
|
||||||
|
icon: any
|
||||||
|
handle?: () => void
|
||||||
|
}
|
@ -17,14 +17,8 @@
|
|||||||
placement="left"
|
placement="left"
|
||||||
>
|
>
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<n-button
|
<div v-show="!isMini" class="btn-item" :class="[btnList.length - 1 === index && 'go-mb-0']">
|
||||||
v-show="!isMini"
|
<n-button v-if="item.type === TypeEnum.BOTTON" :circle="isAside" secondary @click="item.handle">
|
||||||
class="btn-item"
|
|
||||||
:class="[btnList.length - 1 === index && 'go-mb-0']"
|
|
||||||
:circle="isAside"
|
|
||||||
secondary
|
|
||||||
@click="item.handle"
|
|
||||||
>
|
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<n-icon size="22" v-if="isAside">
|
<n-icon size="22" v-if="isAside">
|
||||||
<component :is="item.icon"></component>
|
<component :is="item.icon"></component>
|
||||||
@ -33,15 +27,34 @@
|
|||||||
</template>
|
</template>
|
||||||
<n-text depth="3" v-show="!isAside">{{ item.name }}</n-text>
|
<n-text depth="3" v-show="!isAside">{{ item.name }}</n-text>
|
||||||
</n-button>
|
</n-button>
|
||||||
|
<!-- 下载 -->
|
||||||
|
<n-upload
|
||||||
|
v-else-if="item.type === TypeEnum.IMPORTUPLOAD"
|
||||||
|
v-model:file-list="importUploadFileListRef"
|
||||||
|
:show-file-list="false"
|
||||||
|
:customRequest="importCustomRequest"
|
||||||
|
@before-upload="importBeforeUpload"
|
||||||
|
>
|
||||||
|
<n-button :circle="isAside" secondary>
|
||||||
|
<template #icon>
|
||||||
|
<n-icon size="22" v-if="isAside">
|
||||||
|
<component :is="item.icon"></component>
|
||||||
|
</n-icon>
|
||||||
|
<component v-else :is="item.icon"></component>
|
||||||
|
</template>
|
||||||
|
<n-text depth="3" v-show="!isAside">{{ item.name }}</n-text>
|
||||||
|
</n-button>
|
||||||
|
</n-upload>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<!-- 提示 -->
|
<!-- 提示 -->
|
||||||
<span>{{ item.name }}</span>
|
<span>{{ item.name }}</span>
|
||||||
</n-tooltip>
|
</n-tooltip>
|
||||||
<!-- PawIcon -->
|
<!-- PawIcon -->
|
||||||
<n-icon
|
<n-icon
|
||||||
|
v-if="isAside"
|
||||||
v-show="settingStore.getChartToolsStatus === ToolsStatusEnum.ASIDE && isMini"
|
v-show="settingStore.getChartToolsStatus === ToolsStatusEnum.ASIDE && isMini"
|
||||||
size="22"
|
size="22"
|
||||||
v-if="isAside"
|
|
||||||
>
|
>
|
||||||
<PawIcon></PawIcon>
|
<PawIcon></PawIcon>
|
||||||
</n-icon>
|
</n-icon>
|
||||||
@ -49,10 +62,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, h } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { useSettingStore } from '@/store/modules/settingStore/settingStore'
|
import { useSettingStore } from '@/store/modules/settingStore/settingStore'
|
||||||
import { ToolsStatusEnum } from '@/store/modules/settingStore/settingStore.d'
|
import { ToolsStatusEnum } from '@/store/modules/settingStore/settingStore.d'
|
||||||
import { importHandle, exportHandle } from './utils'
|
import { exportHandle } from './utils'
|
||||||
|
import { useFile } from './hooks/useFile.hooks'
|
||||||
|
import { BtnListType, TypeEnum } from './index.d'
|
||||||
import { icon } from '@/plugins'
|
import { icon } from '@/plugins'
|
||||||
|
|
||||||
const { DownloadIcon, ShareIcon, PawIcon } = icon.ionicons5
|
const { DownloadIcon, ShareIcon, PawIcon } = icon.ionicons5
|
||||||
@ -63,14 +78,17 @@ let mouseTime: any = null
|
|||||||
const isMini = ref<boolean>(true)
|
const isMini = ref<boolean>(true)
|
||||||
// 是否是侧边栏
|
// 是否是侧边栏
|
||||||
const isAside = computed(() => settingStore.getChartToolsStatus === ToolsStatusEnum.ASIDE)
|
const isAside = computed(() => settingStore.getChartToolsStatus === ToolsStatusEnum.ASIDE)
|
||||||
|
// 文件上传
|
||||||
|
const { importUploadFileListRef, importCustomRequest, importBeforeUpload } = useFile()
|
||||||
|
|
||||||
const btnList = [{
|
const btnList: BtnListType[] = [{
|
||||||
key: 'import',
|
key: 'import',
|
||||||
|
type: TypeEnum.IMPORTUPLOAD,
|
||||||
name: '导入',
|
name: '导入',
|
||||||
icon: DownloadIcon,
|
icon: DownloadIcon,
|
||||||
handle: importHandle
|
|
||||||
}, {
|
}, {
|
||||||
key: 'export',
|
key: 'export',
|
||||||
|
type: TypeEnum.BOTTON,
|
||||||
name: '导出',
|
name: '导出',
|
||||||
icon: ShareIcon,
|
icon: ShareIcon,
|
||||||
handle: exportHandle
|
handle: exportHandle
|
||||||
@ -108,7 +126,7 @@ $asideBottom: 70px;
|
|||||||
border-radius: 25px;
|
border-radius: 25px;
|
||||||
border: 1px solid;
|
border: 1px solid;
|
||||||
mix-blend-mode: luminosity;
|
mix-blend-mode: luminosity;
|
||||||
transition: height ease-in 1s, padding 0.4s, bottom .4s;
|
transition: height ease-in 1s, padding 0.4s, bottom 0.4s;
|
||||||
@include filter-border-color("hover-border-color-shallow");
|
@include filter-border-color("hover-border-color-shallow");
|
||||||
&.aside {
|
&.aside {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -118,7 +136,6 @@ $asideBottom: 70px;
|
|||||||
bottom: $asideBottom;
|
bottom: $asideBottom;
|
||||||
.btn-item {
|
.btn-item {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
padding-bottom: 6px;
|
|
||||||
/* 没生效,用上面的 go-mb-0 代替 */
|
/* 没生效,用上面的 go-mb-0 代替 */
|
||||||
&:last-child {
|
&:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
@ -126,6 +143,7 @@ $asideBottom: 70px;
|
|||||||
@include deep() {
|
@include deep() {
|
||||||
.n-button__icon {
|
.n-button__icon {
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
|
margin-bottom: 14px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,19 @@ import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore
|
|||||||
import { canvasCut, downloadTextFile } from '@/utils'
|
import { canvasCut, downloadTextFile } from '@/utils'
|
||||||
const chartEditStore = useChartEditStore()
|
const chartEditStore = useChartEditStore()
|
||||||
|
|
||||||
// 导入
|
|
||||||
export const importHandle = () => { }
|
|
||||||
|
|
||||||
// 导出
|
// 导出
|
||||||
export const exportHandle = () => {
|
export const exportHandle = () => {
|
||||||
|
// 取消选中
|
||||||
|
chartEditStore.setTargetSelectChart(undefined)
|
||||||
|
|
||||||
// 导出数据
|
// 导出数据
|
||||||
downloadTextFile(JSON.stringify(chartEditStore.getStorageInfo || []), undefined, 'json')
|
downloadTextFile(
|
||||||
|
JSON.stringify(chartEditStore.getStorageInfo || [], (k, v) => {
|
||||||
|
return v === undefined ? null : v
|
||||||
|
}),
|
||||||
|
undefined,
|
||||||
|
'json'
|
||||||
|
)
|
||||||
|
|
||||||
// 导出图片
|
// 导出图片
|
||||||
const ruler = document.getElementById('mb-ruler')
|
const ruler = document.getElementById('mb-ruler')
|
||||||
@ -19,6 +25,7 @@ export const exportHandle = () => {
|
|||||||
window['$message'].error('导出失败!')
|
window['$message'].error('导出失败!')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 记录缩放比例
|
// 记录缩放比例
|
||||||
const scaleTemp = chartEditStore.getEditCanvas.scale
|
const scaleTemp = chartEditStore.getEditCanvas.scale
|
||||||
// 去除标尺Dom
|
// 去除标尺Dom
|
||||||
@ -28,7 +35,6 @@ export const exportHandle = () => {
|
|||||||
// 展示水印
|
// 展示水印
|
||||||
watermark.style.display = 'block'
|
watermark.style.display = 'block'
|
||||||
|
|
||||||
window['$message'].warning('生成截图和数据中, 请耐心等待...')
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
canvasCut(range, () => {
|
canvasCut(range, () => {
|
||||||
// 隐藏水印
|
// 隐藏水印
|
||||||
@ -40,8 +46,3 @@ export const exportHandle = () => {
|
|||||||
})
|
})
|
||||||
}, 600)
|
}, 600)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 改变工具栏展示样式
|
|
||||||
export const changeTypeHandle = () => {
|
|
||||||
|
|
||||||
}
|
|
@ -10,7 +10,6 @@ export const useComInstall = (localStorageInfo: ChartEditStorageType) => {
|
|||||||
const intervalTiming = setInterval(() => {
|
const intervalTiming = setInterval(() => {
|
||||||
if (window['$vue'].component) {
|
if (window['$vue'].component) {
|
||||||
clearInterval(intervalTiming)
|
clearInterval(intervalTiming)
|
||||||
show.value = true
|
|
||||||
localStorageInfo.componentList.forEach(async (e: CreateComponentType) => {
|
localStorageInfo.componentList.forEach(async (e: CreateComponentType) => {
|
||||||
if (!window['$vue'].component(e.chartConfig.chartKey)) {
|
if (!window['$vue'].component(e.chartConfig.chartKey)) {
|
||||||
window['$vue'].component(
|
window['$vue'].component(
|
||||||
@ -19,6 +18,7 @@ export const useComInstall = (localStorageInfo: ChartEditStorageType) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
show.value = true
|
||||||
}
|
}
|
||||||
}, 200)
|
}, 200)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user