Jelajahi Sumber

Merge branch 'dev' of http://192.168.1.41:3000/maixinrong/Calculation into dev

Tony Kang 8 bulan lalu
induk
melakukan
00ae95050a

+ 33 - 0
app/base/base_bills_service.js

@@ -787,6 +787,39 @@ class BaseBillsSerivce extends TreeService {
         ledgerBills.is_tp = ledgerExtra ? ledgerExtra.is_tp : 0;
         return ledgerBills
     }
+
+    /**
+     * 获取最大节点id
+     *
+     * @param {Number} mid - master id
+     * @return {Number}
+     * @private
+     */
+    async _getMaxLid(mid) {
+        const cacheKey = this.setting.keyPre + mid;
+        let maxId = this.setting.cacheKey ? parseInt(await this.cache.get(cacheKey)) : undefined;
+        if (this.setting.cacheKey) {
+            // 判断是否存在变更新增部位maxId,有则取两者最大值
+            const changeReviseCacheKey = 'change_ledger_maxLid2:' + mid;
+            const changeReviseMaxId = await this.cache.get(changeReviseCacheKey);
+            if (changeReviseMaxId) {
+                maxId = !maxId ? parseInt(changeReviseMaxId) : Math.max(maxId, parseInt(changeReviseMaxId));
+            }
+        }
+        if (!maxId) {
+            const sql = 'SELECT Max(??) As max_id FROM ?? Where ' + this.setting.mid + ' = ?';
+            const sqlParam = [this.setting.kid, this.tableName, mid];
+            const queryResult = await this.db.queryOne(sql, sqlParam);
+            maxId = queryResult.max_id || 0;
+            const sql1 = 'SELECT Max(??) As max_id FROM ?? Where ' + this.setting.mid + ' = ?';
+            const sqlParam1 = [this.setting.kid, this.ctx.service.changeLedger.tableName, mid];
+            const queryResult1 = await this.db.queryOne(sql1, sqlParam1);
+            const maxId1 = queryResult1.max_id || 0;
+            maxId = Math.max(maxId, maxId1);
+            if (this.setting.cacheKey) this.cache.set(cacheKey, maxId, 'EX', this.ctx.app.config.cacheTime);
+        }
+        return maxId;
+    }
 }
 
 module.exports = BaseBillsSerivce;

+ 3 - 8
app/base/base_tree_service.js

@@ -35,6 +35,7 @@ class TreeService extends Service {
         super(ctx);
         this.tableName = setting.tableName;
         this.setting = setting;
+        if (this.setting.cacheKey === undefined) this.setting.cacheKey = true;
         // 以下字段仅可通过树结构操作改变,不可直接通过update方式从接口提交,发现时过滤
         this.readOnlyFields = ['id'];
         this.readOnlyFields.push(this.setting.mid);
@@ -332,19 +333,13 @@ class TreeService extends Service {
      */
     async _getMaxLid(mid) {
         const cacheKey = this.setting.keyPre + mid;
-        let maxId = parseInt(await this.cache.get(cacheKey));
-        // 判断是否存在变更新增部位maxId,有则取两者最大值
-        const changeReviseCacheKey = 'change_ledger_maxLid2:' + mid;
-        const changeReviseMaxId = await this.cache.get(changeReviseCacheKey);
-        if (changeReviseMaxId) {
-            maxId = !maxId ? parseInt(changeReviseMaxId) : Math.max(maxId, parseInt(changeReviseMaxId));
-        }
+        let maxId = this.setting.cacheKey ? parseInt(await this.cache.get(cacheKey)) : undefined;
         if (!maxId) {
             const sql = 'SELECT Max(??) As max_id FROM ?? Where ' + this.setting.mid + ' = ?';
             const sqlParam = [this.setting.kid, this.tableName, mid];
             const queryResult = await this.db.queryOne(sql, sqlParam);
             maxId = queryResult.max_id || 0;
-            this.cache.set(cacheKey, maxId, 'EX', this.ctx.app.config.cacheTime);
+            if (this.setting.cacheKey) this.cache.set(cacheKey, maxId, 'EX', this.ctx.app.config.cacheTime);
         }
         return maxId;
     }

+ 1 - 0
app/const/account_permission.js

@@ -41,6 +41,7 @@ const permission = {
         title: '工程变更',
         type: 'checkbox',
         children: [
+            { title: '创建变更令', value: 3, hint: '开启该选项,非本人创建的标段也可创建变更令', hintIcon: 'fa-question-circle' },
             { title: '变更意向', value: 1, hint: '开启该选项,变更立项可新建变更意向书', hintIcon: 'fa-question-circle' },
             { title: '删除附件', value: 2, hint: '开启该选项,可删除审批通过前自己上传的附件', hintIcon: 'fa-question-circle' },
         ],

+ 1 - 1
app/const/audit.js

@@ -648,7 +648,7 @@ const change = (function() {
     // 标段概况页
     // 描述文本
     const auditString = [];
-    auditString[status.uncheck] = '';
+    auditString[status.uncheck] = '待上报';
     auditString[status.checking] = '审批中';
     auditString[status.checked] = '审批通过';
     auditString[status.checkNo] = '审批退回';

+ 25 - 4
app/controller/change_controller.js

@@ -78,6 +78,8 @@ module.exports = app => {
                             await ctx.service.change.defaultUpdate({ final_auditor_str }, { where: { cid: c.cid } });
                         }
                     }
+                    const user = await ctx.service.projectAccount.getDataById(c.uid);
+                    c.username = user ? user.name : '';
                     page_total = ctx.helper.add(page_total, c.total_price);
                 }
             }
@@ -133,6 +135,10 @@ module.exports = app => {
             const apLists = allPlanCodes.length > 0 ? ctx.app._.uniq(ctx.app._.map(allPlanCodes, 'plan_code')) : [];
             const need_checking = await ctx.service.change.getCheckingList(ctx.tender.id, ctx.session.sessionUser.accountId, true);
 
+            const pa = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId);
+            const userPermission = pa && pa.permission ? JSON.parse(pa.permission) : null;
+            const addPermission = !!(userPermission && userPermission.change !== undefined && userPermission.change.indexOf('3') !== -1);
+
             const renderData = {
                 moment,
                 tender,
@@ -159,6 +165,7 @@ module.exports = app => {
                 auditType,
                 precision: ctx.tender.info.precision,
                 need_checking,
+                addPermission,
             };
 
             if (ctx.session.sessionProject.page_show.openChangeState) {
@@ -300,7 +307,7 @@ module.exports = app => {
                 const stateInfo = ctx.helper._.find(fun_set.change_state, { order: 3 });
                 // 在生成新变更令后,需要copy前一个变更令报表的签名信息
                 const lastChange = await ctx.service.change.getLastChange(tenderId);
-                const change = await ctx.service.change.add(tenderId, ctx.session.sessionUser.accountId, data.code, data.plan_code, data.name, stateInfo.value);
+                const change = await ctx.service.change.add(tenderId, ctx.session.sessionUser.accountId, data.code, data.plan_code, data.name, data.add_plan_list, stateInfo.value);
                 await ctx.service.roleRptRel.createRoleRelationshipFromOtherBz(tenderId, '-300', change.cid, lastChange ? lastChange.cid : null);
 
                 ctx.body = { err: 0, msg: '', data: change };
@@ -671,12 +678,26 @@ module.exports = app => {
                         const changeList = await ctx.service.changeAuditList.getList(ctx.change.cid);
                         const auditList2 = await ctx.service.changeAudit.getListGroupByTimes(ctx.change.cid, ctx.change.times);
                         // changeList = JSON.parse(JSON.stringify(changeList.sort())).sort().sort();
+                        // for (const cl of changeList) {
+                        //     const audit_amount = cl.audit_amount !== null && cl.audit_amount !== '' ? cl.audit_amount.split(',') : '';
+                        //     // 清单表页赋值
+                        //     for (const [index, au] of auditList2.entries()) {
+                        //         if (au.usite !== 0) {
+                        //             cl['audit_amount_' + au.uid] = au.uid === ctx.session.sessionUser.accountId ? cl.spamount : (audit_amount[index - 1] ? audit_amount[index - 1] : null);
+                        //         }
+                        //     }
+                        // }
                         for (const cl of changeList) {
                             const audit_amount = cl.audit_amount !== null && cl.audit_amount !== '' ? cl.audit_amount.split(',') : '';
                             // 清单表页赋值
-                            for (const [index, au] of auditList2.entries()) {
-                                if (au.usite !== 0) {
-                                    cl['audit_amount_' + au.uid] = au.uid === ctx.session.sessionUser.accountId ? cl.spamount : (audit_amount[index - 1] ? audit_amount[index - 1] : null);
+                            for (const au in ctx.change.userGroups) {
+                                if (ctx.change.userGroups[au][0].audit_order !== 0) {
+                                    cl['audit_amount_' + ctx.change.userGroups[au][0].audit_order] =
+                                        (ctx.change.userGroups[au][0].audit_type === auditType.key.and &&
+                                            ctx.helper._.findIndex(ctx.change.userGroups[au], { status: audit.change.status.checking }) !== -1 &&
+                                            ctx.helper._.findIndex(ctx.change.userGroups[au], { uid: ctx.session.sessionUser.accountId, status: audit.change.status.checked }) !== -1) ||
+                                        (ctx.change.shenpiPower && ctx.helper._.findIndex(ctx.change.userGroups[au], { uid: ctx.session.sessionUser.accountId }) !== -1) ?
+                                            cl.spamount : (audit_amount[au - 1] !== undefined ? parseFloat(audit_amount[au - 1]) : null);
                                 }
                             }
                         }

+ 9 - 1
app/controller/contract_controller.js

@@ -86,10 +86,15 @@ module.exports = app => {
                 const accountInfo = await this.ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId);
                 const userPermission = accountInfo !== undefined && accountInfo.permission !== ''
                     ? JSON.parse(accountInfo.permission) : null;
-                const tenderList = await ctx.service.tender.getContractList('', userPermission, ctx.session.sessionUser.is_admin);
+                let tenderList = await ctx.service.tender.getContractList('', userPermission, ctx.session.sessionUser.is_admin);
                 const projectList = await ctx.service.subProject.getSubProjectByTender(ctx.session.sessionProject.id, tenderList);
+                const removeTidList = [];
                 for (const t of tenderList) {
                     const spInfo = ctx.helper._.find(projectList, { id: t.spid });
+                    if (!spInfo) {
+                        removeTidList.push(t.id);
+                        continue;
+                    }
                     spInfo.child_order = spInfo.child_order ? spInfo.child_order : 0;
                     spInfo.is_folder = 1;
                     t.tree_pid = spInfo.id;
@@ -105,6 +110,9 @@ module.exports = app => {
                     t.income_total_price = incomeList.reduce((total, item) => ctx.helper.add(total, item.total_price), 0);
                     t.income_yf_price = incomeList.reduce((total, item) => ctx.helper.add(total, item.yf_price), 0);
                 }
+                if (removeTidList.length > 0) {
+                    tenderList = tenderList.filter(item => !removeTidList.includes(item.id));
+                }
                 const categoryData = await ctx.service.category.getAllCategory(ctx.session.sessionProject.id);
                 const renderData = {
                     // jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.contract.tender),

+ 8 - 4
app/lib/sum_load.js

@@ -453,12 +453,13 @@ class sumLoad {
         this.ctx = ctx;
     }
 
-    recusiveLoadGatherGcl(node, parent, ignoreParent = false) {
+    recusiveLoadGatherGcl(node, parent, ignoreParent = false, match = false) {
+        const loadMatch = match || node.match || (parent && parent.match);
         const isLeaf = !node.children || node.children.length === 0;
-        const cur = (!ignoreParent || isLeaf) && node.b_code ? this.loadTree.gather(node, parent) : parent;
+        const cur = loadMatch && (!ignoreParent || isLeaf) && node.b_code ? this.loadTree.gather(node, parent) : parent;
         if (isLeaf) return;
         for (const child of node.children) {
-            this.recusiveLoadGatherGcl(child, cur, ignoreParent);
+            this.recusiveLoadGatherGcl(child, cur, ignoreParent, loadMatch);
         }
     }
 
@@ -555,7 +556,7 @@ class sumLoad {
     async stageGatherGcl(select, maxId, tenders, defaultData, cover, ignore, loadChange) {
         const ignoreParent = this.ctx.tender.info.fun_rela.sum_load.ignoreParent;
         this.loadTree = new gatherStageGclTree(this.ctx, {
-            parent: select, maxId, type: 'ledger', defaultData, ignoreParent, cover, ignoreNotFind: ignore, loadChange,
+            parent: select, maxId, type: 'ledger', defaultData, ignoreParent, cover, ignoreNotFind: ignore, loadChange
         });
         const posterity = await this.ctx.service.ledger.getPosterityByParentId(this.ctx.tender.id, select.ledger_id);
         const extraData = await this.ctx.service.ledgerExtra.getData(this.ctx.tender.id, ['is_tp']);
@@ -599,6 +600,9 @@ class sumLoad {
                 stageId: 'id',
             });
             billsTree.loadDatas(billsData);
+            billsTree.nodes.forEach(x => {
+                x.match = tender.match_code ? x.code === tender.match_code : true;
+            });
             for (const top of billsTree.children) {
                 if ([1].indexOf(top.node_type) < 0) continue;
                 this.recusiveLoadGatherGcl(top, null, ignoreParent);

+ 6 - 1
app/public/js/change.js

@@ -152,7 +152,10 @@ const getAuditTypeText = function (type) {
     return `<span class="text-${auditType.info[type].class}">${auditType.info[type].long}</span>`;
 };
 $(document).ready(() => {
-
+    if (openChangePlan) {
+        console.log(getLocalCache('change_add_plan_list'));
+        $('#add_plan_list').prop('checked', getLocalCache('change_add_plan_list'));
+    }
     // 获取审批流程
     $('a[data-target="#sp-list" ]').on('click', function () {
         const data = {
@@ -392,12 +395,14 @@ $(document).ready(() => {
             code: $('#bj-code').val(),
             plan_code: $('#plan-code').val(),
             name: $('#bj-name').val(),
+            add_plan_list: openChangePlan ? $('#add_plan_list').is(':checked') : false,
         };
         if (data.code || data.code !== '' || data.name || data.name !== '') {
             postData('/tender/'+ $('#tenderId').val() +'/change/add', data, function (rst) {
                 $('#bj-code').removeClass('is-invalid');
                 $('#mj-add').modal('hide');
                 $(this).attr('disabled', false);
+                if (openChangePlan) setLocalCache('change_add_plan_list', data.add_plan_list);
                 window.location.href = '/tender/'+ $('#tenderId').val() +'/change/' + rst.cid + '/information';
             }, function () {
                 $('#mj-code').addClass('is-invalid');

+ 40 - 2
app/public/js/change_information_approval.js

@@ -63,11 +63,14 @@ $(document).ready(() => {
     };
     for (const aid of aidList) {
         // const userinfo = _.find(auditList2, { 'uid': aid });
+        const audit = _.find(auditors2, function(item){
+            return _.findIndex(item, { audit_order: aid }) !== -1;
+        });
         const newColcount = {
-            title: (auditors2[aid - 1] && auditors2[aid - 1].length > 1 ? (aid + '审') : auditors2[aid - 1][0].name) + ' 审批|数量',
+            title: (audit && audit.length > 1 ? (aid + '审') : audit[0].name) + ' 审批|数量',
             colSpan: '2|1', rowSpan: '1|1',
             field: 'audit_amount_' + aid,
-            hAlign: 2, width: 60, type: 'Number', readOnly: _.findIndex(auditors2[aid - 1], { uid: parseInt(accountId) }) === -1 ? true : 'readOnly.isSettle' ,
+            hAlign: 2, width: 60, type: 'Number', readOnly: _.findIndex(audit, { uid: parseInt(accountId) }) === -1 ? true : 'readOnly.isSettle' ,
         };
         const newColTp = {
             title: '|金额',
@@ -219,6 +222,41 @@ $(document).ready(() => {
             }
         },
         deletePress: function (sheet) {
+            if (!sheet.zh_setting) return;
+            // 暂时仅支持移除数量
+            const sel = sheet.getSelections()[0], datas = [];
+            for (let iRow = sel.row; iRow < sel.row + sel.rowCount; iRow++) {
+                let bDel = false;
+                const node = sheet.zh_data[iRow];
+                const data = { id: node.id };
+                for (let iCol = sel.col; iCol < sel.col + sel.colCount; iCol++) {
+                    const col = sheet.zh_setting.cols[iCol];
+                    if (col.field === 'oamount2' || (col.readOnly !== true && _.includes(col.field, 'audit_amount_') && !checkIsSettle(node))) {
+                        // node[col.field] = null;
+                        if (col.field !== 'oamount2') {
+                            data.spamount = null;
+                        } else {
+                            data[col.field] = null;
+                        }
+                        bDel = true;
+                    }
+                }
+                if (bDel) datas.push(data);
+            }
+            if (datas.length > 0) {
+                // 更新至服务器
+                postData(window.location.pathname + '/save', { type:'paste_amount_rows', updateData: datas }, function (result) {
+                    changeList = result;
+                    changeSpreadObj.setAuditValue();
+                    SpreadJsObj.loadSheetData(changeSpreadSheet, SpreadJsObj.DataType.Data, changeList);
+                    changeSpreadObj.makeSjsFooter();
+                    changeSpreadObj.resetXmjSpread(SpreadJsObj.getSelectObject(changeSpreadSheet));
+                }, function () {
+                    changeSpreadObj.setAuditValue();
+                    SpreadJsObj.reLoadRowData(info.sheet, info.cellRange.row, info.cellRange.rowCount);
+                    return;
+                });
+            }
             return;
         },
         editEnded: function (e, info) {

+ 31 - 0
app/public/js/change_information_set.js

@@ -463,6 +463,37 @@ $(document).ready(() => {
             // setObjEnable($('#add-white-btn'), !readOnly && select && changeList.indexOf(select) !== -1);
         },
         deletePress: function (sheet) {
+            if (!sheet.zh_setting) return;
+            // 暂时仅支持移除数量
+            const sel = sheet.getSelections()[0], datas = [];
+            for (let iRow = sel.row; iRow < sel.row + sel.rowCount; iRow++) {
+                let bDel = false;
+                const node = sheet.zh_data[iRow];
+                for (let iCol = sel.col; iCol < sel.col + sel.colCount; iCol++) {
+                    const col = sheet.zh_setting.cols[iCol];
+                    if (col.field === 'camount' || col.field === 'oamount2') {
+                        node[col.field] = null;
+                        if (col.field === 'camount') {
+                            node.camount_expr = '';
+                            node.spamount = null;
+                        }
+                        delete node.waitingLoading;
+                        bDel = true;
+                    }
+                }
+                if (bDel) datas.push(node);
+            }
+            if (datas.length > 0) {
+                postData(window.location.pathname + '/save', { type:'paste', updateData: datas }, function (result) {
+                    changeList = result;
+                    SpreadJsObj.loadSheetData(changeSpreadSheet, SpreadJsObj.DataType.Data, changeList);
+                    changeSpreadObj.makeSjsFooter();
+                    changeSpreadObj.resetXmjSpread(SpreadJsObj.getSelectObject(changeSpreadSheet));
+                }, function () {
+                    SpreadJsObj.reLoadRowData(info.sheet, info.cellRange.row, info.cellRange.rowCount);
+                    return;
+                });
+            }
             return;
         },
         editEnded: function (e, info) {

+ 63 - 1
app/public/js/change_information_show.js

@@ -7,6 +7,28 @@
  * @date 2018/11/22
  * @version
  */
+$.event.special.valuechange = {
+    teardown: function (namespaces) {
+        $(this).unbind('.valuechange');
+    },
+
+    handler: function (e) {
+        $.event.special.valuechange.triggerChanged($(this));
+    },
+
+    add: function (obj) {
+        $(this).on('keyup.valuechange cut.valuechange paste.valuechange input.valuechange', obj.selector, $.event.special.valuechange.handler)
+    },
+
+    triggerChanged: function (element) {
+        var current = element[0].contentEditable === 'true' ? element.html() : element.val()
+            , previous = typeof element.data('previous') === 'undefined' ? element[0].defaultValue : element.data('previous');
+        if (current !== previous) {
+            element.trigger('valuechange', [element.data('previous')]);
+            element.data('previous', current);
+        }
+    }
+};
 $(document).ready(() => {
     const changeSpreadSetting = {
         cols: [
@@ -56,8 +78,11 @@ $(document).ready(() => {
     };
     for (const aid of aidList) {
         // const userinfo = _.find(auditList2, { 'uid': aid });
+        const audit = _.find(auditors2, function(item){
+            return _.findIndex(item, { audit_order: aid }) !== -1;
+        });
         const newColcount = {
-            title: (auditors2[aid - 1] && auditors2[aid - 1].length > 1 ? (aid + '审') : auditors2[aid - 1][0].name) + ' 审批|数量',
+            title: (audit && audit.length > 1 ? (aid + '审') : audit[0].name) + ' 审批|数量',
             colSpan: '2|1', rowSpan: '1|1',
             field: 'audit_amount_' + aid,
             hAlign: 2, width: 60, type: 'Number',
@@ -247,6 +272,43 @@ $(document).ready(() => {
             }
         });
     });
+
+    // 记录变更信息操作
+    $('body').on('valuechange', '#w_code', function (e, previous) {
+        const new_w_code = $(this).val();
+        if (new_w_code !== w_code) {
+            $('#show-save-btn').show();
+            $('#sp-btn').hide();
+            $('.title-main').addClass('bg-warning');
+        } else {
+            $('#show-save-btn').hide();
+            $('#sp-btn').show();
+            $('.title-main').removeClass('bg-warning');
+        }
+    });
+
+    // 保存修改ajax提交(不刷新页面)
+    $('.save_change_btn').on('click', function () {
+        const new_w_code = $('#w_code').val();
+        // 后改为br
+        // 更新至服务器
+        postData(window.location.pathname + '/save', { type:'info', updateData: { w_code: new_w_code } }, function (result) {
+            toastr.success(result ? result.msg : '');
+            $('#show-save-btn').hide();
+            $('#sp-btn').show();
+            $('.title-main').removeClass('bg-warning');
+            w_code = new_w_code;
+        });
+        return false;
+    });
+
+    $('#cancel_change').on('click', function () {
+        $('#show-save-btn').hide();
+        $('#sp-btn').show();
+        $('.title-main').removeClass('bg-warning');
+        $('#w_code').val(w_code);
+        // toastr.success('已还原到上次保存状态');
+    });
 });
 /**
  * 获取成功后的操作

+ 195 - 81
app/public/js/contract_detail.js

@@ -1,12 +1,12 @@
 const copyBlockTag = 'zh.calc.copyBlock';
-const ckBillsSpread = '/contract/' + window.location.pathname.split('/')[2] + '/detail/contract-billsSelect';
 $(document).ready(function() {
+    const ckBillsSpread = '/contract/' + window.location.pathname.split('/')[2] + '/' + contractConst.typeMap[contract_type] + '/detail/contract-billsSelect';
     autoFlashHeight();
     const contractSpreadSetting = {
         cols: [
             {title: '编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 100, formatter: '@', readOnly: 'readOnly.code', cellType: 'tree'},
             {title: '合同编号', colSpan: '1', rowSpan: '2', field: 'c_code', hAlign: 0, width: 120, formatter: '@', readOnly: true},
-            {title: '项目名称/合同名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 240, formatter: '@', readOnly: 'readOnly.code'},
+            {title: '项目名称/合同名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 240, formatter: '@', readOnly: 'readOnly.code', cellType: 'ellipsisAutoTip', scrollHeightClass: '.sjs-height-1'},
             {title: '创建人', colSpan: '1', rowSpan: '2', field: 'username', hAlign: 1, width: 80, formatter: '@', readOnly: true},
             {title: '合同金额', colSpan: '1', rowSpan: '2', field: 'total_price', hAlign: 2, width: 120, formatter: '@', readOnly: true},
         ],
@@ -36,7 +36,7 @@ $(document).ready(function() {
         localCache: {
             key: 'contract-spread',
             colWidth: true,
-        }
+        },
     };
 
     const contractCol = {
@@ -67,12 +67,12 @@ $(document).ready(function() {
         contractSpreadSetting.cols.push({title: '回款进度', colSpan: '1', rowSpan: '2', formatter: '@', readOnly: true, field: 'stackedBar', hAlign: 0, width: 200, cellType: 'stackedBar', stackedBarCover: true, bc_type: 'grid', getTip: getStackedBarTip});
     }
     contractSpreadSetting.cols.push({title: '合同状态', colSpan: '1', rowSpan: '2', field: 'status', hAlign: 1, width: 100, formatter: '@', readOnly: true, getValue:'getValue.status', foreColor:'foreColor.status'});
-    contractSpreadSetting.cols.push({title: '备注', colSpan: '1', rowSpan: '2', field: 'remark', hAlign: 0, width: 120, formatter: '@', readOnly: !permission_edit, cellType: 'ellipsisAutoTip', scrollHeightClass: '.sjs-height-1'});
+    contractSpreadSetting.cols.push({title: '备注', colSpan: '1', rowSpan: '2', field: 'remark', hAlign: 0, width: 120, formatter: '@', readOnly: 'readOnly.code', cellType: 'ellipsisAutoTip', scrollHeightClass: '.sjs-height-1'});
 
     const contractSpread = SpreadJsObj.createNewSpread($('#contract-spread')[0]);
     const contractSheet = contractSpread.getActiveSheet();
-    sjsSettingObj.setGridSelectStyle(contractSpreadSetting);
-    // sjsSettingObj.setFxTreeStyle(contractSpreadSetting, sjsSettingObj.FxTreeStyle.jz);
+    // sjsSettingObj.setGridSelectStyle(contractSpreadSetting);
+    sjsSettingObj.setFxTreeStyle(contractSpreadSetting, sjsSettingObj.FxTreeStyle.contract);
     SpreadJsObj.initSpreadSettingEvents(contractSpreadSetting, contractCol);
     SpreadJsObj.initSheet(contractSheet, contractSpreadSetting);
     const treeSetting = {
@@ -81,11 +81,11 @@ $(document).ready(function() {
         order: 'order',
         level: 'level',
         rootId: -1,
-        keys: ['id', 'tid', 'spid'],
+        keys: ['id', 'tid', 'spid', 'contract_type'],
         calcFields: ['pay_price', 'total_price', 'sf_price', 'debit_price', 'yf_price'],
         autoExpand: 3,
-        markExpandKey: 'contract-bills-expand',
-        markExpandSubKey: window.location.pathname.split('/')[2],
+        markExpandKey: 'contract-bills-expand' + window.location.pathname.split('/')[2] + contractConst.typeMap[contract_type],
+        markExpandSubKey: window.location.pathname.split('/')[2] + contractConst.typeMap[contract_type],
     };
     const calcField = ['total_price', 'yf_price'];
     const calcFieldColor = {'total_price': '#bbb', 'yf_price': '#28a745'};
@@ -127,27 +127,6 @@ $(document).ready(function() {
             }
             return [tree, node, count];
         },
-        // setAllForeColor: function (sheet) {
-        //     for(var i = 0; i < sheet.zh_tree.nodes.length; i++){
-        //         if (!sheet.zh_tree.nodes[i].c_code) continue;
-        //         const value = contractCol.getValue.status(sheet.zh_tree.nodes[i]);
-        //         console.log(i, value);
-        //         this.setForeColor(sheet, i, value);
-        //     }
-        // },
-        // setForeColor: function (sheet, row, value = null, col = 7, color = '') {
-        //     value = value !== null ? value : sheet.getValue(row, col);
-        //     if (!value) return;
-        //     if (value === '已结算') {
-        //         color = '#6c757d';
-        //     } else if (value === '已完成') {
-        //         color = '#28a745';
-        //     } else if (value === '履行中') {
-        //         color = '#da9500';
-        //     }
-        //     console.log(sheet.getCell(row, col).text(), color);
-        //     sheet.getCell(row, col).foreColor(color);
-        // },
         /**
          * 刷新顶部按钮是否可用
          * @param sheet
@@ -178,21 +157,31 @@ $(document).ready(function() {
                 return;
             }
             const first = sheet.zh_tree.nodes[row];
-            if (first && permission_add && (is_admin || _.findIndex(contractTreeAudits, { uid: user_id }) === -1 || _.findIndex(contractTreeAudits, { contract_id: first.contract_id, uid: user_id }) !== -1)) {
-                $('#add-cons-btn').show();
+            if (first && first.c_code) {
+                const parent = tree.getParent(first)
+                if (parent && permission_add && (is_admin || _.findIndex(contractTreeAudits, { uid: user_id }) === -1 || _.findIndex(contractTreeAudits, { contract_id: parent.contract_id, uid: user_id }) !== -1)) {
+                    $('#add-cons-btn').show();
+                } else {
+                    $('#add-cons-btn').hide();
+                }
             } else {
-                $('#add-cons-btn').hide();
+                if (first && permission_add && (is_admin || _.findIndex(contractTreeAudits, { uid: user_id }) === -1 || _.findIndex(contractTreeAudits, { contract_id: first.contract_id, uid: user_id }) !== -1)) {
+                    $('#add-cons-btn').show();
+                } else {
+                    $('#add-cons-btn').hide();
+                }
             }
             if (!first) {
                 invalidAll();
                 return;
             }
-            let last = first, sameParent = true, childCanDel = true, hadContract = this.checkContract(first);
+            let last = first, sameParent = true, childCanDel = true;
+                // hadContract = this.checkContract(first);
             if (sel.rowCount > 1 && first) {
                 for (let r = 1; r < sel.rowCount; r++) {
                     const rNode = tree.nodes[sel.row + r];
                     childCanDel = this.checkDelete(rNode, childCanDel);
-                    if (!hadContract) hadContract = this.checkContract(rNode);
+                    // if (!hadContract) hadContract = this.checkContract(rNode);
                     if (!rNode) {
                         sameParent = false;
                         break;
@@ -215,6 +204,13 @@ $(document).ready(function() {
             //         break;
             //     }
             // }
+            const nextNodes = _.filter(tree.getChildren(tree.getParent(first)), function (item){ return item.order > first.order });
+            // let nextHadContract = false;
+            // for (const next of nextNodes) {
+            //     if (nextHadContract) continue;
+            //     nextHadContract = this.checkContract(next);
+            // }
+            const nextHadContract = _.findIndex(nextNodes, function(item) { return item.c_code; }) !== -1;
             const valid = !sheet.zh_setting.readOnly;
 
             setObjEnable($('a[name=base-opr][type=add]'), valid && first && first.level > 1);
@@ -223,9 +219,9 @@ $(document).ready(function() {
             setObjEnable($('a[name=base-opr][type=up-move]'), valid && first && sameParent && first.level > 1 && preNode);
             setObjEnable($('a[name=base-opr][type=down-move]'), valid && first && sameParent && first.level > 1 && !tree.isLastSibling(last));
             setObjEnable($('a[name=base-opr][type=up-level]'), valid && first && sameParent && tree.getParent(first)
-                && first.level > 2 && tree.isLastSibling(last) && upPower && !hadContract);
+                && first.level > 2 && (!nextHadContract || tree.isLastSibling(last)) && upPower && first.c_code === undefined);
             setObjEnable($('a[name=base-opr][type=down-level]'), valid && first && sameParent
-                && first.level > 1 && preNode && (preNode.children.length > 0 || preNode.children.length === 0) && !hadContract && preNode.c_code === undefined);
+                && first.level > 1 && preNode && (preNode.children.length > 0 || preNode.children.length === 0) && preNode.c_code === undefined);
             // setObjEnable($('#cut'), valid);
             // setObjEnable($('#paste'), valid);
         },
@@ -373,8 +369,9 @@ $(document).ready(function() {
                 }
                 return {...pay, showEdit}
             })
+            console.log(pays);
             newPays.forEach((pay, idx) => {
-                paysHtml += `<tr class="text-center">
+                paysHtml += `<tr class="text-center" data-cpid="${pay.id}">
                                         <td>${idx + 1}</td>
                                         <td>${moment(pay.pay_time).format('YYYY-MM-DD')}</td>
                                         <td>${pay.pay_price}</td>
@@ -385,7 +382,7 @@ $(document).ready(function() {
                                         <td>${pay.username}</td>
                                         <td>${moment(pay.create_time).format('YYYY-MM-DD HH:mm:ss')}</td>
                                         <td>${pay.remark}</td>
-                                        <td><a href="javascript:void(0);" class="text-primary open-pay-files" data-cpid="${pay.id}"><i class="fa fa-paperclip fa-rotate-90"></i></a></td>
+                                        <td><a href="javascript:void(0);" class="text-primary open-pay-files" data-cpid="${pay.id}"><i class="fa fa-paperclip fa-rotate-90"></i></a> <span class="files-num">${pay.files.length > 0 ? pay.files.length : ''}</span></td>
                                         <td><a href="javascript:void(0);" class="text-primary pay-edit" data-id="${pay.id}" ${ !pay.showEdit ? `style="display:none"` : ''}>编辑</a> <a href="javascript:void(0);" class="text-danger pay-del" data-id="${pay.id}" ${ !pay.showEdit ? `style="display:none"` : ''}>删除</a></td>
                                     </tr>`;
             });
@@ -448,11 +445,23 @@ $(document).ready(function() {
                 if (!info.oldSelections || info.newSelections[0].row !== info.oldSelections[0].row || info.newSelections[0].rowCount !== info.oldSelections[0].rowCount) {
                     contractTreeSpreadObj.refreshOperationValid(info.sheet);
                     contractTreeSpreadObj.setContract(info.sheet);
+                    SpreadJsObj.saveTopAndSelect(info.sheet, ckBillsSpread);
                 }
             } else {
                 $('#add-cons-btn').hide();
             }
         },
+        cleanData: function (result) {
+            if (result && result.update && result.update.length > 0) {
+                for (const r of result.update) {
+                    if (!r.c_code) {
+                        r.total_price = null;
+                        r.yf_price = null;
+                    }
+                }
+            }
+            return result;
+        },
         /**
          * 新增节点
          * @param spread
@@ -525,6 +534,7 @@ $(document).ready(function() {
                         count: type === 'add' ? addCount : count,
                     }
                 }, function (result) {
+                    self.cleanData(result);
                     const refreshData = tree.loadPostData(result);
                     self.refreshTree(sheet, refreshData);
                     if (['up-move', 'down-move'].indexOf(type) > -1) {
@@ -935,6 +945,20 @@ $(document).ready(function() {
             callback: function (key, opt) {
                 $('#cons-add').modal('show');
             },
+            visible: function (key, opt) {
+                const sheet = contractSheet;
+                const selection = sheet.getSelections();
+                const sel = selection ? selection[0] : sheet.getSelections()[0];
+                const row = sel ? sel.row : -1;
+                const tree = sheet.zh_tree;
+                if (!tree) return false;
+                const first = sheet.zh_tree.nodes[row];
+                if (first && first.c_code) {
+                    const parent = sheet.zh_tree.getParent(first);
+                    return parent && (is_admin || _.findIndex(contractTreeAudits, { uid: user_id }) === -1 || _.findIndex(contractTreeAudits, { contract_id: parent.contract_id, uid: user_id }) !== -1);
+                }
+                return first && (is_admin || _.findIndex(contractTreeAudits, { uid: user_id }) === -1 || _.findIndex(contractTreeAudits, { contract_id: first.contract_id, uid: user_id }) !== -1);
+            },
             disabled: function (key, opt) {
                 const sheet = contractSheet;
                 const selection = sheet.getSelections();
@@ -1172,7 +1196,7 @@ $(document).ready(function() {
                     data[c] = $('#htdetail_' + c + ' input').val();
                 }
             }
-            if (data.c_code === '' || data.c_name === '') {
+            if (data.c_code === '' || data.name === '') {
                 toastr.warning('合同编号和合同名称不能为空');
                 return;
             }
@@ -1183,6 +1207,11 @@ $(document).ready(function() {
                 toastr.warning('合同金额只能输入数字');
                 return;
             }
+            if (parseFloat(data.total_price) < node.yf_price) {
+                const name = contract_type === contractConst.type.expenses ? '付' : '回';
+                toastr.warning('合同金额不能小于累计应' + name);
+                return;
+            }
             if (data.party_b === '') {
                 toastr.warning('签订单位(乙方)不能为空');
                 return;
@@ -1327,6 +1356,8 @@ $(document).ready(function() {
         $('#cons-addpay input[name="sf_price"]').val(cpInfo ? cpInfo.sf_price : '');
         $('#cons-addpay select[name="pay_type"]').val(cpInfo ? cpInfo.pay_type : $('#cons-addpay select[name="pay_type"] option:first').text());
         $('#cons-addpay textarea[name="remark"]').val(cpInfo ? cpInfo.remark : '');
+        $('#cons-addpay .yf-tips').text('');
+        $('#cons-addpay .sf-tips').text('');
 
     }
 
@@ -1365,6 +1396,7 @@ $(document).ready(function() {
                 postDataWithFile('/contract/' + stid + '/detail/' + contractConst.typeMap[contract_type] + '/' + node.id + '/pay/' + cpInfo.id + '/file/upload', formData, function (result) {
                     cpInfo.files = result;
                     contractTreeSpreadObj.openContractPayFiles(cpInfo);
+                    $('#htpay-table tbody').find('tr[data-cpid="' + cpInfo.id + '"]').find('.files-num').text(result.length || '');
                 });
             }
         }
@@ -1384,6 +1416,7 @@ $(document).ready(function() {
             postData('/contract/' + stid + '/detail/' + contractConst.typeMap[contract_type] + '/' + node.id + '/pay/' + cpInfo.id + '/file/delete', { id: fid }, function (result) {
                 cpInfo.files = result;
                 contractTreeSpreadObj.openContractPayFiles(cpInfo);
+                $('#htpay-table tbody').find('tr[data-cpid="' + cpInfo.id + '"]').find('.files-num').text(result.length || '');
             });
         }, '确认删除该文件?');
     });
@@ -1401,6 +1434,7 @@ $(document).ready(function() {
         // SpreadJsObj.initSpreadSettingEvents(changeSpreadSetting, changeCol);
         SpreadJsObj.loadSheetData(contractSheet, SpreadJsObj.DataType.Tree, contractTree);
         SpreadJsObj.loadTopAndSelect(contractSheet, ckBillsSpread);
+        contractTreeSpreadObj.setContract(contractSheet);
         checkShowLast(result.contractTree.length);
         contractTreeSpreadObj.refreshOperationValid(contractSheet);
         // contractTreeSpreadObj.setAllForeColor(contractSheet);
@@ -1445,8 +1479,8 @@ $(document).ready(function() {
 
         const sqSpread = SpreadJsObj.createNewSpread($('#sq-spread')[0]);
         const sqSheet = sqSpread.getActiveSheet();
-        sjsSettingObj.setGridSelectStyle(sqSpreadSetting);
-        // sjsSettingObj.setFxTreeStyle(contractSpreadSetting, sjsSettingObj.FxTreeStyle.jz);
+        // sjsSettingObj.setGridSelectStyle(sqSpreadSetting);
+        sjsSettingObj.setFxTreeStyle(sqSpreadSetting, sjsSettingObj.FxTreeStyle.jz);
         SpreadJsObj.initSheet(sqSheet, sqSpreadSetting);
         const sqTreeSetting = {
             id: 'contract_id',
@@ -1655,6 +1689,14 @@ $(document).ready(function() {
 
 
     if (permission_add) {
+        $('#cons-add').on('show.bs.modal', function () {
+            $('#cons-add input[name="code"]').val('');
+            $('#cons-add input[name="name"]').val('');
+            $('#cons-add input[name="total_price"]').val('');
+            $('#cons-add input[name="party_b"]').val('');
+            $('#cons-add textarea[name="remark"]').val('');
+        });
+
         $('#add-contract').click(function () {
             const node = SpreadJsObj.getSelectObject(contractSheet);
             if (!node) {
@@ -1701,10 +1743,57 @@ $(document).ready(function() {
 
     $('#cons-addpay input[type="number"]').change(function () {
         const name = $(this).attr('name');
+        const node = SpreadJsObj.getSelectObject(contractSheet);
+        if (!node || !node.c_code) {
+            toastr.error('请选择一个合同节点');
+            return;
+        }
+        if (node.uid !== user_id) {
+            toastr.error('只能修改自己的合同' + contractConst.typeName[contract_type]);
+            return;
+        }
+        if (node.settle_code) {
+            toastr.error('该合同已结算,不能修改');
+            return;
+        }
+        let sf_price = $('#cons-addpay input[name="sf_price"]').val() || 0;
+        const pay_price = $('#cons-addpay input[name="pay_price"]').val() || 0;
+        const debit_price = $('#cons-addpay input[name="debit_price"]').val() || 0;
+        const yf_price = ZhCalc.sub(pay_price, debit_price);
+        $('#cons-addpay .yf-tips').text('');
+        const cpid = $('#cons-addpay input[name="cpid"]').val();
+        if (cpid) {
+            const cpInfo = _.find(contractPays, { id: parseInt(cpid) });
+            const newNodePayPrice = ZhCalc.add(ZhCalc.sub(node.pay_price, cpInfo.pay_price), parseFloat(pay_price));
+            const newNodeDebitPrice = ZhCalc.add(ZhCalc.sub(node.debit_price, cpInfo.debit_price), parseFloat(debit_price));
+            const newNodeYfPrice = ZhCalc.sub(newNodePayPrice, newNodeDebitPrice);
+            if (parseFloat(sf_price) > ZhCalc.add(cpInfo.sf_price, ZhCalc.sub(newNodeYfPrice, node.sf_price))) {
+                $('#cons-addpay .sf-tips').text(' ≤ ' + ZhCalc.add(cpInfo.sf_price, ZhCalc.sub(newNodeYfPrice, node.sf_price)));
+            } else {
+                $('#cons-addpay .sf-tips').text('');
+            }
+            if (parseFloat(yf_price) > ZhCalc.add(cpInfo.yf_price, ZhCalc.sub(node.total_price, node.yf_price))) {
+                $('#cons-addpay .yf-tips').text(' ≤ ' + ZhCalc.add(cpInfo.yf_price, ZhCalc.sub(node.total_price, node.yf_price)));
+            } else {
+                $('#cons-addpay .yf-tips').text('');
+            }
+        } else {
+            if (name !== 'sf_price') {
+                $('#cons-addpay input[name="sf_price"]').val(yf_price);
+                sf_price = yf_price;
+            }
+            if (parseFloat(sf_price) > ZhCalc.sub(ZhCalc.add(node.yf_price, yf_price), node.sf_price)) {
+                $('#cons-addpay .sf-tips').text(' ≤ ' + ZhCalc.sub(ZhCalc.add(node.yf_price, yf_price), node.sf_price));
+            } else {
+                $('#cons-addpay .sf-tips').text('');
+            }
+            if (parseFloat(yf_price) > ZhCalc.sub(node.total_price, node.yf_price)) {
+                $('#cons-addpay .yf-tips').text(' ≤ ' + ZhCalc.sub(node.total_price, node.yf_price));
+            } else {
+                $('#cons-addpay .yf-tips').text('');
+            }
+        }
         if (name === 'pay_price' || name === 'debit_price') {
-            const pay_price = $('#cons-addpay input[name="pay_price"]').val() || 0;
-            const debit_price = $('#cons-addpay input[name="debit_price"]').val() || 0;
-            const yf_price = ZhCalc.sub(pay_price, debit_price);
             $('#cons-addpay input[name="yf_price"]').val(yf_price);
         }
     });
@@ -1733,25 +1822,7 @@ $(document).ready(function() {
             remark: $('#cons-addpay textarea[name="remark"]').val(),
         }
         const name = contract_type === contractConst.type.expenses ? '付' : '回';
-        if (!data.pay_price) {
-            toastr.error('请输入'+ name +'款金额');
-            return;
-        }
-        // 金额只能输入数字
-        if (!/^\d+(\.\d+)?$/.test(data.pay_price)) {
-            toastr.error(name + '款金额只能输入数字');
-            return;
-        }
-        if (data.debit_price && !/^\d+(\.\d+)?$/.test(data.debit_price)) {
-            toastr.error('扣款金额只能输入数字');
-            return;
-        }
-        if (data.sf_price && !/^\d+(\.\d+)?$/.test(data.sf_price)) {
-            toastr.error('实'+ name +'金额只能输入数字');
-            return;
-        }
-        if (!data.pay_type) {
-            toastr.error('请选择' + contractConst.typeName[contract_type] + '方式');
+        if (!judgePays(node, data, name)) {
             return;
         }
         console.log(node, data);
@@ -1798,39 +1869,82 @@ $(document).ready(function() {
             remark: $('#cons-addpay textarea[name="remark"]').val(),
         }
         const name = contract_type === contractConst.type.expenses ? '付' : '回';
+        if (!judgePays(node, data, name, cpInfo)) {
+            return;
+        }
+        console.log(node, data);
+        postData(window.location.pathname + '/update', {postType: 'save-contract-pay', postData: { select: node.id, pay: data }}, function (result) {
+            const refreshNode = contractTree.loadPostData(result.node);
+            contractTreeSpreadObj.refreshTree(contractSheet, refreshNode);
+            contractTreeSpreadObj.setContractPays(result.pays, node);
+            // const selection = contractSheet.getSelections();
+            // const sel = selection ? selection[0] : contractSheet.getSelections()[0];
+            // const row = sel ? sel.row : -1;
+            // contractTreeSpreadObj.setForeColor(contractSheet, row);
+            $('#cons-addpay').modal('hide');
+        })
+    });
+
+    function judgePays(node, data, name, cpInfo = null) {
+        let flag = true;
+        if (!data.pay_time) {
+            toastr.error('请输入'+ (name === '付' ? '支付' : '回款') +'日期');
+            return false;
+        }
         if (!data.pay_price) {
             toastr.error('请输入'+ name +'款金额');
-            return;
+            return false;
         }
         // 金额只能输入数字
         if (!/^\d+(\.\d+)?$/.test(data.pay_price)) {
             toastr.error(name + '款金额只能输入数字');
-            return;
+            return false;
         }
         if (data.debit_price && !/^\d+(\.\d+)?$/.test(data.debit_price)) {
             toastr.error('扣款金额只能输入数字');
-            return;
+            return false;
+        }
+        if (parseFloat(data.debit_price) > parseFloat(data.pay_price)) {
+            toastr.error('扣款金额不能大于'+ name +'款金额');
+            return false;
         }
         if (data.sf_price && !/^\d+(\.\d+)?$/.test(data.sf_price)) {
             toastr.error('实'+ name +'金额只能输入数字');
-            return;
+            return false;
         }
+        if (cpInfo) {
+            const newNodePayPrice = ZhCalc.add(ZhCalc.sub(node.pay_price, cpInfo.pay_price), parseFloat(data.pay_price));
+            const newNodeDebitPrice = ZhCalc.add(ZhCalc.sub(node.debit_price, cpInfo.debit_price), parseFloat(data.debit_price));
+            const newNodeYfPrice = ZhCalc.sub(newNodePayPrice, newNodeDebitPrice);
+            const newNodeSfPrice = ZhCalc.add(ZhCalc.sub(node.sf_price, cpInfo.sf_price), parseFloat(data.sf_price));
+            if (newNodeYfPrice > node.total_price) {
+                toastr.error('累计应'+ name +'金额不能大于合同金额');
+                return false;
+            }
+            if (newNodeSfPrice > newNodeYfPrice) {
+                toastr.error('累计实'+ name +'金额不能大于累计应'+ name +'金额');
+                return false;
+            }
+        } else {
+            if (ZhCalc.add(parseFloat(data.yf_price), node.yf_price) > node.total_price) {
+                toastr.error('累计应'+ name +'金额不能大于合同金额');
+                return false;
+            }
+            if (ZhCalc.add(parseFloat(data.sf_price), node.sf_price) > ZhCalc.add(parseFloat(data.yf_price), node.yf_price)) {
+                toastr.error('累计实'+ name +'金额不能大于累计应'+ name +'金额');
+                return false;
+            }
+        }
+        // if (parseFloat(data.sf_price) > parseFloat(data.yf_price)) {
+        //     toastr.error('实'+ name +'金额不能大于应'+ name +'金额');
+        //     return false;
+        // }
         if (!data.pay_type) {
             toastr.error('请选择' + contractConst.typeName[contract_type] + '方式');
-            return;
+            return false;
         }
-        console.log(node, data);
-        postData(window.location.pathname + '/update', {postType: 'save-contract-pay', postData: { select: node.id, pay: data }}, function (result) {
-            const refreshNode = contractTree.loadPostData(result.node);
-            contractTreeSpreadObj.refreshTree(contractSheet, refreshNode);
-            contractTreeSpreadObj.setContractPays(result.pays, node);
-            // const selection = contractSheet.getSelections();
-            // const sel = selection ? selection[0] : contractSheet.getSelections()[0];
-            // const row = sel ? sel.row : -1;
-            // contractTreeSpreadObj.setForeColor(contractSheet, row);
-            $('#cons-addpay').modal('hide');
-        })
-    });
+        return flag;
+    }
 
     $('body').on('click', '.open-pay-files', function () {
         const cpid = $(this).attr('data-cpid');

+ 1 - 1
app/public/js/contract_index.js

@@ -57,7 +57,7 @@ $(document).ready(function() {
                 if (is_admin) {
                     html.push(`<td class="text-center">`);
                     if (!node.is_folder) {
-                        html.push(`<a href="javascript:void(0);" data-toggle="modal" data-stid="${node.id}" class="btn btn-sm btn-primary get-audits"> 成员管理</a>`);
+                        html.push(`<a href="javascript:void(0);" data-toggle="modal" data-stid="${node.id}" class="btn btn-sm btn-outline-primary get-audits"> 成员管理</a>`);
                     }
                     html.push('</td>');
                 }

+ 11 - 1
app/public/js/file_detail.js

@@ -475,7 +475,8 @@ $(document).ready(function() {
     const levelTreeSetting = {
         treeId: 'filing',
         view: {
-            selectedMulti: false
+            selectedMulti: false,
+            showTitle: false,
         },
         data: {
             simpleData: {
@@ -540,6 +541,10 @@ $(document).ready(function() {
                     toastr.error('顶层节点请勿移动');
                     return false;
                 }
+                if (nodes[0].is_fixed) {
+                    toastr.error('固定分类请勿移动');
+                    return false;
+                }
                 if (nodes[0].source_node.filing_type !== target.source_node.filing_type) {
                     toastr.error('请勿跨越最顶层节点移动');
                     return false;
@@ -591,6 +596,11 @@ $(document).ready(function() {
     });
     $('#add-child').click(() => {
         if (!filingObj.curFiling) return;
+        const fixedChild = filingObj.curFiling.source_node.children.find(x => { return x.is_fixed; });
+        if (fixedChild) {
+            toastr.error('该分类下存在固定分类,不可添加子级');
+            return;
+        }
         if (filingObj.curFiling.source_node.file_count > 0) {
             toastr.error('该分类下已导入文件,不可添加子级');
             return;

+ 1 - 1
app/public/js/shares/batch_import.js

@@ -131,7 +131,7 @@ const BatchImportStageGcl = function (setting) {
         importStageGcl: async function (node, cover, ignore, loadChange) {
             const updateData = { lid: node.lid, type: 'stage', cover, ignore, loadChange, tenders: [] };
             for (const tender of node.children) {
-                updateData.tenders.push({ tid: tender.tid, name: tender.name, stageCount: tender.stageCount, stage: tender.stage });
+                updateData.tenders.push({ tid: tender.tid, name: tender.name, stageCount: tender.stageCount, stage: tender.stage, match_code: tender.match_code });
             }
 
             const result = await postDataAsync(window.location.pathname + '/sumLoad', updateData);

+ 31 - 1
app/public/js/shares/sjs_setting.js

@@ -29,11 +29,41 @@ const sjsSettingObj = (function () {
             }
         }
     };
+    const setContractFxTreeStyle = function (setting) {
+        setting.selectedBackColor = '#fffacd';
+        setting.tree = {
+            getFont: function (sheet, data, row, col, defaultFont) {
+                if (sheet.zh_tree) {
+                    const levelField = sheet.zh_tree.setting.level;
+                    return data[levelField] === 1 ? 'bold ' + defaultFont : defaultFont;
+                } else {
+                    return defaultFont;
+                }
+            },
+            getColor: function (sheet, data, row, col, defaultColor) {
+                if (sheet.zh_tree) {
+                    const levelField = sheet.zh_tree.setting.level;
+                    if (data[levelField] === 2) {
+                        return '#C4CAFB';
+                    } else if (!data.c_code && data[levelField] > 2) {
+                        return '#DFE8F9';
+                    } else {
+                        return defaultColor;
+                    }
+                } else {
+                    return defaultColor;
+                }
+            }
+        }
+    };
     const setFxTreeStyle = function (setting, tag) {
         switch (tag) {
             case FxTreeStyle.jz:
                 setJzFxTreeStyle(setting);
                 break;
+            case FxTreeStyle.contract:
+                setContractFxTreeStyle(setting);
+                break;
         }
     };
 
@@ -130,4 +160,4 @@ const sjsSettingObj = (function () {
         setTpThousandthFormat, setThousandthFormat, setTpColsThousandthFormat,
         setPropValue, set3FCols, setQcCols, setOrgPriceCol, setNodeTypeCol, setIsTpCol,
     };
-})();
+})();

+ 2 - 1
app/public/js/shares/tender_select.js

@@ -151,7 +151,7 @@ const TenderSelect = function (setting) {
                 defaultRowHeight: 21,
                 headerFont: '12px 微软雅黑',
                 font: '12px 微软雅黑',
-                headColWidth: [],
+                headColWidth: [30],
                 getColor: function (sheet, data, row, col, defaultColor) {
                     if (data) {
                         return data.invalid ? '#ddd' : defaultColor;
@@ -168,6 +168,7 @@ const TenderSelect = function (setting) {
                 resultSpreadSetting.cols.push(
                     {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 180, formatter: '@', readOnly: true, cellType: 'ellipsisAutoTip'},
                     {title: '可选期', colSpan: '1', rowSpan: '1', field: 'stage', hAlign: 0, width: 60},
+                    {title: '指定项目节', colSpan: '1', rowSpan: '1', field: 'match_code', hAlign: 0, width: 70, formatter: '@', },
                 )
             }
             SpreadJsObj.initSheet(this.resultSheet, resultSpreadSetting);

+ 38 - 1
app/service/change.js

@@ -129,7 +129,7 @@ module.exports = app => {
             change.finalAuditorIds = change.userGroups[change.userGroups.length - 1].map(x => { return x.uid; });
         }
 
-        async add(tenderId, userId, code, plan_code, name, delimit = 100) {
+        async add(tenderId, userId, code, plan_code, name, plan_list = false, delimit = 100) {
             const sql = 'SELECT COUNT(*) as count FROM ?? WHERE `tid` = ? AND ((`code` = ? AND `status` != ?) OR (`p_code` = ? AND `status` = ?))';
             const sqlParam = [this.tableName, tenderId, code, audit.change.status.checked, code, audit.change.status.checked];
             const codeCount = await this.db.queryOne(sql, sqlParam);
@@ -180,6 +180,43 @@ module.exports = app => {
                         content = content + (planInfo.content ? (planInfo.reason ? '\r\n' : '') + planInfo.content.replace(/[\r\n]/g, '\r\n') : '');
                         change.content = content ? content : null;
                         change.expr = planInfo.expr;
+                        if (plan_list) {
+                            const planList = await this.ctx.service.changePlanList.getAllDataByCondition({ where: { cpid: planInfo.id } });
+                            const insertList = [];
+                            for (const p of planList) {
+                                insertList.push({
+                                    tid: tenderId,
+                                    cid,
+                                    lid: '0',
+                                    code: p.code,
+                                    name: p.name,
+                                    unit: p.unit,
+                                    unit_price: p.unit_price,
+                                    oamount: p.oamount,
+                                    oamount2: p.oamount,
+                                    camount: p.samount,
+                                    camount_expr: p.samount,
+                                    samount: '',
+                                    gcl_id: '',
+                                    mx_id: '',
+                                    spamount: p.camount,
+                                    detail: '',
+                                    xmj_code: null,
+                                    xmj_jldy: null,
+                                    xmj_dwgc: null,
+                                    xmj_fbgc: null,
+                                    xmj_fxgc: null,
+                                    is_valuation: 1,
+                                    order: null,
+                                    delimit,
+                                });
+                            }
+                            if (insertList.length > 0) {
+                                await this.transaction.insert(this.ctx.service.changeAuditList.tableName, insertList);
+                                // // 重新算变更令总额
+                                // await this.ctx.changeAuditList.calcCamountSum(this.transaction);
+                            }
+                        }
                     }
                 }
                 const operate = await this.transaction.insert(this.tableName, change);

+ 9 - 0
app/service/construction_unit.js

@@ -5,6 +5,7 @@
  */
 
 const BaseService = require('../base/base_service');
+const accountGroup = require('../const/account_group');
 
 module.exports = app => {
 
@@ -116,6 +117,14 @@ module.exports = app => {
             // 删除单位
             return await this.db.delete(this.tableName, { id });
         }
+
+        async getReportData(pid) {
+            const data = this.getAllDataByCondition({ where: { pid } });
+            data.forEach(x => {
+                x.type_str = accountGroup.group[x.type];
+            });
+            return data;
+        }
     }
     return ConstructionUnit;
 };

+ 37 - 7
app/service/contract_tree.js

@@ -305,7 +305,7 @@ module.exports = app => {
                 const maxOrder = await this.ctx.service.contract.getMaxOrder(options, select[this.setting.kid], transaction);
                 const newDatas = [];
                 const maxId = await this._getMaxLid(options);
-                for (let i = 0; i < count; i++) {
+                for (let i = 1; i < count + 1; i++) {
                     const newData = [];
                     if (this.setting.uuid) newData.id = this.uuid.v4();
                     newData[this.setting.kid] = maxId + i;
@@ -314,7 +314,7 @@ module.exports = app => {
                     newData[this.setting.type] = options[this.setting.type];
                     newData[this.setting.mid] = options.tid || null;
                     newData[this.setting.level] = select[this.setting.level] + 1;
-                    newData[this.setting.order] = maxOrder + i;
+                    newData[this.setting.order] = maxOrder - 1 + i;
                     newData[this.setting.fullPath] = select[this.setting.fullPath] + '-' + newData[this.setting.kid];
                     newData[this.setting.isLeaf] = true;
                     newDatas.push(newData);
@@ -336,7 +336,7 @@ module.exports = app => {
 
             let createData = await this.getLastChildData(options, select[this.setting.kid]);
             let updateData = select;
-            return { create: createData, update: updateData };
+            return { create: [createData], update: [updateData] };
         }
 
         /**
@@ -590,6 +590,11 @@ module.exports = app => {
             const selects = await this.getDataByKidAndCount(options, kid, count);
 
             if (selects.length !== count) throw '升级节点数据错误';
+            if (this._.findIndex(selects, function (item) {
+                return item.c_code;
+            }) !== -1) {
+                throw '存在合同节点不可升级';
+            }
             const first = selects[0], last = selects[count - 1];
             const parent = await this.getDataByKid(options, first[this.setting.pid]);
             if (!parent) throw '升级节点数据错误';
@@ -651,6 +656,11 @@ module.exports = app => {
             if (!count) count = 1;
             const selects = await this.getDataByKidAndCount(options, kid, count);
             if (!selects) throw '降级节点数据错误';
+            if (this._.findIndex(selects, function (item) {
+                return item.c_code;
+            }) !== -1) {
+                throw '存在合同节点不可降级';
+            }
             const first = selects[0], last = selects[count - 1];
             const pre = await this.getDataByParentAndOrder(options, first[this.setting.pid], first[this.setting.order] - 1);
             if (!pre) throw '节点不可降级';
@@ -879,6 +889,11 @@ module.exports = app => {
             // 查询selectData的lastChild
             const lastChild = await this.getLastChildData(options, select[this.setting.kid]);
             const nexts = await this.getNextsData(options, select[this.setting.pid], select[this.setting.order]);
+            if (this._.findIndex(nexts, function (item) {
+                return item.c_code;
+            }) !== -1) {
+                throw '存在合同节点不可升级';
+            }
             if (nexts && nexts.length > 0) {
                 // 修改nextsData pid, 排序
                 // this.initSqlBuilder();
@@ -904,8 +919,8 @@ module.exports = app => {
                 // });
                 // const [sql1, sqlParam1] = this.sqlBuilder.build(this.tableName, 'update');
                 const orderInc = lastChild ? lastChild[this.setting.order] - select[this.setting.order] : - select[this.setting.order];
-                const sql1 = 'UPDATE ?? SET `' + this.setting.order + '` = ' + (orderInc > 0 ? '+' : '-') + Math.abs(orderInc) + ' WHERE ' + this.ctx.helper._getOptionsSql(options) + ' AND ' + this.setting.pid + ' = ? AND `' + this.setting.order + '` > ?';
-                const sqlParam1 = [this.tableName, select[this.setting.kid], select[this.setting.pid], select[this.setting.order]];
+                const sql1 = 'UPDATE ?? SET `'+ this.setting.pid + '` = '+ select[this.setting.kid] +' , `' + this.setting.order + '` = `'+ this.setting.order + '`' + (orderInc > 0 ? '+' : '-') + Math.abs(orderInc) + ' WHERE ' + this.ctx.helper._getOptionsSql(options) + ' AND ' + this.setting.pid + ' = ? AND `' + this.setting.order + '` > ?';
+                const sqlParam1 = [this.tableName, select[this.setting.pid], select[this.setting.order]];
                 transaction ? await transaction.query(sql1, sqlParam1) : await this.db.query(sql1, sqlParam1);
 
                 // 选中节点 isLeaf应为false
@@ -919,8 +934,8 @@ module.exports = app => {
                 const oldSubStr = this.db.escape(select[this.setting.pid] + '-');
                 const newSubStr = this.db.escape(select[this.setting.kid] + '-');
                 const sqlArr = [];
-                sqlArr.push('Update ?? SET `' + this.setting.fullPath + '` = Replace(`' + this.setting.fullPath + '`,' + oldSubStr + ',' + newSubStr + ') Where');
-                sqlArr.push('(`' + this.ctx.helper._getOptionsSql(options) + ')');
+                sqlArr.push('Update ?? SET `' + this.setting.fullPath + '` = Replace(`' + this.setting.fullPath + '`,' + oldSubStr + ',' + newSubStr + ') Where ');
+                sqlArr.push(this.ctx.helper._getOptionsSql(options));
                 sqlArr.push(' And (');
                 for (const data of nexts) {
                     sqlArr.push('`' + this.setting.fullPath + '` Like ' + this.db.escape(data[this.setting.fullPath] + '%'));
@@ -931,6 +946,7 @@ module.exports = app => {
                 sqlArr.push(')');
                 const sql = sqlArr.join('');
                 const resultData = transaction ? await transaction.query(sql, [this.tableName]) : await this.db.query(sql, [this.tableName]);
+                transaction ? await transaction.query(sql, [this.ctx.service.contract.tableName]) : await this.db.query(sql, [this.ctx.service.contract.tableName]);
                 return resultData;
             }
         }
@@ -942,6 +958,12 @@ module.exports = app => {
          * @private
          */
         async _syncUplevelChildren(options, select, transaction = null) {
+            // const children = await this.getDataByFullPath(options, select[this.setting.fullPath] + '-%');
+            // if (this._.findIndex(children, function (item) {
+            //     return item.c_code;
+            // }) !== -1) {
+            //     throw '存在合同节点不可升级';
+            // }
             // this.initSqlBuilder();
             // this.sqlBuilder.setAndWhere(this.setting.mid, {
             //     value: select[this.setting.mid],
@@ -965,6 +987,7 @@ module.exports = app => {
                 'WHERE ' + this.ctx.helper._getOptionsSql(options) + ' AND ' + this.setting.fullPath + ' LIKE ?';
             const sqlParam = [this.tableName, select[this.setting.fullPath] + '-%'];
             const data = transaction ? await transaction.query(sql, sqlParam) : await this.db.query(sql, sqlParam);
+            transaction ? await transaction.query(sql, [this.ctx.service.contract.tableName, select[this.setting.fullPath] + '-%']) : await this.db.query(sql, [this.ctx.service.contract.tableName, select[this.setting.fullPath] + '-%']);
 
             return data;
         }
@@ -977,6 +1000,12 @@ module.exports = app => {
          * @private
          */
         async _syncDownlevelChildren(options, select, newFullPath, transaction = null) {
+            // const children = await this.getDataByFullPath(options, select[this.setting.fullPath] + '-%');
+            // if (this._.findIndex(children, function (item) {
+            //     return item.c_code;
+            // }) !== -1) {
+            //     throw '存在合同节点不可降级';
+            // }
             // this.initSqlBuilder();
             // this.sqlBuilder.setAndWhere(this.setting.mid, {
             //     value: select[this.setting.mid],
@@ -1000,6 +1029,7 @@ module.exports = app => {
                 'WHERE ' + this.ctx.helper._getOptionsSql(options) + ' AND ' + this.setting.fullPath + ' LIKE ?';
             const sqlParam = [this.tableName, select[this.setting.fullPath] + '-%'];
             const data = transaction ? await transaction.query(sql, sqlParam) : await this.db.query(sql, sqlParam);
+            transaction ? await transaction.query(sql, [this.ctx.service.contract.tableName, select[this.setting.fullPath] + '-%']) : await this.db.query(sql, [this.ctx.service.contract.tableName, select[this.setting.fullPath] + '-%']);
 
             return data;
         }

+ 4 - 0
app/service/report.js

@@ -435,6 +435,10 @@ module.exports = app => {
                                 customDefine.gather_select, customSelect ? customSelect.gather_select : null));
                             runnableKey.push(filter);
                             break;
+                        case 'construction_unit':
+                            runnableRst.push(service.constructionUnit.getReportData(this.ctx.session.sessionProject.id));
+                            runnableKey.push(filter);
+                            break;
                         default:
                             break;
                     }

+ 1 - 1
app/service/sub_project.js

@@ -26,11 +26,11 @@ module.exports = app => {
 
         async getSubProject(pid, uid, admin, filterFolder = false) {
             let result = await this.getAllDataByCondition({ where: { project_id: pid, is_delete: 0 } });
-            if (admin) return result;
 
             const permission = await this.ctx.service.subProjPermission.getUserPermission(pid, uid);
             result = result.filter(x => {
                 if (x.is_folder) return !filterFolder;
+                if (admin) return true;
                 const pb = permission.find(y => { return x.id === y.spid});
                 if (!pb) return false;
                 x.user_permission = pb;

+ 5 - 4
app/view/change/index.ejs

@@ -69,7 +69,7 @@
                 </div>
             </div>
             <div class="ml-auto">
-                <% if (tender.user_id === ctx.session.sessionUser.accountId) { %>
+                <% if (tender.user_id === ctx.session.sessionUser.accountId || addPermission) { %>
                     <a href="#add-bj" data-toggle="modal" data-target="#add-bj" class="btn btn-sm btn-primary pull-right ml-1">新建变更令</a>
                     <a href="#setting" data-toggle="modal" data-target="#setting" class="btn btn-sm btn-outline-primary pull-right ml-2"><i class="fa fa-cog"></i></a>
                     <a href="#batch-sb" data-toggle="modal" data-target="#batch-sb" class="btn btn-sm btn-primary pull-right ml-2">批量上报</a>
@@ -89,11 +89,11 @@
                 <table class="table table-bordered" id="change-table">
                     <thead class="text-center">
                     <tr><th width="3%">序号</th>
-                        <th width="18%" id="sort_change">申请编号/变更令号</th><th width="24%">变更工程名称</th>
+                        <th width="16%" id="sort_change">申请编号/变更令号</th><th width="22%">变更工程名称</th>
                         <th width="7%">变更性质</th><% if (ctx.session.sessionProject.page_show.openChangeState) { %><th width="7%">变更令状态</th><% } %>
                         <th width="7%">变更金额</th><th width="7%">计价金额</th>
-                        <th width="7%">不计价金额</th><th width="7%">审批状态</th>
-                        <th width="14%">审批进度</th><th width="4%">操作</th>
+                        <th width="7%">不计价金额</th><th width="6%">创建人</th><th width="7%">审批状态</th>
+                        <th width="12%">审批进度</th><th width="4%">操作</th>
                     </tr>
                     </thead>
                     <tbody id="changeList">
@@ -115,6 +115,7 @@
                         <td style="text-align: right"><%= ctx.helper.roundNum(c.total_price, tpUnit) %></td>
                         <td style="text-align: right"><%= ctx.helper.roundNum(c.valuation_tp, tpUnit) %></td>
                         <td style="text-align: right"><%= ctx.helper.roundNum(c.unvaluation_tp, tpUnit) %></td>
+                        <td style="text-align: center"><%- c.username %></td>
                         <td class="text-center">
                             <% if (c.status === auditConst.status.uncheck && c.uid === ctx.session.sessionUser.accountId) { %>
                                 <a href="<%- '/tender/' + ctx.tender.id + '/change/' + c.cid %>/information" class="btn <%- auditConst.statusButtonClass[c.status] %> btn-sm"><%- auditConst.statusButton[c.status] %></a>

+ 3 - 2
app/view/change/information.ejs

@@ -59,7 +59,7 @@
                     <% } %>
                 </div>
                 <!--info状态区分-->
-                <% if (!change.readOnly) { %>
+                <% if (!change.readOnly || (change.status === auditConst.status.checked && (ctx.session.sessionUser.is_admin || ctx.helper._.findIndex(change.auditors, { uid: ctx.session.sessionUser.accountId }) !== -1))) { %>
                     <div class="pull-right px-3" id="show-save-btn" style="display: none">
 <!--                        <span>您修改了变更信息,记得保存修改。</span>-->
                         <button class="btn btn-sm btn-primary save_change_btn" id="save_change"><i class="fa fa-save"></i> 保存修改</button>
@@ -343,7 +343,7 @@
                                 </div>
                                 <div class="form-group">
                                     <label>批复文号</label>
-                                    <input class="form-control form-control-sm" id="w_code" placeholder="" type="text" value="<%- change.w_code %>" <% if (!change.shenpiPower) { %>readonly<% } %>>
+                                    <input class="form-control form-control-sm" id="w_code" placeholder="" type="text" value="<%- change.w_code %>" <% if (!(change.shenpiPower || (change.status === auditConst.status.checked && (ctx.session.sessionUser.is_admin || ctx.helper._.findIndex(change.auditors, { uid: ctx.session.sessionUser.accountId }) !== -1)))) { %>readonly<% } %>>
                                 </div>
                             </form>
                             <% } %>
@@ -590,6 +590,7 @@
     for (let i = 0; i < auditors2.length; i++) {
         aidList.push(auditors2[i][0].audit_order);
     }
+    let w_code = JSON.parse(unescape('<%- escape(JSON.stringify(change.w_code ? change.w_code : '')) %>'));
 </script>
 <script src="/public/js/change_information_show.js?202206211"></script>
 <% } else if (change.shenpiPower) { %>

+ 5 - 1
app/view/change/modal.ejs

@@ -42,7 +42,7 @@
         </div>
     </div>
 </div>
-<% if (tender.user_id === ctx.session.sessionUser.accountId) { %>
+<% if (tender.user_id === ctx.session.sessionUser.accountId || addPermission) { %>
 <!--弹出添加变更令-->
 <div class="modal fade" id="add-bj-modal" data-backdrop="static">
     <div class="modal-dialog" role="document">
@@ -109,6 +109,10 @@
                             <% } %>
                         </select>
                     </div>
+                    <div class="form-group form-check">
+                        <input type="checkbox" class="form-check-input" id="add_plan_list">
+                        <label class="form-check-label" for="add_plan_list">同步方案清单</label>
+                    </div>
                     <input value="" type="hidden" id="bj-name">
                 <% } else { %>
                     <div class="form-group">

+ 2 - 2
app/view/contract/detail.ejs

@@ -98,7 +98,7 @@
                                     <tr>
                                         <th class="text-center align-middle">合同金额</th>
                                         <td class="change-input-td" id="htdetail_total_price"></td>
-                                        <th class="text-center align-middle"><% if (ctx.contract_type === contractConst.type.income) { %>累计回款(P)<% } else if (ctx.contract_type === contractConst.type.expenses) { %>累计付(P)<% } %></th>
+                                        <th class="text-center align-middle"><% if (ctx.contract_type === contractConst.type.income) { %>累计回款(P)<% } else if (ctx.contract_type === contractConst.type.expenses) { %>累计付(P)<% } %></th>
                                         <td id="htdetail_pay_price"></td>
                                         <th class="text-center align-middle">累计扣款(K)</th>
                                         <td id="htdetail_debit_price"></td>
@@ -106,7 +106,7 @@
                                     <tr>
                                         <th class="text-center align-middle"><% if (ctx.contract_type === contractConst.type.income) { %>累计应回(S=P-K)<% } else if (ctx.contract_type === contractConst.type.expenses) { %>累计应付(S=P-K)<% } %></th>
                                         <td id="htdetail_yf_price"></td>
-                                        <th class="text-center align-middle"><% if (ctx.contract_type === contractConst.type.income) { %>累计已回(A)<% } else if (ctx.contract_type === contractConst.type.expenses) { %>累计已付(A)<% } %></th>
+                                        <th class="text-center align-middle"><% if (ctx.contract_type === contractConst.type.income) { %>累计实回(A)<% } else if (ctx.contract_type === contractConst.type.expenses) { %>累计实付(A)<% } %></th>
                                         <td id="htdetail_sf_price"></td>
                                         <th class="text-center align-middle"><% if (ctx.contract_type === contractConst.type.income) { %>待回款(S-A)<% } else if (ctx.contract_type === contractConst.type.expenses) { %>待支付(S-A)<% } %></th>
                                         <td id="htdetail_df_price"></td>

+ 5 - 5
app/view/contract/detail_modal.ejs

@@ -147,7 +147,7 @@
             </div>
             <div class="modal-body">
                 <div class="form-group form-group-sm">
-                    <label><% if (ctx.contract_type === contractConst.type.expenses) { %>支付<% } else if (ctx.contract_type === contractConst.type.income) { %>回款<% } %>日期</label>
+                    <label><% if (ctx.contract_type === contractConst.type.expenses) { %>支付<% } else if (ctx.contract_type === contractConst.type.income) { %>回款<% } %>日期<b class="text-danger">*</b></label>
                     <input class="datepicker-here form-control form-control-sm" name="pay_time" placeholder="点击选择时间" data-date-format="yyyy-MM-dd" data-language="zh" type="text">
                 </div>
                 <div class="form-group">
@@ -159,11 +159,11 @@
                     <input class="form-control form-control-sm" name="debit_price" placeholder="请输入扣款金额" type="number">
                 </div>
                 <div class="form-group">
-                        <label>应<% if (ctx.contract_type === contractConst.type.expenses) { %>付<% } else if (ctx.contract_type === contractConst.type.income) { %>回<% } %>金额</label>
+                        <label>应<% if (ctx.contract_type === contractConst.type.expenses) { %>付<% } else if (ctx.contract_type === contractConst.type.income) { %>回<% } %>金额<span class="text-danger yf-tips"></span></label>
                     <input class="form-control form-control-sm" name="yf_price" placeholder="<% if (ctx.contract_type === contractConst.type.expenses) { %>付<% } else if (ctx.contract_type === contractConst.type.income) { %>回<% } %>款-扣款" type="number" readonly>
                 </div>
                 <div class="form-group">
-                    <label>实<% if (ctx.contract_type === contractConst.type.expenses) { %>付<% } else if (ctx.contract_type === contractConst.type.income) { %>回<% } %>金额</label>
+                    <label>实<% if (ctx.contract_type === contractConst.type.expenses) { %>付<% } else if (ctx.contract_type === contractConst.type.income) { %>回<% } %>金额<span class="text-danger sf-tips"></span></label>
                     <input class="form-control form-control-sm" name="sf_price" placeholder="请输入实<% if (ctx.contract_type === contractConst.type.expenses) { %>付<% } else if (ctx.contract_type === contractConst.type.income) { %>回<% } %>金额" type="number">
                 </div>
                 <div class="form-group">
@@ -232,7 +232,7 @@
             <div class="modal-body">
                 <h5>当前合同【<span id="close_contract_code"></span>】:</h5>
                 <h5>存在待支付金额<strong>【<span id="close_df_price"></span>】</strong>,确定关闭?</h5>
-                <h5>关闭后,合同将锁定,无法进行编辑、上传文件等操作。</h5>
+                <h5>关闭后,合同将锁定,无法进行编辑等操作。</h5>
                 <div class="form-group mt-3">
                     <label>结算书编号:<b class="text-danger">*</b></label>
                     <input class="form-control form-control-sm" placeholder="输入结算书编号" id="close_settle_code" type="text">
@@ -253,7 +253,7 @@
                 <h5 class="modal-title">解锁合同</h5>
             </div>
             <div class="modal-body">
-                <h5>解锁后,合同可进行编辑、上传文件等操作。</h5>
+                <h5>解锁后,合同可进行编辑等操作。</h5>
             </div>
             <div class="modal-footer">
                 <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">取消</button>

+ 3 - 3
app/view/contract/index.ejs

@@ -24,12 +24,12 @@
                 <% } else { %>
                 <table class="table table-bordered">
                     <tr class="text-center">
-                        <th style="min-width: 200px" rowspan="2">项目名称</th>
-                        <th width="10%" rowspan="2">创建时间</th>
+                        <th style="min-width: 200px" rowspan="2" class="align-middle">项目名称</th>
+                        <th width="10%" rowspan="2" class="align-middle">创建时间</th>
                         <th colspan="3">支出合同</th>
                         <th colspan="3">收入合同</th>
                         <% if (ctx.session.sessionUser.is_admin) { %>
-                        <th width="10%" rowspan="2">操作</th>
+                        <th width="10%" rowspan="2" class="align-middle">操作</th>
                         <% } %>
                     </tr>
                     <tr class="text-center">

+ 5 - 5
app/view/contract/modal.ejs

@@ -65,12 +65,12 @@
                 <table id="contract-audit-table" class="table table-bordered text-center" data-height="300" data-toggle="table">
                     <thead>
                     <tr>
-                        <th rowspan="2">用户名</th>
-                        <th rowspan="2">角色/职位</th>
-                        <th rowspan="2">编辑节点</th>
-                        <th rowspan="2">添加合同</th>
+                        <th rowspan="2" class="align-middle">用户名</th>
+                        <th rowspan="2" class="align-middle">角色/职位</th>
+                        <th rowspan="2" class="align-middle">编辑节点</th>
+                        <th rowspan="2" class="align-middle">添加合同</th>
                         <th colspan="2">授权节点合同查看范围</th>
-                        <th rowspan="2">操作</th>
+                        <th rowspan="2" class="align-middle">操作</th>
                     </tr>
                     <tr>
                         <th>本单位</th>

+ 4 - 4
app/view/sub_proj/modal.ejs

@@ -151,12 +151,12 @@
                     <table class="table table-bordered">
                         <thead class="text-center">
                         <tr>
-                            <th rowspan="2">成员名称</th>
-                            <th rowspan="2">职位</th>
+                            <th rowspan="2" class="align-middle">成员名称</th>
+                            <th rowspan="2" class="align-middle">职位</th>
                             <th colspan="2">动态投资</th>
                             <th colspan="3">资料归集</th>
-                            <th rowspan="2">关联标段</th>
-                            <th rowspan="2">移除</th>
+                            <th rowspan="2" class="align-middle">关联标段</th>
+                            <th rowspan="2" class="align-middle">移除</th>
                         </tr>
                         <tr>
                             <th>查看</th>

+ 130 - 405
sql/update.sql

@@ -1,408 +1,3 @@
-ALTER TABLE `zh_material`
-ADD COLUMN `rate_tp` decimal(30, 8) NULL DEFAULT NULL COMMENT '建筑含税总金额' AFTER `rate`;
-
-ALTER TABLE `zh_ledger_0`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_1`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_2`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_3`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_4`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_5`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_6`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_7`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_8`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_9`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_10`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_11`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_12`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_13`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_14`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_15`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_16`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_17`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_18`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_19`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_20`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_21`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_22`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_23`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_24`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_25`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_26`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_27`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_28`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_29`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_30`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_31`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_32`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_33`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_34`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_35`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_36`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_37`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_38`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_39`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_40`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_41`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_42`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_43`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_44`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_45`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_46`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_47`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_48`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_49`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_50`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_51`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_52`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_53`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_54`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_55`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_56`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_57`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_58`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_59`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_60`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_61`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_62`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_63`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_64`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_65`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_66`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_67`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_68`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_69`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_70`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_71`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_72`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_73`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_74`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_75`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_76`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_77`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_78`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_79`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_80`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_81`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_82`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_83`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_84`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_85`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_86`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_87`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_88`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_89`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_90`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_91`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_92`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_93`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_94`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_95`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_96`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_97`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_98`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_ledger_99`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-
-ALTER TABLE `zh_revise_bills_0`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_1`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_2`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_3`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_4`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_5`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_6`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_7`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_8`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_9`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_10`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_11`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_12`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_13`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_14`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_15`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_16`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_17`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_18`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_19`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_20`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_21`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_22`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_23`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_24`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_25`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_26`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_27`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_28`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_29`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_30`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_31`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_32`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_33`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_34`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_35`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_36`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_37`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_38`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_39`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_40`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_41`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_42`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_43`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_44`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_45`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_46`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_47`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_48`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_49`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_50`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_51`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_52`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_53`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_54`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_55`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_56`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_57`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_58`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_59`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_60`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_61`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_62`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_63`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_64`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_65`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_66`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_67`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_68`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_69`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_70`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_71`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_72`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_73`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_74`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_75`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_76`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_77`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_78`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_79`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_80`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_81`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_82`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_83`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_84`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_85`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_86`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_87`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_88`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_89`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_90`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_91`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_92`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_93`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_94`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_95`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_96`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_97`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_98`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-ALTER TABLE `zh_revise_bills_99`
-ADD COLUMN `features` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目特征' AFTER `memo`;
-
 ALTER TABLE `zh_rpt_tree_node_cust`
 ADD COLUMN `tender_id` INT NULL DEFAULT -1 COMMENT '新需求,跟标段走,不跟客户走' AFTER `cust_acc_id`,
 ADD INDEX `tender` (`tender_id` ASC);
@@ -464,6 +59,136 @@ ALTER TABLE `zh_tender_cache`
 MODIFY COLUMN `ledger_flow_cur_uid` varchar(1000) NOT NULL DEFAULT '0' COMMENT '台账-当前流程人id' AFTER `ledger_status`,
 MODIFY COLUMN `ledger_flow_pre_uid` varchar(1000) NOT NULL DEFAULT '0' COMMENT '台账-上一流程人id' AFTER `ledger_flow_cur_info`;
 
+CREATE TABLE `zh_contract_tree` (
+  `id` varchar(100) CHARACTER SET utf8 NOT NULL COMMENT '自增id',
+  `spid` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '项目id',
+  `tid` int(11) DEFAULT NULL COMMENT '标段id',
+  `contract_type` tinyint(1) NOT NULL COMMENT '合同类型(1是支出,2是收入)',
+  `contract_id` int(11) NOT NULL COMMENT '节点id',
+  `contract_pid` int(11) NOT NULL COMMENT '父节点id',
+  `level` tinyint(4) NOT NULL COMMENT '层级',
+  `order` mediumint(4) NOT NULL DEFAULT '0' COMMENT '同级排序',
+  `full_path` varchar(255) CHARACTER SET utf8 DEFAULT '' COMMENT '层级定位辅助字段parent.full_path.contract_id',
+  `is_leaf` tinyint(1) NOT NULL COMMENT '是否叶子节点,界面显示辅助字段',
+  `code` varchar(50) CHARACTER SET utf8 DEFAULT '' COMMENT '节点编号',
+  `name` varchar(255) CHARACTER SET utf8 DEFAULT '' COMMENT '名称',
+  `unit` varchar(255) CHARACTER SET utf8 DEFAULT '' COMMENT '单位',
+  `remark` varchar(1000) CHARACTER SET utf8 DEFAULT '' COMMENT '备注',
+  PRIMARY KEY (`id`),
+  KEY `sub_id` (`spid`),
+  KEY `tid` (`tid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT = '合同管理树结构表';
+
+CREATE TABLE `zh_contract` (
+  `id` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
+  `spid` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '项目id',
+  `tid` int(11) DEFAULT NULL COMMENT '标段id',
+  `contract_type` tinyint(1) DEFAULT NULL COMMENT '合同类型(1是支出,2是收入)',
+  `uid` int(11) DEFAULT NULL COMMENT '创建人id',
+  `contract_id` int(11) NOT NULL COMMENT '节点id',
+  `contract_pid` int(11) NOT NULL COMMENT '父节点id',
+  `level` tinyint(4) NOT NULL COMMENT '层级',
+  `is_leaf` tinyint(1) DEFAULT '1' COMMENT '是否是子节点',
+  `order` mediumint(4) NOT NULL DEFAULT '0' COMMENT '同级排序',
+  `full_path` varchar(255) CHARACTER SET utf8 DEFAULT '' COMMENT '层级定位辅助字段parent.full_path.contract_id',
+  `c_code` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT '合同编号',
+  `name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '合同名称',
+  `total_price` decimal(30,8) DEFAULT '0.00000000' COMMENT '合同金额',
+  `pay_price` decimal(30,8) DEFAULT '0.00000000' COMMENT '累计支付(回款)金额',
+  `debit_price` decimal(30,8) DEFAULT '0.00000000' COMMENT '累计扣款金额',
+  `yf_price` decimal(30,8) DEFAULT '0.00000000' COMMENT '累计应付(应回)金额',
+  `sf_price` decimal(30,8) DEFAULT '0.00000000' COMMENT '累计已付(已回)金额',
+  `party_a` varchar(255) COLLATE utf8_unicode_ci DEFAULT '' COMMENT '甲方',
+  `party_a_user` varchar(255) COLLATE utf8_unicode_ci DEFAULT '' COMMENT '甲方签约人',
+  `party_b` varchar(255) COLLATE utf8_unicode_ci DEFAULT '' COMMENT '乙方',
+  `party_b_user` varchar(255) COLLATE utf8_unicode_ci DEFAULT '' COMMENT '乙方签约人',
+  `sign_date` datetime DEFAULT NULL COMMENT '签订日期',
+  `address` varchar(255) COLLATE utf8_unicode_ci DEFAULT '' COMMENT '签约地点',
+  `entity` varchar(255) COLLATE utf8_unicode_ci DEFAULT '' COMMENT '单位',
+  `bank` varchar(255) COLLATE utf8_unicode_ci DEFAULT '' COMMENT '开户行',
+  `bank_account` varchar(255) COLLATE utf8_unicode_ci DEFAULT '' COMMENT '收款账号',
+  `settle_code` varchar(255) COLLATE utf8_unicode_ci DEFAULT '' COMMENT '结算书编号',
+  `remark` varchar(1000) COLLATE utf8_unicode_ci DEFAULT '' COMMENT '备注',
+  `exist_pay` tinyint(1) DEFAULT '0' COMMENT '是否存在合同支付(回款)',
+  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='合同详情表';
+
+CREATE TABLE `zh_contract_pay` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `spid` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '项目id',
+  `tid` int(11) DEFAULT NULL COMMENT '标段id',
+  `contract_type` tinyint(1) NOT NULL COMMENT '合同类型(1是支出,2是收入)',
+  `cid` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '合同详情id',
+  `uid` int(11) DEFAULT NULL COMMENT '创建人id',
+  `pay_time` datetime DEFAULT NULL COMMENT '支付日期',
+  `pay_price` decimal(30,8) DEFAULT '0.00000000' COMMENT '付款金额',
+  `debit_price` decimal(30,8) DEFAULT '0.00000000' COMMENT '扣款金额',
+  `yf_price` decimal(30,8) DEFAULT '0.00000000' COMMENT '应付(回)金额',
+  `sf_price` decimal(30,8) DEFAULT '0.00000000' COMMENT '实付金额',
+  `pay_type` varchar(50) COLLATE utf8_unicode_ci DEFAULT '' COMMENT '支付方式',
+  `remark` varchar(1000) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '备注',
+  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT = '合同支付表';
+
+CREATE TABLE `zh_contract_pay_attachment` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `spid` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '项目id',
+  `tid` int(11) DEFAULT NULL COMMENT '标段id',
+  `contract_type` tinyint(1) NOT NULL COMMENT '合同类型(1是支出,2是收入)',
+  `cid` varchar(100) COLLATE utf8_unicode_ci NOT NULL COMMENT '合同详情id',
+  `cpid` int(11) NOT NULL COMMENT '合同支付id',
+  `uid` int(11) NOT NULL COMMENT '上传者id',
+  `filename` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT '文件名称',
+  `fileext` varchar(5) COLLATE utf8_unicode_ci NOT NULL COMMENT '文件后缀',
+  `filesize` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT '文件大小',
+  `filepath` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT '文件存储路径',
+  `upload_time` datetime NOT NULL COMMENT '上传时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  KEY `idx_cid` (`cpid`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_unicode_ci COMMENT = '合同支付附件表';
+
+CREATE TABLE `zh_contract_attachment` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `spid` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '项目id',
+  `tid` int(11) DEFAULT NULL COMMENT '标段id',
+  `contract_type` tinyint(1) NOT NULL COMMENT '合同类型(1是支出,2是收入)',
+  `cid` varchar(100) COLLATE utf8_unicode_ci NOT NULL COMMENT '合同详情id',
+  `uid` int(11) NOT NULL COMMENT '上传者id',
+  `filename` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT '文件名称',
+  `fileext` varchar(5) COLLATE utf8_unicode_ci NOT NULL COMMENT '文件后缀',
+  `filesize` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT '文件大小',
+  `filepath` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT '文件存储路径',
+  `upload_time` datetime NOT NULL COMMENT '上传时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  KEY `idx_cid` (`cid`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_unicode_ci COMMENT = '合同文件表';
+
+CREATE TABLE `zh_contract_audit` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `spid` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '项目id',
+  `tid` int(11) DEFAULT NULL COMMENT '标段id',
+  `uid` int(11) NOT NULL COMMENT '用户id',
+  `permission_add` tinyint(1) DEFAULT '0' COMMENT '添加合同权限',
+  `permission_edit` tinyint(1) DEFAULT '0' COMMENT '编辑节点权限',
+  `permission_show_unit` tinyint(1) DEFAULT '0' COMMENT '查看该节点下同单位下合同权限',
+  `permission_show_node` tinyint(1) DEFAULT '0' COMMENT '查看该节点下所有合同权限',
+  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+  PRIMARY KEY (`id`)
+) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_unicode_ci COMMENT = '合同权限用户表';
+
+CREATE TABLE `zh_contract_tree_audit` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `spid` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '项目id',
+  `tid` int(11) DEFAULT NULL COMMENT '标段id',
+  `contract_type` tinyint(1) DEFAULT NULL COMMENT '合同类型(1是支出,2是收入)',
+  `contract_id` int(11) DEFAULT NULL COMMENT '节点id',
+  `uid` int(11) DEFAULT NULL COMMENT '节点授权人id',
+  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+  PRIMARY KEY (`id`)
+) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_unicode_ci COMMENT = '合同节点授权用户表';
+
 -- update请放在最后
 
 Update zh_filing_template SET is_fixed = 1 WHERE tree_level = 1;