lianghongjie 1 jaar geleden
bovenliggende
commit
486f42518b
25 gewijzigde bestanden met toevoegingen van 287 en 199 verwijderingen
  1. 2 1
      src/dict/imgs.ts
  2. 5 0
      src/modules/editor/components/CompUI/basicUI/Container/index.ts
  3. 6 1
      src/modules/editor/components/CompUI/basicUI/Image2/component.tsx
  4. 6 0
      src/modules/editor/components/CompUI/basicUI/Page/PageForm.tsx
  5. 5 0
      src/modules/editor/components/CompUI/basicUI/Page/index.ts
  6. 9 11
      src/modules/editor/components/CompUI/basicUI/Text/component.tsx
  7. 3 8
      src/modules/editor/components/CompUI/basicUI/Transfer/index.tsx
  8. 58 59
      src/modules/editor/components/CompUI/defines/createAttrsForm.tsx
  9. 2 1
      src/modules/editor/components/TipIcons/create.ts
  10. 5 0
      src/modules/editor/components/TipIcons/index.ts
  11. 45 43
      src/modules/editor/components/Viewport/Content/index.tsx
  12. 15 15
      src/modules/editor/components/Viewport/Toolbar/index.tsx
  13. 3 5
      src/modules/editor/components/Viewport/index.tsx
  14. 1 3
      src/modules/editor/controllers/TransferCtrl/index.ts
  15. 39 11
      src/modules/editor/module/actions/edit.ts
  16. 1 1
      src/modules/editor/module/actions/image.ts
  17. 49 27
      src/modules/editor/module/helpers/index.ts
  18. 2 2
      src/modules/editor/module/https/index.ts
  19. 2 0
      src/modules/editor/module/index.ts
  20. 15 2
      src/modules/editor/module/stores/index.ts
  21. 6 0
      src/modules/editor/objects/DesignTemp/creates/createCompStyle.ts
  22. 1 1
      src/modules/editor/objects/Toolbars/default.ts
  23. 2 0
      src/modules/editor/typings.ts
  24. 1 1
      src/pages/website/MyComps/components/CompItem.tsx
  25. 4 7
      src/pages/website/Promotion2/components/PromotionItem.tsx

+ 2 - 1
src/dict/imgs.ts

@@ -1,3 +1,4 @@
 export const Dict_Imgs = {
-  Default: require("@/assets/imgs/default.png") as string,
+  Default:
+    "https://sku3d-test.obs.cn-east-3.myhuaweicloud.com/queen/default.png",
 };

+ 5 - 0
src/modules/editor/components/CompUI/basicUI/Container/index.ts

@@ -13,6 +13,11 @@ export const { createComp, useCompData } = createCompHooks({
   children: {
     default: () => [] as string[],
   },
+  layout: {
+    background: {
+      color: "#ffffff",
+    },
+  },
 });
 
 export const Form = createAttrsForm([]);

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

@@ -11,7 +11,7 @@ export const Component = defineComponent({
   setup(props) {
     const comp = useCompData(props.compId);
 
-    const { store, controls } = useEditor();
+    const { store, controls, helper } = useEditor();
 
     async function changeVal() {
       const url = await controls.pickCtrl.pickOneImage();
@@ -51,6 +51,11 @@ export const Component = defineComponent({
                 ? value.url
                 : value.url + "?editMode=" + store.isEditMode
             }
+            onLoad={() => {
+              if (helper.isCurrComp(props.compId)) {
+                controls.transferCtrl.initStyle();
+              }
+            }}
           />
         </View>
       );

+ 6 - 0
src/modules/editor/components/CompUI/basicUI/Page/PageForm.tsx

@@ -3,6 +3,7 @@ import FormUI, { ColumnItem } from "@queenjs/components/FormUI";
 import { set } from "lodash";
 import { defineComponent } from "vue";
 import { any } from "vue-types";
+import { createColorOpts } from "../../defines/formOpts/createColorOpts";
 
 const styleColumns: ColumnItem[] = [
   {
@@ -10,6 +11,11 @@ const styleColumns: ColumnItem[] = [
     dataIndex: "padding",
     component: "Input",
   },
+  {
+    label: "背景颜色",
+    dataIndex: "background.color",
+    ...createColorOpts(),
+  },
 ];
 
 export const PageForm = defineComponent({

+ 5 - 0
src/modules/editor/components/CompUI/basicUI/Page/index.ts

@@ -13,6 +13,11 @@ export const { createComp, useCompData } = createCompHooks({
   children: {
     default: () => [] as string[],
   },
+  layout: {
+    background: {
+      color: "#ffffff",
+    },
+  },
 });
 
 export const Form = PageForm;

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

@@ -15,11 +15,9 @@ import { View } from "../View";
 export const Component = defineComponent({
   props: {
     compId: string().def(""),
-    value: string().def(""),
   },
-  emits: ["update:value"],
-  setup(props, { emit }) {
-    const comp = props.compId ? useCompData(props.compId) : null;
+  setup(props) {
+    const comp = useCompData(props.compId);
     const { store } = useEditor();
     const config = {
       plugins: [
@@ -58,22 +56,21 @@ export const Component = defineComponent({
     return () => (
       <View
         class={[textStyle, store.currCompId === props.compId && "drag-disable"]}
-        style={{ ["--text-len"]: comp?.value.length }}
         compId={props.compId}
       >
         <ckeditor
           class={textStyle}
           editor={InlineEditor}
           onBlur={() => {
-            if (comp) {
-              comp.value = editorInstance.getData();
-            } else {
-              emit("update:value", editorInstance.getData());
-            }
+            store.setTextEditingState(false);
+            comp.value = editorInstance.getData();
+          }}
+          onFocus={() => {
+            store.setTextEditingState(true);
           }}
           onReady={(editor: InlineEditor) => {
             editorInstance = editor;
-            editor.setData(comp?.value || props.value);
+            editor.setData(comp.value);
             if (store.isPreview) {
               editor.enableReadOnlyMode("editor");
             }
@@ -93,6 +90,7 @@ const textStyle = css`
   }
   .ck.ck-editor__editable_inline {
     cursor: text;
+    overflow: hidden;
     pointer-events: none;
 
     > :last-child,

+ 3 - 8
src/modules/editor/components/CompUI/basicUI/Transfer/index.tsx

@@ -1,14 +1,13 @@
+import { CompToolbars } from "@/modules/editor/objects/Toolbars";
 import { css } from "@linaria/core";
 import { defineComponent, onMounted, onUnmounted } from "vue";
 import { useEditor } from "../../../..";
-import { TransferCtrl } from "@/modules/editor/controllers/TransferCtrl";
-import { CompToolbars } from "@/modules/editor/objects/Toolbars";
 
 export const Transfer = defineComponent({
   setup() {
     const editor = useEditor();
-    const { store } = editor;
-    const transferCtrl = new TransferCtrl(editor);
+    const { store, controls } = editor;
+    const { transferCtrl } = controls;
     const { transferStyle } = transferCtrl;
 
     onMounted(() => {
@@ -24,10 +23,6 @@ export const Transfer = defineComponent({
       transferCtrl.destroy();
     });
 
-    onUnmounted(() => {
-      transferCtrl.resetStyle();
-    });
-
     return () => {
       const comp = store.currComp;
       const toolbarOpts =

+ 58 - 59
src/modules/editor/components/CompUI/defines/createAttrsForm.tsx

@@ -1,13 +1,12 @@
 import { DesignComp } from "@/modules/editor/objects/DesignTemp/DesignComp";
+import { compMasks } from "@/modules/editor/objects/DesignTemp/creates/CompMasks";
 import FormUI, { ColumnItem } from "@queenjs/components/FormUI";
+import { InputNumber, Select } from "ant-design-vue";
 import { isEmpty, set } from "lodash";
 import { defineComponent } from "vue";
 import { any } from "vue-types";
 import { GroupNumber } from "../formItems/GroupNumber";
-import { InputNumber, Select } from "ant-design-vue";
 import { createColorOpts } from "./formOpts/createColorOpts";
-import { ImagePicker } from "../formItems/ImagePicker";
-import { compMasks } from "@/modules/editor/objects/DesignTemp/creates/CompMasks";
 
 const layoutColumns: ColumnItem[] = [
   {
@@ -91,63 +90,63 @@ const layoutColumns: ColumnItem[] = [
 const bgColumns: ColumnItem[] = [
   {
     label: "背景颜色",
-    dataIndex: "background.color",
+    dataIndex: "layout.background.color",
     ...createColorOpts(),
   },
-  {
-    label: "背景图片",
-    dataIndex: "background.image",
-    component: ImagePicker,
-  },
-  {
-    label: "repeat",
-    dataIndex: "background.repeat",
-    component: "Select",
-    props: {
-      options: [
-        "repeat",
-        "no-repeat",
-        "repeat-x",
-        "repeat-y",
-        "repeat-round",
-        "repeat-space",
-      ].map((v) => ({ label: v, value: v })),
-    },
-  },
-  {
-    label: "position",
-    dataIndex: "background.position",
-    component: "Select",
-    props: {
-      options: [
-        "center",
-        "top",
-        "bottom",
-        "left",
-        "left-top",
-        "left-bottom",
-        "right",
-        "right-top",
-        "right-bottom",
-      ].map((v) => ({ label: v, value: v })),
-    },
-  },
-  {
-    label: "size",
-    dataIndex: "background.size",
-    component: "Select",
-    props: {
-      options: ["auto", "cover", "contain"].map((v) => ({
-        label: v,
-        value: v,
-      })),
-    },
-  },
-  {
-    label: "clipPath",
-    dataIndex: "background.clipPath",
-    component: "Input",
-  },
+  // {
+  //   label: "背景图片",
+  //   dataIndex: "background.image",
+  //   component: ImagePicker,
+  // },
+  // {
+  //   label: "repeat",
+  //   dataIndex: "background.repeat",
+  //   component: "Select",
+  //   props: {
+  //     options: [
+  //       "repeat",
+  //       "no-repeat",
+  //       "repeat-x",
+  //       "repeat-y",
+  //       "repeat-round",
+  //       "repeat-space",
+  //     ].map((v) => ({ label: v, value: v })),
+  //   },
+  // },
+  // {
+  //   label: "position",
+  //   dataIndex: "background.position",
+  //   component: "Select",
+  //   props: {
+  //     options: [
+  //       "center",
+  //       "top",
+  //       "bottom",
+  //       "left",
+  //       "left-top",
+  //       "left-bottom",
+  //       "right",
+  //       "right-top",
+  //       "right-bottom",
+  //     ].map((v) => ({ label: v, value: v })),
+  //   },
+  // },
+  // {
+  //   label: "size",
+  //   dataIndex: "background.size",
+  //   component: "Select",
+  //   props: {
+  //     options: ["auto", "cover", "contain"].map((v) => ({
+  //       label: v,
+  //       value: v,
+  //     })),
+  //   },
+  // },
+  // {
+  //   label: "clipPath",
+  //   dataIndex: "background.clipPath",
+  //   component: "Input",
+  // },
 ];
 
 export function createAttrsForm(valueColumns: ColumnItem[]) {
@@ -180,7 +179,7 @@ export function createAttrsForm(valueColumns: ColumnItem[]) {
               columns={layoutColumns}
               onChange={changeVal}
             />
-            {!isEmpty(component?.background) ? (
+            {!isEmpty(component?.layout?.background) ? (
               <>
                 <div>组件背景</div>
                 <FormUI

+ 2 - 1
src/modules/editor/components/TipIcons/create.ts

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

+ 5 - 0
src/modules/editor/components/TipIcons/index.ts

@@ -3,6 +3,7 @@ import {
   IconArrowRight,
   IconAxis,
   IconBtnNext,
+  IconCamera,
   IconClear,
   IconCube,
   IconDelete,
@@ -20,6 +21,10 @@ import {
 import { createTipIcon } from "./create";
 
 export const TipIcons = {
+  Screenshot: createTipIcon({
+    icons: [IconCamera],
+    tips: ["截屏并保存封面"],
+  }),
   Align: createTipIcon({
     icons: [IconArrowLeft, IconAxis, IconArrowRight],
     tips: ["左对齐", "居中", "右对齐"],

+ 45 - 43
src/modules/editor/components/Viewport/Content/index.tsx

@@ -11,7 +11,7 @@ import { Transfer } from "../../CompUI/basicUI/Transfer";
 export default defineUI({
   setup() {
     const editor = useEditor();
-    const { store, actions, helper, components, controls } = editor;
+    const { store, actions, helper, controls } = editor;
 
     const hotKeyCtrl = new HotKeyCtrl(editor);
     hotKeyCtrl.init();
@@ -28,54 +28,56 @@ export default defineUI({
     return () => {
       const pageRoot = helper.findRootComp();
       if (!pageRoot) return;
-      return store.isEditMode ? (
-        <CompUI.Page.Component class={contentStyle} compId={pageRoot.id}>
-          {{
-            Container(children: any) {
-              return (
-                <>
-                  <Container
-                    class={store.isEditPage ? "!min-h-750px" : ""}
-                    group-name="canvas"
-                    onDrop={(e: any) => {
-                      if (e.payload) {
-                        actions.addCompToDesign(e.payload, e.addedIndex);
-                      } else {
-                        actions.moveComp(e.removedIndex, e.addedIndex);
-                      }
-                    }}
-                    onDragStart={() => (state.draging = true)}
-                    onDragEnd={() => (state.draging = false)}
-                    non-drag-area-selector={".drag-disable"}
-                  >
-                    {children}
-                  </Container>
-                  {store.currCompId &&
-                    store.currCompId !== "root" &&
-                    !state.draging && <Transfer key={store.currCompId} />}
-                </>
-              );
-            },
-            CompItem(comp: DesignComp) {
-              const Comp =
-                controls.compUICtrl.state.components.get(comp.compKey)
-                  ?.Component || NotFoundComp;
-              return (
-                <Draggable class="!flex flex-col" key={comp.id}>
-                  <Comp compId={comp.id} />
-                </Draggable>
-              );
-            },
-          }}
-        </CompUI.Page.Component>
-      ) : (
-        <components.Preview />
+      return (
+        <div class="flex justify-center my-60px ">
+          <CompUI.Page.Component class={contentStyle} compId={pageRoot.id}>
+            {{
+              Container(children: any) {
+                return (
+                  <>
+                    <Container
+                      class={store.isEditPage ? "!min-h-750px" : ""}
+                      group-name="canvas"
+                      onDrop={(e: any) => {
+                        if (e.payload) {
+                          actions.addCompToDesign(e.payload, e.addedIndex);
+                        } else {
+                          actions.moveComp(e.removedIndex, e.addedIndex);
+                        }
+                      }}
+                      onDragStart={() => (state.draging = true)}
+                      onDragEnd={() => (state.draging = false)}
+                      non-drag-area-selector={".drag-disable"}
+                    >
+                      {children}
+                    </Container>
+                    {store.currCompId &&
+                      store.currCompId !== "root" &&
+                      !store.textEditingState &&
+                      !state.draging && <Transfer key={store.currCompId} />}
+                  </>
+                );
+              },
+              CompItem(comp: DesignComp) {
+                const Comp =
+                  controls.compUICtrl.state.components.get(comp.compKey)
+                    ?.Component || NotFoundComp;
+                return (
+                  <Draggable class="!flex flex-col" key={comp.id}>
+                    <Comp compId={comp.id} />
+                  </Draggable>
+                );
+              },
+            }}
+          </CompUI.Page.Component>
+        </div>
       );
     };
   },
 });
 
 const contentStyle = css`
+  width: 375px;
   position: relative;
   user-select: none;
 

+ 15 - 15
src/modules/editor/components/Viewport/Toolbar/index.tsx

@@ -1,25 +1,25 @@
 import { useEditor } from "@/modules/editor";
-import { Button } from "ant-design-vue";
 import { defineUI } from "queenjs";
+import { TipIcons } from "../../TipIcons";
+import { css } from "@linaria/core";
 
 export default defineUI({
   setup() {
-    const { history } = useEditor().controls.historyCtrl;
+    const { actions } = useEditor();
     return () => (
-      <div>
-        <Button
-          onClick={() => history.undo()}
-          disabled={!history.state.canUndo}
-        >
-          撤销
-        </Button>
-        <Button
-          onClick={() => history.redo()}
-          disabled={!history.state.canRedo}
-        >
-          重做
-        </Button>
+      <div class="absolute top-20px right-20px">
+        <TipIcons.Screenshot
+          class={btnCls}
+          onClick={() => actions.updateThumbnailByScreenshot(true)}
+        />
       </div>
     );
   },
 });
+
+const btnCls = css`
+  padding: 10px;
+  border-radius: 50%;
+  background-color: #333;
+  @apply shadow;
+`;

+ 3 - 5
src/modules/editor/components/Viewport/index.tsx

@@ -19,11 +19,9 @@ export default defineUI({
         <slots.Header class="p-16px bg-component border-bottom !border-2px" />
         <div class="flex flex-1 h-0">
           <slots.SliderLeft class="w-300px bg-component border-right !border-2px" />
-          <div class="flex-1 h-1/1 scrollbar overflow-y-auto">
-            {/* <slots.Toolbar /> */}
-            <div class="flex justify-center my-60px ">
-              <slots.Content class="w-375px bg-white" />
-            </div>
+          <div class="flex-1 h-1/1 scrollbar overflow-y-auto relative">
+            <slots.Toolbar />
+            <slots.Content />
           </div>
           <slots.SliderRight class="w-360px bg-component border-left !border-2px" />
         </div>

+ 1 - 3
src/modules/editor/controllers/TransferCtrl/index.ts

@@ -84,9 +84,6 @@ export class TransferCtrl extends ModuleControl<EditorModule> {
     });
     this.currObserver.observe(this.compEl, {
       attributes: true,
-      childList: true,
-      subtree: true,
-      characterDataOldValue: true,
     });
   }
 
@@ -107,5 +104,6 @@ export class TransferCtrl extends ModuleControl<EditorModule> {
 
   destroy() {
     this.currObserver?.disconnect();
+    this.resetStyle();
   }
 }

+ 39 - 11
src/modules/editor/module/actions/edit.ts

@@ -2,6 +2,7 @@ import { Exception, queenApi } from "queenjs";
 import { EditorModule } from "..";
 import { DesignComp } from "../../objects/DesignTemp/DesignComp";
 import { ICompKeys } from "../../typings";
+import { pick } from "lodash";
 
 export const editActions = EditorModule.action({
   // 添加组件到画布
@@ -35,10 +36,12 @@ export const editActions = EditorModule.action({
   },
   // 删除组件
   removeComp(compId: string) {
-    if (compId === this.store.currCompId) {
-      this.store.setCurrComp("");
+    if (this.helper.isCompCanDelete(compId)) {
+      if (compId === this.store.currCompId) {
+        this.store.setCurrComp("");
+      }
+      this.store.deleteComp(compId);
     }
-    this.store.deleteComp(compId);
   },
   // 移动组件
   moveComp(selIndex: number, targetIndex: number) {
@@ -48,16 +51,17 @@ export const editActions = EditorModule.action({
 
   // 保存项目
   async saveDesign() {
-    try {
-      queenApi.showLoading("保存中");
-      // 清除无用组件
-      this.store.setCurrComp("");
-      this.store.clearUnusedComps();
+    // 清除无用组件
+    this.store.setCurrComp("");
+    this.store.clearUnusedComps();
 
-      // 封面截屏
-      const blob = await this.helper.screenshot();
-      this.store.designData.thumbnail = URL.createObjectURL(blob);
+    // 封面截屏
+    if (!this.store.designData.thumbnail) {
+      await this.actions.updateThumbnailByScreenshot();
+    }
 
+    try {
+      queenApi.showLoading("保存中");
       await this.controls.uploader.uploadBlobs(this.store.designData);
       await this.https[this.store.isEditPage ? "saveDesign" : "saveComp"](
         this.store.designData
@@ -70,6 +74,30 @@ export const editActions = EditorModule.action({
     }
   },
 
+  // 截屏保存封面
+  async updateThumbnailByScreenshot(autoSave?: boolean) {
+    try {
+      queenApi.showLoading("截屏中");
+      const blob = await this.helper.screenshot({
+        ratio: this.store.isEditComp ? 0 : 1,
+      });
+      const thumbnail = URL.createObjectURL(blob);
+      this.store.updateDesignThumbnail(thumbnail);
+
+      if (autoSave) {
+        await this.controls.uploader.uploadBlobs(this.store.designData);
+        await this.https[this.store.isEditPage ? "saveDesign" : "saveComp"](
+          pick(this.store.designData, ["_id", "thumbnail"])
+        );
+        queenApi.messageSuccess("保存成功");
+      }
+    } catch (error: any) {
+      throw Exception.error(error.toString());
+    } finally {
+      queenApi.hideLoading();
+    }
+  },
+
   // 设置组件显示隐藏
   setCompPosition(comp: DesignComp) {
     comp.layout.position =

+ 1 - 1
src/modules/editor/module/actions/image.ts

@@ -4,7 +4,7 @@ export const ImgCompActions = EditorModule.action({
   handleImageHotKey(key: string) {
     if (!this.store.isEditMode) return;
     if (this.store.currComp?.compKey !== "Image") return;
-    
+
     const value = this.store.currComp.value;
     if (key == "w") {
       value.y = (parseFloat(value.y) - 0.5).toFixed(2);

+ 49 - 27
src/modules/editor/module/helpers/index.ts

@@ -35,6 +35,9 @@ export const helpers = EditorModule.helper({
   createStyle(layout: Partial<Layout>) {
     return createCompStyle(this, layout);
   },
+  isCurrComp(compId: string) {
+    return this.store.currCompId === compId;
+  },
   isCustomChildComp(comp: DesignComp): boolean {
     const parentComp = this.helper.findParentComp(comp.id);
     if (!parentComp) return false;
@@ -42,32 +45,51 @@ export const helpers = EditorModule.helper({
       parentComp.children.default?.findIndex((d) => d === comp.id) ?? -1;
     return i >= 0;
   },
-  // async screenshot() {
-  //   // 解决html2canvas不支持object-fit的问题
-  //   // https://github.com/niklasvh/html2canvas/issues/1064
-  //   const dom = document.querySelector(".page-editing-content") as HTMLElement;
-  //   const canvas = await html2canvas(dom, {
-  //     useCORS: true,
-  //   });
-  //   dom.appendChild(canvas);
-  //   return new Promise<Blob>((resolve, reject) => {
-  //     canvas.toBlob((blob) => {
-  //       if (blob) {
-  //         resolve(blob);
-  //       } else {
-  //         reject("截屏失败");
-  //       }
-  //     });
-  //   });
-  // },
-  async screenshot() {
-    const dom = document.querySelector(".page-editing-content")?.parentElement as HTMLElement;
-    const result = domtoimage.toBlob(dom);
-    // result.then((blob) => {
-    //   const img = document.createElement("img");
-    //   img.src = URL.createObjectURL(blob);
-    //   dom.appendChild(img);
-    // });
-    return result;
+  isCompCanDelete(compId: string): boolean {
+    const comp = this.helper.findComp(compId);
+    if (!comp || !this.helper.isCustomChildComp(comp)) return false;
+    if (this.store.isEditComp) return true;
+    return this.store.pageCompIds.includes(compId);
+  },
+  async screenshot(options?: { ratio: number }): Promise<Blob> {
+    const dom = document.querySelector(".page-editing-content")
+      ?.parentElement as HTMLElement;
+    if (options?.ratio) {
+      const result = await domtoimage.toJpeg(dom);
+      const img = await new Promise<HTMLImageElement>((resolve) => {
+        const image = new Image();
+        image.src = result;
+        image.onload = function () {
+          resolve(image);
+        };
+      });
+      const canvas = document.createElement("canvas");
+      canvas.width = img.naturalWidth;
+      canvas.height = Math.min(
+        img.naturalWidth / options.ratio,
+        img.naturalHeight
+      );
+      const ctx = canvas.getContext("2d");
+      ctx?.drawImage(
+        img,
+        0,
+        0,
+        canvas.width,
+        canvas.height,
+        0,
+        0,
+        canvas.width,
+        canvas.height
+      );
+      return new Promise((resolve) => {
+        canvas.toBlob((blob) => {
+          if (blob) {
+            resolve(blob);
+          }
+        });
+      });
+    } else {
+      return domtoimage.toBlob(dom);
+    }
   },
 });

+ 2 - 2
src/modules/editor/module/https/index.ts

@@ -12,13 +12,13 @@ export const https = EditorModule.http({
       method: "GET",
     });
   },
-  saveDesign(data: DesignTemp) {
+  saveDesign(data: Partial<DesignTemp>) {
     return this.request("/h5/update", {
       method: "POST",
       data,
     });
   },
-  saveComp(data: DesignTemp) {
+  saveComp(data: Partial<DesignTemp>) {
     return this.request("/frame/update", {
       method: "POST",
       data,

+ 2 - 0
src/modules/editor/module/index.ts

@@ -11,6 +11,7 @@ import { helpers } from "./helpers";
 import { https } from "./https";
 import { store } from "./stores";
 import { UploadController } from "@queenjs/controllers";
+import { TransferCtrl } from "../controllers/TransferCtrl";
 
 export class EditorModule extends ModuleRoot {
   config = this.setConfig({
@@ -32,6 +33,7 @@ export class EditorModule extends ModuleRoot {
       },
       dir: "queenshow",
     }),
+    transferCtrl: new TransferCtrl(this),
     historyCtrl: new HistoryCtrl(this),
     pickCtrl: new ImagePickController(),
     compUICtrl: new CompUICtrl(this),

+ 15 - 2
src/modules/editor/module/stores/index.ts

@@ -5,6 +5,7 @@ import { EditorMode, ICompKeys } from "../../typings";
 
 export const store = EditorModule.store({
   state: () => ({
+    textEditingState: false,
     mode: "editPage" as EditorMode,
     currCompId: "root",
     designData: new DesignTemp(),
@@ -42,12 +43,18 @@ export const store = EditorModule.store({
     async insertDesignContent(compKey: ICompKeys, index?: number) {
       const { pageCompIds } = this.store;
       index === undefined && (index = pageCompIds.length);
-      const compId = await this.controls.compUICtrl.createCompId(compKey, "root");
+      const compId = await this.controls.compUICtrl.createCompId(
+        compKey,
+        "root"
+      );
       pageCompIds.splice(index, 0, compId);
       return compId;
     },
     async insertCompContainer(compKey: ICompKeys, container: DesignComp) {
-      const compId = await this.controls.compUICtrl.createCompId(compKey, container.id);
+      const compId = await this.controls.compUICtrl.createCompId(
+        compKey,
+        container.id
+      );
       container.children.default || (container.children.default = []);
       container.children.default.push(compId);
       return compId;
@@ -103,5 +110,11 @@ export const store = EditorModule.store({
         }
       });
     },
+    setTextEditingState(state: boolean) {
+      this.store.textEditingState = state;
+    },
+    updateDesignThumbnail(url: string) {
+      this.store.designData.thumbnail = url;
+    },
   },
 });

+ 6 - 0
src/modules/editor/objects/DesignTemp/creates/createCompStyle.ts

@@ -61,6 +61,12 @@ export function createCompStyle(module: EditorModule, layout: Layout) {
     style.transform = styleTransform;
   }
 
+  if (layout.background) {
+    if (layout.background.color) {
+      style.backgroundColor = layout.background.color;
+    }
+  }
+
   return style;
 }
 

+ 1 - 1
src/modules/editor/objects/Toolbars/default.ts

@@ -64,7 +64,7 @@ export const toolbars = createToolbars({
   delete: {
     component: TipIcons.Delete,
     getVisible(comp) {
-      return this.helper.isCustomChildComp(comp);
+      return this.helper.isCompCanDelete(comp.id);
     },
     onClick(comp) {
       this.actions.removeComp(comp.id);

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

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

+ 1 - 1
src/pages/website/MyComps/components/CompItem.tsx

@@ -1,7 +1,7 @@
 import { css, cx } from "@linaria/core";
 import { IconMore } from "@queenjs/icons";
 import { Image, View } from "@queenjs/ui";
-import { Dropdown, Menu, Tag } from "ant-design-vue";
+import { Dropdown, Menu } from "ant-design-vue";
 import dayjs from "dayjs";
 import { defineUI } from "queenjs";
 import { any } from "vue-types";

+ 4 - 7
src/pages/website/Promotion2/components/PromotionItem.tsx

@@ -1,13 +1,13 @@
+import { clipboard } from "@/utils";
 import { css, cx } from "@linaria/core";
 import { IconMore } from "@queenjs/icons";
 import { Image, View } from "@queenjs/ui";
-import { Divider, Dropdown, Menu, Tag, Button } from "ant-design-vue";
+import { useQRCode } from "@vueuse/integrations/useQRCode";
+import { Button, Dropdown, Menu } from "ant-design-vue";
 import dayjs from "dayjs";
 import { defineUI } from "queenjs";
 import { defineComponent } from "vue";
 import { any, string } from "vue-types";
-import { useQRCode } from "@vueuse/integrations/useQRCode";
-import { useClipboard } from "@vueuse/core";
 
 const ShareBox = defineComponent({
   props: {
@@ -22,15 +22,12 @@ const ShareBox = defineComponent({
     }
 
     const qrUrl = useQRCode(shareLink);
-    const { copy, copied } = useClipboard();
 
     return () => (
       <div class="p-20px bg-dark-500 text-center">
         <img src={qrUrl.value} />
         <div class="mb-20px"></div>
-        <Button onClick={() => copy(shareLink)} disabled={copied.value}>
-          {copied.value ? "已复制" : "复制链接"}
-        </Button>
+        <Button onClick={() => clipboard.copy(shareLink)}>复制链接</Button>
       </div>
     );
   },