Browse Source

签约清单,允许编辑

MaiXinRong 4 years ago
parent
commit
14ed85c6e6

+ 39 - 1
app/controller/deal_bills_controller.js

@@ -18,6 +18,7 @@ const loadExcelType = {
     actual: 2,
     actual: 2,
 };
 };
 const loadType = loadExcelType.display;
 const loadType = loadExcelType.display;
+const auditConst = require('../const/audit').ledger;
 
 
 module.exports = app => {
 module.exports = app => {
     class DealBillsController extends app.BaseController {
     class DealBillsController extends app.BaseController {
@@ -34,7 +35,10 @@ module.exports = app => {
                 data: [],
                 data: [],
             };
             };
             try {
             try {
-                responseData.data = await ctx.service.dealBills.getAllDataByCondition({ where: { tender_id: ctx.tender.id } });
+                responseData.data = await ctx.service.dealBills.getAllDataByCondition({
+                    where: { tender_id: ctx.tender.id },
+                    orders: [['order', 'asc']],
+                });
             } catch (error) {
             } catch (error) {
                 this.log(error);
                 this.log(error);
                 responseData.err = 1;
                 responseData.err = 1;
@@ -137,6 +141,40 @@ module.exports = app => {
                 }
                 }
             }
             }
         }
         }
+
+        async _base(ctx, type, data) {
+            if (isNaN(data.id) || data.id <= 0) throw '数据错误';
+            if (type !== 'add') {
+                if (isNaN(data.count) || data.count <= 0) data.count = 1;
+            }
+            switch (type) {
+                case 'add':
+                    return await ctx.service.dealBills.addNodeBatch(ctx.tender.id, data.id, {}, data.count);
+                case 'delete':
+                    return await ctx.service.dealBills.delete(ctx.tender.id, data.id, data.count);
+            }
+        }
+
+        /**
+         * 更新清单相关 (Ajax)
+         * @param ctx
+         * @return {Promise<void>}
+         */
+        async update(ctx) {
+            try {
+                if (!ctx.tender.data) throw '标段数据错误';
+                if (ctx.tender.data.user_id !== ctx.session.sessionUser.accountId ||
+                    (ctx.tender.ledger_status === auditConst.status.checking || ctx.tender.ledger_status === auditConst.status.checked))
+                    throw '您无权进行该操作';
+                const data = JSON.parse(ctx.request.body.data);
+                const result = await ctx.service.dealBills.updateDatas(data);
+                ctx.body = { err: 0, msg: '', data: result };
+            } catch (err) {
+                this.log(err);
+                ctx.body = this.ajaxErrorBody(err);
+            }
+
+        }
     }
     }
 
 
     return DealBillsController;
     return DealBillsController;

+ 203 - 2
app/public/js/ledger.js

@@ -2198,7 +2198,7 @@ $(document).ready(function() {
                             {title: '单位', field: 'unit', hAlign: 1, width: 50, formatter: '@'},
                             {title: '单位', field: 'unit', hAlign: 1, width: 50, formatter: '@'},
                             {title: '单价', field: 'unit_price', hAlign: 2, width: 50},
                             {title: '单价', field: 'unit_price', hAlign: 2, width: 50},
                             {title: '数量', field: 'quantity', hAlign: 2, width: 50},
                             {title: '数量', field: 'quantity', hAlign: 2, width: 50},
-                            {title: '金额', field: 'total_price', hAlign: 2, width: 50},
+                            {title: '金额', field: 'total_price', hAlign: 2, width: 50, readOnly: true},
                         ],
                         ],
                         emptyRows: 3,
                         emptyRows: 3,
                         headRows: 1,
                         headRows: 1,
@@ -2266,6 +2266,180 @@ $(document).ready(function() {
             this.spread = SpreadJsObj.createNewSpread(this.obj);
             this.spread = SpreadJsObj.createNewSpread(this.obj);
             this.sheet = this.spread.getActiveSheet();
             this.sheet = this.spread.getActiveSheet();
             SpreadJsObj.initSheet(this.spread.getActiveSheet(), this.spreadSetting);
             SpreadJsObj.initSheet(this.spread.getActiveSheet(), this.spreadSetting);
+
+
+            this.OprObj = {
+                /**
+                 * 删除按钮响应事件
+                 * @param sheet
+                 */
+                deletePress: function (sheet) {
+                    if (!sheet.zh_setting || readOnly || sheet.zh_setting.readOnly) return;
+
+                    const sortData = sheet.zh_data;
+                    const datas = [];
+                    const sels = sheet.getSelections();
+                    if (!sels || !sels[0]) return;
+
+                    for (let iRow = sels[0].row; iRow < sels[0].row + sels[0].rowCount; iRow++) {
+                        let bDel = false;
+                        const node = sortData[iRow];
+                        if (node) {
+                            const data = {id: node.id};
+                            for (let iCol = sels[0].col; iCol < sels[0].col + sels[0].colCount; iCol++) {
+                                const colSetting = sheet.zh_setting.cols[iCol];
+                                if (colSetting.field === 'code') {
+                                    toastr.error('清单编号不能为空,如需删除签约清单请使用右键删除');
+                                    return;
+                                }
+                                const style = sheet.getStyle(iRow, iCol);
+                                if (!style.locked) {
+                                    const colSetting = sheet.zh_setting.cols[iCol];
+                                    data[colSetting.field] = null;
+                                    bDel = true;
+                                }
+                            }
+                            if (bDel) {
+                                datas.push(data);
+                            }
+                        }
+                    }
+                    if (datas.length > 0) {
+                        postData(self.url + '/update', {update: datas}, function (result) {
+                            self.loadUpdateData(result);
+                            SpreadJsObj.reLoadSheetData(sheet);
+                        }, function () {
+                            SpreadJsObj.reLoadSheetData(sheet);
+                        });
+                    }
+                },
+                delete: function (sheet) {
+                    if (!sheet.zh_setting || readOnly || sheet.zh_setting.readOnly) return;
+
+                    const sortData = sheet.zh_data;
+                    const datas = [];
+                    const sels = sheet.getSelections();
+                    if (!sels || !sels[0]) return;
+
+                    for (let iRow = sels[0].row, iLen = sels[0].row + sels[0].rowCount; iRow < iLen; iRow++) {
+                        const node = sortData[iRow];
+                        datas.push(node.id);
+                    }
+                    if (datas.length > 0) {
+                        postData(self.url + '/update', {del: datas}, function (result) {
+                            self.loadUpdateData(result);
+                            SpreadJsObj.reLoadSheetData(sheet);
+                        }, function () {
+                            SpreadJsObj.reLoadSheetData(sheet);
+                        });
+                    }
+                },
+                editEnded: function (e, info) {
+                    if (!info.sheet.zh_setting || !info.sheet.zh_data || info.sheet.zh_setting.readOnly) return;
+
+                    const node = info.sheet.zh_data[info.row];
+                    const col = info.sheet.zh_setting.cols[info.col];
+                    const data = {};
+
+                    if (node) {
+                        data.update = {};
+                        data.update.id = node.id;
+
+                        const oldValue = node ? node[col.field] : null;
+                        const newValue = trimInvalidChar(info.editingText);
+                        if (oldValue == info.editingText || ((!oldValue || oldValue === '') && (newValue === ''))) {
+                            SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                            return;
+                        }
+                        data.update[col.field] = newValue;
+                    } else {
+                        if (col.field !== 'code') {
+                            toastr.warning('新增签约清单,请先输入清单编号');
+                            SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                            return;
+                        }
+                        data.add = {};
+                        data.add.order = info.row + 1;
+                        data.add.code = trimInvalidChar(info.editingText);
+                    }
+
+                    postData(self.url +  '/update', data, function (result) {
+                        self.loadUpdateData(result);
+                        SpreadJsObj.reLoadSheetData(info.sheet);
+                    }, function () {
+                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                    });
+                },
+                clipboardPasting(e, info) {
+                    const setting = info.sheet.zh_setting, sortData = info.sheet.zh_data;
+                    info.cancel = true;
+
+                    if (!setting || !sortData || setting.readOnly) return;
+                    const pasteData = info.pasteData.html
+                        ? SpreadJsObj.analysisPasteHtml(info.pasteData.html)
+                        : (info.pasteData.text === ''
+                            ? SpreadJsObj.Clipboard.getAnalysisPasteText()
+                            : SpreadJsObj.analysisPasteText(info.pasteData.text));
+                    const hint = {
+                        code: {type: 'warning', msg: '签约清单编号不可为空,已过滤'},
+                        unit_price: {type: 'warning', msg: '输入的 单价 非法,已过滤'},
+                        quantity: {type: 'warning', msg: '输入的 数量 非法,已过滤'},
+                    };
+
+                    const uDatas = [], iDatas = [];
+                    for (let iRow = 0; iRow < info.cellRange.rowCount; iRow++) {
+                        const curRow = info.cellRange.row + iRow;
+                        const node = sortData[curRow];
+
+                        let bPaste = false;
+                        const data = {};
+                        for (let iCol = 0; iCol < info.cellRange.colCount; iCol++) {
+                            const curCol = info.cellRange.col + iCol;
+                            const colSetting = setting.cols[curCol];
+                            const value = trimInvalidChar(pasteData[iRow][iCol]);
+
+                            if (colSetting.field === 'code' && (!value || value === '')) {
+                                toastMessageUniq(hint.code);
+                                break;
+                            }
+                            if (colSetting.type === 'Number') {
+                                const num = _.toNumber(value);
+                                if (num) {
+                                    data[colSetting.field] = num;
+                                    bPaste = true;
+                                } else if (colSetting.field === 'unit_price') {
+                                    toastMessageUniq(hint.unit_price);
+                                } else if (colSetting.field === 'quantity') {
+                                    toastMessageUniq(hint.quantity);
+                                }
+                            } else {
+                                data[colSetting.field] = value;
+                                bPaste = true;
+                            }
+                        }
+                        if (bPaste) {
+                            if (node) {
+                                data.id = node.id;
+                                uDatas.push(data);
+                            } else {
+                                data.order = curRow + 1;
+                                iDatas.push(data);
+                            }
+                        }
+                    }
+                    const updateData = {};
+                    if (uDatas.length > 0) updateData.update = uDatas;
+                    if (iDatas.length > 0) updateData.add = iDatas;
+                    if (uDatas.length > 0 || iDatas.length > 0) {
+                        postData(self.url + '/update', updateData, function (result) {
+                            self.loadUpdateData(result);
+                            SpreadJsObj.reLoadSheetData(info.sheet);
+                        });
+                    } else {
+                        SpreadJsObj.reLoadSheetData(info.sheet);
+                    }
+                },
+            };
             if (!readOnly) {
             if (!readOnly) {
                 this.spread.bind(spreadNS.Events.CellDoubleClick, function (e, info) {
                 this.spread.bind(spreadNS.Events.CellDoubleClick, function (e, info) {
                     const dealSheet = info.sheet;
                     const dealSheet = info.sheet;
@@ -2305,6 +2479,9 @@ $(document).ready(function() {
                         posOperationObj.loadCurPosData();
                         posOperationObj.loadCurPosData();
                     });
                     });
                 });
                 });
+                this.spread.bind(spreadNS.Events.EditEnded, this.OprObj.editEnded);
+                this.spread.bind(spreadNS.Events.ClipboardPasting, this.OprObj.clipboardPasting);
+                SpreadJsObj.addDeleteBind(this.spread, this.OprObj.deletePress);
             }
             }
             $('#upload-deal-bills').click(function () {
             $('#upload-deal-bills').click(function () {
                     const file = $('#deal-bills-file')[0];
                     const file = $('#deal-bills-file')[0];
@@ -2359,7 +2536,7 @@ $(document).ready(function() {
                                 return !select;
                                 return !select;
                             },
                             },
                             callback: function (key, opt) {
                             callback: function (key, opt) {
-
+                                self.OprObj.delete(self.sheet);
                             },
                             },
                         },
                         },
                         sprEdit: '---------',
                         sprEdit: '---------',
@@ -2412,6 +2589,30 @@ $(document).ready(function() {
                 }
                 }
             }
             }
         }
         }
+        loadUpdateData(updateData) {
+            if (updateData.add) {
+                for (const a of updateData.add) {
+                    this.data.push(a);
+                }
+            }
+            if (updateData.update) {
+                for (const u of updateData.update) {
+                    const d = this.data.find(function (x) {
+                        return u.id === x.id;
+                    });
+                    if (d) {
+                        _.assign(d, u);
+                    } else {
+                        this.data.push(d);
+                    }
+                }
+            }
+            if (updateData.del) {
+                _.remove(this.data, function (d) {
+                    return updateData.del.indexOf(d.id) >= 0;
+                });
+            }
+        }
     }
     }
     class BatchInsertBillsPosObj {
     class BatchInsertBillsPosObj {
         constructor (obj) {
         constructor (obj) {

+ 1 - 1
app/public/js/spreadjs_rela/spreadjs_zh.js

@@ -637,7 +637,7 @@ const SpreadJsObj = {
             sheet.setRowCount(totalRow, spreadNS.SheetArea.viewport);
             sheet.setRowCount(totalRow, spreadNS.SheetArea.viewport);
             // 控制空白行
             // 控制空白行
             const emptyRows = sheet.getRange(sortData.length, -1, sheet.zh_setting.emptyRows, -1);
             const emptyRows = sheet.getRange(sortData.length, -1, sheet.zh_setting.emptyRows, -1);
-            emptyRows.locked(sheet.zh_dataType === 'tree');
+            emptyRows.locked(sheet.zh_dataType === 'tree' || sheet.zh_setting.readOnly);
             if (sortData) {
             if (sortData) {
                 // 单元格写入数据
                 // 单元格写入数据
                 sortData.forEach(function (data, i) {
                 sortData.forEach(function (data, i) {

+ 1 - 0
app/router.js

@@ -184,6 +184,7 @@ module.exports = app => {
     app.post('/tender/:id/deal/get-data', sessionAuth, tenderCheck, uncheckTenderCheck, 'dealBillsController.getData');
     app.post('/tender/:id/deal/get-data', sessionAuth, tenderCheck, uncheckTenderCheck, 'dealBillsController.getData');
     app.post('/tender/:id/deal/upload-excel', sessionAuth, tenderCheck, uncheckTenderCheck, 'dealBillsController.loadExcel');
     app.post('/tender/:id/deal/upload-excel', sessionAuth, tenderCheck, uncheckTenderCheck, 'dealBillsController.loadExcel');
     app.get('/tender/:id/deal/download/:file', sessionAuth, tenderCheck, uncheckTenderCheck, 'dealBillsController.download');
     app.get('/tender/:id/deal/download/:file', sessionAuth, tenderCheck, uncheckTenderCheck, 'dealBillsController.download');
+    app.post('/tender/:id/deal/update', sessionAuth, tenderCheck, uncheckTenderCheck, 'dealBillsController.update');
 
 
     // 计量台账
     // 计量台账
     // 期计量
     // 期计量

+ 87 - 2
app/service/deal_bills.js

@@ -161,7 +161,8 @@ module.exports = app => {
                     //if (this.ctx.helper.validBillsCode(code)) {
                     //if (this.ctx.helper.validBillsCode(code)) {
                     if (code) {
                     if (code) {
                         const data = {
                         const data = {
-                            deal_id: bills.length + 1,
+                            uuid: this.uuid.v4(),
+                            order: bills.length + 1,
                             tender_id: tenderId,
                             tender_id: tenderId,
                             code: code,
                             code: code,
                             name: this.ctx.helper.replaceReturn(row[iName]),
                             name: this.ctx.helper.replaceReturn(row[iName]),
@@ -206,12 +207,96 @@ module.exports = app => {
         * @param {Number} tenderId - 所属标段Id
         * @param {Number} tenderId - 所属标段Id
         */
         */
         async getDataByTenderId(tenderId) {
         async getDataByTenderId(tenderId) {
-            const sql = 'SELECT Bills.* FROM ' + this.tableName + ' As Bills WHERE tender_id = ?';
+            const sql = 'SELECT Bills.* FROM ' + this.tableName + ' As Bills WHERE tender_id = ? ORDER BY ';
             const sqlParam = [tenderId];
             const sqlParam = [tenderId];
             return await this.db.query(sql, sqlParam);
             return await this.db.query(sql, sqlParam);
             // let rst = await this.getDataByCondition({tender_id: tenderId});
             // let rst = await this.getDataByCondition({tender_id: tenderId});
             // return rst;
             // return rst;
         }
         }
+
+        async _addDatas(data) {
+            const info =  this.ctx.tender.info;
+
+            const datas = data instanceof Array ? data : [data];
+            const insertData = [];
+            for (const d of datas) {
+                if (!d.code || !d.order) throw '新增签约清单,提交的数据错误';
+                const nd = { id: this.uuid.v4(), tender_id: this.ctx.tender.id };
+                nd.code = d.code;
+                nd.order = d.order;
+                if (d.name) nd.name = d.name;
+                if (d.unit) nd.unit = d.unit;
+                if (d.unit_price) nd.unit_price = this.ctx.helper.round(d.unit_price, info.decimal.up);
+                const precision = this.ctx.helper.findPrecision(info.precision, d.unit);
+                if (d.quantity) {
+                    nd.quantity = this.ctx.helper.round(d.quantity, precision.value);
+                    nd.total_price = this.ctx.helper.mul(nd.unit_price, nd.quantity, info.decimal.tp);
+                }
+                insertData.push(nd);
+            }
+            const result = await this.db.insert(this.tableName, insertData);
+            return insertData;
+        }
+
+        async _delDatas (data) {
+            await this.db.delete(this.tableName, {id: data});
+            return data;
+        }
+
+        async _updateDatas (data) {
+            const info =  this.ctx.tender.info;
+
+            const datas = data instanceof Array ? data : [data];
+            const orgDatas = await this.getAllDataByCondition({where: {id: this.ctx.helper._.map(datas, 'id')}});
+
+            const uDatas = [];
+            for (const d of datas) {
+                const od = this.ctx.helper._.find(orgDatas, {id: d.id});
+                if (!od) continue;
+
+                const nd = {id: od.id};
+
+                if (d.code !== undefined) nd.code = d.code;
+                if (d.order !== undefined) nd.order = d.order;
+                if (d.name !== undefined) nd.name = d.name;
+                if (d.unit !== undefined) nd.unit = d.unit;
+                nd.unit_price = d.unit_price !== undefined ? this.ctx.helper.round(d.unit_price, info.decimal.up) : od.unit_price;
+                const precision = this.ctx.helper.findPrecision(info.precision, d.unit);
+                if (d.quantity !== undefined) {
+                    nd.quantity = this.ctx.helper.round(d.quantity, precision.value);
+                    nd.total_price = this.ctx.helper.mul(nd.unit_price, nd.quantity, info.decimal.tp);
+                } else {
+                    nd.quantity = this.ctx.helper.round(od.quantity, precision.value);
+                    nd.total_price = this.ctx.helper.mul(nd.unit_price, nd.quantity, info.decimal.tp);
+                }
+                uDatas.push(nd);
+            }
+            if (uDatas.length > 0) {
+                await this.db.updateRows(this.tableName, uDatas);
+                return uDatas;
+            } else {
+                return [];
+            }
+        }
+
+        async updateDatas(data) {
+            const result = {add: [], del: [], update: []};
+            try {
+                if (data.add) {
+                    result.add = await this._addDatas(data.add);
+                }
+                if (data.update) {
+                    result.update = await this._updateDatas(data.update);
+                }
+                if (data.del) {
+                    result.del = await this._delDatas(data.del);
+                }
+                return result;
+            } catch (err) {
+                if (err) result.err = err;
+                return result;
+            }
+        }
     }
     }
 
 
     return DealBills;
     return DealBills;

+ 3 - 1
app/service/stage_bonus.js

@@ -121,7 +121,9 @@ module.exports = app => {
                 : this.ctx.tender.info.decimal.tp;
                 : this.ctx.tender.info.decimal.tp;
 
 
             const datas = data instanceof Array ? data : [data];
             const datas = data instanceof Array ? data : [data];
-            const orgDatas = await this.getAllDataByCondition({sid: this.ctx.stage.id, id: this.ctx.helper._.map(datas, 'id')});
+            const orgDatas = await this.getAllDataByCondition({
+                where: { sid: this.ctx.stage.id, id: this.ctx.helper._.map(datas, 'id') }
+            });
 
 
             const uDatas = [];
             const uDatas = [];
             for (const d of datas) {
             for (const d of datas) {

+ 3 - 1
app/service/stage_jgcl.js

@@ -126,7 +126,9 @@ module.exports = app => {
                 : this.ctx.tender.info.decimal.tp;
                 : this.ctx.tender.info.decimal.tp;
 
 
             const datas = data instanceof Array ? data : [data];
             const datas = data instanceof Array ? data : [data];
-            const orgDatas = await this.getAllDataByCondition({sid: this.ctx.stage.id, id: this.ctx.helper._.map(datas, 'id')});
+            const orgDatas = await this.getAllDataByCondition({
+                where: { sid: this.ctx.stage.id, id: this.ctx.helper._.map(datas, 'id') }
+            });
             const info = this.ctx.tender.info;
             const info = this.ctx.tender.info;
 
 
             const uDatas = [];
             const uDatas = [];

+ 3 - 1
app/service/stage_other.js

@@ -108,7 +108,9 @@ module.exports = app => {
                 : this.ctx.tender.info.decimal.tp;
                 : this.ctx.tender.info.decimal.tp;
 
 
             const datas = data instanceof Array ? data : [data];
             const datas = data instanceof Array ? data : [data];
-            const orgDatas = await this.getAllDataByCondition({sid: this.ctx.stage.id, id: this.ctx.helper._.map(datas, 'id')});
+            const orgDatas = await this.getAllDataByCondition({
+                where: { sid: this.ctx.stage.id, id: this.ctx.helper._.map(datas, 'id') }
+            });
 
 
             const uDatas = [];
             const uDatas = [];
             for (const d of datas) {
             for (const d of datas) {

+ 4 - 0
sql/update.sql

@@ -9,3 +9,7 @@ ALTER TABLE `zh_material_bills` ADD `is_summary` TINYINT(1) NOT NULL DEFAULT '1'
 
 
 ALTER TABLE `zh_material_bills_history` ADD `is_summary` TINYINT(1) NOT NULL DEFAULT '1' COMMENT '是否汇总' AFTER `pre_tp`;
 ALTER TABLE `zh_material_bills_history` ADD `is_summary` TINYINT(1) NOT NULL DEFAULT '1' COMMENT '是否汇总' AFTER `pre_tp`;
 
 
+ALTER TABLE `zh_deal_bills`
+MODIFY COLUMN `id`  varchar(50) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL COMMENT '主键(uuid)' FIRST ,
+CHANGE COLUMN `deal_id` `order`  int(11) NOT NULL AFTER `tender_id`;
+