Ver código fonte

feat:预览页面-download组件

ananzhusen 1 ano atrás
pai
commit
77c1cd24ff

Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
public/view/js/r.js


+ 0 - 1
src/services/common.ts

@@ -786,7 +786,6 @@ export const newFile = () => {
     },
   });
   // setTimeout(() => {
-  //   console.log("autoSave")
   //   autoSave(true);
   // }, 300);
   meta2d.emit('business-assets',true);

+ 343 - 1
src/services/download.ts

@@ -1,8 +1,14 @@
 import { cdn, upCdn } from '@/services/api';
 import { checkData } from '@/services/utils';
 import axios from 'axios';
+// import { MessagePlugin } from 'tdesign-vue-next';
+import { useUser } from '@/services/user';
+import JSZip from 'jszip';
+import { Pen, getGlobalColor, isShowChild } from '@meta2d/core';
+
 export const img_cdn = 'https://assets.le5lecdn.com';
 export const img_upCdn = 'https://drive.le5lecdn.com';
+const { user, signout } = useUser();
 
 const components = [
   'inputDom',
@@ -256,7 +262,7 @@ export const getComponentPurchased = async (list: any) => {
   return res.list;
 };
 
-export const get2dComponentJs = async (names: string[]=components) => {
+export const get2dComponentJs = async (names: string[] = components) => {
   let list = [];
   names.forEach((item) => {
     list.push({
@@ -289,3 +295,339 @@ export const getGoods = async () => {
   return res;
 };
 
+export enum Frame {
+  vue2,
+  vue3,
+  react,
+  html,
+}
+
+let frameFlag = -1;
+
+export const preFrameDownload = async (type: Frame) => {
+  frameFlag = type;
+  // MessagePlugin.info('正在下载打包中,可能需要几分钟,请耐心等待...');
+  zip3D(
+    type === Frame.vue3 ? 'toVue3' : type === Frame.vue2 ? 'toVue2' : 'toReact'
+  );
+  zip2D(
+    type === Frame.vue3
+      ? 'downloadVue3'
+      : type === Frame.vue2
+      ? 'downloadVue2'
+      : 'downloadReact'
+  );
+  const data: any = meta2d.data();
+  if (data._id) delete data._id;
+  if (data.id) delete data.id;
+  if (data.image) delete data.image;
+  data.userId = user.id;
+  checkData(data);
+  const [{ default: JSZip }, { saveAs }] = await Promise.all([
+    import('jszip'),
+    import('file-saver'),
+  ]);
+  const zip = new JSZip();
+  let _fileName =
+    (data.name && data.name.replace(/\//g, '_').replace(/:/g, '_')) ||
+    'le5le.meta2d';
+  //处理付费svg
+  if (Object.keys(data.paths).length >= 3) {
+    //简单判断有无svg图元
+    const res: any = await axios.post('/api/paid/2d/component', {
+      type: 'SVG线性图元',
+    });
+    if (res.list.length === 1 && !res.list[0].name) {
+      //已经购买全部
+      for (let key of Object.keys(data.paths)) {
+        let path = data.paths[key];
+        if (
+          path.indexOf('-1.18Zm4-1') !== -1 ||
+          path.indexOf('-1.19Zm4-1') !== -1 ||
+          path.indexOf('2.85ZM') !== -1 ||
+          path.indexOf('-1-2.39.3') !== -1
+        ) {
+          data.paths[key] = '';
+        }
+      }
+    } else {
+      //购买部分
+      let purchasedList = res.list.map((i) => i.name);
+      data.pens.forEach((pen) => {
+        if (pen.name === 'svgPath' && pen.svgUrl) {
+          if (purchasedList.includes(pen.svgUrl)) {
+            pen.pathId = null;
+          }
+        }
+      });
+    }
+  }
+
+  const _zip: any = zip.folder(`${_fileName}`);
+  _zip.file(
+    `${
+      type === Frame.vue3
+        ? 'meta2d-vue3'
+        : type === Frame.vue2
+        ? 'meta2d-vue2'
+        : 'meta2d-react'
+    }/public/json/data.json`,
+    JSON.stringify(data).replaceAll(cdn, '').replaceAll(upCdn, '')
+  );
+  await Promise.all([
+    zipJs(_zip),
+    zipBkImg(_zip),
+    zipImages(_zip, meta2d.store.data.pens),
+    type === Frame.vue3
+      ? zipVue3Files(_zip)
+      : type === Frame.vue2
+      ? zipVue2Files(_zip)
+      : zipReactFiles(_zip),
+    zipIotPens(_zip),
+  ]);
+  const blob = await zip.generateAsync({ type: 'blob' });
+  saveAs(blob, `${_fileName}.zip`);
+  frameFlag = -1;
+};
+
+async function zipIotPens(zip: JSZip) {
+  //处理控件
+  const js = await get2dComponentJs();
+  zip.file(
+    `${
+      frameFlag === Frame.vue3
+        ? 'meta2d-vue3'
+        : frameFlag === Frame.vue2
+        ? 'meta2d-vue2'
+        : 'meta2d-react'
+    }/public/js/2d-components.js`,
+    js,
+    { createFolders: true }
+  );
+  const res: Blob = await axios.get('/view/js/r.js', {
+    responseType: 'blob',
+  });
+  zip.file(
+    `${
+      frameFlag === Frame.vue3
+        ? 'meta2d-vue3'
+        : frameFlag === Frame.vue2
+        ? 'meta2d-vue2'
+        : 'meta2d-react'
+    }/public/js/r.js`,
+    res,
+    { createFolders: true }
+  );
+}
+
+async function zipJs(zip: JSZip) {
+  const files = ['/view/js/marked.min.js', '/view/js/lcjs.iife.js'];
+  await Promise.all(
+    files.map(async (filePath) => {
+      const res: Blob = await axios.get(filePath, {
+        responseType: 'blob',
+      });
+      zip.file(
+        `${
+          frameFlag === Frame.vue3
+            ? 'meta2d-vue3'
+            : frameFlag === Frame.vue2
+            ? 'meta2d-vue2'
+            : 'meta2d-react'
+        }/public` + filePath.replace('/view', ''),
+        res,
+        { createFolders: true }
+      );
+    })
+  );
+}
+
+export async function zipBkImg(zip: JSZip) {
+  let img = meta2d.store.data.bkImage;
+  if (img) {
+    if (img.startsWith('/') || img.startsWith(cdn) || img.startsWith(upCdn)) {
+      const pngs = await getTemPngs([img.replace(cdn, '').replace(upCdn, '')]);
+      await zipImage(zip, img, pngs[img.replace(cdn, '').replace(upCdn, '')]);
+    }
+  }
+}
+
+async function zipImage(zip: JSZip, image: string, temImage?: string) {
+  const res: Blob = await axios.get(temImage || image, {
+    responseType: 'blob',
+    // params: {
+    //   isZip: true,
+    // },
+  });
+  zip.file(
+    (frameFlag === -1
+      ? ''
+      : `${
+          frameFlag === Frame.vue3
+            ? 'meta2d-vue3'
+            : frameFlag === Frame.vue2
+            ? 'meta2d-vue2'
+            : 'meta2d-react'
+        }/public`) + (cdn ? image.replace(cdn, '').replace(upCdn, '') : image),
+    res,
+    {
+      createFolders: true,
+    }
+  );
+}
+
+const zip3D = (name: string) => {
+  const pen_3d = meta2d.store.data.pens.filter(
+    (pen) =>
+      pen.name === 'iframe' &&
+      (pen.tags.includes('meta3d') || pen.iframe.indexOf('3d') !== -1)
+  );
+  if (pen_3d && pen_3d.length) {
+    //存在3d场景
+    pen_3d.forEach((pen) => {
+      //发送消息
+      // let params = queryURLParams(pen.iframe.split('?')[1]);
+      (
+        pen.calculative.singleton.div.children[0] as HTMLIFrameElement
+      ).contentWindow.postMessage(
+        JSON.stringify({
+          type: 1,
+          name,
+          // id: params.id,
+        }),
+        '*'
+      );
+    });
+  }
+};
+
+const zip2D = (name: string) => {
+  const pen_2d = meta2d.store.data.pens.filter(
+    (pen) =>
+      pen.name === 'iframe' &&
+      (pen.iframe.indexOf('2d.le5le.com') !== -1 ||
+        pen.iframe.indexOf('/2d/') !== -1 ||
+        pen.iframe.indexOf('v.le5le.com') !== -1 ||
+        pen.iframe.indexOf('/v/') !== -1 ||
+        pen.iframe.indexOf('/preview') !== -1)
+  );
+  if (pen_2d && pen_2d.length) {
+    //存在3d场景
+    pen_2d.forEach((pen) => {
+      //发送消息
+      // let params = queryURLParams(pen.iframe.split('?')[1]);
+      (
+        pen.calculative.singleton.div.children[0] as HTMLIFrameElement
+      ).contentWindow.postMessage(
+        JSON.stringify({
+          name,
+          type: 1,
+        }),
+        '*'
+      );
+    });
+  }
+};
+
+/**
+ * 图片放到 zip 里
+ * @param pens 可以是非具有 calculative 的 pen
+ */
+export async function zipImages(zip: JSZip, pens: Pen[]) {
+  if (!pens) {
+    return;
+  }
+
+  // 不止 image 上有图片, strokeImage ,backgroundImage 也有图片
+  const imageKeys = [
+    {
+      string: 'image',
+    },
+    { string: 'strokeImage' },
+    { string: 'backgroundImage' },
+  ] as const;
+  const images: string[] = [];
+  for (const pen of pens) {
+    for (const i of imageKeys) {
+      const image = pen[i.string];
+      if (image) {
+        // HTMLImageElement 无法精确控制图片格式
+        if (
+          image.startsWith('/') ||
+          image.startsWith(cdn) ||
+          image.startsWith(upCdn)
+        ) {
+          // 只考虑相对路径下的 image ,绝对路径图片无需下载
+          if (!images.includes(image)) {
+            images.push(image);
+          }
+        }
+      }
+    }
+    // 无需递归遍历子节点,现在所有的节点都在外层
+  }
+  //付费pngs
+  const pngs = await getTemPngs(
+    images.map((i) => i.replace(cdn, '').replace(upCdn, ''))
+  );
+  await Promise.all(
+    images.map((image) =>
+      zipImage(zip, image, pngs[image.replace(cdn, '').replace(upCdn, '')])
+    )
+  );
+}
+
+//新
+async function zipVue3Files(zip: JSZip) {
+  const files = [
+    '/view/meta2d-vue3/src/components/Meta2d.vue',
+    '/view/meta2d-vue3/src/App.vue',
+    '/view/meta2d-vue3/src/main.js',
+    '/view/meta2d-vue3/src/style.css',
+    '/view/meta2d-vue3/index.html',
+    '/view/meta2d-vue3/package.json',
+    '/view/meta2d-vue3/README.md',
+    '/view/meta2d-vue3/vite.config.js',
+  ] as const;
+  // 文件同时加载
+  await Promise.all(files.map((filePath) => zipFile(zip, filePath)));
+}
+
+async function zipVue2Files(zip: JSZip) {
+  const files = [
+    '/view/meta2d-vue2/src/components/Meta2d.vue',
+    '/view/meta2d-vue2/src/App.vue',
+    '/view/meta2d-vue2/src/main.js',
+    // '/view/meta2d-vue2/src/style.css',
+    '/view/meta2d-vue2/public/index.html',
+    '/view/meta2d-vue2/package.json',
+    '/view/meta2d-vue2/README.md',
+    // '/view/meta2d-vue3/vite.config.js',
+  ] as const;
+  // 文件同时加载
+  await Promise.all(files.map((filePath) => zipFile(zip, filePath)));
+}
+
+async function zipReactFiles(zip: JSZip) {
+  const files = [
+    '/view/meta2d-react/src/index.css',
+    '/view/meta2d-react/src/index.js',
+    '/view/meta2d-react/src/Meta2d.css',
+    '/view/meta2d-react/src/Meta2d.jsx',
+    '/view/meta2d-react/package.json',
+    '/view/meta2d-react/README.md',
+    '/view/meta2d-react/public/index.html',
+  ] as const;
+  // 文件同时加载
+  await Promise.all(files.map((filePath) => zipFile(zip, filePath)));
+}
+
+async function zipFile(zip: JSZip, filePath: string) {
+  const res: Blob = await axios.get(
+    (cdn ? cdn + '/v' : import.meta.env.BASE_URL.slice(0, -1)) + filePath,
+    {
+      responseType: 'blob',
+    }
+  );
+  zip.file(filePath.replace('/view', ''), res, { createFolders: true });
+}

+ 6 - 5
src/views/Preview.vue

@@ -13,7 +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, getPayList } from '@/services/download';
+import { getDownloadList, getPayList, preFrameDownload, Frame} from '@/services/download';
 const route = useRoute();
 
 const meta2dDom = ref('');
@@ -40,7 +40,8 @@ onMounted(() => {
 });
 
 const dealWithMessage = (e) => {
-  if (typeof e.data !== 'string') {
+  if (typeof e.data !== 'string'||!e.data ||
+    e.data.startsWith('setImmediate')) {
     return;
   }
   try {
@@ -53,11 +54,11 @@ const dealWithMessage = (e) => {
         } else if (data.name === 'prePayList') {
           doGetPayList();
         } else if (data.name === 'downloadVue3') {
-
+          preFrameDownload(Frame.vue3);
         } else if (data.name === 'downloadVue2') {
-
+          preFrameDownload(Frame.vue2);
         } else if (data.name === 'downloadReact') {
-
+          preFrameDownload(Frame.react);
         }
       } else {
         meta2d.emit(data.name);

Diferenças do arquivo suprimidas por serem muito extensas
+ 567 - 462
src/views/components/Header.vue


Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff