import { reactive, ref } from 'vue'; import { addCollection, updateCollection, getCollection, cdn } from './api'; import { getPayList, getDownloadList, Frame, get2dComponentJs, getTemPngs, // getDeployPngs, img_cdn, img_upCdn, getFrameDownloadList, getComponentPurchased, getGoods, // getDeployAccess, } from './download'; import { rootDomain } from './defaults'; import { newFile, queryURLParams } from './common'; import axios from 'axios'; import { MessagePlugin } from 'tdesign-vue-next'; import { useUser } from '@/services/user'; import { getResource } from './handle3d'; import { s8 } from './random'; import { load3d } from './load3d'; import router from '@/router'; import { noLoginTip } from './utils'; import localforage from 'localforage'; export const activedGroup = ref(''); export const activeAssets = ref('system'); const { user } = useUser(); const isVip = () => { if (!(user && user.id)) { MessagePlugin.warning(noLoginTip); return; } if (!user.vip) { MessagePlugin.info('需要开通会员~'); return; } return true; }; const taskDialog = reactive({ visible: false, tasks: [], cancel: false, reload: false, downloadList: [], }); export const useTask = () => { const setTask = (key, value) => { taskDialog[key] = value; }; return { taskDialog, setTask, }; }; export const reDownload = async () => { taskDialog.tasks[1].status = 'process'; taskDialog.reload = false; let result = await saveZip(taskDialog.downloadList); if (result === 'error') { taskDialog.tasks[1].status = 'error'; taskDialog.reload = true; return; } taskDialog.tasks[1].status = 'success'; MessagePlugin.closeAll(); taskDialog.tasks[2].status = 'success'; MessagePlugin.success('下载成功,请在浏览器下载列表中查看'); taskDialog.visible = false; }; const payDialog = reactive({ visible: false, data: { price: 0, list: [], hasJs: false, checked: true, }, token: false, }); export const usePay = () => { const setPay = (key, value) => { payDialog[key] = value; }; return { payDialog, setPay, }; }; const prePay = async () => { if (user.vipData?.deployment) { //可视化会员 if ((user.vipData.deployment & 128) === 128) { //直接下载 payDialog.token = true; doDownloadProjectSource(); return; } } //TODO 付费 let purchased = await getComponentPurchased({ pngs: [...prePayList.pngs], jsPens: [], iotPens: [], svgPens: [], }); if ( [...prePayList.jsPens].length || [...prePayList.iotPens].length || [...prePayList.svgPens].length ) { payDialog.data.hasJs = true; } else { payDialog.data.hasJs = false; } let names = purchased.map((item) => item.name); let goods = await getGoods(); let list = [...prePayList.pngs].filter((item) => !names.includes(item)); if (!list.length) { //直接下载 doDownloadProjectSource(); } else { let unitPrice = goods.find((item) => item.type === '图片图元').unitPrice; payDialog.data.price = unitPrice * list.length; payDialog.data.checked = true; payDialog.visible = true; payDialog.data.list = list; } }; export const payProjectDialog = reactive({ visible: false, data: { price: 0, payAll: false, list: [], title: '', checked: true, payList: [], }, token: '', }); /* const prePayProject = async () => { if (user.vipData?.deployment) { //可视化会员 if ((user.vipData.deployment & 128) === 128) { //直接下载 payDialog.token = true; doDownloadProject(); return; } } const result: { token?: string; vip?: boolean; error?: string; deployment?: any; } = await getDeployAccess( Object.keys(page3dDatas).length ? '3d,v' : 'v', prePayList ); if (result.vip) { if (result.token) { payProjectDialog.token = result.token; doDownloadProject(); return; } } //图形库 let _goods = await getGoods(); let purchasedList = await getComponentPurchased(prePayList); payProjectDialog.data.list = []; // return; payProjectDialog.data.payAll = false; // _goods.forEach((goods)=>{ for (let i = 0; i < _goods.length; i++) { let goods = _goods[i]; let purchased = purchasedList?.filter((_item) => _item.type === goods.type); let names = purchased.map((item) => item.name); let list = []; if (goods.type === '图片图元') { list = [...prePayList.pngs]; } else if (goods.type === 'JS线性图元') { list = [...prePayList.jsPens]; } else if (goods.type === 'SVG线性图元') { list = [...prePayList.svgPens]; } else if (goods.type === '控件') { list = [...prePayList.iotPens]; } let num = 0; if (goods.type === 'SVG线性图元' && [...prePayList.svgPens].includes('*')) { //需要购买全部 num = goods.count - names.length; payProjectDialog.data.payAll = true; } else { // list.forEach((item)=>{ for (let j = 0; j < list.length; j++) { let item = list[j]; if (!names.includes(item)) { if (goods.type === '控件') { payProjectDialog.data.list.push({ name: item, }); } else if (goods.type === 'JS线性图元') { payProjectDialog.data.list.push({ svg: globalThis.jsPensMap ? globalThis.jsPensMap[item] : item, }); } else { payProjectDialog.data.list.push({ img: item, }); } num += 1; } } } goods.num = num; } let price = 0; for (let i = 0; i < _goods.length; i++) { price += _goods[i].num * _goods[i].unitPrice; } payProjectDialog.data.price = price; let payList = []; let names = purchasedList.map((item) => item.name); prePayList.pngs.forEach((item) => { if (!names.includes(item)) { payList.push({ type: '图片图元', name: item, }); } }); prePayList.jsPens.forEach((item) => { if (!names.includes(item)) { payList.push({ type: 'JS线性图元', name: item, }); } }); prePayList.iotPens.forEach((item) => { if (!names.includes(item)) { payList.push({ type: '控件', name: item, }); } }); if ([...prePayList.svgPens].includes('*')) { payList.push({ type: 'SVG线性图元', }); } else { prePayList.svgPens.forEach((item) => { if (!names.includes(item)) { payList.push({ type: 'SVG线性图元', name: item, }); } }); } payProjectDialog.data.checked = true; payProjectDialog.data.payList = payList; switch (downloadType) { case Frame.html: payProjectDialog.data.title = '下载离线部署包'; break; case Frame.vue2: payProjectDialog.data.title = '下载vue2组件包'; break; case Frame.vue3: payProjectDialog.data.title = '下载vue3组件包'; break; case Frame.react: payProjectDialog.data.title = '下载react组件包'; break; } if (payProjectDialog.data.price === 0) { doDownloadProject(); } else { payProjectDialog.visible = true; } };*/ const data = reactive({ id: undefined, tree: [ // { // value: '1', // label: '文件夹1', // children: [ // { // value: '11', // label: '页面1', // type: 'page', // pageId: '1', // pageType: '', //v/2d/3d // tag: '首页', // }, // ], // }, // { // value: '2', // label: '文件夹2', // children: [ // { // value: '21', // label: '页面1', // type: 'page', // }, // { // value: '22', // label: '页面1', // type: 'page', // }, // ], // }, ], actived: [], }); export const graphicsRef = ref(null); const tree = ref(); const activeNode = ref(null); let activePage = null; //新建工程 export const newProject = () => { //新建页面 newFile(); //新建工程 data.tree = [ { value: s8(), label: '文件夹', children: [ { value: s8(), label: '页面', type: 'page', pageType: '', //v/2d/3d }, ], }, ]; data.id = undefined; //展示工程 activeAssets.value = 'structure'; graphicsRef.value.assetsChange(activeAssets.value); activedGroup.value = '工程'; }; const getHomePage = (treeData) => { for (let i = 0; i < treeData.length; i++) { if (treeData[i].type === 'page' && treeData[i].tag === '首页') { return treeData[i]; } if (treeData[i].children) { const page = getHomePage(treeData[i].children); if (page) { return page; } } } }; export const loadProject = () => { if (!isVip()) { return; } const input = document.createElement('input'); input.type = 'file'; input.onchange = async (event) => { const elem = event.target as HTMLInputElement; if (elem.files && elem.files[0]) { // 路由跳转 可能在 openFile 后执行 if (elem.files[0].name.endsWith('.zip')) { let projectData = await uploadProjectSource(elem.files[0]); if (projectData) { let home = getHomePage(projectData.data); if (!home) { home = projectData.data[0].children?.length ? projectData.data[0].children[0] : projectData.data[0]; } router.push({ path: '/', query: { r: Date.now() + '', id: home.pageId, }, }); } //获取首页 if (activedGroup.value !== '工程') { activeAssets.value = 'structure'; graphicsRef.value.assetsChange(activeAssets.value); activedGroup.value = '工程'; } } else { MessagePlugin.info('打开工程文件只支持 zip 格式'); } } }; input.click(); }; export const useProject = () => { const getProject = async (id: string) => { if (id === data.id) { setActive(meta2d.store.data.id); return; } const ret: any = await getCollection('web', id); data.tree = ret.data; data.id = ret.id; setActive(meta2d.store.data.id); }; const setActive = (pageId) => { const find = (treeData) => { for (let i = 0; i < treeData.length; i++) { if (treeData[i].pageId === pageId) { data.actived = [treeData[i].value]; return; } if (treeData[i].children) { find(treeData[i].children); } } }; find(data.tree); }; const setProject = async (data) => {}; const saveProject = async (id?: string, over?: boolean) => { if (!data.tree.length) { //无数据 return; } if (!activeNode.value && !over) { return; } if (id) { if (!tree.value) { // let activePage = getLeaf(activeNode.value.data.value,data.tree); setData(data.tree, activeNode.value.data.value, 'pageId', id); // activePage.pageId = id; } else { await activeNode.value.setData({ pageId: id }); } setData(data.tree, activeNode.value.data.value, 'pageId', id); } // return const treeData = (await tree?.value?.getTreeData?.()) || data.tree; if (!(treeData && treeData.length > 0)) { return; } const _data = { id: data.id, data: treeData, name: 'test', image: '', }; // if(data.id&&!id){ // // 已经有工程 没有 不需要更新数据 // return data.id; // } if (data.id) { await updateCollection('web', _data); return data.id; } else { const ret: any = await addCollection('web', _data); data.id = ret.id; return ret.id; } }; const clearProject = () => { data.id = undefined; data.tree = []; }; const setActivedNode = (node) => { activeNode.value = node; // if(!data.tree){ // } // activePage = getLeaf(node.data.value,data.tree); }; return { data, tree, activePage, activeNode, saveProject, getProject, setProject, clearProject, setActivedNode, }; }; const getLeaf = (id, arr: any) => { arr.forEach((item) => { if (item.children) { getLeaf(id, item.children); } else { if (item.value === id) { return item; } } }); }; const setData = (arr: any, id, key, value) => { arr.forEach((item) => { if (item.children) { setData(item.children, id, key, value); } else { if (item.value === id) { item[key] = value; } } }); }; let downloadType: Frame = Frame.html; let pageDatas = {}; let page3dDatas = {}; let page2dDatas = {}; const setDownloadType = (type: Frame) => { downloadType = type; }; const prePayList = reactive({ pngs: new Set(), jsPens: new Set(), iotPens: new Set(), svgPens: new Set(), }); let downloadList = []; const isV = (url) => { return ( url.indexOf(`v${rootDomain}`) !== -1 || url.indexOf(`view${rootDomain}/v`) !== -1 || url.indexOf(`/view/v`) !== -1 || url.indexOf(`/preview`) !== -1 ); }; const is3D = (url) => { return ( url.indexOf(`3d${rootDomain}`) !== -1 || url.indexOf(`view${rootDomain}/3d`) !== -1 || url.indexOf(`/view/3d`) !== -1 ); }; const is2D = (url) => { return ( url.indexOf(`2d${rootDomain}`) !== -1 || url.indexOf(`view${rootDomain}/2d`) !== -1 || url.indexOf(`/view/2d`) !== -1 ); }; const getPageDataByUrl = async (url) => { let id = queryURLParams(url.split('?')[1])?.id; if (isV(url)) { if (!pageDatas[id]) { let data = await getCollection('v', id); pageDatas[id] = data.data; } //TODO 更改图纸中的iframe地址 if (downloadType === Frame.html) { return `/view?data=${id}`; //`/view/v?data=${id}` } else { return `/2d?id=${id}`; } } else if (is3D(url)) { if (!page3dDatas[id]) { let data = await getCollection('3d', id); page3dDatas[id] = data.data; } if (downloadType === Frame.html) { return `/view?data=${id}`; //`/view/v?data=${id}` } else { return `/view/index.html?data=${id}`; } } else if (is2D(url)) { if (!page2dDatas[id]) { let data = await getCollection('2d', id); page2dDatas[id] = data.data; } if (downloadType === Frame.html) { return `/view?data=${id}`; //`/view/v?data=${id}` } else { return `/2d?id=${id}`; } } }; //获取工程包含的所有数据内容 /** * * @param replace 是否替换地址 */ const getDatas = async (replace = true) => { const list = treeToList(data.tree).filter((item) => item.type && item.pageId); pageDatas = {}; page3dDatas = {}; page2dDatas = {}; await Promise.all( list.map(async (item: any) => { let v = await getCollection('v', item.pageId); pageDatas[item.pageId] = v.data; if (v.data?.pens?.length) { // 内嵌iframe网页 const pens = v.data.pens.filter( (pen) => pen.name === 'iframe' && (isV(pen.iframe) || is3D(pen.iframe) || is2D(pen.iframe)) ); for (let i = 0; i < pens.length; i++) { let pen = pens[i]; let iframe = await getPageDataByUrl(pen.iframe); if (replace) { pen.iframe = iframe; } } for (let i = 0; i < v.data.pens.length; i++) { let pen = v.data.pens[i]; if (pen.events?.length) { for (let j = 0; j < pen.events.length; j++) { //打开弹框 const actions = pen.events[j].actions; //.filter((action)=>action.action === 14); for (let k = 0; k < actions.length; k++) { let action = actions[k]; if (action.action === 14) { //打开弹框 let iframe = await getPageDataByUrl(action.params); if (replace) { action.params = iframe; } } else if (action.action === 1) { //更改iframe属性 if (action.value?.iframe) { let iframe = await getPageDataByUrl(action.value.iframe); if (replace) { action.value.iframe = iframe; } } } } } } if (pen.triggers?.length) { for (let j = 0; j < pen.triggers.length; j++) { const trigger = pen.triggers[j]; for (let k = 0; k < trigger.status.length; k++) { let status = trigger.status[k]; for (let l = 0; l < status.actions.length; l++) { let action = status.actions[l]; if (action.action === 14) { //打开弹框 // action.params = await getPageDataByUrl(action.params); let iframe = await getPageDataByUrl(action.params); if (replace) { action.params = iframe; } } else if (action.action === 1) { //更改iframe属性 if (action.value?.iframe) { // action.value.iframe = await getPageDataByUrl(action.value.iframe); let iframe = await getPageDataByUrl(action.value.iframe); if (replace) { action.value.iframe = iframe; } } } } } } } } } }) ); }; const getEnterprisePens = async () => { let pngs = [], jsPens = [], iotPens = [], svgPens = []; for (let key in pageDatas) { const pageData = pageDatas[key]; const payList = getPayList(pageData); pngs.push(...payList.pngs); jsPens.push(...payList.jsPens); iotPens.push(...payList.iotPens); svgPens.push(...payList.svgPens); } for (let key in page2dDatas) { const pageData = page2dDatas[key]; const payList = getPayList(pageData); pngs.push(...payList.pngs); jsPens.push(...payList.jsPens); iotPens.push(...payList.iotPens); svgPens.push(...payList.svgPens); } prePayList.pngs = new Set(pngs); prePayList.jsPens = new Set(jsPens); prePayList.iotPens = new Set(iotPens); prePayList.svgPens = new Set(svgPens); }; // 下载工程 export const downloadProject = async (type: Frame) => { // if (!isVip()) { // return; // } downloadType = type; //通过工程获取所有的页面数据 ,包括2d 3d v await getDatas(); // if (isDownload) { //安装包 await doDownloadProject(); return; // } //获取 2d 大屏企业图形库 // await getEnterprisePens(); // await prePayProject(); }; export const doDownloadProject = async () => { //TODO 验证付费图形库 taskDialog.visible = true; taskDialog.tasks = [ { status: 'prepare', title: '获取工程数据资源', }, { status: 'prepare', title: '下载工程资源', }, { status: 'prepare', title: '完成', }, ]; taskDialog.tasks[0].status = 'process'; let dList = []; let flag_3d = false; if (downloadType === Frame.html) { for (let key in pageDatas) { pageDatas[key].userId = user.id; dList.push(...(await getDownloadList(pageDatas[key], key, false))); } for (let key in page2dDatas) { page2dDatas[key].userId = user.id; dList.push(...(await getDownloadList(page2dDatas[key], key, false))); } for (let key in page3dDatas) { flag_3d = true; let source3dList = await getResource( page3dDatas[key].data, key, 'deploy' ); dList.push(...source3dList); } //下载运行环境文件 dList.push(...getDownloadList(undefined, 'v', flag_3d)); } else { for (let key in pageDatas) { pageDatas[key].userId = user.id; dList.push( ...(await getFrameDownloadList( pageDatas[key], key, downloadType, false )) ); } for (let key in page2dDatas) { page2dDatas[key].userId = user.id; dList.push( ...(await getFrameDownloadList( page2dDatas[key], key, downloadType, false )) ); } for (let key in page3dDatas) { flag_3d = true; let source3dList = await getResource( page3dDatas[key].data, key, 'deploy' ); dList.push(...source3dList); } //下载运行环境文件 dList.push(...getFrameDownloadList(undefined, 'v', downloadType, flag_3d)); } taskDialog.tasks[0].status = 'success'; taskDialog.tasks[1].status = 'process'; downloadList = uniqueObjArrayFast(dList, 'path'); //下载列表 let result = await saveDownload(downloadList); if (!result) { return; } taskDialog.tasks[1].status = 'success'; taskDialog.tasks[2].status = 'process'; taskDialog.visible = false; }; const saveDownload = async (downloadList) => { const list = [...downloadList]; //控件 let jsPath = ''; let jsPensPath = ''; switch (downloadType) { case Frame.html: jsPath = '/view/js/2d-components.js'; jsPensPath = `/view/js/1.js`; break; case Frame.vue2: jsPath = '/meta2d-vue2/public/js/2d-components.js'; jsPensPath = `/meta2d-vue2/public/js/1.js`; break; case Frame.vue3: jsPath = '/meta2d-vue3/public/js/2d-components.js'; jsPensPath = `/meta2d-vue3/public/js/1.js`; break; case Frame.react: jsPath = '/meta2d-react/public/js/2d-components.js'; jsPensPath = `/meta2d-react/public/js/1.js`; break; } // if (isDownload) { // 安装包 list.push({ url: '/view/js/2d-components.js', //需要购买 path: jsPath, }); /* } else { const js = await get2dComponentJs([...prePayList.iotPens]); list.push({ data: js, path: jsPath, }); ///png图形库 let pngs: any = {}; //TODO token let token = ''; if (token) { pngs = await getDeployPngs([...prePayList.pngs], token); } else { pngs = await getTemPngs([...prePayList.pngs]); } list.forEach((item) => { if (item.url) { let url = item.url.replace(img_cdn, '').replace(img_upCdn, ''); if (pngs[url]) { item.url = pngs[url]; } } }); //js线性图元 let arr = []; if (token) { arr = [...prePayList.jsPens]; } else { const res: any = await axios.post( '/api/paid/2d/component?pageSize=1000', { type: 'JS线性图元', collection: 'v', id: meta2d.store.data.id, } ); let purchased = []; if (res?.list && res.list.length) { purchased = res.list.map((item) => item.name); } [...prePayList.jsPens].forEach((item) => { if (purchased.includes(item)) { arr.push(item); } }); } const res_list: any = await axios.post('/api/2d/tools', { list: arr.map((item) => { return { type: 'JS线性图元', name: item, }; }), }); const json = `!window.meta2dToolId&&(window.meta2dToolId="${res_list?.id}");var tmpTools=` + JSON.stringify(res_list?.list) + `;!window.meta2dTools&&(window.meta2dTools=[]);window.meta2dTools.push.apply(window.meta2dTools,tmpTools);`; list.push({ data: json, path: jsPensPath, }); //SVG线性图元 if ([...prePayList.svgPens].length) { // let purchased = data.purchasedList?.filter( // (_item) => _item.type === 'SVG线性图元' // ); let purchased = []; if (!token) { const res: any = await axios.post( '/api/paid/2d/component?pageSize=1000', { type: 'SVG线性图元', collection: 'v', id: meta2d.store.data.id, } ); purchased = res?.list || []; } //TODO let count = 0; // data.goods.find((item) => item.type === 'SVG线性图元')?.count; if (purchased.length === count || token) { // if (purchased.length === 1 && !purchased[0].name) { //已经购买全部 list.forEach((item) => { if ( item.data && (item.path.indexOf('/projects/2d') !== -1 || item.path.indexOf('/projects/v') !== -1 || item.path.indexOf('/public/json') !== -1) && item.path.indexOf('/projects/v/png/') === -1 && item.path.indexOf('/projects/2d/png/') === -1 ) { //清空所有svgpath let meta2dData = JSON.parse(item.data); for (let key of Object.keys(meta2dData.paths)) { let path = meta2dData.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 ) { meta2dData.paths[key] = ''; } } item.data = JSON.stringify(meta2dData); } }); } else { let svgnames = purchased.map((i) => i.name); list.forEach((item) => { if ( item.data && (item.path.indexOf('/projects/2d') !== -1 || item.path.indexOf('/projects/v') !== -1 || item.path.indexOf('/public/json') !== -1) && item.path.indexOf('/projects/v/png/') === -1 && item.path.indexOf('/projects/2d/png/') === -1 ) { //2d 图纸数据 let meta2dData = JSON.parse(item.data); meta2dData.pens.forEach((pen) => { if (pen.name === 'svgPath' && pen.svgUrl) { if (svgnames.includes(pen.svgUrl.replace(img_cdn, ''))) { pen.pathId = null; } } }); item.data = JSON.stringify(meta2dData); } }); } } }*/ //开始下载list let result = await saveZip(list); if (result === 'error') { taskDialog.tasks[1].status = 'error'; taskDialog.reload = true; taskDialog.downloadList = list; return false; } MessagePlugin.closeAll(); MessagePlugin.success('下载成功,请在浏览器下载列表中查看'); return true; }; const saveZip = async (list: any[], fileName: string = '工程下载') => { //开始下载list const [{ default: JSZip }, { saveAs }] = await Promise.all([ import('jszip'), import('file-saver'), ]); const zip = new JSZip(); const _zip = zip.folder(`${fileName}`); const results = await Promise.all( list.map(async (item: any) => { if (item.url) { //接口请求 try { let url = item.url.startsWith('/') ? cdn + item.url : item.url; if (url.indexOf('/view/index.html') !== -1) { url = url.replace('/view/index.html', '/v/view/index.html'); //线上不包含cdn的inde.html } if (url.includes('?')) { url = url + `&r=${Date.now()}`; } else { url = url + `?r=${Date.now()}`; } let res: Blob = null; let localBlob: any = await localforage.getItem(item.path); if (localBlob) { res = localBlob; } else { res = await axios.get(url, { responseType: 'blob', }); } if (!res) { throw new Error('请求失败'); } localforage.setItem(item.path, res); //缓存 let path = item.path.split('?')[0]; if (path.startsWith('/')) { path = path.slice(1); } _zip.file(path, res, { createFolders: true }); } catch (error) { return { error: error.message,url: item.url}; // 返回错误信息 } } else if (item.data) { //直接写数据 let path = item.path; if (path.startsWith('/')) { path = path.slice(1); } _zip.file(path, item.data, { createFolders: true }); } }) ); console.log("results",results); let errorLen = results.map((item) => item && item.error); // if (errorLen.length > 5) { // MessagePlugin.error('下载失败,请确保网络畅通'); // return 'error'; // } //清除本地存储 list.forEach((item) => { localforage.removeItem(item.path); }); const blob = await zip.generateAsync({ type: 'blob' }); saveAs(blob, `${fileName}.zip`); }; //遍历树 const treeToList = (tree) => { const list = []; for (let i = 0; i < tree.length; i++) { const item = tree[i]; list.push(item); if (item.children) { list.push(...treeToList(item.children)); } } return list; }; //下载zip资源 export const downloadProjectSource = async () => { // if (!isVip()) { // return; //非vip用户不能下载 // } await getDatas(false); // if (isDownload) { //安装包 await doDownloadProjectSource(); // return; // } // await getEnterprisePens(); //获取企业图库 // await prePay(); }; export const doDownloadProjectSource = async () => { // prePayList.pngs.forEach taskDialog.reload = false; taskDialog.visible = true; taskDialog.tasks = [ { status: 'prepare', title: '获取工程数据资源', }, { status: 'prepare', title: '下载资源', }, { status: 'prepare', title: '完成', }, ]; taskDialog.tasks[0].status = 'process'; let dList = []; let imgList = []; for (let key in pageDatas) { imgList.push(...(await getImgList(pageDatas[key]))); } for (let key in page2dDatas) { imgList.push(...(await getImgList(page2dDatas[key]))); } imgList = uniqueObjArrayFast(imgList, 'path'); //获取去水印企业图库 /*if ([...prePayList.pngs].length && !isDownload) { let pngs: any = {}; if (payDialog.token) { pngs = await getDeployPngs( [...prePayList.pngs], undefined ); } else { pngs = await getTemPngs([...prePayList.pngs]); } if (!pngs) { pngs = {}; } imgList.forEach((item) => { if (item.url) { let url = item.url.replace(img_cdn, '').replace(img_upCdn, ''); if (pngs[url]) { item.url = pngs[url]; } } }); }*/ dList.push(...imgList); for (let key in pageDatas) { dList.push({ data: JSON.stringify(pageDatas[key]), path: `${key}.json`, }); } for (let key in page2dDatas) { dList.push({ data: JSON.stringify(page2dDatas[key]), path: `${key}.json`, }); } //TODO 获取zip包的内容 for (let key in page3dDatas) { let source3dList = await getResource( page3dDatas[key].data, '3d-' + key, 'deployAsZip' ); dList.push(...source3dList); } dList.push({ data: JSON.stringify(data.tree), path: 'project.json', }); dList = uniqueObjArrayFast(dList, 'path'); //去重 taskDialog.tasks[0].status = 'success'; taskDialog.tasks[1].status = 'process'; //下载 //开始下载list let result = await saveZip(dList); if (result === 'error') { taskDialog.tasks[1].status = 'error'; taskDialog.reload = true; taskDialog.downloadList = dList; return; } taskDialog.tasks[1].status = 'success'; MessagePlugin.closeAll(); taskDialog.tasks[2].status = 'success'; MessagePlugin.success('下载成功,请在浏览器下载列表中查看'); taskDialog.visible = false; }; //TODO 任务取消 是否需要删除已经上传的内容 export const uploadProjectSource = async (file) => { taskDialog.visible = true; taskDialog.tasks = [ { status: 'prepare', title: '解析ZIP文件', }, { status: 'prepare', title: '上传资源文件', }, { status: 'prepare', title: '生成项目', }, { status: 'prepare', title: '完成', }, ]; // return; //TODO 上传zip包 const { default: JSZip } = await import('jszip'); const zip = new JSZip(); await zip.loadAsync(file, { base64: true }); taskDialog.tasks[0].status = 'success'; taskDialog.tasks[1].status = 'process'; let fileName = file.name.slice(0, -4); let treeData = ''; for (const key in zip.files) { if (zip.files[key].dir) { fileName = key.split('/')[0]; // 取第一个文件夹名称 continue; } if (key.endsWith('project.json')) { // 工程json 文件 treeData = await zip.file(key).async('string'); break; } } if (!treeData) { MessagePlugin.error('这不是一个工程包,请重新选择'); return false; } const imgMap = {}; //新老图纸映射 const _2dDataMap = {}; //2d数据映射 const _3dIDMap = {}; //3d id映射 const _2dIDMap = {}; //2d id映射 //上传所有图片资源 for (const key in zip.files) { if (taskDialog.cancel) { return; } if (zip.files[key].dir) { continue; } let _keyLower = key.toLowerCase(); if ( _keyLower.endsWith('.png') || _keyLower.endsWith('.svg') || _keyLower.endsWith('.gif') || _keyLower.endsWith('.jpg') || _keyLower.endsWith('.jpeg') ) { let _filename = key.substr(key.lastIndexOf('/') + 1); const form = new FormData(); form.append('name', _filename); form.append('directory', '/大屏/图片/默认'); form.append('shared', true + ''); form.append('file', await zip.file(key).async('blob')); form.append('conflict', 'new'); const result: any = await axios.post('/api/image/upload', form); let arr = key.split('/'); // arr.shift(); if (arr[0] === fileName) { arr.shift(); } if (arr[0] === fileName) { arr.shift(); } let _key = '/' + arr.join('/'); if (result) { imgMap[_key] = result.url; } } else if (_keyLower.endsWith('.json')) { let arr = key.split('/'); if (arr[0] === fileName) { arr.shift(); } if (arr[0] === fileName) { arr.shift(); } let data = await zip.file(key).async('string'); let id = arr[0].split('.')[0]; // if(!arr[0].endsWith('.json')){ if (!key.endsWith('project.json')) { _2dDataMap[id] = data; } // } } else { //TODO 多个3d场景问题 if (key.indexOf('3d') !== -1 && key.indexOf('files/') === -1) { let id_3d = await load3d(zip, key); if (id_3d) { let originId = key.split('3d-')[1]; _3dIDMap[originId] = id_3d; } } } } taskDialog.tasks[1].status = 'success'; taskDialog.tasks[2].status = 'process'; if (taskDialog.cancel) { return; } //将 图纸里面的地址替换成最新的地址 for (let old in imgMap) { let newImg = imgMap[old]; for (let key in _2dDataMap) { _2dDataMap[key] = _2dDataMap[key].replaceAll(old, newImg); } } //上传所有图纸 //生成 老图纸和新图纸对应的map let arr = Object.keys(_2dDataMap); // for(let key in _2dDataMap){ for (let i = 0; i < arr.length; i++) { if (taskDialog.cancel) { return; } let idata = JSON.parse(_2dDataMap[arr[i]]); const ret: any = await addCollection('v', { data: idata, image: idata.image || 'xxx', name: idata.name || '新建项目', folder: idata.folder, system: false, case: idata.case, }); _2dIDMap[arr[i]] = ret.id; } treeData = JSON.parse(treeData); arr = treeToList(treeData) .filter((item) => item.pageId) .map((item) => item.pageId); deepUpdateID(treeData, _2dIDMap); //上传 生成的新的工程树 const projectData = { id: data.id, data: treeData, name: 'test', image: '', }; const ret: any = await addCollection('web', projectData); const projectId = ret.id; //更新图纸里面工程树id内容 // for(let key in _2dDataMap){ for (let i = 0; i < arr.length; i++) { if (taskDialog.cancel) { return; } let idata = await update2dData(_2dDataMap[arr[i]], _2dIDMap, _3dIDMap); const ret: any = await updateCollection('v', { data: idata, id: _2dIDMap[arr[i]], otherData: { projectId }, }); _2dIDMap[arr[i]] = ret.id; } taskDialog.tasks[2].status = 'success'; taskDialog.tasks[3].status = 'process'; taskDialog.tasks[3].status = 'success'; taskDialog.visible = false; return ret; }; //将工程树里面的图纸id替换成新的id const deepUpdateID = (treeData, _2dIDMap) => { treeData.forEach((item) => { if (item.children) { deepUpdateID(item.children, _2dIDMap); } else { if (item.type === 'page') { item.pageId = _2dIDMap[item.pageId]; } } }); }; const update2dData = async (_data, _2dIDMap, _3dIDMap) => { let domain = 'https://view.le5le.com'; // if (isDownload || location.origin.indexOf('le5le.com') === -1) { domain = location.origin + '/view'; // } let data = JSON.parse(_data); if (data.pens?.length) { // 内嵌iframe网页 const pens = data.pens.filter( (pen) => pen.name === 'iframe' && (isV(pen.iframe) || is3D(pen.iframe) || is2D(pen.iframe)) ); for (let i = 0; i < pens.length; i++) { let pen = pens[i]; let id = queryURLParams(pen.iframe.split('?')[1])?.id; if (is3D(pen.iframe)) { pen.iframe = `${domain}/3d/?id=${_3dIDMap[id]}`; } else { pen.iframe = `${domain}/v/?id=${_2dIDMap[id]}`; } } for (let i = 0; i < data.pens.length; i++) { let pen = data.pens[i]; if (pen.events?.length) { for (let j = 0; j < pen.events.length; j++) { //打开弹框 const actions = pen.events[j].actions; for (let k = 0; k < actions.length; k++) { let action = actions[k]; if (action.action === 14) { //打开弹框 if ( is2D(action.params) || is3D(action.params) || isV(action.params) ) { let id = queryURLParams(action.params.split('?')[1])?.id; action.params = `${domain}/v/?id=${_2dIDMap[id]}`; } } else if (action.action === 1) { //更改iframe属性 if (action.value?.iframe) { if (is2D(action.value.iframe) || isV(action.value.iframe)) { let id = queryURLParams( action.value.iframe.split('?')[1] )?.id; action.value.iframe = `${domain}/v/?id=${_2dIDMap[id]}`; } else if (is3D(action.value.iframe)) { let id = queryURLParams( action.value.iframe.split('?')[1] )?.id; action.value.iframe = `${domain}/3d/?id=${_3dIDMap[id]}`; } } } else if (action.action === 13) { //打开视图 action.value = _2dIDMap[action.value]; } } } } if (pen.triggers?.length) { for (let j = 0; j < pen.triggers.length; j++) { const trigger = pen.triggers[j]; for (let k = 0; k < trigger.status.length; k++) { let status = trigger.status[k]; for (let l = 0; l < status.actions.length; l++) { let action = status.actions[l]; if (action.action === 14) { //打开弹框 if ( is2D(action.params) || is3D(action.params) || isV(action.params) ) { let id = queryURLParams(action.params.split('?')[1])?.id; action.params = `${domain}/v/?id=${_2dIDMap[id]}`; } } else if (action.action === 1) { //更改iframe属性 if (action.value?.iframe) { if (is2D(action.value.iframe) || isV(action.value.iframe)) { let id = queryURLParams( action.value.iframe.split('?')[1] )?.id; action.value.iframe = `${domain}/v/?id=${_2dIDMap[id]}`; } else if (is3D(action.value.iframe)) { let id = queryURLParams( action.value.iframe.split('?')[1] )?.id; action.value.iframe = `${domain}/3d/?id=${_3dIDMap[id]}`; } } } else if (action.action === 13) { //打开视图 action.value = _2dIDMap[action.value]; } } } } } } } return data; }; //去重 function uniqueObjArrayFast(arr, key) { const seen = {}; return arr.filter((item) => { const val = item[key]; return seen.hasOwnProperty(val) ? false : (seen[val] = true); }); } const uploadProject = async (file) => {}; const getImgList = async (meta2dData) => { let lists = []; let img = meta2dData.bkImage; if (img) { if ( img.startsWith('/') || img.startsWith(img_cdn) || img.startsWith(img_upCdn) ) { let _img = img.replace(img_cdn, '').replace(img_upCdn, ''); if (_img.startsWith('/v/')) { _img = _img.slice(2); } _img = decodeURIComponent(_img); lists.push({ url: img, path: _img, }); meta2dData.bkImage = _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(img_cdn) || image.startsWith(img_upCdn) ) { // 只考虑相对路径下的 image ,绝对路径图片无需下载 let _img = image.replace(img_cdn, '').replace(img_upCdn, ''); if (_img.startsWith('/v/')) { _img = _img.slice(2); } _img = decodeURIComponent(_img); if (!images.includes(image)) { // let _img = image.replace(cdn, '').replace(upCdn, ''); lists.push({ url: image, path: _img, }); } pen[i] = _img; } } } pen.events?.forEach((event) => { if (event.actions?.length) { event.actions.forEach((action) => { if (action.action === 1) { //更改属性 if (action.value?.image) { let image = action.value.image; if ( image.startsWith('/') || image.startsWith(img_cdn) || image.startsWith(img_upCdn) ) { // 只考虑相对路径下的 image ,绝对路径图片无需下载 let _img = image.replace(img_cdn, '').replace(img_upCdn, ''); if (_img.startsWith('/v/')) { _img = _img.slice(2); } _img = decodeURIComponent(_img); if (!images.includes(image)) { lists.push({ url: image, path: _img, }); } action.value.image = _img; } } } }); } }); pen.triggers?.forEach((trigger) => { trigger?.status?.forEach((state) => { if (state.actions?.length) { state.actions.forEach((action) => { if (action.action === 1) { //更改属性 if (action.value?.image) { let image = action.value.image; if ( image.startsWith('/') || image.startsWith(img_cdn) || image.startsWith(img_upCdn) ) { // 只考虑相对路径下的 image ,绝对路径图片无需下载 let _img = image.replace(img_cdn, '').replace(img_upCdn, ''); if (_img.startsWith('/v/')) { _img = _img.slice(2); } _img = decodeURIComponent(_img); if (!images.includes(image)) { lists.push({ url: image, path: _img, }); } action.value.image = _img; } } } }); } }); }); } return lists; };