Browse Source

总分包 v0.1

MaiXinRong 3 năm trước cách đây
mục cha
commit
f86ebb32c9

+ 60 - 28
app/controller/tender_controller.js

@@ -165,14 +165,12 @@ module.exports = app => {
                 };
                 await this.layout(view, renderData, modal);
             } catch (err) {
-                console.log(err);
                 this.log(err);
                 this.ctx.redirect('/dashboard');
             }
         }
 
         async _list(view, renderData, modal = '', list_status = '') {
-            console.log(1);
             try {
                 renderData.tenderList = await this.ctx.service.tender.getList(list_status, renderData.userPermission, this.ctx.session.sessionUser.is_admin);
 
@@ -232,7 +230,6 @@ module.exports = app => {
          * @return {void}
          */
         async listInfo(ctx) {
-            console.log('listInfo');
             this.jsFiles = this.app.jsFiles.tender.info;
             await this._listDetail('tender/info.ejs', 'tender/modal.ejs');
         }
@@ -244,7 +241,6 @@ module.exports = app => {
          * @return {Promise<void>}
          */
         async listProgress(ctx) {
-            console.log('listProgress');
             this.jsFiles = this.app.jsFiles.tender.progress;
             await this._listDetail('tender/progress.ejs', 'tender/modal.ejs');
         }
@@ -256,7 +252,6 @@ module.exports = app => {
          * @return {Promise<void>}
          */
         async listManage(ctx) {
-            console.log('listManager');
             this.jsFiles = this.app.jsFiles.tender.manage;
             // 先判断权限
             // 获取用户新建标段权利
@@ -296,6 +291,66 @@ module.exports = app => {
             }
         }
 
+        async listLoad(ctx) {
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                if (!data.tid && !data.lid && !data.type) throw '数据错误';
+                const responseData = {
+                    err: 0,
+                    msg: '',
+                    data: { ledgerAuditConst: auditConst.ledger, stageAuditConst: auditConst.stage },
+                };
+                responseData.data.category = await this.ctx.service.category.getAllCategory(this.ctx.session.sessionProject.id);
+                // 获取用户权限
+                const accountInfo = await this.ctx.service.projectAccount.getDataById(this.ctx.session.sessionUser.accountId);
+                const userPermission = accountInfo !== undefined && accountInfo.permission !== '' ? JSON.parse(accountInfo.permission) : null;
+                const tenderList = await this.ctx.service.tender.getList('', userPermission);
+                for (const t of tenderList) {
+                    if (t.ledger_status === auditConst.ledger.status.checked) {
+                        t.lastStage = await this.ctx.service.stage.getLastestStage(t.id, false);
+                    }
+                }
+                if (data.type === 'ledger') {
+                    responseData.data.tenders = tenderList.filter(x => {
+                        return x.ledger_status === auditConst.ledger.status.checked;
+                    });
+                    const history = await this.ctx.service.sumLoadHistory.getLedgerHistory(data.tid, data.lid);
+                    if (history) responseData.data.history = { tenders: history.tender, load_time: history.load_time, type: 'ledger' };
+                } else if (data.type === 'stage') {
+                    responseData.data.tenders = tenderList.filter(x => {
+                        return x.ledger_status === auditConst.ledger.status.checked && !!x.lastStage;
+                    });
+                    let history = await this.ctx.service.sumLoadHistory.getStageHistory(data.tid, data.lid);
+                    if (history) {
+                        responseData.data.history = { tenders: history.tender, load_time: history.load_time, type: 'stage' };
+                    } else {
+                        history = await this.ctx.service.sumLoadHistory.getReviseHistory(data.tid, data.lid);
+                        if (history) {
+                            responseData.data.history = { tenders: history.tender, load_time: history.load_time, type: 'revise' };
+                        } else {
+                            history = await this.ctx.service.sumLoadHistory.getLedgerHistory(data.tid, data.lid);
+                            if (history) responseData.data.history = { tenders: history.tender, load_time: history.load_time, type: 'ledger' };
+                        }
+                    }
+                } else if (data.type === 'revise') {
+                    responseData.data.tenders = tenderList.filter(x => {
+                        return x.ledger_status === auditConst.ledger.status.checked;
+                    });
+                    let history = await this.ctx.service.sumLoadHistory.getReviseHistory(data.tid, data.lid);
+                    if (history) {
+                        responseData.data.history = { tenders: history.tender, load_time: history.load_time, type: 'revise' };
+                    } else {
+                        history = await this.ctx.service.sumLoadHistory.getLedgerHistory(data.tid, data.lid);
+                        if (history) responseData.data.history = { tenders: history.tender, load_time: history.load_time, type: 'ledger' };
+                    }
+                }
+                ctx.body = responseData;
+            } catch(err) {
+                this.log(err);
+                this.ajaxErrorBody(err, '获取标段列表错误');
+            }
+        }
+
         /**
          * 新增标段(Ajax)
          *
@@ -641,29 +696,6 @@ module.exports = app => {
         }
 
         /**
-         * 切换标段 --》 暂时废弃,不存在此功能
-         *
-         * @param {Object} ctx - egg全局变量
-         * @return {void}
-         */
-        async switchTender(ctx) {
-            let tenderId = ctx.params.tenderId;
-            tenderId = parseInt(tenderId);
-            try {
-                if (isNaN(tenderId) || tenderId <= 0) {
-                    throw '参数错误';
-                }
-                const result = await ctx.service.tender.switchTender(tenderId);
-                if (!result) {
-                    throw '切换标段失败!';
-                }
-            } catch (error) {
-                this.setMessage(error.toString(), this.messageType.ERROR);
-            }
-            ctx.redirect(ctx.request.header.referer);
-        }
-
-        /**
          * 保存标段操作
          *
          * @param {Object} ctx - egg全局变量

+ 22 - 21
app/public/js/ledger.js

@@ -57,6 +57,7 @@ const checkOption = {
 
 $(document).ready(function() {
     let stdXmj, stdGcl, dealBills, searchLedger;
+    const tenderSelect = TenderSelect({type: 'stage'});
     autoFlashHeight();
     // 初始化台账
     const ledgerSpread = SpreadJsObj.createNewSpread($('#ledger-spread')[0]);
@@ -1003,21 +1004,6 @@ $(document).ready(function() {
     sjsSettingObj.setFxTreeStyle(ledgerSpreadSetting, sjsSettingObj.FxTreeStyle.jz);
     if (thousandth) sjsSettingObj.setTpThousandthFormat(ledgerSpreadSetting);
     ledgerTreeCol.initSpreadSetting(ledgerSpreadSetting);
-    // ledgerSpreadSetting.rowHeader = [
-    //     {
-    //         rowHeaderType: 'tag',
-    //         setting: {
-    //             getColor: function (index, data) {
-    //                 if (!data) return;
-    //                 if (index%10 === 0) return '#007bff';
-    //                 if (index%10 === 1) return '#28a745';
-    //                 if (index%10 === 2) return '#dc3545';
-    //                 if (index%10 === 3) return '#da9500';
-    //                 if (index%10 === 4) return '#17a2b8';
-    //             }
-    //         },
-    //     },
-    // ];
     ledgerSpreadSetting.headColWidth = [50];
     ledgerSpreadSetting.rowHeader = [
         {
@@ -1060,20 +1046,20 @@ $(document).ready(function() {
     SpreadJsObj.initSheet(ledgerSpread.getActiveSheet(), ledgerSpreadSetting);
     SpreadJsObj.selChangedRefreshBackColor(ledgerSpread.getActiveSheet());
     // 绑定事件
-    ledgerSpread.bind(GC.Spread.Sheets.Events.SelectionChanged, treeOperationObj.selectionChanged);
+    ledgerSpread.bind(spreadNS.Events.SelectionChanged, treeOperationObj.selectionChanged);
     ledgerSpread.bind(spreadNS.Events.TopRowChanged, treeOperationObj.topRowChanged);
 
     if (!ledgerSpreadSetting.readOnly) {
-        ledgerSpread.bind(GC.Spread.Sheets.Events.SelectionChanged, function (e, info) {
+        ledgerSpread.bind(spreadNS.Events.SelectionChanged, function (e, info) {
             treeOperationObj.refreshOperationValid(info.sheet, info.newSelections);
         });
-        ledgerSpread.bind(GC.Spread.Sheets.Events.EditEnded, treeOperationObj.editEnded);
+        ledgerSpread.bind(spreadNS.Events.EditEnded, treeOperationObj.editEnded);
         SpreadJsObj.addDeleteBind(ledgerSpread, treeOperationObj.deletePress);
-        ledgerSpread.bind(GC.Spread.Sheets.Events.ClipboardChanging, function (e, info) {
+        ledgerSpread.bind(spreadNS.Events.ClipboardChanging, function (e, info) {
             const copyText = SpreadJsObj.getFilterCopyText(info.sheet);
             SpreadJsObj.Clipboard.setCopyData(copyText);
         });
-        ledgerSpread.bind(GC.Spread.Sheets.Events.ClipboardPasting, treeOperationObj.clipboardPasting);
+        ledgerSpread.bind(spreadNS.Events.ClipboardPasting, treeOperationObj.clipboardPasting);
         ledgerSpread.bind(spreadNS.Events.EditStarting, treeOperationObj.editStarting);
         SpreadJsObj.addCutEvents(ledgerSpread, treeOperationObj.cut);
 
@@ -1563,7 +1549,6 @@ $(document).ready(function() {
                     // }
                     //u_type: importExcel.uploadType.file,
                 });
-                //$('#upload-ledger').modal('show');
             },
             visible: function (key, opt) {
                 return !readOnly;
@@ -1610,6 +1595,22 @@ $(document).ready(function() {
                 return !readOnly;
             }
         };
+        billsContextMenuOptions.items.importGclBills2Xmj = {
+            name: '导入(其他标段)工程量清单至项目节',
+            icon: 'fa-file-excel-o',
+            disabled: function (key, opt) {
+                const node = SpreadJsObj.getSelectObject(ledgerSpread.getActiveSheet());
+                return readOnly || !node
+                    || (node.children && node.children.length > 0)
+                    || (!_.isNil(node.b_code) && node.b_code !== '');
+            },
+            callback: function (key, opt) {
+                tenderSelect.showSelect(SpreadJsObj.getSelectObject(ledgerSpread.getActiveSheet()));
+            },
+            visible: function (key, opt) {
+                return !readOnly;
+            }
+        };
         billsContextMenuOptions.items.sprImport = '----';
     }
     billsContextMenuOptions.items.tag = {

+ 150 - 0
app/public/js/shares/tender_select.js

@@ -0,0 +1,150 @@
+const TenderSelect = function (setting) {
+    const tsObj = {
+        setting,
+        tenderSpread: null,
+        tenderSheet: null,
+        resultSpread: null,
+        resultSheet: null,
+        select: null,
+        tenderSourceTree: null,
+        trArray: [],
+        _rebuildStageSelect: function () {
+            if (tsObj.setting.type === 'stage') {
+                const getItems = function (data) {
+                    if (!data) return [];
+                    const items = [];
+                    for (let i = 1; i <= data.stageCount; i++) {
+                        items.push({value: i, text: `第${i}期`});
+                    }
+                    return items;
+                };
+                for (let i = 0; i < tsObj.resultSheet.getRowCount(); i++) {
+                    const cellType2 = new spreadNS.CellTypes.ComboBox().itemHeight(10).editorValueType(spreadNS.CellTypes.EditorValueType.value).items(getItems(tsObj.trArray[i]));
+                    tsObj.resultSheet.getCell(i, 1).cellType(cellType2);
+                }
+            }
+        },
+        _addTender: function (tender) {
+            const tr = tsObj.trArray.find(x => { return x.tid === tender.tid; });
+            const t = {tid: tender.tid, name: tender.name, stageCount: tender.stageCount};
+            if (!tr) tsObj.trArray.push(t);
+            return t;
+        },
+        _removeTender: function (tender) {
+            const gri = tsObj.trArray.findIndex(function (x, i, arr) {
+                return x.tid === tender.tid;
+            });
+            if (gri >= 0) tsObj.trArray.splice(gri, 1);
+        },
+        reloadResultData: function () {
+            SpreadJsObj.reLoadSheetData(tsObj.resultSheet);
+            this._rebuildStageSelect();
+        },
+        tsButtonClicked: function (e, info) {
+            if (!info.sheet.zh_setting) return;
+
+            const col = info.sheet.zh_setting.cols[info.col];
+            if (col.field !== 'selected') return;
+
+            const node = SpreadJsObj.getSelectObject(info.sheet);
+            node.selected = !node.selected;
+            if (node.children && node.children.length > 0) {
+                const posterity = tsObj.tenderSourceTree.getPosterity(node);
+                for (const p of posterity) {
+                    p.selected = node.selected;
+                    if (!p.children || p.children.length === 0){
+                        if (p.selected) {
+                            tsObj._addTender(p);
+                        } else {
+                            tsObj._removeTender(p);
+                        }
+                    }
+                }
+                SpreadJsObj.reLoadRowData(info.sheet, info.row, posterity.length + 1);
+            } else {
+                if (node.selected) {
+                    tsObj._addTender(node);
+                } else {
+                    tsObj._removeTender(node);
+                }
+                SpreadJsObj.reLoadRowData(info.sheet, info.row, 1);
+            }
+            tsObj.reloadResultData();
+        },
+        trEditEnded: function (e, info) {
+            const data = SpreadJsObj.getSelectObject(info.sheet);
+            const col = info.sheet.zh_setting.cols[info.col];
+            data[col.field] = info.sheet.getValue(info.row, info.col);
+        },
+        initTenderSelect: function () {
+            if (this.tenderSpread) return;
+
+            this.tenderSpread = SpreadJsObj.createNewSpread($('#ts-source-spread')[0]);
+            this.tenderSheet = this.tenderSpread.getActiveSheet();
+            SpreadJsObj.initSheet(this.tenderSheet, {
+                cols: [
+                    {title: '选择', field: 'selected', hAlign: 1, width: 40, formatter: '@', cellType: 'checkbox'},
+                    {title: '名称', field: 'name', hAlign: 0, width: 180, formatter: '@', cellType: 'tree'},
+                    {title: '期数', field: 'phase', hAlign: 1, width: 60, formatter: '@'},
+                    {title: '审批状态', field: 'status', hAlign: 1, width: 60, formatter: '@'}
+                ],
+                emptyRows: 0,
+                headRows: 1,
+                headRowHeight: [32],
+                defaultRowHeight: 21,
+                headerFont: '12px 微软雅黑',
+                font: '12px 微软雅黑',
+                headColWidth: [0],
+                selectedBackColor: '#fffacd',
+                readOnly: true,
+            });
+
+            this.resultSpread = SpreadJsObj.createNewSpread($('#ts-result-spread')[0]);
+            this.resultSheet = this.resultSpread.getActiveSheet();
+
+            const resultSpreadSetting = {
+                cols: [],
+                emptyRows: 0,
+                headRows: 1,
+                headRowHeight: [32],
+                defaultRowHeight: 21,
+                headerFont: '12px 微软雅黑',
+                font: '12px 微软雅黑',
+                headColWidth: [],
+            };
+            if (this.setting.type === 'ledger') {
+                resultSpreadSetting.cols.push(
+                    {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 230, formatter: '@', readOnly: true}
+                );
+            } else if (this.setting.type === 'stage') {
+                resultSpreadSetting.cols.push(
+                    {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 180, formatter: '@', readOnly: true},
+                    {title: '可选期', colSpan: '1', rowSpan: '1', field: 'stage', hAlign: 0, width: 60},
+                )
+            }
+            SpreadJsObj.initSheet(this.resultSheet, resultSpreadSetting);
+            this.tenderSpread.bind(spreadNS.Events.ButtonClicked, tsObj.tsButtonClicked);
+            if (this.setting.type === 'stage') {
+                this.resultSpread.bind(spreadNS.Events.EditEnded, tsObj.trEditEnded);
+            }
+            postData('/list/load', {type: tsObj.setting.type, tid: tsObj.select.tender_id, lid: tsObj.select.id}, data => {
+                tsObj.trArray = data.history ? data.history.tenders : [];
+                tsObj.tenderSourceTree = Tender2Tree.convert(data.category, data.tenders, data.ledgerAuditConst, data.stageAuditConst);
+                SpreadJsObj.loadSheetData(tsObj.tenderSheet, SpreadJsObj.DataType.Tree, tsObj.tenderSourceTree);
+                SpreadJsObj.loadSheetData(tsObj.resultSheet, SpreadJsObj.DataType.Data, tsObj.trArray);
+            });
+        }
+    };
+
+    $('#tender-select').on('shown.bs.modal', () => {
+        tsObj.initTenderSelect();
+    });
+
+    const showSelect = function (node) {
+        tsObj.select = node;
+        $('#ts-hint').hide();
+        $('#tender-select').modal('show');
+    };
+
+    return { showSelect }
+};

+ 19 - 0
app/public/js/spreadjs_rela/spreadjs_zh.js

@@ -676,6 +676,13 @@ const SpreadJsObj = {
             }
             sheet.getRange(-1, col, -1, 1).cellType(sheet.extendCellType[cellKey]);
         }
+        if (colSetting.cellType === 'stageCombo') {
+            if (!sheet.extendCellType.stageCombo) {
+                sheet.extendCellType.stageCombo = this.CellType.getStageComboCellType();
+                SpreadJsObj._addActivePaintEvents(sheet, sheet.extendCellType.stageCombo);
+            }
+            sheet.getRange(-1, col, -1, 1).cellType(sheet.extendCellType.stageCombo);
+        }
         if (colSetting.cellType === 'datepicker') {
             if (!sheet.extendCellType.datepicker) {
                 sheet.extendCellType.datepicker = this.CellType.getDatePickerCellType();
@@ -2186,6 +2193,18 @@ const SpreadJsObj = {
             combo.itemHeight(10).editorValueType(spreadNS.CellTypes.EditorValueType.value).items(items);
             return combo;
         },
+        getStageComboCellType: function () {
+            const ComboCellType = function () {};
+            ComboCellType.prototype = new spreadNS.CellTypes.ComboBox();
+            const proto = ComboCellType.prototype;
+            proto.paint = function (ctx, value, x, y, w, h, style, context) {
+                const setting = context.sheet.zh_setting;
+                const col = setting.cols[context.col];
+                const data = SpreadJsObj.getSelectObject(context.sheet);
+                this.itemHeight(10).editorValueType(spreadNS.CellTypes.EditorValueType.value).items(col.getItems(data));
+            };
+            return new ComboCellType();
+        },
         /**
          * 获取 日期选择 CellType
          * @returns {DatePickerCellType}

+ 1 - 0
app/router.js

@@ -108,6 +108,7 @@ module.exports = app => {
      */
     // 金额概况
     app.get('/list', sessionAuth, 'tenderController.listDefault');
+    app.post('/list/load', sessionAuth, 'tenderController.listLoad');
     app.get('/list/info', sessionAuth, 'tenderController.listInfo');
 
     // 计量进度

+ 80 - 0
app/service/sum_load_history.js

@@ -0,0 +1,80 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date 2021/7/20
+ * @version
+ */
+
+module.exports = app => {
+
+    class SumLoadHistory extends app.BaseService {
+
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'sum_load_history';
+        }
+
+        async getHistroy(tid, lid, type) {
+            const his = await this.db.select(this.tableName, {
+                where: { tid, lid, type },
+                orders: [['load_time', 'desc']],
+                limit: 1,
+                offset: 0,
+            });
+            const result = his.length > 0 ? his[0] : null;
+            if (result && result.tenders) result.tenders = JSON.parse(result.tenders);
+            if (result && result.errors) result.errors = JSON.parse(result.errors);
+            return result;
+        }
+
+        async getLedgerHistory(tid, lid) {
+            return await this.getHistroy(tid, lid, 'ledger');
+        }
+
+        async getReviseHistory(tid, lid) {
+            return await this.getHistroy(tid, lid, 'revise');
+        }
+
+        async getStageHistory(tid, lid) {
+            return await this.getHistroy(tid, lid, 'stage');
+        }
+
+        async saveLedgerHistory(tid, lid, tenders, errors) {
+            const data = {
+                tid, lid, type: 'ledger',
+                load_time: new Date(), uid: this.ctx.session.sessionUser.accountId,
+                tenders: JSON.stringify(tenders), errors: errors ? JSON.stringify(errors) : '',
+            };
+            await this.db.insert(this.tableName, data);
+        }
+
+        async saveReviseHistory(tid, rid, lid, tenders, errors) {
+            const data = {
+                tid, lid, type: 'revise', rid,
+                load_time: new Date(), uid: this.ctx.session.sessionUser.accountId,
+                tenders: JSON.stringify(tenders), errors: errors ? JSON.stringify(errors) : '',
+            };
+            await this.db.insert(this.tableName, data);
+        }
+
+        async saveStageHistory(tid, sid, lid, tenders, errors) {
+            const data = {
+                tid, lid, type: 'revise', sid,
+                load_time: new Date(), uid: this.ctx.session.sessionUser.accountId,
+                tenders: JSON.stringify(tenders), errors: errors ? JSON.stringify(errors) : '',
+            };
+            await this.db.insert(this.tableName, data);
+        }
+    }
+
+    return SumLoadHistory;
+};

+ 1 - 0
app/view/ledger/explode_modal.ejs

@@ -404,3 +404,4 @@
 <% include ../shares/check_data_modal.ejs %>
 <% include ../shares/check_modal2.ejs %>
 <% include ../shares/new_tag_modal.ejs %>
+<% include ../shares/tender_select_modal.ejs %>

+ 31 - 0
app/view/shares/tender_select_modal.ejs

@@ -0,0 +1,31 @@
+<div class="modal fade" id="tender-select" data-backdrop="static">
+    <div class="modal-dialog modal-lg" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title" id="tender-select-title">选择标段</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">&times;</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                <div class="row">
+                    <div class="col-6">
+                        <h5>可选标段 </h5>
+                        <div class="modal-height-300" id="ts-source-spread">
+                        </div>
+                    </div>
+                    <div class="col-6">
+                        <h5>已选标段 </h5>
+                        <div class="modal-height-300" id="ts-result-spread">
+                        </div>
+                    </div>
+                    <div class="text-danger text-center ml-3" id="ts-hint">我是提示呀</div>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">取消</button>
+                <button class="btn btn-sm btn-primary" id="tender-select-ok">确定</button>
+            </div>
+        </div>
+    </div>
+</div>

+ 2 - 0
config/web.js

@@ -152,6 +152,8 @@ const JsFiles = {
                     '/public/js/ledger_tree_col.js',
                     '/public/js/std_lib.js',
                     '/public/js/ledger_check.js',
+                    '/public/js/shares/tenders2tree.js',
+                    '/public/js/shares/tender_select.js',
                     '/public/js/ledger.js',
                 ],
                 mergeFile: 'explode',