|
@@ -1,8 +1,14 @@
|
|
import { cdn, upCdn } from '@/services/api';
|
|
import { cdn, upCdn } from '@/services/api';
|
|
import { checkData } from '@/services/utils';
|
|
import { checkData } from '@/services/utils';
|
|
import axios from 'axios';
|
|
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_cdn = 'https://assets.le5lecdn.com';
|
|
export const img_upCdn = 'https://drive.le5lecdn.com';
|
|
export const img_upCdn = 'https://drive.le5lecdn.com';
|
|
|
|
+const { user, signout } = useUser();
|
|
|
|
|
|
const components = [
|
|
const components = [
|
|
'inputDom',
|
|
'inputDom',
|
|
@@ -256,7 +262,7 @@ export const getComponentPurchased = async (list: any) => {
|
|
return res.list;
|
|
return res.list;
|
|
};
|
|
};
|
|
|
|
|
|
-export const get2dComponentJs = async (names: string[]=components) => {
|
|
|
|
|
|
+export const get2dComponentJs = async (names: string[] = components) => {
|
|
let list = [];
|
|
let list = [];
|
|
names.forEach((item) => {
|
|
names.forEach((item) => {
|
|
list.push({
|
|
list.push({
|
|
@@ -289,3 +295,339 @@ export const getGoods = async () => {
|
|
return res;
|
|
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 });
|
|
|
|
+}
|