common.ts 28 KB

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