CompTree.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. import { CompObject } from "@/modules/editor/controllers/SelectCtrl/compObj";
  2. import { TreeToolbars } from "@/modules/editor/objects/Toolbars";
  3. import { css } from "@linaria/core";
  4. import { Image } from "@queenjs/ui";
  5. import { useReactive } from "@queenjs/use";
  6. import { Tree } from "ant-design-vue";
  7. import { defineComponent, watch } from "vue";
  8. import { string } from "vue-types";
  9. import { useEditor } from "../../../..";
  10. import { DesignComp } from "../../../../objects/DesignTemp/DesignComp";
  11. type TreeItem = {
  12. key: string;
  13. title: string;
  14. value: string;
  15. children: TreeItem[];
  16. };
  17. export const CompTree = defineComponent({
  18. setup() {
  19. const { store, actions, helper, controls } = useEditor();
  20. const { compUICtrl } = controls;
  21. const state = useReactive(() => ({
  22. expandedKeys: [] as string[],
  23. treeData() {
  24. const rootComp = helper.findRootComp();
  25. function getCompChildren(ids: string[]): TreeItem[] {
  26. return ids.map((id) => {
  27. const comp = helper.findComp(id) as DesignComp;
  28. return {
  29. key: comp.id,
  30. title:
  31. comp.title ||
  32. compUICtrl.state.components.get(comp.compKey)?.name ||
  33. "未命名",
  34. value: comp.id,
  35. children: getCompChildren(comp.getChildIds()),
  36. };
  37. });
  38. }
  39. return getCompChildren(rootComp?.id ? [rootComp.id] : []);
  40. },
  41. }));
  42. watch(
  43. () => store.currCompId,
  44. () => {
  45. state.expandedKeys = store.currCompId
  46. ? helper.getCompTrees(store.currCompId).map((comp) => comp.id)
  47. : [];
  48. }
  49. );
  50. return () => {
  51. return (
  52. <Tree
  53. class={treeStyle}
  54. treeData={state.treeData}
  55. v-model={[state.expandedKeys, "expandedKeys"]}
  56. selectedKeys={[store.currCompId]}
  57. blockNode={true}
  58. onSelect={(ids) => {
  59. const id =
  60. (ids[0] as string) || state.expandedKeys.at(-2) || "root";
  61. if (helper.isStreamCardChild(id)) {
  62. controls.selectCtrl.selecteObjs([
  63. new CompObject(store.compMap[id]),
  64. ]);
  65. return;
  66. }
  67. actions.pickComp(id);
  68. }}
  69. >
  70. {{
  71. title: (data: any) => {
  72. return <CompNode title={data.title} id={data.key} />;
  73. },
  74. }}
  75. </Tree>
  76. );
  77. };
  78. },
  79. });
  80. const CompNode = defineComponent({
  81. props: {
  82. id: string().isRequired,
  83. title: string().isRequired,
  84. },
  85. setup(props) {
  86. const editor = useEditor();
  87. const comp = editor.helper.findComp(props.id);
  88. return () => {
  89. if (!comp) return;
  90. const compOpts = editor.controls.compUICtrl.state.components.get(
  91. comp.compKey
  92. );
  93. const actions = TreeToolbars[comp.compKey] || TreeToolbars.default;
  94. const thumbnail =
  95. comp.compKey === "Image"
  96. ? comp.value.url
  97. : comp.thumbnail || compOpts?.thumbnail;
  98. return (
  99. <div class={nodeStyle}>
  100. <Image src={thumbnail} size={240} />
  101. <span class="w-0 flex-1 truncate">{props.title}</span>
  102. <span class="space-x-4px">
  103. {actions.map((action) =>
  104. action.getVisible.call(editor, comp) ? (
  105. <action.component
  106. class="p-4px"
  107. key={comp.id}
  108. value={action.getValue?.(comp)}
  109. onClick={(e: MouseEvent) => {
  110. e.stopPropagation();
  111. action.onClick.call(editor, comp);
  112. }}
  113. />
  114. ) : null
  115. )}
  116. </span>
  117. </div>
  118. );
  119. };
  120. },
  121. });
  122. const treeStyle = css`
  123. .ant-tree-switcher {
  124. display: flex;
  125. justify-content: center;
  126. align-items: center;
  127. }
  128. `;
  129. const nodeStyle = css`
  130. display: flex;
  131. align-items: center;
  132. padding: 6px;
  133. @apply rounded;
  134. > img {
  135. width: 24px;
  136. height: 24px;
  137. margin-right: 6px;
  138. object-fit: contain;
  139. }
  140. `;