import { cloneDeep, pick } from "lodash"; import { Exception, queenApi } from "queenjs"; import { EditorModule } from ".."; import { ScreenshotCtrl } from "../../controllers/ScreenshotCtrl"; import { CompObject } from "../../controllers/SelectCtrl/compObj"; import { DesignComp } from "../../objects/DesignTemp/DesignComp"; import { ICompKeys, Layout } from "../../typings"; import CompSave from "../../components/CompSave"; 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[] = []; export const editActions = EditorModule.action({ pickComp(compId: string, selected = true) { if (compId == "") { //空的时候,就选择根页面 compId = "root"; } const selectCardChild = (id: string) => { const paths = this.helper.getCompTrees(id); const cardChilds = paths[2]; if (cardChilds) { this.actions.selectObjs([cardChilds.id]); } else { this.actions.selectObjs([]); if (id != "root") { this.store.setCurrComp(this.store.currStreamCardId); } } }; if (this.store.currCompId == compId) { return; } this.store.setCurrComp(compId); if (selected) { selectCardChild(compId); } }, // 通过点击添加组件到画布 async clickCompToDesign(compKey: ICompKeys, cb?: (comp: DesignComp) => void) { if (!this.store.currStreamCardId) { queenApi.messageError("请先选中一个卡片"); return; } //点击默认都创建一个容器 //创建容器 const isCreatCard = compKey != "Text" && compKey != "Image" && compKey != "Rectage" && compKey != "Line" && compKey != "Arc" && compKey != "Triangle" && compKey != "Ellipse" && compKey != "Polygon" && compKey != "PolygonNormal" && compKey != "Curve"; let yOffset = 0; if ( this.store.currCompId != this.store.currStreamCardId && !isCreatCard && this.store.currCompId != "root" ) { const bound = this.helper.getCardCompBound(this.store.currCompId); yOffset = bound.y + bound.h; } let currCard = this.store.currStreamCard; if (isCreatCard) { //先创建卡片 const currCardIndex = this.store.streamCardIds.indexOf(this.store.currStreamCardId) + 1; const compId = await this.store.insertDesignContent( "Container", currCardIndex ); currCard = this.helper.findComp(compId) as DesignComp; } const compId = await this.store.insertCompContainer(compKey, currCard); const addedComp = this.store.compMap[compId]; addedComp.layout.position = "absolute"; const currComp = this.helper.findComp(compId) as DesignComp; cb?.(currComp); //添加组件到当前选中的组件下面 let xOffset = this.helper.designSizeToPx( 375 - (currComp.layout.size?.[0] || 750) / 2 ); const obj = new CompObject(currComp); //没有选中组件添加到当前卡片最后 const children = currCard.children.default || []; if (yOffset == 0 && children.length >= 2) { const prevCompIndex = children.indexOf(compId) - 1; const bound = this.helper.getCardCompBound(children[prevCompIndex]); yOffset = bound.y + bound.h; } obj.worldTransform.translate(xOffset, yOffset); currComp.layout.transformMatrix = obj.worldTransform.getMatrixStr(); this.actions.pickComp(compId); this.helper.extendStreamCard(currCard.id); if (compKey == "Text") { this.actions.textFocus(compId, true); } this.controls.cropCtrl.close(); }, // 通过点击添加组件到画布 async clickCompUserToDesign(id: string, isSys) { if (!this.store.currStreamCardId) { queenApi.messageError("请先选中一个卡片"); return; } const { result } = await this.https.getCompDetail(id, isSys); //先创建卡片 // const currCardIndex = this.store.streamCardIds.indexOf(this.store.currStreamCardId) + 1; // const cardId = await this.store.insertDesignContent( // "Container", // currCardIndex // ); // const currCard = this.helper.findComp(cardId) as DesignComp; const currCard = this.store.currStreamCard; const comp = this.store.addUserCard(result); const compId = comp.id; const childIds = [...(currCard.children.default || [])]; childIds.push(compId); currCard.children.default = childIds; this.store.setCompPid(compId, currCard.id); const addedComp = this.store.compMap[compId]; addedComp.layout.position = "absolute"; this.actions.initAddedCompPos(this.store.currCompId, compId, currCard.id); this.actions.pickComp(compId); }, initAddedCompPos(currId: string, addedId:string, cardId:string) { let yOffset = 0; if ( currId != this.store.currStreamCardId && currId != "root" ) { const paths = this.helper.getCompTrees(currId) const bound = this.helper.getCardCompBound(paths[2].id); yOffset = bound.y + bound.h; } const currComp = this.helper.findComp(addedId) as DesignComp; //添加组件到当前选中的组件下面 let xOffset = this.helper.designSizeToPx( 375 - (currComp.layout.size?.[0] || 750) / 2 ); const obj = new CompObject(currComp); const currCard = this.helper.findComp(cardId) as DesignComp; //没有选中组件添加到当前卡片最后 const children = currCard.children.default || []; if (yOffset == 0 && children.length >= 2) { const prevCompIndex = children.indexOf(addedId) - 1; const bound = this.helper.getCardCompBound(children[prevCompIndex]); yOffset = bound.y + bound.h; } obj.worldTransform.translate(xOffset, yOffset); currComp.layout.transformMatrix = obj.worldTransform.getMatrixStr(); this.helper.extendStreamCard(currCard.id); this.controls.cropCtrl.close(); }, // 通过拖拽添加组件到画布 async dragCompToDesign(event: MouseEvent, compKey: string, data:any) { const currCardDom = this.store.currStreamCard.$el; if (compKey == "CompCard") { const { result } = await this.https.getCompDetail(data.id, data.isSys); const comp = this.store.addUserCard(result); const currCard = this.store.currStreamCard; const compId = comp.id; const childIds = [...(currCard.children.default || [])]; childIds.push(compId); currCard.children.default = childIds; const addedComp = this.store.compMap[compId]; addedComp.layout.position = "absolute"; this.store.setCompPid(compId, currCard.id); this.actions.pickComp(compId); } else { await this.actions.addCompToDesign(compKey as any); } setTimeout(() => { const cardPoints = this.helper.getPointOffsetWith( event, currCardDom ); const { currComp } = this.store; let selCtrl = this.controls.selectCtrl; selCtrl.translate( this.helper.designSizeToPx(375 - (currComp.layout.size?.[0] || 750) / 2), cardPoints.y ); this.helper.extendStreamCard(this.store.currStreamCardId); if (compKey == "Text") { this.actions.selectObjs([]); this.actions.textFocus(currComp.id, true); } this.controls.cropCtrl.close(); }, 100); }, async selectObjs(ids: string[], last = "") { this.store.selected = ids; this.store.selectId = ids.length > 1 ? Date.now() + "" : ""; this.store.lastSelected = last ? last : ( ids.length > 0 ? ids[ids.length-1] : "") }, // 添加组件到画布 async addCompToDesign(compKey: ICompKeys, index?: number) { if (!this.store.currStreamCardId) { //必须选中一个streamCard return; } if (compKey == "Container") { // index = this.store.streamCardIds.indexOf(this.store.currStreamCardId) + 1; const compId = await this.store.insertDesignContent(compKey, index); this.actions.pickComp(compId); return; } const compId = await this.store.insertCompContainer( compKey, this.store.currStreamCard ); const addedComp = this.store.compMap[compId]; this.actions.setCompPositionFloat(addedComp); this.actions.pickComp(compId); }, // 切换当前组件 // pickComp(compId: string) { // const { store, helper } = this; // // 组合模式下,切换组件 // // if (store.currCompId && store.groupModeStatus) { // // const enableGroupIds = helper // // .findParentComp(compId) // // ?.getChildIds() as string[]; // // const comps = helper.getCompTrees(compId); // // while (comps.length) { // // const comp = comps.pop() as DesignComp; // // const index = store.groupIds.indexOf(comp.id); // // if (index >= 0) { // // const groupIds = [...store.groupIds]; // // groupIds.splice(index, 1); // // store.setGroupIds(groupIds); // // } else if (enableGroupIds.includes(comp.id)) { // // store.groupIds.push(comp.id); // // return; // // } // // } // // return; // // } // // let nextCompId = compId; // // if (this.store.isEditPage) { // // const comps = this.helper.getCompTrees(compId); // // nextCompId = comps[1].id; // // } // if (this.store.currCompId == compId) { // return; // } // if (this.store.currComp.compKey == "Text") { // this.store.setTextEditingState(false); // } // this.store.setCurrComp(compId); // if (this.store.currCompId == this.store.currStreamCardId) { // this.controls.transferCtrl.destroy(); // } // }, // 切换到父组件 pickParentComp(compId: string) { const parentComp = this.helper.findParentComp(compId); parentComp && this.store.setCurrComp(parentComp.id); }, ctrlc() { // console.log("contrc ", this.store.selected); ctrlcselected = this.store.selected.slice(0); }, copyLastSelected() { if (this.store.currCompId && this.store.currCompId != "root") { ctrlcselected = [this.store.currCompId] } }, toogleGroup() { if (this.store.selected.length > 1) { this.actions.createGroupComps(); return; } if (this.store.selected.length == 1) { const c = this.helper.findComp(this.store.selected[0]) as DesignComp; if (c.compKey == "Group") { this.actions.cancelGroupComps(c); } } }, ctrlv() { console.log("ctrlv ", this.store.selected); if (ctrlcselected.length < 1) return; const news :string[] = []; const deepCopy = (c:DesignComp) => { const childs = c.children.default || []; if (childs.length > 0 ) { childs.forEach((id, index)=>{ const cp = this.helper.findComp(id) as DesignComp; const cp1 = cloneDeep(cp); cp1.id = nanoid(); this.store.compMap[cp1.id] = cp1; this.store.setCompPid(cp1.id, c.id); childs[index] = cp1.id; deepCopy(cp); }) } } ctrlcselected.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); }, 100); }, addComps(ids:string[]) { const childs = this.store.currStreamCard.children.default?.slice(0) || []; childs.push(...ids); this.store.currStreamCard.children.default = childs; }, // 删除组件 removeSelectComps() { const selected = this.store.selected.slice(0); this.actions.selectObjs([]); let n = selected.length; while (n--) { this.actions.removeComp(selected[n]); } }, // 删除组件 removeComp(compId: string) { const paths = this.helper.getCompTrees(compId); if (!paths[2]) return; compId = paths[2].id; if (this.helper.isCompCanDelete(compId)) { if (this.helper.isStreamCard(compId)) { this.actions.removeStreamCard(compId); return; } const cardid = this.store.currStreamCardId; if (compId === this.store.currCompId) { this.store.setCurrComp(this.store.currStreamCardId); } this.store.deleteComp(compId); this.helper.extendStreamCard(cardid); this.actions.selectObjs([]); } }, async removeStreamCard(compId: string) { await queenApi.showConfirm({ title: "删除", content: "确认删除当前内容?" }); // if (this.store.streamCardIds.length < 2) { // queenApi.messageError("") // return; // } let nextCard = this.store.currStreamCardId; if (compId == this.store.currStreamCardId) { const i = this.store.streamCardIds.indexOf(compId); nextCard = this.store.streamCardIds[i + 1]; if (!nextCard) { nextCard = this.store.streamCardIds[i - 1]; } } this.controls.selectCtrl.selecteObjs([]); this.store.deleteComp(compId); this.store.setCurrComp(nextCard); }, // 移动组件顺序 moveComp(selIndex: number, targetIndex: number) { if (selIndex === targetIndex) return; this.store.moveComp(selIndex, targetIndex); }, // 保存容器为组件 async saveAsComp(comp: DesignComp) { try { const CompSave = this.components.CompSave as any; let title = ""; let type = "comp"; try { const ret:any = await queenApi.dialog(, {width:"300px", title: "保存到我的"}); if (!ret) { return; } title = ret.title; type = ret.type; } catch (error) { return; } console.log( title, type); // 组件封面 const blob = await new ScreenshotCtrl().snap({ element: comp.$el, }); const thumbnail = URL.createObjectURL(blob); // const title = await queenApi.showInput({ // title: "保存到我的", // defaultValue: this.controls.compUICtrl.state.components.get( // comp.compKey // )?.name, // }); const data = { title, type, thumbnail, compMap: cloneDeep(this.store.designData.compMap), }; this.helper.clearUnusedComps(data.compMap, comp.id); data.compMap.root = data.compMap[comp.id]; data.compMap.root.id = "root"; //清除平移距离 const mtx = Matrix.createFromMatrixStr(data.compMap.root.layout.transformMatrix as string); mtx.tx = 0; mtx.ty = 0; data.compMap.root.layout.transformMatrix = mtx.getMatrixStr(); delete data.compMap[comp.id]; queenApi.showLoading("保存中"); await this.controls.uploader.uploadBlobs(data); await this.https.createComp(data); queenApi.messageSuccess("保存成功"); } catch (error: any) { throw Exception.error(error.toString()); } finally { queenApi.hideLoading(); } }, // 保存项目 async saveDesign() { try { // 清除无用组件 this.helper.clearUnusedComps(this.store.designData.compMap); // 封面截屏 if (!this.store.designData.thumbnail) { await this.actions.updateThumbnailByScreenshot(); } queenApi.showLoading("保存中"); await this.controls.uploader.uploadBlobs(this.store.designData); if (this.store.isWk) { await this.https[this.store.isEditPage ? "saveWkDesign" : "saveComp"]( this.store.designData ); } else { await this.https[this.store.isEditPage ? "saveDesign" : "saveComp"]( this.store.designData ); } queenApi.messageSuccess("保存成功"); } catch (error: any) { throw Exception.error(error.toString()); } finally { queenApi.hideLoading(); } }, // 截屏保存封面 async updateThumbnailByScreenshot(autoSave?: boolean) { try { const rootComp = this.helper.findRootComp(); if (!rootComp) return; queenApi.showLoading("截屏中"); const blob = await new ScreenshotCtrl().snap({ element: rootComp.$el, ratio: this.store.isEditComp ? 0 : 1, }); const thumbnail = URL.createObjectURL(blob); this.store.setDesignThumbnail(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(); } }, // 设置组件变换 setCompTransform(comp: DesignComp, transform: Layout["transform"]) { if (!comp) return; comp.layout.transform = transform; console.log(comp); }, // 设置组件变换 setCompTransformMatrix(comp: DesignComp, transformMatrix: string) { if (!comp) return; comp.layout.transformMatrix = transformMatrix; }, // 设置组件浮动 setCompPositionFloat(comp: DesignComp) { comp.layout.position = "absolute"; }, // 设置组件浮动 setCompPosition(comp: DesignComp) { comp.layout.position = comp.layout.position === "absolute" ? undefined : "absolute"; }, // 设置组件显示隐藏 setCompVisible(comp: DesignComp) { comp.layout.visible = comp.layout.visible === false ? true : false; }, // 清除组件变换 clearCompTransform(comp: DesignComp) { comp.layout.margin = ""; comp.layout.transform = undefined; }, // 设置组件锁定状态 setCompLock(comp: DesignComp) { console.log(comp); }, // 设置组件层级 setCompLayer(comp: DesignComp, offset: number) { comp.layout.zIndex = Math.min( Math.max((comp.layout.zIndex || 0) + offset, 0), 99 ); }, //横向对齐 setAlignX(flag: 0 | 1 | 2 | 3) { console.log("alignX") const selectCtrl = this.controls.selectCtrl; if (this.store.selected.length == 1) { const objc = selectCtrl.objContainer as ObjsContainer; const box = objc.getBound(); switch(flag) { case 0: selectCtrl.translate(-box.left , 0); break; case 1: selectCtrl.translate(-(box.center.x - 187.5) , 0); break; case 2: selectCtrl.translate(375 - box.right, 0); break; } return; } const anchorBox = this.helper.findComp(this.store.lastSelected); if (!anchorBox) return; const anchor = new CompObject(anchorBox); const anchorRect = anchor.getBox(); const objc = selectCtrl.objContainer as ObjsContainer; let min = 10000, max = -10000; let step = 0; if (flag == 3) {//Y轴均匀排布 objc.parent.children.forEach((c)=>{ const child = c as CompObject; const r = child.getBox(); const x = r.x + r.w / 2.0; if (x max ) max = x; }) const stepCount = objc.parent.children.length; step = (max - min) / (stepCount - 1); const stepIndexMap:any = {}; objc.parent.children.forEach((c)=>{ const child = c as CompObject; const r = child.getBox(); const x = r.x + r.w / 2.0; let minIndex = -1; let minV = 10000; for (let i=0; i{ const child = c as CompObject; if (child.comp.id == this.store.lastSelected) return; const r = child.getBox(); switch(flag) { case 0: child.translate(anchorRect.x -r.x, 0); break; case 1: child.translate(anchorRect.x + anchorRect.w / 2.0 - (r.x + r.w/2.0), 0); break; case 2: child.translate(anchorRect.x + anchorRect.w - (r.x + r.w), 0); break; } }) objc.updateSize(); selectCtrl.upgateGizmoStyle(); }, setAlignY(flag: 0 | 1 | 2 | 3) { const selectCtrl = this.controls.selectCtrl; if (this.store.selected.length == 1) { const objc = selectCtrl.objContainer as ObjsContainer; const box = objc.getBound(); const card = new CompObject(this.store.currStreamCard); const cardBox = card.getBox(); switch(flag) { case 0: selectCtrl.translate(0, -box.top); break; case 1: selectCtrl.translate(0 , -(box.center.y - cardBox.h / 2.0)); break; case 2: selectCtrl.translate(0, cardBox.h - box.bottom); break; } return; } const anchorBox = this.helper.findComp(this.store.lastSelected); if (!anchorBox) return; const anchor = new CompObject(anchorBox); const anchorRect = anchor.getBox(); const objc = selectCtrl.objContainer as ObjsContainer; let min = 10000; let max = -10000; let step = 0; if (flag == 3) {//Y轴均匀排布 objc.parent.children.forEach((c)=>{ const child = c as CompObject; const r = child.getBox(); const y = r.y + r.h / 2.0; if (y max ) max = y; }) const stepCount = objc.parent.children.length; step = (max - min) / (stepCount - 1); const stepIndexMap:any = {}; objc.parent.children.forEach((c)=>{ const child = c as CompObject; const r = child.getBox(); const y = r.y + r.h / 2.0; let minIndex = -1; let minV = 10000; for (let i=0; i{ const child = c as CompObject; if (child.comp.id == this.store.lastSelected) return; const r = child.getBox(); switch(flag) { case 0: child.translate(0, anchorRect.y -r.y); break; case 1: child.translate(0, anchorRect.y + anchorRect.h / 2.0 - (r.y + r.h /2.0)); break; case 2: child.translate(0, anchorRect.y + anchorRect.h - (r.y + r.h)); break; } }) objc.updateSize(); selectCtrl.upgateGizmoStyle(); }, // 宽度铺满 fullCompWidth(comp: DesignComp) { comp.layout.size || (comp.layout.size = []); comp.layout.size[0] = 750; }, // setCompAlign(comp: DesignComp, align: string) { comp.layout.alignSelf = align; if (comp.layout.transform?.x) { comp.layout.transform.x = 0; } }, // 开启组合模式 enableGroupMode() { this.store.setGroupIds( this.store.currCompId ? [this.store.currCompId] : [] ); this.store.setGroupMode(true); }, // 关闭组合模式 async disableGroupMode() { const groupId = await this.controls.transferCtrl.groupCtrl.combineGroup(); if (groupId) { this.store.setCurrComp(groupId); } this.store.setGroupIds([]); this.store.setGroupMode(false); }, // 取消打组 cancelGroupComps(groupComp: DesignComp) { const childs = groupComp.children.default || []; const objC = this.controls.selectCtrl.objContainer as ObjsContainer; const parentMtrx = objC.parent.worldTransform.clone(); childs.forEach(o=>{ const obj = this.helper.findComp(o) as DesignComp; const mxt = Matrix.createFromMatrixStr(obj.layout.transformMatrix as string); mxt.prepend(parentMtrx); obj.layout.transformMatrix = mxt.getMatrixStr(); }) const paths = this.helper.getCompTrees(groupComp.id) const card = paths[1]; const parentChilds = (card.children.default || []).filter(item=>item != groupComp.id); parentChilds.push(...childs); card.children.default = parentChilds; this.actions.selectObjs([childs[0]]); }, createGroupComps() { const selectCtrl = this.controls.selectCtrl; const Objc = this.controls.selectCtrl.objContainer as ObjsContainer; const id = this.controls.compUICtrl.createCompId("Group"); const comp = this.helper.findComp(id) as DesignComp; comp.layout.position = "absolute"; //先删除现有的节点 const sels = this.store.selected.slice(0); const chils = this.store.currStreamCard.children.default || []; const newChilds :any = []; chils.forEach(c=>{ if (sels.indexOf(c) == -1) newChilds.push(c); }) newChilds.push(id); this.store.currStreamCard.children.default = newChilds; //更新节点的新位置 Objc.parent.children.forEach(obj=>{ const cobj = obj as CompObject; const comp = cobj.comp; comp.layout.transformMatrix = cobj.localTransform.getMatrixStr(); }) //再添加新的节点 comp.layout.size = [this.helper.pxToDesignSize(Objc.width), this.helper.pxToDesignSize(Objc.height)]; comp.layout.transformMatrix = selectCtrl.transferStyle.matrix; comp.children.default = sels; this.actions.selectObjs([]) setTimeout(() => { this.actions.pickComp(comp.id); }, 0); }, handleSelectMoving(key: string) { if (this.store.selected.length < 1) return; let x = 0, y = 0; switch (key) { case "left": x = -1; break; case "right": x = 1; break; case "up": y = -1; break; case "down": y = 1; break; } this.controls.selectCtrl.translate(x * 0.5, y * 0.5); this.controls.selectCtrl.assistCtrl?.flashDrawCardDists(); }, // 点击模板 async clickTplToDesign(record) { const res = await queenApi.showConfirm({ title: "", content: "要替换正在编辑的内容?", }); if (!res) return; const frameData = await this.https.getDesignDetail(record._id, { isSys: true, }); const { compMap, content, desc, thumbnail, title } = frameData.result; const designData = { ...this.store.designData, compMap, content, desc, thumbnail, title, }; this.actions.selectObjs([]); this.store.setCurrComp("root"); this.store.setDesignData(designData); this.store.currStreamCardId = this.store.streamCardIds[0]; }, });