Bladeren bron

台账分解、台账修订,导入工程量至项目节

MaiXinRong 5 jaren geleden
bovenliggende
commit
0feebbc7fd

+ 47 - 1
app/base/base_bills_service.js

@@ -21,7 +21,6 @@ class BaseBillsSerivce extends TreeService {
 
     // 继承方法
     clearParentingData(data) {
-        console.log(1);
         data.unit_price = null;
         data.sgfh_qty = null;
         data.sgfh_tp = null;
@@ -449,6 +448,53 @@ class BaseBillsSerivce extends TreeService {
         const result = await this.db.queryOne(sql);
         return result;
     }
+
+    // 导入Excel
+    async importGclExcel(id, sheet, data) {
+        const node = await this.getDataById(id);
+        if (!node || !node.is_leaf || node.tender_id !== this.ctx.tender.id) throw '数据错误';
+
+        const maxId = await this._getMaxLid(this.ctx.tender.id);
+
+        const AnalysisExcel = require('../lib/analysis_excel').AnalysisGclExcelTree;
+        const analysisExcel = new AnalysisExcel(this.ctx);
+        const cacheData = analysisExcel.analysisData(sheet, node, maxId, data);
+
+        const datas = [];
+        for (const node of cacheData.items) {
+            datas.push({
+                id: node.id, tender_id: this.ctx.tender.id,
+                ledger_id: node.ledger_id,
+                ledger_pid: node.ledger_pid,
+                level: node.level,
+                order: node.order,
+                is_leaf: !node.children || node.children.length === 0,
+                full_path: node.full_path,
+                b_code: node.b_code,
+                name: node.name,
+                unit: node.unit,
+                sgfh_qty: node.sgfh_qty,
+                sgfh_tp: node.sgfh_tp,
+                quantity: node.quantity,
+                unit_price: node.unit_price,
+                total_price: node.total_price,
+                crid: node.crid,
+            });
+        }
+        const conn = await this.db.beginTransaction();
+        try {
+            await this.db.update(this.tableName, {id: node.id, is_leaf: false});
+            await this.db.insert(this.tableName, datas);
+            await conn.commit();
+        } catch(err) {
+            await conn.rollback();
+            throw err;
+        }
+        this._cacheMaxLid(this.ctx.tender.id, cacheData.keyNodeId);
+
+        node.is_leaf = false;
+        return { create: datas, update: [node]};
+    }
 }
 
 module.exports = BaseBillsSerivce;

+ 0 - 1
app/controller/deal_bills_controller.js

@@ -122,7 +122,6 @@ module.exports = app => {
                             data.push([db.code, db.name, db.unit, db.quantity, db.unit_price, db.total_price]);
                         }
                         const arraySheetData = this.ctx.helper.simpleXlsxSheetData(setting, data);
-                        console.log(arraySheetData);
                         xlsx.writeFile({
                             SheetNames: ['Sheet1'],
                             Sheets: {

+ 12 - 2
app/controller/ledger_controller.js

@@ -473,11 +473,21 @@ module.exports = app => {
          */
         async uploadExcel(ctx) {
             try {
+                const ueType = ctx.params.ueType;
                 const compressData = ctx.request.body.data;
                 const data = JSON.parse(LzString.decompressFromUTF16(compressData));
                 const responseData = { err: 0, msg: '', data: {}, };
-                const templateId = await this.ctx.service.valuation.getValuationTemplate(this.ctx.tender.data.valuation);
-                responseData.data = await ctx.service.ledger.importExcel(templateId, data);
+                switch (ueType) {
+                    case 'tz':
+                        const templateId = await this.ctx.service.valuation.getValuationTemplate(this.ctx.tender.data.valuation);
+                        responseData.data = await ctx.service.ledger.importExcel(templateId, data);
+                        break;
+                    case 'gcl2xmj':
+                        responseData.data = await ctx.service.ledger.importGclExcel(data.id, data.sheet);
+                        break;
+                    default:
+                        throw '数据错误';
+                }
                 ctx.body = responseData;
             } catch (err) {
                 this.log(err);

+ 1 - 1
app/controller/profile_controller.js

@@ -176,7 +176,7 @@ module.exports = app => {
                 response.msg = '绑定成功';
                 response.url = ctx.request.header.referer;
             } catch (error) {
-                console.log(error);
+                this.ctx.helper.log(error);
                 response.err = 1;
                 response.msg = error.toString();
             }

+ 40 - 8
app/controller/revise_controller.js

@@ -379,6 +379,18 @@ module.exports = app => {
             }
         }
 
+        async checkRevise(ctx) {
+            const revise = await ctx.service.ledgerRevise.getLastestRevise(ctx.tender.id);
+            if (revise.uid !== ctx.session.sessionUser.accountId) {
+                throw '修订数据错误';
+            } else if (revise.status === audit.revise.status.checking) {
+                throw '修订审批中,不可修改';
+            } else if (revise.status === audit.revise.status.checked) {
+                throw '修订已完成,如需修订台账,请新增修订';
+            }
+            return revise;
+        }
+
         async _billsBase(revise, type, data) {
             if (isNaN(data.id) || data.id <= 0) throw '数据错误';
             if (type !== 'add') {
@@ -498,18 +510,12 @@ module.exports = app => {
         async update(ctx) {
             try {
                 if (!ctx.tender.data) throw '标段数据错误';
-                const revise = await ctx.service.ledgerRevise.getLastestRevise(ctx.tender.id);
-                if (revise.uid !== ctx.session.sessionUser.accountId) {
-                    throw '修订数据错误';
-                } else if (revise.status === audit.revise.status.checking) {
-                    throw '修订审批中,不可修改';
-                } else if (revise.status === audit.revise.status.checked) {
-                    throw '修订已完成,如需修订台账,请新增修订';
-                }
                 const data = JSON.parse(ctx.request.body.data);
                 if (!data.postType || !data.postData) throw '数据错误';
                 const responseData = {err: 0, msg: '', data: {}};
 
+                const revise = await this.checkRevise(ctx);
+
                 switch (data.postType) {
                     case 'add':
                     case 'delete':
@@ -551,6 +557,32 @@ module.exports = app => {
         }
 
         /**
+         * 上传 清单Excel 并导入
+         * @param ctx
+         * @return {Promise<void>}
+         */
+        async uploadExcel(ctx) {
+            try {
+                const revise = await this.checkRevise(ctx);
+
+                const ueType = ctx.params.ueType;
+                const compressData = ctx.request.body.data;
+                const data = JSON.parse(LzString.decompressFromUTF16(compressData));
+                const responseData = { err: 0, msg: '', data: {}, };
+                switch (ueType) {
+                    case 'gcl2xmj':
+                        responseData.data = await ctx.service.reviseBills.importGclExcel(data.id, data.sheet, {crid: revise.id});
+                        break;
+                }
+                ctx.body = responseData;
+            } catch (err) {
+                this.log(err);
+                ctx.body = { err: 1, msg: err.toString(), data: null };
+            }
+
+        }
+
+        /**
          * 新增审批人(Ajax)
          *
          * @param ctx

+ 4 - 4
app/controller/stage_controller.js

@@ -236,8 +236,8 @@ module.exports = app => {
             }
             //console.timeEnd('pre');
             //console.time('assign');
-            console.log('cur: ' + curStageData.length);
-            console.log('pre: ' + preStageData.length);
+            //console.log('cur: ' + curStageData.length);
+            //console.log('pre: ' + preStageData.length);
             this.ctx.helper.assignRelaData(posData, [
                 {data: curStageData, fields: ['contract_qty', 'qc_qty', 'postil'], prefix: '', relaId: 'pid'},
                 {data: preStageData, fields: ['contract_qty', 'qc_qty'], prefix: 'pre_', relaId: 'pid'}
@@ -308,8 +308,8 @@ module.exports = app => {
                 }
                 //console.timeEnd('pre');
                 //console.time('assign');
-                console.log('cur: ' + curStageData.length);
-                console.log('pre: ' + preStageData.length);
+                //console.log('cur: ' + curStageData.length);
+                //console.log('pre: ' + preStageData.length);
                 this.ctx.helper.assignRelaData(responseData.data, [
                     {data: curStageData, fields: ['contract_qty', 'qc_qty', 'postil'], prefix: '', relaId: 'pid'},
                     {data: preStageData, fields: ['contract_qty', 'qc_qty'], prefix: 'pre_', relaId: 'pid'}

+ 13 - 0
app/extend/helper.js

@@ -845,5 +845,18 @@ module.exports = {
             {'!ref': outputPos[0] + ':' + outputPos[outputPos.length - 1]},
             {'!cols': setting.width.map((w) => Object.assign({}, {wpx: w}))});
         return result;
+    },
+
+    logger(error) {
+        if (error.stack) {
+            this.ctx.logger.error(error);
+        } else {
+            this.ctx.getLogger('fail').info(JSON.stringify({
+                error: error,
+                project: this.ctx.session.sessionProject,
+                user: this.ctx.session.sessionUser,
+                body: this.ctx.session.body,
+            }));
+        }
     }
 };

+ 191 - 23
app/lib/analysis_excel.js

@@ -8,6 +8,25 @@
  * @version
  */
 const _ = require('lodash');
+const aeUtils = {
+    toNumber: function (value) {
+        let num = _.toNumber(value);
+        return _.isNaN(num) ? null : num;
+    },
+    checkColHeader: function (row, colHeaderMatch) {
+        const colsDef = {};
+        for (const iCol in row) {
+            const text = row[iCol];
+            for (const head in colHeaderMatch) {
+                const match = colHeaderMatch[head];
+                if (match.indexOf(text) >= 0) {
+                    colsDef[head] = iCol;
+                }
+            }
+        }
+        return colsDef;
+    }
+};
 
 class ImportBaseTree {
     /**
@@ -264,11 +283,6 @@ class AnalysisExcelTree {
         };
     }
 
-    toNumber (value) {
-        let num = _.toNumber(value);
-        return _.isNaN(num) ? null : num;
-    }
-
     /**
      * 读取项目节节点
      * @param {Array} row - excel行数据
@@ -281,10 +295,10 @@ class AnalysisExcelTree {
         node.name = this.ctx.helper.replaceReturn(row[this.colsDef.name]);
         node.unit = this.ctx.helper.replaceReturn(row[this.colsDef.unit]);
         const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, node.unit);
-        node.sgfh_qty = this.ctx.helper.round(this.toNumber(row[this.colsDef.sgfh_qty]), precision.value);
-        node.dgn_qty1 = this.toNumber(row[this.colsDef.dgn_qty1]);
-        node.dgn_qty2 = this.toNumber(row[this.colsDef.dgn_qty2]);
-        node.unit_price = this.toNumber(row[this.colsDef.unit_price]);
+        node.sgfh_qty = this.ctx.helper.round(aeUtils.toNumber(row[this.colsDef.sgfh_qty]), precision.value);
+        node.dgn_qty1 = aeUtils.toNumber(row[this.colsDef.dgn_qty1]);
+        node.dgn_qty2 = aeUtils.toNumber(row[this.colsDef.dgn_qty2]);
+        node.unit_price = aeUtils.toNumber(row[this.colsDef.unit_price]);
         node.drawing_code = this.ctx.helper.replaceReturn(row[this.colsDef.drawing_code]);
         node.memo = this.ctx.helper.replaceReturn(row[this.colsDef.memo]);
         // if (node.sgfh_qty && node.unit_price) {
@@ -319,8 +333,8 @@ class AnalysisExcelTree {
         node.name = this.ctx.helper.replaceReturn(row[this.colsDef.name]);
         node.unit = this.ctx.helper.replaceReturn(row[this.colsDef.unit]);
         const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, node.unit);
-        node.sgfh_qty = this.ctx.helper.round(this.toNumber(row[this.colsDef.sgfh_qty]), precision.value);
-        node.unit_price = this.toNumber(row[this.colsDef.unit_price]);
+        node.sgfh_qty = this.ctx.helper.round(aeUtils.toNumber(row[this.colsDef.sgfh_qty]), precision.value);
+        node.unit_price = aeUtils.toNumber(row[this.colsDef.unit_price]);
         node.drawing_code = this.ctx.helper.replaceReturn(row[this.colsDef.drawing_code]);
         node.memo = this.ctx.helper.replaceReturn(row[this.colsDef.memo]);
         // if (node.sgfh_qty && node.unit_price) {
@@ -352,7 +366,7 @@ class AnalysisExcelTree {
     _loadPos(row) {
         const pos = {};
         pos.name = this.ctx.helper.replaceReturn(row[this.colsDef.name]);
-        pos.sgfh_qty = this.toNumber(row[this.colsDef.sgfh_qty]);
+        pos.sgfh_qty = aeUtils.toNumber(row[this.colsDef.sgfh_qty]);
         pos.drawing_code = this.ctx.helper.replaceReturn(row[this.colsDef.drawing_code]);
         return this.cacheTree.addPos(pos);
     }
@@ -391,16 +405,7 @@ class AnalysisExcelTree {
      * @param {Number} row - Excel数据行
      */
     checkColHeader(row) {
-        const colsDef = {};
-        for (const iCol in row) {
-            const text = row[iCol];
-            for (const head in this.colHeaderMatch) {
-                const match = this.colHeaderMatch[head];
-                if (match.indexOf(text) >= 0) {
-                    colsDef[head] = iCol;
-                }
-            }
-        }
+        const colsDef = aeUtils.checkColHeader(row, this.colHeaderMatch);
         if (colsDef.code && colsDef.b_code && colsDef.pos) {
             this.colsDef = colsDef;
         }
@@ -432,4 +437,167 @@ class AnalysisExcelTree {
     }
 }
 
-module.exports = AnalysisExcelTree;
+class ImportGclBaseTree {
+    /**
+     * 构造函数
+     * @param {Array} tempData - 清单模板数据
+     */
+    constructor (ctx, parent, maxId, defaultData) {
+        this.ctx = ctx;
+        this.parent = parent;
+        this.defaultData = defaultData;
+        // 常量
+        this.splitChar = '-';
+        // 索引
+        // 以code为索引
+        this.codeNodes = {};
+        this.items = [];
+
+        // 缓存
+        this.keyNodeId = maxId ? maxId + 1 : 1;
+        this.blankParent = null;
+    }
+
+    /**
+     * 根据 编号 查找 父项项目节
+     * @param {String} code - 子项编号
+     * @returns {*}
+     */
+    findParent(code) {
+        const codePath = code.split(this.splitChar);
+        if (codePath.length > 1) {
+            codePath.splice(codePath.length - 1, 1);
+            return this.codeNodes[codePath.join(this.splitChar)];
+        }
+    }
+
+    /**
+     * 添加 树节点 并完善该节点的树结构
+     * @param {Object} node - 添加节点
+     * @param {Object} parent - 父项
+     * @returns {*}
+     */
+    addNodeWithParent(node, parent) {
+        parent = parent ? parent : this.parent;
+        if (!parent.children) parent.children = [];
+
+        node.id = this.ctx.app.uuid.v4();
+        node.tender_id = this.ctx.tender.id;
+        node.ledger_id = this.keyNodeId;
+        this.keyNodeId += 1;
+        node.ledger_pid = parent.ledger_id;
+        node.level = parent.level + 1;
+        node.order = parent.children.length + 1;
+        node.full_path = parent.full_path + '-' + node.ledger_id;
+        parent.children.push(node);
+        node.children = [];
+        if (this.defaultData) _.assignIn(node, this.defaultData);
+        this.items.push(node);
+        if (!_.isNil(node.b_code) && node.b_code !== '') {
+            this.codeNodes[node.b_code] = node;
+        } else {
+            this.blankParent = node;
+        }
+        return node;
+    }
+
+    /**
+     * 添加 项目节
+     * @param {Object} node - 项目节
+     * @returns {*}
+     */
+    addNode(node) {
+        if (_.isNil(node.b_code) || node.b_code === '') {
+            return this.addNodeWithParent(node, null);
+        } else if (node.b_code.split(this.splitChar).length > 1) {
+            const parent = this.findParent(node.b_code);
+            return this.addNodeWithParent(node, parent ? parent : this.blankParent);
+        } else {
+            return this.addNodeWithParent(node, this.blankParent);
+        }
+    }
+}
+
+class AnalysisGclExcelTree {
+    /**
+     * 构造函数
+     */
+    constructor(ctx) {
+        this.ctx = ctx;
+        this.colsDef = null;
+        this.colHeaderMatch = {
+            b_code: ['编号', '清单编号', '子目号'],
+            name: ['名称'],
+            unit: ['单位'],
+            sgfh_qty: ['清单数量'], // 施工图复核数量
+            unit_price: ['单价'],
+        };
+    }
+
+    /**
+     * 读取表头并检查
+     * @param {Number} row - Excel数据行
+     */
+    checkColHeader(row) {
+        const colsDef = aeUtils.checkColHeader(row, this.colHeaderMatch);
+        if (colsDef.b_code) {
+            this.colsDef = colsDef;
+        }
+    }
+
+    loadRowData(row) {
+        const node = {};
+        node.b_code = this.ctx.helper.replaceReturn(row[this.colsDef.b_code]);
+        node.name = this.ctx.helper.replaceReturn(row[this.colsDef.name]);
+        if ((_.isNil(node.b_code) || node.b_code === '') && (_.isNil(node.name) || node.name === '')) return node;
+
+        node.unit = this.ctx.helper.replaceReturn(row[this.colsDef.unit]);
+        const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, node.unit);
+        node.sgfh_qty = this.ctx.helper.round(aeUtils.toNumber(row[this.colsDef.sgfh_qty]), precision.value);
+        node.unit_price = aeUtils.toNumber(row[this.colsDef.unit_price]);
+        if (node.sgfh_qty && node.unit_price) {
+            node.sgfh_tp = this.ctx.helper.mul(node.sgfh_qty, node.unit_price, this.ctx.tender.info.decimal.tp);
+        } else {
+            node.sgfh_tp = null;
+        }
+        node.quantity = node.sgfh_qty;
+        node.total_price = node.sgfh_tp;
+        return this.cacheTree.addNode(node);
+    }
+
+    /**
+     * 将excel清单 平面数据 解析为 树结构数据
+     * @param {object} sheet - excel清单数据
+     * @param {Array} parentId - 导入至的节点id
+     * @returns {ImportBaseTree}
+     */
+    analysisData(sheet, parent, maxId, defaultData) {
+        try {
+            this.colsDef = null;
+            this.cacheTree = new ImportGclBaseTree(this.ctx, parent, maxId, defaultData);
+            this.errorData = [];
+            this.loadEnd = false;
+
+            for (const iRow in sheet.rows) {
+                const row = sheet.rows[iRow];
+                if (this.colsDef && !this.loadEnd) {
+                    const result = this.loadRowData(row);
+                    // 读取失败则写入错误数据 todo 返回前端告知用户?
+                    if (!result) {
+                        this.errorData.push({
+                            serialNo: iRow,
+                            data: row,
+                        });
+                    }
+                } else {
+                    this.checkColHeader(row);
+                }
+            }
+            return this.cacheTree;
+        } catch(err) {
+            this.ctx.helper.log(err);
+        }
+    }
+}
+
+module.exports = { AnalysisExcelTree, AnalysisGclExcelTree };

+ 1 - 1
app/middleware/stage_check.js

@@ -103,7 +103,7 @@ module.exports = options => {
             this.stage = stage;
             yield next;
         } catch (err) {
-            console.log(err);
+            this.helper.log(err);
             // 输出错误到日志
             if (err.stack) {
                 this.logger.error(err);

+ 1 - 1
app/middleware/tender_select.js

@@ -46,7 +46,7 @@ module.exports = options => {
                 yield next;
             }
         } catch (err) {
-            console.log(err);
+            this.helper.log(err);
             this.redirect(this.menuList.dashboard.url);
         }
     };

+ 20 - 7
app/public/js/ledger.js

@@ -1005,6 +1005,7 @@ $(document).ready(function() {
                         return !(valid && first && sameParent && !(first.level === 1 && first.node_type));
                     }
                 },
+                'sprBase': '-----------',
                 'copyBlock': {
                     name: '复制整块',
                     icon: 'fa-files-o',
@@ -1058,6 +1059,7 @@ $(document).ready(function() {
                         }
                     }
                 },
+                'sprBlock': '-----------',
                 'batchInsert': {
                     name: '批量插入',
                     type: 'batchInsert',
@@ -1128,6 +1130,7 @@ $(document).ready(function() {
                         $('#batch').modal('show');
                     }
                 },
+                'sprBatch': '-----------',
                 'importExcel': {
                     name: '导入分项清单Excel',
                     icon: 'fa-file-excel-o',
@@ -1141,7 +1144,7 @@ $(document).ready(function() {
                                 url: '/template/导入分项清单EXCEL格式.xls',
                             },
                             callback: function (sheet) {
-                                postDataCompress(window.location.pathname + '/upload-excel', sheet, function (result) {
+                                postDataCompress(window.location.pathname + '/upload-excel/tz', sheet, function (result) {
                                     ledgerTree.loadDatas(result.bills);
                                     treeCalc.calculateAll(ledgerTree);
                                     SpreadJsObj.loadSheetData(ledgerSpread.getActiveSheet(), 'tree', ledgerTree);
@@ -1163,23 +1166,33 @@ $(document).ready(function() {
                             || (!_.isNil(node.b_code) && node.b_code !== '');
                     },
                     callback: function (key, opt) {
+                        const node = SpreadJsObj.getSelectObject(ledgerSpread.getActiveSheet());
                         importExcel.doImport({
                             template: {
                                 hint: '工程量清单',
                                 url: '/template/导入工程量清单EXCEL格式.xls',
                             },
                             callback: function (sheet) {
-                                postDataCompress(window.location.pathname + '/upload-excel', sheet, function (result) {
-                                    ledgerTree.loadDatas(result.bills);
-                                    treeCalc.calculateAll(ledgerTree);
-                                    SpreadJsObj.loadSheetData(ledgerSpread.getActiveSheet(), 'tree', ledgerTree);
-                                    pos.loadDatas(result.pos);
-                                    posOperationObj.loadCurPosData();
+                                postDataCompress(window.location.pathname + '/upload-excel/gcl2xmj', {id: node.id, sheet: sheet}, function (result) {
+                                    const ledgerSheet = ledgerSpread.getActiveSheet();
+                                    const sel = ledgerSheet.getSelections();
+
+                                    const refreshNode = ledgerTree.loadPostData(result);
+                                    treeOperationObj.refreshTree(ledgerSheet, refreshNode);
+                                    if (refreshNode.create[0]) {
+                                        if (sel && sel[0]) {
+                                            ledgerSheet.setSelection(refreshNode.create[0].index, sel[0].col, sel[0].rowCount, sel[0].colCount);
+                                        } else {
+                                            ledgerSheet.setSelection(refreshNode.create[0].index, 0, 1, 1);
+                                        }
+                                    }
+                                    treeOperationObj.refreshOperationValid(ledgerSheet);
                                 }, null);
                             }
                         });
                     }
                 },
+                'sprImport': '-----------',
                 'exportExcel': {
                     name: '导出表格数据',
                     icon: 'fa-file-excel-o',

+ 39 - 1
app/public/js/revise.js

@@ -856,6 +856,7 @@ $(document).ready(() => {
                         return !(valid && first && sameParent && !(first.level === 1 && first.node_type) && !nodeUsed);
                     }
                 },
+                'sprBase': '-----------',
                 'batchInsert': {
                     name: '批量插入',
                     type: 'batchInsert',
@@ -910,7 +911,44 @@ $(document).ready(() => {
                         }
                         $('#batch').modal('show');
                     }
-                }
+                },
+                'sprBatch': '-----------',
+                'importGclBills2Xmj': {
+                    name: '导入工程量清单至项目节',
+                    icon: 'fa-file-excel-o',
+                    disabled: function (key, opt) {
+                        const node = SpreadJsObj.getSelectObject(billsSheet);
+                        return readOnly
+                            || (node.children && node.children.length > 0)
+                            || (!_.isNil(node.b_code) && node.b_code !== '')
+                            || billsTree.checkNodeUsed(node, pos);
+                    },
+                    callback: function (key, opt) {
+                        const node = SpreadJsObj.getSelectObject(billsSheet);
+                        importExcel.doImport({
+                            template: {
+                                hint: '工程量清单',
+                                url: '/template/导入工程量清单EXCEL格式.xls',
+                            },
+                            callback: function (sheet) {
+                                postDataCompress(window.location.pathname + '/upload-excel/gcl2xmj', {id: node.id, sheet: sheet}, function (result) {
+                                    const sel = billsSheet.getSelections();
+
+                                    const refreshNode = billsTree.loadPostData(result);
+                                    billsTreeSpreadObj.refreshTree(billsSheet, refreshNode);
+                                    if (refreshNode.create[0]) {
+                                        if (sel && sel[0]) {
+                                            billsSheet.setSelection(refreshNode.create[0].index, sel[0].col, sel[0].rowCount, sel[0].colCount);
+                                        } else {
+                                            billsSheet.setSelection(refreshNode.create[0].index, 0, 1, 1);
+                                        }
+                                    }
+                                    billsTreeSpreadObj.refreshOperationValid(billsSheet);
+                                }, null);
+                            }
+                        });
+                    }
+                },
             }
         });
     }

+ 0 - 2
app/public/js/tender_list_manage.js

@@ -373,8 +373,6 @@ $(document).ready(() => {
     initTenderTree();
     $('.c-body').html(getTenderTreeHtml());
     bindTenderUrl();
-    console.log(tenderTree);
-    console.log(category);
     // 分类
     $('#cate-set').on('show.bs.modal', function () {
         createTree();

+ 7 - 4
app/router.js

@@ -94,7 +94,7 @@ module.exports = app => {
     app.post('/tender/:id/ledger/load', sessionAuth, tenderCheck, 'ledgerController.loadExplodeData');
     app.post('/tender/:id/ledger/get-children', sessionAuth, tenderCheck, 'ledgerController.getChildren');
     app.post('/tender/:id/ledger/update', sessionAuth, tenderCheck, 'ledgerController.update');
-    app.post('/tender/:id/ledger/upload-excel', sessionAuth, tenderCheck, 'ledgerController.uploadExcel');
+    app.post('/tender/:id/ledger/upload-excel/:ueType', sessionAuth, tenderCheck, 'ledgerController.uploadExcel');
     app.get('/tender/:id/ledger/download/:file', sessionAuth, tenderCheck, 'ledgerController.download');
     //app.post('/tender/:id/pos', sessionAuth, tenderCheck, 'ledgerController.pos');
     app.post('/tender/:id/pos/update', sessionAuth, tenderCheck, 'ledgerController.posUpdate');
@@ -105,21 +105,24 @@ module.exports = app => {
     app.post('/tender/:id/ledger/audit/delete', sessionAuth, tenderCheck, 'ledgerAuditController.remove');
     app.post('/tender/:id/ledger/audit/start', sessionAuth, tenderCheck, 'ledgerAuditController.start');
     app.post('/tender/:id/ledger/audit/check', sessionAuth, tenderCheck, 'ledgerAuditController.check');
+
     // 台账对比
     app.get('/tender/:id/ledger/gather', sessionAuth, tenderCheck, 'ledgerController.gather');
     app.post('/tender/:id/ledger/gather/load', sessionAuth, tenderCheck, 'ledgerController.loadGatherData');
+
     // 台账修订
     app.get('/tender/:id/revise', sessionAuth, tenderCheck, 'reviseController.index');
     app.post('/tender/:id/revise/add', sessionAuth, tenderCheck, 'reviseController.add');
     app.post('/tender/:id/revise/cancel', sessionAuth, tenderCheck, 'reviseController.cancel');
     app.post('/tender/:id/revise/save', sessionAuth, tenderCheck, 'reviseController.save');
-
+    // 台账修订页面
     app.get('/tender/:id/revise/info', sessionAuth, tenderCheck, 'reviseController.info');
     app.post('/tender/:id/revise/info/update', sessionAuth, tenderCheck, 'reviseController.update');
-
+    app.post('/tender/:id/revise/info/upload-excel/:ueType', sessionAuth, tenderCheck, 'reviseController.uploadExcel');
+    // 查看修订数据
     app.get('/tender/:id/revise/history', sessionAuth, tenderCheck, 'reviseController.history');
     app.post('/tender/:id/revise/history/info', sessionAuth, tenderCheck, 'reviseController.historyInfo');
-
+    // 修订审批
     app.post('/tender/:id/revise/audit/add', sessionAuth, tenderCheck, 'reviseController.addAuditor');
     app.post('/tender/:id/revise/audit/remove', sessionAuth, tenderCheck, 'reviseController.removeAuditor');
     app.post('/tender/:id/revise/audit/start', sessionAuth, tenderCheck, 'reviseController.start');

+ 1 - 161
app/service/ledger.js

@@ -282,43 +282,6 @@ module.exports = app => {
             await this.ctx.service.pos.deletePosData(this.transaction, mid, this._.map(deleteData, 'id'));
         }
 
-        /**
-         * 过滤data中update方式不可提交的字段
-         * @param {Number} id - 主键key
-         * @param {Object} data
-         * @return {Object<{id: *}>}
-         * @private
-         */
-        // _filterUpdateInvalidField(id, data) {
-        //     const result = {
-        //         id,
-        //     };
-        //     for (const prop in data) {
-        //         if (readOnlyFields.indexOf(prop) === -1) {
-        //             result[prop] = data[prop];
-        //         }
-        //     }
-        //     return result;
-        // }
-
-        /**
-         * newData中,以orgData为基准,过滤掉orgData中未定义或值相等的部分
-         * @param {Object} orgData
-         * @param {Object} newData
-         * @private
-         */
-        _filterChangedField(orgData, newData) {
-            const result = {};
-            let bChanged = false;
-            for (const prop in orgData) {
-                if (this._.isEmpty(newData[prop]) && newData[prop] !== orgData[prop]) {
-                    result[prop] = newData[prop];
-                    bChanged = true;
-                }
-            }
-            return bChanged ? result : undefined;
-        }
-
         _checkField(data, field) {
             const fields = field instanceof Array ? field : [field];
             for (const prop in data) {
@@ -330,21 +293,6 @@ module.exports = app => {
         }
 
         /**
-         * 检查data中是否含有计算字段
-         * @param {Object} data
-         * @return {boolean}
-         * @private
-         */
-        // _checkCalcField(data) {
-        //     for (const prop in data) {
-        //         if (calcFields.indexOf(prop) >= 0) {
-        //             return true;
-        //         }
-        //     }
-        //     return false;
-        // }
-
-        /**
          * 复制粘贴整块
          * @param {Number} tenderId - 标段Id
          * @param {Number} selectId - 选中几点Id
@@ -451,103 +399,6 @@ module.exports = app => {
         }
 
         /**
-         * 提交数据 - 响应计算(增量方式计算)
-         * @param {Number} tenderId
-         * @param {Object} data
-         * @return {Promise<*>}
-         */
-        // async updateCalc(tenderId, data) {
-        //     // 简单验证数据
-        //     if (tenderId <= 0 || !this.ctx.tender) {
-        //         throw '标段不存在';
-        //     }
-        //     const info = this.ctx.tender.info;
-        //     if (!data) {
-        //         throw '提交数据错误';
-        //     }
-        //     const datas = data instanceof Array ? data : [data];
-        //     const ids = [];
-        //     for (const row of datas) {
-        //         if (tenderId !== row.tender_id) {
-        //             throw '提交数据错误';
-        //         }
-        //         ids.push(row.id);
-        //     }
-        //
-        //     this.transaction = await this.db.beginTransaction();
-        //     try {
-        //         for (const row of datas) {
-        //             const updateNode = await this.getDataById(row.id);
-        //             if (!updateNode || tenderId !== updateNode.tender_id || row.ledger_id !== updateNode.ledger_id) {
-        //                 throw '提交数据错误';
-        //             }
-        //             let updateData;
-        //             if (row.unit) {
-        //                 if (row.sgfh_qty === undefined) { row.sgfh_qty = updateNode.sgfh_qty; }
-        //                 if (row.sjcl_qty === undefined) { row.sjcl_qty = updateNode.sjcl_qty; }
-        //                 if (row.qtcl_qty === undefined) { row.qtcl_qty = updateNode.qtcl_qty; }
-        //                 if (row.deal_qty === undefined) { row.deal_qty = updateNode.deal_qty; }
-        //             }
-        //             if (row.b_code) {
-        //                 row.dgn_qty1 = null;
-        //                 row.dgn_qty2 = null;
-        //             }
-        //             if (this._checkCalcField(row)) {
-        //                 let calcData = JSON.parse(JSON.stringify(row));
-        //                 const precision = this.ctx.helper.findPrecision(info.precision, row.unit ? row.unit : updateNode.unit);
-        //                 // 数量保留小数位数
-        //                 this.ctx.helper.checkFieldPrecision(calcData, qtyFields, precision.value);
-        //                 // 单位保留小数位数
-        //                 this.ctx.helper.checkFieldPrecision(calcData, upFields, info.decimal.up);
-        //                 // 未提交单价则读取数据库单价
-        //                 if (row.unit_price === undefined) calcData.unit_price = updateNode.unit_price;
-        //                 // 计算
-        //                 if (row.sgfh_qty !== undefined || row.sjcl_qty !== undefined || row.qtcl_qty !== undefined ||
-        //                     row.deal_qty !== undefined || row.unit_price) {
-        //                     if (row.sgfh_qty === undefined) calcData.sgfh_qty = updateNode.sgfh_qty;
-        //                     if (row.sjcl_qty === undefined) calcData.sjcl_qty = updateNode.sjcl_qty;
-        //                     if (row.qtcl_qty === undefined) calcData.qtcl_qty = updateNode.qtcl_qty;
-        //                     if (row.deal_qty === undefined) calcData.deal_qty = updateNode.deal_qty;
-        //                     calcData.quantity = this.ctx.helper.sum([calcData.sgfh_qty, calcData.sjcl_qty, calcData.qtcl_qty]);
-        //                     calcData.sgfh_tp = this.ctx.helper.mul(calcData.sgfh_qty, calcData.unit_price, info.decimal.tp);
-        //                     calcData.sjcl_tp = this.ctx.helper.mul(calcData.sjcl_qty, calcData.unit_price, info.decimal.tp);
-        //                     calcData.qtcl_tp = this.ctx.helper.mul(calcData.qtcl_qty, calcData.unit_price, info.decimal.tp);
-        //                     calcData.total_price = this.ctx.helper.mul(calcData.quantity, calcData.unit_price, info.decimal.tp);
-        //                     calcData.deal_tp = this.ctx.helper.mul(calcData.deal_qty, calcData.unit_price, info.decimal.tp);
-        //                 } else if (row.sgfh_tp !== undefined || row.sjcl_tp !== undefined || row.qtcl_tp !== undefined || row.deal_tp !== undefined) {
-        //                     calcData.sgfh_qty = null;
-        //                     calcData.sjcl_qty = null;
-        //                     calcData.qtcl_qty = null;
-        //                     calcData.quantity = null;
-        //                     calcData.deal_qty = null;
-        //                     calcData.sgfh_tp = (row.sgfh_tp !== undefined) ? this.ctx.helper.round(calcData.row.sgfh_tp, info.decimal.tp) : updateNode.sgfh_tp;
-        //                     calcData.sjcl_tp = (row.sgfh_tp !== undefined) ? this.ctx.helper.round(calcData.row.sjcl_tp, info.decimal.tp) : updateNode.sjcl_tp;
-        //                     calcData.qtcl_tp = (row.sgfh_tp !== undefined) ? this.ctx.helper.round(calcData.row.qtcl_tp, info.decimal.tp) : updateNode.qtcl_tp;
-        //                     calcData.total_price = this.ctx.helper.sum([calcData.sgfh_tp, calcData.sjcl_tp, calcData.qtcl_tp]);
-        //                     calcData.deal_tp = (row.deal_tp !== undefined) ? this.ctx.helper.round(calcData.row.deal_tp, info.decimal.tp) : updateNode.deal_tp;
-        //                 } else if (row.unit_price !== undefined) {
-        //                     calcData.sgfh_tp = this.ctx.helper.mul(calcData.sgfh_qty, calcData.unit_price, info.decimal.tp);
-        //                     calcData.sjcl_tp = this.ctx.helper.mul(calcData.sjcl_qty, calcData.unit_price, info.decimal.tp);
-        //                     calcData.qtcl_tp = this.ctx.helper.mul(calcData.qtcl_qty, calcData.unit_price, info.decimal.tp);
-        //                     calcData.total_price = this.ctx.helper.mul(calcData.quantity, calcData.unit_price, info.decimal.tp);
-        //                     calcData.deal_tp = this.ctx.helper.mul(calcData.deal_qty, calcData.unit_price, info.decimal.tp);
-        //                 }
-        //                 updateData = this._filterUpdateInvalidField(updateNode.id, calcData);
-        //             } else {
-        //                 updateData = this._filterUpdateInvalidField(updateNode.id, row);
-        //             }
-        //             await this.transaction.update(this.tableName, updateData);
-        //         }
-        //         await this.transaction.commit();
-        //     } catch (err) {
-        //         await this.transaction.rollback();
-        //         throw err;
-        //     }
-        //
-        //     return { update: await this.getDataByIds(ids) };
-        // }
-
-        /**
          *
          * @param tenderId
          * @param xmj
@@ -821,24 +672,16 @@ module.exports = app => {
          * @returns {Promise<void>}
          */
         async importExcel(templateId, excelData) {
-            console.time('analysis');
-            const AnalysisExcel = require('../lib/analysis_excel');
+            const AnalysisExcel = require('../lib/analysis_excel').AnalysisExcelTree;
             const analysisExcel = new AnalysisExcel(this.ctx);
             const tempData = await this.ctx.service.tenderNodeTemplate.getData(templateId, true);
             const cacheTree = analysisExcel.analysisData(excelData, tempData);
             const cacheKey = keyPre + this.ctx.tender.id;
             const orgMaxId = parseInt(await this.cache.get(cacheKey));
-            console.timeEnd('analysis');
             const transaction = await this.db.beginTransaction();
             try {
-                console.time('deleteBills');
                 await transaction.delete(this.tableName, {tender_id: this.ctx.tender.id});
-                console.timeEnd('deleteBills');
-                console.time('deletePos');
                 await transaction.delete(this.ctx.service.pos.tableName, {tid: this.ctx.tender.id});
-                console.timeEnd('deletePos');
-                console.time('insertBills');
-                //const bills = await this._importCacheTreeNodes(transaction, cacheTree.items);
                 const datas = [];
                 for (const node of cacheTree.items) {
                     datas.push({
@@ -866,12 +709,9 @@ module.exports = app => {
                     });
                 }
                 await transaction.insert(this.tableName, datas);
-                console.timeEnd('insertBills');
-                console.time('insertPos');
                 if (cacheTree.pos && cacheTree.pos.length > 0) {
                     await transaction.insert(this.ctx.service.pos.tableName, cacheTree.pos);
                 }
-                console.timeEnd('insertPos');
                 await transaction.commit();
                 this.cache.set(cacheKey, cacheTree.items.length + 1, 'EX', this.ctx.app.config.cacheTime);
                 return {bills: datas, pos: cacheTree.pos}

+ 0 - 2
app/service/stage_pay.js

@@ -93,7 +93,6 @@ module.exports = app => {
                     throw '标段数据有误';
                 }
                 const prePays = await this.getStageLastestPays(preStage.id);
-                console.log(prePays.length);
                 for (const pp of prePays) {
                     const p = this._.find(pays, {id: pp.pid});
                     stagePays.push({
@@ -105,7 +104,6 @@ module.exports = app => {
                         pre_finish: pp.pre_finish || (pp.rprice ? pp.end_tp === pp.rprice : false),
                     });
                 }
-                console.log(stagePays.length);
             } else {
                 for (const p of pays) {
                     stagePays.push({

+ 1 - 1
app/service/tender.js

@@ -291,7 +291,7 @@ module.exports = app => {
                 await transaction.commit();
                 return true;
             } catch (err) {
-                console.log(err);
+                this.ctx.helper.log(err);
                 await transaction.rollback();
                 return false;
             }

+ 1 - 0
app/view/revise/info_modal.ejs

@@ -477,6 +477,7 @@
 </div>
 <% } %>
 <% include ../shares/merge_peg_modal.ejs %>
+<% include ../shares/import_excel_modal.ejs %>
 <script>
     <% if (ctx.session.sessionUser.accountId === revise.uid && (revise.status === audit.status.uncheck || revise.status === audit.status.checkNo)) { %>
     const accountList = JSON.parse('<%- JSON.stringify(accountList) %>');

+ 16 - 13
app/view/shares/import_excel_modal.ejs

@@ -1,3 +1,4 @@
+<!--依赖xlsx/jQuery-->
 <!--导入清单Excel-->
 <div class="modal fade" id="import-excel" data-backdrop="static" enctype="multipart/form-data">
     <div class="modal-dialog" role="document">
@@ -25,6 +26,7 @@
 </div>
 <script>
     const importExcel = (function () {
+        let callback;
         // 选择excel文件后,加载全部sheet
         $('#import-excel-file').change(function () {
             if (this.files.length === 0) {
@@ -68,24 +70,24 @@
             }
         });
         // 清除上一次数据
-        $('#upload-ledger').bind('hidden.bs.modal', function () {
+        $('#import-excel').bind('hidden.bs.modal', function () {
             $('#import-excel-file').val('');
             $('#excel-sheets').html('');
         });
 
+        // 上传excel内容,并导入
+        $('#import-excel-ok').click(function () {
+            const sheetName = $('input[name=sheetName]:checked').val();
+            if (sheetName) {
+                const sheet = {
+                    rows: xlsxUtils.getSheetByName(sheetName, {header: 1}),
+                    merge: xlsxUtils._wb.Sheets[sheetName]["!merges"]
+                };
+                if (callback) callback(sheet);
+                $('#import-excel').modal('hide');
+            }
+        });
         const doImport = function (setting) {
-            // 上传excel内容,并导入
-            $('#import-excel-ok').click(function () {
-                const sheetName = $('input[name=sheetName]:checked').val();
-                if (sheetName) {
-                    const sheet = {
-                        rows: xlsxUtils.getSheetByName(sheetName, {header: 1}),
-                        merge: xlsxUtils._wb.Sheets[sheetName]["!merges"]
-                    };
-                    setting.callback(sheet);
-                    $('#import-excel').modal('hide');
-                }
-            });
             if (setting.template) {
                 $('#import-template').show();
                 $('#import-type-hint').html(setting.template.hint);
@@ -94,6 +96,7 @@
                 $('#import-template').hide();
             }
             $('#import-excel').modal('show');
+            callback = setting.callback;
         }
         return { doImport };
     })();

+ 2 - 0
config/web.js

@@ -195,6 +195,8 @@ const JsFiles = {
         revise: {
             info: {
                 files: [
+                    "/public/js/js-xlsx/xlsx.full.min.js",
+                    "/public/js/js-xlsx/xlsx.utils.js",
                     "/public/js/spreadjs/sheets/gc.spread.sheets.all.10.0.1.min.js",
                     "/public/js/decimal.min.js",
                     "/public/js/math.min.js",