common.ts 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103
  1. import { reactive, ref } from 'vue';
  2. import { MessagePlugin } from 'tdesign-vue-next';
  3. import localforage from 'localforage';
  4. import dayjs from 'dayjs';
  5. import axios from 'axios';
  6. import router from '@/router/index';
  7. import { useUser } from '@/services/user';
  8. import { showNotification, Meta2dBackData, checkData } from '@/services/utils';
  9. import { noLoginTip, localStorageName } from '@/services/utils';
  10. import { upload, dataURLtoBlob } from '@/services/file';
  11. import { delImage, addCollection, updateCollection, getLe5leV } from '@/services/api';
  12. import { baseVer } from '@/services/upgrade';
  13. import { debounce } from './debouce';
  14. import { deepClone, isDomShapes } from '@meta2d/core';
  15. import { useSelection } from '@/services/selections';
  16. import { rootDomain } from './defaults';
  17. import { updateObject } from './object';
  18. const { select } = useSelection();
  19. const assets = reactive({
  20. home: `https://${rootDomain.slice(1)}`,
  21. account: `https://account${rootDomain}',`,
  22. '3d': `https://3d${rootDomain}`,
  23. '2d': `https://2d${rootDomain}`,
  24. helps_v: [
  25. {
  26. name: '产品介绍',
  27. url: `https://doc${rootDomain}/document/118756411`,
  28. },
  29. {
  30. name: '快速上手',
  31. url: `https://doc${rootDomain}/document/119363000`,
  32. },
  33. {
  34. name: '使用手册',
  35. url: `https://doc${rootDomain}/document/118764244`,
  36. },
  37. {
  38. name: '快捷键',
  39. url: `https://doc${rootDomain}/document/119620214`,
  40. divider: true,
  41. },
  42. {
  43. name: '企业服务与支持',
  44. url: `https://doc${rootDomain}/document/119296274`,
  45. divider: true,
  46. },
  47. {
  48. name: '关于我们',
  49. url: `https://${rootDomain.slice(1)}/about.html`,
  50. },
  51. ],
  52. });
  53. export const useAssets = () => {
  54. const getAssets = async () => {
  55. // 官网或安装包版本
  56. // if (import.meta.env.VITE_TRIAL != 1) {
  57. // return;
  58. // }
  59. // 企业版
  60. const ret = await axios.get('/api/assets');
  61. if (ret) {
  62. Object.assign(assets, ret);
  63. }
  64. };
  65. return {
  66. assets,
  67. getAssets,
  68. };
  69. };
  70. const meta2dData = reactive({
  71. name:'新建项目'
  72. });
  73. export const useMeta2dData = () => {
  74. const getMeta2dData = async () => {
  75. return meta2dData;
  76. };
  77. const setMeta2dData = async (data:any) => {
  78. for(const key in data){
  79. meta2d.store.data[key] = data[key];
  80. }
  81. updateObject(meta2dData, data);
  82. };
  83. return {
  84. meta2dData,
  85. getMeta2dData,
  86. setMeta2dData,
  87. };
  88. };
  89. const dot = ref(false);
  90. export const useDot = () => {
  91. const getDot = async () => {
  92. return dot;
  93. };
  94. const setDot = async (value = true) => {
  95. dot.value = value;
  96. if (value) {
  97. tree.patch = true;
  98. debounce(autoSave, 3000);
  99. }
  100. };
  101. return {
  102. dot,
  103. getDot,
  104. setDot,
  105. };
  106. };
  107. const { user } = useUser();
  108. export enum SaveType {
  109. Save,
  110. SaveAs,
  111. }
  112. let saveTimer: any = 0;
  113. let saveFlag: boolean = true;
  114. export function queryURLParams(value?: string) {
  115. let url = value || window.location.href.split('?')[1];
  116. const urlSearchParams = new URLSearchParams(url);
  117. const params = Object.fromEntries(urlSearchParams.entries());
  118. return params;
  119. }
  120. // TODO 保存图纸
  121. export const save = async (
  122. type: SaveType = SaveType.Save,
  123. vType?: string,
  124. notice?: boolean,
  125. userFlag?:number,
  126. onlyJson?:boolean
  127. ) => {
  128. if (!saveFlag) {
  129. return;
  130. }
  131. if (saveTimer) {
  132. clearTimeout(saveTimer);
  133. }
  134. saveFlag = false;
  135. saveTimer = setTimeout(() => {
  136. saveFlag = true;
  137. }, 2000);
  138. // 区分是模板还是方案
  139. meta2d.stopAnimate();
  140. if( vType === 'v.component'){
  141. // @ts-ignore
  142. meta2d.store.data.component = true
  143. }
  144. const data: Meta2dBackData = meta2d.data();
  145. if (!(user && user.id)) {
  146. MessagePlugin.warning(noLoginTip);
  147. localforage.setItem(localStorageName, JSON.stringify(data));
  148. return;
  149. }
  150. // 保存为组件
  151. if (
  152. vType === 'v.component' &&
  153. meta2d.store.active &&
  154. meta2d.store.active.length === 1 &&
  155. meta2d.store.active[0].name === 'combine'
  156. ) {
  157. let comData: any = {
  158. center: data.center,
  159. folder: '',
  160. origin: data.origin,
  161. scale: data.scale,
  162. x: data.x,
  163. y: data.y,
  164. };
  165. // comData.name =
  166. // (meta2d.store.active[0] as any).description ||
  167. // `meta2d.${new Date().toLocaleString()}`;
  168. comData.name = (meta2d.store.active[0] as any).description ||'新建项目';
  169. let blob: Blob;
  170. try {
  171. blob = dataURLtoBlob(meta2d.activeToPng(10) + '');
  172. } catch (e) {
  173. MessagePlugin.error(
  174. '无法下载,宽度不合法,可能没有选中画笔/选中画笔大小超出浏览器最大限制'
  175. );
  176. return;
  177. }
  178. //todo 传参数
  179. const file:any = await upload(blob, true, comData.name , `/大屏/组件/默认`,'new');
  180. if (!file) {
  181. return;
  182. }
  183. // // 缩略图
  184. comData.image = file.url;
  185. comData.fullname = file.fullname;
  186. comData.component = true;
  187. const allPens = meta2d.canvas.getAllByPens(meta2d.store.active);
  188. comData.componentDatas = meta2d.toComponent(
  189. allPens,
  190. (meta2d.store.data as Meta2dBackData).showChild,
  191. false
  192. );
  193. comData.version = data.version;
  194. let ids = allPens.map(item=>item.id);
  195. comData.pens = data.pens.filter((pen)=>ids.includes(pen.id));
  196. const body = {
  197. data:comData,
  198. image:comData.image,
  199. name:comData.name,
  200. folder: '',
  201. template:userFlag===2?true:(data.isTemplate||false),
  202. case:comData.case
  203. }
  204. let ret: any = await addCollection('v.component', body); // 新增
  205. if (ret.error) {
  206. return;
  207. }
  208. MessagePlugin.success('成功保存为组件!');
  209. meta2d.emit('business-save', vType);
  210. return;
  211. }
  212. //删除老图片 新图片上传
  213. checkData(data);
  214. if (
  215. (globalThis as any).beforeSaveMeta2d &&
  216. !(await (globalThis as any).beforeSaveMeta2d(data))
  217. ) {
  218. return;
  219. }
  220. if(!data.isSystem && data.id){
  221. if(vType === 'v-template' && (data.component||data.isTemplate===false)){
  222. //模版 -> 组件/方案
  223. delete data.id;
  224. delete data._id;
  225. delete data.folder;
  226. }else if(vType === 'v.component' && !data.component){
  227. //组件 -> 模版/方案
  228. delete data.id;
  229. delete data._id;
  230. delete data.folder;
  231. }else if(!vType && (data.isTemplate&&data.component)){
  232. //方案 -> 模版/组件
  233. delete data.id;
  234. delete data._id;
  235. delete data.folder;
  236. }
  237. }
  238. const thumbFolder =
  239. vType === 'v-template'
  240. ? '模板'
  241. : vType === 'v.component'
  242. ? '组件'
  243. : '方案';
  244. const params = queryURLParams();
  245. if (type === SaveType.SaveAs) {
  246. //另存为去掉teams信息
  247. delete data.teams;
  248. delete data.folder;
  249. delete data.id;
  250. }
  251. //如果不是自己创建的团队图纸,就不去修改缩略图(没有权限去删除缩略图)
  252. if (!data.name) {
  253. // 文件名称
  254. // data.name = `meta2d.${new Date().toLocaleString()}`;
  255. data.name = `新建项目`;
  256. (meta2d.store.data as Meta2dBackData).name = data.name;
  257. }
  258. if (data.component || vType === 'v.component') {
  259. data.component = true;
  260. // pens 存储原数据用于二次编辑 ; componentDatas 组合后的数据,用于复用
  261. data.componentDatas = meta2d.toComponent(
  262. undefined,
  263. (meta2d.store.data as Meta2dBackData).showChild,
  264. false //自定义组合节点生成默认锚点
  265. );
  266. } else {
  267. data.component = false; // 必要值
  268. }
  269. let collection = data.component ? 'v.component' : 'v';
  270. if(data.id && data.ownerId !== user.id){
  271. //不是拥有者,判断有无编辑权限
  272. let temRet:any = await updateCollection(collection, {id:data.id || data._id, name: data.name});
  273. if(temRet.error){
  274. return;
  275. }
  276. }
  277. if(!onlyJson){
  278. // if (!data.id || (data.ownerId === user.id)) {
  279. // 图纸不是创建用户的图纸 先不改缩略图
  280. for (const pen of meta2d.store.data.pens) {
  281. if (['iframe'].includes(pen.name)) {
  282. //重新生成绘制图片
  283. pen.onRenderPenRaw?.(pen);
  284. }
  285. }
  286. let blob: Blob;
  287. try {
  288. blob = dataURLtoBlob(meta2d.toPng(10) + '');
  289. } catch (e) {
  290. MessagePlugin.error(
  291. '无法下载,宽度不合法,画布可能没有画笔/画布大小超出浏览器最大限制'
  292. );
  293. return;
  294. }
  295. let conflict = 'new';
  296. // if (data.id && type === SaveType.Save) {
  297. // // conflict = undefined
  298. // if (data.image && !(await delImage(data.image))) {
  299. // return;
  300. // }
  301. // }
  302. const file:any = await upload(
  303. blob,
  304. true,
  305. // 更新是缩略图路径一般为/file/2023/1025/1/1/新建项目_dfa573a5
  306. // data.image?.split('/').pop()更新操作项目名不变
  307. data.name,// + '.' + dayjs().format('YYYYMMDDHHMMss'),
  308. `/大屏/${thumbFolder}/${data.folder || '默认'}`,
  309. conflict
  310. );
  311. if (!file) {
  312. return;
  313. }
  314. // if (data.id && type === SaveType.Save) {
  315. // // conflict = undefined
  316. // if (data.image && !(await delImage(data.image))) {
  317. // return;
  318. // }
  319. // }
  320. // 缩略图
  321. data.image = file.url;
  322. data.filename = file.filename;
  323. (meta2d.store.data as Meta2dBackData).image = data.image;
  324. (meta2d.store.data as Meta2dBackData).filename = data.filename;
  325. // }
  326. }else{
  327. data.image = undefined;
  328. }
  329. let ret: any;
  330. !data.version && (data.version = baseVer);
  331. // TODO
  332. if (!data.folder) {
  333. data.folder = ''; // folder.name;
  334. }
  335. let childIds = [];
  336. data.pens.forEach((pen)=>{
  337. if(pen.name === 'iframe'){
  338. if(pen.iframe.indexOf(`view${rootDomain}`) !== -1){
  339. let params = queryURLParams(pen.iframe.split('?')[1])
  340. childIds.push(params.id);
  341. }
  342. }
  343. });
  344. // data.childIds = childIds;
  345. const body:any = {
  346. data,
  347. image:data.image,
  348. name:data.name,
  349. folder:data.folder,
  350. // shared:true,
  351. template:userFlag===2?true:(data.isTemplate||false),
  352. case:data.case,
  353. childIds
  354. }
  355. delete data.name;
  356. delete data.image;
  357. delete data.folder;
  358. delete data.case;
  359. delete data.isSystem;
  360. delete data.isTemplate;
  361. if(params.n && data.ownerId !== user.id){
  362. for (const k of delAttrs) {
  363. delete (data as any)[k];
  364. }
  365. }
  366. if (type === SaveType.SaveAs) {
  367. // 另存为一定走 新增 ,由于后端 未控制 userId 等属性,清空一下
  368. for (const k of delAttrs) {
  369. delete (data as any)[k];
  370. }
  371. body.template = false;
  372. body.component = false;
  373. ret = await addCollection(collection, body);
  374. } else {
  375. // if (data._id && data.teams && data.owner?.id !== user.id) {
  376. // // 团队图纸 不允许修改文件夹信息
  377. // delete data.folder;
  378. // ret = await updateCollection(collection, data);
  379. // } else
  380. if (data.id || data._id) {
  381. body.ownerId = data.ownerId;
  382. body.ownerName = data.ownerName;
  383. ret = await updateCollection(collection, {id:data.id || data._id,...body});
  384. } else {
  385. ret = await addCollection(collection, body); // 新增
  386. }
  387. }
  388. if (ret.error) {
  389. return;
  390. }
  391. // 保存图纸之后的钩子函数
  392. globalThis.afterSaveMeta2d && (await globalThis.afterSaveMeta2d(ret));
  393. if (
  394. !data.id ||
  395. router.currentRoute.value.query.version ||
  396. type === SaveType.SaveAs // 另存为肯定走新增,也会产生新的 id
  397. ) {
  398. data.id = ret.id;
  399. (meta2d.store.data as Meta2dBackData).id = data.id;
  400. router.replace({
  401. path: '/',
  402. query: {
  403. id: data.id,
  404. r: Date.now() + '',
  405. c: vType === 'v.component' ? 1 : undefined,
  406. },
  407. });
  408. }
  409. notice && MessagePlugin.success('保存成功!');
  410. meta2d.emit('business-save', vType);
  411. dot.value = false;
  412. localforage.removeItem(localStorageName);
  413. return true;
  414. };
  415. export const chargeDialogShow = ref(false);
  416. export const autoSaveAS = async(id:string)=>{
  417. //先请求打开图纸
  418. const ret: any = await getLe5leV(id);
  419. if(!ret.data && ret.price>0){
  420. return;
  421. }
  422. sessionStorage.setItem('opening', '1');
  423. router.push({
  424. path: '/',
  425. query: {
  426. r: Date.now() + '',
  427. },
  428. });
  429. //去除图纸一些信息
  430. for (const k of delAttrs) {
  431. delete ret[k];
  432. delete ret.data[k];
  433. }
  434. chargeDialogShow.value = false;
  435. meta2d.open(ret.data);
  436. meta2d.fitView();
  437. //另存为付费用户图纸
  438. setTimeout(()=>{
  439. save(SaveType.SaveAs, '', undefined, 1);
  440. },500)
  441. }
  442. const pen = ref(false);
  443. export const drawPen = () => {
  444. meta2d.inactive();
  445. try {
  446. if (!meta2d.canvas.drawingLineName) {
  447. // 开了钢笔,需要关掉铅笔
  448. meta2d.canvas.pencil && drawingPencil();
  449. meta2d.drawLine(meta2d.store.options.drawingLineName);
  450. } else {
  451. meta2d.finishDrawLine();
  452. meta2d.drawLine();
  453. }
  454. //钢笔
  455. pen.value = !!meta2d.canvas.drawingLineName;
  456. } catch (e: any) {
  457. MessagePlugin.warning(e.message);
  458. }
  459. };
  460. const pencil = ref(false);
  461. const drawingPencil = () => {
  462. try {
  463. if (!meta2d.canvas.pencil) {
  464. // 开了铅笔需要关掉钢笔
  465. meta2d.canvas.drawingLineName && drawPen();
  466. meta2d.drawingPencil();
  467. } else {
  468. meta2d.stopPencil();
  469. }
  470. pencil.value = meta2d.canvas.pencil || false;
  471. } catch (e: any) {
  472. MessagePlugin.warning(e.message);
  473. }
  474. };
  475. export const magnifier = ref(false);
  476. export const showMagnifier = () => {
  477. if (!meta2d.canvas.magnifierCanvas.magnifier) {
  478. meta2d.showMagnifier();
  479. } else {
  480. meta2d.hideMagnifier();
  481. }
  482. magnifier.value = meta2d.canvas.magnifierCanvas.magnifier;
  483. };
  484. export const map = ref(false);
  485. export const showMap = () => {
  486. if (!meta2d.map?.isShow) {
  487. meta2d.showMap();
  488. } else {
  489. meta2d.hideMap();
  490. }
  491. map.value = meta2d.map?.isShow;
  492. };
  493. export const title = '系统可能不会保存您所做的更改,是否继续?';
  494. export const unLogin = '未登录,系统可能不会保存您的文件,是否继续?';
  495. export const unsave = '当前文件未保存,是否继续?(开通vip可享受自动保存服务)';
  496. export function autoSave(force = false) {
  497. if (!dot.value && (!force || router.currentRoute.value.query.id)) {
  498. return;
  499. }
  500. const data: any = meta2d.data();
  501. if (
  502. user &&
  503. user.id &&
  504. user.vip &&
  505. (data.id||data._id) &&
  506. !data.component &&
  507. // data.owner &&
  508. data.ownerId === user.id
  509. ) {
  510. let _vType = '';
  511. if (data.isTemplate) {
  512. _vType = 'v-template';
  513. }
  514. save(SaveType.Save, _vType, false, undefined, true);
  515. } else {
  516. // data.updateAt = dayjs().format();
  517. localforage.setItem(localStorageName, JSON.stringify(data));
  518. }
  519. }
  520. // export const notificFn = async (fn: Function, params: any) => {
  521. // if (!(user && user.id)) {
  522. // if (await showNotification(unLogin)) {
  523. // fn(params);
  524. // }
  525. // } else {
  526. // if (dot.value) {
  527. // if (user.isVip) {
  528. // if (await save(SaveType.Save)) {
  529. // fn(params);
  530. // }
  531. // } else {
  532. // if (await showNotification(unsave)) {
  533. // fn(params);
  534. // }
  535. // }
  536. // } else {
  537. // fn(params);
  538. // }
  539. // }
  540. // };
  541. export const onScaleWindow = () => {
  542. // meta2d.fitView();
  543. meta2d.fitSizeView(true, 32);
  544. };
  545. export const onScaleFull = () => {
  546. meta2d.scale(1);
  547. // meta2d.centerView();
  548. const { x, y, origin, center } = meta2d.store.data;
  549. meta2d.translate(-x - origin.x, -y - origin.y);
  550. meta2d.translate(meta2d.store.options.x || 0, meta2d.store.options.y || 0);
  551. };
  552. export const blank = async (save = true) => {
  553. meta2d.canvas.drawingLineName && drawPen();
  554. meta2d.canvas.pencil && drawingPencil();
  555. meta2d.canvas.magnifierCanvas.magnifier && showMagnifier();
  556. meta2d.map?.isShow && showMap();
  557. save && autoSave(true);
  558. dot.value = false;
  559. sessionStorage.removeItem('openingId');
  560. meta2d.open({ pens: [], background: '#1e2430', color: '#bdc7db', width: 1920, height: 1080 } as any);
  561. select();
  562. };
  563. let lastTime = false;
  564. export const newFile = () => {
  565. if(dot.value && !lastTime){
  566. MessagePlugin.warning('当前画布未保存,请先保存!');
  567. lastTime = true;
  568. return;
  569. }
  570. lastTime = false;
  571. blank();
  572. router.push({
  573. path: '/',
  574. query: {
  575. r: Date.now() + '',
  576. },
  577. });
  578. // setTimeout(() => {
  579. // autoSave(true);
  580. // }, 300);
  581. meta2d.emit('business-assets',true);
  582. };
  583. export const inTreePanel = reactive({
  584. value: false,
  585. timer: undefined,
  586. });
  587. const tree = reactive({
  588. list: [],
  589. patch: true,
  590. });
  591. export const getPenTree = () => {
  592. tree.patch = false;
  593. const list = [];
  594. for (const item of meta2d.store.data.pens) {
  595. if (item.parentId) {
  596. continue;
  597. }
  598. const elem = calcElem(item);
  599. elem && list.push(elem);
  600. }
  601. tree.list = list.reverse();
  602. return tree.list;
  603. };
  604. const iframeTree = reactive({
  605. list: [],
  606. patch: true,
  607. });
  608. export const getIframeTree = () => {
  609. iframeTree.patch = false;
  610. const list = [];
  611. for (const item of meta2d.store.data.pens) {
  612. if (item.name !== 'iframe') {
  613. continue;
  614. }
  615. const elem = calcElem(item);
  616. elem && list.push(elem);
  617. }
  618. iframeTree.list = list.reverse();
  619. return iframeTree.list;
  620. };
  621. export const getPenAnimations = (idOrTag?: string) => {
  622. const animations = [];
  623. let pens: any[] = meta2d.store.active || [];
  624. if (idOrTag) {
  625. pens = meta2d.find(idOrTag) || [];
  626. }
  627. for (const pen of pens) {
  628. if (pen.animations) {
  629. for (const a of pen.animations) {
  630. animations.push(a.name);
  631. }
  632. }
  633. }
  634. return Array.from(new Set(animations));
  635. };
  636. const calcElem = (node: any) => {
  637. if (!node) {
  638. return;
  639. }
  640. let tag = '中';
  641. if (
  642. isDomShapes.includes(node.name) ||
  643. node.name.endsWith('Dom') ||
  644. meta2d.store.options.domShapes.includes(node.name)
  645. ) {
  646. tag = 'dom';
  647. } else if (node.canvasLayer === 1) {
  648. tag = '模板';
  649. } else if (node.name === 'image') {
  650. if(node.canvasLayer === 2){
  651. tag = '下层';
  652. }else if(node.canvasLayer===3){
  653. tag = '中层';
  654. }else{
  655. tag = '上层';
  656. }
  657. } else {
  658. tag = '中层';
  659. }
  660. const elem: any = {
  661. label: (node as any).description || node.name,
  662. value: node.id,
  663. locked: node.locked,
  664. visible: node.visible,
  665. tag,
  666. };
  667. if (!node.children) {
  668. return elem;
  669. }
  670. elem.children = [];
  671. for (const id of node.children) {
  672. const child = calcElem(meta2d.store.pens[id]);
  673. child && elem.children.push(child);
  674. }
  675. return elem;
  676. };
  677. export const setChildrenVisible = (node: any, v: boolean) => {
  678. const children = node.getChildren();
  679. if (children && children.length > 0) {
  680. for (const child of children) {
  681. child.data.visible = v;
  682. setChildrenVisible(child, v);
  683. }
  684. }
  685. };
  686. export const fonts = [
  687. '新宋体',
  688. '微软雅黑',
  689. '黑体',
  690. '楷体',
  691. '斗鱼追光体',
  692. '庞门正道标题体',
  693. 'DS-DIGI-1',
  694. 'DS-DIGIB-2',
  695. 'DS-DIGII-3',
  696. 'DS-DIGIT-4',
  697. 'ALIBABA Regular',
  698. 'ALIBABA Bold',
  699. '-apple-system',
  700. 'BlinkMacSystemFont',
  701. 'PingFang SC',
  702. 'Hiragino Sans GB',
  703. 'Microsoft YaHei UI',
  704. 'Microsoft YaHei',
  705. 'fangsong',
  706. 'Source Han Sans CN',
  707. 'sans-serif',
  708. 'serif',
  709. 'Apple Color Emoji',
  710. 'Segoe UI Emoji',
  711. 'Segoe UI Symbol',
  712. ];
  713. export const delAttrs = [
  714. 'userId',
  715. 'shared',
  716. 'team',
  717. 'owner',
  718. 'username',
  719. 'editor',
  720. 'editorId',
  721. 'editorName',
  722. 'createdAt',
  723. 'tags',
  724. 'image',
  725. 'id',
  726. '_id',
  727. 'view',
  728. 'updatedAt',
  729. 'star',
  730. 'recommend',
  731. ];
  732. export const typeOptions = [
  733. {
  734. label: '字符串',
  735. value: 'string',
  736. },
  737. {
  738. label: '整数',
  739. value: 'integer',
  740. },
  741. {
  742. label: '浮点数',
  743. value: 'float',
  744. },
  745. {
  746. label: '布尔',
  747. value: 'bool',
  748. },
  749. {
  750. label: '对象',
  751. value: 'object',
  752. },
  753. {
  754. label: '数组',
  755. value: 'array',
  756. },
  757. ];
  758. let folder = reactive<any>({
  759. _id: '',
  760. });
  761. export const useFolder = () => {
  762. const getFolder = async () => {
  763. return folder;
  764. };
  765. const setFolder = async (value: any) => {
  766. folder = deepClone(value);
  767. };
  768. return {
  769. folder,
  770. getFolder,
  771. setFolder,
  772. };
  773. };
  774. export function changeType(value: string) {
  775. if (value === 'false') {
  776. return false;
  777. } else if (value === 'true') {
  778. return true;
  779. } else if (
  780. value === '' ||
  781. isNaN(Number(value)) ||
  782. (typeof value === 'string' && value.endsWith('.'))
  783. ) {
  784. // 小数也进入这个
  785. return value;
  786. }
  787. return Number(value);
  788. }
  789. // 附加缓存数据
  790. const extendData = reactive<any>({
  791. lineIntersect: false,
  792. });
  793. export const useExtendData = () => {
  794. const setExtendData = (key: any,value:any) => {
  795. extendData[key] = value;
  796. }
  797. const getExtendData = (key: any) => {
  798. return extendData[key];
  799. }
  800. return {
  801. extendData,
  802. getExtendData,
  803. setExtendData,
  804. };
  805. };
  806. export function dealDataBeforeOpen(data){
  807. data.oldV = false;
  808. data.pens.forEach((pen)=>{
  809. if(pen.image){
  810. pen.image = pen.image.split('?')[0];
  811. }
  812. if (!(pen.animations && pen.animations.length)) {
  813. if (!pen.type && pen.frames) {
  814. pen.animations = [
  815. {
  816. name: '动画1',
  817. temType: 'id',
  818. animate: 'custom',
  819. frames: deepClone(pen.frames),
  820. animateCycle: pen.animateCycle,
  821. keepAnimateState: pen.keepAnimateState,
  822. linear: pen.linear,
  823. autoPlay: pen.autoPlay,
  824. nextAnimate: pen.nextAnimate,
  825. },
  826. ];
  827. data.oldV = true;
  828. } else if (pen.type && pen.lineAnimateType !== undefined) {
  829. pen.animations = [
  830. {
  831. name: '动画1',
  832. temType: 'id',
  833. animateSpan: pen.animateSpan || 1,
  834. lineAnimateType: pen.lineAnimateType,
  835. animateColor: pen.animateColor,
  836. animateReverse: pen.animateReverse,
  837. animateCycle: pen.animateCycle,
  838. animateLineWidth: pen.animateLineWidth,
  839. autoPlay: pen.autoPlay,
  840. nextAnimate: pen.nextAnimate,
  841. },
  842. ];
  843. data.oldV = true;
  844. }
  845. }
  846. if (pen.events?.length) {
  847. for (let i = 0; i < pen.events.length; i++) {
  848. const event = pen.events[i];
  849. // pen.events.forEach((event)=>{
  850. if (event.action !== undefined) {
  851. data.oldV = true;
  852. // 老格式
  853. if (event.name === 'valueUpdate') {
  854. if (event.where && event.where.key) {
  855. /*
  856. if (!pen.realTimes) {
  857. pen.realTimes = [];
  858. }
  859. let index = pen.realTimes.findIndex(
  860. (el) => el.key === event.where.key
  861. );
  862. let trigger = {
  863. name: '状态1',
  864. conditionType: 'and',
  865. conditions: [
  866. {
  867. type: event.where?.type === 'custom' ? 'fn' : '',
  868. key: event.where?.key,
  869. operator: event.where?.comparison,
  870. value: event.where?.value,
  871. fnJs: event.where?.fnJs,
  872. },
  873. ],
  874. actions: [
  875. {
  876. action: event.action,
  877. value: event.value,
  878. params: event.params,
  879. },
  880. ],
  881. };
  882. if (index !== -1) {
  883. pen.realTimes[index].triggers.push(trigger);
  884. } else {
  885. pen.realTimes.push({
  886. label: event.where.key,
  887. key: event.where.key,
  888. triggers: [trigger],
  889. });
  890. }
  891. pen.events.splice(i, 1);
  892. i--;*/
  893. //new
  894. if (!pen.triggers) {
  895. pen.triggers = [];
  896. }
  897. let trigger = {
  898. name: '状态1',
  899. conditionType: 'and',
  900. conditions: [
  901. {
  902. type: event.where?.type === 'custom' ? 'fn' : '',
  903. key: event.where?.key,
  904. operator: event.where?.comparison,
  905. value: event.where?.value,
  906. fnJs: event.where?.fnJs,
  907. },
  908. ],
  909. actions: [
  910. {
  911. action: event.action,
  912. value: event.value,
  913. params: event.params,
  914. },
  915. ],
  916. };
  917. let index = pen.triggers.findIndex(
  918. (el) => el.temKey === event.where.key
  919. );
  920. if(index !== -1){
  921. const state = pen.triggers[index].status;
  922. const idx = state.findIndex((el)=>el.conditions?.length&&el.conditions[0].key === trigger.conditions[0].key&&el.conditions[0].operator === trigger.conditions[0].operator&&el.conditions[0].value === trigger.conditions[0].value);
  923. if(idx!==-1){
  924. state[idx].actions.push(...deepClone(trigger.actions));
  925. }else{
  926. pen.triggers[index].status.push(trigger);
  927. }
  928. }else{
  929. pen.triggers.push({
  930. temKey:event.where?.key,
  931. name:`场景状态${i+1}`,
  932. status:[trigger]
  933. });
  934. }
  935. pen.events.splice(i, 1);
  936. i--;
  937. } else {
  938. //TODO 没有选择触发条件的情况
  939. if (event.value.indexOf('pen.value') !== -1) {
  940. if (!pen.realTimes) {
  941. pen.realTimes = [];
  942. }
  943. pen.realTimes.push({
  944. label: 'value',
  945. key: 'value',
  946. triggers: [
  947. {
  948. name: '状态1',
  949. conditionType: 'and',
  950. conditions: [],
  951. actions: [
  952. {
  953. action: event.action,
  954. value: event.value,
  955. params: event.params,
  956. },
  957. ],
  958. },
  959. ],
  960. });
  961. pen.events.splice(i, 1);
  962. i--;
  963. }
  964. }
  965. } else {
  966. event.conditionType = 'and';
  967. event.actions = [
  968. {
  969. action: event.action,
  970. value: event.value,
  971. params: event.params,
  972. },
  973. ];
  974. if (event.where && event.where.type) {
  975. event.conditions = [
  976. {
  977. type: event.where.type === 'custom' ? 'fn' : '',
  978. key: event.where.key,
  979. operator: event.where.comparison,
  980. //valueType target
  981. value: event.where.value,
  982. fnJs: event.where.fnJs,
  983. },
  984. ];
  985. }
  986. delete event.action;
  987. delete event.value;
  988. delete event.params;
  989. delete event.where;
  990. }
  991. }
  992. // });
  993. }
  994. }
  995. //状态格式转换
  996. if(!(pen.triggers?.length) && pen.realTimes?.length){
  997. pen.triggers = [];
  998. pen.realTimes.forEach((realTime,index)=>{
  999. const delIdx = [];
  1000. realTime.triggers?.forEach((trigger,_idx)=>{
  1001. if(trigger.conditions?.length){
  1002. trigger.conditions.forEach((condition,_idx)=>{
  1003. condition.key = realTime.key;
  1004. condition.keyLabel = realTime.label || realTime.key;
  1005. });
  1006. if(trigger.conditions?.length === 1){
  1007. const _idx2 = realTime.triggers.findIndex((el)=>el.conditions?.length&&el.conditions[0].key === trigger.conditions[0].key&&el.conditions[0].operator === trigger.conditions[0].operator&&el.conditions[0].value === trigger.conditions[0].value);
  1008. if(_idx !== _idx2){
  1009. realTime.triggers[_idx2].actions.push(...deepClone(realTime.triggers[_idx].actions));
  1010. delIdx.push(_idx);
  1011. }
  1012. }
  1013. }
  1014. });
  1015. delIdx.forEach((idx,index)=>{
  1016. realTime.triggers.splice((idx-index),1);
  1017. });
  1018. if(realTime.triggers?.length){
  1019. pen.triggers.push({
  1020. name:`状态情况${index+1}`,
  1021. status:deepClone(realTime.triggers)
  1022. });
  1023. }
  1024. delete realTime.triggers;
  1025. });
  1026. }
  1027. if(pen.triggers?.length){
  1028. pen.triggers = pen.triggers.filter((item)=>item.status?.length);
  1029. }
  1030. if(pen.name === 'table2'){
  1031. pen.name = 'tablePlus'
  1032. }
  1033. })
  1034. }