const Router = require('koa-router'); const fs = require('fs'); const path = require('path'); const url = require('url'); const request = require('request') const router = new Router(); const sys = require('../config/sys') const sceneDir = path.join(__dirname, '../', sys.static_dir, sys.scene_dir) const uploadFile = require('../util/upload') const copyDir = require('../util/copydir') const upqiniu = require('../util/upqiniu') // 获取一个文件夹所有第一子文件夹 function getFiles() { return new Promise((resolve, reject) => { fs.readdir(sceneDir, (err, files) => { if (err) { reject(err) } else { resolve(files) } }) }) } // 删除文件夹所有文件 function deleteFolder(dir) { var files = []; if (fs.existsSync(dir)) { files = fs.readdirSync(dir); files.forEach(function (file, index) { var curPath = dir + "/" + file; if (fs.statSync(curPath).isDirectory()) { // recurse deleteFolder(curPath); } else { fs.unlinkSync(curPath); } }); fs.rmdirSync(dir); } } // 清除一个json复合正则的字段 function clearRgFileds(obj, rg) { let type = Object.prototype.toString.call(obj) if (type === '[object Object]') { for (let key in obj) filter(obj[key], key) } else if (type === '[object Array]') { for (let i = 0; i < obj.length; i++) filter(obj[i], i) } function filter (filed, key) { let filedType = Object.prototype.toString.call(obj[key]) if (filedType === '[object Object]' || filedType === '[object Array]') { clearRgFileds(obj[key], rg) } else if (filed && rg.test(filed.toString())) { if (type === '[object Object]') { delete obj[key] } else { obj.splice(key, 1) } } } } async function savehots(hots = {}, name) { let dataFile = 'data2.js' let dataPath = path.join(sceneDir, name, dataFile) let infoFile = 'hot/js/data.js' let infoPath = path.join(sceneDir, name, infoFile) let data = JSON.parse(fs.readFileSync(dataPath)) let hotJSON = {} let infoJSON = {} Object.keys(hots).forEach(hotKey => { hotJSON[hotKey] = { position: hots[hotKey].position, rotation: hots[hotKey].rotation, link: `//www.4dmodel.com/SuperTwo/hot_online/index.html?m=${hotKey}` } infoJSON[hotKey] = hots[hotKey].infoAttribute || ({ title: '', content: '', iframes: [], modules: [], images: [], videos: [] }) }) data.hots = hotJSON fs.writeFileSync(dataPath, JSON.stringify(data)) fs.writeFileSync(infoPath, JSON.stringify(infoJSON)) await upqiniu(name, dataFile) await upqiniu(name, infoFile) } async function saveGuide(guides = [], name) { let dataFile = 'data2.js' let someFile = 'someData.json' let dataPath = path.join(sceneDir, name, dataFile) let somDataPath = path.join(sceneDir, name, someFile) let data = JSON.parse(fs.readFileSync(dataPath)); let somData = JSON.parse(fs.readFileSync(somDataPath)) let audio = {} let images = [] somData.model.images.forEach(i => i && (i.thumbnail_signed_src || images.push(i))) guides.forEach(i => i.thumbnail_signed_src && images.push(i)) images.forEach(guide => { try { audio[JSON.parse(guide.metadata).scan_id] = { time: 40000 } } catch (e) { } }) somData.model.images = images data.audio = audio fs.writeFileSync(somDataPath, JSON.stringify(somData)) fs.writeFileSync(dataPath, JSON.stringify(data)) await upqiniu(name, dataFile) await upqiniu(name, someFile) } async function saveMusics(musics = {}, name) { let dataFile = 'data2.js' let dataPath = path.join(sceneDir, name, dataFile) let data = JSON.parse(fs.readFileSync(dataPath)); data.tourAudio = musics fs.writeFileSync(dataPath, JSON.stringify(data)) await upqiniu(name, dataFile) } async function saveInfo(info, name) { let dataFile = 'data2.js' let someFile = 'someData.json' let dataPath = path.join(sceneDir, name, dataFile) let data = JSON.parse(fs.readFileSync(dataPath)); let somDataPath = path.join(sceneDir, name, someFile); let somData = JSON.parse(fs.readFileSync(somDataPath)); somData.model.name = info.name somData.model.summary = info.summary somData.model.camera_start = info.camera_start Object.keys(info).forEach(key => { somData[key] = info[key] }) // somData.backgroundMusic = info.backgroundMusic // somData.hoticon = info.hoticon somData.loadlogo = info.loadlogo === "true" ? true : false data.weixinDesc = info.weixinDesc fs.writeFileSync(somDataPath, JSON.stringify(somData)) fs.writeFileSync(dataPath, JSON.stringify(data)) await upqiniu(name, dataFile) await upqiniu(name, someFile) } // 添加场景 router.post('/addscene', async ctx => { let name = ctx.request.body.name let files = await getFiles() let index = files.findIndex(file => file === name) if (~index) { return ctx.body = { msg: '该场景已存在,请更改场景名称', code: 500 } } await new Promise((resolve, reject) => { fs.mkdir(path.join(sceneDir, name), err => { if (err) { reject(err) } else { resolve() } }) }) ctx.body = { content: '成功创建场景', code: 200 } }) // 删除场景 router.post('/delscene', async ctx => { let dir = path.join(sceneDir, ctx.request.body.name) deleteFolder(dir) ctx.body = { code: 200 } }) // 获取所有场景 router.get('/list', async ctx => { let files = await getFiles() let content = files.map(file => { let name = '' try { let somedata = JSON.parse(fs.readFileSync(path.join(sceneDir, file, 'someData.json'))) name = somedata.name || somedata.model.name } catch (e) { } return { name: file, title: name, query: url.format({ protocol: sys.protocol, host: 'www.4dmodel.com', port: sys.port, pathname: sys.scene_query, query: {m: file} }), edit: url.format({ protocol: sys.protocol, host: sys.host, port: sys.port, pathname: sys.scene_edit, query: { m: file } }) } }) ctx.body = { content, code: 200 } }) // 转化运行场景需要的参数 router.post('/transform', async ctx => { let url = ctx.request.body.url let modelDataUrl = path.join(sceneDir, ctx.request.body.name, 'modeldata.js') let someDataUrl = path.join(sceneDir, ctx.request.body.name, 'someData.json') let readFile let transformData if (fs.existsSync(someDataUrl)) { readFile = 'someData.json' transformData = fs.readFileSync(someDataUrl) } else if (fs.existsSync(modelDataUrl)) { readFile = 'modeldata.js' transformData = fs.readFileSync(modelDataUrl) } else { transformData = await new Promise((resolve, reject) => { request(url, function(err, res, body) { if (err) { reject(err) } else { resolve(body) } }) }) readFile = url } if (!transformData) { return ctx.body = { msg: '该场景缺少核心启动文件!', code: 500 } } try { transformData = JSON.parse(transformData) } catch (e) { return ctx.body = { code: 500, msg: readFile + '不是有效的json格式文件!' } } transformData = transformSomeData(transformData) transformData.model.sid = ctx.request.body.name let hotUrl = path.join(sceneDir, ctx.request.body.name, 'hot') if (!fs.existsSync(hotUrl)) { await new Promise((resolve, reject) => { copyDir(path.join(__dirname, '../', sys.static_dir, './hottemp'), hotUrl, resolve) }) } let dataPath = path.join(sceneDir, ctx.request.body.name, 'data2.js') fs.writeFileSync(dataPath, '{}') await upqiniu(ctx.request.body.name, 'data2.js') fs.writeFileSync(someDataUrl, JSON.stringify(transformData)) await upqiniu(ctx.request.body.name, 'someData.json') ctx.body = { code: 200 } }) // 保存配置 router.post('/savesetting', async ctx => { let { name, hots, guides = [], info, tourAudio = {} } = ctx.request.body if (!guides.length) { let ret = [] for (let key in guides) { ret.push(guides[key]) } guides = ret } await saveGuide(guides, name) await savehots(hots, name) await saveInfo(info, name) await saveMusics(tourAudio, name) ctx.body = { code: 200, msg: '修改成功!' } }) // 上传文件 router.post('/uploadFile', async ctx => { let result = await uploadFile(ctx, sceneDir); let file = result.file.substr(('/'+result.name+'/').length); let qiniuLocal = await upqiniu(result.name, file); ctx.body = { code: 200, msg: '文件上传成功', content: qiniuLocal } }) router.get('/getSomeData', async ctx => { let url = ctx.request.query.url let data = await new Promise((resolve, reject) => { request(url, function (err, res, body) { if (err) { reject(err) } else { resolve(body) } }) }) try { transformData = transformSomeData(JSON.parse(data)) } catch (e) { return ctx.body = { code: 500, msg: url + '不是有效的json格式文件!' } } ctx.body = transformData }) function transformSomeData(transformData) { if (!transformData.model) { transformData = { model: transformData } delete transformData.model.icon delete transformData.model.camera_start transformData.model.address = JSON.stringify(transformData.model.address) } clearRgFileds(transformData, /\/\//) let delFileds = [ 'enable_social_sharing', 'social_sharing_enabled', 'account_social_sharing_default', 'owner', 'address', 'is_vr', 'vision_version', 'created', 'unit_type', 'owner' ] let assigFileds = { files: { templates: ['data/{{number}}/{{filename}}'] }, } delFileds.forEach(filed => { delete transformData[filed] delete transformData.model[filed] }) Object.keys(assigFileds).forEach(filed => transformData[filed] = assigFileds[filed]) if (!transformData.model.camera_start) { for (let i = 0; i < transformData.model.images.length; i++) { let metadata = JSON.parse(transformData.model.images[0].metadata) if (metadata.scan_id) { transformData.model.camera_start = { camera: { "zoom": -1, "quaternion": [ metadata.camera_quaternion.x, metadata.camera_quaternion.y, metadata.camera_quaternion.z, metadata.camera_quaternion.w ] }, pano: { "uuid": metadata.scan_id }, "mode": 0 } break; } } } let deufaltPlayer = { "presented_by": true, "highlight_reel": true, "floor_plan": true, "tour_buttons": true, "dollhouse": true, "fast_transitions": false, "autoplay": false, } transformData.model.player_options = transformData.model.player_options || {}; Object.keys(deufaltPlayer).forEach(key => transformData.model.player_options[key] = deufaltPlayer[key]) transformData.model.images = [transformData.model.images[0]] return transformData } module.exports = exports = {router};