lianghongjie 1 年間 前
コミット
f4dfc7bb87
28 ファイル変更326 行追加217 行削除
  1. 6 1
      src/modules/editor/components/CompUI/basicUI/Image/component.tsx
  2. 63 0
      src/modules/editor/components/CompUI/basicUI/Transfer/RingBtns.tsx
  3. 45 41
      src/modules/editor/components/CompUI/basicUI/Transfer/index.tsx
  4. 29 52
      src/modules/editor/components/CompUI/basicUI/View.tsx
  5. 1 1
      src/modules/editor/components/CompUI/customUI/Cards/Card11/component.tsx
  6. 1 1
      src/modules/editor/components/CompUI/customUI/Cards/CardList/component.tsx
  7. 2 2
      src/modules/editor/components/CompUI/customUI/Titles/Title1/component.tsx
  8. 6 5
      src/modules/editor/components/CompUI/defines/createAttrsForm.tsx
  9. 2 2
      src/modules/editor/components/CompUI/defines/createCompHooks.ts
  10. 35 5
      src/modules/editor/components/CompUI/defines/createCompId.ts
  11. 1 1
      src/modules/editor/components/Preview/index.tsx
  12. 0 0
      src/modules/editor/components/TipIcons/TipIcon.tsx
  13. 2 3
      src/modules/editor/components/TipIcons/create.ts
  14. 7 7
      src/modules/editor/components/TipIcons/index.ts
  15. 7 6
      src/modules/editor/components/Viewport/Content/index.tsx
  16. 17 16
      src/modules/editor/components/Viewport/Slider/SliderRight/CompTree.tsx
  17. 6 10
      src/modules/editor/components/Viewport/Slider/SliderRight/index.tsx
  18. 1 1
      src/modules/editor/components/Viewport/index.tsx
  19. 1 1
      src/modules/editor/components/index.ts
  20. 0 9
      src/modules/editor/configs/index.ts
  21. 20 18
      src/modules/editor/module/helpers/index.ts
  22. 6 4
      src/modules/editor/module/index.ts
  23. 3 3
      src/modules/editor/module/stores/index.ts
  24. 1 0
      src/modules/editor/objects/DesignTemp/DesignComp.ts
  25. 39 21
      src/modules/editor/objects/DesignTemp/versions/0.0.1.ts
  26. 6 6
      src/modules/editor/objects/TreeNode/treeNodeActions.ts
  27. 1 1
      src/modules/editor/typings.ts
  28. 18 0
      src/utils/index.ts

+ 6 - 1
src/modules/editor/components/CompUI/basicUI/Image/component.tsx

@@ -3,6 +3,7 @@ import { defineComponent } from "vue";
 import { object, string } from "vue-types";
 import { useCompData } from ".";
 import { View } from "../View";
+import { css } from "@linaria/core";
 
 export const Component = defineComponent({
   props: {
@@ -43,7 +44,7 @@ export const Component = defineComponent({
           onDblclick={store.isEditMode ? changeVal : undefined}
         >
           <img
-            class={"w-1/1 h-1/1 object-cover pointer-events-none"}
+            class={imgStyle}
             style={{
               transform: `scale(${scale}) translate(${ox}%,${oy}%)`,
               objectFit,
@@ -55,3 +56,7 @@ export const Component = defineComponent({
     };
   },
 });
+
+const imgStyle = css`
+  @apply overflow-hidden object-cover pointer-events-none;
+`;

+ 63 - 0
src/modules/editor/components/CompUI/basicUI/Transfer/RingBtns.tsx

@@ -0,0 +1,63 @@
+import { css } from "@linaria/core";
+import { defineComponent } from "vue";
+
+export default defineComponent({
+  setup() {
+    const btns = ["up", "right", "bottom", "left"];
+    return () => (
+      <div class={rootStyle}>
+        {btns.map((_, i) => {
+          return (
+            <div
+              class="fanBtn"
+              style={{ transform: `rotate(${(360 / btns.length) * i}deg)` }}
+            >
+              ↑
+            </div>
+          );
+        })}
+        <div class="resetBtn">复位</div>
+      </div>
+    );
+  },
+});
+
+const rootStyle = css`
+  position: relative;
+  width: 48px;
+  height: 48px;
+  border-radius: 50%;
+  background: #eee;
+  overflow: hidden;
+
+  @apply shadow;
+
+  .fanBtn {
+    position: absolute;
+    width: 48px;
+    height: 48px;
+
+    background-color: #fff;
+    font-size: 12px;
+    text-align: center;
+    clip-path: polygon(1% 0, 50% 49%, 99% 0);
+    &:hover {
+      background: @inf-primary-color;
+    }
+  }
+
+  .resetBtn {
+    position: absolute;
+    width: 28px;
+    height: 28px;
+    text-align: center;
+    line-height: 28px;
+    border-radius: 50%;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    background: #fff;
+    font-size: 12px;
+    @apply shadow;
+  }
+`;

+ 45 - 41
src/modules/editor/components/CompUI/basicUI/Transfer.tsx → src/modules/editor/components/CompUI/basicUI/Transfer/index.tsx

@@ -1,7 +1,8 @@
 import { css } from "@linaria/core";
 import { defineComponent, onMounted, ref } from "vue";
 import { string } from "vue-types";
-import { useEditor } from "../../..";
+import { useEditor } from "../../../..";
+import RingBtns from "./RingBtns";
 
 export const Transfer = defineComponent({
   props: {
@@ -21,18 +22,13 @@ export const Transfer = defineComponent({
     };
 
     const comp = store.designData.compMap[props.compId];
-    let parentCompEl: HTMLElement;
+    let compEl: HTMLElement;
 
     onMounted(() => {
       if (!resizeRef.value || !moveRef.value) return;
       resizeRef.value.addEventListener("mousedown", startDrag);
       moveRef.value.addEventListener("mousedown", startMove);
-      const parentContentEl = getClosestParentWithClass(
-        resizeRef.value,
-        "view_content"
-      );
-      if (!parentContentEl) return;
-      parentCompEl = parentContentEl;
+      compEl = moveRef.value.parentElement as HTMLElement;
     });
 
     function startMove(e: MouseEvent) {
@@ -43,7 +39,7 @@ export const Transfer = defineComponent({
       document.addEventListener("mouseup", stopMove);
     }
     function move(e: MouseEvent) {
-      const viewEl = parentCompEl.parentElement;
+      const viewEl = compEl.parentElement;
       if (!viewEl) return;
       start.offsetX = e.clientX - start.x;
       start.offsetY = e.clientY - start.y;
@@ -65,20 +61,21 @@ export const Transfer = defineComponent({
     function startDrag(e: MouseEvent) {
       start.x = e.clientX;
       start.y = e.clientY;
-      start.width = comp.layout.size?.[0] || 0;
-      start.height = comp.layout.size?.[1] || 0;
+      start.width = comp.layout.size?.[0] || compEl.clientWidth * 2;
+      start.height = comp.layout.size?.[1] || compEl.clientHeight * 2;
 
       document.addEventListener("mousemove", drag);
       document.addEventListener("mouseup", stopDrag);
     }
 
     function drag(e: MouseEvent) {
+      console.log(e.clientX, e.clientY);
       start.offsetX = e.clientX - start.x;
       start.offsetY = e.clientY - start.y;
-      parentCompEl.style.width = helper.designToNaturalSize(
+      compEl.style.width = helper.designToNaturalSize(
         start.width + start.offsetX * 2
       );
-      parentCompEl.style.height = helper.designToNaturalSize(
+      compEl.style.height = helper.designToNaturalSize(
         start.height + start.offsetY * 2
       );
     }
@@ -93,35 +90,37 @@ export const Transfer = defineComponent({
 
     return () => (
       <>
-        <div ref={resizeRef} class={resizeStyle}></div>
-        <div ref={moveRef} class={moveStyle}></div>
+        <div class={borderStyle}></div>
+        <div ref={resizeRef} class={[resizeStyle, "drag-disable"]}></div>
+        <div ref={moveRef} class={[moveStyle, "drag-disable"]}></div>
+        <RingBtns class={offsetStyle} />
       </>
     );
   },
 });
 
-function getClosestParentWithClass(element: HTMLElement, className: string) {
-  let parent = element.parentElement;
-
-  while (parent) {
-    if (parent.classList.contains(className)) {
-      return parent;
-    }
-    parent = parent.parentElement;
-  }
-
-  return null;
-}
+const borderStyle = css`
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  outline: 2px solid @inf-primary-color;
+  pointer-events: none;
+  z-index: 9;
+`;
 
 const resizeStyle = css`
   position: absolute;
   bottom: 0;
   right: 0;
-  width: 8px;
-  height: 8px;
-  border-bottom: 4px solid;
-  border-right: 4px solid;
-  border-color: @inf-primary-fade-color;
+  width: 16px;
+  height: 16px;
+  border-radius: 50%;
+  background-color: #fff;
+  z-index: 9;
+  transform: translate(50%, 50%);
+  box-shadow: 0 0 2px 2px rgba(0, 0, 0, 0.2);
   cursor: nwse-resize;
   &:hover {
     border-color: @inf-primary-color;
@@ -133,14 +132,19 @@ const moveStyle = css`
   bottom: 0;
   left: 50%;
   width: 40px;
-  height: 4px;
-  transform: translate(-50%, 50%);
-  background-color: @inf-primary-color;
-  border-radius: 4px;
+  height: 8px;
+  transform: translate(-50%, 5px);
+  background-color: #fff;
+  border-radius: 8px;
+  box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.2);
+  z-index: 9;
   cursor: all-scroll;
-  &:hover {
-    border-color: #fff;
-    box-shadow: 0 0 3px 2px rgba(0, 0, 0, 0.5);
-    outline: 2px solid #fff;
-  }
+`;
+
+const offsetStyle = css`
+  position: absolute;
+  bottom: 0;
+  left: 50%;
+  transform: translate(-50%, 60px);
+  z-index: 9;
 `;

+ 29 - 52
src/modules/editor/components/CompUI/basicUI/View.tsx

@@ -1,9 +1,10 @@
 import { css } from "@linaria/core";
-import { omit, upperFirst } from "lodash";
+import { upperFirst } from "lodash";
 import { defineComponent } from "vue";
 import { string } from "vue-types";
 import { useEditor } from "../../..";
 import { DesignComp } from "../../../objects/DesignTemp/DesignComp";
+import { Transfer } from "./Transfer";
 
 export const View = defineComponent({
   props: {
@@ -18,9 +19,16 @@ export const View = defineComponent({
 
     function createStyle(): any {
       const style: any = {};
-      const { textAlign, margin, zIndex, visible } = comp.layout || {};
-      if (textAlign) {
-        style.textAlign = textAlign;
+      const {
+        alignSelf,
+        margin,
+        zIndex,
+        visible,
+        size = [],
+      } = comp.layout || {};
+      const [w, h] = size;
+      if (alignSelf) {
+        style.alignSelf = alignSelf;
       }
       if (visible === false) {
         style.display = "none";
@@ -36,6 +44,13 @@ export const View = defineComponent({
       if (margin) {
         style.margin = margin;
       }
+
+      if (comp.layout?.padding) {
+        style.padding = comp.layout.padding;
+      }
+
+      if (w) style["width"] = helper.designToNaturalSize(w);
+      if (h) style["height"] = helper.designToNaturalSize(h);
       return style;
     }
 
@@ -55,8 +70,6 @@ export const View = defineComponent({
         style.padding = layout.padding;
       }
 
-      if (w) style["width"] = helper.designToNaturalSize(w);
-      if (h) style["height"] = helper.designToNaturalSize(h);
       // if (layout?.offsetX) {
       //   style["marginLeft"] = helper.designToNaturalSize(
       //     layout.offsetX as number
@@ -67,36 +80,22 @@ export const View = defineComponent({
     }
 
     return () => {
-      const isComp = !!props.compId;
-      const isSelected = isComp && store.currCompId === props.compId;
-
-      const bgOpts = Object.values(omit(comp.background, ["image", "color"]));
-      const bgClasses = bgOpts.length ? `bg-${bgOpts.join(" bg-")}` : "";
+      const isSelected = store.currCompId === props.compId;
 
-      return isComp ? (
+      return (
         <div
-          class={[
-            viewStyle,
-            store.isEditMode && "view_editing",
-            store.isEditMode && isSelected && "view_selected",
-            bgClasses,
-          ]}
+          class={[viewStyle, store.isEditMode && viewEditStyle]}
           style={createStyle()}
           onClick={(e) => {
             e.stopPropagation();
-            if (isComp && !isSelected) {
+            if (!isSelected) {
               actions.pickComp(props.compId as string);
             }
           }}
           onDblclick={() => emit("dblclick")}
         >
-          <div class="view_content" style={createContentStyle()}>
-            {slots.default?.()}
-          </div>
-        </div>
-      ) : (
-        <div class="view_inside" onDblclick={() => emit("dblclick")}>
           {slots.default?.()}
+          {isSelected && <Transfer compId={props.compId} />}
         </div>
       );
     };
@@ -107,36 +106,14 @@ const viewStyle = css`
   position: relative;
   font-size: 0;
 
-  &.view_editing {
-    .view_content {
-      &:hover {
-        outline: 1px dashed @inf-primary-color;
-      }
-    }
-    .view_inside:hover {
-      outline: 1px dashed @inf-primary-color;
-      outline-offset: -1px;
-    }
-  }
-
-  .view_content {
-    display: inline-block;
+  > :first-child {
     width: 100%;
     height: 100%;
-    background: no-repeat center / cover;
-  }
-
-  &.view_selected {
-    > .view_content {
-      outline: 1px solid @inf-primary-color;
-    }
-  }
-
-  .view_inside {
-    position: relative;
   }
+`;
 
-  .view_content {
-    overflow: hidden;
+const viewEditStyle = css`
+  &:hover {
+    outline: 2px dashed @inf-primary-color;
   }
 `;

+ 1 - 1
src/modules/editor/components/CompUI/customUI/Cards/Card11/component.tsx

@@ -10,7 +10,7 @@ export const Component = createUIComp({
   },
   setup(props) {
     const { children, value } = useCompData(props.compId);
-    const createList = useCreateChild("list");
+    const createList = useCreateChild("list", props.compId);
 
     watch(
       () => [value.columns],

+ 1 - 1
src/modules/editor/components/CompUI/customUI/Cards/CardList/component.tsx

@@ -12,7 +12,7 @@ export const Component = createUIComp({
   setup(props) {
     const { helper } = useEditor();
     const { value, children } = useCompData(props.compId);
-    const createList = useCreateChild("list");
+    const createList = useCreateChild("list", props.compId);
 
     watch(
       () => [value.total],

+ 2 - 2
src/modules/editor/components/CompUI/customUI/Titles/Title1/component.tsx

@@ -11,7 +11,7 @@ export const Component = createUIComp({
   setup(props) {
     const { value, children } = useCompData(props.compId);
     return () => (
-      <>
+      <div>
         <Text.Component compId={children.title} />
         <Text.Component
           class={compStyle}
@@ -20,7 +20,7 @@ export const Component = createUIComp({
           }}
           compId={children.subTitle}
         />
-      </>
+      </div>
     );
   },
 });

+ 6 - 5
src/modules/editor/components/CompUI/defines/createAttrsForm.tsx

@@ -4,7 +4,7 @@ import { isEmpty, set } from "lodash";
 import { defineComponent } from "vue";
 import { any } from "vue-types";
 import { GroupNumber } from "../formItems/GroupNumber";
-import { InputNumber } from "ant-design-vue";
+import { InputNumber, Select } from "ant-design-vue";
 import { createColorOpts } from "./formOpts/createColorOpts";
 import { ImagePicker } from "../formItems/ImagePicker";
 
@@ -19,13 +19,14 @@ const layoutColumns: ColumnItem[] = [
   },
   {
     label: "对齐",
-    dataIndex: "layout.textAlign",
-    component: "Select",
+    dataIndex: "layout.alignSelf",
+    component: Select,
     props: {
+      class: "w-full",
       options: [
-        { label: "左对齐", value: "left" },
+        { label: "左对齐", value: "start" },
         { label: "居中", value: "center" },
-        { label: "右对齐", value: "right" },
+        { label: "右对齐", value: "end" },
       ],
     },
   },

+ 2 - 2
src/modules/editor/components/CompUI/defines/createCompHooks.ts

@@ -38,11 +38,11 @@ export function createCompHooks<T, C extends { [name: string]: AnyFun }>(
     };
   }
 
-  function useCreateChild<T extends keyof C>(key: T) {
+  function useCreateChild<T extends keyof C>(key: T, compId: string) {
     const editor = useEditor();
     const createChild: any = (...args: any) => {
       const result = (defaultOpts as any).children[key](defaultOpts, ...args);
-      addCacheToMap(editor.store.designData.compMap);
+      addCacheToMap(editor.store.designData.compMap, compId);
       return result;
     };
     return createChild as C[T];

+ 35 - 5
src/modules/editor/components/CompUI/defines/createCompId.ts

@@ -1,13 +1,23 @@
 import { DesignComp } from "@/modules/editor/objects/DesignTemp/DesignComp";
 import { CompUI } from "..";
+import { mapValuesDeep } from "@/utils";
+import { Exception } from "queenjs";
 
-const cacheCompArr: DesignComp[] = [];
+const cacheCompMap = new Map<string, DesignComp>();
 
-export function addCacheToMap(obj: Record<string, DesignComp>) {
-  cacheCompArr.forEach((comp) => {
+export function addCacheToMap(
+  obj: Record<string, DesignComp>,
+  parentId: string
+) {
+  let lastComp: DesignComp | undefined;
+  cacheCompMap.forEach((comp) => {
     obj[comp.id] = comp;
+    lastComp = comp;
   });
-  cacheCompArr.length = 0;
+  if (lastComp) {
+    setCompPid(lastComp, parentId);
+  }
+  cacheCompMap.clear();
 }
 
 export function createCompId(
@@ -17,6 +27,26 @@ export function createCompId(
   const comp = CompUI[compKey].createComp(
     Object.assign(options || {}, { compKey })
   );
-  cacheCompArr.push(comp);
+  cacheCompMap.set(comp.id, comp);
+
+  const childIds = mapValuesDeep(
+    comp.children,
+    (v) => typeof v === "string",
+    (v: string) => v
+  );
+
+  childIds.forEach((id) => {
+    const childComp = cacheCompMap.get(id);
+    if (!childComp) {
+      throw Exception.error("无效的childCompId");
+    }
+    setCompPid(childComp, comp.id);
+  });
   return comp.id;
 }
+
+export function setCompPid(comp: DesignComp, pid: string) {
+  Object.defineProperty(comp, "pid", {
+    value: pid,
+  });
+}

+ 1 - 1
src/modules/editor/components/Preview/index.tsx

@@ -6,7 +6,7 @@ export default defineUI({
   setup() {
     const { store } = useEditor();
     return () => (
-      <div>
+      <div class="flex flex-col">
         {store.pageCompIds.map((id) => {
           const compKey = store.designData.compMap[id]?.compKey;
           const Comp: any = CompUI[compKey]?.Component;

+ 0 - 0
src/modules/editor/objects/TipIcons/TipIcon.tsx → src/modules/editor/components/TipIcons/TipIcon.tsx


+ 2 - 3
src/modules/editor/objects/TipIcons/create.ts → src/modules/editor/components/TipIcons/create.ts

@@ -1,12 +1,11 @@
-import { IComponent } from "queenjs/typing";
 import { h } from "vue";
 import { TipIcon } from "./TipIcon";
 
 export function createTipIcon(options: {
   icons: any[];
   tips: Array<string | JSX.Element>;
-}): IComponent {
-  return (props: FuncProps<{ value?: number; disable?: boolean }>) => {
+}): (props: { value?: number; disable?: boolean }) => JSX.Element {
+  return (props: any) => {
     return h(TipIcon, { ...options, ...props });
   };
 }

+ 7 - 7
src/modules/editor/objects/TipIcons/index.ts → src/modules/editor/components/TipIcons/index.ts

@@ -12,24 +12,24 @@ import {
 } from "@queenjs/icons";
 import { createTipIcon } from "./create";
 
-export const tipIcons = {
-  shadow: createTipIcon({
+export const TipIcons = {
+  Shadow: createTipIcon({
     icons: [IconShadow, IconShadowOff],
     tips: ["阴影-开", "阴影-关"],
   }),
-  visible: createTipIcon({
+  Visible: createTipIcon({
     icons: [IconEyeOn, IconEyeOff],
     tips: ["显示", "隐藏"],
   }),
-  lock: createTipIcon({
+  Lock: createTipIcon({
     icons: [IconLock, IconUnlock],
     tips: ["显示", "隐藏"],
   }),
-  delete: createTipIcon({
+  Delete: createTipIcon({
     icons: [IconDelete],
     tips: ["删除"],
   }),
-  clear: createTipIcon({
+  Clear: createTipIcon({
     icons: [IconClear],
     tips: ["清除材质"],
   }),
@@ -37,7 +37,7 @@ export const tipIcons = {
     icons: [IconUndo],
     tips: ["撤销"],
   }),
-  redo: createTipIcon({
+  Redo: createTipIcon({
     icons: [IconRedo],
     tips: ["重做"],
   }),

+ 7 - 6
src/modules/editor/components/Viewport/Content/index.tsx

@@ -10,7 +10,7 @@ import { CompUI } from "../../CompUI";
 export default defineUI({
   setup() {
     const editor = useEditor();
-    const { actions, helper } = editor;
+    const { store, actions, helper, components } = editor;
 
     const hotKeyCtrl = new HotKeyCtrl(editor);
     hotKeyCtrl.init();
@@ -20,7 +20,8 @@ export default defineUI({
 
     return () => {
       const pageRoot = helper.findRootComp();
-      return pageRoot ? (
+      if (!pageRoot) return;
+      return store.isEditMode ? (
         <CompUI.Page.Component class={contentStyle} compId={pageRoot.id}>
           {{
             Container(children: any) {
@@ -44,23 +45,23 @@ export default defineUI({
             CompItem(comp: DesignComp) {
               const Comp = CompUI[comp.compKey].Component;
               return (
-                <Draggable>
+                <Draggable class="!flex flex-col">
                   <Comp compId={comp.id} />
                 </Draggable>
               );
             },
           }}
         </CompUI.Page.Component>
-      ) : null;
+      ) : (
+        <components.Preview />
+      );
     };
   },
 });
 
 const contentStyle = css`
   position: relative;
-  border: 1px solid transparent;
   user-select: none;
-  @apply min-h-750px bg-white;
 
   .dndrop-container.vertical > .dndrop-draggable-wrapper {
     overflow: unset;

+ 17 - 16
src/modules/editor/components/Viewport/Slider/SliderRight/CompTree.tsx

@@ -1,10 +1,11 @@
-import { useEditor } from "@/modules/editor";
-import { DesignComp } from "@/modules/editor/objects/DesignTemp/DesignComp";
+import { treeNodeActions } from "@/modules/editor/objects/TreeNode/treeNodeActions";
 import { css } from "@linaria/core";
 import { useReactive } from "@queenjs/use";
 import { Tree } from "ant-design-vue";
 import { defineComponent } from "vue";
 import { string } from "vue-types";
+import { useEditor } from "../../../..";
+import { DesignComp } from "../../../../objects/DesignTemp/DesignComp";
 import { CompUI } from "../../../CompUI";
 
 type TreeItem = {
@@ -18,9 +19,12 @@ export const CompTree = defineComponent({
   setup() {
     const { store, actions, helper } = useEditor();
     const state = useReactive(() => ({
+      expandedKeys() {
+        const comps = helper.getCompTrees(store.currCompId);
+        return comps.map((comp) => comp.id);
+      },
       treeData() {
         const rootComp = helper.findRootComp();
-
         function getCompChildren(ids: string[]): TreeItem[] {
           return ids.map((id) => {
             const comp = helper.findComp(id) as DesignComp;
@@ -32,23 +36,22 @@ export const CompTree = defineComponent({
             };
           });
         }
-
-        return [
-          {
-            key: rootComp?.id || "",
-            title: "页面",
-            children: getCompChildren(store.pageCompIds),
-          },
-        ];
+        return getCompChildren(rootComp?.id ? [rootComp.id] : []);
       },
     }));
+
     return () => (
       <Tree
         class={treeStyle}
         treeData={state.treeData}
+        expandedKeys={state.expandedKeys}
         selectedKeys={[store.currCompId]}
         blockNode={true}
-        onSelect={(ids) => actions.pickComp(ids[0] as string)}
+        onSelect={(ids) =>
+          actions.pickComp(
+            (ids[0] as string) || state.expandedKeys.at(-2) || "root"
+          )
+        }
       >
         {{
           title: (data: any) => {
@@ -67,13 +70,11 @@ const CompNode = defineComponent({
   },
   setup(props) {
     const editor = useEditor();
-    const { config, helper } = editor;
-    const comp = helper.findComp(props.id);
+    const comp = editor.helper.findComp(props.id);
     return () => {
       if (!comp) return;
       const compOpts = CompUI[comp.compKey].options;
-      const actions =
-        config.treeNodeActions[comp.compKey] || config.treeNodeActions.default;
+      const actions = treeNodeActions[comp.compKey] || treeNodeActions.default;
       const thumbnail =
         comp.compKey === "Image" ? comp.value.url : compOpts.thumbnail;
       return (

+ 6 - 10
src/modules/editor/components/Viewport/Slider/SliderRight/index.tsx

@@ -1,8 +1,7 @@
-import { useEditor } from "@/modules/editor";
 import { defineUI } from "queenjs";
 import { h } from "vue";
+import { useEditor } from "../../../..";
 import { CompUI } from "../../../CompUI";
-import { createAttrsForm } from "../../../CompUI/defines/createAttrsForm";
 import { CompTree } from "./CompTree";
 
 export default defineUI({
@@ -14,16 +13,13 @@ export default defineUI({
 
       return (
         <div class="flex flex-col h-1/1">
-          <div class="p-16px border-bottom  !border-2px">设置栏</div>
+          <div class="p-16px border-bottom !border-2px">设置栏</div>
           <div class="flex-1 p-16px scrollbar">
-            {h(
-              currComp?.compKey
-                ? CompUI[currComp.compKey].Form
-                : (createAttrsForm([]) as any),
-              { component: currComp }
-            )}
+            {currComp?.compKey
+              ? h(CompUI[currComp.compKey].Form, { component: currComp })
+              : null}
           </div>
-          <div class="p-16px border-top border-bottom  !border-2px">组件树</div>
+          <div class="p-16px border-bottom !border-2px border-top">组件树</div>
           <div class="h-300px py-20px pr-20px scrollbar">
             <CompTree />
           </div>

+ 1 - 1
src/modules/editor/components/Viewport/index.tsx

@@ -21,7 +21,7 @@ export default defineUI({
           <slots.SliderLeft class="w-300px bg-component border-right !border-2px" />
           <div class="flex-1 h-1/1 scrollbar overflow-y-auto">
             {/* <slots.Toolbar /> */}
-            <slots.Content class="w-375px mx-auto my-30px" />
+            <slots.Content class="w-375px min-h-750px mx-auto my-30px bg-white" />
           </div>
           <slots.SliderRight class="w-360px bg-component border-left !border-2px" />
         </div>

+ 1 - 1
src/modules/editor/components/index.ts

@@ -3,5 +3,5 @@ import Viewport from "./Viewport";
 
 export default {
   Viewport,
-  Preview
+  Preview,
 };

+ 0 - 9
src/modules/editor/configs/index.ts

@@ -1,9 +0,0 @@
-import { Dict_Apis } from "@/dict";
-import { treeNodeActions } from "./treeNodeActions";
-
-export const config = {
-  httpConfig: {
-    baseURL: Dict_Apis.promotion,
-  },
-  treeNodeActions,
-};

+ 20 - 18
src/modules/editor/module/helpers/index.ts

@@ -1,3 +1,4 @@
+import { mapValuesDeep } from "@/utils";
 import { EditorModule } from "..";
 import { DesignComp } from "../../objects/DesignTemp/DesignComp";
 import { Layout } from "../../typings";
@@ -12,29 +13,30 @@ export const helpers = EditorModule.helper({
     if (comp) return comp;
   },
   findParentComp(compId: string): DesignComp | undefined {
-    const parentComp = Object.values(this.store.designData.compMap).find(
-      (comp) => {
-        const ids = this.helper.getCompChildIds(comp);
-        return ids.includes(compId);
-      }
-    );
-    return parentComp;
+    const comp = this.helper.findComp(compId);
+    if (comp) return this.helper.findComp(comp.pid);
   },
   findRootComp(): DesignComp | undefined {
     return this.store.designData.compMap["root"];
   },
-  getCompChildIds(comp: DesignComp) {
-    function getIds(data: any, ids: string[] = []) {
-      if (data instanceof Array) {
-        data.forEach((item) => getIds(item, ids));
-      } else if (data instanceof Object) {
-        Object.values(data).forEach((item) => getIds(item, ids));
-      } else if (typeof data === "string") {
-        ids.push(data);
+  getCompTrees(compId: string) {
+    const comps: DesignComp[] = [];
+    const getParentComp = (compId: string) => {
+      const comp = this.helper.findComp(compId);
+      if (comp) {
+        comps.unshift(comp);
+        getParentComp(comp.pid);
       }
-      return ids;
-    }
-    return getIds(comp.children);
+    };
+    getParentComp(compId);
+    return comps;
+  },
+  getCompChildIds(comp: DesignComp) {
+    return mapValuesDeep(
+      comp.children,
+      (v) => typeof v === "string",
+      (v: string) => v
+    );
   },
   parseLayoutToStyle(layout: Layout): any {
     return layout;

+ 6 - 4
src/modules/editor/module/index.ts

@@ -1,6 +1,6 @@
+import { Dict_Apis } from "@/dict";
 import { ModuleRoot } from "queenjs";
 import components from "../components";
-import { config } from "../configs";
 import { HistoryCtrl } from "../controllers/HistoryCtrl";
 import { ImagePickController } from "../controllers/ImagePickerController";
 import { editActions } from "./actions/edit";
@@ -11,7 +11,11 @@ import { https } from "./https";
 import { store } from "./stores";
 
 export class EditorModule extends ModuleRoot {
-  config = this.setConfig(config);
+  config = this.setConfig({
+    httpConfig: {
+      baseURL: Dict_Apis.promotion,
+    },
+  });
   components = this.useComponents(components);
 
   actions = this.createActions([initActions, editActions, ImgCompActions]);
@@ -38,5 +42,3 @@ export class EditorModule extends ModuleRoot {
     location.href = link;
   }
 }
-
-export const { useEditor, initEditor } = EditorModule.hook("Editor");

+ 3 - 3
src/modules/editor/module/stores/index.ts

@@ -10,7 +10,7 @@ import { EditorMode, ICompKeys } from "../../typings";
 export const store = EditorModule.store({
   state: () => ({
     mode: "edit" as EditorMode,
-    currCompId: "",
+    currCompId: "root",
     designData: new DesignTemp(),
   }),
   getters: {
@@ -38,13 +38,13 @@ export const store = EditorModule.store({
       const { pageCompIds } = this.store;
       index === undefined && (index = pageCompIds.length);
       const compId = createCompId(compKey);
-      addCacheToMap(this.store.designData.compMap);
+      addCacheToMap(this.store.designData.compMap, "root");
       pageCompIds.splice(index, 0, compId);
       return compId;
     },
     insertCompContainer(compKey: ICompKeys, container: DesignComp) {
       const compId = createCompId(compKey);
-      addCacheToMap(this.store.designData.compMap);
+      addCacheToMap(this.store.designData.compMap, container.id);
       container.children.default || (container.children.default = []);
       container.children.default.push(compId);
       return compId;

+ 1 - 0
src/modules/editor/objects/DesignTemp/DesignComp.ts

@@ -3,6 +3,7 @@ import { Background, ICompKeys, Layout } from "../../typings";
 import { cloneDeep } from "lodash";
 
 export class DesignComp {
+  declare pid: string; // pid 作为前端临时数据,不存储到服务器,在初始化时关联
   id = nanoid();
   compKey: ICompKeys = "Text";
   value: any = undefined;

+ 39 - 21
src/modules/editor/objects/DesignTemp/versions/0.0.1.ts

@@ -1,26 +1,27 @@
 import { CompUI } from "@/modules/editor/components/CompUI";
 import { addCacheToMap } from "@/modules/editor/components/CompUI/defines/createCompId";
+import { mapValuesDeep } from "@/utils";
 import { set } from "lodash";
-import { AnyFun } from "queenjs/typing";
 import { DesignComp } from "../DesignComp";
 
 export function dataTransform(data: any) {
   data.compMap || (data.compMap = {});
+  const compMap: Record<string, DesignComp> = data.compMap;
 
-  deepEachComp(data.content, (...args: any[]) => {
-    const comp = args.pop();
-    set(data.content, args.join("."), comp.id);
-    data.compMap[comp.id] = comp;
+  // 遍历content中的每一个Comp, 包括Comp.children里的Comp
+  deepEachComp(data.content, (paths, comp) => {
+    set(data.content, paths.join("."), comp.id);
+    compMap[comp.id] = comp;
     if (!comp.children) {
-      comp.children = (CompUI as any)[comp.compKey].createComp({
+      comp.children = CompUI[comp.compKey].createComp({
         compKey: comp.compKey,
       }).children;
-      addCacheToMap(data.compMap);
+      addCacheToMap(compMap, comp.id);
     }
   });
 
-  if (!data.compMap.root) {
-    data.compMap.root = CompUI.Page.createComp({
+  if (!compMap.root) {
+    compMap.root = CompUI.Page.createComp({
       id: "root",
       compKey: "Page",
       layout: data.pageStyle,
@@ -29,26 +30,43 @@ export function dataTransform(data: any) {
       },
     });
   }
+
+  Object.values(compMap).forEach((comp) => {
+    const childIds = mapValuesDeep(
+      comp.children,
+      (v) => typeof v === "string",
+      (v: string) => v
+    );
+    childIds.forEach((cid) => {
+      const childComp = compMap[cid];
+      Object.defineProperty(childComp, "pid", { value: comp.id });
+    });
+  });
+
   return data;
 }
 
-function deepEachComp(obj: any, itemFn: AnyFun) {
-  if (obj instanceof Array) {
-    obj.forEach((item, i) => deepEachComp(item, itemFn.bind(null, i)));
+function deepEachComp(
+  obj: any,
+  itemFn: (paths: string[], comp: DesignComp) => void,
+  paths: string[] = []
+) {
+  if (isComp(obj)) {
+    deepEachComp(obj.children, itemFn, [...paths, "children"]);
+    itemFn(paths, obj);
+  } else if (obj instanceof Array) {
+    obj.forEach((item, i) =>
+      deepEachComp(item, itemFn, [...paths, i.toString()])
+    );
   } else if (obj instanceof Object) {
-    if (isComp(obj)) {
-      deepEachComp(obj.children, itemFn.bind(null, "children"));
-      itemFn(obj);
-    } else {
-      Object.entries(obj).map(([key, item]) => {
-        deepEachComp(item, itemFn.bind(null, key));
-      });
-    }
+    Object.entries(obj).map(([key, item]) => {
+      deepEachComp(item, itemFn, [...paths, key]);
+    });
   }
 }
 
 function isComp(obj: any): obj is DesignComp {
-  if (obj.compKey) {
+  if (obj instanceof Object && obj.compKey) {
     return true;
   } else {
     return false;

+ 6 - 6
src/modules/editor/configs/treeNodeActions.ts → src/modules/editor/objects/TreeNode/treeNodeActions.ts

@@ -1,7 +1,7 @@
-import { EditorModule } from "../module";
-import { DesignComp } from "../objects/DesignTemp/DesignComp";
-import { tipIcons } from "../objects/TipIcons";
-import { ICompKeys } from "../typings";
+import { TipIcons } from "../../components/TipIcons";
+import { EditorModule } from "../../module";
+import { ICompKeys } from "../../typings";
+import { DesignComp } from "../DesignTemp/DesignComp";
 
 type Action = {
   component: any;
@@ -15,14 +15,14 @@ export const treeNodeActions: { [name in ICompKeys]?: Action[] } & {
 } = {
   default: [
     {
-      component: tipIcons.visible,
+      component: TipIcons.Visible,
       getValue: (comp) => (comp.layout.visible !== false ? 0 : 1),
       onClick(comp) {
         this.actions.switchCompVisible(comp);
       },
     },
     {
-      component: tipIcons.delete,
+      component: TipIcons.Delete,
       disable(comp) {
         return !this.store.pageCompIds.includes(comp.id);
       },

+ 1 - 1
src/modules/editor/typings.ts

@@ -7,7 +7,7 @@ export type EditorMode = "edit" | "preview";
 export type Layout = {
   visible?: boolean;
   size?: number[]; // width height
-  textAlign?: string;
+  alignSelf?: string;
   offsetX?: number;
   offsetY?: number;
   zIndex?: number;

+ 18 - 0
src/utils/index.ts

@@ -0,0 +1,18 @@
+export function mapValuesDeep<T>(
+  obj: any,
+  isItem: (v: any) => boolean,
+  handle: (v: any) => T
+) {
+  const arr: T[] = [];
+  function mapItem(obj: any) {
+    if (isItem(obj)) {
+      arr.push(handle(obj));
+    } else if (obj instanceof Array) {
+      obj.forEach(mapItem);
+    } else if (obj instanceof Object) {
+      Object.values(obj).forEach(mapItem);
+    }
+  }
+  mapItem(obj);
+  return arr;
+}