瀏覽代碼

Merge branch 'dev' of http://124.70.149.18:10880/lianghj/queenshow into dev

qinyan 1 年之前
父節點
當前提交
1a90e64077

+ 26 - 11
src/modules/editor/components/CompUI/basicUI/Page/screen.tsx

@@ -6,28 +6,43 @@ export default defineComponent({
     setup(props, ctx) {
         const editor = useEditor();
         const ctrl = editor.controls.screenCtrl;
-        
+
         return ()=>{
             return (
                 <div class="px-16px">
                     <div class="flex items-center">
                         <span class="w-70px">屏幕类型</span>
-                        <Select value={ctrl.state.useFor} onChange={(v)=>{
-                            ctrl.state.setUseFor(v as any);
+                        <Select value={ctrl.state.screen.useFor} onChange={(v)=>{
+                            const s = {useFor: v, pageMode: ctrl.state.screen.pageMode, pageSizeType: ctrl.state.screen.pageSizeType}
+                            ctrl.saveScreenPage();
+                            ctrl.state.setScreen(s as any);
+
                         }} class = "flex-1 overflow-hidden" options={[{ label: "手机", value: "mobile" }, { label: "PC", value: "pc" }]}  />
                     </div>
                     <div  class="flex items-center mt-5px">
                         <span class="w-70px">页面模式</span>
                         <Select onChange={(v)=>{
-                            ctrl.state.setPageMode(v as any);
-                        }} value={ctrl.state.pageMode} class = "flex-1 overflow-hidden" options={[{ label: "长页", value: "long" }, { label: "翻页", value: "short" }]}  />
-                    </div>
-                    <div  class="flex items-center mt-5px">
-                        <span class="w-70px">屏幕长度</span>
-                        <Select onChange={(v)=>{
-                            ctrl.state.setPageSizeType(v as any);
-                        }} value={ctrl.state.pageSizeType} class = "flex-1 overflow-hidden" options={[{ label: "短屏幕", value: "short" }, { label: "普通屏幕", value: "normal"},  { label: "长屏幕", value: "long"}]}  />
+                            ctrl.saveScreenPage();
+                            const s = {useFor: ctrl.state.screen.useFor, pageMode:v, pageSizeType: ctrl.state.screen.pageSizeType} 
+                            if( v == "long") {
+                                s.pageSizeType = "normal";
+                            }
+                            ctrl.state.setScreen(s as any);
+                            editor.controls.editorCtrl.autoInScreen();
+
+                        }} value={ctrl.state.screen.pageMode} class = "flex-1 overflow-hidden" options={[{ label: "长页", value: "long" }, { label: "翻页", value: "short" }]}  />
                     </div>
+                    {
+                        ctrl.state.screen.pageMode == "short" && <div  class="flex items-center mt-5px">
+                           <span class="w-70px">屏幕长度</span>
+                           <Select onChange={(v)=>{
+                               ctrl.saveScreenPage();
+                               const s = {useFor: ctrl.state.screen.useFor, pageMode:ctrl.state.screen.pageMode, pageSizeType: v}
+                               ctrl.state.setScreen(s as any);
+                           }} value={ctrl.state.screen.pageSizeType} class = "flex-1 overflow-hidden" options={[{ label: "短屏幕", value: "short" }, { label: "普通屏幕", value: "normal"},  { label: "长屏幕", value: "long"}]}  />
+                       </div>
+                    }
+                 
                 </div>
             )
         }

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

@@ -122,7 +122,7 @@ export const View = defineComponent({
         }
       }
 
-      const isLongPage = controls.screenCtrl.state.pageMode == "long";
+      const isLongPage = controls.screenCtrl.isLongPage
 
       return (
         <div

+ 4 - 0
src/modules/editor/components/Viewport/Content/index.tsx

@@ -83,6 +83,7 @@ export default defineUI({
                       <div key={item} class={["card-item relative transition-opacity hover:opacity-80"]} style={style} onClick={()=>{
                          actions.selectObjs([]);
                          actions.pickComp(item, false);
+                         controls.editorCtrl.autoInScreen();
                       }}>
                           {
                               store.streamCardIds.length > 1 && <IconDelete onClick={()=>{
@@ -99,6 +100,9 @@ export default defineUI({
                 <img class="mt-15px cursor-pointer" onClick={()=>{
                       const index = store.streamCardIds.length;
                       actions.addCompToDesign("Container", index);
+                      setTimeout(() => {
+                        controls.editorCtrl.autoInScreen();
+                      }, 200);
                 }} src={require("@/assets/imgs/add.svg")} alt="" />
                 </Container>
               </div>

+ 5 - 0
src/modules/editor/controllers/EditorCtrl/index.ts

@@ -177,6 +177,11 @@ export class EditorCtrl extends ModuleControl<EditorModule> {
     this.state.setPos({x: left, y: top});
   }
 
+  autoInScreen() {
+     this.updateEditorSize();
+     this.setScale(1);
+  }
+
   setScale(scale: number) {
     if (isNaN(scale)) scale = this.state.scale;
     else if (scale < 0.5) scale = 0.5;

+ 6 - 0
src/modules/editor/controllers/HotKeyCtrl/index.ts

@@ -41,6 +41,12 @@ export class HotKeyCtrl extends ModuleControl<EditorModule> {
         this.actions.ctrlv();
       },
     },
+    {
+      hotKey: "ctrl+x",
+      action() {
+        this.actions.ctrlx();
+      },
+    },
     // 删除当前组件
     {
       hotKey: "Backspace,del",

+ 74 - 16
src/modules/editor/controllers/ScreenCtrl/index.ts

@@ -3,6 +3,7 @@ import { EditorModule } from "../../module";
 import { reactive } from "vue";
 import { DesignComp } from "../../objects/DesignTemp/DesignComp";
 import { RxValue } from "../ReactCtrl/rxValue";
+import { CardState } from "../../objects/DesignTemp";
 
 
 // const WidthHeightRatios = [1.377, 1.777, 2.177];
@@ -19,24 +20,29 @@ const PCRates = [0.42, 0.8];
 export const MobleScreenNames = ["短屏", "普通", "长屏幕"];
 export class ScreenCtrl extends ModuleControl<EditorModule> {
    state = RxValue.create({
-      useFor: "mobile" as "mobile" | "pc", // pc 还是 手机
-      pageMode: "long" as "long" | "short", //长页面还是短页面(一屏高度)
-      pageSizeType: "normal" as "normal" | "long" | "short", //适配类型 长屏 正常 短屏幕
-
+      screen: {
+            useFor: "mobile" as "mobile" | "pc", // pc 还是 手机
+            pageMode: "long" as "long" | "short", //长页面还是短页面(一屏高度)
+            pageSizeType: "normal" as "normal" | "long" | "short", //适配类型 长屏 正常 短屏幕
+      },
       docWidth: window.innerWidth,   //实际屏幕宽度
       docHeight: window.innerHeight,  //实际屏幕高度
       safeFactor: 0.8,
    })
+
    get isShortPage () {
-      return this.state.pageMode == "short";
+      return this.state.screen.pageMode == "short";
+   }
+   get isLongPage() {
+      return this.state.screen.pageMode == "long";
+   }
+   get currScreenId() {
+      return this.state.screen.useFor + this.state.screen.pageMode + this.state.screen.pageSizeType;
    }
    
    initEvent() {
       if ( !this.store.isEditMode ) return;
-
-      this.state.onUseForChanged(()=>this.updateAdapterState());
-      this.state.onPageModeChanged(()=>this.updateAdapterState());
-      this.state.onPageSizeTypeChanged(()=>this.updateAdapterState());
+      this.state.onScreenChanged(()=>this.updateAdapterState());
 
       const size = 3;
       const safeFactor =  Math.pow((PCRates[0] / PCRates[1]) , 1.0 / size);
@@ -56,12 +62,14 @@ export class ScreenCtrl extends ModuleControl<EditorModule> {
    }
 
    getAdapterIndex() {
-      if(this.state.pageMode == "long") return 1;
-      return ["short", "normal", "long"].indexOf(this.state.pageSizeType)
+      if(this.state.screen.pageMode == "long") return 1;
+      return ["short", "normal", "long"].indexOf(this.state.screen.pageSizeType)
    }
 
    updateAdapterState() {
       if (!this.store.rootPage) return;
+      
+      this.restorScreenPage();
 
       this.store.streamCardIds.forEach(c=>{
          const card = this.helper.findComp(c) as DesignComp;
@@ -72,15 +80,65 @@ export class ScreenCtrl extends ModuleControl<EditorModule> {
       const h =  this.helper.designSizeToPx(this.getCurrScreenHeight());
 
       this.controls.editorCtrl.state.setPage({w, h});
-
-     
       this.store.rootPage.layout.size[0] = this.getCurrScreenWidth();
-      this.store.rootPage.layout.size[1] = this.getCurrScreenHeight();
+      this.store.rootPage.layout.size[1] = this.getCurrScreenHeight(); 
+   }
+
+   restorScreenPage() {
+      if (!this.store.rootPage) return;
+
+      //获取当前screen的配置
+      const screenId = this.state.screen.useFor + this.state.screen.pageMode + this.state.screen.pageSizeType;
+      const screenCards = this.store.designData.compScreenMap[screenId] || [];
+
+      //刷新当前card的配置
+      this.store.streamCardIds.forEach(c=>{
+         const card = this.helper.findComp(c) as DesignComp;
+         const screenCard = screenCards.find(item=>item.id == c)
+         let newChilds:string[] = [];
+         let childrs = screenCard?.children || [];
+         childrs.forEach(item=>{
+            newChilds.push(item.id);
+            const screenComp = this.helper.findComp(item.id) as DesignComp;
+            screenComp.layout.size[0] = item.size[0];
+            screenComp.layout.size[1] = item.size[1];
+            screenComp.layout.transformMatrix = item.matrix;
+         })
+         card.children.default = newChilds;
+      })
+   }
+
+   saveScreenPage() {
+      //获取当前screen的配置
+      const screenId = this.state.screen.useFor + this.state.screen.pageMode + this.state.screen.pageSizeType;
+      const screenCards =  ScreenCtrl.createScreenCards(this.store.compMap, this.store.rootPage);
+      if (!this.store.designData.compScreenMap) this.store.designData.compScreenMap = {};
+      this.store.designData.compScreenMap[screenId] = screenCards;
+   }
+
+  static createScreenCards(compMap:any, rootPage: DesignComp) {
+      //获取当前screen的配置
+      const screenCards =  [] as CardState [];
+      const streamCardIds = rootPage.children.default || [];
+      streamCardIds.forEach(c=>{
+         const card = compMap[c] as DesignComp;
+         const screenCard :CardState = {
+            id: c,
+            children: []
+         }
+         let childrs = card.children.default || [];
+         childrs.forEach(item=>{
+            const c = compMap[item] as DesignComp;
+            screenCard.children.push({id: item, size: c.layout.size, matrix: c.layout.transformMatrix as string} );
+         })
+         screenCards.push(screenCard);
+      })
+      return screenCards;
    }
 
    getCurrScreenHeight() {
       const pageValue = this.state
-      if ( pageValue.useFor == "pc") {
+      if ( pageValue.screen.useFor == "pc") {
          return PCDesignHeight;
       }
       const currScreenIndex = this.getAdapterIndex();
@@ -90,7 +148,7 @@ export class ScreenCtrl extends ModuleControl<EditorModule> {
    getCurrScreenWidth() {
       const currScreenIndex = this.getAdapterIndex();
       const pageValue = this.state
-      if ( pageValue.useFor == "pc" ) {
+      if ( pageValue.screen.useFor == "pc" ) {
          return PCWidths[currScreenIndex];
       }
       return MobleDesignWidth

+ 90 - 19
src/modules/editor/module/actions/edit.tsx

@@ -1,4 +1,4 @@
-import { cloneDeep, pick } from "lodash";
+import { cloneDeep, curry, pick } from "lodash";
 import { Exception, queenApi } from "queenjs";
 import { EditorModule } from "..";
 import { ScreenshotCtrl } from "../../controllers/ScreenshotCtrl";
@@ -10,9 +10,17 @@ import { ObjsContainer } from "../../controllers/SelectCtrl/ObjsContainer";
 import { getKeyThenIncreaseKey } from "ant-design-vue/lib/message";
 import { Matrix } from "../../controllers/SelectCtrl/matrix";
 import { nanoid } from "nanoid";
-import { string } from "vue-types";
 
-let ctrlcselected: string[] = [];
+
+const ctrlState = {
+  selected: [] as string[],
+  type: 0,  // 1 ctrlc 2 ctrlx
+  cardId: "", //当前的卡片Id
+  screenId: "", //屏幕Id
+  selWidth: 0,
+  selX: 0,
+  selY: 0
+}
 
 export const editActions = EditorModule.action({
   pickComp(compId: string, selected = true) {
@@ -259,7 +267,7 @@ export const editActions = EditorModule.action({
       this.helper.extendStreamCard(compId);
 
       this.actions.selectObjs([]);
-      
+
       return;
     }
 
@@ -319,12 +327,30 @@ export const editActions = EditorModule.action({
   },
 
   ctrlc() {
-    //  console.log("contrc ", this.store.selected);
-    ctrlcselected = this.store.selected.slice(0);
+    ctrlState.selected = []; 
+    const children = this.store.currStreamCard.children.default || [];
+    children.forEach(c=>{
+      if (this.store.selected.indexOf(c) > -1) {
+        ctrlState.selected.push(c);
+      }
+    })
+    ctrlState.screenId = this.controls.screenCtrl.currScreenId;
+    ctrlState.cardId = this.store.currStreamCardId;
+    ctrlState.type = 1;
+    const objc = this.controls.selectCtrl.objContainer as ObjsContainer;
+    ctrlState.selWidth = this.helper.pxToDesignSize(objc.width);
+    objc.setPivot(0);
+    const currX = objc.parent.x, currY = objc.parent.y;
+    ctrlState.selX = currX;
+    ctrlState.selY = currY;
+    objc.setPivot(4);
   },
+
   copyLastSelected() {
     if (this.store.currCompId && this.store.currCompId != "root") {
-      ctrlcselected = [this.store.currCompId];
+      ctrlState.selected = [this.store.currCompId];
+      ctrlState.cardId = this.store.currStreamCardId;
+      ctrlState.type = 1;
     }
   },
 
@@ -368,10 +394,33 @@ export const editActions = EditorModule.action({
       }
     }
   },
+  ctrlx() {
+    //console.log("ctrlv ", this.store.selected);
+    //console.log("ctrlv ", this.store.selected);
+
+    //保持图层顺序
+    ctrlState.selected = []; 
+    const children = this.store.currStreamCard.children.default || [];
+    children.forEach(c=>{
+      if (this.store.selected.indexOf(c) > -1) {
+        ctrlState.selected.push(c);
+      }
+    })
+
+    ctrlState.cardId = this.store.currStreamCardId;
+    ctrlState.type = 2;
+    ctrlState.screenId = this.controls.screenCtrl.currScreenId;
+    const objc = this.controls.selectCtrl.objContainer as ObjsContainer;
+    ctrlState.selWidth = this.helper.pxToDesignSize(objc.width);
+    objc.setPivot(0);
+    const currX = objc.parent.x, currY = objc.parent.y;
+    ctrlState.selX = currX;
+    ctrlState.selY = currY;
+    objc.setPivot(4);
+  },
 
   ctrlv() {
-    console.log("ctrlv ", this.store.selected);
-    if (ctrlcselected.length < 1) return;
+    if (ctrlState.selected.length < 1) return;
 
     const news: string[] = [];
 
@@ -391,24 +440,46 @@ export const editActions = EditorModule.action({
       }
     };
 
-    ctrlcselected.forEach((c) => {
+
+    ctrlState.selected.forEach((c) => {
       const cp = this.helper.findComp(c) as DesignComp;
       const cp1 = cloneDeep(cp);
       cp1.id = nanoid();
       news.push(cp1.id);
-
       this.store.compMap[cp1.id] = cp1;
       this.store.setCompPid(cp1.id, this.store.currStreamCardId);
 
       deepCopy(cp);
     });
-
     this.actions.addComps(news);
 
     this.actions.selectObjs(news);
 
     setTimeout(() => {
-      this.controls.selectCtrl.translate(20, 20);
+      if (ctrlState.type == 2) {//剪辑删除原来的组件
+         const card = this.helper.findComp(ctrlState.cardId) as DesignComp;
+         const childs = card.children.default?.slice(0) || [];
+         ctrlState.selected.forEach(s=>{
+             let i = childs.indexOf(s);
+             if (i != -1) {
+              childs.splice(i, 1);
+             }
+         })
+         card.children.default = childs;
+         this.helper.extendStreamCard(ctrlState.cardId);
+         ctrlState.selected = [];
+      }
+
+      //获取当前选中的内容
+      if ( ctrlState.cardId != this.store.currStreamCardId) {//跨卡片拷贝
+          let pox = this.helper.getCardNextPosY(this.store.currStreamCardId, ctrlState.selWidth);
+          this.controls.selectCtrl.translate(0, pox.y - ctrlState.selY);
+          return;
+      }
+
+      if (ctrlState.screenId == this.controls.screenCtrl.currScreenId) {
+        this.controls.selectCtrl.translate(20, 20);
+      }
     }, 100);
   },
 
@@ -554,14 +625,14 @@ export const editActions = EditorModule.action({
   async saveDesign() {
     try {
       // 清除无用组件
-      this.helper.clearUnusedComps(this.store.designData.compMap);
+      this.helper.clearProjectUnusedComps(this.store.designData.compMap);
       const c = this.controls.screenCtrl;
-
+      c.saveScreenPage();
       const root = this.helper.findRootComp() as DesignComp;
-      root.value.useFor = c.state.useFor;
-      root.value.pageMode = c.state.pageMode;
-      root.value.pageSizeType = c.state.pageSizeType;
-
+      root.value.useFor = c.state.screen.useFor;
+      root.value.pageMode = c.state.screen.pageMode;
+      root.value.pageSizeType = c.state.screen.pageSizeType;
+      
       // 封面截屏
       if (!this.store.designData.thumbnail) {
         await this.actions.updateThumbnailByScreenshot();

+ 9 - 5
src/modules/editor/module/actions/init.ts

@@ -30,11 +30,6 @@ export const initActions = EditorModule.action({
     const ret = await this.https.getDesignDetail(id, { isSys });
     this.store.setDesignData(ret.result);
 
-    const root = this.helper.findRootComp() as DesignComp;
-    this.controls.screenCtrl.state.useFor = root.value.useFor || "mobile";
-    this.controls.screenCtrl.state.pageMode = root.value.pageMode || "long";
-    this.controls.screenCtrl.state.pageSizeType = root.value.pageSizeType || "normal";
-  
     //设置组件父子关系
     const ite = (root:any)=> {
       const cards = root.children?.default || [];
@@ -47,6 +42,15 @@ export const initActions = EditorModule.action({
       })
     }
     ite(this.store.rootPage);
+
+    const root = this.helper.findRootComp() as DesignComp;
+    this.controls.screenCtrl.state.screen.useFor= root.value.useFor || "mobile"
+    this.controls.screenCtrl.state.screen.pageMode = root.value.pageMode || "long"  
+    this.controls.screenCtrl.state.screen.pageSizeType = root.value.pageSizeType || "normal"
+
+    if ( !root.value.useFor && !root.value.pageMode ) {//模板版本
+
+    }
   },
 
   async initWkDesign(id: string) {

+ 64 - 0
src/modules/editor/module/helpers/index.ts

@@ -147,12 +147,49 @@ export const helpers = EditorModule.helper({
       return used;
     };
     getUsedIds([rootId]);
+
     Object.keys(compMap).forEach((compId) => {
       if (!used.has(compId)) {
         delete compMap[compId];
       }
     });
   },
+
+  clearProjectUnusedComps(compMap: Record<string, DesignComp>) {
+    const used = new Set<string>();
+    const getUsedIds = (ids: string[]) => {
+      ids.forEach((id) => {
+        const comp = compMap[id];
+        if (!comp) return;
+        used.add(id);
+        getUsedIds(comp.getChildIds());
+      });
+      return used;
+    };
+    getUsedIds(["root"]);
+
+    const compScreenMap = this.store.designData.compScreenMap
+    const keys = Object.keys(compScreenMap) 
+    keys.forEach(k=>{
+        const card = compScreenMap[k];
+        card.forEach(c=>{
+          c.children.forEach(item=>{
+            const comp = compMap[item.id];
+            if (!comp) return;
+            used.add(item.id);
+            getUsedIds([item.id])
+          })
+        })
+    })
+    
+    Object.keys(compMap).forEach((compId) => {
+      if (!used.has(compId)) {
+        delete compMap[compId];
+      }
+    });
+  },
+
+
   getPointOffsetWith(e: MouseEvent, dom: HTMLElement) {
     const domRect = dom.getBoundingClientRect();
     return {
@@ -196,6 +233,33 @@ export const helpers = EditorModule.helper({
     card.setH(maxH);
   },
 
+  getCardNextPosY(cardId:string, itemWidth:number) {
+      let yOffset = 0;
+      if (cardId != this.store.currStreamCardId) {
+        //const paths = this.helper.getCompTrees(cardId);
+        const bound = this.helper.getCardCompBound(cardId);
+        yOffset = bound.y + bound.h;
+      } else {
+        const currCard = this.helper.findComp(cardId) as DesignComp;
+        //没有选中组件添加到当前卡片最后
+        const children = currCard.children.default || [];
+        let prevCompIndex = -1;
+        if (this.store.currCompId != "" && this.store.currCompId != "root") {
+           prevCompIndex = children.indexOf(this.store.currCompId);
+        }
+        if (prevCompIndex != -1) {
+          const bound = this.helper.getCardCompBound(children[prevCompIndex]);
+          yOffset = bound.y + bound.h;
+        }
+      }
+      const w = this.controls.screenCtrl.getCurrScreenWidth();
+      //添加组件到当前选中的组件下面
+      const xOffset:number = this.helper.designSizeToPx(
+        w / 2.0 - (itemWidth || w) / 2
+      );
+      return {x: xOffset, y: yOffset};
+  },
+
   getClientId() {
     let clientId = undefined;
     try {

+ 0 - 7
src/modules/editor/module/stores/index.ts

@@ -179,7 +179,6 @@ export const store = EditorModule.store({
     },
 
     deleteComp(compId: string) {
-      const { compMap } = this.store.designData;
       const parentComp = this.helper.findParentComp(compId);
       let deleteOK = false;
       if (parentComp) {
@@ -196,12 +195,6 @@ export const store = EditorModule.store({
       }
 
       if (deleteOK) {
-        //不删除孩子节点
-        // const comp = this.helper.findComp(compId) as DesignComp;
-        // const ids = comp.getChildIds();
-        // [compId, ...ids].forEach((id) => {
-        //   delete compMap[id];
-        // });
         delete this.store.compPids[compId];
       }
     },

+ 9 - 2
src/modules/editor/objects/DesignTemp/index.ts

@@ -1,5 +1,11 @@
 import { DesignComp } from "./DesignComp";
 import { dataTransform } from "./versions/1.0.0";
+import { dataTransform as V101Upgrade } from "./versions/1.0.1";
+
+export type CardState = {
+  id: string;
+  children: {id:string, matrix: string, size: [number, number, { unit?: "px" | "%" }?]}[]
+}
 
 export class DesignTemp {
   version?: string;
@@ -7,13 +13,14 @@ export class DesignTemp {
   title = "";
   desc = "";
   pageStyle?: any;
-  content: string[] = ["root"];
+  content: string[] = ["root"]; //rootPcShort rootPcNormal rootPcLong rootMobShort rootMobLong
   thumbnail?: string;
   compMap: { [compId: string]: DesignComp } = {};
+  compScreenMap: {[Screen: string]: CardState[]} = {}
 
   constructor(data?: Partial<DesignTemp>) {
     if (!data) return;
-    Object.assign(this, dataTransform(data));
+    Object.assign(this, V101Upgrade(dataTransform(data)));
     // 初始化DesignComp
     Object.entries(this.compMap).forEach(([key, value]) => {
       this.compMap[key] = new DesignComp(value);

+ 14 - 0
src/modules/editor/objects/DesignTemp/versions/1.0.1.ts

@@ -0,0 +1,14 @@
+import { ScreenCtrl } from "@/modules/editor/controllers/ScreenCtrl";
+export function dataTransform(data: any) {
+  if (data.version == "1.0.1") {
+    return data;
+  }
+  data.version = "1.0.1";
+  if (!data.compScreenMap) { //默认为手机 long页面
+        data.compMap.root.value.pageMode = "long";
+        data.compMap.root.value.useFor = "mobile";
+        data.compMap.root.value.pageSizeType = "normal";
+      data.compScreenMap = {"mobilelongnormal": ScreenCtrl.createScreenCards(data.compMap, data.compMap.root)}
+   }
+   return data;
+}