CompTree.tsx 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. import { TreeToolbars } from "@/modules/editor/objects/Toolbars";
  2. import { css } from "@linaria/core";
  3. import { Image } from "@queenjs/ui";
  4. import { useReactive } from "@queenjs/use";
  5. import { Tree, TreeProps } from "ant-design-vue";
  6. import { defineComponent, nextTick, watch } from "vue";
  7. import { string, bool } from "vue-types";
  8. import { useEditor } from "../../../..";
  9. import { DesignComp } from "../../../../objects/DesignTemp/DesignComp";
  10. import { TreeDataItem } from "ant-design-vue/lib/tree";
  11. import { CompObject } from "@/modules/editor/controllers/SelectCtrl/compObj";
  12. type TreeItem = {
  13. key: string;
  14. title: string;
  15. value: string;
  16. children: TreeItem[];
  17. };
  18. export const CompTree = defineComponent({
  19. setup() {
  20. const { store, actions, helper, controls } = useEditor();
  21. const { compUICtrl } = controls;
  22. const state = useReactive(() => ({
  23. expandedKeys: [] as string[],
  24. treeData() {
  25. const rootComp = helper.findRootComp();
  26. let deep = 0;
  27. function getCompChildren(ids: string[]): TreeItem[] {
  28. deep += 1;
  29. if (deep >2 ) ids = ids.reverse();
  30. return ids.map((id) => {
  31. const comp = helper.findComp(id) as DesignComp;
  32. return {
  33. key: comp.id,
  34. title:
  35. comp.title ||
  36. compUICtrl.state.components.get(comp.compKey)?.name ||
  37. "未命名",
  38. value: comp.id,
  39. children: getCompChildren(
  40. comp.getChildIds(),
  41. ),
  42. };
  43. });
  44. }
  45. return getCompChildren(rootComp?.id ? [rootComp.id] : []);
  46. },
  47. }));
  48. watch(
  49. () => store.currCompId,
  50. () => {
  51. // expandedKeys需要等Tree的内部状态更新后再赋值
  52. nextTick(() => {
  53. state.expandedKeys = store.currCompId
  54. ? helper.getCompTrees(store.currCompId).map((comp) => comp.id)
  55. : [];
  56. });
  57. }
  58. );
  59. const onDrop = (info: any) => {
  60. const dragNode = info.dragNode; //被拖拽
  61. const dropNode = info.node; //拖拽落下
  62. const dragKey = dragNode.key;
  63. const dropKey = dropNode.key;
  64. const dragPos = dragNode.pos.split("-");
  65. const dropPos = dropNode.pos.split("-");
  66. const dragLevel = dragPos.length;
  67. const dropLevel = dropPos.length;
  68. if (
  69. dragLevel >= 5 ||
  70. dragKey == "root" ||
  71. dragLevel < dropLevel ||
  72. dragLevel - dropLevel > 1
  73. ) {
  74. return;
  75. }
  76. let parentComp: any = null;
  77. if (dragLevel > dropLevel) {
  78. parentComp = helper.findComp(dropKey);
  79. } else {
  80. parentComp = helper.findParentComp(dropKey);
  81. }
  82. const currComp = helper.findComp(dragKey);
  83. const currParent = helper.findParentComp(dragKey);
  84. if (!currComp) return;
  85. const currParentComp = helper.findParentComp(dragKey);
  86. const index = currParentComp?.children.default?.indexOf(currComp.id);
  87. if (index != -1) {
  88. currParentComp?.children.default?.splice(index as number, 1);
  89. helper.extendStreamCard(currParentComp?.id || "");
  90. }
  91. actions.pickComp("");
  92. if (!info.dropToGap) {
  93. parentComp?.children.default == parentComp?.children.default || [];
  94. if (currComp.compKey == "Container") {
  95. parentComp?.children.default?.unshift(currComp?.id);
  96. } else {
  97. parentComp?.children.default?.push(currComp?.id);
  98. }
  99. if (currParent?.id != parentComp.id) {
  100. const len = parentComp?.children.default?.length;
  101. const index = currComp.compKey == "Container" ? 0 : len - 1;
  102. const revert = currComp.compKey == "Container" ? false : true;
  103. sortCompInCard(parentComp, index, revert);
  104. }
  105. } else {
  106. if (currComp.compKey == "Container") {
  107. parentComp?.children.default?.splice(
  108. info.dropPosition,
  109. 0,
  110. currComp.id
  111. );
  112. } else {
  113. const len = parentComp?.children.default.length;
  114. parentComp?.children.default?.splice(
  115. len - info.dropPosition,
  116. 0,
  117. currComp.id
  118. );
  119. }
  120. if (currParent?.id != parentComp.id) {
  121. const revert = currComp.compKey == "Container" ? false : true;
  122. sortCompInCard(parentComp, info.dropPosition, revert);
  123. }
  124. }
  125. nextTick(() => {
  126. actions.pickComp(currComp.id);
  127. helper.extendStreamCard(parentComp.id);
  128. });
  129. };
  130. const sortCompInCard = (
  131. parentComp: DesignComp,
  132. index: number,
  133. revert = false
  134. ) => {
  135. if (parentComp?.compKey != "Container") {
  136. return;
  137. }
  138. const children = parentComp.children.default || [];
  139. if (children?.length > 0) {
  140. const prveCompId = revert ? children[index + 1] : children[index - 1];
  141. const nowCompId = children[index];
  142. const nowComp = helper.findComp(nowCompId);
  143. if (!prveCompId) {
  144. const nowCompBound = helper.getCardCompBound(nowCompId);
  145. if (!nowComp) {
  146. return;
  147. }
  148. const nowObj = new CompObject(nowComp);
  149. nowObj.worldTransform.translate(-nowCompBound.x, -nowCompBound.y);
  150. nowComp.layout.transformMatrix = nowObj.worldTransform.getMatrixStr();
  151. return;
  152. }
  153. const prevCompBound = helper.getCardCompBound(prveCompId);
  154. const prevComp = helper.findComp(prveCompId);
  155. if (!prevComp || !nowComp) {
  156. return;
  157. }
  158. const obj = new CompObject(prevComp);
  159. const yOffset = prevCompBound.h;
  160. obj.worldTransform.translate(0, yOffset);
  161. nowComp.layout.transformMatrix = obj.worldTransform.getMatrixStr();
  162. }
  163. };
  164. return () => (
  165. <div class="!overflow-x-auto">
  166. <Tree
  167. class={treeStyle}
  168. treeData={state.treeData}
  169. v-model={[state.expandedKeys, "expandedKeys"]}
  170. selectedKeys={[store.currCompId]}
  171. blockNode={true}
  172. draggable={true}
  173. onDrop={onDrop}
  174. onSelect={(ids) => {
  175. const id =
  176. (ids[0] as string) || state.expandedKeys.at(-2) || "root";
  177. actions.pickComp(id);
  178. }}
  179. >
  180. {{
  181. title: (data: any) => {
  182. return <CompNode title={data.title} id={data.key} />;
  183. },
  184. }}
  185. </Tree>
  186. </div>
  187. );
  188. },
  189. });
  190. const CompNode = defineComponent({
  191. props: {
  192. id: string().isRequired,
  193. title: string().isRequired,
  194. },
  195. setup(props) {
  196. const editor = useEditor();
  197. const comp = editor.helper.findComp(props.id);
  198. return () => {
  199. if (!comp) return;
  200. const compOpts = editor.controls.compUICtrl.state.components.get(
  201. comp.compKey
  202. );
  203. const actions = TreeToolbars[comp.compKey] || TreeToolbars.default;
  204. const thumbnail =
  205. comp.compKey === "Image"
  206. ? comp.value.url
  207. : comp.thumbnail || compOpts?.thumbnail;
  208. return (
  209. <div class={nodeStyle}>
  210. <Image src={thumbnail} size={240} />
  211. <span class="w-1/1 flex-1 whitespace-nowrap mr-30px">
  212. {props.title}
  213. </span>
  214. <span class="space-x-4px whitespace-nowrap">
  215. {actions.map((action, i) =>
  216. action.getVisible.call(editor, comp) ? (
  217. <action.component
  218. key={i}
  219. class="p-4px"
  220. value={action.getValue?.(comp)}
  221. onClick={(e: MouseEvent) => {
  222. e.stopPropagation();
  223. action.onClick.call(editor, comp);
  224. }}
  225. />
  226. ) : null
  227. )}
  228. </span>
  229. </div>
  230. );
  231. };
  232. },
  233. });
  234. const treeStyle = css`
  235. .ant-tree-switcher {
  236. display: flex;
  237. justify-content: center;
  238. align-items: center;
  239. }
  240. `;
  241. const nodeStyle = css`
  242. display: flex;
  243. align-items: center;
  244. padding: 6px;
  245. @apply rounded;
  246. > img {
  247. width: 24px;
  248. height: 24px;
  249. margin-right: 6px;
  250. object-fit: contain;
  251. }
  252. `;