Browse Source

1. 调整台账、部位明细主键,相关表字段、代码等
2. 台账修订1.0
2.1 台账修订页面(新增、作废)修订详细页面)

MaiXinRong 6 years ago
parent
commit
78f4ec14c0

+ 8 - 0
app/base/base_controller.js

@@ -138,6 +138,14 @@ class BaseController extends Controller {
             throw '该模式下不可提交此数据';
             throw '该模式下不可提交此数据';
         }
         }
     }
     }
+
+    ajaxErrorBody(error, msg) {
+        if (error.stack) {
+            return {err: 2, msg: msg, data: null};
+        } else {
+            return {err: 1, msg: err.toString(), data: null};
+        }
+    }
 }
 }
 
 
 module.exports = BaseController;
 module.exports = BaseController;

+ 2 - 1
app/base/base_service.js

@@ -111,7 +111,8 @@ class BaseService extends Service {
     }
     }
 
 
     async defaultUpdate(data, options) {
     async defaultUpdate(data, options) {
-        await this.db.update(this.tableName, data, options);
+        const result = await this.db.update(this.tableName, data, options);
+        return result;
     }
     }
 
 
     /**
     /**

+ 6 - 1
app/const/audit.js

@@ -52,7 +52,12 @@ const revise = (function () {
         checked: 3, // 审批通过
         checked: 3, // 审批通过
         checkNo: 4, // 审批退回
         checkNo: 4, // 审批退回
     };
     };
-    return { status }
+    const statusString = [];
+    statusString[status.uncheck] = '草稿';
+    statusString[status.checking] = '审批中';
+    statusString[status.checked] = '完成';
+    statusString[status.checkNo] = '退回';
+    return { status, statusString }
 })();
 })();
 
 
 // 期审批流程
 // 期审批流程

+ 116 - 3
app/controller/ledger_controller.js

@@ -658,9 +658,11 @@ module.exports = app => {
 
 
         async _getAddReviseValid(ctx) {
         async _getAddReviseValid(ctx) {
             const stage  = await ctx.service.stage.getLastestStage(ctx.tender.id, true);
             const stage  = await ctx.service.stage.getLastestStage(ctx.tender.id, true);
+            const revise = await ctx.service.ledgerRevise.getLastestRevise(ctx.tender.id);
             return (ctx.tender.data.user_id === ctx.session.sessionUser.accountId) &&
             return (ctx.tender.data.user_id === ctx.session.sessionUser.accountId) &&
                 (ctx.tender.data.ledger_status === auditConst.status.checked) &&
                 (ctx.tender.data.ledger_status === auditConst.status.checked) &&
-                (!stage || stage.status === audit.stage.status.checked);
+                (!stage || stage.status === audit.stage.status.checked) &&
+                (!revise || !revise.valid || revise.status === audit.revise.status.checked);
         }
         }
 
 
         /**
         /**
@@ -695,6 +697,11 @@ module.exports = app => {
             }
             }
         }
         }
 
 
+        /**
+         * 新增 修订 (Post)
+         * @param ctx
+         * @returns {Promise<void>}
+         */
         async addRevise(ctx) {
         async addRevise(ctx) {
             try {
             try {
                 const addValid = await this._getAddReviseValid(ctx);
                 const addValid = await this._getAddReviseValid(ctx);
@@ -702,18 +709,90 @@ module.exports = app => {
                     throw '无法新增修订';
                     throw '无法新增修订';
                 }
                 }
                 const revise = await ctx.service.ledgerRevise.add(ctx.tender.id, ctx.session.sessionUser.accountId);
                 const revise = await ctx.service.ledgerRevise.add(ctx.tender.id, ctx.session.sessionUser.accountId);
-                console.log(3);
+
+                ctx.redirect('/tender/' + ctx.tender.id + '/ledger/revise/info');
+            } catch(err) {
+                this.log(err);
+                ctx.redirect(ctx.request.header.referer);
+            }
+        }
+
+        /**
+         * 作废 修订 (Post)
+         * @param ctx
+         * @returns {Promise<void>}
+         */
+        async cancelRevise(ctx) {
+            try {
+                const revise = await ctx.service.ledgerRevise.getLastestRevise(ctx.tender.id);
+                if (revise.uid !== ctx.session.sessionUser.accountId) {
+                    throw '您无权作废该修订';
+                }
+                if (revise.status === audit.revise.checking) {
+                    throw '修订审批中,不可作废';
+                } else if (revise.status === audit.revise.checked) {
+                    throw '修订已审批通过,不可作废';
+                }
+                if (revise.valid) {
+                    const result = await ctx.service.ledgerRevise.cancelRevise(revise.id);
+                }
 
 
                 ctx.redirect('/tender/' + ctx.tender.id + '/ledger/revise/');
                 ctx.redirect('/tender/' + ctx.tender.id + '/ledger/revise/');
-                //ctx.redirect('/tender/' + ctx.tender.id + '/ledger/revise/' + revise.id + '/info');
             } catch(err) {
             } catch(err) {
                 this.log(err);
                 this.log(err);
                 ctx.redirect(ctx.request.header.referer);
                 ctx.redirect(ctx.request.header.referer);
             }
             }
         }
         }
 
 
+        async _getDefaultReviseInfoData(ctx, revise) {
+            const reviseBills = await ctx.service.reviseBills.getData(ctx.tender.id, revise.id);
+            const revisePos = await ctx.service.revisePos.getData(ctx.tender.id, revise.id);
+            const [ledgerSpread, posSpread] = this._getSpreadSetting();
+            return {
+                revise: revise, tender: ctx.tender.data,
+                reviseBills, revisePos, ledgerSpread, posSpread, tenderMenu,
+                preUrl: '/tender/' + ctx.tender.id,
+                audit: audit.revise,
+                jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.ledger.revise),
+            };
+        }
+
+        async _getHistoryReviseInfo(ctx, revise) {
+            const renderData = await this._getDefaultReviseInfoData(ctx, revise);
+            renderData.ledgerSpread.readOnly = true;
+            renderData.posSpread.readOnly = true;
+            renderData.readOnly = true;
+            renderData.history = true;
+            renderData.historyRevise = await ctx.service.ledgerRevise.getReviseList(ctx.tender.id);
+            await this.layout('ledger/revise_info.ejs', renderData, 'ledger/revise_info_modal.ejs');
+        }
+
+        async _getReviseInfo(ctx, revise) {
+            const renderData = await this._getDefaultReviseInfoData(ctx, revise);
+            const readOnly = revise.status === audit.revise.status.checking || revise.status === audit.revise.status.checked || revise.status.uid !== ctx.session.sessionUser.accountId;
+            if (readOnly) {
+                renderData.ledgerSpread.readOnly = true;
+                renderData.posSpread.readOnly = true;
+            }
+            renderData.readOnly = readOnly;
+            renderData.history = false;
+            renderData.historyRevise = [];
+            await this.layout('ledger/revise_info.ejs', renderData, 'ledger/revise_info_modal.ejs');
+        }
+
+        /**
+         * 修订 详细页面(Get)
+         * @param ctx
+         * @returns {Promise<void>}
+         */
         async reviseInfo(ctx) {
         async reviseInfo(ctx) {
             try {
             try {
+                const revise = await ctx.service.ledgerRevise.getLastestRevise(ctx.tender.id);
+                if (revise.status === audit.revise.status.checked) {
+                    await this._getHistoryReviseInfo(ctx);
+                } else {
+                    await this._getReviseInfo(ctx, revise);
+                }
             } catch (err) {
             } catch (err) {
                 this.log(err);
                 this.log(err);
                 ctx.redirect(ctx.request.header.referer);
                 ctx.redirect(ctx.request.header.referer);
@@ -721,6 +800,40 @@ module.exports = app => {
         }
         }
 
 
         /**
         /**
+         * 保存 修订详情 (Ajax-post)
+         * @param ctx
+         * @returns {Promise<void>}
+         */
+        async saveRevise(ctx) {
+            try {
+                const revise = await ctx.service.ledgerRevise.getLastestRevise(ctx.tender.id);
+                if (!revise.valid) {
+                    throw '该修订已作废';
+                } else if (revise.status === audit.revise.status.uncheck || revise.status === audit.revise.status.checkNo) {
+                    if (ctx.session.sessionUser.accountId !== revise.uid) {
+                        throw '您无权修改';
+                    }
+                } else if (revise.status === audit.revise.status.checking) {
+                    throw '修订在审批中,不可修改修订数据';
+                } else if (revise.staut === audit.revise.status.checked) {
+                    throw '修订已经审批通过,不可修改修订数据,请新增下一修订';
+                }
+                const data = JSON.parse(ctx.request.body.data);
+                if (data.content === undefined) {
+                    throw '保存数据有误'
+                }
+                const result = await ctx.service.ledgerRevise.defaultUpdate({id: revise.id, content: data.content});
+                if (result.affectedRows !== 1) {
+                    throw '保存数据失败,请重试';
+                }
+                ctx.body = {err: 0, msg: '', data: null};
+            } catch(err) {
+                this.log(err);
+                ctx.body = this.ajaxErrorBody(err, '保存数据失败,请重试');
+            }
+        }
+
+        /**
          * 计量台账页面 (Get)
          * 计量台账页面 (Get)
          *
          *
          * @param {object} ctx - egg全局变量
          * @param {object} ctx - egg全局变量

+ 14 - 0
app/extend/helper.js

@@ -678,5 +678,19 @@ module.exports = {
      */
      */
     replaceReturn(str) {
     replaceReturn(str) {
         return str ? str.replace(/[\r\n]/g, '') : str;
         return str ? str.replace(/[\r\n]/g, '') : str;
+    },
+
+    /**
+     * 获取 字符串 数组的 mysql 筛选条件
+     *
+     * @param arr
+     * @returns {*}
+     */
+    getInArrStrSqlFilter(arr) {
+        const self = this;
+        const arrEs = _.forIn(arr, function (a) {
+            return self.ctx.app.mysql.escape(a);
+        });
+        return arrEs.join(',');
     }
     }
 };
 };

+ 3 - 0
app/lib/analysis_excel.js

@@ -132,6 +132,7 @@ class ImportBaseTree {
      * @returns {*}
      * @returns {*}
      */
      */
     addXmjNode(node) {
     addXmjNode(node) {
+        node.id = this.ctx.app.uuid.v4();
         node.tender_id = this.ctx.tender.id;
         node.tender_id = this.ctx.tender.id;
         node.children = [];
         node.children = [];
         if (node.code.split(this.splitChar).length > 1) {
         if (node.code.split(this.splitChar).length > 1) {
@@ -159,6 +160,7 @@ class ImportBaseTree {
      * @param {Object} node - 工程量清单
      * @param {Object} node - 工程量清单
      */
      */
     addGclNode(node) {
     addGclNode(node) {
+        node.id = this.ctx.app.uuid.v4();
         node.tender_id = this.ctx.tender.id;
         node.tender_id = this.ctx.tender.id;
         node.pos = [];
         node.pos = [];
         if (this.finalXmjNode) {
         if (this.finalXmjNode) {
@@ -173,6 +175,7 @@ class ImportBaseTree {
      */
      */
     addPos (pos){
     addPos (pos){
         if (this.finalNode && this.finalNode.pos) {
         if (this.finalNode && this.finalNode.pos) {
+            pos.id = this.ctx.app.uuid.v4();
             pos.tid = this.ctx.tender.id;
             pos.tid = this.ctx.tender.id;
             pos.add_stage = 0;
             pos.add_stage = 0;
             pos.add_times = 0;
             pos.add_times = 0;

+ 33 - 0
app/public/js/revise.js

@@ -0,0 +1,33 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+$(document).ready(() => {
+    autoFlashHeight();
+    const billsSpread = SpreadJsObj.createNewSpread($('#bills-spread')[0]);
+    const billsSheet = billsSpread.getActiveSheet();
+    SpreadJsObj.initSheet(billsSheet, billsSpreadSetting);
+    const posSpread = SpreadJsObj.createNewSpread($('#pos-spread')[0]);
+    const posSheet = posSpread.getActiveSheet();
+    SpreadJsObj.initSheet(posSheet, posSpreadSetting);
+    $.divResizer({
+        select: '#revise-resize',
+        callback: function () {
+            billsSpread.refresh();
+            let bcontent = $(".bcontent-wrap") ? $(".bcontent-wrap").height() : 0;
+            $(".sp-wrap").height(bcontent-40);
+            posSpread.refresh();
+        }
+    });
+    // 修订详情 保存
+    $('#save').click(function () {
+        const content = $('textarea').val();
+        postData('save', { content: content });
+    });
+});

+ 6 - 2
app/router.js

@@ -97,10 +97,14 @@ module.exports = app => {
     app.post('/tender/:id/pos', sessionAuth, tenderCheck, 'ledgerController.pos');
     app.post('/tender/:id/pos', sessionAuth, tenderCheck, 'ledgerController.pos');
     app.post('/tender/:id/pos/update', sessionAuth, tenderCheck, 'ledgerController.posUpdate');
     app.post('/tender/:id/pos/update', sessionAuth, tenderCheck, 'ledgerController.posUpdate');
     app.post('/tender/:id/pos/paste', sessionAuth, tenderCheck, 'ledgerController.posPaste');
     app.post('/tender/:id/pos/paste', sessionAuth, tenderCheck, 'ledgerController.posPaste');
-
+    // 台账修订
     app.get('/tender/:id/ledger/revise', sessionAuth, tenderCheck, 'ledgerController.revise');
     app.get('/tender/:id/ledger/revise', sessionAuth, tenderCheck, 'ledgerController.revise');
     app.post('/tender/:id/ledger/revise/add', sessionAuth, tenderCheck, 'ledgerController.addRevise');
     app.post('/tender/:id/ledger/revise/add', sessionAuth, tenderCheck, 'ledgerController.addRevise');
-    app.get('/tender/:id/ledger/index', sessionAuth, 'ledgerController.index');
+    app.post('/tender/:id/ledger/revise/cancel', sessionAuth, tenderCheck, 'ledgerController.cancelRevise');
+    app.post('/tender/:id/ledger/revise/save', sessionAuth, tenderCheck, 'ledgerController.saveRevise');
+    app.get('/tender/:id/ledger/revise/info', sessionAuth, tenderCheck, 'ledgerController.reviseInfo');
+    //app.post('/tender/:id/ledger/revise/audit/', sessionAuth, tenderCheck, 'ledgerController.reviseStatus');
+    //app.get('/tender/:id/ledger/index', sessionAuth, 'ledgerController.index');
 
 
     // 台账审批相关
     // 台账审批相关
     app.get('/tender/:id/ledger/audit', sessionAuth, tenderCheck, 'ledgerAuditController.index');
     app.get('/tender/:id/ledger/audit', sessionAuth, tenderCheck, 'ledgerAuditController.index');

+ 26 - 15
app/service/ledger.js

@@ -70,6 +70,7 @@ module.exports = app => {
                 tmp.tender_id = tenderId;
                 tmp.tender_id = tenderId;
                 delete tmp.id;
                 delete tmp.id;
                 delete tmp.pid;
                 delete tmp.pid;
+                tmp.id = this.uuid.v4();
                 insertData.push(tmp);
                 insertData.push(tmp);
             }
             }
             const operate = await transaction.insert(this.tableName, insertData);
             const operate = await transaction.insert(this.tableName, insertData);
@@ -180,7 +181,9 @@ module.exports = app => {
             const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
             const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
             const data = await this.db.query(sql, sqlParam);
             const data = await this.db.query(sql, sqlParam);
 
 
-            return data;
+            return this._.sortBy(data, function (d) {
+                return nodesIds.indexOf(d.ledger_id);
+            });
         }
         }
         /**
         /**
          * 根据主键id获取数据
          * 根据主键id获取数据
@@ -624,6 +627,7 @@ module.exports = app => {
                 this.cache.set(cacheKey, maxId, 'EX', this.ctx.app.config.cacheTime);
                 this.cache.set(cacheKey, maxId, 'EX', this.ctx.app.config.cacheTime);
             }
             }
 
 
+            data.id = this.uuid.v4();
             data.tender_id = tenderId;
             data.tender_id = tenderId;
             data.ledger_id = maxId + 1;
             data.ledger_id = maxId + 1;
             data.ledger_pid = selectData.ledger_pid;
             data.ledger_pid = selectData.ledger_pid;
@@ -661,6 +665,7 @@ module.exports = app => {
             }
             }
             this.cache.set(cacheKey, maxId + 1, 'EX', this.ctx.app.config.cacheTime);
             this.cache.set(cacheKey, maxId + 1, 'EX', this.ctx.app.config.cacheTime);
 
 
+            data.id = this.uuid.v4();
             data.tender_id = tenderId;
             data.tender_id = tenderId;
             data.ledger_id = maxId + 1;
             data.ledger_id = maxId + 1;
             data.ledger_pid = pid;
             data.ledger_pid = pid;
@@ -804,6 +809,7 @@ module.exports = app => {
                 this.cache.set(cacheKey, maxId, 'EX', this.ctx.app.config.cacheTime);
                 this.cache.set(cacheKey, maxId, 'EX', this.ctx.app.config.cacheTime);
             }
             }
 
 
+            data.id = this.uuid.v4();
             data.tender_id = tenderId;
             data.tender_id = tenderId;
             data.ledger_id = maxId + 1;
             data.ledger_id = maxId + 1;
             data.ledger_pid = selectData.ledger_id;
             data.ledger_pid = selectData.ledger_id;
@@ -1516,8 +1522,10 @@ module.exports = app => {
                 // 选中节点的所有后兄弟节点,order+粘贴节点个数
                 // 选中节点的所有后兄弟节点,order+粘贴节点个数
                 await this._updateSelectNextsOrder(selectData, copyNodes.length);
                 await this._updateSelectNextsOrder(selectData, copyNodes.length);
                 // 数据库创建新增节点数据
                 // 数据库创建新增节点数据
-                for (const node of copyNodes) {
-                    const datas = await this.getDataByFullPath(tenderId, node.full_path + '%');
+                for (let iNode = 0; iNode < copyNodes.length; iNode++) {
+                    const node = copyNodes[iNode];
+                    let datas = await this.getDataByFullPath(tenderId, node.full_path + '%');
+                    datas = this._.sortBy(datas, 'level');
 
 
                     const cacheKey = keyPre + this.ctx.tender.id;
                     const cacheKey = keyPre + this.ctx.tender.id;
                     let maxId = parseInt(await this.cache.get(cacheKey));
                     let maxId = parseInt(await this.cache.get(cacheKey));
@@ -1534,7 +1542,8 @@ module.exports = app => {
                         const idChange = {
                         const idChange = {
                             org: data.id,
                             org: data.id,
                         };
                         };
-                        delete data.id;
+                        data.id = this.uuid.v4();
+                        idChange.new = data.id;
                         data.tender_id = this.ctx.tender.id;
                         data.tender_id = this.ctx.tender.id;
                         if (!data.is_leaf) {
                         if (!data.is_leaf) {
                             for (const children of datas) {
                             for (const children of datas) {
@@ -1548,18 +1557,17 @@ module.exports = app => {
                         }
                         }
                         data.ledger_id = newId;
                         data.ledger_id = newId;
                         data.full_path = data.full_path.replace(orgParentPath, newParentPath);
                         data.full_path = data.full_path.replace(orgParentPath, newParentPath);
-                        if (data.ledger_pid === copyNodes[0].ledger_pid) {
+                        if (data.ledger_pid === node.ledger_pid) {
                             data.ledger_pid = selectData.ledger_pid;
                             data.ledger_pid = selectData.ledger_pid;
-                            data.order = selectData.order + index + 1;
+                            data.order = selectData.order + iNode + 1;
                         }
                         }
                         data.level = data.level + selectData.level - copyNodes[0].level;
                         data.level = data.level + selectData.level - copyNodes[0].level;
-                        const newData = await this.transaction.insert(this.tableName, data);
                         if (data.is_leaf) {
                         if (data.is_leaf) {
-                            idChange.new = newData.insertId;
                             leafBillsId.push(idChange);
                             leafBillsId.push(idChange);
                         }
                         }
-                        newIds.push(newData.insertId);
+                        newIds.push(data.id);
                     }
                     }
+                    const newData = await this.transaction.insert(this.tableName, datas);
                     for (const id of leafBillsId) {
                     for (const id of leafBillsId) {
                         await this.ctx.service.pos.copyBillsPosData(id.org, id.new, this.transaction);
                         await this.ctx.service.pos.copyBillsPosData(id.org, id.new, this.transaction);
                     }
                     }
@@ -1809,6 +1817,7 @@ module.exports = app => {
                 for (let i = 0, iLen = data.length; i < iLen; i++) {
                 for (let i = 0, iLen = data.length; i < iLen; i++) {
                     // 合并新增数据
                     // 合并新增数据
                     const qd = {
                     const qd = {
+                        id: this.uuid.v4(),
                         tender_id: tenderId,
                         tender_id: tenderId,
                         ledger_id: maxId + i + 1,
                         ledger_id: maxId + i + 1,
                         ledger_pid: selectData.ledger_id,
                         ledger_pid: selectData.ledger_id,
@@ -1822,8 +1831,7 @@ module.exports = app => {
                     };
                     };
                     qd.full_path = selectData.full_path + '.' + qd.ledger_id;
                     qd.full_path = selectData.full_path + '.' + qd.ledger_id;
                     const insertResult = await this.transaction.insert(this.tableName, qd);
                     const insertResult = await this.transaction.insert(this.tableName, qd);
-                    qd.id = insertResult.insertId;
-                    newIds.push(insertResult.insertId);
+                    newIds.push(qd.id);
                     if (data[i].pos.length > 0) {
                     if (data[i].pos.length > 0) {
                         await this.ctx.service.pos.insertLedgerPosData(this.transaction, tenderId, qd, data[i].pos);
                         await this.ctx.service.pos.insertLedgerPosData(this.transaction, tenderId, qd, data[i].pos);
                         await this._calcNode(qd, this.transaction);
                         await this._calcNode(qd, this.transaction);
@@ -1882,6 +1890,7 @@ module.exports = app => {
                 for (let i = 0, iLen = data.length; i < iLen; i++) {
                 for (let i = 0, iLen = data.length; i < iLen; i++) {
                     // 合并新增数据
                     // 合并新增数据
                     const qd = {
                     const qd = {
+                        id: this.uuid.v4(),
                         tender_id: tenderId,
                         tender_id: tenderId,
                         ledger_id: maxId + i + 1,
                         ledger_id: maxId + i + 1,
                         ledger_pid: parentData.ledger_id,
                         ledger_pid: parentData.ledger_id,
@@ -1895,8 +1904,7 @@ module.exports = app => {
                     };
                     };
                     qd.full_path = parentData.full_path + '.' + qd.ledger_id;
                     qd.full_path = parentData.full_path + '.' + qd.ledger_id;
                     const insertResult = await this.transaction.insert(this.tableName, qd);
                     const insertResult = await this.transaction.insert(this.tableName, qd);
-                    qd.id = insertResult.insertId;
-                    newIds.push(insertResult.insertId);
+                    newIds.push(qd.id);
                     if (data[i].pos.length > 0) {
                     if (data[i].pos.length > 0) {
                         await this.ctx.service.pos.insertLedgerPosData(this.transaction, tenderId, qd, data[i].pos);
                         await this.ctx.service.pos.insertLedgerPosData(this.transaction, tenderId, qd, data[i].pos);
                         await this._calcNode(qd, this.transaction);
                         await this._calcNode(qd, this.transaction);
@@ -1975,6 +1983,7 @@ module.exports = app => {
 
 
         async _importCacheTreeNode(transaction, node) {
         async _importCacheTreeNode(transaction, node) {
             const data = {
             const data = {
+                id: this.uuid.v4(),
                 tender_id: this.ctx.tender.id,
                 tender_id: this.ctx.tender.id,
                 ledger_id: node.ledger_id,
                 ledger_id: node.ledger_id,
                 ledger_pid: node.ledger_pid,
                 ledger_pid: node.ledger_pid,
@@ -1997,7 +2006,7 @@ module.exports = app => {
                 drawing_code: node.drawing_code,
                 drawing_code: node.drawing_code,
             };
             };
             const result = await transaction.insert(this.tableName, data);
             const result = await transaction.insert(this.tableName, data);
-            data.id = result.insertId;
+            //data.id = result.insertId;
             if (node.children && node.children.length > 0) {
             if (node.children && node.children.length > 0) {
                 for (const child of node.children) {
                 for (const child of node.children) {
                     await this._importCacheTreeNode(transaction, child);
                     await this._importCacheTreeNode(transaction, child);
@@ -2007,7 +2016,8 @@ module.exports = app => {
             }
             }
             if (node.pos && node.pos.length > 0) {
             if (node.pos && node.pos.length > 0) {
                 for (const p of node.pos) {
                 for (const p of node.pos) {
-                    p.lid = result.insertId;
+                    //p.lid = result.insertId;
+                    p.lid = node.id;
                 }
                 }
             }
             }
         }
         }
@@ -2016,6 +2026,7 @@ module.exports = app => {
             const datas = [];
             const datas = [];
             for (const node of nodes) {
             for (const node of nodes) {
                 datas.push({
                 datas.push({
+                    id: this.uuid.v4(),
                     tender_id: this.ctx.tender.id,
                     tender_id: this.ctx.tender.id,
                     ledger_id: node.ledger_id,
                     ledger_id: node.ledger_id,
                     ledger_pid: node.ledger_pid,
                     ledger_pid: node.ledger_pid,

+ 48 - 1
app/service/ledger_revise.js

@@ -30,7 +30,7 @@ module.exports = app => {
          * @returns {Promise<*>} - ledger_change下所有数据,并关联 project_account(读取提交人名称、单位、公司)
          * @returns {Promise<*>} - ledger_change下所有数据,并关联 project_account(读取提交人名称、单位、公司)
          */
          */
         async getReviseList (tid) {
         async getReviseList (tid) {
-            const sql = 'SELECT *, pa.name As user_name, pa.role As user_role, pa.company As user_company' +
+            const sql = 'SELECT lc.*, pa.name As user_name, pa.role As user_role, pa.company As user_company' +
                 '  FROM ' + this.tableName + ' As lc' +
                 '  FROM ' + this.tableName + ' As lc' +
                 '  INNER JOIN ' + this.ctx.service.projectAccount.tableName + ' As pa ON lc.uid = pa.id' +
                 '  INNER JOIN ' + this.ctx.service.projectAccount.tableName + ' As pa ON lc.uid = pa.id' +
                 '  WHERE lc.tid = ?' +
                 '  WHERE lc.tid = ?' +
@@ -41,6 +41,24 @@ module.exports = app => {
             return await this.db.query(sql, sqlParam);
             return await this.db.query(sql, sqlParam);
         }
         }
 
 
+        async getLastestRevise(tid) {
+            const sql = 'SELECT lc.*, pa.name As user_name, pa.role As user_role, pa.company As user_company' +
+                '  FROM ' + this.tableName + ' As lc' +
+                '  INNER JOIN ' + this.ctx.service.projectAccount.tableName + ' As pa ON lc.uid = pa.id' +
+                '  WHERE lc.tid = ?' +
+                '  ORDER BY lc.in_time DESC' +
+                '  LIMIT 0, 1';
+            const sqlParam = [tid];
+            return await this.db.queryOne(sql, sqlParam);
+            // const revise = await this.db.select(this.tableName, {
+            //     where: {tid: tid},
+            //     orders: [['in_time', 'DESC']],
+            //     limit: 1,
+            //     offset: 0,
+            // });
+            // return revise.length > 0 ? revise[0] : null;
+        }
+
         /**
         /**
          * 获取新增修订的序号
          * 获取新增修订的序号
          * @param {Number}tid - 标段id
          * @param {Number}tid - 标段id
@@ -58,6 +76,22 @@ module.exports = app => {
             // }
             // }
         }
         }
 
 
+        async _initReviseBills(transaction, tid, rid) {
+            const sql = 'Insert Into ' + this.ctx.service.reviseBills.tableName +
+                '  Select ? As rid, ' + this.ctx.service.ledger.tableName + '.* From ' + this.ctx.service.ledger.tableName +
+                '  Where `tender_id` = ?';
+            const sqlParam = [rid, tid];
+            await transaction.query(sql, sqlParam);
+        }
+
+        async _initRevisePos(transaction, tid, rid) {
+            const sql = 'Insert Into ' + this.ctx.service.revisePos.tableName +
+                '  Select ? As rid, ' + this.ctx.service.pos.tableName + '.* From ' + this.ctx.service.pos.tableName +
+                '  Where `tid` = ?';
+            const sqlParam = [rid, tid];
+            await transaction.query(sql, sqlParam);
+        }
+
         /**
         /**
          * 新增修订
          * 新增修订
          * @param {Number}tid - 标段id
          * @param {Number}tid - 标段id
@@ -81,13 +115,26 @@ module.exports = app => {
                     throw '新增台账修订失败';
                     throw '新增台账修订失败';
                 }
                 }
                 // todo 拷贝数据(清单、部位明细)
                 // todo 拷贝数据(清单、部位明细)
+                await this._initReviseBills(transaction, tid, data.id);
+                await this._initRevisePos(transaction, tid, data.id);
                 await transaction.commit();
                 await transaction.commit();
+                return data;
             } catch(err) {
             } catch(err) {
                 await transaction.rollback();
                 await transaction.rollback();
                 throw err;
                 throw err;
             }
             }
         }
         }
 
 
+        /**
+         * 作废修订
+         * @param id
+         * @returns {Promise<void>}
+         */
+        async cancelRevise(id) {
+            const result = await this.db.update(this.tableName, {id: id, valid: false});
+            return result.affectedRows === 1;
+        }
+
     }
     }
 
 
     return LedgerRevise;
     return LedgerRevise;

+ 3 - 3
app/service/pos.js

@@ -41,6 +41,7 @@ module.exports = app => {
         }
         }
 
 
         async _insertPosData(transaction, data, tid) {
         async _insertPosData(transaction, data, tid) {
+            data.id = this.uuid.v4();
             data.tid = tid;
             data.tid = tid;
             // todo 新增期
             // todo 新增期
             data.add_stage = 0;
             data.add_stage = 0;
@@ -52,7 +53,6 @@ module.exports = app => {
                 data.quantity = this.round(data.quantity, precision.value);
                 data.quantity = this.round(data.quantity, precision.value);
             }
             }
             const addRst = await transaction.insert(this.tableName, data);
             const addRst = await transaction.insert(this.tableName, data);
-            data.id = addRst.insertId;
         }
         }
 
 
         /**
         /**
@@ -217,7 +217,7 @@ module.exports = app => {
             const posData = await this.getAllDataByCondition({ where: { lid: orgLid } });
             const posData = await this.getAllDataByCondition({ where: { lid: orgLid } });
             if (posData.length > 0) {
             if (posData.length > 0) {
                 for (const pd of posData) {
                 for (const pd of posData) {
-                    delete pd.id;
+                    pd.id = this.uuid.v4();
                     pd.lid = newLid;
                     pd.lid = newLid;
                     pd.tid = this.ctx.tender.id;
                     pd.tid = this.ctx.tender.id;
                 }
                 }
@@ -238,7 +238,7 @@ module.exports = app => {
             const insertDatas = [];
             const insertDatas = [];
             for (const d of data) {
             for (const d of data) {
                 const inD = {
                 const inD = {
-                    tid: tid, lid: bills.id,
+                    id: this.uuid.v4(), tid: tid, lid: bills.id,
                     add_stage: 0, add_times: 0, add_user: this.ctx.session.sessionUser.accountId,
                     add_stage: 0, add_times: 0, add_user: this.ctx.session.sessionUser.accountId,
                     name: d.name, drawing_code: d.drawing_code,
                     name: d.name, drawing_code: d.drawing_code,
                 };
                 };

+ 39 - 0
app/service/revise_bills.js

@@ -0,0 +1,39 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+module.exports = app => {
+    class ReviseBills extends app.BaseService {
+
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'revise_bills';
+        }
+
+        /**
+         * 获取 修订 清单数据
+         * @param {Number}tid - 标段id
+         * @param {uuid}rid - 修订id
+         * @returns {Promise<void>}
+         */
+        async getData(tid, rid) {
+            return await this.db.select(this.tableName, {
+                where: {tender_id: tid, rid: rid}
+            });
+        }
+    }
+
+    return ReviseBills;
+};

+ 39 - 0
app/service/revise_pos.js

@@ -0,0 +1,39 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+module.exports = app => {
+    class RevisePos extends app.BaseService {
+
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'revise_pos';
+        }
+
+        /**
+         * 获取 修订 清单数据
+         * @param {Number}tid - 标段id
+         * @param {uuid}rid - 修订id
+         * @returns {Promise<void>}
+         */
+        async getData(tid, rid) {
+            return await this.db.select(this.tableName, {
+                where: {tid: tid, rid: rid}
+            });
+        }
+    }
+
+    return RevisePos;
+};

+ 2 - 2
app/service/stage_bills.js

@@ -32,10 +32,10 @@ module.exports = app => {
          * @returns {Promise<*>}
          * @returns {Promise<*>}
          */
          */
         async getLastestStageData(tid, sid, lid) {
         async getLastestStageData(tid, sid, lid) {
-            let lidSql = '';
+            let lidSql = '', self = this;
             if (lid) {
             if (lid) {
                 if (lid instanceof Array) {
                 if (lid instanceof Array) {
-                    lidSql = lid.length > 0 ? ' And lid in (' + lid.join(',') + ')' : '';
+                    return lid.length > 0 ? this.ctx.helper.getInArrStrSqlFilter(lid) : '';
                 } else {
                 } else {
                     lidSql = ' And lid in (' + this.db.escape(lid) + ')';
                     lidSql = ' And lid in (' + this.db.escape(lid) + ')';
                 }
                 }

+ 1 - 1
app/view/layout/page.ejs

@@ -111,7 +111,7 @@
             return  queryString === '' ? '?' + firstQuery : '?' + firstQuery + '&' + queryString;
             return  queryString === '' ? '?' + firstQuery : '?' + firstQuery + '&' + queryString;
         }
         }
     };
     };
-    if (options.totalPages > 0) {
+    if (options.totalPages > 1) {
         $(".pagination").bootstrapPaginator(options);
         $(".pagination").bootstrapPaginator(options);
     } else {
     } else {
         $(".pagination").hide();
         $(".pagination").hide();

+ 13 - 5
app/view/ledger/revise.ejs

@@ -40,19 +40,27 @@
                     <td><%- lr.corder %></td>
                     <td><%- lr.corder %></td>
                     <td><%- lr.in_time ? lr.in_time.toLocaleDateString() : '' %></td>
                     <td><%- lr.in_time ? lr.in_time.toLocaleDateString() : '' %></td>
                     <td><%- lr.user_name %></td>
                     <td><%- lr.user_name %></td>
-                    <td></td>
+                    <td <% if (!lr.valid) {%>class="text-danger"<% } %>>
+                        <% if (lr.valid) { %>
+                        <%- auditConst.statusString[lr.status] %>
+                        <% } else { %>
+                        作废
+                        <% } %>
+                    </td>
                     <td><%- lr.end_time ? lr.end_time.toLocaleDateString() : '' %></td>
                     <td><%- lr.end_time ? lr.end_time.toLocaleDateString() : '' %></td>
                     <td>
                     <td>
+                        <% if (lr.valid) { %>
                         <% if (lr.status === auditConst.status.uncheck) { %>
                         <% if (lr.status === auditConst.status.uncheck) { %>
-                        <a href="<%- preUrl + 'ledger/revise/' + lr.id +'/info' %>" class="btn btn-primary btn-sm">修订</a>
+                        <a href="<%- preUrl + '/ledger/revise/info' %>" class="btn btn-primary btn-sm">修订</a>
                         <a href="#remove" data-toggle="modal" data-target="#remove" class="btn btn-secondary btn-sm">作废</a>
                         <a href="#remove" data-toggle="modal" data-target="#remove" class="btn btn-secondary btn-sm">作废</a>
                         <% } else if (lr.status === auditConst.status.checking) { %>
                         <% } else if (lr.status === auditConst.status.checking) { %>
-                        <a href="<%- preUrl + 'ledger/revise/' + lr.id +'/info' %>" class="btn btn-success btn-sm">审批</a><
+                        <a href="<%- preUrl + '/ledger/revise/info' %>" class="btn btn-success btn-sm">审批</a><
                         <% } else if (lr.status === auditConst.status.checkNo) { %>
                         <% } else if (lr.status === auditConst.status.checkNo) { %>
-                        <a href="<%- preUrl + 'ledger/revise/' + lr.id +'/info' %>" class="btn btn-primary btn-sm">重新上报</a>
+                        <a href="<%- preUrl + '/ledger/revise/info' %>" class="btn btn-primary btn-sm">重新上报</a>
                         <a href="#remove" data-toggle="modal" data-target="#remove" class="btn btn-secondary btn-sm">作废</a>
                         <a href="#remove" data-toggle="modal" data-target="#remove" class="btn btn-secondary btn-sm">作废</a>
                         <% } else if (ledgerRevise.indexOf(lr) === ledgerRevise.length - 1) { %>
                         <% } else if (ledgerRevise.indexOf(lr) === ledgerRevise.length - 1) { %>
-                        <a href="<%- preUrl + 'ledger/revise/' + lr.id +'/info' %>">查看修订内容</a>
+                        <a href="<%- preUrl + '/ledger/revise/info' %>">查看修订内容</a>
+                        <% } %>
                         <% } %>
                         <% } %>
                     </td>
                     </td>
                 </tr>
                 </tr>

+ 150 - 0
app/view/ledger/revise_info.ejs

@@ -0,0 +1,150 @@
+<% include ../tender/tender_sub_menu.ejs %>
+<div class="panel-content">
+    <div class="panel-title">
+        <div class="title-main  d-flex justify-content-between">
+            <!--工具-->
+            <% if ((revise.status === audit.status.uncheck || revise.status === audit.status.checkNo) && revise.uid === ctx.session.sessionUser.accountId) { %>
+            <div>
+                <!--编制人工具-->
+                <div class="d-inline-flex">
+                    <a href="" class="btn btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="复制"><i class="fa fa-files-o" aria-hidden="true"></i></a>
+                    <a href="" class="btn btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="剪切"><i class="fa fa-scissors" aria-hidden="true"></i></a>
+                    <a href="" class="btn btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="粘贴"><i class="fa fa-clipboard" aria-hidden="true"></i></a>
+                    <a href="" class="btn btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="删除"><i class="fa fa-remove" aria-hidden="true"></i></a>
+                    <a href="" class="btn btn-sm disabled" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="升级"><i class="fa fa-arrow-left" aria-hidden="true"></i></a>
+                    <a href="" class="btn btn-sm disabled" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="降级"><i class="fa fa-arrow-right" aria-hidden="true"></i></a>
+                    <a href="" class="btn btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="下移"><i class="fa fa-arrow-down" aria-hidden="true"></i></a>
+                    <a href="" class="btn btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="上移"><i class="fa fa-arrow-up" aria-hidden="true"></i></a>
+                </div>
+
+                <div class="d-inline-block">
+                    <div class="input-group input-group-sm ml-2 mt-1">
+                        <div class="input-group-prepend">
+                            <span class="input-group-text" id="basic-addon1">表达式</span>
+                        </div>
+                        <input type="text" class="form-control m-0">
+                    </div>
+                </div>
+            </div>
+            <% } %>
+            <div>
+                <% if (revise.status === audit.status.uncheck) { %>
+                <a href="#sub-sp" data-toggle="modal" data-target="#sub-sp" class="btn btn-primary btn-sm pull-right">上报审批</a>
+                <% } else if (revise.status === audit.status.checkNo) { %>
+                <a href="#sp-list" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-secondary btn-sm pull-right">审批退回</a>
+                    <% if (revise.uid === ctx.session.sessionUser.accountId) { %>
+                    <a href="#sub-sp" data-toggle="modal" data-target="#sub-sp2" class="btn btn-primary btn-sm pull-right">重新上报</a>
+                    <% } %>
+                <% } else if (revise.status === audit.status.checking) { %>
+                <a href="#sp-list" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-warning btn-sm pull-right text-dark">审批中</a>
+                <!--审批-->
+                <a href="#sp-done" data-toggle="modal" data-target="#sp-done" class="btn btn-success btn-sm pull-right">审批通过</a>
+                <a href="#sp-back" data-toggle="modal" data-target="#sp-back" class="btn btn-warning btn-sm pull-right">审批退回</a>
+                <% } else if (revise.status === audit.status.checked) { %>
+                <a href="#sp-list" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-secondary btn-sm pull-right">审批完成</a>
+                <% } %>
+            </div>
+        </div>
+    </div>
+    <div class="content-wrap row pr-46">
+        <div class="c-header p-0 col-12"></div>
+        <!--核心内容(两栏)-->
+        <div class="row w-100 sub-content">
+            <!--左栏-->
+            <div class="c-body col-8">
+                <!--0号台帐模式-->
+                <div class="sjs-height-1" style="overflow: hidden" id="bills-spread">
+                </div>
+                <div class="bcontent-wrap">
+                    <div id="revise-resize" class="resize-y" id="top-spr" r-Type="height" div1=".sjs-height-1" div2=".bcontent-wrap" title="调整大小"><!--调整上下高度条--></div>
+                    <div class="bc-bar mb-1">
+                        <ul class="nav nav-tabs">
+                            <li class="nav-item">
+                                <a class="nav-link active" href="#">部位明细</a>
+                            </li>
+                            <li class="nav-item">
+                                <div class="mt-1 ml-2">
+                                    <div class="input-group input-group-sm">
+                                        <input type="text" class="form-control" placeholder="输入名称查找">
+                                        <div class="input-group-append" id="button-addon3">
+                                            <button class="btn btn-outline-secondary" type="button" title="上一个"><i class="fa fa-angle-double-left"></i></button>
+                                            <button class="btn btn-outline-secondary" type="button" title="下一个"><i class="fa fa-angle-double-right"></i></button>
+                                        </div>
+                                    </div>
+                                </div>
+                            </li>
+                        </ul>
+                    </div>
+                    <div class="sp-wrap" id="pos-spread">
+                    </div>
+                </div>
+            </div>
+            <!--右栏-->
+            <div class="c-body col">
+                <div class="tab-content">
+                    <div id="xdcontent" class="tab-pane active">
+                        <div class="sjs-bar-1">
+                            <div class="d-flex"><a href="javascirpt: void(0);" class="btn btn-sm btn-outline-success mb-1 ml-auto" id="save">保存</a></div>
+                        </div>
+                        <div class="sjs-sh-1" style="overflow:auto">
+                            <div class="form-group mt-2">
+                                <label >创建时间</label>
+                                <input type="" class="form-control" value="<%- revise.in_time.toLocaleString() %>" disabled>
+                            </div>
+                            <div class="form-group mt-2">
+                                <label >提交人</label>
+                                <input type="" class="form-control" value="<%- revise.user_name %>" disabled>
+                            </div>
+                            <div class="form-group">
+                                <label >修订内容<b class="text-danger">*</b></label>
+                                <textarea class="form-control" value="编写错漏5" rows="12"><%- revise.content %></textarea>
+                            </div>
+                        </div>
+                    </div>
+                    <div id="xiangmujie" class="tab-pane">
+                        <div class="sjs-bar-2">
+                            <select class="form-control form-control-sm"><option>0号计量台帐部位参考(项目节)</option></select>
+                        </div>
+                        <div class="sjs-sh-2">
+                            <table class="table table-bordered">
+                                <tr><th></th><th>项目节编号</th><th>名称</th><th>单位</th></tr>
+                            </table>
+                        </div>
+                    </div>
+                    <div id="qingdan" class="tab-pane">
+                        <div class="sjs-bar-3">
+                            <select class="form-control form-control-sm"><option>0号计量台帐部位参考(项目节)</option></select>
+                        </div>
+                        <div class="sjs-sh-3">
+                            <table class="table table-bordered">
+                                <tr><th></th><th>清单编号</th><th>名称</th><th>单位</th></tr>
+                            </table>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <!--右侧菜单-->
+        <div class="side-menu">
+            <!--右侧菜单-->
+            <ul class="nav flex-column right-nav">
+                <li class="nav-item">
+                    <a class="nav-link active" data-toggle="tab" href="#xdcontent" role="tab">修订详情</a>
+                </li>
+                <li class="nav-item">
+                    <a class="nav-link" data-toggle="tab" href="#xiangmujie" role="tab">项目节</a>
+                </li>
+                <li class="nav-item">
+                    <a class="nav-link" data-toggle="tab" href="#qingdan" role="tab">工程量清单</a>
+                </li>
+            </ul>
+        </div>
+    </div>
+</div>
+<script>
+    const readOnly = <%- readOnly %>;
+    const billsSpreadSetting = JSON.parse('<%- JSON.stringify(ledgerSpread) %>');
+    const posSpreadSetting = JSON.parse('<%- JSON.stringify(posSpread) %>');
+    const bills = JSON.parse('<% JSON.stringify(reviseBills) %>');
+    const pos = JSON.parse('<% JSON.stringify(revisePos) %>');
+</script>

+ 195 - 0
app/view/ledger/revise_info_modal.ejs

@@ -0,0 +1,195 @@
+<% if (revise.status === audit.status.uncheck) { %>
+<!--上报审批-->
+<div class="modal fade" id="sub-sp" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">上报审批</h5>
+            </div>
+            <div class="modal-body">
+                <div class="form-group">
+                    <label>搜索审批人</label>
+                    <div class="input-group">
+                        <input class="form-control" placeholder="请输入姓名进行检索" type="text">
+                        <div class="input-group-append">
+                            <button class="btn btn-outline-secondary" type="button"><i class="fa fa-search"></i></button>
+                        </div>
+                    </div>
+                </div>
+                <div class="card border-primary">
+                    <div class="card-body">
+                        <h5 class="card-title">
+                            <a href="#" class="btn btn-primary btn-sm pull-right">添加</a>张三
+                        </h5>
+                        <h6 class="card-subtitle mb-2 text-muted">监理</h6>
+                        <p class="card-text">XXXXX公司</p>
+                    </div>
+                </div>
+                <div class="card mt-3">
+                    <div class="card-header">
+                        审批流程
+                    </div>
+                    <ul class="list-group list-group-flush">
+                        <li class="list-group-item"><a href="" class="text-danger pull-right">移除</a>1 张三  <small class="text-muted">监理</small></li>
+                        <li class="list-group-item"><a href="" class="text-danger pull-right">移除</a>2 王五 <small class="text-muted">监理</small></li>
+                        <li class="list-group-item"><a href="" class="text-danger pull-right">移除</a>3 李四 <small class="text-muted">监理</small></li>
+                    </ul>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-primary">确认上报</button>
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
+            </div>
+        </div>
+    </div>
+</div>
+<% } else if (revise.status === audit.status.checkNo) { %>
+<!--重新审批-->
+<div class="modal fade" id="sub-sp2" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">重新上报</h5>
+            </div>
+            <div class="modal-body">
+                <div class="alert alert-primary" role="alert">
+                    重新上报后,将由 王五 继续审批
+                </div>
+                <div class="card mt-3">
+                    <div class="card-header">
+                        审批流程
+                    </div>
+                    <ul class="list-group list-group-flush">
+                        <li class="list-group-item">
+                            <span class="text-success pull-right">审批通过</span>
+                            <h5 class="card-title">1 张三 <small class="text-muted">监理</small></h5>
+                            <p class="card-text">审批意见。2018-01-01</p>
+                        </li>
+                        <li class="list-group-item">
+                            <span class="text-warning pull-right">退回</span>
+                            <h5 class="card-title">2 王五 <small class="text-muted">监理</small></h5>
+                            <p class="card-text"></p>
+                        </li>
+                        <li class="list-group-item">
+                            <h5 class="card-title">3 李四 <small class="text-muted">监理</small></h5>
+                            <p class="card-text"></p>
+                        </li>
+                    </ul>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-primary">确认上报</button>
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
+            </div>
+        </div>
+    </div>
+</div>
+<% } else if (revise.status === audit.status.checking) { %>
+<!--审批通过-->
+<div class="modal fade" id="sp-done" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">审批通过</h5>
+            </div>
+            <div class="modal-body">
+                <div class="card mt-3">
+                    <ul class="list-group list-group-flush">
+                        <li class="list-group-item">
+                            <span class="text-success pull-right">审批通过</span>
+                            <h5 class="card-title">1 张三 <small class="text-muted">监理</small></h5>
+                            <p class="card-text">审批意见。2018-01-01</p>
+                        </li>
+                        <li class="list-group-item">
+                            <span class="text-warning pull-right">审批中</span>
+                            <h5 class="card-title">2 王五 <small class="text-muted">监理</small></h5>
+                            <div class="form-group">
+                                <label>审批意见<b class="text-danger">*</b></label>
+                                <textarea class="form-control" ></textarea>
+                            </div>
+                        </li>
+                        <li class="list-group-item">
+                            <h5 class="card-title">3 李四 <small class="text-muted">监理</small></h5>
+                        </li>
+                    </ul>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-success" >确认通过</button>
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
+            </div>
+        </div>
+    </div>
+</div>
+<!--审批退回-->
+<div class="modal fade" id="sp-back" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">审批退回</h5>
+            </div>
+            <div class="modal-body">
+                <div class="card mt-3">
+                    <ul class="list-group list-group-flush">
+                        <li class="list-group-item">
+                            <span class="text-success pull-right">审批通过</span>
+                            <h5 class="card-title">1 张三 <small class="text-muted">监理</small></h5>
+                            <p class="card-text">审批意见。2018-01-01</p>
+                        </li>
+                        <li class="list-group-item">
+                            <span class="text-warning pull-right">审批中</span>
+                            <h5 class="card-title">2 王五 <small class="text-muted">监理</small></h5>
+                            <div class="form-group">
+                                <label>审批意见<b class="text-danger">*</b></label>
+                                <textarea class="form-control" ></textarea>
+                            </div>
+                            <div class="alert alert-warning">审批退回,将直接退回给上报人。</data-min-view>
+                        </li>
+                        <li class="list-group-item">
+                            <h5 class="card-title">3 李四 <small class="text-muted">监理</small></h5>
+                        </li>
+                    </ul>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-warning" >确认退回</button>
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
+            </div>
+        </div>
+    </div>
+</div>
+<% } %>
+<% if (revise.status !== audit.status.uncheck) { %>
+<!--审批流程/结果-->
+<div class="modal fade" id="sp-list" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">审批流程</h5>
+            </div>
+            <div class="modal-body">
+                <div class="card mt-3">
+                    <ul class="list-group list-group-flush">
+                        <li class="list-group-item">
+                            <span class="text-success pull-right">审批通过</span>
+                            <h5 class="card-title">1 张三 <small class="text-muted">监理</small></h5>
+                            <p class="card-text">审批意见。2018-01-01</p>
+                        </li>
+                        <li class="list-group-item">
+                            <span class="text-warning pull-right">审批中</span>
+                            <h5 class="card-title">2 王五 <small class="text-muted">监理</small></h5>
+                            <p class="card-text"></p>
+                        </li>
+                        <li class="list-group-item">
+                            <h5 class="card-title">3 李四 <small class="text-muted">监理</small></h5>
+                        </li>
+                    </ul>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
+            </div>
+        </div>
+    </div>
+</div>
+<% } %>

+ 10 - 6
app/view/ledger/revise_modal.ejs

@@ -16,9 +16,11 @@
         </div>
         </div>
     </form>
     </form>
 </div>
 </div>
+
+<% if (ledgerRevise.length > 0 && (ledgerRevise[0].status === auditConst.status.uncheck || ledgerRevise[0].status === auditConst.status.checkNo) && ctx.session.sessionUser.accountId === ledgerRevise[0].uid) { %>
 <!--弹出作废-->
 <!--弹出作废-->
 <div class="modal fade" id="remove" data-backdrop="static">
 <div class="modal fade" id="remove" data-backdrop="static">
-    <div class="modal-dialog" role="document">
+    <form class="modal-dialog" role="document" action="<%- preUrl + '/ledger/revise/cancel' %>" method="post" onsubmit="return $('#cancel-confirm').val() === '修订作废';">
         <div class="modal-content">
         <div class="modal-content">
             <div class="modal-header">
             <div class="modal-header">
                 <h5 class="modal-title">作废修订</h5>
                 <h5 class="modal-title">作废修订</h5>
@@ -30,13 +32,15 @@
                     <br>确认作废,请在以下输入框输入"&nbsp;&nbsp;&nbsp;<b>修订作废</b>&nbsp;&nbsp;&nbsp;",再点击“确认作废”按钮。
                     <br>确认作废,请在以下输入框输入"&nbsp;&nbsp;&nbsp;<b>修订作废</b>&nbsp;&nbsp;&nbsp;",再点击“确认作废”按钮。
                 </div>
                 </div>
                 <div class="form-group">
                 <div class="form-group">
-                    <input class="form-control"  placeholder="" type="text">
+                    <input class="form-control" placeholder="" type="text" id="cancel-confirm">
                 </div>
                 </div>
             </div>
             </div>
             <div class="modal-footer">
             <div class="modal-footer">
-                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
-                <button type="button" class="btn btn-danger">确认作废</button>
+                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                <button type="button" class="btn btn-secondary" data-dismiss="modal" >取消</button>
+                <button type="submit" class="btn btn-danger">确认作废</button>
             </div>
             </div>
         </div>
         </div>
-    </div>
-</div>
+    </form>
+</div>
+<% } %>

+ 0 - 3
config/config.qa.js

@@ -61,8 +61,5 @@ module.exports = appInfo => {
         disableConsoleAfterReady: false,
         disableConsoleAfterReady: false,
     };
     };
 
 
-    // 分页相关
-    config.pageSize = 3;
-
     return config;
     return config;
 };
 };

+ 14 - 0
config/web.js

@@ -123,6 +123,20 @@ const JsFiles = {
                     "/public/js/ledger_audit.js",
                     "/public/js/ledger_audit.js",
                 ],
                 ],
                 mergeFile: 'ledger_audit',
                 mergeFile: 'ledger_audit',
+            },
+            revise: {
+                files: [
+                    "/public/js/spreadjs/sheets/gc.spread.sheets.all.10.0.1.min.js",
+                    "/public/js/decimal.min.js",
+                ],
+                mergeFiles: [
+                    "/public/js/div_resizer.js",
+                    "/public/js/spreadjs_rela/spreadjs_zh.js",
+                    "/public/js/zh_calc.js",
+                    "/public/js/path_tree.js",
+                    "/public/js/revise.js",
+                ],
+                mergeFile: 'revise',
             }
             }
         },
         },
         stage: {
         stage: {

+ 34 - 14
test/app/service/ledger.test.js

@@ -108,6 +108,14 @@ describe('test/app/service/ledger.test.js', () => {
         assert(result);
         assert(result);
         ctx.service.ledger.cache.set('tender_node_maxId:' + ctx.tender.id, 16, 'EX', ctx.app.config.cacheTime);
         ctx.service.ledger.cache.set('tender_node_maxId:' + ctx.tender.id, 16, 'EX', ctx.app.config.cacheTime);
     });
     });
+    // 统一校验
+    afterEach(function* () {
+        const ctx = app.mockContext(mockData);
+
+        const nodes = yield ctx.service.ledger.getDataByTenderId(ctx.tender.id, -1);
+        const paths = _.uniqBy(nodes, 'full_path');
+        assert(nodes.length === paths.length);
+    });
     /* 期望运行结果:
     /* 期望运行结果:
         1
         1
         ├── 1-1
         ├── 1-1
@@ -448,20 +456,25 @@ describe('test/app/service/ledger.test.js', () => {
     it('test pasteBlock', function* () {
     it('test pasteBlock', function* () {
         const ctx = app.mockContext(mockData);
         const ctx = app.mockContext(mockData);
         // 选中1-2-1, 粘贴1-1-1和new
         // 选中1-2-1, 粘贴1-1-1和new
+        const node = yield ctx.service.ledger.getDataByNodeId(ctx.tender.id, 15);
         const resultData = yield ctx.service.ledger.pasteBlock(ctx.tender.id, 15, [6, 17]);
         const resultData = yield ctx.service.ledger.pasteBlock(ctx.tender.id, 15, [6, 17]);
 
 
-        const ledger = resultData.ledger;
-        assert(ledger.create.length === 5);
-        assert(ledger.create[0].order = 2);
-        assert(ledger.create[0].level = 3);
-        assert(ledger.create[0].full_path = '1.3.18');
+        const create = _.sortBy(resultData.ledger.create, ['level', 'order']);
+        assert(create.length === 5);
 
 
-        assert(ledger.create[1].order = 3);
-        assert(ledger.create[1].level = 3);
-        assert(ledger.create[1].full_path = '1.3.22');
+        const node1 = _.find(create, {code: '1-1-1'});
+        assert(node1.order === 2);
+        assert(node1.level === 3);
+        assert(node1.full_path === node.full_path.replace('.' + node.ledger_id, '.' + node1.ledger_id));
+        const node2 = _.find(create, function (c) {
+            return c.ledger_pid === node.ledger_pid && c.ledger_id !== node1.ledger_id;
+        });
+        assert(node2.order === 3);
+        assert(node2.level === 3);
+        assert(node2.full_path === node.full_path.replace('.' + node.ledger_id, '.' + node2.ledger_id));
 
 
-        assert(ledger.update.length === 1);
-        assert(ledger.update[0].order = 3);
+        assert(resultData.ledger.update.length === 1);
+        assert(resultData.ledger.update[0].order === 4);
 
 
         assert(resultData.pos.length === 0);
         assert(resultData.pos.length === 0);
     });
     });
@@ -544,8 +557,10 @@ describe('test/app/service/ledger.test.js', () => {
             code: '1-2-3',
             code: '1-2-3',
         }]);
         }]);
         assert(resultData.length === 2);
         assert(resultData.length === 2);
-        assert(resultData[0].code === '1-2-2');
-        assert(resultData[1].code === '1-2-3');
+        let node = _.find(resultData, {id: node1.id});
+        assert(node.code === '1-2-2');
+        node = _.find(resultData, {id: node2.id});
+        assert(node.code === '1-2-3');
     });
     });
     /* 期望运行结果:
     /* 期望运行结果:
         1
         1
@@ -838,7 +853,12 @@ describe('test/app/service/ledger.test.js', () => {
         const ctx = app.mockContext(mockData);
         const ctx = app.mockContext(mockData);
 
 
         // 选中202-2-c(1-2-2下)(id=20),删除节点
         // 选中202-2-c(1-2-2下)(id=20),删除节点
-        const resultData = yield ctx.service.ledger.deleteNode(ctx.tender.id, 20);
+        const node = yield ctx.service.ledger.getDataByCondition({
+            tender_id: ctx.tender.id,
+            code: '202-2-c',
+            level: 5,
+        });
+        const resultData = yield ctx.service.ledger.deleteNode(ctx.tender.id, node.ledger_id);
         assert(resultData.delete.length === 1);
         assert(resultData.delete.length === 1);
         assert(resultData.update.length === 1);
         assert(resultData.update.length === 1);
     });
     });
@@ -942,7 +962,7 @@ describe('test/app/service/ledger.test.js', () => {
         assert(result2);
         assert(result2);
         assert(result2.create.length === 1);
         assert(result2.create.length === 1);
         assert(result2.update.length === 1);
         assert(result2.update.length === 1);
-        assert(result2.update[0].code = '1-4-2-1');
+        assert(result2.update[0].code === '1-4-2-1');
         assert(!result2.update[0].is_leaf);
         assert(!result2.update[0].is_leaf);
         // 从标准库添加1-4-2-1-1
         // 从标准库添加1-4-2-1-1
         const condition3 = { list_id: 1, code: '1-4-2-1-1'};
         const condition3 = { list_id: 1, code: '1-4-2-1-1'};