edit.tsx 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130
  1. import { cloneDeep, pick } from "lodash";
  2. import { nanoid } from "nanoid";
  3. import { Exception, queenApi } from "queenjs";
  4. import { EditorModule } from "..";
  5. import { ScreenshotCtrl } from "../../controllers/ScreenshotCtrl";
  6. import { ObjsContainer } from "../../controllers/SelectCtrl/ObjsContainer";
  7. import { CompObject } from "../../controllers/SelectCtrl/compObj";
  8. import { Matrix } from "../../controllers/SelectCtrl/matrix";
  9. import { DesignComp } from "../../objects/DesignTemp/DesignComp";
  10. import { ICompKeys, Layout } from "../../typings";
  11. import CompSave from "../../components/CompSave";
  12. import { getKeyThenIncreaseKey } from "ant-design-vue/lib/message";
  13. import { cloneObj, createObj, history } from "../../objects/DesignTemp/factory";
  14. const ctrlState = {
  15. selected: [] as string[],
  16. type: 0, // 1 ctrlc 2 ctrlx 3 ctrlq
  17. cardId: "", //当前的卡片Id
  18. screenId: "", //屏幕Id
  19. selWidth: 0,
  20. selX: 0,
  21. selY: 0,
  22. };
  23. export const editActions = EditorModule.action({
  24. async addImageToDesign(url) {
  25. queenApi.showLoading("图片加载中");
  26. const maxW = this.controls.screenCtrl.getCurrScreenWidth();
  27. try {
  28. const temImg: any = await this.helper.loadImage(url);
  29. const ratio = temImg.width / temImg.height;
  30. const W = temImg.width > maxW ? maxW : temImg.width;
  31. const H = W / ratio;
  32. await this.actions.clickCompToDesign("Image", (comp) => {
  33. comp.setSize(W, H);
  34. comp.value.url = url;
  35. });
  36. } catch (e) {
  37. queenApi.hideLoading();
  38. queenApi.messageError("图片加载失败");
  39. return;
  40. }
  41. queenApi.hideLoading();
  42. },
  43. async dragAddImageToDesign(e: MouseEvent, url) {
  44. const page = this.controls.pageCtrl;
  45. if (!page.currStreamCardId) {
  46. queenApi.messageError("请先选中一个卡片");
  47. return;
  48. }
  49. queenApi.showLoading("图片加载中");
  50. const maxW = this.controls.screenCtrl.getCurrScreenWidth();
  51. try {
  52. const temImg: any = await this.helper.loadImage(url);
  53. const ratio = temImg.width / temImg.height;
  54. const W = temImg.width > maxW ? maxW : temImg.width;
  55. const H = W / ratio;
  56. const currCard = page.currStreamCard;
  57. const currComp = createObj({ compKey: "Image" }, false);
  58. currComp.setSize(W, H);
  59. currComp.value.url = url;
  60. page.designData.compMap[currComp.id] = currComp;
  61. // page.setCompPid(currComp.id, page.currStreamCardId);
  62. const childIds = [...page.currStreamCard.children.default];
  63. childIds.push(currComp.id);
  64. currCard.children.setDefault(childIds);
  65. this.controls.editorCtrl.clickPickComp(currComp.id);
  66. this.actions.centerLastComp(e);
  67. } catch (e) {
  68. queenApi.hideLoading();
  69. queenApi.messageError("图片加载失败");
  70. return;
  71. }
  72. queenApi.hideLoading();
  73. history.submit();
  74. },
  75. async dragAddVideoToDesign(e: MouseEvent, url) {
  76. const page = this.controls.pageCtrl;
  77. if (!page.currStreamCardId) {
  78. queenApi.messageError("请先选中一个卡片");
  79. return;
  80. }
  81. queenApi.showLoading("视频加载中");
  82. // const maxW = this.controls.screenCtrl.getCurrScreenWidth();
  83. try {
  84. // const temImg :any = await this.helper.loadImage(url);
  85. // const ratio = temImg.width / temImg.height;
  86. // const W = temImg.width > maxW ? maxW : temImg.width;
  87. // const H = W / ratio;
  88. const currCard = page.currStreamCard;
  89. const currComp = createObj({ compKey: "Video" }, false);
  90. // currComp.setSize(W, H );
  91. currComp.value.url = url;
  92. page.designData.compMap[currComp.id] = currComp;
  93. // page.setCompPid(currComp.id, page.currStreamCardId);
  94. const childIds = [...page.currStreamCard.children.default];
  95. childIds.push(currComp.id);
  96. currCard.children.setDefault(childIds);
  97. this.controls.editorCtrl.clickPickComp(currComp.id);
  98. this.actions.centerLastComp(e);
  99. } catch (e) {
  100. queenApi.hideLoading();
  101. queenApi.messageError("图片加载失败");
  102. return;
  103. }
  104. queenApi.hideLoading();
  105. history.submit();
  106. },
  107. // 通过点击添加组件到画布
  108. async clickCompToDesign(
  109. compKey: ICompKeys,
  110. cb?: (comp: DesignComp) => void,
  111. history = true
  112. ) {
  113. const page = this.controls.pageCtrl;
  114. if (!page.currStreamCardId) {
  115. queenApi.messageError("请先选中一个卡片");
  116. return;
  117. }
  118. let yOffset = 0;
  119. if (
  120. page.state.currCompId != page.state.currStreamCardId &&
  121. page.state.currCompId != "root"
  122. ) {
  123. const bound = this.helper.getCardCompBound(page.state.currCompId);
  124. yOffset = bound.y + bound.h;
  125. }
  126. let currCard = page.currStreamCard;
  127. const currComp = createObj({ compKey }, false);
  128. // debugger
  129. //@ts-ignore
  130. const objs: any[] = currComp.children.objs || [];
  131. if (objs.length > 0) {
  132. objs.forEach((o) => {
  133. page.designData.compMap[o.id] = o;
  134. page.setCompPid(o.id, currComp.id);
  135. });
  136. }
  137. page.designData.compMap[currComp.id] = currComp;
  138. page.setCompPid(currComp.id, currCard.id);
  139. const childIds = [...currCard.children.default];
  140. childIds.push(currComp.id);
  141. currCard.children.setDefault(childIds);
  142. const compId = currComp.id;
  143. cb?.(currComp);
  144. const w = this.controls.screenCtrl.getCurrScreenWidth();
  145. //添加组件到当前选中的组件下面
  146. let xOffset = this.helper.designSizeToPx(
  147. w / 2.0 - (currComp.layout.size?.[0] || w) / 2
  148. );
  149. const obj = new CompObject(currComp);
  150. //没有选中组件添加到当前卡片最后
  151. const children = currCard.children.default || [];
  152. if (yOffset == 0 && children.length >= 2) {
  153. const prevCompIndex = children.indexOf(compId) - 1;
  154. const bound = this.helper.getCardCompBound(children[prevCompIndex]);
  155. yOffset = bound.y + bound.h;
  156. }
  157. obj.worldTransform.translate(xOffset, yOffset);
  158. currComp.layout.transformMatrix = obj.worldTransform.getMatrixStr();
  159. this.controls.editorCtrl.clickPickComp(compId);
  160. this.helper.extendStreamCard(currCard.id);
  161. if (compKey == "Text") {
  162. this.actions.textFocus(compId, true);
  163. }
  164. this.controls.cropCtrl.close();
  165. if (history) this.history.submit();
  166. },
  167. // 通过点击添加组件到画布
  168. async clickCompUserToDesign(id: string, isSys) {
  169. const page = this.controls.pageCtrl;
  170. if (!page.currStreamCardId) {
  171. queenApi.messageError("请先选中一个卡片");
  172. return;
  173. }
  174. const { result } = await this.https.getCompDetail(id, isSys);
  175. const currCard = page.currStreamCard;
  176. const comp = page.addUserCard(result);
  177. const compId = comp.id;
  178. const childIds = [...(currCard.children.default || [])];
  179. childIds.push(compId);
  180. currCard.children.setDefault(childIds);
  181. page.setCompPid(compId, currCard.id);
  182. this.actions.initAddedCompPos(this.store.currCompId, compId, currCard.id);
  183. this.controls.editorCtrl.clickPickComp(compId);
  184. history.submit();
  185. },
  186. initAddedCompPos(currId: string, addedId: string, cardId: string) {
  187. let yOffset = 0;
  188. if (currId != this.controls.pageCtrl.currStreamCardId && currId != "root") {
  189. const paths = this.helper.getCompTrees(currId);
  190. const bound = this.helper.getCardCompBound(paths[2].id);
  191. yOffset = bound.y + bound.h;
  192. }
  193. const currComp = this.helper.findComp(addedId) as DesignComp;
  194. const w = this.controls.screenCtrl.getCurrScreenWidth();
  195. //添加组件到当前选中的组件下面
  196. let xOffset = this.helper.designSizeToPx(
  197. w / 2.0 - (currComp.layout.size?.[0] || w) / 2
  198. );
  199. const obj = new CompObject(currComp);
  200. const currCard = this.helper.findComp(cardId) as DesignComp;
  201. //没有选中组件添加到当前卡片最后
  202. const children = currCard.children.default || [];
  203. if (yOffset == 0 && children.length >= 2) {
  204. const prevCompIndex = children.indexOf(addedId) - 1;
  205. const bound = this.helper.getCardCompBound(children[prevCompIndex]);
  206. yOffset = bound.y + bound.h;
  207. }
  208. obj.worldTransform.translate(xOffset, yOffset);
  209. currComp.layout.transformMatrix = obj.worldTransform.getMatrixStr();
  210. this.helper.extendStreamCard(currCard.id);
  211. this.controls.cropCtrl.close();
  212. },
  213. // 通过拖拽添加组件到画布
  214. async dragCompToDesign(event: MouseEvent, compKey: string, data: any) {
  215. const page = this.controls.pageCtrl;
  216. if (compKey == "CompCard") {
  217. const { result } = await this.https.getCompDetail(data.id, data.isSys);
  218. const comp = page.addUserCard(result);
  219. const currCard = page.currStreamCard;
  220. const compId = comp.id;
  221. const childIds = [...(currCard.children.default || [])];
  222. childIds.push(compId);
  223. currCard.children.setDefault(childIds);
  224. page.setCompPid(compId, currCard.id);
  225. this.controls.editorCtrl.clickPickComp(compId);
  226. } else {
  227. await this.actions.addCompToDesign(compKey as any);
  228. }
  229. setTimeout(() => {
  230. this.actions.centerLastComp(event);
  231. const currComp = this.controls.pageCtrl.currComp;
  232. if (compKey == "Text") {
  233. this.actions.textFocus(currComp.id, true);
  234. }
  235. history.submit();
  236. }, 100);
  237. },
  238. centerLastComp(event: MouseEvent) {
  239. const currCardDom = this.controls.pageCtrl.currStreamCard.$el;
  240. const cardPoints = this.helper.getPointOffsetWith(event, currCardDom);
  241. const page = this.controls.pageCtrl;
  242. let selCtrl = this.controls.selectCtrl;
  243. const w = this.controls.screenCtrl.getCurrScreenWidth();
  244. selCtrl.translate(
  245. this.helper.designSizeToPx(
  246. w / 2.0 - (page.currComp.layout.size?.[0] || w) / 2
  247. ),
  248. cardPoints.y
  249. );
  250. this.helper.extendStreamCard(page.state.currStreamCardId);
  251. this.controls.cropCtrl.close();
  252. },
  253. // 添加组件到画布
  254. async addCompToDesign(compKey: ICompKeys, index?: number) {
  255. const page = this.controls.pageCtrl;
  256. if (!page.state.currStreamCardId) {
  257. //必须选中一个streamCard
  258. return;
  259. }
  260. if (compKey == "Container") {
  261. const compId = page.insertDesignCard(index);
  262. this.controls.editorCtrl.clickPickComp(compId);
  263. return;
  264. }
  265. const compId = page.insertCompContainer(
  266. compKey,
  267. this.controls.pageCtrl.currStreamCard
  268. );
  269. this.controls.editorCtrl.clickPickComp(compId);
  270. },
  271. pickParentComp(compId: string) {
  272. const page = this.controls.pageCtrl;
  273. const parentComp = this.helper.findParentComp(compId);
  274. parentComp && page.setCurrComp(parentComp.id);
  275. },
  276. ctrlc() {
  277. const page = this.controls.pageCtrl;
  278. ctrlState.selected = [];
  279. const children = page.currStreamCard.children.default || [];
  280. const gizmo = this.controls.selectCtrl.gizmo;
  281. const selected = gizmo.selected.map((item) => item.comp.id);
  282. children.forEach((c) => {
  283. if (selected.indexOf(c) > -1) {
  284. ctrlState.selected.push(c);
  285. }
  286. });
  287. ctrlState.screenId = this.controls.screenCtrl.currScreenId;
  288. ctrlState.cardId = page.currStreamCardId;
  289. ctrlState.type = 1;
  290. const objc = this.controls.selectCtrl.objContainer;
  291. ctrlState.selWidth = this.helper.pxToDesignSize(objc.width);
  292. objc.setPivot(0);
  293. const currX = objc.parent.x,
  294. currY = objc.parent.y;
  295. ctrlState.selX = currX;
  296. ctrlState.selY = currY;
  297. objc.setPivot(4);
  298. },
  299. copyLastSelected() {
  300. if (this.store.currCompId && this.store.currCompId != "root") {
  301. ctrlState.selected = [this.store.currCompId];
  302. ctrlState.cardId = this.controls.pageCtrl.currStreamCardId;
  303. ctrlState.type = 1;
  304. }
  305. },
  306. setSameSize(isWidth: boolean) {
  307. const selectCtrl = this.controls.selectCtrl;
  308. const gizmo = selectCtrl.objContainer;
  309. const layout = this.controls.pageCtrl.currComp.layout;
  310. const w = this.controls.screenCtrl.getCurrScreenWidth();
  311. if (this.selected.length == 1) {
  312. const size: any = layout.size.slice(0);
  313. let isSame = false;
  314. if (isWidth) {
  315. isSame = w == size[0];
  316. size[0] = w;
  317. } else {
  318. isSame =
  319. size[1] == this.controls.pageCtrl.currStreamCard.layout.size[1];
  320. size[1] = this.controls.pageCtrl.currStreamCard.layout.size[1];
  321. }
  322. if (!isSame) {
  323. layout.setSize(size);
  324. this.history.submit();
  325. }
  326. return;
  327. }
  328. const anchorBox = this.helper.findComp(gizmo.state.lastId);
  329. if (!anchorBox) return;
  330. gizmo.parent.children.forEach((c) => {
  331. const child = c as CompObject;
  332. const r = child.getBox();
  333. if (isWidth) child.comp.layout.size[0] = anchorBox.layout.size[0];
  334. else child.comp.layout.size[1] = anchorBox.layout.size[1];
  335. });
  336. gizmo.updateSize();
  337. selectCtrl.upgateGizmoStyle();
  338. history.submit();
  339. },
  340. toogleGroup() {
  341. const gizmo = this.controls.selectCtrl.gizmo;
  342. if (gizmo.selected.length > 1) {
  343. this.actions.createGroupComps();
  344. return;
  345. }
  346. if (gizmo.selected.length == 1) {
  347. const c = gizmo.selected[0].comp;
  348. if (c.compKey == "Group") {
  349. this.actions.cancelGroupComps(c);
  350. }
  351. }
  352. },
  353. ctrlq() {
  354. const page = this.controls.pageCtrl;
  355. if (!page.currCompId) return;
  356. ctrlState.selected = [page.currCompId];
  357. ctrlState.screenId = this.controls.screenCtrl.currScreenId;
  358. ctrlState.cardId = page.currStreamCardId;
  359. ctrlState.type = 3;
  360. },
  361. ctrlx() {
  362. //console.log("ctrlv ", this.store.selected);
  363. //console.log("ctrlv ", this.store.selected);
  364. const page = this.controls.pageCtrl;
  365. const gizmo = this.controls.selectCtrl.gizmo;
  366. const selected = gizmo.selected.map((item) => item.comp.id);
  367. //保持图层顺序
  368. ctrlState.selected = [];
  369. const children = page.currStreamCard.children.default || [];
  370. children.forEach((c) => {
  371. if (selected.indexOf(c) > -1) {
  372. ctrlState.selected.push(c);
  373. }
  374. });
  375. ctrlState.cardId = page.state.currStreamCardId;
  376. ctrlState.type = 2;
  377. ctrlState.screenId = this.controls.screenCtrl.currScreenId;
  378. const objc = this.controls.selectCtrl.objContainer;
  379. ctrlState.selWidth = this.helper.pxToDesignSize(objc.width);
  380. objc.setPivot(0);
  381. const currX = objc.parent.x,
  382. currY = objc.parent.y;
  383. ctrlState.selX = currX;
  384. ctrlState.selY = currY;
  385. objc.setPivot(4);
  386. },
  387. ctrlv() {
  388. if (ctrlState.selected.length < 1) return;
  389. const ctrl = this.controls.pageCtrl;
  390. const news: string[] = [];
  391. const deepCopy = (c: DesignComp) => {
  392. const childs = c.children.default || [];
  393. if (childs.length > 0) {
  394. childs.forEach((id, index) => {
  395. const cp = this.helper.findComp(id) as DesignComp;
  396. const cp1 = cloneObj(cp);
  397. ctrl.compMap[cp1.id] = cp1;
  398. ctrl.setCompPid(cp1.id, c.id);
  399. childs[index] = cp1.id;
  400. deepCopy(cp1);
  401. });
  402. }
  403. };
  404. ctrlState.selected.forEach((c) => {
  405. const cp = this.helper.findComp(c) as DesignComp;
  406. const cp1 = cloneObj(cp);
  407. news.push(cp1.id);
  408. ctrl.compMap[cp1.id] = cp1;
  409. ctrl.setCompPid(cp1.id, ctrl.currStreamCardId);
  410. deepCopy(cp1);
  411. });
  412. this.actions.addComps(news);
  413. this.controls.selectCtrl.gizmo.selectObjs(news);
  414. //剪辑
  415. if (ctrlState.type == 2) {
  416. //剪辑删除原来的组件
  417. const card = this.helper.findComp(ctrlState.cardId) as DesignComp;
  418. const childs = card.children.default?.slice(0) || [];
  419. ctrlState.selected.forEach((s) => {
  420. let i = childs.indexOf(s);
  421. if (i != -1) {
  422. childs.splice(i, 1);
  423. }
  424. });
  425. card.children.default = childs;
  426. this.helper.extendStreamCard(ctrlState.cardId);
  427. ctrlState.selected = [];
  428. }
  429. //获取当前选中的内容
  430. if (ctrlState.cardId != ctrl.currStreamCardId) {
  431. //跨卡片拷贝
  432. let pox = this.helper.getCardNextPosY(
  433. ctrl.currStreamCardId,
  434. ctrlState.selWidth
  435. );
  436. this.controls.selectCtrl.translate(0, pox.y - ctrlState.selY);
  437. return;
  438. }
  439. if (ctrlState.screenId == this.controls.screenCtrl.currScreenId) {
  440. this.controls.selectCtrl.translate(20, 20);
  441. }
  442. history.submit();
  443. },
  444. addComps(ids: string[]) {
  445. const childs =
  446. this.controls.pageCtrl.currStreamCard.children.default.slice(0);
  447. childs.push(...ids);
  448. this.controls.pageCtrl.currStreamCard.children.setDefault(childs);
  449. },
  450. ctrlAndA() {
  451. const childrens = (
  452. this.controls.pageCtrl.currStreamCard.children.default || []
  453. ).slice(0);
  454. this.controls.selectCtrl.gizmo.selectObjs(childrens);
  455. },
  456. // 删除组件
  457. removeSelectComps() {
  458. const selected = this.controls.selectCtrl.gizmo.selected.slice(0);
  459. this.controls.editorCtrl.clickPickComp("");
  460. let n = selected.length;
  461. while (n--) {
  462. this.actions.removeComp(selected[n].comp.id);
  463. }
  464. history.submit();
  465. },
  466. // 删除组件
  467. removeComp(compId: string, submitHistory = false) {
  468. const ctrl = this.controls.pageCtrl;
  469. const paths = this.helper.getCompTrees(compId);
  470. if (!paths[2]) {
  471. if (this.helper.isStreamCard(compId)) {
  472. this.actions.removeStreamCard(compId);
  473. return;
  474. }
  475. return;
  476. }
  477. compId = paths[2].id;
  478. if (this.helper.isCompCanDelete(compId)) {
  479. if (this.helper.isStreamCard(compId)) {
  480. this.actions.removeStreamCard(compId);
  481. return;
  482. }
  483. const cardid = ctrl.currStreamCardId;
  484. if (compId === ctrl.currCompId) {
  485. ctrl.setCurrComp(ctrl.currStreamCardId);
  486. }
  487. ctrl.deleteComp(compId);
  488. this.helper.extendStreamCard(cardid);
  489. this.controls.editorCtrl.clickPickComp("");
  490. }
  491. if (submitHistory) {
  492. history.submit();
  493. }
  494. },
  495. async removeStreamCard(compId: string) {
  496. const ctrl = this.controls.pageCtrl;
  497. await queenApi.showConfirm({ title: "删除", content: "确认删除当前页面?" });
  498. let nextCard = ctrl.currStreamCardId;
  499. if (compId == ctrl.currStreamCardId) {
  500. const i = ctrl.streamCardIds.indexOf(compId);
  501. nextCard = ctrl.streamCardIds[i + 1];
  502. if (!nextCard) {
  503. nextCard = ctrl.streamCardIds[i - 1];
  504. }
  505. }
  506. this.controls.selectCtrl.gizmo.selectObjs([]);
  507. this.controls.propsCtrl.showProp("root");
  508. ctrl.setCurrComp(nextCard);
  509. ctrl.deleteComp(compId);
  510. },
  511. // 移动组件顺序
  512. moveComp(selIndex: number, targetIndex: number) {
  513. this.controls.editorCtrl.clickPickComp("root");
  514. if (selIndex === targetIndex) return;
  515. this.controls.pageCtrl.moveComp(selIndex, targetIndex);
  516. },
  517. // 保存容器为组件
  518. async saveAsComp(comp: DesignComp) {
  519. const ctrl = this.controls.pageCtrl;
  520. try {
  521. const CompSave = this.components.CompSave as any;
  522. let title = "";
  523. let type = "comp";
  524. try {
  525. const ret: any = await queenApi.dialog(<CompSave />, {
  526. width: "300px",
  527. title: "保存到我的",
  528. });
  529. if (!ret) {
  530. return;
  531. }
  532. title = ret.title;
  533. type = ret.type;
  534. } catch (error) {
  535. return;
  536. }
  537. console.log(title, type);
  538. // 组件封面
  539. const blob = await new ScreenshotCtrl().snap({
  540. element: comp.$el,
  541. });
  542. const thumbnail = URL.createObjectURL(blob);
  543. // const title = await queenApi.showInput({
  544. // title: "保存到我的",
  545. // defaultValue: this.controls.compUICtrl.state.components.get(
  546. // comp.compKey
  547. // )?.name,
  548. // });
  549. const ddata = ctrl.toJson();
  550. const data = {
  551. title,
  552. type,
  553. thumbnail,
  554. compMap: ddata.compMap,
  555. };
  556. this.helper.clearUnusedComps(data.compMap, comp.id);
  557. data.compMap.root = data.compMap[comp.id];
  558. data.compMap.root.id = "root";
  559. //清除平移距离
  560. const mtx = Matrix.createFromMatrixStr(
  561. data.compMap.root.layout.transformMatrix as string
  562. );
  563. mtx.tx = 0;
  564. mtx.ty = 0;
  565. data.compMap.root.layout.transformMatrix = mtx.getMatrixStr();
  566. delete data.compMap[comp.id];
  567. queenApi.showLoading("保存中");
  568. this.controls.uploader.ignoreDashField = true;
  569. await this.controls.uploader.uploadBlobs(data);
  570. await this.https.createComp(data);
  571. queenApi.messageSuccess("保存成功");
  572. } catch (error: any) {
  573. throw Exception.error(error.toString());
  574. } finally {
  575. queenApi.hideLoading();
  576. }
  577. },
  578. // 保存项目
  579. async saveDesign() {
  580. const ctrl = this.controls.pageCtrl;
  581. try {
  582. // 清除无用组件
  583. this.helper.clearProjectUnusedComps(ctrl.designData.compMap);
  584. const c = this.controls.screenCtrl;
  585. c.saveScreenPage();
  586. const root = this.helper.findRootComp() as DesignComp;
  587. root.value.useFor = c.state.screen.useFor;
  588. root.value.pageMode = c.state.screen.pageMode;
  589. root.value.pageSizeType = c.state.screen.pageSizeType;
  590. // 封面截屏
  591. if (!ctrl.designData.thumbnail) {
  592. await this.actions.updateThumbnailByScreenshot();
  593. }
  594. queenApi.showLoading("保存中");
  595. await this.controls.uploader.uploadBlobs(ctrl.designData);
  596. if (this.store.isWk) {
  597. await this.https[this.store.isEditPage ? "saveWkDesign" : "saveComp"](
  598. ctrl.toJson()
  599. );
  600. } else {
  601. await this.https[this.store.isEditPage ? "saveDesign" : "saveComp"](
  602. ctrl.toJson()
  603. );
  604. }
  605. queenApi.messageSuccess("保存成功");
  606. } catch (error: any) {
  607. throw Exception.error(error.toString());
  608. } finally {
  609. queenApi.hideLoading();
  610. }
  611. },
  612. // 截屏保存封面
  613. async updateThumbnailByScreenshot(autoSave?: boolean) {
  614. const ctrl = this.controls.pageCtrl;
  615. try {
  616. const rootComp = ctrl.rootPage;
  617. if (!rootComp) return;
  618. queenApi.showLoading("截屏中");
  619. const blob = await new ScreenshotCtrl().snap({
  620. element: rootComp.$el,
  621. ratio: this.store.isEditComp ? 0 : 1,
  622. });
  623. const thumbnail = URL.createObjectURL(blob);
  624. ctrl.setDesignThumbnail(thumbnail);
  625. if (autoSave) {
  626. await this.controls.uploader.uploadBlobs(ctrl.designData);
  627. await this.https[this.store.isEditPage ? "saveDesign" : "saveComp"](
  628. pick(ctrl.designData, ["_id", "thumbnail"])
  629. );
  630. queenApi.messageSuccess("保存成功");
  631. }
  632. } catch (error: any) {
  633. throw Exception.error(error.toString());
  634. } finally {
  635. queenApi.hideLoading();
  636. }
  637. },
  638. // 设置组件变换
  639. setCompTransformMatrix(comp: DesignComp, transformMatrix: string) {
  640. if (!comp) return;
  641. comp.layout.transformMatrix = transformMatrix;
  642. },
  643. // 设置组件显示隐藏
  644. setCompVisible(comp: DesignComp) {
  645. comp.layout.visible = comp.layout.visible === false ? true : false;
  646. },
  647. // 组件重命名
  648. async resetCompName(comp: DesignComp) {
  649. const res = await queenApi.showInput({
  650. title: "重命名",
  651. defaultValue: comp.layout.cusName,
  652. });
  653. if (!res) return;
  654. comp.layout.cusName = res;
  655. },
  656. // 清除组件变换
  657. // clearCompTransform(comp: DesignComp) {
  658. // comp.layout.margin = "";
  659. // comp.layout.transform = undefined;
  660. // },
  661. // 设置组件锁定状态
  662. setCompLock(comp: DesignComp) {
  663. comp.layout.setLocked(!comp.layout.locked);
  664. },
  665. // 设置组件层级
  666. setCompLayer(comp: DesignComp, offset: number) {
  667. const currCard = this.controls.pageCtrl.currStreamCard;
  668. const cards = currCard.children.default.slice(0);
  669. const i = cards.indexOf(comp.id);
  670. if (i == -1) return;
  671. if (offset < 0) {
  672. //向下移动
  673. if (i == 0) return;
  674. const temp = cards[i - 1];
  675. cards[i - 1] = comp.id;
  676. cards[i] = temp;
  677. currCard.children.setDefault(cards);
  678. history.submit();
  679. return;
  680. }
  681. if (i == cards.length - 1) return;
  682. const temp = cards[i + 1];
  683. cards[i + 1] = comp.id;
  684. cards[i] = temp;
  685. currCard.children.setDefault(cards);
  686. history.submit();
  687. },
  688. //横向对齐
  689. setAlignX(flag: 0 | 1 | 2 | 3, isGroup = false) {
  690. console.log("alignX");
  691. const selectCtrl = this.controls.selectCtrl;
  692. const w = this.helper.designSizeToPx(
  693. this.controls.screenCtrl.getCurrScreenWidth()
  694. );
  695. const gizmo = selectCtrl.gizmo;
  696. if (gizmo.selected.length == 1 || isGroup) {
  697. const box = gizmo.getBound();
  698. switch (flag) {
  699. case 0:
  700. selectCtrl.translate(-box.left, 0);
  701. break;
  702. case 1:
  703. selectCtrl.translate(-(box.center.x - w / 2.0), 0);
  704. break;
  705. case 2:
  706. selectCtrl.translate(w - box.right, 0);
  707. break;
  708. }
  709. history.submit();
  710. return;
  711. }
  712. //多选元素对齐模式
  713. const anchorBox = this.helper.findComp(gizmo.state.lastId);
  714. if (!anchorBox) return;
  715. const anchor = new CompObject(anchorBox);
  716. const anchorRect = anchor.getBox();
  717. let min = 10000,
  718. max = -10000;
  719. let step = 0;
  720. if (flag == 3) {
  721. //Y轴均匀排布
  722. gizmo.parent.children.forEach((c) => {
  723. const child = c as CompObject;
  724. const r = child.getBox();
  725. const x = r.x + r.w / 2.0;
  726. if (x < min) min = x;
  727. if (x > max) max = x;
  728. });
  729. const stepCount = gizmo.parent.children.length;
  730. step = (max - min) / (stepCount - 1);
  731. const stepIndexMap: any = {};
  732. gizmo.parent.children.forEach((c) => {
  733. const child = c as CompObject;
  734. const r = child.getBox();
  735. const x = r.x + r.w / 2.0;
  736. let minIndex = -1;
  737. let minV = 10000;
  738. for (let i = 0; i < stepCount; i++) {
  739. const ty = i * step + min;
  740. if (Math.abs(x - ty) < minV && !stepIndexMap[i]) {
  741. minV = Math.abs(x - ty);
  742. minIndex = i;
  743. }
  744. }
  745. stepIndexMap[minIndex] = true;
  746. child.translate(minIndex * step + min - x, 0);
  747. });
  748. gizmo.parent.updateTransform();
  749. history.submit();
  750. return;
  751. }
  752. gizmo.parent.children.forEach((c) => {
  753. const child = c as CompObject;
  754. if (child.comp.id == gizmo.state.lastId) return;
  755. const r = child.getBox();
  756. switch (flag) {
  757. case 0:
  758. child.translate(anchorRect.x - r.x, 0);
  759. break;
  760. case 1:
  761. child.translate(
  762. anchorRect.x + anchorRect.w / 2.0 - (r.x + r.w / 2.0),
  763. 0
  764. );
  765. break;
  766. case 2:
  767. child.translate(anchorRect.x + anchorRect.w - (r.x + r.w), 0);
  768. break;
  769. }
  770. });
  771. gizmo.parent.updateTransform();
  772. history.submit();
  773. },
  774. setAlignY(flag: 0 | 1 | 2 | 3, isGroup = false) {
  775. const selectCtrl = this.controls.selectCtrl;
  776. const gizmo = selectCtrl.gizmo;
  777. if (gizmo.selected.length == 1 || isGroup) {
  778. const objc = selectCtrl.objContainer;
  779. const box = objc.getBound();
  780. const card = new CompObject(this.controls.pageCtrl.currStreamCard);
  781. const cardBox = card.getBox();
  782. switch (flag) {
  783. case 0:
  784. selectCtrl.translate(0, -box.top);
  785. break;
  786. case 1:
  787. selectCtrl.translate(0, -(box.center.y - cardBox.h / 2.0));
  788. break;
  789. case 2:
  790. selectCtrl.translate(0, cardBox.h - box.bottom);
  791. break;
  792. }
  793. history.submit();
  794. return;
  795. }
  796. const anchorBox = this.helper.findComp(gizmo.state.lastId);
  797. if (!anchorBox) return;
  798. const anchor = new CompObject(anchorBox);
  799. const anchorRect = anchor.getBox();
  800. const objc = selectCtrl.objContainer;
  801. let min = 10000;
  802. let max = -10000;
  803. let step = 0;
  804. if (flag == 3) {
  805. //Y轴均匀排布
  806. objc.parent.children.forEach((c) => {
  807. const child = c as CompObject;
  808. const r = child.getBox();
  809. const y = r.y + r.h / 2.0;
  810. if (y < min) min = y;
  811. if (y > max) max = y;
  812. });
  813. const stepCount = objc.parent.children.length;
  814. step = (max - min) / (stepCount - 1);
  815. const stepIndexMap: any = {};
  816. objc.parent.children.forEach((c) => {
  817. const child = c as CompObject;
  818. const r = child.getBox();
  819. const y = r.y + r.h / 2.0;
  820. let minIndex = -1;
  821. let minV = 10000;
  822. for (let i = 0; i < stepCount; i++) {
  823. const ty = i * step + min;
  824. if (Math.abs(y - ty) < minV && !stepIndexMap[i]) {
  825. minV = Math.abs(y - ty);
  826. minIndex = i;
  827. }
  828. }
  829. stepIndexMap[minIndex] = true;
  830. child.translate(0, minIndex * step + min - y);
  831. });
  832. gizmo.parent.updateTransform();
  833. history.submit();
  834. return;
  835. }
  836. objc.parent.children.forEach((c) => {
  837. const child = c as CompObject;
  838. if (child.comp.id == gizmo.state.lastId) return;
  839. const r = child.getBox();
  840. switch (flag) {
  841. case 0:
  842. child.translate(0, anchorRect.y - r.y);
  843. break;
  844. case 1:
  845. child.translate(
  846. 0,
  847. anchorRect.y + anchorRect.h / 2.0 - (r.y + r.h / 2.0)
  848. );
  849. break;
  850. case 2:
  851. child.translate(0, anchorRect.y + anchorRect.h - (r.y + r.h));
  852. break;
  853. }
  854. });
  855. history.submit();
  856. },
  857. // 宽度铺满
  858. fullCompWidth(comp: DesignComp) {
  859. comp.layout.size[0] = this.controls.screenCtrl.getCurrScreenWidth();
  860. },
  861. // 取消打组
  862. cancelGroupComps(groupComp: DesignComp) {
  863. const childs = groupComp.children.default;
  864. const gizmo = this.controls.selectCtrl.gizmo;
  865. const parentMtrx = gizmo.parent.worldTransform.clone();
  866. gizmo.selectObjs([]); //取消选择
  867. childs.forEach((o) => {
  868. const obj = this.helper.findComp(o) as DesignComp;
  869. const mxt = Matrix.createFromMatrixStr(
  870. obj.layout.transformMatrix as string
  871. );
  872. mxt.prepend(parentMtrx);
  873. obj.layout.setTransformMatrix(mxt.getMatrixStr());
  874. });
  875. const paths = this.helper.getCompTrees(groupComp.id);
  876. const card = paths[1];
  877. const parentChilds = (card.children.default || []).filter(
  878. (item) => item != groupComp.id
  879. );
  880. parentChilds.push(...childs);
  881. const page = this.controls.pageCtrl;
  882. childs.forEach((item) => {
  883. page.setCompPid(item, card.id);
  884. });
  885. card.children.setDefault(parentChilds);
  886. this.controls.editorCtrl.clickPickComp(childs[0]);
  887. history.submit();
  888. },
  889. createGroupComps() {
  890. const gizmo = this.controls.selectCtrl.gizmo;
  891. const page = this.controls.pageCtrl;
  892. const sels = gizmo.selected.map((item) => item.comp.id);
  893. const id = this.controls.compUICtrl.createCompId("Group");
  894. page.setCompPid(id, page.currStreamCardId);
  895. const comp = this.helper.findComp(id) as DesignComp;
  896. const chils = this.controls.pageCtrl.currStreamCard.children.default || [];
  897. const newChilds: any = [];
  898. const groupChilds: string[] = [];
  899. chils.forEach((c) => {
  900. if (sels.indexOf(c) == -1) newChilds.push(c);
  901. else {
  902. groupChilds.push(c);
  903. }
  904. });
  905. newChilds.push(id);
  906. //更新节点的新位置
  907. const newMatrixMap: any = {};
  908. gizmo.parent.children.forEach((obj) => {
  909. const cobj = obj as CompObject;
  910. const comp = cobj.comp;
  911. newMatrixMap[comp.id] = cobj.localTransform.getMatrixStr();
  912. });
  913. page.currStreamCard.children.setDefault(newChilds);
  914. //再添加新的节点
  915. comp.layout.setSize([
  916. this.helper.pxToDesignSize(gizmo.width),
  917. this.helper.pxToDesignSize(gizmo.height),
  918. ]);
  919. comp.layout.setTransformMatrix(gizmo.parent.worldTransform.getMatrixStr());
  920. this.controls.selectCtrl.gizmo.selectObjs([]);
  921. groupChilds.forEach((c) => {
  922. const comp = this.helper.findComp(c) as DesignComp;
  923. comp.layout.setTransformMatrix(newMatrixMap[c]);
  924. page.setCompPid(c, id);
  925. });
  926. comp.children.setDefault(groupChilds);
  927. this.controls.propsCtrl.showProp(comp.id);
  928. this.controls.selectCtrl.gizmo.selectObjs([comp.id]);
  929. history.submit();
  930. },
  931. handleSelectMoving(key: string) {
  932. if (this.controls.selectCtrl.gizmo.selected.length < 1) return;
  933. let x = 0,
  934. y = 0;
  935. switch (key) {
  936. case "left":
  937. x = -1;
  938. break;
  939. case "right":
  940. x = 1;
  941. break;
  942. case "up":
  943. y = -1;
  944. break;
  945. case "down":
  946. y = 1;
  947. break;
  948. }
  949. this.controls.selectCtrl.translate(x * 0.5, y * 0.5);
  950. this.controls.selectCtrl.assistCtrl?.flashDrawCardDists();
  951. history.submit();
  952. },
  953. // 点击模板
  954. async clickTplToDesign(record) {
  955. const ctrl = this.controls.pageCtrl;
  956. const res = await queenApi.showConfirm({
  957. title: "",
  958. content: "要替换正在编辑的内容?",
  959. });
  960. if (!res) return;
  961. const frameData = await this.https.getDesignDetail(record._id, {
  962. isSys: true,
  963. });
  964. const { compMap, content, desc, thumbnail, title, _id } = frameData.result;
  965. const designData = {
  966. _id: ctrl.designData._id,
  967. version: ctrl.designData.version,
  968. compMap,
  969. content,
  970. desc,
  971. thumbnail,
  972. title,
  973. };
  974. this.controls.editorCtrl.clickPickComp("root");
  975. ctrl.setDesignData(designData);
  976. ctrl.state.setDesignId(_id as string);
  977. },
  978. });