Browse Source

计量附件内容

laiguoran 5 năm trước cách đây
mục cha
commit
d49fd9cb95

+ 193 - 0
app/controller/stage_controller.js

@@ -19,6 +19,8 @@ const measureType = tenderConst.measureType;
 const path = require('path');
 const PayCalculator = require('../lib/pay_calc');
 const accountGroup = require('../const/account_group').group;
+const sendToWormhole = require('stream-wormhole');
+const fs = require('fs');
 
 module.exports = app => {
     class StageController extends app.BaseController {
@@ -150,6 +152,13 @@ module.exports = app => {
                 } else {
                     renderData.preStageData = [];
                 }
+                renderData.whiteList = this.ctx.app.config.multipart.whitelist;
+                // 获取附件列表
+                const attData = await ctx.service.stageAtt.getDataByTenderIdAndStageId(ctx.tender.id, ctx.params.order);
+                for (const index in attData) {
+                    attData[index].in_time = moment(attData[index].in_time * 1000).format('YYYY-MM-DD');
+                }
+                renderData.attData = attData;
                 await this.layout('stage/index.ejs', renderData, 'stage/modal.ejs');
             } catch (err) {
                 this.log(err);
@@ -960,6 +969,190 @@ module.exports = app => {
                 ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage');
             }
         }
+
+        /**
+         * 上传附件
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async uploadFile(ctx) {
+            const responseData = {
+                err: 0,
+                msg: '',
+                data: [],
+            };
+            let stream;
+            try {
+                stream = await ctx.getFileStream();
+                const create_time = Date.parse(new Date()) / 1000;
+                const fileInfo = path.parse(stream.filename);
+                const dirName = 'app/public/upload/stage/' + moment().format('YYYYMMDD');
+                const fileName = 'stage' + create_time + fileInfo.ext;
+
+                // 判断文件夹是否存在,不存在则直接创建文件夹
+                if (!fs.existsSync(path.join(this.app.baseDir, dirName))) {
+                    await fs.mkdirSync(path.join(this.app.baseDir, dirName));
+                }
+                // 保存文件
+                await ctx.helper.saveStreamFile(stream, path.join(this.app.baseDir, dirName, fileName));
+                // 保存数据到att表
+                const fileData = {
+                    tid: ctx.params.id,
+                    sid: ctx.params.order,
+                    in_time: create_time,
+                    filename: fileInfo.name,
+                    fileext: fileInfo.ext,
+                    filesize: stream.fields.size,
+                    filepath: path.join(dirName, fileName),
+                };
+                const result = await ctx.service.stageAtt.save(stream.fields, fileData, ctx.session.sessionUser.accountId);
+                if (!result) {
+                    throw '导入数据库保存失败';
+                }
+                const attData = await ctx.service.stageAtt.getDataByFid(result.insertId);
+                attData.in_time = moment(create_time * 1000).format('YYYY-MM-DD');
+                responseData.data = attData;
+            } catch (err) {
+                this.log(err);
+                // 失败需要消耗掉stream 以防卡死
+                if (stream) {
+                    await sendToWormhole(stream);
+                }
+                this.setMessage(err.toString(), this.messageType.ERROR);
+                responseData.err = 1;
+                responseData.msg = err.toString();
+            }
+            ctx.body = responseData;
+        }
+
+        /**
+         * 下载附件
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async downloadFile(ctx) {
+            const id = ctx.params.fid;
+            if (id) {
+                try {
+                    const fileInfo = await ctx.service.stageAtt.getDataById(id);
+                    if (fileInfo !== undefined && fileInfo !== '') {
+                        const fileName = path.join(this.app.baseDir, fileInfo.filepath);
+                        // 解决中文无法下载问题
+                        const userAgent = (ctx.request.header['user-agent'] || '').toLowerCase();
+                        let disposition = '';
+                        if (userAgent.indexOf('msie') >= 0 || userAgent.indexOf('chrome') >= 0) {
+                            disposition = 'attachment; filename=' + encodeURIComponent(fileInfo.filename + fileInfo.fileext);
+                        } else if (userAgent.indexOf('firefox') >= 0) {
+                            disposition = 'attachment; filename*="utf8\'\'' + encodeURIComponent(fileInfo.filename + fileInfo.fileext) + '"';
+                        } else {
+                            /* safari等其他非主流浏览器只能自求多福了 */
+                            disposition = 'attachment; filename=' + new Buffer(fileInfo.filename + fileInfo.fileext).toString('binary');
+                        }
+                        ctx.response.set({
+                            'Content-Type': 'application/octet-stream',
+                            'Content-Disposition': disposition,
+                            'Content-Length': fileInfo.filesize,
+                        });
+                        ctx.body = await fs.createReadStream(fileName);
+                    } else {
+                        throw '不存在该文件';
+                    }
+                } catch (err) {
+                    this.log(err);
+                    this.setMessage(err.toString(), this.messageType.ERROR);
+                }
+            }
+        }
+
+        /**
+         * 删除附件
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async deleteFile(ctx) {
+            const responseData = {
+                err: 0,
+                msg: '',
+                data: '',
+            };
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                const fileInfo = await ctx.service.stageAtt.getDataById(data.id);
+                if (fileInfo !== undefined && fileInfo !== '') {
+                    // 先删除文件
+                    await fs.unlinkSync(path.join(this.app.baseDir, fileInfo.filepath));
+                    // 再删除数据库
+                    await ctx.service.stageAtt.deleteById(data.id);
+                    responseData.data = '';
+                } else {
+                    throw '不存在该文件';
+                }
+
+                // if (data.tid === undefined || data.uci === undefined || data.uc === undefined || data.ac === undefined) {
+                //     throw '参数有误';
+                // }
+                // const [addCompany, selectCompany] = await ctx.service.changeCompany.setCompanyList(data);
+                // responseData.data = { add: addCompany, select: selectCompany };
+            } catch (err) {
+                responseData.err = 1;
+                responseData.msg = err;
+            }
+
+            ctx.body = responseData;
+        }
+
+        /**
+         * 保存附件(或替换)
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async saveFile(ctx) {
+            const responseData = {
+                err: 0,
+                msg: '',
+                data: [],
+            };
+            let stream;
+            try {
+                stream = await ctx.getFileStream({ requireFile: false });
+                let fileData = {};
+                if (stream.filename !== undefined) {
+                    const create_time = Date.parse(new Date()) / 1000;
+                    const fileInfo = path.parse(stream.filename);
+                    const dirName = 'app/public/upload/stage/' + moment().format('YYYYMMDD');
+                    const fileName = 'stage' + create_time + fileInfo.ext;
+
+                    // 判断文件夹是否存在,不存在则直接创建文件夹
+                    if (!fs.existsSync(path.join(this.app.baseDir, dirName))) {
+                        await fs.mkdirSync(path.join(this.app.baseDir, dirName));
+                    }
+                    // 保存文件
+                    await ctx.helper.saveStreamFile(stream, path.join(this.app.baseDir, dirName, fileName));
+                    // 保存数据到att表
+                    fileData = {
+                        filesize: stream.fields.size,
+                        filepath: path.join(dirName, fileName),
+                    };
+                }
+                const result = await ctx.service.stageAtt.updateByID(stream.fields, fileData);
+                if (!result) {
+                    throw '导入数据库保存失败';
+                }
+                const attData = await ctx.service.stageAtt.getDataByFid(stream.fields.id);
+                attData.in_time = moment(attData.in_time * 1000).format('YYYY-MM-DD');
+                responseData.data = attData;
+            } catch (err) {
+                this.log(err);
+                // 失败需要消耗掉stream 以防卡死
+                if (stream) {
+                    await sendToWormhole(stream);
+                }
+                this.setMessage(err.toString(), this.messageType.ERROR);
+                responseData.err = 1;
+                responseData.msg = err.toString();
+            }
+            ctx.body = responseData;
+        }
     }
 
     return StageController;

+ 1 - 0
app/public/js/change_set.js

@@ -46,6 +46,7 @@ $(document).ready(() => {
     for (const ggd in gclGatherData) {
         gclGatherData[ggd].code = gclGatherData[ggd].b_code;
     }
+    console.log(gclGatherData);
     // 数组去重
     for (const db of gclGatherData) {
         const exist_index = dealBillList.findIndex(function (item) {

+ 247 - 3
app/public/js/stage.js

@@ -86,6 +86,36 @@ function needCheckDetail() {
     $('#check_point').show();
 }
 
+// 生成所有附件列表
+function getAllList(currPageNum = 1) {
+    // 每页最多几个附件
+    const pageCount = 11;
+    // 附件总数
+    const total = attData.length;
+    // 总页数
+    const pageNum = Math.ceil(total/pageCount);
+    $('#totalPage').text(pageNum);
+    $('#currentPage').text(currPageNum);
+    // 当前页附件内容
+    const currPageAttData = attData.slice((currPageNum-1)*pageCount, currPageNum*pageCount);
+    let html = '';
+    for(const att of currPageAttData) {
+        html += '<tr><td><a href="javascript:void(0)" file-id="'+ att.id +'">'+ att.filename + att.fileext +'</a></td><td>'+ att.username +'</td></tr>';
+    }
+    $('#alllist-table').html(html);
+}
+// 生成当前节点列表
+function getNodeList(node) {
+    let html = '';
+    for(const att of attData) {
+        if (parseInt(node) === att.lid) {
+            html += '<tr><td><a href="javascript:void(0)" file-id="'+ att.id +'">'+ att.filename + att.fileext +'</a></td><td>'+ att.username +'</td></tr>';
+
+        }
+    }
+    $('#nodelist-table').html(html);
+}
+
 $(document).ready(() => {
     // 界面布局
     autoFlashHeight();
@@ -413,6 +443,9 @@ $(document).ready(() => {
     // 绘制界面
     SpreadJsObj.loadSheetData(slSpread.getActiveSheet(), 'tree', stageTree);
 
+    //初始化所有附件列表
+    getAllList();
+
     // 初始化 部位明细 Spread
     const spSpread = SpreadJsObj.createNewSpread($('#stage-pos')[0]);
     const spCol = _.find(posSpreadSetting.cols, {field: 'qc_qty'});
@@ -599,6 +632,7 @@ $(document).ready(() => {
             } else {
                 SpreadJsObj.loadSheetData(spSpread.getActiveSheet(), 'data', []);
             }
+            getNodeList(node.id);
         },
         editEnded: function (e, info) {
             if (info.sheet.zh_setting) {
@@ -972,7 +1006,7 @@ $(document).ready(() => {
         }
     });
     // 展开收起附件
-    $('a', '.side-menu').bind('click', function () {
+    $('a', '.right-nav').bind('click', function () {
         //const main = $('#main-view'), tool = $('#tools-view');
         const tab = $(this), tabPanel = $(tab.attr('content'));
         const showTools = function (show) {
@@ -1000,7 +1034,7 @@ $(document).ready(() => {
         };
         if (!tab.hasClass('active')) {
             $('a', '.side-menu').removeClass('active');
-            $('.tab-content .tab-pane').removeClass('active');
+            $('.tab-content .tab-select-show').removeClass('active');
             tab.addClass('active');
             tabPanel.addClass('active');
             showTools(tab.hasClass('active'));
@@ -1008,6 +1042,10 @@ $(document).ready(() => {
                 searchLedger = new SearchLedger($('#search'), slSpread);
                 searchLedger.spread.refresh();
             }
+            if (tab.attr('content') === '#fujian') {
+                const node = SpreadJsObj.getSelectObject(slSpread.getActiveSheet());
+                getNodeList(node.id);
+            }
         } else {
             tab.removeClass('active');
             tabPanel.removeClass('active');
@@ -1016,4 +1054,210 @@ $(document).ready(() => {
         slSpread.refresh();
         spSpread.refresh();
     });
-});
+
+    // 切换附件里节点和所有附件
+    $('#fujian .nav-link').on('click', function () {
+        const tabPanel = $(this).attr('fujian-content');
+        if (tabPanel !== 'syfujian') {
+            $('#showPage').hide();
+        } else {
+            $('#showPage').show();
+        }
+    });
+
+    // 上传附件
+    $('#upload-file-btn').click(function () {
+        const file = $('#upload-file')[0];
+        if (file.files[0] === undefined) {
+            toast('未选择上传文件!', 'error');
+            return false;
+        }
+        const filesize = file.files[0].size;
+        if (filesize > 10 * 1024 * 1024) {
+            toast('文件大小过大!', 'error');
+            return false;
+        }
+        const fileext = '.' + file.files[0].name.toLowerCase().split('.').splice(-1)[0];
+        if (whiteList.indexOf(fileext) === -1) {
+            toast('只能上传指定格式的附件!', 'error');
+            return false;
+        }
+        const node = SpreadJsObj.getSelectObject(slSpread.getActiveSheet());
+        const formData = new FormData();
+        formData.append('lid', node.id);
+        formData.append('size', filesize);
+        formData.append('file', file.files[0]);
+        postDataWithFile('/tender/' + tender.id + '/measure/stage/' + tender.ledger_times + '/upload/file', formData, function (data) {
+            $('#upload').modal('hide');
+            // 插入到attData中
+            console.log(data);
+            attData.unshift(data);
+            // 重新生成LIst
+            getAllList();
+            getNodeList(node.id);
+        }, function () {
+            toast('附件上传失败', 'error');
+        });
+        $('#upload-file').val('');
+    });
+
+    // 获取附件信息
+    $('body').on('click', '.list-table a', function () {
+        const fid = $(this).attr('file-id');
+        if ($('#showAttachment').attr('file-id') === fid && !$('#showAttachment').is(":hidden")) {
+            return;
+        }
+        const att = attData.find(function (item) {
+            return item.id === parseInt(fid);
+        });
+        console.log(att);
+        $('#edit-att').hide();
+        $('#show-att').show();
+        if (att !== undefined) {
+            $('#show-att tr').eq(0).children('td').text(att.filename + att.fileext);
+            const name = att.code !== null && att.code !== '' ? att.code : att.b_code;
+            $('#show-att tr').eq(1).children('td').text(name + ' ' + att.lname);
+            $('#show-att tr').eq(2).find('a').attr('href', '/tender/' + tender.id + '/measure/stage/' + tender.ledger_times + '/download/file/' + att.id);
+            $('#show-att tr').eq(3).children('td').eq(0).text(att.username);
+            $('#show-att tr').eq(3).children('td').eq(1).text(att.in_time);
+            $('#show-att tr').eq(4).children('td').text(att.remark);
+            console.log(userID);
+            console.log(att.uid);
+            if (parseInt(userID) === att.uid) {
+                $('#btn-att').show();
+                $('#btn-att a').eq(1).show();
+                $('#btn-att a').eq(0).hide();
+                $('#btn-att a').eq(2).hide();
+                $('#btn-att a').eq(3).hide();
+            } else {
+                $('#btn-att').hide();
+                $('#btn-att a').eq(1).hide();
+                $('#btn-att a').eq(0).hide();
+                $('#btn-att a').eq(2).hide();
+                $('#btn-att a').eq(3).hide();
+            }
+            $('#showAttachment').attr('file-id', fid);
+            $('#showAttachment').show();
+        } else {
+            $('#showAttachment').hide();
+            $('#showAttachment').attr('file-id', '');
+            toast('附件信息获取失败', 'error');
+        }
+    });
+
+    $('body').on('click', '#btn-att a', function () {
+        const content = $(this).attr('content');
+        const fid = $('#showAttachment').attr('file-id');
+        const node = SpreadJsObj.getSelectObject(slSpread.getActiveSheet());
+        if (content === 'edit') {
+            $('#btn-att a').eq(1).hide();
+            $('#btn-att a').eq(0).show();
+            $('#btn-att a').eq(2).show();
+            $('#btn-att a').eq(3).show();
+            $('#show-att').hide();
+            $('#edit-att').show();
+            const att = attData.find(function (item) {
+                return item.id === parseInt(fid);
+            });
+            $('#edit-att .form-group').eq(0).find('input').val(att.filename);
+            $('#edit-att .form-group').eq(0).find('span').eq(1).text(att.fileext);
+            const name = att.code !== null && att.code !== '' ? att.code : att.b_code;
+            $('#edit-att .form-group').eq(1).find('input').val(name + ' ' + att.lname);
+            $('#edit-att .form-group').eq(2).find('input').val(att.in_time);
+            $('#edit-att .form-group').eq(3).find('input').val(att.remark);
+        } else if (content === 'cancel') {
+            $('#show-att').show();
+            $('#edit-att').hide();
+            $('#btn-att a').eq(1).show();
+            $('#btn-att a').eq(0).hide();
+            $('#btn-att a').eq(2).hide();
+            $('#btn-att a').eq(3).hide();
+        } else if (content === 'save') {
+            const formData = new FormData();
+            formData.append('id', fid);
+            formData.append('filename', $('#edit-att .form-group').eq(0).find('input').val());
+            formData.append('fileext', $('#edit-att .form-group').eq(0).find('span').eq(1).text());
+            formData.append('remark', $('#edit-att .form-group').eq(3).find('input').val());
+            const file = $('#change-att-btn')[0];
+            if (file.files[0] !== undefined) {
+                const filesize = file.files[0].size;
+                formData.append('size', filesize);
+                formData.append('file', file.files[0]);
+            }
+            postDataWithFile('/tender/' + tender.id + '/measure/stage/' + tender.ledger_times + '/save/file', formData, function (data) {
+                // 替换到attData中
+                const att_index = attData.findIndex(function (item) {
+                    return item.id === parseInt(fid);
+                });
+                attData.splice(att_index, 1, data);
+                // 重新生成List
+                getAllList(parseInt($('#currentPage').text()));
+                getNodeList(node.id);
+                $('#show-att').show();
+                $('#edit-att').hide();
+                $('#show-att tr').eq(0).children('td').text(data.filename + data.fileext);
+                const name = data.code !== null && data.code !== '' ? data.code : data.b_code;
+                $('#show-att tr').eq(1).children('td').text(name + ' ' + data.lname);
+                $('#show-att tr').eq(2).find('a').attr('href', '/tender/' + tender.id + '/measure/stage/' + tender.ledger_times + '/download/file/' + data.id);
+                $('#show-att tr').eq(3).children('td').eq(0).text(data.username);
+                $('#show-att tr').eq(3).children('td').eq(1).text(data.in_time);
+                $('#show-att tr').eq(4).children('td').text(data.remark);
+                $('#btn-att a').eq(1).show();
+                $('#btn-att a').eq(0).hide();
+                $('#btn-att a').eq(2).hide();
+                $('#btn-att a').eq(3).hide();
+            }, function () {
+                toast('附件上传失败', 'error');
+            });
+            $('#change-att-btn').val('');
+        } else if (content === 'del') {
+            const data = {id: fid};
+            postData('/tender/' + tender.id + '/measure/stage/' + tender.ledger_times + '/delete/file', data, function (result) {
+                // 删除到attData中
+                const att_index = attData.findIndex(function (item) {
+                    return item.id === parseInt(fid);
+                });
+                attData.splice(att_index, 1);
+                // 重新生成List
+                getAllList();
+                getNodeList(node.id);
+                $('#showAttachment').hide();
+                $('#showAttachment').attr('file-id', '');
+            });
+        }
+    });
+
+    // 替换附件
+    $('#change-att-btn').on('change', function () {
+        const file = $('#change-att-btn')[0].files[0];
+        const name = file.name;
+        const filename = name.substring(0, name.lastIndexOf("."));
+        const fileext = name.substr(name.indexOf("."));
+        const filesize = file.size;
+        if (filesize > 10 * 1024 * 1024) {
+            toast('文件大小过大!', 'error');
+            $('#change-att-btn').val('');
+            return false;
+        }
+        if (whiteList.indexOf(fileext) === -1) {
+            toast('只能上传指定格式的附件!', 'error');
+            $('#change-att-btn').val('');
+            return false;
+        }
+        $('#edit-att .form-group').eq(0).find('input').val(filename);
+        $('#edit-att .form-group').eq(0).find('span').eq(1).text(fileext);
+    });
+
+    // 切换页数
+    $('.page-select').on('click', function () {
+        const totalPageNum = $('#totalPage').text();
+        const lastPageNum = $('#currentPage').text();
+        const status = $(this).attr('content');
+        console.log(totalPageNum,lastPageNum,status);
+        if (status === 'pre' && lastPageNum > 1) {
+            getAllList(parseInt(lastPageNum)-1);
+        } else if (status === 'next' && lastPageNum < totalPageNum) {
+            getAllList(parseInt(lastPageNum)+1);
+        }
+    })
+});

+ 1 - 0
app/public/upload/stage/page.html

@@ -0,0 +1 @@
+当前页存变更令附件

+ 5 - 0
app/router.js

@@ -160,6 +160,11 @@ module.exports = app => {
     app.post('/tender/:id/measure/stage/:order/compare/load', sessionAuth, tenderCheck, stageCheck, 'stageController.compareAuditor');
     // 报表
     app.get('/tender/:id/measure/stage/:order/report', sessionAuth, tenderCheck, 'stageController.report');
+    // 计量附件
+    app.post('/tender/:id/measure/stage/:order/upload/file', sessionAuth, 'stageController.uploadFile');
+    app.get('/tender/:id/measure/stage/:order/download/file/:fid', sessionAuth, 'stageController.downloadFile');
+    app.post('/tender/:id/measure/stage/:order/delete/file', sessionAuth, 'stageController.deleteFile');
+    app.post('/tender/:id/measure/stage/:order/save/file', sessionAuth, 'stageController.saveFile');
     // 变更管理
     app.get('/tender/:id/change', sessionAuth, tenderCheck, 'changeController.index');
     app.get('/tender/:id/change/status/:status', sessionAuth, tenderCheck, 'changeController.status');

+ 90 - 0
app/service/stage_att.js

@@ -0,0 +1,90 @@
+'use strict';
+
+/**
+ *
+ *  附件
+ * @author Ellisran
+ * @date 2019/1/11
+ * @version
+ */
+
+module.exports = app => {
+    class StageAtt extends app.BaseService {
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'stage_attachment';
+        }
+
+        /**
+         * 添加附件
+         * @param {Object} postData - 表单信息
+         * @param {Object} fileData - 文件信息
+         * @param {int} uid - 上传者id
+         * @return {void}
+         */
+        async save(postData, fileData, uid) {
+            const data = {
+                lid: postData.lid,
+                uid,
+                remark: '',
+            };
+            Object.assign(data, fileData);
+            const result = await this.db.insert(this.tableName, data);
+            return result;
+        }
+
+        /**
+         * 添加附件
+         * @param {Object} postData - 表单信息
+         * @param {Object} fileData - 文件信息
+         * @param {int} uid - 上传者id
+         * @return {void}
+         */
+        async updateByID(postData, fileData) {
+            delete postData.size;
+            const data = {};
+            Object.assign(data, fileData);
+            Object.assign(data, postData);
+            const result = await this.db.update(this.tableName, data);
+            return result.affectedRows === 1;
+        }
+
+        /**
+         * 获取所有附件
+         * @param {int} tid - 标段id
+         * @param {int} sid - 当前期数
+         * @return {void}
+         */
+        async getDataByTenderIdAndStageId(tid, sid) {
+            const sql = 'SELECT att.id, att.lid, att.uid, att.filename, att.fileext, att.filesize, att.remark, att.in_time,' +
+                ' pa.name as `username`, leg.name as `lname`, leg.code as `code`, leg.b_code as `b_code`' +
+                ' FROM ?? AS att,?? AS pa,?? AS leg' +
+                ' WHERE leg.id = att.lid AND pa.id = att.uid AND att.tid = ? AND att.sid = ? ORDER BY att.in_time DESC';
+            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, this.ctx.service.ledger.tableName, tid, sid];
+            return await this.db.query(sql, sqlParam);
+        }
+
+        /**
+         * 获取单个附件
+         * @param {int} tid - 标段id
+         * @param {int} sid - 当前期数
+         * @return {void}
+         */
+        async getDataByFid(id) {
+            const sql = 'SELECT att.id, att.lid, att.uid, att.filename, att.fileext, att.filesize, att.remark, att.in_time,' +
+                ' pa.name as `username`, leg.name as `lname`, leg.code as `code`, leg.b_code as `b_code`' +
+                ' FROM ?? AS att,?? AS pa,?? AS leg' +
+                ' WHERE leg.id = att.lid AND pa.id = att.uid AND att.id = ? ORDER BY att.in_time DESC';
+            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, this.ctx.service.ledger.tableName, id];
+            return await this.db.queryOne(sql, sqlParam);
+        }
+    }
+
+    return StageAtt;
+};

+ 84 - 143
app/view/stage/index.ejs

@@ -58,7 +58,7 @@
                 <div class="resize-x" id="right-spr" r-Type="width" div1="#main-view" div2="#tools-view" title="调整大小" a-type="percent"><!--调整左右高度条--></div>
                 <div class="tab-content">
                     <!--查找定位-->
-                    <div id="search" class="tab-pane">
+                    <div id="search" class="tab-pane tab-select-show">
                         <div class="sjs-bar-1">
                             <div class="input-group input-group-sm">
                                 <div class="input-group-prepend">
@@ -79,175 +79,106 @@
                         </div>
                     </div>
                     <!--附件-->
-                    <div id="fujian" class="tab-pane">
+                    <div id="fujian" class="tab-pane tab-select-show">
                         <div class="sjs-bar">
                             <ul class="nav nav-tabs">
                                 <li class="nav-item">
-                                    <a class="nav-link active" data-toggle="tab" href="#dqjiedian" role="tab">当前节点</a>
+                                    <a class="nav-link active" data-toggle="tab" href="#dqjiedian" role="tab" fujian-content="dqjiedian">当前节点</a>
                                 </li>
                                 <li class="nav-item">
-                                    <a class="nav-link" data-toggle="tab" href="#syfujian" role="tab">所有附件</a>
+                                    <a class="nav-link" data-toggle="tab" href="#syfujian" role="tab" fujian-content="syfujian">所有附件</a>
                                 </li>
                                 <li class="nav-item ml-auto">
                                     <!--所有附件 翻页-->
-                                    <a href="#"><i class="fa fa-chevron-left"></i></a> 1/10 <a href="#"><i class="fa fa-chevron-right"></i></a>
+                                    <span id="showPage" style="display: none"><a href="javascript:void(0);" class="page-select" content="pre"><i class="fa fa-chevron-left"></i></a> <span id="currentPage">1</span>/<span id="totalPage">10</span> <a href="javascript:void(0);" class="page-select" content="next"><i class="fa fa-chevron-right"></i></a></span>
                                     <a href="#upload" data-toggle="modal" data-target="#upload"  class="btn btn-sm btn-outline-primary ml-3">上传</a>
                                 </li>
                             </ul>
                         </div>
                         <div class="tab-content">
                             <div class="tab-pane active" id="dqjiedian">
-                                <div class="sjs-height-3">
+                                <div class="sjs-height-3" style="overflow:auto; overflow-x:hidden;">
                                     <table class="table table-sm table-bordered table-hover">
-                                        <tbody><tr><th>文件名</th><th width="80">上传</th></tr>
-                                        <tr><td><a href="">asdasd.jpg</a></td><td>张三</td></tr>
-                                        <tr><td><a href="">sd22d.jpg</a></td><td>张三</td></tr>
-                                        </tbody></table>
-                                </div>
-                                <div class="sjs-bottom">
-                                    <div class="tab-content">
-                                        <div class="tab-pane active">
-                                            <div class="sjs-bottom-2">
-                                                <div class="d-flex justify-content-end mb-1">
-                                                    <!--默认 有删除权限-->
-                                                    <a href="#" class="btn btn-sm text-danger">删除</a>
-                                                    <!--默认 有编辑权限-->
-                                                    <a href="#" class="btn btn-sm btn-outline-primary">编辑</a>
-                                                    <!--编辑模式-->
-                                                    <a href="#" class="btn btn-sm btn-outline-success mr-1">保存</a>
-                                                    <a href="#" class="btn btn-sm btn-outline-secondary">取消</a>
-                                                </div>
-                                                <!--显示信息-->
-                                                <table class="table table-sm table-bordered">
-                                                    <tbody>
-                                                    <tr><th>文件名</th><td colspan="3">asdasd.jpg</td></tr>
-                                                    <tr><th>所在节点</th><td colspan="3">1 第一部分 建筑安装工程非</td></tr>
-                                                    <tr><td colspan="4"><a href="">下载附件</a></td></tr>
-                                                    <tr><th>上传者</th><td>张三</td><th>上传时间</th><td>2018-10-20</td></tr>
-                                                    <tr><th>备注</th><td colspan="3"></td></tr>
-                                                    </tbody>
-                                                </table>
-                                                <!--编辑模式-->
-                                                <div class="form-group">
-                                                    <div class="input-group input-group-sm">
-                                                        <div class="input-group-prepend">
-                                                            <span class="input-group-text">文件名</span>
-                                                        </div>
-                                                        <input type="text" class="form-control" value="asdasd">
-                                                        <div class="input-group-append">
-                                                            <span class="input-group-text">.jpg</span>
-                                                        </div>
-                                                    </div>
-                                                </div>
-                                                <div class="form-group">
-                                                    <div class="input-group input-group-sm">
-                                                        <div class="input-group-prepend">
-                                                            <span class="input-group-text">所在节点</span>
-                                                        </div>
-                                                        <input type="text" class="form-control" value="1 第一部分 建筑安装工程非" readonly="">
-                                                    </div>
-                                                </div>
-                                                <div class="form-group">
-                                                    <div class="input-group input-group-sm">
-                                                        <div class="input-group-prepend">
-                                                            <span class="input-group-text">上传时间</span>
-                                                        </div>
-                                                        <input type="text" class="form-control" value="2018-10-20" readonly="">
-                                                    </div>
-                                                </div>
-                                                <div class="form-group">
-                                                    <div class="input-group input-group-sm">
-                                                        <div class="input-group-prepend">
-                                                            <span class="input-group-text">备注</span>
-                                                        </div>
-                                                        <input type="text" class="form-control" value="">
-                                                    </div>
-                                                </div>
-                                                <div class="form-group">
-                                                    <label>替换文件</label>
-                                                    <div class="custom-file">
-                                                        <input type="file" class="custom-file-input" id="customFile">
-                                                        <label class="custom-file-label" for="customFile">Choose file</label>
-                                                    </div>
-                                                </div>
-                                            </div>
-                                        </div>
-                                    </div>
+                                        <tr><th>文件名</th><th width="80">上传</th></tr>
+                                        <tbody id="nodelist-table" class="list-table">
+                                        </tbody>
+                                    </table>
                                 </div>
                             </div>
                             <div class="tab-pane" id="syfujian">
-                                <div class="sjs-height-3">
+                                <div class="sjs-height-3" style="overflow:auto; overflow-x:hidden;">
                                     <table class="table table-sm table-bordered table-hover">
-                                        <tbody><tr><th>文件名</th><th width="80">上传</th></tr>
-                                        <tr><td><a href="">asdasd.jpg</a></td><td>张三</td></tr>
-                                        <tr><td><a href="">sd22d.jpg</a></td><td>张三</td></tr>
-                                        </tbody></table>
+                                        <tr><th>文件名</th><th width="80">上传</th></tr>
+                                        <tbody id="alllist-table" class="list-table">
+                                        </tbody>
+                                    </table>
                                 </div>
-                                <div class="sjs-bottom">
-                                    <div class="tab-content">
-                                        <div class="tab-pane active">
-                                            <div class="sjs-bottom-2">
-                                                <div class="d-flex justify-content-end mb-1">
-                                                    <!--默认 有删除权限-->
-                                                    <a href="#" class="btn btn-sm text-danger">删除</a>
-                                                    <!--默认 有编辑权限-->
-                                                    <a href="#" class="btn btn-sm btn-outline-primary">编辑</a>
-                                                    <!--编辑模式-->
-                                                    <a href="#" class="btn btn-sm btn-outline-success mr-1">保存</a>
-                                                    <a href="#" class="btn btn-sm btn-outline-secondary">取消</a>
-                                                </div>
-                                                <!--显示信息-->
-                                                <table class="table table-sm table-bordered">
-                                                    <tbody>
-                                                    <tr><th>文件名</th><td colspan="3">asdasd.jpg</td></tr>
-                                                    <tr><th>所在节点</th><td colspan="3">1 第一部分 建筑安装工程非</td></tr>
-                                                    <tr><td colspan="4"><a href="">下载附件</a></td></tr>
-                                                    <tr><th>上传者</th><td>张三</td><th>上传时间</th><td>2018-10-20</td></tr>
-                                                    <tr><th>备注</th><td colspan="3"></td></tr>
-                                                    </tbody>
-                                                </table>
-                                                <!--编辑模式-->
-                                                <div class="form-group">
-                                                    <div class="input-group input-group-sm">
-                                                        <div class="input-group-prepend">
-                                                            <span class="input-group-text">文件名</span>
-                                                        </div>
-                                                        <input type="text" class="form-control" value="asdasd">
-                                                        <div class="input-group-append">
-                                                            <span class="input-group-text">.jpg</span>
-                                                        </div>
+                            </div>
+                            <div class="sjs-bottom">
+                                <br>
+                                <div class="tab-content" id="showAttachment" style="display: none" file-id="">
+                                    <div class="sjs-bottom-2">
+                                        <div class="d-flex justify-content-end mb-1" id="btn-att">
+                                            <!--默认 有删除权限-->
+                                            <a href="javascript:void(0);" content="del" class="btn btn-sm text-danger" style="display: none">删除</a>
+                                            <!--默认 有编辑权限-->
+                                            <a href="javascript:void(0);" content="edit" class="btn btn-sm btn-outline-primary" style="display: none">编辑</a>
+                                            <!--编辑模式-->
+                                            <a href="javascript:void(0);" content="save" class="btn btn-sm btn-outline-success mr-1" style="display: none">保存</a>
+                                            <a href="javascript:void(0);" content="cancel" class="btn btn-sm btn-outline-secondary" style="display: none">取消</a>
+                                        </div>
+                                        <!--显示信息-->
+                                        <table class="table table-sm table-bordered" id="show-att">
+                                            <tbody>
+                                            <tr><th>文件名</th><td colspan="3">asdasd.jpg</td></tr>
+                                            <tr><th>所在节点</th><td colspan="3">1 第一部分 建筑安装工程非</td></tr>
+                                            <tr><td colspan="4"><a href="javascript:void(0);">下载附件</a></td></tr>
+                                            <tr><th>上传者</th><td>张三</td><th>上传时间</th><td>2018-10-20</td></tr>
+                                            <tr><th>备注</th><td colspan="3"></td></tr>
+                                            </tbody>
+                                        </table>
+                                        <div id="edit-att" style="display: none">
+                                        <!--编辑模式-->
+                                            <div class="form-group">
+                                                <div class="input-group input-group-sm">
+                                                    <div class="input-group-prepend">
+                                                        <span class="input-group-text">文件名</span>
                                                     </div>
-                                                </div>
-                                                <div class="form-group">
-                                                    <div class="input-group input-group-sm">
-                                                        <div class="input-group-prepend">
-                                                            <span class="input-group-text">所在节点</span>
-                                                        </div>
-                                                        <input type="text" class="form-control" value="1 第一部分 建筑安装工程非" readonly="">
+                                                    <input type="text" class="form-control" value="asdasd">
+                                                    <div class="input-group-append">
+                                                        <span class="input-group-text">.jpg</span>
                                                     </div>
                                                 </div>
-                                                <div class="form-group">
-                                                    <div class="input-group input-group-sm">
-                                                        <div class="input-group-prepend">
-                                                            <span class="input-group-text">上传时间</span>
-                                                        </div>
-                                                        <input type="text" class="form-control" value="2018-10-20" readonly="">
+                                            </div>
+                                            <div class="form-group">
+                                                <div class="input-group input-group-sm">
+                                                    <div class="input-group-prepend">
+                                                        <span class="input-group-text">所在节点</span>
                                                     </div>
+                                                    <input type="text" class="form-control" value="1 第一部分 建筑安装工程非" readonly="">
                                                 </div>
-                                                <div class="form-group">
-                                                    <div class="input-group input-group-sm">
-                                                        <div class="input-group-prepend">
-                                                            <span class="input-group-text">备注</span>
-                                                        </div>
-                                                        <input type="text" class="form-control" value="">
+                                            </div>
+                                            <div class="form-group">
+                                                <div class="input-group input-group-sm">
+                                                    <div class="input-group-prepend">
+                                                        <span class="input-group-text">上传时间</span>
                                                     </div>
+                                                    <input type="text" class="form-control" value="2018-10-20" readonly="">
                                                 </div>
-                                                <div class="form-group">
-                                                    <label>替换文件</label>
-                                                    <div class="custom-file">
-                                                        <input type="file" class="custom-file-input" id="customFile">
-                                                        <label class="custom-file-label" for="customFile">Choose file</label>
+                                            </div>
+                                            <div class="form-group">
+                                                <div class="input-group input-group-sm">
+                                                    <div class="input-group-prepend">
+                                                        <span class="input-group-text">备注</span>
                                                     </div>
+                                                    <input type="text" class="form-control" value="">
+                                                </div>
+                                            </div>
+                                            <div class="form-group">
+                                                <label>替换文件</label>
+                                                <div class="custom-file">
+                                                    <input type="file" class="custom-file-input" id="change-att-btn">
+                                                    <label class="custom-file-label" for="customFile">Choose file</label>
                                                 </div>
                                             </div>
                                         </div>
@@ -271,12 +202,19 @@
             </ul>
         </div>
     </div>
+    <div style="display: none">
+        <img src="/public/images/ellipsis_horizontal.png" id="ellipsis-icon" />
+        <img src="/public/images/icon-ok.png" id="icon-ok" />
+    </div>
 </div>
-<!--<img src="/public/images/ellipsis_horizontal.png" id="ellipsis-icon" />-->
 <script>
     GC.Spread.Sheets.LicenseKey = "559432293813965#A0y3iTOzEDOzkjMyMDN9UTNiojIklkI1pjIEJCLi4TPB9mM5AFNTd4cvZ7SaJUVy3CWKtWYXx4VVhjMpp7dYNGdx2ia9sEVlZGOTh7NRlTUwkWR9wEV4gmbjBDZ4ElR8N7cGdHVvEWVBtCOwIGW0ZmeYVWVr3mI0IyUiwCMzETN8kzNzYTM0IicfJye&Qf35VfiEzRwEkI0IyQiwiIwEjL6ByUKBCZhVmcwNlI0IiTis7W0ICZyBlIsIyNyMzM5ADI5ADNwcTMwIjI0ICdyNkIsIibj9SbvNmL4N7bjRnch56ciojIz5GRiwiI8+Y9sWY9QmZ0Jyp96uL9v6L0wap9biY9qiq95q197Wr9g+89iojIh94Wiqi";
 </script>
 <script>
+    String.prototype.replaceAll = function (FindText, RepText) {
+        regExp = new RegExp(FindText, 'g');
+        return this.replace(regExp, RepText);
+    }
     const readOnly = <%- stage.readOnly %>;
     const ledgerSpreadSetting = JSON.parse('<%- JSON.stringify(ledgerSpread) %>');
     const posSpreadSetting = JSON.parse('<%- JSON.stringify(posSpread) %>');
@@ -287,6 +225,9 @@
     const ledgerData = JSON.parse('<%- JSON.stringify(ledgerData) %>');
     const curStageData = JSON.parse('<%- JSON.stringify(curStageData) %>');
     const preStageData = JSON.parse('<%- JSON.stringify(preStageData) %>');
+    const whiteList = JSON.parse('<%- JSON.stringify(whiteList) %>');
+    const attData = JSON.parse('<%- JSON.stringify(attData) %>');
+    const userID = '<%- ctx.session.sessionUser.accountId %>';
 </script>
 <% if (ctx.stage.status === auditConst.status.uncheck && ctx.session.sessionUser.accountId === ctx.stage.user_id) {%>
 <script>

+ 3 - 3
app/view/stage/modal.ejs

@@ -238,15 +238,15 @@
             <div class="modal-body">
                 <div class="form-group">
                     <label for="formGroupExampleInput">大小限制:10MB,支持<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="rar,zip">压缩包格式</span></label>
-                    <input type="file" class="form-control">
+                    <input type="file" class="form-control" id="upload-file">
                 </div>
             </div>
             <div class="modal-footer">
                 <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
-                <button type="button" class="btn btn-primary" >确认</button>
+                <button type="button" class="btn btn-primary" id="upload-file-btn">确认</button>
             </div>
         </div>
     </div>
 </div>
-<img src="/public/images/icon-ok.png" id="icon-ok" />
+
 <% include ./audit_modal.ejs %>

+ 6 - 6
app/view/stage/stage_sub_menu.ejs

@@ -12,14 +12,14 @@
             </div>
         <div class="nav-box">
                 <ul class="nav-list list-unstyled">
-                    <li class="<% if (ctx.url === '/tender' + ctx.tender.id + '/measure/stage' + ctx.stage.order) { %>active<% } %>">
+                    <li class="<% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/stage/' + ctx.stage.order) { %>active<% } %>">
                         <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- ctx.stage.order %>"><span class="ml-3">计量台帐</span></a>
                     </li>
                 </ul>
             </div>
         <div class="nav-box">
                 <ul class="nav-list list-unstyled">
-                    <li class="<% if (ctx.url === '/tender' + ctx.tender.id + '/measure/stage' + ctx.stage.order) { %>active<% } %>">
+                    <li class="<% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/stage/' + ctx.stage.order + '/detail') { %>active<% } %>">
                         <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- stage.order %>/detail"><span class="ml-3">中间计量</span></a>
                         <span class=" position-absolute tips-dot" data-toggle="tooltip" data-placement="bottom" data-original-title="完成中间计量" id="check_point" <% if (!ctx.stage.check_detail) { %>style="display: none;"<% } %>>
                             <i class="fa fa-circle text-danger"></i>
@@ -29,28 +29,28 @@
             </div>
         <div class="nav-box">
                 <ul class="nav-list list-unstyled">
-                    <li class="<% if (ctx.url === '/tender' + ctx.tender.id + '/measure/stage' + ctx.stage.order) { %>active<% } %>">
+                    <li class="<% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/stage/' + ctx.stage.order + '/pay') { %>active<% } %>">
                         <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- stage.order %>/pay"><span class="ml-3">合同支付</span></a>
                     </li>
                 </ul>
             </div>
         <div class="nav-box">
                 <ul class="nav-list list-unstyled">
-                    <li class="<% if (ctx.url === '/tender' + ctx.tender.id + '/measure/stage' + ctx.stage.order) { %>active<% } %>">
+                    <li class="<% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/stage/' + ctx.stage.order + '/change') { %>active<% } %>">
                         <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- stage.order %>/change"><span class="ml-3">变更概况</span></a>
                     </li>
                 </ul>
             </div>
         <div class="nav-box">
                 <ul class="nav-list list-unstyled">
-                    <li class="<% if (ctx.url === '/tender' + ctx.tender.id + '/measure/stage' + ctx.stage.order) { %>active<% } %>">
+                    <li class="<% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/stage/' + ctx.stage.order + '/gather') { %>active<% } %>">
                         <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- stage.order %>/gather"><span class="ml-3">清单汇总</span></a>
                     </li>
                 </ul>
             </div>
         <div class="nav-box">
                 <ul class="nav-list list-unstyled">
-                    <li class="<% if (ctx.url === '/tender' + ctx.tender.id + '/measure/stage' + ctx.stage.order) { %>active<% } %>">
+                    <li class="<% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/stage/' + ctx.stage.order + '/compare') { %>active<% } %>">
                         <a href="/tender/<%- ctx.tender.id %>/measure/stage/<%- stage.order %>/compare"><span class="ml-3">审核比较</span></a>
                     </li>
                 </ul>

+ 65 - 9
package-lock.json

@@ -2938,9 +2938,9 @@
       "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
     },
     "decimal.js": {
-      "version": "10.1.1",
-      "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.1.1.tgz",
-      "integrity": "sha512-vEEgyk1fWVEnv7lPjkNedAIjzxQDue5Iw4FeX4UkNUDSVyD/jZTD0Bw2kAO7k6iyyJRAhM9oxxI0D1ET6k0Mmg=="
+      "version": "10.2.0",
+      "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.0.tgz",
+      "integrity": "sha512-vDPw+rDgn3bZe1+F/pyEwb1oMG2XTlRVgAa6B4KccTEpYgF8w6eQllVbQcfIJnZyvzFtFpxnpGtx8dd7DJp/Rw=="
     },
     "decode-uri-component": {
       "version": "0.2.0",
@@ -3328,6 +3328,18 @@
         "urllib": "^2.25.1",
         "utility": "^1.13.1",
         "ylru": "^1.2.0"
+      },
+      "dependencies": {
+        "egg-multipart": {
+          "version": "1.5.1",
+          "resolved": "https://registry.npmjs.org/egg-multipart/-/egg-multipart-1.5.1.tgz",
+          "integrity": "sha512-xh64J7An0UdWRnGFikEEkKGLywjhANfK7XX9/yeXOXfL09FmVenQZJgsdUz13BEKIyWarlY9sgmf95+IpUMA2w==",
+          "requires": {
+            "co": "^4.6.0",
+            "co-busboy": "^1.3.1",
+            "humanize-bytes": "^1.0.1"
+          }
+        }
       }
     },
     "egg-bin": {
@@ -4056,13 +4068,50 @@
       }
     },
     "egg-multipart": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/egg-multipart/-/egg-multipart-1.5.1.tgz",
-      "integrity": "sha512-xh64J7An0UdWRnGFikEEkKGLywjhANfK7XX9/yeXOXfL09FmVenQZJgsdUz13BEKIyWarlY9sgmf95+IpUMA2w==",
+      "version": "2.7.1",
+      "resolved": "https://registry.npmjs.org/egg-multipart/-/egg-multipart-2.7.1.tgz",
+      "integrity": "sha512-MFhEY05dkOTDCqRVO34MY57yqjoSF1usuEjCBBGJBgT9QeHwzGf5Yb1D4d7BzDR9QQA5Ehcmc40f/LlHAZDMQg==",
       "requires": {
-        "co": "^4.6.0",
-        "co-busboy": "^1.3.1",
-        "humanize-bytes": "^1.0.1"
+        "co-busboy": "^1.4.0",
+        "humanize-bytes": "^1.0.1",
+        "moment": "^2.22.2",
+        "mz": "^2.7.0",
+        "mz-modules": "^2.1.0",
+        "stream-wormhole": "^1.1.0",
+        "uuid": "^3.3.2"
+      },
+      "dependencies": {
+        "moment": {
+          "version": "2.24.0",
+          "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
+          "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
+        },
+        "mz-modules": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/mz-modules/-/mz-modules-2.1.0.tgz",
+          "integrity": "sha512-sjk8lcRW3vrVYnZ+W+67L/2rL+jbO5K/N6PFGIcLWTiYytNr22Ah9FDXFs+AQntTM1boZcoHi5qS+CV1seuPog==",
+          "requires": {
+            "glob": "^7.1.2",
+            "ko-sleep": "^1.0.3",
+            "mkdirp": "^0.5.1",
+            "pump": "^3.0.0",
+            "rimraf": "^2.6.1"
+          }
+        },
+        "pump": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+          "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+          "requires": {
+            "end-of-stream": "^1.1.0",
+            "once": "^1.3.1"
+          }
+        },
+        "uuid": {
+          "version": "3.3.2",
+          "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
+          "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
+        }
       }
     },
     "egg-mysql": {
@@ -8868,6 +8917,13 @@
         "seed-random": "2.2.0",
         "tiny-emitter": "2.1.0",
         "typed-function": "1.1.0"
+      },
+      "dependencies": {
+        "decimal.js": {
+          "version": "10.1.1",
+          "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.1.1.tgz",
+          "integrity": "sha512-vEEgyk1fWVEnv7lPjkNedAIjzxQDue5Iw4FeX4UkNUDSVyD/jZTD0Bw2kAO7k6iyyJRAhM9oxxI0D1ET6k0Mmg=="
+        }
       }
     },
     "media-typer": {

+ 1 - 0
package.json

@@ -9,6 +9,7 @@
     "egg": "^1.13.0",
     "egg-js-validator": "^1.0.2",
     "egg-mysql": "^3.0.0",
+    "egg-multipart": "^2.7.1",
     "egg-redis": "^1.0.2",
     "egg-scripts": "^1.0.0",
     "egg-session-redis": "^1.0.0",