import type { ProjectInfo, Page, ReferLine } from "#/project"; import { defineStore } from "pinia"; import { asyncComponentAll } from "shalu-dashboard-ui"; import { ScreenFillEnum } from "@/enum/screenFillEnum"; import { update, defaultsDeep } from "lodash"; import { getNormalizedContainer } from "@/utils/common"; import { editPageDesignApi } from "@/api/index"; import { message } from "ant-design-vue"; type ProjectState = { projectInfo: ProjectInfo; activePageIndex: number; addCompData: { key: number; name: string; componentType: string; container: { style: Record; props: Record; }; } | null; mode: "edit" | "player"; selectedElementKeys: number[]; }; const defaultPage: Page = { key: "1", name: "页面1", background: { type: "color", color: "#0B074BFF", image: "", fillType: "", }, elements: [], referLines: [], }; const CURRENT_PROJECT = "currentProject"; export const useProjectStore = defineStore({ id: "project", state: (): ProjectState => ({ // 项目信息 projectInfo: { pageId: "", name: "", description: "", sizeType: "", width: 0, height: 0, fillType: ScreenFillEnum.AUTO, pages: [{ ...defaultPage }], }, // 当前编辑页面索引 activePageIndex: 0, // 添加组件临时数据 addCompData: null, // 视图模式 mode: "edit", // 选中的元素 selectedElementKeys: [], }), getters: { referLines(state) { return state.projectInfo.pages[state.activePageIndex].referLines; }, elements(state) { return state.projectInfo.pages[state.activePageIndex].elements; }, currentPage(state) { return state.projectInfo.pages[state.activePageIndex]; }, currentSelectedElements(state) { return state.projectInfo.pages[state.activePageIndex].elements.filter( (item) => state.selectedElementKeys.includes(item.key) ); }, }, actions: { setProjectInfo(info: any) { Object.assign(this.projectInfo, info); localStorage.setItem(CURRENT_PROJECT, JSON.stringify(info)); }, getCurrentProjectInfo(): ProjectInfo | undefined { let info = JSON.parse(localStorage.getItem(CURRENT_PROJECT) || "null"); if (!info) { info = { name: "默认项目", description: "这是一个默认项目", sizeType: "custom", width: 1280, height: 720, fillType: ScreenFillEnum.AUTO, pages: [{ ...defaultPage }], }; } this.setProjectInfo(info as unknown as ProjectInfo); return info; }, updateProjectInfo(info: any) { Object.assign(this.projectInfo, info); }, updateProjectInfoByPath(path: string, payload: any) { update(this.projectInfo, path, () => payload); }, addReferLine(line: ReferLine) { this.projectInfo.pages[this.activePageIndex].referLines.push(line); }, removeReferLine(key: number) { const index = this.referLines.findIndex((line) => line.key === key); index !== -1 && this.projectInfo.pages[this.activePageIndex].referLines.splice( index, 1 ); }, updateReferLine(line: ReferLine) { const index = this.referLines.findIndex((l) => l.key === line.key); if (index !== -1) { this.projectInfo.pages[this.activePageIndex].referLines[index] = line; } }, // 添加组件 async addElement(element: any) { this.addCompData = null; if (!element) return; const elements = this.projectInfo.pages[this.activePageIndex].elements; // 获取每个自定义组件暴露出来的默认属性 const { defaultPropsValue } = (await asyncComponentAll[element.componentType]?.()) || {}; const { width = 400, height = 260 } = defaultPropsValue?.container?.props || {}; const { props: containerProps = {}, style = {} } = defaultPropsValue?.container || {}; const index = elements.filter((item) => item.componentType === element.componentType) .length + 1; const { x, y } = element.container.props; const container = getNormalizedContainer({ style, props: { ...containerProps, width, height, x: x - width / 2, y: y - height / 2, }, }); // 添加组件 this.projectInfo.pages[this.activePageIndex].elements.push({ ...defaultsDeep(element, defaultPropsValue), name: element.name + index, zIndex: elements.length + 1, visible: true, locked: false, container, }); this.selectedElementKeys = [element.key]; }, // 更新组件 updateElement(key: number, path: string, payload: any) { const pageIndex = this.activePageIndex; const element = this.projectInfo.pages[pageIndex].elements.find((item) => item.key === key); const elementIndex = this.projectInfo.pages[pageIndex].elements.findIndex((item) => item.key === key); // 如果是锁定状态不能修改宽高 位置 if ( element && element.locked && [ "container.props.width", "container.props.height", "container.props.x", "container.props.y", ].includes(path) ) return; if (element) { update(this.projectInfo.pages[pageIndex].elements[elementIndex], path, () => payload); } }, // 删除组件 removeElement(key: number) { const index = this.projectInfo.pages[ this.activePageIndex ].elements.findIndex((item) => item.key === key); if (index !== -1) { this.projectInfo.pages[this.activePageIndex].elements.splice(index, 1); } }, // 设置临时添加组件数据 setAddCompData(data: any) { this.addCompData = data; }, // 清除临时添加组件数据 clearAddCompData() { this.addCompData = null; }, setMode(mode: "edit" | "player") { this.mode = mode; }, // 设置选中的元素 setSelectedElementKeys(keys: number[]) { this.selectedElementKeys = keys; }, // 删除所有选中的元素 clearAllSelectedElement() { this.selectedElementKeys = []; }, // 设置当前页面背景 setCurrentPageBackground(background: any) { this.projectInfo.pages[this.activePageIndex].background = background; }, setFillType(fillType: ScreenFillEnum) { this.projectInfo.fillType = fillType; }, // 保存当前项目到服务器 async handleSaveProject() { const params = { appPageId: this.projectInfo.pageId, json: JSON.stringify(this.projectInfo), html: "", js: "", type: 0, }; editPageDesignApi(params); message.success("保存成功"); }, }, });