lianghongjie 1 gadu atpakaļ
vecāks
revīzija
549bde1b91
25 mainītis faili ar 371 papildinājumiem un 168 dzēšanām
  1. 2 2
      src/dict/apis.ts
  2. 1 1
      src/dict/imgs.ts
  3. 12 4
      src/modules/editor/components/CompUI/basicUI/Image/component.tsx
  4. 1 1
      src/modules/editor/components/CompUI/basicUI/Image/index.ts
  5. 11 3
      src/modules/editor/components/CompUI/basicUI/Text/component.tsx
  6. 1 1
      src/modules/editor/components/CompUI/basicUI/Text/index.ts
  7. 34 25
      src/modules/editor/components/CompUI/basicUI/View.tsx
  8. 15 14
      src/modules/editor/components/CompUI/customUI/Cards/Card1/component.tsx
  9. 9 3
      src/modules/editor/components/CompUI/customUI/Cards/Card1/index.tsx
  10. 52 0
      src/modules/editor/components/CompUI/customUI/Cards/CardList/component.tsx
  11. 49 0
      src/modules/editor/components/CompUI/customUI/Cards/CardList/index.tsx
  12. 7 11
      src/modules/editor/components/CompUI/customUI/Cover/component.tsx
  13. 10 4
      src/modules/editor/components/CompUI/customUI/Cover/index.ts
  14. 21 20
      src/modules/editor/components/CompUI/customUI/Titles/Title1/component.tsx
  15. 16 19
      src/modules/editor/components/CompUI/customUI/Titles/Title1/index.ts
  16. 36 22
      src/modules/editor/components/CompUI/defines/createAttrsForm.tsx
  17. 17 3
      src/modules/editor/components/CompUI/defines/createOptions.ts
  18. 1 13
      src/modules/editor/components/CompUI/defines/createUIComp.tsx
  19. 3 1
      src/modules/editor/components/CompUI/index.ts
  20. 1 7
      src/modules/editor/components/Viewport/Content/index.tsx
  21. 10 5
      src/modules/editor/components/Viewport/Slider/SliderRight.tsx
  22. 21 3
      src/modules/editor/defines/DesignTemp/DesignComp.ts
  23. 19 0
      src/modules/editor/defines/DesignTemp/index.ts
  24. 20 6
      src/modules/editor/stores/index.ts
  25. 2 0
      src/modules/editor/typings.ts

+ 2 - 2
src/dict/apis.ts

@@ -7,8 +7,8 @@ const treeVersion = "/tree/v1";
 const Dict_Apis = {
   auth: `${baseURL}${baseVersion}/usercenter`,
   queentree: `${baseURL}${treeVersion}/assetcenter`,
-  promotion: `${baseURL}${baseVersion}/promotion`,
-  // promotion: `${localURL}/promotion`,
+  // promotion: `${baseURL}${baseVersion}/promotion`,
+  promotion: `${localURL}/promotion`,
 };
 
 export { Dict_Apis };

+ 1 - 1
src/dict/imgs.ts

@@ -1,3 +1,3 @@
 export const Dict_Imgs = {
-  Default: require("@/assets/imgs/default.png"),
+  Default: require("@/assets/imgs/default.png") as string,
 };

+ 12 - 4
src/modules/editor/components/CompUI/basicUI/Image/component.tsx

@@ -2,22 +2,30 @@ import { useEditor } from "@/modules/editor";
 import { queenApi } from "queenjs";
 import { string } from "vue-types";
 import { createUIComp } from "../../defines/createUIComp";
+import { useCompData } from ".";
 
 export const Component = createUIComp({
   props: {
-    value: string().def(""),
+    compId: string(),
+    value: string(),
   },
   emits: ["update:value"],
   setup(props, { emit }) {
+    const comp = props.compId ? useCompData(props.compId) : null;
     const { store } = useEditor();
     async function changeVal() {
       const files = await queenApi.selectFile();
-      emit("update:value", URL.createObjectURL(files[0]));
+      const url = URL.createObjectURL(files[0]);
+      if (comp) {
+        comp.value = URL.createObjectURL(files[0]);
+      } else {
+        emit("update:value", url);
+      }
     }
     return () => (
       <img
-        class="w-1/1 h-1/1"
-        src={props.value}
+        class="w-1/1 h-1/1 object-cover"
+        src={comp?.value || props.value}
         onClick={store.isEditMode ? changeVal : undefined}
       />
     );

+ 1 - 1
src/modules/editor/components/CompUI/basicUI/Image/index.ts

@@ -4,7 +4,7 @@ import { createOptions } from "../../defines/createOptions";
 
 export { Component } from "./component";
 
-export const options = createOptions({
+export const { options, useCompData } = createOptions({
   name: "图片",
   value: Dict_Imgs.Default,
 });

+ 11 - 3
src/modules/editor/components/CompUI/basicUI/Text/component.tsx

@@ -3,20 +3,23 @@ import { Alignment } from "@ckeditor/ckeditor5-alignment";
 import { Bold, Italic } from "@ckeditor/ckeditor5-basic-styles";
 import { InlineEditor } from "@ckeditor/ckeditor5-editor-inline";
 import { Essentials } from "@ckeditor/ckeditor5-essentials";
-import { FontFamily, FontSize, FontColor } from "@ckeditor/ckeditor5-font";
+import { FontColor, FontFamily, FontSize } from "@ckeditor/ckeditor5-font";
 import { Link } from "@ckeditor/ckeditor5-link";
 import { Paragraph } from "@ckeditor/ckeditor5-paragraph";
 import { css } from "@linaria/core";
 import { reactive } from "vue";
 import { string } from "vue-types";
+import { useCompData } from ".";
 import { createUIComp } from "../../defines/createUIComp";
 
 export const Component = createUIComp({
   props: {
+    compId: string(),
     value: string().def(""),
   },
   emits: ["update:value"],
   setup(props, { emit }) {
+    const comp = props.compId ? useCompData(props.compId) : null;
     const { store } = useEditor();
     const config = {
       plugins: [
@@ -61,11 +64,15 @@ export const Component = createUIComp({
           editor={InlineEditor}
           onBlur={(e: any, editor: InlineEditor) => {
             state.focus = false;
-            emit("update:value", editor.getData());
+            if (comp) {
+              comp.value = editor.getData();
+            } else {
+              emit("update:value", editor.getData());
+            }
           }}
           onFocus={() => (state.focus = true)}
           onReady={(editor: InlineEditor) => {
-            editor.setData(props.value);
+            editor.setData(comp?.value || props.value);
             if (!store.isEditMode) {
               editor.enableReadOnlyMode("editor");
             }
@@ -78,6 +85,7 @@ export const Component = createUIComp({
 });
 
 const textStyle = css`
+  font-size: 0.14rem;
   p {
     margin: 0;
   }

+ 1 - 1
src/modules/editor/components/CompUI/basicUI/Text/index.ts

@@ -3,7 +3,7 @@ import { createOptions } from "../../defines/createOptions";
 
 export { Component } from "./component";
 
-export const options = createOptions({
+export const { options, useCompData } = createOptions({
   name: "文本",
   value: "请输入内容",
 });

+ 34 - 25
src/modules/editor/components/CompUI/basicUI/View.tsx

@@ -1,38 +1,43 @@
 import { css } from "@linaria/core";
 import { omit, upperFirst } from "lodash";
 import { defineComponent } from "vue";
-import { any, string } from "vue-types";
+import { string } from "vue-types";
 import { useEditor } from "../../..";
-import { Background, Layout } from "../../../typings";
+import { DesignComp } from "../../../defines/DesignTemp/DesignComp";
 
 export const View = defineComponent({
   props: {
     compId: string(),
-    background: any<Background>(),
-    layout: any<Layout>(),
   },
   setup(props, { slots }) {
     const { store, actions, helper } = useEditor();
+    const comp =
+      (props.compId && store.designCompMap.get(props.compId)) ||
+      new DesignComp();
 
     function createStyle(): any {
       const style: any = {};
-      const { textAlign, offsetY, zIndex } = props.layout || {};
+      const { textAlign, margin, zIndex } = comp.layout || {};
       if (textAlign) {
         style.textAlign = textAlign;
       }
-      if (offsetY) {
-        style[`margin` + ((offsetY as number) > 0 ? "Top" : "Bottom")] =
-          helper.designToNaturalSize(Math.abs(offsetY as number) * -1);
-      }
+      // if (offsetY) {
+      //   style[`margin` + ((offsetY as number) > 0 ? "Top" : "Bottom")] =
+      //     helper.designToNaturalSize(Math.abs(offsetY as number) * -1);
+      // }
       if (zIndex) {
         style["zIndex"] = zIndex;
       }
+
+      if (margin) {
+        style.margin = margin;
+      }
       return style;
     }
 
     function createContentStyle() {
       const style: any = {};
-      const { background, layout } = props;
+      const { background, layout } = comp;
       const [w, h] = (layout?.size as number[]) || [];
       if (background) {
         Object.entries(background).forEach(([key, value]) => {
@@ -41,16 +46,18 @@ export const View = defineComponent({
           }
           style["background" + upperFirst(key)] = value;
         });
-        console.log(style, background);
+      }
+      if (layout?.padding) {
+        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
-        );
-      }
+      // if (layout?.offsetX) {
+      //   style["marginLeft"] = helper.designToNaturalSize(
+      //     layout.offsetX as number
+      //   );
+      // }
 
       return style;
     }
@@ -59,7 +66,7 @@ export const View = defineComponent({
       const isComp = !!props.compId;
       const isSelected = isComp && store.currCompId === props.compId;
 
-      const bgOpts = Object.values(omit(props.background, ["image", "color"]));
+      const bgOpts = Object.values(omit(comp.background, ["image", "color"]));
       const bgClasses = bgOpts.length ? `bg-${bgOpts.join(" bg-")}` : "";
 
       return isComp ? (
@@ -70,11 +77,12 @@ export const View = defineComponent({
             bgClasses,
           ]}
           style={createStyle()}
-          onClick={
-            isComp && !isSelected
-              ? () => actions.pickCurrComp(props.compId as string)
-              : undefined
-          }
+          onClick={(e) => {
+            e.stopPropagation();
+            if (isComp && !isSelected) {
+              actions.pickCurrComp(props.compId as string);
+            }
+          }}
         >
           <div class="view_content" style={createContentStyle()}>
             {slots.default?.()}
@@ -89,10 +97,11 @@ export const View = defineComponent({
 
 const viewStyle = css`
   position: relative;
-
+  font-size: 0;
+  /* 
   > * {
     pointer-events: none;
-  }
+  } */
 
   .view_content {
     display: inline-block;
@@ -114,7 +123,7 @@ const viewStyle = css`
       display: none;
     }
 
-    .view_content {
+    > .view_content {
       outline: 1px solid @inf-primary-color;
     }
 

+ 15 - 14
src/modules/editor/components/CompUI/customUI/Cards/Card1/component.tsx

@@ -1,22 +1,22 @@
 import { Dict_Imgs } from "@/dict";
 import { css } from "@linaria/core";
 import { reactive, watch } from "vue";
-import { any } from "vue-types";
-import { options } from ".";
+import { string } from "vue-types";
 import { Image, Text } from "../../..";
 import { createUIComp } from "../../../defines/createUIComp";
+import { useCompData } from ".";
 
 export const Component = createUIComp({
   props: {
-    value: any<typeof options.value>().isRequired,
+    compId: string().isRequired,
   },
   setup(props) {
-    const state = reactive(props.value);
+    const { value, children } = useCompData(props.compId);
 
     watch(
-      () => [state.cardColumns],
+      () => [value.cardColumns],
       () => {
-        const { cardColumns, list } = state;
+        const { cardColumns, list } = value;
         const offset = cardColumns - list.length;
         if (offset > 0) {
           Array.from({ length: offset }, () => {
@@ -30,19 +30,19 @@ export const Component = createUIComp({
 
     return () => (
       <>
-        <Text.Component v-model={[state.title, "value"]} />
-        <Text.Component v-model={[state.desc, "value"]} />
+        <Text.Component compId={children.title.id} />
+        <Text.Component compId={children.desc.id} />
         <div class="flex space-x-16px">
-          {state.list.map((d, i) => (
+          {value.list.map((d, i) => (
             <div class="w-0 flex-1 relative">
               <Image.Component
                 class={imgStyle}
-                style={{ borderColor: state.themeColor }}
+                style={{ borderColor: value.themeColor }}
                 v-model={[d.img, "value"]}
               />
               <div
                 class={numberStyle}
-                style={{ backgroundColor: state.themeColor }}
+                style={{ backgroundColor: value.themeColor }}
               >
                 {(++i / 100).toString().split(".")[1]}
               </div>
@@ -64,10 +64,11 @@ const numberStyle = css`
   position: absolute;
   left: 50%;
   border-radius: 50%;
-  width: 40px;
-  height: 40px;
+  width: 0.8rem;
+  height: 0.8rem;
   text-align: center;
-  line-height: 40px;
+  font-size: 0.18rem;
+  line-height: 0.8rem;
   box-sizing: content-box;
   border: 3px solid #fff;
   transform: translate(-50%, -50%);

+ 9 - 3
src/modules/editor/components/CompUI/customUI/Cards/Card1/index.tsx

@@ -5,7 +5,7 @@ import { createColorOpts } from "../../../defines/formOpts/createColorOpts";
 
 export { Component } from "./component";
 
-export const options = createOptions({
+export const { options, useCompData } = createOptions({
   name: "卡片",
   value: {
     cardColumns: 3,
@@ -15,10 +15,16 @@ export const options = createOptions({
       desc: "xxxxx",
       img: Dict_Imgs.Default,
     })),
-    title: "新科技反光面料 引领潮流新风尚",
-    desc: "时尚 | 精致 | 百搭",
   },
   background: { color: "#333333" },
+  children: {
+    title: {
+      value: "新科技反光面料 引领潮流新风尚",
+    },
+    desc: {
+      value: "时尚 | 精致 | 百搭",
+    },
+  },
 });
 
 export const Form = createAttrsForm([

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

@@ -0,0 +1,52 @@
+import { Dict_Imgs } from "@/dict";
+import { watch } from "vue";
+import { string } from "vue-types";
+import { useCompData } from ".";
+import { Image, Text } from "../../..";
+import { useEditor } from "../../../../..";
+import { createUIComp } from "../../../defines/createUIComp";
+
+export const Component = createUIComp({
+  props: {
+    compId: string().isRequired,
+  },
+  setup(props) {
+    const { helper } = useEditor();
+    const { value } = useCompData(props.compId);
+
+    watch(
+      () => [value.total],
+      () => {
+        const { total, list } = value;
+        const offset = total - list.length;
+        if (offset > 0) {
+          Array.from({ length: offset }, () => {
+            list.push({ img: Dict_Imgs.Default, desc: "描述" });
+          });
+        } else {
+          list.splice(total, offset * -1);
+        }
+      }
+    );
+
+    return () => (
+      <div
+        class="grid"
+        style={{
+          gridTemplateColumns: `repeat(${value.columns}, 1fr)`,
+          gridGap: helper.designToNaturalSize(value.gap),
+        }}
+      >
+        {value.list.map((d, i) => (
+          <div key={i}>
+            <Image.Component
+              style={{ height: helper.designToNaturalSize(value.imgHeight) }}
+              v-model={[d.img, "value"]}
+            />
+            {value.showDesc && <Text.Component v-model={[d.desc, "value"]} />}
+          </div>
+        ))}
+      </div>
+    );
+  },
+});

+ 49 - 0
src/modules/editor/components/CompUI/customUI/Cards/CardList/index.tsx

@@ -0,0 +1,49 @@
+import { Dict_Imgs } from "@/dict";
+import { createAttrsForm } from "../../../defines/createAttrsForm";
+import { createOptions } from "../../../defines/createOptions";
+import { InputNumber } from "ant-design-vue";
+
+export { Component } from "./component";
+
+export const { options, useCompData } = createOptions({
+  name: "卡片列表",
+  value: {
+    gap: 10,
+    columns: 3,
+    total: 3,
+    imgHeight: 120,
+    showDesc: false,
+    list: Array.from({ length: 3 }, () => ({
+      img: Dict_Imgs.Default,
+      desc: "描述",
+    })),
+  },
+});
+
+export const Form = createAttrsForm([
+  {
+    label: "卡片总数",
+    dataIndex: "value.total",
+    component: InputNumber,
+  },
+  {
+    label: "每行数量",
+    dataIndex: "value.columns",
+    component: InputNumber,
+  },
+  {
+    label: "卡片间距",
+    dataIndex: "value.gap",
+    component: InputNumber,
+  },
+  {
+    label: "图片高度",
+    dataIndex: "value.imgHeight",
+    component: InputNumber,
+  },
+  {
+    label: "显示描述",
+    dataIndex: "value.showDesc",
+    component: "Switch",
+  },
+]);

+ 7 - 11
src/modules/editor/components/CompUI/customUI/Cover/component.tsx

@@ -1,18 +1,19 @@
 import { css } from "@linaria/core";
 import { isPc } from "@queenjs/utils";
 import { onMounted, ref } from "vue";
-import { any } from "vue-types";
-import { options } from ".";
+import { string } from "vue-types";
+import { useCompData } from ".";
 import { Text } from "../..";
 import { createUIComp } from "../../defines/createUIComp";
 
 export const Component = createUIComp({
   props: {
-    value: any<typeof options.value>().isRequired,
+    compId: string().isRequired,
   },
   setup(props) {
-    const elRef = ref();
+    const { children } = useCompData(props.compId);
 
+    const elRef = ref();
     onMounted(() => {
       elRef.value.style.height = isPc()
         ? "12.8rem"
@@ -22,10 +23,7 @@ export const Component = createUIComp({
     return () => {
       return (
         <div class={compStyle} ref={elRef}>
-          <Text.Component
-            class="title"
-            v-model={[props.value.title, "value"]}
-          />
+          <Text.Component compId={children.title.id} />
           <div class="arrow">↓</div>
         </div>
       );
@@ -34,9 +32,6 @@ export const Component = createUIComp({
 });
 
 const compStyle = css`
-  .title {
-    margin-top: 1.4rem;
-  }
   .arrow {
     position: absolute;
     left: 50%;
@@ -44,6 +39,7 @@ const compStyle = css`
     width: 0.7rem;
     height: 0.7rem;
     line-height: 0.7rem;
+    font-size: 0.36rem;
     text-align: center;
     color: #fff;
     border: 2px solid #fff;

+ 10 - 4
src/modules/editor/components/CompUI/customUI/Cover/index.ts

@@ -3,15 +3,21 @@ import { createOptions } from "../../defines/createOptions";
 
 export { Component } from "./component";
 
-export const options = createOptions({
+export const { options, useCompData } = createOptions({
   name: "封面",
-  value: {
-    title: `<p style="text-align:center;"><span style="color:hsl(0,0%,100%);font-size:28px;">新科技反光面料</span></p><p style="text-align:center;"><span style="color:hsl(0,0%,100%);font-size:28px;">引领潮流新风尚</span></p><p style="text-align:center;">&nbsp;</p><p style="text-align:center;"><span style="color:hsl(0,0%,100%);font-size:16px;">时尚 | 精致 | 百搭</span></p>`,
-  },
+  value: {},
   background: {
     image:
       "https://infishwaibao.oss-cn-chengdu.aliyuncs.com/release/sku3d/img/partner_bg.5e324d05.png",
   },
+  children: {
+    title: {
+      value: `<p style="text-align:center;"><span style="color:hsl(0,0%,100%);font-size:28px;">新科技反光面料</span></p><p style="text-align:center;"><span style="color:hsl(0,0%,100%);font-size:28px;">引领潮流新风尚</span></p><p style="text-align:center;">&nbsp;</p><p style="text-align:center;"><span style="color:hsl(0,0%,100%);font-size:16px;">时尚 | 精致 | 百搭</span></p>`,
+      layout: {
+        margin: "1.4rem auto 0",
+      },
+    },
+  },
 });
 
 export const Form = createAttrsForm([

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

@@ -1,33 +1,34 @@
-import { any } from "vue-types";
-import { options } from ".";
-import { createUIComp } from "../../../defines/createUIComp";
-import { Text } from "../../..";
 import { css } from "@linaria/core";
+import { string } from "vue-types";
+import { Text } from "../../..";
+import { createUIComp } from "../../../defines/createUIComp";
+import { useCompData } from ".";
 
 export const Component = createUIComp({
   props: {
-    value: any<typeof options.value>().isRequired,
+    compId: string().isRequired,
   },
   setup(props) {
+    const { value, children } = useCompData(props.compId);
     return () => (
-      <Text.Component
-        style={{
-          "--theme-color": props.value.themeColor,
-        }}
-        class={[
-          compStyle,
-          props.value.themeType && `style_${props.value.themeType}`,
-        ]}
-        v-model={[props.value.title, "value"]}
-      />
+      <>
+        <Text.Component compId={children.title.id} />
+        <Text.Component
+          class={compStyle}
+          style={{
+            "--theme-color": value.themeColor,
+          }}
+          compId={children.subTitle.id}
+        />
+      </>
     );
   },
 });
 
 const compStyle = css`
-  &.style_border {
-    border-top: 1px solid;
-    border-bottom: 1px solid;
-    border-color: var(--theme-color);
-  }
+  width: 3rem;
+  margin: 0 auto;
+  border-top: 1px solid;
+  border-bottom: 1px solid;
+  border-color: var(--theme-color);
 `;

+ 16 - 19
src/modules/editor/components/CompUI/customUI/Titles/Title1/index.ts

@@ -4,35 +4,32 @@ import { createColorOpts } from "../../../defines/formOpts/createColorOpts";
 
 export { Component } from "./component";
 
-export const options = createOptions({
+export const { options, useCompData } = createOptions({
   name: "标题",
   value: {
-    title: "我的风格我选择",
-    themeType: "none",
     themeColor: "#666666",
   },
+  children: {
+    title: {
+      value: `<p style="text-align:center;"><span style="color:hsl(0, 0%, 0%);font-size:28px;">我的风格我选择</span></p>`,
+      layout: {
+        textAlign: "center",
+      },
+    },
+    subTitle: {
+      value: `<p style="text-align:center;"><span style="color:hsl(0, 0%, 30%);font-size:16px;">2023主推新品</span></p>`,
+      layout: {
+        textAlign: "center",
+        margin: "0.1rem auto 0",
+      },
+    },
+  },
 });
 
 export const Form = createAttrsForm([
-  {
-    label: "样式",
-    dataIndex: "value.themeType",
-    component: "Select",
-    props: {
-      options: [
-        { label: "无", value: "none" },
-        { label: "样式1", value: "border" },
-      ],
-    },
-  },
   {
     label: "主题颜色",
     dataIndex: "value.themeColor",
     ...createColorOpts(),
   },
-  {
-    label: "标题",
-    dataIndex: "value.title",
-    component: "Input",
-  },
 ]);

+ 36 - 22
src/modules/editor/components/CompUI/defines/createAttrsForm.tsx

@@ -30,25 +30,35 @@ const layoutColumns: ColumnItem[] = [
     },
   },
   {
-    label: "左右偏移",
-    dataIndex: "layout.offsetX",
-    component: "Slider",
-    props: {
-      min: -375,
-      max: 375,
-    },
-    getValue: (v) => v || 0,
+    label: "外边距",
+    dataIndex: "layout.margin",
+    component: "Input",
   },
   {
-    label: "上下偏移",
-    dataIndex: "layout.offsetY",
-    component: "Slider",
-    props: {
-      min: -375,
-      max: 375,
-    },
-    getValue: (v) => v || 0,
+    label: "内边距",
+    dataIndex: "layout.padding",
+    component: "Input",
   },
+  // {
+  //   label: "左右偏移",
+  //   dataIndex: "layout.offsetX",
+  //   component: "Slider",
+  //   props: {
+  //     min: -375,
+  //     max: 375,
+  //   },
+  //   getValue: (v) => v || 0,
+  // },
+  // {
+  //   label: "上下偏移",
+  //   dataIndex: "layout.offsetY",
+  //   component: "Slider",
+  //   props: {
+  //     min: -375,
+  //     max: 375,
+  //   },
+  //   getValue: (v) => v || 0,
+  // },
   {
     label: "层级",
     dataIndex: "layout.zIndex",
@@ -136,6 +146,16 @@ export function createAttrsForm(valueColumns: ColumnItem[]) {
         const { component } = props;
         return (
           <div>
+            {valueColumns.length ? (
+              <>
+                <div>组件属性</div>
+                <FormUI
+                  data={component}
+                  columns={valueColumns}
+                  onChange={changeVal}
+                />
+              </>
+            ) : null}
             <div>组件布局</div>
             <FormUI
               data={component}
@@ -144,12 +164,6 @@ export function createAttrsForm(valueColumns: ColumnItem[]) {
             />
             <div>组件背景</div>
             <FormUI data={component} columns={bgColumns} onChange={changeVal} />
-            <div>组件属性</div>
-            <FormUI
-              data={component}
-              columns={valueColumns}
-              onChange={changeVal}
-            />
           </div>
         );
       };

+ 17 - 3
src/modules/editor/components/CompUI/defines/createOptions.ts

@@ -1,12 +1,26 @@
+import { useEditor } from "@/modules/editor";
 import { Background, Layout } from "../../../typings";
+import { DesignComp } from "@/modules/editor/defines/DesignTemp/DesignComp";
 
-type IOptions<T> = {
+type IOptions<T, C> = {
   name: string;
   value: T;
   layout?: Layout;
   background?: Background;
+  children?: C;
 };
 
-export function createOptions<T>(opts: IOptions<T>) {
-  return opts;
+// export function createOptions<T>(opts: IOptions<T>) {
+//   return opts;
+// }
+
+export function createOptions<T, C>(options: IOptions<T, C>) {
+  function useCompData(compId: string): {
+    value: T;
+    children: Record<keyof C, DesignComp>;
+  } {
+    const editor = useEditor();
+    return editor.store.designCompMap.get(compId) as any;
+  }
+  return { options, useCompData };
 }

+ 1 - 13
src/modules/editor/components/CompUI/defines/createUIComp.tsx

@@ -1,24 +1,12 @@
 import { defineComponent } from "vue";
-import { any, string } from "vue-types";
 import { View } from "../basicUI/View";
 
 export const createUIComp: typeof defineComponent = function (options: any) {
   const { setup } = options;
-  options.props.layout = any();
-  options.props.background = any();
-  options.props.compId = string();
 
   options.setup = function (props: any, options: any) {
     const render = setup(props, options);
-    return () => (
-      <View
-        compId={props.compId}
-        layout={props.layout}
-        background={props.background}
-      >
-        {render()}
-      </View>
-    );
+    return () => <View compId={props.compId}>{render()}</View>;
   };
 
   return defineComponent(options);

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

@@ -1,5 +1,7 @@
 export * as Image from "./basicUI/Image";
 export * as Text from "./basicUI/Text";
-export * as Cover from "./customUI/Cover";
 export * as Card1 from "./customUI/Cards/Card1";
+export * as CardList from "./customUI/Cards/CardList";
+export * as Cover from "./customUI/Cover";
 export * as Title1 from "./customUI/Titles/Title1";
+

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

@@ -5,7 +5,6 @@ import { Container, Draggable } from "vue-dndrop";
 import { useEditor } from "../../..";
 import { HotKeyCtrl } from "../../../controllers/HotKeyCtrl";
 import Canvas from "../../Canvas";
-import { AnyFun } from "queenjs/typing";
 
 export default defineUI({
   setup() {
@@ -31,12 +30,7 @@ export default defineUI({
               const Comp: any = config.compUI[d.compKey]?.Component;
               return Comp ? (
                 <Draggable key={d.id}>
-                  <Comp
-                    compId={d.id}
-                    v-model={[d.value, "value"]}
-                    background={d.background}
-                    layout={d.layout}
-                  />
+                  <Comp compId={d.id} />
                 </Draggable>
               ) : undefined;
             })}

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

@@ -1,6 +1,7 @@
 import { useEditor } from "@/modules/editor";
 import { defineUI } from "queenjs";
 import { h } from "vue";
+import { createAttrsForm } from "../../CompUI/defines/createAttrsForm";
 
 export default defineUI({
   setup() {
@@ -11,11 +12,15 @@ export default defineUI({
       const { currComp } = editor.store;
 
       return (
-        <div>
-          <div class="p-16px border-bottom !border-2px">设置栏</div>
-          <div class="m-16px">
-            {currComp?.compKey &&
-              h(compUI[currComp.compKey].Form, { component: currComp })}
+        <div class="flex flex-col h-1/1">
+          <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 }
+            )}
           </div>
         </div>
       );

+ 21 - 3
src/modules/editor/defines/DesignTemp/DesignComp.ts

@@ -6,11 +6,29 @@ export class DesignComp {
   id = nanoid();
   compKey: ICompKeys = "Text";
   value: any = undefined;
-  layout?: Layout;
-  background?: Background;
+  layout?: Layout = {};
+  background?: Background = {};
+  children?: Record<string, DesignComp> = {};
 
   constructor(data?: Partial<DesignComp>) {
     if (!data) return;
-    Object.assign(this, cloneDeep(data));
+    const newData = filterObj(data);
+
+    if (newData.children) {
+      Object.entries(newData.children).forEach(([key, value]) => {
+        newData.children[key] = new DesignComp(value as any);
+      });
+    }
+    Object.assign(this, cloneDeep(newData));
   }
 }
+
+function filterObj(obj: any) {
+  const filteredObj: any = {};
+  Object.keys(obj).forEach((key) => {
+    if (obj[key] !== null && obj[key] !== undefined) {
+      filteredObj[key] = obj[key];
+    }
+  });
+  return filteredObj;
+}

+ 19 - 0
src/modules/editor/defines/DesignTemp/index.ts

@@ -12,3 +12,22 @@ export class DesignTemp {
     Object.assign(this, data);
   }
 }
+
+const a = {
+  content: [
+    {
+      id: "",
+      value: {},
+      background: {},
+      layout: {},
+      children: {
+        title: {
+          id: "",
+          value: {},
+          background: {},
+          layout: {},
+        },
+      },
+    },
+  ],
+};

+ 20 - 6
src/modules/editor/stores/index.ts

@@ -8,24 +8,36 @@ export const store = EditorModule.store({
     mode: "edit",
     currCompId: "",
     designData: new DesignTemp(),
+    designCompMap: new Map<string, DesignComp>(),
   }),
   getters: {
     isEditMode(state) {
       return state.mode === "edit";
     },
     currComp(state) {
-      const comp = state.designData.content.find(
-        (d) => d.id === state.currCompId
-      );
-      return comp;
+      return state.designCompMap.get(state.currCompId);
     },
   },
   actions: {
     setMode(v: string) {
       this.store.mode = v;
     },
+    initDesignCompMap() {
+      const { designData, designCompMap } = this.store;
+      const arr = [...designData.content];
+      designCompMap.clear();
+      while (arr.length) {
+        const item = arr[0];
+        designCompMap.set(item.id, item);
+        arr.shift();
+        if (item.children) {
+          arr.unshift(...Object.values(item.children));
+        }
+      }
+    },
     initDesignData(data: Partial<DesignTemp>) {
       this.store.designData = new DesignTemp(data);
+      this.store.initDesignCompMap();
     },
     insertDesignContent(compKey: ICompKeys, index?: number) {
       index || (index = this.store.designData.content.length);
@@ -33,10 +45,12 @@ export const store = EditorModule.store({
       const comp = new DesignComp({
         compKey,
         value: options?.value,
-        layout: options?.layout || {},
-        background: options?.background || {},
+        layout: options?.layout,
+        background: options?.background,
+        children: options?.children as any,
       });
       this.store.designData.content.splice(index, 0, comp);
+      this.store.initDesignCompMap();
       return comp;
     },
     setCurrComp(compId: string) {

+ 2 - 0
src/modules/editor/typings.ts

@@ -8,6 +8,8 @@ export type Layout = {
   offsetX?: number;
   offsetY?: number;
   zIndex?: number;
+  margin?: string;
+  padding?: string;
 };
 
 export type Background = {