mirror of
https://gitee.com/dromara/go-view.git
synced 2025-04-24 22:40:11 +08:00
362 lines
13 KiB
TypeScript
362 lines
13 KiB
TypeScript
import { onUnmounted } from 'vue';
|
||
import html2canvas from 'html2canvas'
|
||
import { getUUID, httpErrorHandle, fetchRouteParamsLocation, base64toFile, JSONStringify, JSONParse } from '@/utils'
|
||
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
|
||
import { EditCanvasTypeEnum, ChartEditStoreEnum, ProjectInfoEnum, ChartEditStorage } from '@/store/modules/chartEditStore/chartEditStore.d'
|
||
import { useChartHistoryStore } from '@/store/modules/chartHistoryStore/chartHistoryStore'
|
||
import { StylesSetting } from '@/components/Pages/ChartItemSetting'
|
||
import { useSystemStore } from '@/store/modules/systemStore/systemStore'
|
||
import { useChartLayoutStore } from '@/store/modules/chartLayoutStore/chartLayoutStore'
|
||
import { ChartLayoutStoreEnum } from '@/store/modules/chartLayoutStore/chartLayoutStore.d'
|
||
import { fetchChartComponent, fetchConfigComponent, createComponent } from '@/packages/index'
|
||
import { saveInterval } from '@/settings/designSetting'
|
||
import throttle from 'lodash/throttle'
|
||
// 接口状态
|
||
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 { BaseEvent, EventLife } from '@/enums/eventEnum'
|
||
import { PublicGroupConfigClass } from '@/packages/public/publicConfig'
|
||
import merge from 'lodash/merge'
|
||
|
||
/**
|
||
* * 画布-版本升级对旧数据无法兼容的补丁
|
||
* @param object
|
||
*/
|
||
const canvasVersionUpdatePolyfill = (object: any) => {
|
||
return object
|
||
}
|
||
|
||
/**
|
||
* * 组件-版本升级对旧数据无法兼容的补丁
|
||
* @param newObject
|
||
* @param sources
|
||
*/
|
||
const componentVersionUpdatePolyfill = (newObject: any, sources: any) => {
|
||
try {
|
||
// 判断是否是组件
|
||
if (sources.id) {
|
||
// 处理事件补丁
|
||
const hasVnodeBeforeMount = 'vnodeBeforeMount' in sources.events
|
||
const hasVnodeMounted = 'vnodeMounted' in sources.events
|
||
|
||
if (hasVnodeBeforeMount) {
|
||
newObject.events.advancedEvents.vnodeBeforeMount = sources?.events.vnodeBeforeMount
|
||
}
|
||
if (hasVnodeMounted) {
|
||
newObject.events.advancedEvents.vnodeMounted = sources?.events.vnodeMounted
|
||
}
|
||
if (hasVnodeBeforeMount || hasVnodeMounted) {
|
||
sources.events = {
|
||
baseEvent: {
|
||
[BaseEvent.ON_CLICK]: undefined,
|
||
[BaseEvent.ON_DBL_CLICK]: undefined,
|
||
[BaseEvent.ON_MOUSE_ENTER]: undefined,
|
||
[BaseEvent.ON_MOUSE_LEAVE]: undefined
|
||
},
|
||
advancedEvents: {
|
||
[EventLife.VNODE_MOUNTED]: undefined,
|
||
[EventLife.VNODE_BEFORE_MOUNT]: undefined
|
||
},
|
||
interactEvents: []
|
||
}
|
||
}
|
||
return newObject
|
||
}
|
||
} catch (error) {
|
||
return newObject
|
||
}
|
||
}
|
||
|
||
/**
|
||
* * 合并处理
|
||
* @param newObject 新的模板数据
|
||
* @param sources 新拿到的数据
|
||
* @returns object
|
||
*/
|
||
const componentMerge = (newObject: any, sources: any, notComponent = false) => {
|
||
// 处理组件补丁
|
||
componentVersionUpdatePolyfill(newObject, sources)
|
||
|
||
// 非组件不处理
|
||
if (notComponent) return merge(newObject, sources)
|
||
// 组件排除 newObject
|
||
const option = sources.option
|
||
if (!option) return merge(newObject, sources)
|
||
|
||
// 为 undefined 的 sources 来源对象属性将被跳过详见 https://www.lodashjs.com/docs/lodash.merge
|
||
sources.option = undefined
|
||
if (option) {
|
||
return {
|
||
...merge(newObject, sources),
|
||
option: option
|
||
}
|
||
}
|
||
}
|
||
|
||
// 请求处理
|
||
export const useSync = () => {
|
||
const chartEditStore = useChartEditStore()
|
||
const chartHistoryStore = useChartHistoryStore()
|
||
const systemStore = useSystemStore()
|
||
const chartLayoutStore = useChartLayoutStore()
|
||
/**
|
||
* * 组件动态注册
|
||
* @param projectData 项目数据
|
||
* @param isReplace 是否替换数据
|
||
* @returns
|
||
*/
|
||
const updateComponent = async (projectData: ChartEditStorage, isReplace = false, changeId = false) => {
|
||
if (isReplace) {
|
||
// 清除列表
|
||
chartEditStore.componentList = []
|
||
// 清除历史记录
|
||
chartHistoryStore.clearBackStack()
|
||
chartHistoryStore.clearForwardStack()
|
||
}
|
||
// 画布补丁处理
|
||
projectData.editCanvasConfig = canvasVersionUpdatePolyfill(projectData.editCanvasConfig)
|
||
|
||
// 列表组件注册
|
||
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)
|
||
}
|
||
})
|
||
|
||
// 创建函数-重新创建是为了处理类种方法消失的问题
|
||
const create = async (
|
||
_componentInstance: CreateComponentType,
|
||
callBack?: (componentInstance: CreateComponentType) => void
|
||
) => {
|
||
// 补充 class 上的方法
|
||
let newComponent: CreateComponentType = await createComponent(_componentInstance.chartConfig)
|
||
if (_componentInstance.chartConfig.redirectComponent) {
|
||
_componentInstance.chartConfig.dataset && (newComponent.option.dataset = _componentInstance.chartConfig.dataset)
|
||
newComponent.chartConfig.title = _componentInstance.chartConfig.title
|
||
newComponent.chartConfig.chartFrame = _componentInstance.chartConfig.chartFrame
|
||
}
|
||
if (callBack) {
|
||
if (changeId) {
|
||
callBack(componentMerge(newComponent, { ..._componentInstance, id: getUUID() }))
|
||
} else {
|
||
callBack(componentMerge(newComponent, _componentInstance))
|
||
}
|
||
} else {
|
||
if (changeId) {
|
||
chartEditStore.addComponentList(
|
||
componentMerge(newComponent, { ..._componentInstance, id: getUUID() }),
|
||
false,
|
||
true
|
||
)
|
||
} else {
|
||
chartEditStore.addComponentList(componentMerge(newComponent, _componentInstance), false, true)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 数据赋值
|
||
for (const key in projectData) {
|
||
// 组件
|
||
if (key === ChartEditStoreEnum.COMPONENT_LIST) {
|
||
let loadIndex = 0
|
||
const listLength = projectData[key].length
|
||
for (const comItem of projectData[key]) {
|
||
// 设置加载数量
|
||
let percentage = parseInt((parseFloat(`${++loadIndex / listLength}`) * 100).toString())
|
||
chartLayoutStore.setItemUnHandle(ChartLayoutStoreEnum.PERCENTAGE, percentage)
|
||
// 判断类型
|
||
if (comItem.isGroup) {
|
||
// 创建分组
|
||
let groupClass = new PublicGroupConfigClass()
|
||
if (changeId) {
|
||
groupClass = componentMerge(groupClass, { ...comItem, id: getUUID() })
|
||
} else {
|
||
groupClass = componentMerge(groupClass, comItem)
|
||
}
|
||
|
||
// 异步注册子应用
|
||
const targetList: CreateComponentType[] = []
|
||
for (const groupItem of (comItem as CreateComponentGroupType).groupList) {
|
||
await create(groupItem, e => {
|
||
targetList.push(e)
|
||
})
|
||
}
|
||
groupClass.groupList = targetList
|
||
|
||
// 分组插入到列表
|
||
chartEditStore.addComponentList(groupClass, false, true)
|
||
} else {
|
||
await create(comItem as CreateComponentType)
|
||
}
|
||
if (percentage === 100) {
|
||
// 清除历史记录
|
||
chartHistoryStore.clearBackStack()
|
||
chartHistoryStore.clearForwardStack()
|
||
}
|
||
}
|
||
} else {
|
||
// 非组件(顺便排除脏数据)
|
||
if (key !== 'editCanvasConfig' && key !== 'requestGlobalConfig') return
|
||
componentMerge(chartEditStore[key], projectData[key], true)
|
||
}
|
||
}
|
||
|
||
// 清除数量
|
||
chartLayoutStore.setItemUnHandle(ChartLayoutStoreEnum.PERCENTAGE, 0)
|
||
}
|
||
|
||
/**
|
||
* * 赋值全局数据
|
||
* @param projectData 项目数据
|
||
* @returns
|
||
*/
|
||
const updateStoreInfo = (projectData: {
|
||
id: string,
|
||
projectName: string,
|
||
indexImage: string,
|
||
remarks: string,
|
||
state: number
|
||
}) => {
|
||
const { id, projectName, remarks, indexImage, state } = projectData
|
||
// ID
|
||
chartEditStore.setProjectInfo(ProjectInfoEnum.PROJECT_ID, id)
|
||
// 名称
|
||
chartEditStore.setProjectInfo(ProjectInfoEnum.PROJECT_NAME, projectName)
|
||
// 描述
|
||
chartEditStore.setProjectInfo(ProjectInfoEnum.REMARKS, remarks)
|
||
// 缩略图
|
||
chartEditStore.setProjectInfo(ProjectInfoEnum.THUMBNAIL, indexImage)
|
||
// 发布
|
||
chartEditStore.setProjectInfo(ProjectInfoEnum.RELEASE, state === 1)
|
||
}
|
||
|
||
// * 数据获取
|
||
const dataSyncFetch = async () => {
|
||
// FIX:重新执行dataSyncFetch需清空chartEditStore.componentList,否则会导致图层重复
|
||
// 切换语言等操作会导致重新执行 dataSyncFetch,此时pinia中并未清空chartEditStore.componentList,导致图层重复
|
||
chartEditStore.componentList = []
|
||
chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.START)
|
||
try {
|
||
const res = await fetchProjectApi({ projectId: fetchRouteParamsLocation() })
|
||
if (res && res.code === ResultEnum.SUCCESS) {
|
||
if (res.data) {
|
||
updateStoreInfo(res.data)
|
||
// 更新全局数据
|
||
await updateComponent(JSONParse(res.data.content))
|
||
return
|
||
}else {
|
||
chartEditStore.setProjectInfo(ProjectInfoEnum.PROJECT_ID, fetchRouteParamsLocation())
|
||
}
|
||
setTimeout(() => {
|
||
chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.SUCCESS)
|
||
}, 1000)
|
||
return
|
||
}
|
||
chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.FAILURE)
|
||
} catch (error) {
|
||
chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.FAILURE)
|
||
httpErrorHandle()
|
||
}
|
||
}
|
||
|
||
// * 数据保存
|
||
const dataSyncUpdate = throttle(async (updateImg = true) => {
|
||
if(!fetchRouteParamsLocation()) return
|
||
|
||
let projectId = chartEditStore.getProjectInfo[ProjectInfoEnum.PROJECT_ID];
|
||
if(projectId === null || projectId === ''){
|
||
window['$message'].error('数据初未始化成功,请刷新页面!')
|
||
return
|
||
}
|
||
|
||
chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.START)
|
||
|
||
// 异常处理:缩略图上传失败不影响JSON的保存
|
||
try {
|
||
if (updateImg) {
|
||
// 获取缩略图片
|
||
const range = document.querySelector('.go-edit-range') as HTMLElement
|
||
// 生成图片
|
||
const canvasImage: HTMLCanvasElement = await html2canvas(range, {
|
||
backgroundColor: null,
|
||
allowTaint: true,
|
||
useCORS: true
|
||
})
|
||
|
||
// 上传预览图
|
||
let uploadParams = new FormData()
|
||
uploadParams.append('object', base64toFile(canvasImage.toDataURL(), `${fetchRouteParamsLocation()}_index_preview.png`))
|
||
const uploadRes = await uploadFile(uploadParams)
|
||
// 保存预览图
|
||
if(uploadRes && uploadRes.code === ResultEnum.SUCCESS) {
|
||
if (uploadRes.data.fileurl) {
|
||
await updateProjectApi({
|
||
id: fetchRouteParamsLocation(),
|
||
indexImage: `${uploadRes.data.fileurl}`
|
||
})
|
||
} else {
|
||
await updateProjectApi({
|
||
id: fetchRouteParamsLocation(),
|
||
indexImage: `${systemStore.getFetchInfo.OSSUrl}${uploadRes.data.fileName}`
|
||
})
|
||
}
|
||
}
|
||
}
|
||
} catch (e) {
|
||
console.log(e)
|
||
}
|
||
|
||
// 保存数据
|
||
let params = new FormData()
|
||
params.append('projectId', projectId)
|
||
params.append('content', JSONStringify(chartEditStore.getStorageInfo || {}))
|
||
const res= await saveProjectApi(params)
|
||
|
||
if (res && res.code === ResultEnum.SUCCESS) {
|
||
// 成功状态
|
||
setTimeout(() => {
|
||
chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.SUCCESS)
|
||
}, 1000)
|
||
return
|
||
}
|
||
// 失败状态
|
||
chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.FAILURE)
|
||
}, 3000)
|
||
|
||
// * 定时处理
|
||
const intervalDataSyncUpdate = () => {
|
||
// 定时获取数据
|
||
const syncTiming = setInterval(() => {
|
||
dataSyncUpdate()
|
||
}, saveInterval * 1000)
|
||
|
||
// 销毁
|
||
onUnmounted(() => {
|
||
clearInterval(syncTiming)
|
||
})
|
||
}
|
||
|
||
return {
|
||
updateComponent,
|
||
updateStoreInfo,
|
||
dataSyncFetch,
|
||
dataSyncUpdate,
|
||
intervalDataSyncUpdate
|
||
}
|
||
}
|