common.ts 32 KB

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