Browse Source

中间计量,主表改用spreadjs

MaiXinRong 6 years ago
parent
commit
d38e1de45c

+ 5 - 1
app/controller/stage_controller.js

@@ -324,7 +324,11 @@ module.exports = app => {
 
                 const data = JSON.parse(ctx.request.body.data);
                 const responseData = { err: 0, msg: '', data: {}, };
-                responseData.data = await ctx.service.stageDetail.saveDetailData(data);
+                if (data instanceof Array) {
+                    responseData.data = await ctx.service.stageDetail.saveDetailDatas(data);
+                } else {
+                    responseData.data = await ctx.service.stageDetail.saveDetailData(data);
+                }
                 ctx.body = responseData;
             } catch (err) {
                 this.log(err);

+ 11 - 8
app/extend/helper.js

@@ -231,16 +231,19 @@ module.exports = {
      */
     async sendRequest(url, data, type = 'POST', dataType = 'json') {
         // 发起请求
-        const response = await this.ctx.curl(url, {
-            method: type,
-            data,
-            dataType,
-        });
-        if (response.status !== 200) {
+        try {
+            const response = await this.ctx.curl(url, {
+                method: type,
+                data,
+                dataType,
+            });
+            if (response.status !== 200) {
+                throw '请求失败';
+            }
+            return response.data;
+        } catch(err) {
             throw '请求失败';
         }
-
-        return response.data;
     },
 
     /**

+ 197 - 100
app/public/js/stage_detail.js

@@ -9,103 +9,87 @@
  */
 
 $(document).ready(() => {
-    let gsSpread;
-    stageIm.init(stage, imType);
-    const gsTree = stageIm.getGsTree();
-
-    function getSelectDetailData() {
-        const rowIndex = parseInt($('#im-list').attr('rowIndex'));
-        const data = stageIm.getImData()[rowIndex];
-        return data;
-    }
-
-    function reLoadDetailData() {
-        const data = getSelectDetailData();
-        $('#edit-detail').show();
-        $('#save-detail').hide();
-        $('#cancel-detail').hide();
-        $('#bgl-code').val(data && data.bgl_code ? data.bgl_code : '');
-        $('#bw-name').val(data && data.bw ? data.bw : '');
-        $('#start-peg').val(data && data.start_peg ? data.start_peg : '');
-        $('#end-peg').val(data && data.end_peg ? data.end_peg : '');
-        $('#unit-name').val(data && data.jldy ? data.jldy : '');
-        $('#drawing-code').val(data && data.drawing_code ? data.drawing_code : '');
-        $('#calc-memo').val(data && data.calc_memo ? data.calc_memo : '');
-        if (data && data.calc_img) {
-            $('#calc-img').html('<img src="/' + data.calc_img + '" class="d-100" width="100%">');
-        } else {
-            $('#calc-img').html('');
-        }
-    }
-
-    function loadPosData() {
-        const data = getSelectDetailData();
-        const html = [];
-        if (data) {
-            const rowIndex = parseInt($('#leaf-xmj-list').attr('rowIndex'));
-            const leafXmj = data.leafXmjs[rowIndex];
-            if (leafXmj) {
-                for (const p of leafXmj.pos) {
+    autoFlashHeight();
+    const detailSpreadSetting = {
+        cols: [
+            {title: '编号', colSpan: '1', rowSpan: '1', field: 'code', hAlign: 0, width: 80, formatter: '@', readOnly: true},
+            {title: '中间计量表号', colSpan: '1', rowSpan: '1', field: 'im_code', hAlign: 0, width: 150, formatter: '@', readOnly: true},
+            {title: '交工证书/凭证号', colSpan: '1', rowSpan: '1', field: 'doc_code', hAlign: 0, width: 180, formatter: '@'},
+            {title: '分布分项工程', colSpan: '1', rowSpan: '1', field: 'fbfx', hAlign: 0, width: 150, formatter: '@', readOnly: true},
+            {title: '本期计量数量/金额', colSpan: '1', rowSpan: '1', field: 'jl', hAlign: 2, width: 220, formatter: '@', readOnly: true},
+        ],
+        headRows: 1,
+        emptyRows: 0,
+        headRowHeight: [32],
+        defaultRowHeight: 32,
+        readOnly: readOnly,
+    };
+    const detailSpread = SpreadJsObj.createNewSpread($('#detail-spread')[0]);
+    SpreadJsObj.initSheet(detailSpread.getActiveSheet(), detailSpreadSetting);
+    const detailOperationObj = {
+        // 部位明细
+        loadPosData: function () {
+            const data = SpreadJsObj.getSelectObject(detailSpread.getActiveSheet());
+            const html = [];
+            if (data) {
+                const rowIndex = parseInt($('#leaf-xmj-list').attr('rowIndex'));
+                const leafXmj = data.leafXmjs[rowIndex];
+                if (leafXmj) {
+                    for (const p of leafXmj.pos) {
+                        html.push('<tr>');
+                        html.push('<td>', p.name, '</td>');
+                        html.push('<td>', p.qty, '</td>');
+                        html.push('<td>', p.jl, '</td>');
+                        html.push('</tr>');
+                    }
+                }
+            }
+            $('#pos-list').html(html.join(''));
+        },
+        // 项目节明细
+        loadLeafXmjsData: function () {
+            const data = SpreadJsObj.getSelectObject(detailSpread.getActiveSheet());
+            const html = [];
+            if (data && data.leafXmjs) {
+                for (const lx of data.leafXmjs) {
                     html.push('<tr>');
-                    html.push('<td>', p.name, '</td>');
-                    html.push('<td>', p.qty, '</td>');
-                    html.push('<td>', p.jl, '</td>');
+                    html.push('<td>', lx.code , '</td>');
+                    html.push('<td>', lx.name , '</td>');
+                    html.push('<td>', lx.jl , '</td>');
                     html.push('</tr>');
                 }
             }
-        }
-        $('#pos-list').html(html.join(''));
-    }
-
-    function loadLeafXmjsData() {
-        const data = getSelectDetailData();
-        const html = [];
-        if (data && data.leafXmjs) {
-            for (const lx of data.leafXmjs) {
-                html.push('<tr>');
-                html.push('<td>', lx.code , '</td>');
-                html.push('<td>', lx.name , '</td>');
-                html.push('<td>', lx.jl , '</td>');
-                html.push('</tr>');
+            $('#leaf-xmj-list').html(html.join(''));
+            $('#leaf-xmj-list').attr('rowIndex', 0);
+            $('tr:first', '#leaf-xmj-list').addClass('table-warning');
+            detailOperationObj.loadPosData();
+            $('tr', '#leaf-xmj-list').bind('click', function () {
+                $('tr.table-warning', '#leaf-xmj-list').removeClass('table-warning');
+                $(this).addClass('table-warning');
+                $('#leaf-xmj-list').attr('rowIndex', this.rowIndex - 1);
+                detailOperationObj.loadPosData();
+            });
+        },
+        // 中间计量数据
+        reLoadDetailData: function () {
+            const data = SpreadJsObj.getSelectObject(detailSpread.getActiveSheet());
+            $('#edit-detail').show();
+            $('#save-detail').hide();
+            $('#cancel-detail').hide();
+            $('#bgl-code').val(data && data.bgl_code ? data.bgl_code : '');
+            $('#bw-name').val(data && data.bw ? data.bw : '');
+            $('#start-peg').val(data && data.start_peg ? data.start_peg : '');
+            $('#end-peg').val(data && data.end_peg ? data.end_peg : '');
+            $('#unit-name').val(data && data.jldy ? data.jldy : '');
+            $('#drawing-code').val(data && data.drawing_code ? data.drawing_code : '');
+            $('#calc-memo').val(data && data.calc_memo ? data.calc_memo : '');
+            if (data && data.calc_img) {
+                $('#calc-img').html('<img src="/' + data.calc_img + '" class="d-100" width="100%">');
+            } else {
+                $('#calc-img').html('');
             }
-        }
-        $('#leaf-xmj-list').html(html.join(''));
-        $('#leaf-xmj-list').attr('rowIndex', 0);
-        loadPosData();
-    }
-
-    function reBuildImData() {
-        const imData = stageIm.buildImData();
-        const html = [];
-        for (const im of imData) {
-            html.push('<tr>');
-            html.push('<td>');
-            html.push(im.code);
-            html.push('</td>');
-            html.push('<td>');
-            html.push(im.im_code);
-            html.push('</td>');
-            html.push('<td>');
-            html.push(im.doc_code);
-            html.push('</td>');
-            html.push('<td>');
-            html.push(im.fbfx);
-            html.push('</td>');
-            html.push('<td align="right">');
-            html.push(im.jl);
-            html.push('</td>');
-            html.push('</tr>');
-        }
-        $('#im-list').html(html.join(''));
-        $('tr:first', '#im-list').addClass('table-warning');
-        $('#im-list').attr('rowIndex', 0);
-        reLoadDetailData();
-        loadLeafXmjsData();
-        $('tr', '#im-list').click(function () {
-            $('tr.table-warning').removeClass('table-warning');
-            $(this).addClass('table-warning');
-            $('#im-list').attr('rowIndex', this.rowIndex - 1);
-
+        },
+        selectionChanged: function (e, info) {
             $('#edit-detail').show();
             $('#cancel-detail').hide();
             $('#save-detail').hide();
@@ -116,12 +100,125 @@ $(document).ready(() => {
             $('#unit-name').attr('readonly', '');
             $('#drawing-code').attr('readonly', '');
             $('#calc-memo').attr('readonly', '');
-            reLoadDetailData();
-            loadLeafXmjsData();
-        });
-        $('tr', '#leaf-xmj-list').click(function () {
-            loadPosData();
-        });
+            detailOperationObj.reLoadDetailData();
+            detailOperationObj.loadLeafXmjsData();
+        },
+        editEnded: function(e, info) {
+            if (info.sheet.zh_setting) {
+                const col = info.sheet.zh_setting.cols[info.col];
+                if (col.field !== 'doc_code') {
+                    SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                    return;
+                }
+                const data = SpreadJsObj.getSelectObject(info.sheet);
+                if (data) {
+                    const updateData = {lid: data.lid}
+                    if (data.uuid) {
+                        updateData.uuid = data.uuid;
+                    } else {
+                        updateData.code = data.code;
+                        updateData.name = data.name;
+                        updateData.unit = data.unit;
+                        updateData.unit_price = data.unit_price;
+                    }
+                    updateData.doc_code = info.editingText;
+                    postData(window.location.pathname + '/save', updateData, function (result) {
+                        stageIm.loadUpdateDetailData(result);
+                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                    }, function () {
+                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                    });
+                } else {
+                    SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                }
+            }
+        },
+        clipboardPasted: function (e, info) {
+            if (info.sheet.zh_setting && info.sheet.zh_data) {
+                const col = info.sheet.zh_setting.cols[info.cellRange.col];
+                if (info.cellRange.colCount > 1) {
+                    toast('请勿同时复制粘贴多列数据', 'warning');
+                    SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
+                    return;
+                }
+                if (col.field !== 'doc_code') {
+                    SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
+                    return;
+                }
+
+                const datas = [];
+                for (let iRow = 0; iRow < info.cellRange.rowCount; iRow++) {
+                    const curRow = info.cellRange.row + iRow;
+                    const data = info.sheet.zh_data[curRow];
+                    if (data) {
+                        const updateData = {lid: data.lid};
+                        if (data.uuid) {
+                            updateData.uuid = data.uuid;
+                        } else {
+                            updateData.code = data.code;
+                            updateData.name = data.name;
+                            updateData.unit = data.unit;
+                            updateData.unit_price = data.unit_price;
+                        }
+                        updateData.doc_code = info.sheet.getText(curRow, info.cellRange.col).replace('\n', '');
+                        datas.push(updateData);
+                    }
+                }
+                if (datas.length > 0) {
+                    postData(window.location.pathname + '/save', datas, function (result) {
+                        stageIm.loadUpdateDetailData(result);
+                        SpreadJsObj.reLoadRowData(info.sheet, info.cellRange.row, info.cellRange.rowCount);
+                    }, function () {
+                        SpreadJsObj.reLoadRowData(info.sheet, info.cellRange.row, info.cellRange.rowCount);
+                    })
+                }
+            }
+        },
+        deletePress: function (sheet) {
+            if (sheet.zh_setting) {
+                const datas = [];
+                const sel = sheet.getSelections()[0];
+                for (let iCol = sel.col; iCol < sel.col + sel.colCount; iCol++) {
+                    const col = sheet.zh_setting.cols[iCol];
+                    for (let iRow = sel.row; iRow < sel.row + sel.rowCount; iRow++) {
+                        const data = sheet.zh_data[iRow];
+                        if (col.field === 'doc_code') {
+                            const updateData = {lid: data.lid};
+                            if (data.uuid) {
+                                updateData.uuid = data.uuid;
+                                updateData.doc_code = null;
+                                datas.push(updateData);
+                            }
+                        }
+                    }
+                }
+                if (datas.length > 0) {
+                    postData(window.location.pathname + '/save', datas, function (result) {
+                        stageIm.loadUpdateDetailData(result);
+                        SpreadJsObj.reLoadRowData(sheet, sel.row, sel.rowCount);
+                    }, function () {
+                        SpreadJsObj.reLoadRowData(sheet, sel.row, sel.rowCount);
+                    });
+                }
+            }
+        },
+    };
+    detailSpread.bind(spreadNS.Events.SelectionChanged, detailOperationObj.selectionChanged);
+    if (!readOnly) {
+        detailSpread.bind(spreadNS.Events.EditEnded, detailOperationObj.editEnded);
+        detailSpread.bind(spreadNS.Events.ClipboardPasted, detailOperationObj.clipboardPasted);
+        SpreadJsObj.addDeleteBind(detailSpread, detailOperationObj.deletePress);
+    }
+
+    let gsSpread;
+    stageIm.init(stage, imType);
+    const gsTree = stageIm.getGsTree();
+
+    function reBuildImData() {
+        const imData = stageIm.buildImData();
+        SpreadJsObj.loadSheetData(detailSpread.getActiveSheet(), SpreadJsObj.DataType.Data, imData);
+        detailOperationObj.reLoadDetailData();
+        detailOperationObj.loadLeafXmjsData();
     }
 
     postData(window.location.pathname + '/load', { loadType: 'all' }, function (data) {
@@ -451,8 +548,8 @@ $(document).ready(() => {
     };
     // 加载草图组成
     $('#edit-img').on('show.bs.modal', function () {
-        const data = getSelectDetailData();
-        const items = data.calc_img_org !== undefined ? JSON.parse(data.calc_img_org) : [];
+        const data = SpreadJsObj.getSelectObject(detailSpread.getActiveSheet());
+        const items = data.calc_img_org ? JSON.parse(data.calc_img_org) : [];
         const html = [];
         for (const item of items) {
             const itemStyle = 'top:' + item.top + ';' + 'left:' + item.left + ';' + 'width:' + item.width + ';' + 'height:' + item.height + ';';

+ 27 - 2
app/public/js/stage_im.js

@@ -9,6 +9,7 @@
  */
 
 const stageIm = (function () {
+    const imFields = ['uuid', 'doc_code', 'bgl_code', 'start_peg', 'end_peg', 'bw', 'jldy', 'drawing_code', 'calc_memo', 'calc_img'];
     const splitChar = '-';
     let stage, imType, details, ImData, pre;
     const gsTreeSetting = {
@@ -150,7 +151,6 @@ const stageIm = (function () {
     }
 
     function checkCustomDetail(im) {
-        const fields = ['uuid', 'doc_code', 'bgl_code', 'start_peg', 'end_peg', 'bw', 'jldy', 'drawing_code', 'calc_memo', 'calc_img'];
         const cd = _.find(details, function (d) {
             return im.lid === d.lid &&
                 (!im.code || im.code === d.code) &&
@@ -159,7 +159,7 @@ const stageIm = (function () {
         });
         if (cd) {
             _.assignInWith(im, cd, function (oV, sV, key) {
-                return fields.indexOf(key) > -1 && sV ? sV : oV;
+                return imFields.indexOf(key) > -1 && sV !== undefined ? sV : oV;
             });
             console.log(im);
         }
@@ -192,6 +192,7 @@ const stageIm = (function () {
             im.leafXmjs = [];
         }
         const leafXmj = gsTree.getLeafXmjParent(node);
+        if (!leafXmj) { return }
         let lx = _.find(im.leafXmjs, {lxid: leafXmj.id});
         if (!lx) {
             lx = {
@@ -311,16 +312,40 @@ const stageIm = (function () {
         return ImData;
     }
 
+    function loadUpdateDetailData (data) {
+        const datas = data instanceof Array ? data : [data];
+        for (const d of datas) {
+            const detail = _.find(details, {uuid: d.uuid});
+            if (detail) {
+                _.assignIn(detail, d);
+            } else {
+                details.push(d);
+            }
+            let imData = _.find(ImData, {lid: d.lid, uuid: d.uuid});
+            if (!imData) {
+                imData = _.find(ImData, {lid: d.lid, code: d.code, name: d.name, unit: d.unit});
+            }
+            if (imData) {
+                _.assignInWith(imData, d, function (oV, sV, key) {
+                    return imFields.indexOf(key) > -1 && !_.isUndefined(sV) ? sV : oV;
+                });
+            }
+            console.log(imData);
+        }
+    }
+
     return {
         init,
         initCheck,
         loadData,
         buildImData,
+        loadUpdateDetailData,
         getGsTree: function () {
             return gsTree;
         },
         getImData: function () {
             return ImData;
         },
+
     }
 })();

+ 0 - 1
app/service/ledger.js

@@ -1830,7 +1830,6 @@ module.exports = app => {
                     qd.id = insertResult.insertId;
                     newIds.push(insertResult.insertId);
                     if (data[i].pos.length > 0) {
-                        console.log(qd);
                         await this.ctx.service.pos.insertLedgerPosData(this.transaction, tenderId, qd, data[i].pos);
                         await this._calcNode(qd, this.transaction);
                     }

+ 68 - 11
app/service/stage_detail.js

@@ -86,20 +86,38 @@ module.exports = app => {
          * @param {Number} tid - 标段id
          * @param {Number} sid - 期id
          * @param {Number} lid - 关联的台账节点id
-         * @param {String} uuid - 中间计量单 唯一id
+         * @param {String|Array[String]} uuid - 中间计量单 唯一id
          * @returns {Promise<*>}
          */
         async getLastestImStageData(tid, sid, lid, uuid) {
-            const sql = 'SELECT * FROM ' + this.tableName + ' As Bills ' +
-                '  INNER JOIN ( ' +
-                '    SELECT MAX(`times` * ' + timesLen + ' + `order`) As `flow`, `lid`, `uuid` From ' + this.tableName +
-                '      WHERE lid = ? And uuid = ?' +
-                '      GROUP BY `lid`, `uuid`' +
-                '  ) As MaxFilter ' +
-                '  ON (Bills.times * ' + timesLen + ' + Bills.order) = MaxFilter.flow And Bills.lid = MaxFilter.lid And Bills.uuid = MaxFilter.uuid' +
-                '  WHERE Bills.tid = ? And Bills.sid = ?';
-            const sqlParam = [lid, uuid, tid, sid];
-            return await this.db.queryOne(sql, sqlParam);
+            if (uuid instanceof Array) {
+                if (uuid.length === 0) { return []; }
+                let uuidSql = '';
+                for (const u of uuid) {
+                    uuidSql = uuidSql === '' ? this.db.escape(u) : uuidSql + ',' + this.db.escape(u);
+                }
+                const sql = 'SELECT * FROM ' + this.tableName + ' As Bills ' +
+                    '  INNER JOIN ( ' +
+                    '    SELECT MAX(`times` * ' + timesLen + ' + `order`) As `flow`, `lid`, `uuid` From ' + this.tableName +
+                    '      WHERE lid = ? And uuid In (' + uuidSql + ')' +
+                    '      GROUP BY `lid`, `uuid`' +
+                    '  ) As MaxFilter ' +
+                    '  ON (Bills.times * ' + timesLen + ' + Bills.order) = MaxFilter.flow And Bills.lid = MaxFilter.lid And Bills.uuid = MaxFilter.uuid' +
+                    '  WHERE Bills.tid = ? And Bills.sid = ?';
+                const sqlParam = [lid, tid, sid];
+                return await this.db.query(sql, sqlParam);
+            } else {
+                const sql = 'SELECT Bills.* FROM ' + this.tableName + ' As Bills ' +
+                    '  INNER JOIN ( ' +
+                    '    SELECT MAX(`times` * ' + timesLen + ' + `order`) As `flow`, `lid`, `uuid` From ' + this.tableName +
+                    '      WHERE lid = ? And uuid = ?' +
+                    '      GROUP BY `lid`, `uuid`' +
+                    '  ) As MaxFilter ' +
+                    '  ON (Bills.times * ' + timesLen + ' + Bills.order) = MaxFilter.flow And Bills.lid = MaxFilter.lid And Bills.uuid = MaxFilter.uuid' +
+                    '  WHERE Bills.tid = ? And Bills.sid = ?';
+                const sqlParam = [lid, uuid, tid, sid];
+                return await this.db.queryOne(sql, sqlParam);
+            }
         }
 
         /**
@@ -135,6 +153,45 @@ module.exports = app => {
                 return data;
             }
         }
+
+        async saveDetailDatas(data) {
+            if (!data instanceof Array) {
+                throw '数据错误';
+            }
+            const transaction = await this.db.beginTransaction();
+            const result = [];
+            try {
+                for (const d of data) {
+                    if (d.uuid) {
+                        const od = await this.getLastestImStageData(this.ctx.tender.id, this.ctx.stage.id, d.lid, d.uuid);
+                        delete od.flow;
+                        if (od.times === this.ctx.stage.curTimes && od.order === this.ctx.stage.curOrder) {
+                            d.id = od.id;
+                            await this.db.update(this.tableName, d);
+                            result.push(d);
+                        } else {
+                            const nd = this._.assign(od, data);
+                            nd.times = this.ctx.stage.curTimes;
+                            nd.order = this.ctx.stage.curOrder;
+                            await this.db.insert(this.tableName, nd);
+                            result.push(nd);
+                        }
+                    } else {
+                        d.uuid = this.uuid.v4();
+                        d.tid = this.ctx.tender.id;
+                        d.sid = this.ctx.stage.id;
+                        d.times = this.ctx.stage.curTimes;
+                        d.order = this.ctx.stage.curOrder;
+                        await transaction.insert(this.tableName, d);
+                        result.push(d);
+                    }
+                }
+                return result;
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
     }
 
     return StageDetail;

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

@@ -10,6 +10,7 @@
     <link rel="stylesheet" href="/public/css/main.css">
     <link rel="stylesheet" href="/public/css/toast.css">
     <link rel="stylesheet" href="/public/css/font-awesome/font-awesome.min.css">
+    <link rel="stylesheet" type="text/css" href="/public/css/jquery-ui/jquery-ui.min.css">
     <link rel="stylesheet" href="/public/css/spreadjs/sheets/gc.spread.sheets.excelsmartcost.css">
     <link rel="stylesheet" href="/public/css/jquery-contextmenu/jquery.contextMenu.min.css">
     <link rel="stylesheet" href="/public/css/ztree/zTreeStyle.css" type="text/css">

+ 1 - 8
app/view/stage/detail.ejs

@@ -19,14 +19,7 @@
             <!--左栏-->
             <div class="c-body col-8">
                 <!--上部分-->
-                <div class="sjs-height-0">
-                    <table class="table table-sm table-bordered">
-                        <thead>
-                        <tr><th>编号</th><th>中间计量表号</th><th>交工证书/凭证号</th><th>分部分项工程</th><th>本期计量数量/金额</th></tr>
-                        </thead>
-                        <tbody id="im-list">
-                        </tbody>
-                    </table>
+                <div class="sjs-height-0" id="detail-spread">
                 </div>
             </div>
             <!--右栏-->

+ 0 - 1
app/view/stage/detail_modal.ejs

@@ -77,7 +77,6 @@
 </div>
 <!--添加草图-->
 <div class="modal fade" id="edit-img" data-backdrop="static">
-    <link rel="stylesheet" type="text/css" href="/public/css/jquery-ui/jquery-ui.min.css">
     <div class="modal-dialog modal-lgx" role="document">
         <div class="modal-content">
             <div class="modal-header">