Browse Source

1. 计量台账,协作相关
2. 报表指标,提供台账-协作指标数据

MaiXinRong 4 years ago
parent
commit
2e0dfec2f8

+ 3 - 0
app/controller/stage_controller.js

@@ -326,6 +326,9 @@ module.exports = app => {
                             });
                         case 'tag':
                             responseData.data.tags = await ctx.service.ledgerTag.getDatas(ctx.tender.id, ctx.stage.id);
+                        case 'cooperation':
+                            responseData.data.cooperation = await this.ctx.service.ledgerCooperation.getValidData(
+                                ctx.tender.id, ctx.session.sessionUser.accountId);
                             break;
                     }
                 }

+ 51 - 0
app/public/js/path_tree.js

@@ -1118,6 +1118,36 @@ const createNewPathTree = function (type, setting) {
                 this.stageItems[keyName] = data;
             }
         }
+        // 解锁相关
+        _loadPwdCache() {
+            const cache = getLocalCache(this.pwdCacheKey);
+            if (!cache) return;
+
+            const cacheArr = cache.split('|');
+            for (const ca of cacheArr) {
+                if (!ca) continue;
+
+                const [ledger_id, pwd] = ca.split(':');
+                if (!ledger_id || !pwd) continue;
+
+                const p = this.pwd.find(x => {return x.ledger_id == ledger_id});
+                p.check = p.pwd === pwd;
+            }
+        }
+        loadPwd(data, cacheKey) {
+            this.loadingPwd = true;
+            try {
+                this.pwdCacheKey = cacheKey;
+                this.pwd = data;
+                this._loadPwdCache();
+                for (const p of this.pwd) {
+                    p.node = this.getItems(p.ledger_id);
+                    this.lockNode(p, !p.check);
+                }
+            } catch(err) {}
+            this.loadingPwd = false;
+        }
+
         getStageItems(id) {
             return this.stageItems[itemsPre + id];
         }
@@ -1274,6 +1304,27 @@ const createNewPathTree = function (type, setting) {
             }
             return result;
         }
+
+        _savePwdCache() {
+            const cache = [];
+            for (const p of this.pwd) {
+                if (p.check && p.pwd) cache.push(p.ledger_id + ':' + p.pwd);
+            }
+            setLocalCache(this.pwdCacheKey, cache.join('|'));
+        }
+        lockNode(p, isLock) {
+            const refresh = [];
+            p.check = !isLock;
+            p.node.lock = isLock;
+            refresh.push(this.getNodeIndex(p.node));
+            const posterity = this.getPosterity(p.node);
+            for (const pn of posterity) {
+                pn.lock = isLock;
+                refresh.push(this.getNodeIndex(pn));
+            }
+            if (!this.loadingPwd) this._savePwdCache();
+            return refresh;
+        }
     }
 
     class MasterTree extends FxTree {

+ 27 - 13
app/public/js/spreadjs_rela/spreadjs_zh.js

@@ -472,7 +472,7 @@ const SpreadJsObj = {
             return backColor;
         }
     },
-    _loadRowStyle: function (sheet, row) {
+    _loadRowStyle: function (sheet, data, row) {
         sheet.zh_setting.cols.forEach(function (col, j) {
             const cell = sheet.getCell(row, j);
 
@@ -484,10 +484,11 @@ const SpreadJsObj = {
                 cell.foreColor(col.foreColor);
             }
 
-            if (col.readOnly && Object.prototype.toString.apply(col.readOnly) !== "[object Function]") {
-                cell.locked(col.readOnly || sheet.zh_setting.readOnly || false);
-            }
-            cell.vAlign(1).hAlign(col.hAlign);
+            const readOnly1 = (sheet.zh_setting.readOnly && Object.prototype.toString.apply(sheet.zh_setting.readOnly) === "[object Function]")
+                ? sheet.zh_setting.readOnly(data) : (sheet.zh_setting.readOnly || false);
+            const readOnly2 = (col.readOnly && Object.prototype.toString.apply(col.readOnly) === "[object Function]")
+                ? col.readOnly(data) : col.readOnly || false;
+            cell.locked(readOnly1 || readOnly2).vAlign(1).hAlign(col.hAlign);
 
             if(col.type === 'Number') {
                 if (col.formatter) {
@@ -530,11 +531,11 @@ const SpreadJsObj = {
                 }
             }
 
-            if (col.readOnly && Object.prototype.toString.apply(col.readOnly) === "[object Function]") {
-                cell.locked(col.readOnly(data) || sheet.zh_setting.readOnly || false).vAlign(1).hAlign(col.hAlign);
-            } else {
-                cell.locked(col.readOnly || sheet.zh_setting.readOnly || false).vAlign(1).hAlign(col.hAlign);
-            }
+            const readOnly1 = (sheet.zh_setting.readOnly && Object.prototype.toString.apply(sheet.zh_setting.readOnly) === "[object Function]")
+                ? sheet.zh_setting.readOnly(data) : (sheet.zh_setting.readOnly || false);
+            const readOnly2 = (col.readOnly && Object.prototype.toString.apply(col.readOnly) === "[object Function]")
+                ? col.readOnly(data) : col.readOnly || false;
+            cell.locked(readOnly1 || readOnly2).vAlign(1).hAlign(col.hAlign);
 
             if(col.type === 'Number') {
                 if (col.formatter) {
@@ -719,9 +720,9 @@ const SpreadJsObj = {
                     self._loadRowData(sheet, data, i);
                     sheet.setRowVisible(i, data.visible);
                 });
-                for (let iRow = sortData.length - 1; iRow < totalRow; iRow++) {
-                    self._loadRowStyle(sheet, iRow);
-                }
+                // for (let iRow = sortData.length - 1; iRow < totalRow; iRow++) {
+                //     self._loadRowStyle(sheet, iRow);
+                // }
             }
             // 设置列单元格格式
             sheet.zh_setting.cols.forEach(function (col, j) {
@@ -804,6 +805,19 @@ const SpreadJsObj = {
             this.endMassOperation(sheet);
         }
     },
+    reloadRowsReadonly: function (sheet, rows) {
+        const sortData = sheet.zh_dataType === 'tree' ? sheet.zh_tree.nodes : sheet.zh_data;
+
+        this.beginMassOperation(sheet);
+        try {
+            for (const row of rows) {
+                if (row < 0) { continue; }
+                this._loadRowStyle(sheet, sortData[row], row);
+            };
+        } catch (err) {
+        }
+        this.endMassOperation(sheet);
+    },
     reloadColData: function (sheet, col, count = 1) {
         const cols = [];
         for (let i = 0; i < count; i++) {

+ 69 - 4
app/public/js/stage.js

@@ -254,6 +254,16 @@ $(document).ready(() => {
     };
     const stagePos = new StagePosData(stagePosSetting);
 
+    const reloadCooperationHtml = function () {
+        const html = [];
+        for (const p of stageTree.pwd) {
+            html.push('<tr>', `<td>${p.node.code}</td>`, `<td>${p.node.name}</td>`);
+            html.push('<td>', p.check ? `已解锁:${p.pwd}` : `<a name="ledger-unlock" lid="${p.ledger_id}" href="javascript: void(0);">解锁</a>`, '</td>');
+            html.push('</tr>');
+        }
+        $('#cooperationList').html(html.join(''));
+    };
+
     class Changes {
         constructor(obj) {
             const self = this;
@@ -546,7 +556,7 @@ $(document).ready(() => {
     const ratioCol = ledgerSpreadSetting.cols.find(x => {return x.field === 'end_gather_percent' || x.field === 'end_correct_percent'});
     ratioCol.field = tenderInfo.display.stage.correct ? 'end_correct_percent' : 'end_gather_percent';
     ledgerSpreadSetting.imageClick = function (data) {
-        if (data.children && data.children.length > 0) return;
+        if (data.children && data.children.length > 0 || data.lock) return;
 
         const nodePos = stagePos.getLedgerPos(data.id);
         if (nodePos && nodePos.length > 0) return;
@@ -621,6 +631,10 @@ $(document).ready(() => {
             },
         },
     ];
+    ledgerSpreadSetting.readOnly = function (data) {
+        if (!data) return false;
+        return data.lock || false;
+    };
     SpreadJsObj.initSheet(slSpread.getActiveSheet(), ledgerSpreadSetting);
     slSpread.getActiveSheet().frozenColumnCount(5);
     slSpread.getActiveSheet().options.frozenlineColor = '#93b5e4';
@@ -1411,7 +1425,9 @@ $(document).ready(() => {
          * 加载计量单元 根据当前台账选择节点
          */
         loadCurPosData: function () {
-            const node = SpreadJsObj.getSelectObject(slSpread.getActiveSheet());
+            const sheet = slSpread.getActiveSheet();
+            const node = SpreadJsObj.getSelectObject(sheet);
+            if (node.lock) spSpread.getActiveSheet().zh_setting.readOnly = node.lock;
             if (node) {
                 const posData = stagePos.ledgerPos[itemsPre + node.id] || [];
                 SpreadJsObj.loadSheetData(spSpread.getActiveSheet(), 'data', posData);
@@ -1683,6 +1699,8 @@ $(document).ready(() => {
             }
         },
         deletePress: function (sheet) {
+            if (sheet.zh_setting.readOnly) return;
+
             if (sheet.zh_setting && sheet.zh_data) {
                 const sortData = sheet.zh_data;
                 if (!sortData || sortData.length === 0) { return; }
@@ -1797,12 +1815,18 @@ $(document).ready(() => {
     });
 
     // 加载计量单元数据 - 暂时统一加载,如有需要,切换成动态加载并缓存
-    postData(window.location.pathname + '/load', { filter: 'ledger;pos;detail;change;tag' }, function (result) {
+    postData(window.location.pathname + '/load', { filter: 'ledger;pos;detail;change;tag;cooperation' }, function (result) {
         // 加载树结构
         stageTree.loadDatas(result.ledgerData);
         // stageTree.loadCurStageData(curStageData);
         // stageTree.loadPreStageData(preStageData);
         treeCalc.calculateAll(stageTree);
+        // 加载解锁相关
+        if (result.cooperation) {
+            stageTree.loadPwd(result.cooperation, 'bills-p-' + userID + '-' + window.location.pathname.split('/')[2]);
+            $('#cooperationCount').html(stageTree.pwd.length || '');
+            reloadCooperationHtml();
+        }
         // 加载部位明细
         stagePos.loadDatas(result.posData);
         stagePos.calculateAll();
@@ -1889,6 +1913,9 @@ $(document).ready(() => {
                     return !checkTzMeasureType();
                 },
                 disabled: function (key, opt) {
+                    const node = SpreadJsObj.getSelectObject(slSpread.getActiveSheet());
+                    if (!node || node.lock) return true;
+
                     const sheet = spSpread.getActiveSheet();
                     if (sheet.zh_data && !readOnly) {
                         const selection = sheet.getSelections();
@@ -1925,7 +1952,7 @@ $(document).ready(() => {
                 },
                 disabled: function (key, opt) {
                     const node = SpreadJsObj.getSelectObject(slSpread.getActiveSheet());
-                    return _.isNil(node) || _.isNil(node.b_code) || node.b_code === '';
+                    return _.isNil(node) || _.isNil(node.b_code) || node.b_code === '' || node.lock;
                 },
                 callback: function (key, opt) {
                     mergePeg.show();
@@ -1937,6 +1964,10 @@ $(document).ready(() => {
                     const data = spSpread.getActiveSheet().zh_data;
                     return data && data.length > 0;
                 },
+                disabled: function (key, opt) {
+                    const node = SpreadJsObj.getSelectObject(slSpread.getActiveSheet());
+                    return node.lock;
+                },
                 callback: function (key, opt) {
                     $('#cbr-ratio').val('');
                     $('#apply2sibling')[0].checked = false;
@@ -3910,4 +3941,38 @@ $(document).ready(() => {
         }
         stageTreeSpreadObj.measureByBatch(posName, ratio, apply2sibling);
     });
+
+    $('body').on('click', '[name=ledger-unlock]', function() {
+        $('#cooperation').modal('hide');
+        const lid = this.getAttribute('lid');
+        if (!lid) return;
+
+        const p = stageTree.pwd.find(x => {return x.ledger_id == lid});
+        if (!p) return;
+
+        $('#unlock-info').html(`${p.node.code} ${p.node.name} 解锁密码<b class="text-danger">*</b>`);
+        $('#unlock-pwd').val('').removeClass('is-invalid');
+        $('.invalid-feedback', '#unlock').hide();
+        $('.alert-warning', '#unlock').hide();
+        $('#unlock-ok').attr('lid', lid);
+        $('#unlock').modal('show');
+    });
+    $('#unlock-ok').click(function () {
+        const lid = this.getAttribute('lid');
+        if (!lid) return;
+
+        const p = stageTree.pwd.find(x => {return x.ledger_id == lid});
+        if (!p) return;
+
+        if (p.pwd === $('#unlock-pwd').val()) {
+            const refresh = stageTree.lockNode(p, false);
+            SpreadJsObj.reloadRowsReadonly(slSpread.getActiveSheet(), refresh);
+            $('#unlock').modal('hide');
+            reloadCooperationHtml();
+        } else {
+            $('#unlock-pwd').addClass('is-invalid');
+            $('.invalid-feedback', '#unlock').show();
+            $('.alert-warning', '#unlock').show();
+        }
+    })
 });

+ 9 - 0
app/service/ledger_cooperation.js

@@ -48,6 +48,15 @@ module.exports = app => {
             };
             return await this.db.update(this.ctx.service.ledgerCooperation.tableName, updateData, options);
         }
+
+        async getValidData(tid, uid) {
+            const condition = {where: {tid: tid, status: 1}};
+            if (uid) {
+                condition.where.user_id = uid;
+                condition.colums = ['ledger_id', 'pwd'];
+            }
+            return await this.getAllDataByCondition(condition);
+        }
     }
 
     return LedgerCooperation;

+ 4 - 0
app/service/report.js

@@ -162,6 +162,10 @@ module.exports = app => {
                                 customDefine.stage_select, customSelect ? customSelect.stage_select : null));
                             runnableKey.push(filter);
                             break;
+                        case 'ledger_cooperation':
+                            runnableRst.push(service.ledgerCooperation.getValidData(params.tender_id));
+                            runnableKey.push(filter);
+                            break;
                         default:
                             break;
                     }

+ 3 - 0
app/view/stage/index.ejs

@@ -36,6 +36,9 @@
                     <a id="exportExcel" class="btn btn-primary btn-sm" href="javascript: void(0)">导出计量台账Excel</a>
                     <a class="btn btn-sm btn-primary" href="javascript: void(0);" id="ledger-check2">数据检查</a>
                 </div>
+                <div class="d-inline-block">
+                    <a class="btn btn-sm btn-danger" href="#cooperation" data-toggle="modal" data-target="#cooperation">多人协同 <i class="fa fa-lock"></i> <span id="cooperationCount"></span></a>
+                </div>
             </div>
             <div class="ml-auto">
             </div>

+ 50 - 0
app/view/stage/modal.ejs

@@ -450,6 +450,56 @@
         </div>
     </div>
 </div>
+<!--多人协同-->
+<div class="modal fade" id="cooperation" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">多人协同</h5>
+            </div>
+            <div class="modal-body">
+                <div class="alert alert-warning">以下项目节及其子项被锁定,请输入密码解锁。</div>
+                <div class="modal-height-300">
+                    <table class="table table-hover table-bordered">
+                        <thead>
+                        <tr><th>项目节编号</th><th>项目节名称</th><th>解锁  </th></tr>
+                        </thead>
+                        <tbody id="cooperationList">
+                        </tbody>
+                    </table>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">关闭</button>
+                <button type="button" class="btn btn-sm btn-primary">确认</button>
+            </div>
+        </div>
+    </div>
+</div>
+<!--解锁-->
+<div class="modal fade" id="unlock" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">解锁项目节</h5>
+            </div>
+            <div class="modal-body">
+                <div class="form-group">
+                    <label id="unlock-info">1-2-2  挖方 解锁密码<b class="text-danger">*</b></label>
+                    <input class="form-control form-control-sm is-invalid" type="password" id="unlock-pwd">
+                    <div class="invalid-feedback">
+                        密码错误
+                    </div>
+                </div>
+                <div class="alert alert-warning">忘记密码请联系管理员。</div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">关闭</button>
+                <button type="button" class="btn btn-sm btn-primary" id="unlock-ok">确认</button>
+            </div>
+        </div>
+    </div>
+</div>
 <% include ./audit_modal.ejs %>
 <% include ../shares/merge_peg_modal.ejs %>
 <% include ../shares/check_modal2.ejs %>

+ 17 - 0
builder_report_index_define.js

@@ -46,6 +46,21 @@ const advance_pay = {
         { name: '结束时间', field: 'end_time', type: dataType.str },
     ],
 };
+const ledger_cooperation = {
+    name: '台账-协作(ledger_cooperation)',
+    remark: '',
+    id: 45,
+    key: 'ledger_cooperation',
+    prefix: '台账-协作',
+    cols: [
+        { name: 'id', field: 'id', type: dataType.int },
+        { name: '标段id', field: 'tid', type: dataType.int },
+        { name: '审批人id', field: 'user_id', type: dataType.int },
+        { name: '台账id', field: 'ledger_id', type: dataType.int },
+        { name: '密码', field: 'pwd', type: dataType.str },
+        { name: '电子签名地址', field: 'sign_path', type: dataType.str },
+    ]
+}
 // 其他台账
 const stage_jgcl = {
     name: '期-甲供材料(mem_stage_jgcl)',
@@ -1142,6 +1157,7 @@ const stage_sum_pay = {
     ],
 };
 
+
 const recursiveMkdirSync = async function(pathName) {
     if (!fs.existsSync(pathName)) {
         const upperPath = path.dirname(pathName);
@@ -1233,6 +1249,7 @@ const exportTableDefine = async function(define) {
 };
 
 const defines = [
+    ledger_cooperation,
     advance_pay,
     union_data,
     month_progress,

+ 1 - 0
config/web.js

@@ -293,6 +293,7 @@ const JsFiles = {
                     '/public/js/sub_menu.js',
                     '/public/js/div_resizer.js',
                     '/public/js/spreadjs_rela/spreadjs_zh.js',
+                    '/public/js/shares/sjs_setting.js',
                     '/public/js/zh_calc.js',
                     '/public/js/path_tree.js',
                     '/public/js/shares/gcl_gather_compare.js',