Selaa lähdekoodia

feat:download

ananzhusen 1 vuosi sitten
vanhempi
sitoutus
640c2333ff
4 muutettua tiedostoa jossa 306 lisäystä ja 18 poistoa
  1. 93 0
      src/services/download.ts
  2. 19 2
      src/views/Preview.vue
  3. 194 0
      src/views/components/Header.vue
  4. 0 16
      src/views/components/View.vue

+ 93 - 0
src/services/download.ts

@@ -0,0 +1,93 @@
+import { cdn, upCdn } from '@/services/api';
+import {
+  checkData,
+} from '@/services/utils';
+
+export const getDownloadList = (meta2dData:any, path:string='v') => {
+  const lists = new Set();
+  //TODO 加一个type区分是数据/还是接口
+  //背景图片
+  // const meta2dData = meta2d.data();
+  let img = meta2dData.bkImage;
+  if (img) {
+    if (img.startsWith('/') || img.startsWith(cdn) || img.startsWith(upCdn)) {
+      let _img = img.replace(cdn, '').replace(upCdn, '');
+      if(_img.startsWith('/v/')){
+        _img = _img.slice(2);
+      }
+      lists.add({
+        url:img,
+        path:`/view/projects/${path}` +_img,
+      })
+    }
+  }
+
+  //图片图元(image strokeImage backgroundImage)
+  const imageKeys = ['image','strokeImage','backgroundImage'];
+  const images: string[] = [];
+  for (const pen of meta2dData.pens) {
+    for (const i of imageKeys) {
+      const image = pen[i];
+      if (image) {
+        if (
+          image.startsWith('/') ||
+          image.startsWith(cdn) ||
+          image.startsWith(upCdn)
+        ) {
+          // 只考虑相对路径下的 image ,绝对路径图片无需下载
+          let _img = image.replace(cdn, '').replace(upCdn, '');
+          if(_img.startsWith('/v/')){
+            _img = _img.slice(2);
+          }
+          if (!images.includes(image)) {
+            // let _img = image.replace(cdn, '').replace(upCdn, '');
+            lists.add({
+              url:image,
+              path:`/view/projects/${path}`+_img
+            });
+          }
+          pen[i] = `/view/projects/${path}`+_img
+        }
+      }
+    }
+  }
+  
+  //其他文件
+  const files = [
+    // '/view/assets/index.js',
+    '/view/assets/index.css',
+    '/view/css/index.css',
+
+    '/view/js/marked.min.js',
+    '/view/js/mycharts.js',
+    '/view/js/echarts.min.js',
+    '/view/js/lcjs.iife.js',
+    '/view/js/highcharts.js',
+    '/view/js/highcharts-more.js',
+    '/view/js/2d-components.js',
+
+    '/view/index.html',
+    '/view/favicon.ico',
+    '/view/view.conf',
+    '/view/离线部署包使用说明.pdf'
+  ];
+  files.forEach((file)=>{
+    lists.add({
+      url: (cdn ? cdn:'')+  file,
+      path:file
+    });
+  });
+
+  //数据
+  // const data: any = meta2d.data();
+  if (meta2dData._id) delete meta2dData._id;
+  if (meta2dData.id) delete meta2dData.id;
+  if ((meta2dData as any).image) delete (meta2dData as any).image;
+  checkData(meta2dData);
+  lists.add({
+    data:JSON.stringify(meta2dData).replaceAll(cdn, '').replaceAll(upCdn, ''),
+    path:`/view/projects/${path}/data`,
+  });
+
+  return lists;
+}

+ 19 - 2
src/views/Preview.vue

@@ -13,6 +13,7 @@ import { useRouter, useRoute } from 'vue-router';
 import { Meta2d, Options, Pen } from '@meta2d/core';
 import { registerBasicDiagram } from '@/services/register';
 import { cdn, getLe5leV } from '@/services/api';
+import { getDownloadList } from '@/services/download';
 const route = useRoute();
 
 const meta2dDom = ref('');
@@ -42,7 +43,12 @@ onMounted(() => {
     try {
       let data = JSON.parse(e.data);
       if (typeof data === 'object') {
-        meta2d.emit(data.name);
+        if(data.type && data.name==='downloadHtml'){
+          //处理下载
+          doDownload(data.path);
+        }else{
+          meta2d.emit(data.name);
+        }
       } else {
         meta2d.emit(data);
       }
@@ -62,7 +68,7 @@ const watcher = watch(
 const open = async () => {
   if (route.query.id) {
     const ret: any = await getLe5leV(route.query.id + '');
-    ret && meta2d.open(ret);
+    ret && ret.data && meta2d.open(ret.data);
   } else {
     let data: any = await localforage.getItem(localStorageName);
     if (data) {
@@ -90,6 +96,17 @@ const opened = () => {
   });
 };
 
+const doDownload = (path:string) => {
+  const list = getDownloadList(meta2d.data(),path);
+  window.parent.postMessage(
+    JSON.stringify({
+      name:'download',
+      data:[...list],
+      type:1
+    })
+  , 
+  '*');
+}
 onUnmounted(() => {
   watcher();
   if (meta2d) {

+ 194 - 0
src/views/components/Header.vue

@@ -348,6 +348,7 @@ import {
 } from '@/services/common';
 import { useEnterprise } from '@/services/enterprise';
 import { CheckIcon,HomeIcon ,DesktopIcon ,ControlPlatformIcon,AppIcon} from 'tdesign-icons-vue-next';
+import { getDownloadList } from '@/services/download';
 
 const { enterprise } = useEnterprise();
 const router = useRouter();
@@ -380,8 +381,33 @@ const initMeta2dName = () => {
   data.name = (meta2d.store.data as Meta2dBackData).name || '';
 };
 
+let downloadList = new Set();
+let iframeNum = 0;
+let compareNum = 0;
 nextTick(() => {
   meta2d.on('opened', initMeta2dName);
+  window.addEventListener('message', function (e) {
+    if (typeof e.data !== 'string'||!e.data||e.data.startsWith('setImmediate')) {
+      return;
+    }
+    try {
+      let data = JSON.parse(e.data);
+      if (typeof data === 'object') {
+        if(data.type && data.name==='download'){
+          downloadList = new Set([...downloadList, ...data.data]);
+          compareNum+=1;
+          if(compareNum>=iframeNum){
+            saveDownload();
+          }
+        }
+        meta2d.emit(data.name);
+      } else {
+        meta2d.emit(data);
+      }
+    } catch (e) {
+      console.info(e);
+    }
+  });
 });
 
 onUnmounted(() => {
@@ -697,6 +723,174 @@ const downloadHtml = async () => {
     return;
   }
 
+  if(user.vipDesc !== '超级会员'&&user.vipDesc !=='旗舰会员'){
+    MessagePlugin.info('需要开通超级会员~');
+    gotoAccount();
+    return
+  }
+
+  MessagePlugin.info('正在下载打包中,可能需要几分钟,请耐心等待...');
+  compareNum = 0;
+  const meta2dData = meta2d.data();
+
+  const pen_3d = meta2dData.pens.filter(
+    (pen) =>
+      pen.name === 'iframe' &&
+      (pen.iframe.indexOf('3d.le5le.com') !== -1)
+  );
+  if (pen_3d && pen_3d.length) {
+    //存在3d场景
+    if(pen_3d.length===1){
+      let params = queryURLParams(pen_3d[0].iframe.split('?')[1]);
+      meta2d.store.pens[pen_3d[0].id].calculative.singleton.div.children[0].contentWindow.postMessage(
+          JSON.stringify({
+            name:'deploy',
+            // id: params.id,
+            type:1, //用于区分是系统消息
+            path:`3d`
+          }),
+          '*'
+      );
+      pen_3d.iframe = '/view?data=3d';
+    }else{
+      pen_3d.forEach((pen) => {
+        //发送消息
+        let params = queryURLParams(pen.iframe.split('?')[1]);
+        (
+          meta2d.store.pens[pen.id].calculative.singleton.div.children[0] as HTMLIFrameElement
+        ).contentWindow.postMessage(
+          JSON.stringify({
+            name:'deploy',
+            // id: params.id,
+            type:1,
+            path:`3d-${params.id}` 
+          }),
+          '*'
+        );
+        pen.iframe = `/view?data=3d-${params.id}`;
+      });
+    }
+    iframeNum+= pen_3d.length;
+  }
+
+  const pen_2d = meta2dData.pens.filter(
+    (pen) =>
+      pen.name === 'iframe' &&
+      (pen.iframe.indexOf('2d.le5le.com') !== -1)
+  );
+  if (pen_2d && pen_2d.length) {
+    //存在3d场景
+    if(pen_2d.length===1){
+      let params = queryURLParams(pen_2d[0].iframe.split('?')[1]);
+      meta2d.store.pens[pen_2d[0].id].calculative.singleton.div.children[0].contentWindow.postMessage(
+          JSON.stringify({
+            name:'downloadHtml',
+            id: params.id,
+            type:1,
+            path:`2d`
+          }),
+          '*'
+      );
+      pen_2d[0].iframe = '/view?data=2d'
+    }else{
+      pen_2d.forEach((pen) => {
+        //发送消息
+        let params = queryURLParams(pen.iframe.split('?')[1]);
+        (
+          meta2d.store.pens[pen.id].calculative.singleton.div.children[0] as HTMLIFrameElement
+        ).contentWindow.postMessage(
+          JSON.stringify({
+            name:'downloadHtml',
+            // id: params.id,
+            type:1,
+            path:`2d-${params.id}`
+          }),
+          '*'
+        );
+      });
+      pen.iframe = `/view?data=2d-${params.id}`
+    }
+    iframeNum+= pen_2d.length;
+  }
+
+  const pen_v = meta2dData.pens.filter(
+    (pen) =>
+      pen.name === 'iframe' &&
+      (pen.iframe.indexOf('/preview') !== -1)
+  );
+
+  if (pen_v && pen_v.length) {
+    //存在3d场景
+      pen_v.forEach((pen) => {
+        //发送消息
+        let params = queryURLParams(pen.iframe.split('?')[1]);
+        (
+          meta2d.store.pens[pen.id].calculative.singleton.div.children[0] as HTMLIFrameElement
+        ).contentWindow.postMessage(
+          JSON.stringify({
+            name:'downloadHtml',
+            // id: params.id,
+            type:1,
+            path:`v-${params.id}`
+          }),
+          '*'
+        );
+       pen.iframe = `/view?data=v-${params.id}`
+    });
+    iframeNum+= pen_v.length;
+  }
+
+  downloadList = getDownloadList(meta2dData);
+  
+  if(iframeNum===0){
+    //如果没有嵌入场景
+    saveDownload();
+  }else{
+    setTimeout(()=>{
+      if(compareNum < iframeNum){
+        //message阻塞/报错的情况
+        saveDownload();
+      }
+    },10000);
+  }
+}
+
+const saveDownload = async()=>{
+  const [{ default: JSZip }, { saveAs }] = await Promise.all([
+    import('jszip'),
+    import('file-saver'),
+  ]);
+  const zip = new JSZip();
+
+  await Promise.all([...downloadList].map(async(item)=>{
+    if(item.url){
+      //接口请求
+      const res: Blob = await axios.get(item.url, {
+        responseType: 'blob',
+      });
+      zip.file(item.path, res, { createFolders: true });
+    }else if(item.data){
+      //直接写数据
+      zip.file(
+        item.path,
+        item.data, { createFolders: true }
+      );
+    }
+  }));
+  let _fileName =
+    (data.name && data.name.replace(/\//g, '_').replace(/:/g, '_')) ||
+    'le5le.meta2d';
+  const blob = await zip.generateAsync({ type: 'blob' });
+  saveAs(blob, `${_fileName}.zip`);
+} 
+
+
+const _downloadHtml = async () => {
+  if (!(user && user.id)) {
+    MessagePlugin.warning(noLoginTip);
+    return;
+  }
+
   // if (!user.isVip) {
   //   gotoAccount();
   //   return;

+ 0 - 16
src/views/components/View.vue

@@ -889,22 +889,6 @@ onMounted(() => {
   window.onbeforeunload = () => {
     autoSave();
   };
-
-  window.addEventListener('message', function (e) {
-    if (typeof e.data !== 'string') {
-      return;
-    }
-    try {
-      let data = JSON.parse(e.data);
-      if (typeof data === 'object') {
-        meta2d.emit(data.name);
-      } else {
-        meta2d.emit(data);
-      }
-    } catch (e) {
-      console.info(e);
-    }
-  });
 });
 
 const watcher = watch(