project.ts 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. import type { ProjectInfo, Page, ReferLine, CustomElement } from "#/project";
  2. import type { ComponentType } from "@/components";
  3. import { defineStore } from "pinia";
  4. import componentAll from "@/components";
  5. import { ScreenFillEnum } from "@/enum/screenFillEnum";
  6. import { update, defaultsDeep } from "lodash";
  7. import { getNormalizedContainer } from "@/utils/common";
  8. type ProjectState = {
  9. projectInfo: ProjectInfo;
  10. activePageIndex: number;
  11. addCompData: {
  12. key: number;
  13. name: string;
  14. componentType: ComponentType;
  15. container: {
  16. style: Record<string, any>;
  17. props: Record<string, any>;
  18. };
  19. } | null;
  20. mode: "edit" | "preview";
  21. selectedElementKeys: number[];
  22. };
  23. const defaultPage: Page = {
  24. name: "页面1",
  25. background: {
  26. type: "color",
  27. color: "#0b074b",
  28. image: "",
  29. fillType: "",
  30. },
  31. elements: [],
  32. referLines: [],
  33. };
  34. const CURRENT_PROJECT = "currentProject";
  35. export const useProjectStore = defineStore({
  36. id: "project",
  37. state: (): ProjectState => ({
  38. // 项目信息
  39. projectInfo: {
  40. name: "",
  41. description: "",
  42. sizeType: "",
  43. width: 0,
  44. height: 0,
  45. fillType: ScreenFillEnum.Auto,
  46. pages: [{ ...defaultPage }],
  47. },
  48. // 当前编辑页面索引
  49. activePageIndex: 0,
  50. // 添加组件临时数据
  51. addCompData: null,
  52. // 视图模式
  53. mode: "edit",
  54. // 选中的元素
  55. selectedElementKeys: [],
  56. }),
  57. getters: {
  58. referLines(state) {
  59. return state.projectInfo.pages[state.activePageIndex].referLines;
  60. },
  61. elements(state) {
  62. return state.projectInfo.pages[state.activePageIndex].elements;
  63. },
  64. currentPage(state) {
  65. return state.projectInfo.pages[state.activePageIndex];
  66. },
  67. },
  68. actions: {
  69. setProjectInfo(info: any) {
  70. Object.assign(this.projectInfo, info);
  71. localStorage.setItem(CURRENT_PROJECT, JSON.stringify(info));
  72. },
  73. getCurrentProjectInfo(): ProjectInfo | undefined {
  74. const info = JSON.parse(localStorage.getItem(CURRENT_PROJECT) || "");
  75. this.setProjectInfo(info as unknown as ProjectInfo);
  76. return info;
  77. },
  78. addReferLine(line: ReferLine) {
  79. this.projectInfo.pages[this.activePageIndex].referLines.push(line);
  80. },
  81. removeReferLine(key: number) {
  82. const index = this.referLines.findIndex((line) => line.key === key);
  83. index !== -1 &&
  84. this.projectInfo.pages[this.activePageIndex].referLines.splice(
  85. index,
  86. 1
  87. );
  88. },
  89. updateReferLine(line: ReferLine) {
  90. const index = this.referLines.findIndex((l) => l.key === line.key);
  91. if (index !== -1) {
  92. this.projectInfo.pages[this.activePageIndex].referLines[index] = line;
  93. }
  94. },
  95. // 添加组件
  96. async addElement(element: any) {
  97. this.addCompData = null;
  98. if (!element) return;
  99. const elements = this.projectInfo.pages[this.activePageIndex].elements;
  100. // 获取每个自定义组件暴露出来的属性
  101. const { defaultPropsValue } =
  102. (await componentAll[element.componentType as ComponentType]?.()) || {};
  103. const { width = 400, height = 260 } = defaultPropsValue?.container?.props || {};
  104. const { props: containerProps = {}, style = {} } = defaultPropsValue?.container || {};
  105. const index =
  106. elements.filter((item) => item.componentType === element.componentType)
  107. .length + 1;
  108. const { x, y } = element.container.props;
  109. const container = getNormalizedContainer({
  110. style,
  111. props: {
  112. ...containerProps,
  113. width,
  114. height,
  115. x: x - width / 2,
  116. y: y - height / 2,
  117. },
  118. });
  119. // 添加组件
  120. this.projectInfo.pages[this.activePageIndex].elements.push({
  121. ...defaultsDeep(element, defaultPropsValue),
  122. name: element.name + index,
  123. zIndex: elements.length + 1,
  124. visible: true,
  125. locked: false,
  126. container,
  127. });
  128. this.selectedElementKeys = [element.key];
  129. },
  130. // 更新组件
  131. updateElement(key: number, path: string, payload: any) {
  132. const element = this.projectInfo.pages[
  133. this.activePageIndex
  134. ].elements.find((item) => item.key === key);
  135. // 如果是锁定状态不能修改宽高 位置
  136. if (
  137. element &&
  138. element.locked &&
  139. [
  140. "container.props.width",
  141. "container.props.height",
  142. "container.props.x",
  143. "container.props.y",
  144. ].includes(path)
  145. )
  146. return;
  147. if (element) {
  148. update(element, path, () => payload);
  149. }
  150. },
  151. // 删除组件
  152. removeElement(key: number) {
  153. const index = this.projectInfo.pages[
  154. this.activePageIndex
  155. ].elements.findIndex((item) => item.key === key);
  156. if (index !== -1) {
  157. this.projectInfo.pages[this.activePageIndex].elements.splice(index, 1);
  158. }
  159. },
  160. // 设置临时添加组件数据
  161. setAddCompData(data: any) {
  162. this.addCompData = data;
  163. },
  164. // 清除临时添加组件数据
  165. clearAddCompData() {
  166. this.addCompData = null;
  167. },
  168. setMode(mode: "edit" | "preview") {
  169. this.mode = mode;
  170. },
  171. // 设置选中的元素
  172. setSelectedElementKeys(keys: number[]) {
  173. this.selectedElementKeys = keys;
  174. },
  175. // 删除所有选中的元素
  176. clearAllSelectedElement() {
  177. this.selectedElementKeys = [];
  178. },
  179. },
  180. });