common.ts 31 KB

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