common.ts 24 KB

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