common.ts 31 KB

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