Explorar el Código

1. 计算模板,导入未分类模板
2. 台账分解,选择计算模板

MaiXinRong hace 7 horas
padre
commit
de11cb8fc4

+ 2 - 0
app/controller/ledger_controller.js

@@ -127,6 +127,7 @@ module.exports = app => {
                 tender.data.hasRevise = !!revise;
                 tender.data.hasRevise = !!revise;
                 const stage = await this.ctx.service.stage.getDataByCondition({ tid: tender.id });
                 const stage = await this.ctx.service.stage.getDataByCondition({ tid: tender.id });
                 tender.data.hasStage = !!stage;
                 tender.data.hasStage = !!stage;
+                const templateFolder = await ctx.service.calcTmplFolder.getData(ctx.session.sessionProject.id + '-' + 'posCalc');
                 const posCalcTemplate = await this.ctx.service.calcTmpl.getAllTemplateDetail(ctx.session.sessionProject.id, 'posCalc');
                 const posCalcTemplate = await this.ctx.service.calcTmpl.getAllTemplateDetail(ctx.session.sessionProject.id, 'posCalc');
                 tender.data.isAssUser = tender.isAssUser;
                 tender.data.isAssUser = tender.isAssUser;
                 tender.data.assLedger = tender.assLedger;
                 tender.data.assLedger = tender.assLedger;
@@ -156,6 +157,7 @@ module.exports = app => {
                     nodeType: stdConst.nodeType,
                     nodeType: stdConst.nodeType,
                     authMobile: pa.auth_mobile,
                     authMobile: pa.auth_mobile,
                     deleteFilePermission: PermissionCheck.delFile(this.ctx.session.sessionUser.permission),
                     deleteFilePermission: PermissionCheck.delFile(this.ctx.session.sessionUser.permission),
+                    templateFolder,
                     posCalcTemplate,
                     posCalcTemplate,
                 };
                 };
                 if ((tender.data.ledger_status !== auditConst.status.checked && ctx.session.sessionUser.is_admin) ||
                 if ((tender.data.ledger_status !== auditConst.status.checked && ctx.session.sessionUser.is_admin) ||

+ 86 - 0
app/public/js/ledger.js

@@ -1789,6 +1789,78 @@ $(document).ready(function() {
         });
         });
     }
     }
 
 
+    const calcTemplateSelect = (function(){
+        let ctrlBills = {}, first = 1;
+        const tree = createNewPathTree('gather', {
+            id: 'tree_id', pid: 'tree_pid', order: 'tree_order',
+            level: 'tree_level', isLeaf: 'tree_is_leaf', fullPath: 'tree_full_path',
+            rootId: -1, calcFields: [], keys: ['id', 'master_id', 'tree_id'],
+        });
+        tree.loadDatas(templateFolder);
+        const templates = createAncillaryGcl({ id: 'id', masterId: 'folder_id', sort: [['create_time', 'desc']] });
+        templates.loadDatas(posCalcTemplate);
+        templates.eachPart(function(masterId, items) {
+            const parent = masterId ? tree.nodes.find(x => { return x.id === masterId; }) : null;
+            for (const i of items) {
+                i.is_calc_template = 1;
+                tree.addNode(i, parent, false);
+            }
+        });
+        tree.sortTreeNode();
+        const spread = SpreadJsObj.createNewSpread($('#sct-spread')[0]);
+        const sheet = spread.getActiveSheet();
+        SpreadJsObj.initSheet(sheet, {
+            cols: [
+                {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 300, formatter: '@', cellType: 'tree'},
+                // {title: '创建人', colSpan: '1', rowSpan: '1', field: 'user_name', hAlign: 0, width: 80, formatter: '@'},
+            ],
+            emptyRows: 0,
+            headRows: 1,
+            headRowHeight: [32],
+            defaultRowHeight: 21,
+            headerFont: '12px 微软雅黑',
+            font: '12px 微软雅黑',
+            readOnly: true,
+            getFont: function (sheet, data, row, col, defaultFont) {
+                return !data.is_calc_template ? defaultFont : 'bold ' + defaultFont;
+            },
+            getColor: function(sheet, data, row, col, defaultColor) {
+                return data && data.id === ctrlBills.calc_template ? spreadColor.common.invalid : defaultColor;
+            }
+        });
+        SpreadJsObj.loadSheetData(sheet, SpreadJsObj.DataType.Tree, tree);
+        const select = function(node) {
+            ctrlBills = node;
+            SpreadJsObj.reloadRowBackColor(sheet, 0, tree.nodes.length);
+            $('#select-calc-template').modal('show');
+        };
+        $('#select-calc-template-ok').click(function() {
+            const ct = SpreadJsObj.getSelectObject(sheet);
+            if (!ct) return;
+            if (!ct.is_calc_template) {
+                toastr.warning('请勿选择文件夹');
+                return;
+            }
+            if (ct.id === ctrlBills.calc_template) {
+                toastr.warning('选择的计算模板与之前相同');
+                return;
+            }
+            const updateData = {postType: 'extra', postData: { id: ctrlBills.id, tender_id: ctrlBills.tender_id, ledger_id: ctrlBills.ledger_id, calc_template: ct.id }};
+            postData(window.location.pathname + '/update', updateData, function (result) {
+                const refreshNode = ledgerTree.loadPostData(result);
+                treeOperationObj.refreshTree(ledgerSheet, refreshNode);
+                posCalcDetail.loadCurDetailData();
+                $('#select-calc-template').modal('hide');
+            });
+        });
+        $('#select-calc-template').on('shown.bs.modal', function() {
+            if (first) {
+                spread.refresh();
+                first = 0;
+            }
+        });
+        return { select }
+    })();
     let batchInsertObj, contractExprObj;
     let batchInsertObj, contractExprObj;
     $.contextMenu.types.batchInsert = function (item, opt, root) {
     $.contextMenu.types.batchInsert = function (item, opt, root) {
         const self = this;
         const self = this;
@@ -1916,6 +1988,20 @@ $(document).ready(function() {
         billsContextMenuOptions.items.sprBase = '----';
         billsContextMenuOptions.items.sprBase = '----';
     }
     }
     if (!readOnly) {
     if (!readOnly) {
+        billsContextMenuOptions.items.selectCalcTmpl = {
+            name: '选择计算模板',
+            callback: function(key, opt) {
+                const node = SpreadJsObj.getSelectObject(ledgerSheet);
+                calcTemplateSelect.select(node);
+            },
+            disabled: function(key, opt) {
+                const node = SpreadJsObj.getSelectObject(ledgerSheet);
+                return !node || !node.b_code;
+            },
+            visible: function(key, opt) {
+                return !readOnly;
+            }
+        };
         billsContextMenuOptions.items.batchInsert = {
         billsContextMenuOptions.items.batchInsert = {
             name: '批量插入',
             name: '批量插入',
             type: 'batchInsert',
             type: 'batchInsert',

+ 33 - 1
app/public/js/path_tree.js

@@ -1761,6 +1761,12 @@ const createNewPathTree = function (type, setting) {
             return this._maxId;
             return this._maxId;
         }
         }
 
 
+        loadDatas(datas){
+            super.loadDatas(datas);
+            const setting = this.setting;
+            this._maxId = datas.length > 0 ? datas.map(x => { return x[setting.id]; }).reduce((a, b) => { return Math.max(a, b)}) : 0;
+        }
+
         addNode(data, parent, checkSame = true) {
         addNode(data, parent, checkSame = true) {
             data[this.setting.pid] = parent ? parent[this.setting.id] : this.setting.rootId;
             data[this.setting.pid] = parent ? parent[this.setting.id] : this.setting.rootId;
             // let item = _.find(this.items, data);
             // let item = _.find(this.items, data);
@@ -1771,7 +1777,7 @@ const createNewPathTree = function (type, setting) {
             item[this.setting.id] = this.newId;
             item[this.setting.id] = this.newId;
             const keyName = itemsPre + item[this.setting.id];
             const keyName = itemsPre + item[this.setting.id];
             item.children = [];
             item.children = [];
-            item.is_leaf = true;
+            item[this.setting.isLeaf] = true;
             item.expanded = true;
             item.expanded = true;
             item.visible = true;
             item.visible = true;
             this.items[keyName] = item;
             this.items[keyName] = item;
@@ -2250,11 +2256,31 @@ const createAncillaryGcl = function (setting) {
             }
             }
         }
         }
 
 
+        _moveDatas(data, resort) {
+            const datas = data instanceof Array ? data : [data];
+            for (const d of datas) {
+                const item = this.getItem(d[this.setting.id]);
+                if (!item) continue;
+
+                const oMasterKey = this.itemPre + item[this.setting.masterId];
+                if (resort.indexOf(oMasterKey) < 0) resort.push(oMasterKey);
+                this.masterIndex[oMasterKey].splice(this.masterIndex[oMasterKey].indexOf(item), 1);
+
+                item[this.setting.masterId] = d[this.setting.masterId];
+
+                const nMasterKey = this.itemPre + item[this.setting.masterId];
+                if (!this.masterIndex[nMasterKey]) this.masterIndex[nMasterKey] = [];
+                this.masterIndex[nMasterKey].push(item);
+                if (resort.indexOf(nMasterKey) < 0) resort.push(nMasterKey);
+            }
+        }
+
         updateDatas(data) {
         updateDatas(data) {
             const resort = [];
             const resort = [];
             if (data.add) this._addDatas(data.add, resort);
             if (data.add) this._addDatas(data.add, resort);
             if (data.del) this._removeDatas(data.del, resort);
             if (data.del) this._removeDatas(data.del, resort);
             if (data.update) this._updateDatas(data.update, resort);
             if (data.update) this._updateDatas(data.update, resort);
+            if (data.move) this._moveDatas(data.move, resort);
             for (const s of resort) {
             for (const s of resort) {
                 this.resortPart(this.masterIndex[s]);
                 this.resortPart(this.masterIndex[s]);
                 this.filterPart(this.masterIndex[s]);
                 this.filterPart(this.masterIndex[s]);
@@ -2299,6 +2325,12 @@ const createAncillaryGcl = function (setting) {
                 this.filterPart(this.masterIndex[key]);
                 this.filterPart(this.masterIndex[key]);
             }
             }
         }
         }
+
+        eachPart(fun) {
+            for (const prop in this.masterIndex) {
+                fun(prop.substring(3, prop.length), this.masterIndex[prop]);
+            }
+        }
     }
     }
 
 
     return new AncillaryGcl(setting);
     return new AncillaryGcl(setting);

+ 40 - 0
app/public/js/pos_calc_tmpl.js

@@ -373,6 +373,13 @@ $(document).ready(() => {
                 });
                 });
             }
             }
         }
         }
+        moveTemplate(templateIds, target, fun) {
+            postData('save', {move: templateIds, folder_id: target.id, type: 'posCalc'}, function(result) {
+                templateObj.data.updateDatas(result);
+                templateObj.refreshSheet();
+                fun();
+            });
+        }
         async loadTemplateDetail(template) {
         async loadTemplateDetail(template) {
             const result = await postDataAsync('load', {filter: 'detail', id: template.id, type: 'posCalc'});
             const result = await postDataAsync('load', {filter: 'detail', id: template.id, type: 'posCalc'});
             if (result && result.detail) {
             if (result && result.detail) {
@@ -752,4 +759,37 @@ $(document).ready(() => {
     $('#import').click(function() {
     $('#import').click(function() {
         detailObj.import();
         detailObj.import();
     });
     });
+
+    $('#rela-no-folder').on('show.bs.modal', function() {
+        const html = [];
+        templateObj.data.eachPart(function(masterId, array) {
+            if (masterId && folderObj.tree.nodes.find(x => { return x.id === masterId; })) return;
+            for (const a of array) {
+                html.push('<tr>');
+                html.push(`<td class="text-center"><input type="checkbox" tmplid="${a.id}" ${(a.create_user_id === userID || !readOnly ? '' : 'readOnly')}></td>`);
+                html.push(`<td>${a.name}</td>`);
+                html.push(`<td class="text-center">${a.user_name}</td>`);
+                html.push('<tr/>');
+            }
+        });
+        $('#no-folder-list').html(html.join(''));
+    });
+    $('#rela-no-folder-ok').click(function() {
+        const node = SpreadJsObj.getSelectObject(folderObj.sheet);
+        if (!node) {
+            toastr.warning('请创建或选择模板分类');
+            return;
+        }
+        const templateIds = [];
+        for (const c of $('input[tmplid]:checked')) {
+            templateIds.push(c.getAttribute('tmplId'));
+        }
+        if (!templateIds) {
+            toastr.warning('请选择模板');
+            return;
+        }
+        templateObj.moveTemplate(templateIds, node, function() {
+            $('#rela-no-folder').modal('hide');
+        });
+    })
 });
 });

+ 10 - 1
app/service/calc_tmpl.js

@@ -135,7 +135,7 @@ module.exports = app => {
             // });
             // });
             const sql = 'SELECT ct.id, ct.pid, ct.folder_id, ct.name, ct.create_user_id, ct.is_locked, pa.name AS user_name' +
             const sql = 'SELECT ct.id, ct.pid, ct.folder_id, ct.name, ct.create_user_id, ct.is_locked, pa.name AS user_name' +
                         `    FROM ${this.tableName} ct LEFT JOIN ${this.ctx.service.projectAccount.tableName} pa ON ct.create_user_id = pa.id WHERE ct.pid = ? and ct.type = ? ORDER BY ct.create_time ${sort}`;
                         `    FROM ${this.tableName} ct LEFT JOIN ${this.ctx.service.projectAccount.tableName} pa ON ct.create_user_id = pa.id WHERE ct.pid = ? and ct.type = ? ORDER BY ct.create_time ${sort}`;
-            return this.db.query(sql, [pid, type])
+            return this.db.query(sql, [pid, type]);
         }
         }
         async analysisTemplate(data) {
         async analysisTemplate(data) {
             const datas = data instanceof Array ? data : [data];
             const datas = data instanceof Array ? data : [data];
@@ -489,11 +489,20 @@ module.exports = app => {
             await this.db.delete(this.tableName, { id });
             await this.db.delete(this.tableName, { id });
             return template;
             return template;
         }
         }
+        async _moveTemplate(id, folder_id) {
+            const org = await this.getAllDataByCondition({ where: { id }});
+            if (org.length !== id.length) throw '选择的模板不存在,请刷新后重试';
+
+            const updateData = id.map(x => { return { id: x, folder_id }});
+            await this.db.updateRows(this.tableName, updateData);
+            return updateData;
+        }
         async saveTemplate(data) {
         async saveTemplate(data) {
             const result = {};
             const result = {};
             if (data.add) result.add = await this._addTemplate(data.add.name, data.type, data.add.folder_id);
             if (data.add) result.add = await this._addTemplate(data.add.name, data.type, data.add.folder_id);
             if (data.del) result.del = await this._delTemplate(data.del);
             if (data.del) result.del = await this._delTemplate(data.del);
             if (data.update) result.update = await this._saveTemplate(data.update.id, data.update);
             if (data.update) result.update = await this._saveTemplate(data.update.id, data.update);
+            if (data.move) result.move = await this._moveTemplate(data.move, data.folder_id);
             return result;
             return result;
         }
         }
         async reCalcTemplate(id, force) {
         async reCalcTemplate(id, force) {

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

@@ -433,6 +433,7 @@
     });
     });
     const syncLedgerUrl = '<%- syncLedgerUrl %>';
     const syncLedgerUrl = '<%- syncLedgerUrl %>';
     const nodeType = JSON.parse('<%- JSON.stringify(nodeType) %>');
     const nodeType = JSON.parse('<%- JSON.stringify(nodeType) %>');
+    const templateFolder = JSON.parse(unescape('<%- escape(JSON.stringify(templateFolder)) %>'));
     const posCalcTemplate = JSON.parse(unescape('<%- escape(JSON.stringify(posCalcTemplate)) %>'));
     const posCalcTemplate = JSON.parse(unescape('<%- escape(JSON.stringify(posCalcTemplate)) %>'));
 </script>
 </script>
 <% if ((tender.ledger_status !== auditConst.status.checked && ctx.session.sessionUser.is_admin) || ((tender.ledger_status === auditConst.status.uncheck || tender.ledger_status === auditConst.status.checkNo) && ctx.session.sessionUser.accountId === tender.user_id)) { %>
 <% if ((tender.ledger_status !== auditConst.status.checked && ctx.session.sessionUser.is_admin) || ((tender.ledger_status === auditConst.status.uncheck || tender.ledger_status === auditConst.status.checkNo) && ctx.session.sessionUser.accountId === tender.user_id)) { %>

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

@@ -119,6 +119,24 @@
         </div>
         </div>
     </div>
     </div>
 </div>
 </div>
+<div class="modal fade" id="select-calc-template" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <div class="d-flex">
+                    <h5 class="modal-title">选择计算模板</h5>
+                </div>
+            </div>
+            <div class="modal-body">
+                <div id="sct-spread" class="modal-height-500"></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="select-calc-template-ok">确定</button>
+            </div>
+        </div>
+    </div>
+</div>
 <!--批量添加清单部位-->
 <!--批量添加清单部位-->
 <div class="modal fade" id="batch" data-backdrop="static">
 <div class="modal fade" id="batch" data-backdrop="static">
     <div class="modal-dialog modal-xl" role="document">
     <div class="modal-dialog modal-xl" role="document">

+ 1 - 1
app/view/template/pos_calc.ejs

@@ -46,7 +46,7 @@
                                     <li class="nav-item mt-1" id="template-ctrl">
                                     <li class="nav-item mt-1" id="template-ctrl">
                                         <a href="javascript: void(0);" name="template-opr" type="add" class="btn btn-sm btn-light text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="新增"><i class="fa fa-plus" aria-hidden="true"></i></a>
                                         <a href="javascript: void(0);" name="template-opr" type="add" class="btn btn-sm btn-light text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="新增"><i class="fa fa-plus" aria-hidden="true"></i></a>
                                         <a href="javascript: void(0);" name="template-opr" type="delete" class="btn btn-sm btn-light text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="删除"><i class="fa fa-remove" aria-hidden="true"></i></a>
                                         <a href="javascript: void(0);" name="template-opr" type="delete" class="btn btn-sm btn-light text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="删除"><i class="fa fa-remove" aria-hidden="true"></i></a>
-                                        <button class="btn btn-sm btn-light text-primary" id="importTemplateNoFolder"> 导入未分类模板</button>
+                                        <button class="btn btn-sm btn-light text-primary" href="#rela-no-folder" data-toggle="modal" data-target="#rela-no-folder"> 导入未分类模板</button>
                                     </li>
                                     </li>
                                 </ul>
                                 </ul>
                             </div>
                             </div>

+ 26 - 1
app/view/template/pos_calc_modal.ejs

@@ -1,3 +1,28 @@
 <% include ./preview_modal.ejs %>
 <% include ./preview_modal.ejs %>
 <% include ../shares/import_file_modal.ejs %>
 <% include ../shares/import_file_modal.ejs %>
-<% include ../shares/delete_hint_modal.ejs %>
+<% include ../shares/delete_hint_modal.ejs %>
+<div class="modal fade" id="rela-no-folder" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <div class="d-flex">
+                    <h5 class="modal-title">导入未分类模板</h5>
+                </div>
+            </div>
+            <div class="modal-body">
+                <table class="table table-bordered">
+                    <tr><th>选择</th><th>模板名称</th><th>创建人</th></tr>
+                    <tbody id="no-folder-list">
+                    </tbody>
+                </table>
+                <div>
+                    <div class="alert alert-info p-1 mt-2">仅可导入本人创建的模板</div>
+                </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="rela-no-folder-ok">确定</button>
+            </div>
+        </div>
+    </div>
+</div>