Explorar o código

Merge branch 'dev' of http://192.168.1.41:3000/maixinrong/Calculation into dev

Tony Kang hai 3 meses
pai
achega
043183456b

+ 1 - 1
app/controller/login_controller.js

@@ -179,7 +179,7 @@ module.exports = app => {
 
                 // 查找项目数据
                 const projectData = await this.ctx.service.project.getProjectByCode(ctx.request.body.project.toString().trim());
-                const subProject = await ctx.service.subProject.getAllDataByCondition({ where: {project_id: projectData.id}});
+                let subProject = await ctx.service.subProject.getSubProject(projectData.id, ctx.session.sessionUser.accountId, ctx.session.sessionUser.is_admin, true);
                 if (result === 2) {
                     // 判断是否有设置停用提示,有则展示
                     const msg = await ctx.service.projectStopmsg.getMsg(projectData.id);

+ 0 - 17
app/controller/project_controller.js

@@ -152,23 +152,6 @@ module.exports = app => {
 
             ctx.body = responseData;
         }
-
-        /**
-         * 保存列设置
-         * @param ctx
-         * @returns {Promise<void>}
-         */
-        async colSet(ctx) {
-            try {
-                const colType = ctx.request.body.col_type;
-                const colSet = JSON.parse(ctx.request.body.col_set);
-                await ctx.service.projectColSet.setProjectColSet(ctx.session.sessionProject.id, colType, colSet);
-                ctx.redirect(ctx.request.header.referer);
-            } catch (err) {
-                ctx.redirect(ctx.request.header.referer);
-            }
-
-        }
     }
 
     return ProjectController;

+ 19 - 0
app/controller/sub_proj_controller.js

@@ -328,6 +328,8 @@ module.exports = app => {
                     case 'update':
                         responseData.data = await this.ctx.service.subProjProgress.updateInfos(ctx.subProject.id, data.postData);
                         break;
+                    case 'add-std':
+                        responseData.data = await this.ctx.service.subProjProgress.addStdNode(ctx.subProject, data.postData.id, data.postData.stdData);
                         break;
                     default:
                         throw '未知操作';
@@ -430,6 +432,23 @@ module.exports = app => {
             ctx.controllerName = ctx.params.block;
             await this.layout('sub_proj/no_permission.ejs');
         }
+
+
+        /**
+         * 保存列设置
+         * @param ctx
+         * @returns {Promise<void>}
+         */
+        async colSet(ctx) {
+            try {
+                const colType = ctx.request.body.col_type;
+                const colSet = JSON.parse(ctx.request.body.col_set);
+                await ctx.service.projectColSet.setProjectColSet(ctx.subProject.project_id, ctx.subProject.id, colType, colSet);
+                ctx.redirect(ctx.request.header.referer);
+            } catch (err) {
+                ctx.redirect(ctx.request.header.referer);
+            }
+        }
     }
 
     return SubProjController;

+ 2 - 2
app/controller/tender_controller.js

@@ -204,7 +204,7 @@ module.exports = app => {
          */
         async listInfo(ctx) {
             this.jsFiles = this.app.jsFiles.tender.info;
-            const projectColSet = await ctx.service.projectColSet.getProjectColSet(ctx.session.sessionProject.id);
+            const projectColSet = await ctx.service.projectColSet.getProjectColSet(ctx.subProject.project_id, ctx.subProject.id);
             this.colSet = ctx.service.projectColSet.analysisColSetWithDefine(projectSetting.colSet.info, projectColSet.info);
             await this._listDetailCache('tender/info.ejs', 'tender/modal.ejs');
         }
@@ -256,7 +256,7 @@ module.exports = app => {
 
         async listInfoFinish(ctx) {
             this.jsFiles = this.app.jsFiles.tender.info;
-            const projectColSet = await ctx.service.projectColSet.getProjectColSet(ctx.session.sessionProject.id);
+            const projectColSet = await ctx.service.projectColSet.getProjectColSet(ctx.subProject.project_id, ctx.subProject.id);
             this.colSet = ctx.service.projectColSet.analysisColSetWithDefine(projectSetting.colSet.info, projectColSet.info);
             await this._listDetailFinish('tender/info.ejs', 'tender/modal.ejs');
         }

+ 17 - 0
app/public/js/sp_progress.js

@@ -558,6 +558,23 @@ $(document).ready(() => {
                             },
                         },
                         page: 'sp_progress',
+                        cellDoubleClick: function(updateData, stdNode, stdTree) {
+                            if (!stdNode) return;
+                            const mainTree = progressObj.tree;
+                            const mainNode = SpreadJsObj.getSelectObject(progressObj.sheet);
+                            if (!mainNode) return;
+
+                            updateData.postData.id = mainTree.getNodeKey(mainNode);
+                            postData(window.location.pathname + '/update', updateData, function (result) {
+                                const refreshData = mainTree.loadPostData(result);
+                                progressObj.refreshTree(refreshData);
+                                const sel = progressObj.sheet.getSelections()[0];
+                                if (sel) {
+                                    progressObj.sheet.setSelection(mainTree.nodes.indexOf(refreshData.create[0]), sel.col, sel.rowCount, sel.colCount);
+                                }
+                                progressObj.refreshOperationValid();
+                            });
+                        },
                     });
                 }
                 fileReference.spread.refresh();

+ 0 - 212
app/public/js/sub_project.js

@@ -62,7 +62,6 @@ $(document).ready(function() {
                     html.push('<button class="btn btn-outline-primary btn-sm ml-1" name="up"><i class="fa fa-arrow-up"></i></button>');
                     html.push('<button class="btn btn-outline-primary btn-sm ml-1" name="down"><i class="fa fa-arrow-down"></i></button>');
                     html.push('<button class="btn btn-outline-primary btn-sm ml-1" name="top">顶层</button>');
-                    if (!node.is_folder) html.push('<button class="btn btn-outline-primary btn-sm ml-1" name="member">成员管理</button>');
                 }
                 html.push('</td>');
                 return html.join('');
@@ -404,215 +403,4 @@ $(document).ready(function() {
             $('#sm-management').attr('tree_id', '');
         });
     });
-
-    let timer = null;
-    let oldSearchVal = null;
-    $('#member-search').bind('input propertychange', function(e) {
-        oldSearchVal = e.target.value;
-        timer && clearTimeout(timer);
-        timer = setTimeout(() => {
-            const newVal = $('#member-search').val();
-            let html = '';
-            if (newVal && newVal === oldSearchVal) {
-                accountList
-                    .filter(item => item && (item.name.indexOf(newVal) !== -1 || (item.mobile && item.mobile.indexOf(newVal) !== -1)))
-                    .forEach(item => {
-                        html += `<dd class="border-bottom p-2 mb-0 " data-id="${item.id}" >
-                        <p class="mb-0 d-flex"><span class="text-primary">${item.name}</span><span
-                                class="ml-auto">${item.mobile || ''}</span></p>
-                        <span class="text-muted">${item.role || ''}</span></dd>`
-                    });
-                $('.book-list').empty();
-                $('.book-list').append(html);
-            } else {
-                if (!$('.acc-btn').length) {
-                    accountGroup.forEach((group, idx) => {
-                        if (!group) return;
-                        html += `<dt><a href="javascript: void(0);" class="acc-btn" data-groupid="${idx}" data-type="hide"><i class="fa fa-plus-square"></i>
-                        </a> ${group.groupName}</dt>
-                        <div class="dd-content" data-toggleid="${idx}">`;
-                        group.groupList.forEach(item => {
-                            html += `<dd class="border-bottom p-2 mb-0 " data-id="${item.id}" >
-                                    <p class="mb-0 d-flex"><span class="text-primary">${item.name}</span><span
-                                            class="ml-auto">${item.mobile || ''}</span></p>
-                                    <span class="text-muted">${item.role || ''}</span>
-                                </dd>`
-                        });
-                        html += '</div>';
-                    });
-                    $('.book-list').empty();
-                    $('.book-list').append(html);
-                }
-            }
-        }, 400);
-    });
-    $('.book-list').on('click', 'dt', function () {
-        const idx = $(this).find('.acc-btn').attr('data-groupid')
-        const type = $(this).find('.acc-btn').attr('data-type')
-        if (type === 'hide') {
-            $(this).parent().find(`div[data-toggleid="${idx}"]`).show(() => {
-                $(this).children().find('i').removeClass('fa-plus-square').addClass('fa-minus-square-o')
-                $(this).find('.acc-btn').attr('data-type', 'show')
-
-            })
-        } else {
-            $(this).parent().find(`div[data-toggleid="${idx}"]`).hide(() => {
-                $(this).children().find('i').removeClass('fa-minus-square-o').addClass('fa-plus-square')
-                $(this).find('.acc-btn').attr('data-type', 'hide')
-            })
-        }
-        return false
-    });
-    let orgMembers, newMembers;
-    const generateMemberHtml = function () {
-        const html = [];
-        for (const mem of newMembers) {
-            html.push(`<tr uid="${mem.uid}">`);
-            html.push(`<td>${mem.name}</td>`);
-            html.push(`<td>${mem.role}</td>`);
-            // 动态投资
-            const viewBudget = mem.budget_permission.indexOf(permissionConst.budget.view.value) >= 0;
-            html.push(`<td><div class="custom-control custom-checkbox mb-2">
-                        <input type="checkbox" ptype="budget" sptype="view" uid="${mem.uid}" id="budgetview${mem.uid}" class="custom-control-input" ${(viewBudget ? 'checked' : '')}>
-                        <label class="custom-control-label" for="budgetview${mem.uid}"></label></div></td>`);
-            const editBudget = mem.budget_permission.indexOf(permissionConst.budget.edit.value) >= 0;
-            html.push(`<td><div class="custom-control custom-checkbox mb-2">
-                        <input type="checkbox" ptype="budget" sptype="edit" id="budgetedit${mem.uid}" uid="${mem.uid}" class="custom-control-input" ${(editBudget ? 'checked' : '')}>
-                        <label class="custom-control-label" for="budgetedit${mem.uid}"></label></div></td>`);
-            // 电子文档
-
-            const fileView = mem.file_permission.indexOf(permissionConst.file.view.value) >= 0;
-            html.push(`<td><div class="custom-control custom-checkbox mb-2">
-                        <input type="checkbox" ptype="file" sptype="view" uid="${mem.uid}" id="fileview${mem.uid}" class="custom-control-input" ${(fileView ? 'checked' : '')}>
-                        <label class="custom-control-label" for="fileview${mem.uid}"></label></div></td>`);
-            const fileUpload = mem.file_permission.indexOf(permissionConst.file.upload.value) >= 0;
-            html.push(`<td><div class="custom-control custom-checkbox mb-2">
-                        <input type="checkbox" ptype="file" sptype="upload" id="fileupload${mem.uid}" uid="${mem.uid}" class="custom-control-input" ${(fileUpload ? 'checked' : '')}>
-                        <label class="custom-control-label" for="fileupload${mem.uid}"></label></div></td>`);
-            const fileDelete = mem.file_permission.indexOf(permissionConst.file.delete.value) >= 0;
-            html.push(`<td><div class="custom-control custom-checkbox mb-2">
-                        <input type="checkbox" ptype="file" sptype="delete" id="filedelete${mem.uid}" uid="${mem.uid}" class="custom-control-input" ${(fileDelete ? 'checked' : '')}>
-                        <label class="custom-control-label" for="filedelete${mem.uid}"></label></div></td>`);
-            const fileEdit = mem.file_permission.indexOf(permissionConst.file.filing.value) >= 0;
-            html.push(`<td><div class="custom-control custom-checkbox mb-2">
-                        <input type="checkbox" ptype="file" sptype="filing" uid="${mem.uid}" id="fileedit${mem.uid}" class="custom-control-input" ${(fileEdit ? 'checked' : '')}>
-                        <label class="custom-control-label" for="fileedit${mem.uid}"></label></div></td>`);
-            // 关联标段
-            const rela = mem.manage_permission.indexOf(permissionConst.manage.rela.value) >= 0;
-            html.push(`<td><div class="custom-control custom-checkbox mb-2">
-                        <input type="checkbox" ptype="manage" sptype="rela" id="rela${mem.uid}" uid="${mem.uid}" class="custom-control-input" ${(rela ? 'checked' : '')}>
-                        <label class="custom-control-label" for="rela${mem.uid}"></label></div></td>`);
-            html.push(`<td><a href="javascript: void(0);" class="btn btn-outline-danger btn-sm ml-1" name="del-member" uid="${mem.uid}">移除</a></td>`);
-            html.push('</tr>');
-        }
-        $('#member-list').html(html.join(''));
-    };
-    $('[data-target="#member"]').click(function(){
-        const tr = this.parentNode.parentNode;
-        curBudget.id = tr.getAttribute('tree_id');
-        curBudget.bid = tr.getAttribute('bid');
-        curBudget.name = tr.getAttribute('bname');
-        curBudget.rela_tender = tr.getAttribute('rela-tender');
-
-    });
-
-    $('body').on('click', 'button[name=member]', function(e) {
-        const treeId = $(this).parent().parent().attr('tree_id');
-        const node = projectTreeObj.ProjectTree.getItems(treeId);
-        if (node.is_folder) return;
-        $('#member-ok').attr('tree_id', treeId);
-        postData('/subproj/member', { id: treeId }, function (result) {
-            orgMembers = result;
-            newMembers = result;
-            generateMemberHtml();
-            $('#member').modal('show');
-        });
-    });
-    $('dl').on('click', 'dd', function () {
-        const auditorId = parseInt($(this).data('id'));
-        const user = accountList.find(x => { return x.id === auditorId; });
-        const check = $(`tr[uid=${auditorId}]`, '#member-list');
-        if (check.length > 0) {
-            toastr.error('请勿重复添加成员');
-            return;
-        }
-        newMembers.push({
-            uid: user.id,
-            name: user.name,
-            role: user.role,
-            budget_permission: [],
-            file_permission: [],
-            manage_permission: [],
-        });
-        generateMemberHtml();
-    });
-    $('#member').on('click', 'a[name="del-member"]', function () {
-        const id = parseInt(this.getAttribute('uid'));
-        newMembers.splice(newMembers.findIndex(x => { return x.uid === id}), 1);
-        generateMemberHtml();
-    });
-    $('#member-list').on('click', 'input', function () {
-        const id = parseInt(this.getAttribute('uid'));
-        const mem = newMembers.find(x => { return x.uid === id});
-        const pType = this.getAttribute('ptype'), spType = this.getAttribute('sptype');
-        if (this.checked) {
-            if (pType === 'budget' && spType === 'view') {
-                mem.budget_permission.push(parseInt(permissionConst.budget.view.value));
-            } else if (pType === 'budget' && spType === 'edit') {
-                mem.budget_permission.push(parseInt(permissionConst.budget.edit.value));
-                if (mem.budget_permission.indexOf(permissionConst.budget.view.value) < 0) {
-                    mem.budget_permission.push(parseInt(permissionConst.budget.view.value));
-                    $(`#budgetview${id}`)[0].checked = true;
-                }
-            } else if (pType === 'file' && spType === 'view') {
-                mem.file_permission.push(parseInt(permissionConst.file.view.value));
-            } else if (pType === 'file' && spType === 'upload') {
-                mem.file_permission.push(parseInt(permissionConst.file.upload.value));
-                if (mem.file_permission.indexOf(permissionConst.file.view.value) < 0) {
-                    mem.file_permission.push(parseInt(permissionConst.file.view.value));
-                    $(`#fileview${id}`)[0].checked = true;
-                }
-            } else if (pType === 'file' && spType === 'delete') {
-                mem.file_permission.push(parseInt(permissionConst.file.delete.value));
-                if (mem.file_permission.indexOf(permissionConst.file.view.value) < 0) {
-                    mem.file_permission.push(parseInt(permissionConst.file.view.value));
-                    $(`#fileview${id}`)[0].checked = true;
-                }
-            } else if (pType === 'file' && spType === 'filing') {
-                mem.file_permission.push(parseInt(permissionConst.file.filing.value));
-                if (mem.file_permission.indexOf(permissionConst.file.view.value) < 0) {
-                    mem.file_permission.push(parseInt(permissionConst.file.view.value));
-                    $(`#fileview${id}`)[0].checked = true;
-                }
-            } else if (pType === 'manage' && spType === 'rela') {
-                mem.manage_permission.push(parseInt(permissionConst.manage.rela.value));
-            }
-        } else {
-            if (pType === 'budget' && spType === 'view') {
-                mem.budget_permission = [];
-                $(`#budgetedit${id}`)[0].checked = false;
-            } else if (pType === 'budget' && spType === 'edit') {
-                mem.budget_permission.splice(mem.budget_permission.indexOf(permissionConst.budget.edit.value), 1);
-            } else if (pType === 'file' && spType === 'view') {
-                mem.file_permission = [];
-                $(`#fileupload${id}`)[0].checked = false;
-                $(`#fileedit${id}`)[0].checked = false;
-                $(`#filedelete${id}`)[0].checked = false;
-            } else if (pType === 'file' && spType === 'upload') {
-                mem.file_permission.splice(mem.file_permission.indexOf(permissionConst.file.upload.value), 1);
-            } else if (pType === 'file' && spType === 'delete') {
-                mem.file_permission.splice(mem.file_permission.indexOf(permissionConst.file.delete.value), 1);
-            } else if (pType === 'file' && spType === 'filing') {
-                mem.file_permission.splice(mem.file_permission.indexOf(permissionConst.file.filing.value), 1);
-            } else if (pType === 'manage' && spType === 'rela') {
-                mem.manage_permission = [];
-            }
-        }
-    });
-    $('#member-ok').click(function(){
-        const id = this.getAttribute('tree_id');
-        postData('/subproj/memberSave', {id, member: newMembers}, function () {
-            $('#member').modal('hide');
-        })
-    });
 });

+ 1 - 1
app/router.js

@@ -266,7 +266,7 @@ module.exports = app => {
     app.post('/sp/:id/list/load2', sessionAuth, subProjectCheck, 'tenderController.listLoad2');
     app.get('/sp/:id/list/info', sessionAuth, subProjectCheck, 'tenderController.listInfo');
     app.get('/sp/:id/list/info/finish', sessionAuth, subProjectCheck, 'tenderController.listInfoFinish');
-    app.post('/sp/:id/list/info/col-set', sessionAuth, projectManagerCheck, subProjectCheck, 'projectController.colSet');
+    app.post('/sp/:id/list/info/col-set', sessionAuth, projectManagerCheck, subProjectCheck, 'subProjController.colSet');
     // 计量进度
     app.get('/sp/:id/list/progress', sessionAuth, subProjectCheck, 'tenderController.listProgress');
     // 管理标段

+ 12 - 11
app/service/project_col_set.js

@@ -31,30 +31,31 @@ module.exports = app => {
             JsonFields.forEach(jf => { if(data[jf]) data[jf] = JSON.parse(data[jf]); });
         }
 
-        async loadProjectColSet(id) {
-            const result = await this.getDataById(id);
+        async loadProjectColSet(pid, spid) {
+            const result = await this.getDataByCondition({ pid, spid });
             this._analysisData(result);
             return result;
         }
 
-        async initProjectColSet(id) {
+        async initProjectColSet(pid, spid) {
             const data = JSON.parse(JSON.stringify(ProjectSetting.defaultColSet));
             JsonFields.forEach(jf => { if(data[jf]) data[jf] = JSON.stringify(data[jf]); });
-            data.id = id;
+            data.pid = pid;
+            data.spid = spid;
             await this.db.insert(this.tableName, data);
         }
 
-        async getProjectColSet(id) {
-            const curSet = await this.loadProjectColSet(id);
+        async getProjectColSet(pid, spid) {
+            const curSet = await this.loadProjectColSet(pid, spid);
             if (curSet) return curSet;
-            await this.initProjectColSet(id);
-            return await this.loadProjectColSet(id);
+            await this.initProjectColSet(pid, spid);
+            return await this.loadProjectColSet(pid, spid);
         }
 
-        async setProjectColSet(id, colSetType, colSet) {
-            const data = {id};
+        async setProjectColSet(pid, spid, colSetType, colSet) {
+            const data = {};
             data[colSetType] = JSON.stringify(colSet);
-            await this.defaultUpdate(data);
+            await this.defaultUpdate(data, { where: { pid, spid } });
         }
 
         analysisColSetWithDefine(colSetDefine, colSet) {

+ 120 - 0
app/service/sub_proj_progress.js

@@ -14,6 +14,7 @@ const defaultData = [
     { code: '2', name: '实施阶段', tree_id: 2, tree_pid: -1, tree_level: 1, tree_order: 2, tree_full_path: '2', tree_is_leaf: 1 },
     { code: '3', name: '竣(交)工阶段', tree_id: 3, tree_pid: -1, tree_level: 1, tree_order: 3, tree_full_path: '3', tree_is_leaf: 1 },
 ];
+const billsUtils = require('../lib/bills_utils');
 
 module.exports = app => {
     class SubProjProgress extends app.BaseTreeService {
@@ -91,6 +92,125 @@ module.exports = app => {
             return result;
         }
 
+        async addStdNode(subProj, targetId, stdData) {
+            const findPreData = function(list, a) {
+                if (!list || list.length === 0) { return null; }
+                for (let i = 0, iLen = list.length; i < iLen; i++) {
+                    if (billsUtils.compareCode(list[i].code, a.code) > 0) {
+                        return i > 0 ? list[i - 1] : null;
+                    }
+                }
+                return list[list.length - 1];
+            };
+            let parent = await this.getDataByKid(subProj.id, targetId);
+            if (targetId && !parent) throw '新增节点数据错误,请刷新页面重试';
+            const orgParentId = parent.id;
+            let children = await this.getChildrenByParentId(subProj.id, targetId);
+            const updateParent = children.length === 0;
+
+            const insertData = [];
+            const maxId = await this._getMaxLid(subProj.id);
+            this.transaction = await this.db.beginTransaction();
+            try {
+                if (updateParent) {
+                    const updateData = { id: parent.id };
+                    updateData[this.setting.isLeaf] = false;
+                    this.clearParentingData(updateData);
+                    await this.transaction.update(this.tableName, updateData);
+                }
+                // 从最顶层节点依次查询是否存在,否则添加
+                const addStdData = stdData[stdData.length - 1];
+                const newData = { code: addStdData.code, name: addStdData.name };
+                newData[this.setting.kid] = maxId + 1;
+                newData[this.setting.pid] = parent ? parent[this.setting.kid] : this.rootId;
+                newData[this.setting.level] = parent ? parent[this.setting.level] + 1 : 1;
+                newData[this.setting.fullPath] = parent ? `${parent[this.setting.fullPath]}-${newData[this.setting.kid]}` : `${newData[this.setting.kid]}`;
+                const pre = findPreData(children, newData);
+                newData[this.setting.order] = pre ? pre[this.setting.order] + 1 : 1;
+                if (!pre || children.indexOf(pre) < children.length - 1) {
+                    await this._updateChildrenOrder(subProj.id, parent ? parent[this.setting.kid] : this.rootId, pre ? pre[this.setting.order] + 1 : 1);
+                }
+                newData[this.setting.isLeaf] = 1;
+                this._getDefaultData(newData, subProj.id);
+                insertData.push(newData);
+                await this.transaction.insert(this.tableName, insertData);
+                await this.transaction.commit();
+            } catch (err) {
+                await this.transaction.rollback();
+                throw err;
+            }
+            this._cacheMaxLid(subProj.id, maxId + stdData.length);
+
+            // 查询应返回的结果
+            const createData = await this.getDataByFullPath(subProj.id, insertData[0][this.setting.fullPath] + '%');
+            const updateData = await this.getNextsData(subProj.id, targetId, insertData[0][this.setting.order]);
+            if (updateParent) {
+                updateData.push(await this.getDataByKid(subProj.id, targetId));
+            }
+            return { create: createData, update: updateData };
+        }
+
+        async addStdNodeWithParent(subProj, targetId, stdData) {
+            const findPreData = function(list, a) {
+                if (!list || list.length === 0) { return null; }
+                for (let i = 0, iLen = list.length; i < iLen; i++) {
+                    if (billsUtils.compareCode(list[i].code, a.code) > 0) {
+                        return i > 0 ? list[i - 1] : null;
+                    }
+                }
+                return list[list.length - 1];
+            };
+            let parent = await this.getDataByKid(subProj.id, targetId);
+            if (targetId && !parent) throw '新增节点数据错误,请刷新页面重试';
+            const orgParentId = parent.id;
+            let children = await this.getChildrenByParentId(subProj.id, targetId);
+            const updateParent = children.length === 0;
+
+            const insertData = [];
+            const maxId = await this._getMaxLid(subProj.id);
+            this.transaction = await this.db.beginTransaction();
+            try {
+                if (updateParent) {
+                    const updateData = { id: parent.id };
+                    updateData[this.setting.isLeaf] = false;
+                    this.clearParentingData(updateData);
+                    await this.transaction.update(this.tableName, updateData);
+                }
+                // 从最顶层节点依次查询是否存在,否则添加
+                for (let i = 0, len = stdData.length; i < len; i++) {
+                    const newData = { code: stdData[i].code, name: stdData[i].name };
+                    newData[this.setting.kid] = maxId + i + 1;
+                    newData[this.setting.pid] = parent ? parent[this.setting.kid] : this.rootId;
+                    newData[this.setting.level] = parent ? parent[this.setting.level] + 1 : 1;
+                    newData[this.setting.fullPath] = parent ? `${parent[this.setting.fullPath]}-${newData[this.setting.kid]}` : `${newData[this.setting.kid]}`;
+                    const pre = findPreData(children, newData);
+                    newData[this.setting.order] = pre ? pre[this.setting.order] + 1 : 1;
+                    if (!pre || children.indexOf(pre) < children.length - 1) {
+                        await this._updateChildrenOrder(subProj.id, parent ? parent[this.setting.kid] : this.rootId, pre ? pre[this.setting.order] + 1 : 1);
+                    }
+                    newData[this.setting.isLeaf] = (i === len - 1);
+                    this._getDefaultData(newData, subProj.id);
+                    insertData.push(newData);
+                    parent = newData;
+                    children = [];
+                }
+                await this.transaction.insert(this.tableName, insertData);
+                await this.transaction.commit();
+            } catch (err) {
+                await this.transaction.rollback();
+                throw err;
+            }
+            this._cacheMaxLid(subProj.id, maxId + stdData.length);
+
+            // 查询应返回的结果
+            const createData = await this.getDataByFullPath(subProj.id, insertData[0][this.setting.fullPath] + '%');
+            const updateData = await this.getNextsData(subProj.id, targetId, insertData[0][this.setting.order]);
+            if (updateParent) {
+                updateData.push(await this.getDataByKid(subProj.id, targetId));
+            }
+            return { create: createData, update: updateData };
+        }
+
         async addChild(spid, select, count) {
             const maxId = await this._getMaxLid(spid);
             const children = await this.getChildrenByParentId(spid, select[this.setting.kid]);

+ 11 - 11
app/service/sub_project.js

@@ -66,6 +66,16 @@ module.exports = app => {
             return rule;
         }
 
+        _filterEmptyFolder(data) {
+            data.sort((a, b) => { return b.tree_level - a.tree_level});
+            const result = [];
+            for (const d of data) {
+                if (!d.is_folder) result.push(d);
+                if (result.find(x => { return x.tree_pid === d.id; })) result.push(d);
+            }
+            return result;
+        }
+
         async getSubProject(pid, uid, admin, filterFolder = false) {
             let result = await this.getAllDataByCondition({ where: { project_id: pid, is_delete: 0 } });
 
@@ -80,17 +90,7 @@ module.exports = app => {
                 return true;
                 // return x.user_permission.budget_permission.length > 0 || x.user_permission.file_permission.length > 0 || x.user_permission.manage_permission.length > 0;
             });
-            return result;
-        }
-
-        _filterEmptyFolder(data) {
-            data.sort((a, b) => { return b.tree_level - a.tree_level});
-            const result = [];
-            for (const d of data) {
-                if (!d.is_folder) result.push(d);
-                if (result.find(x => { return x.tree_pid === d.id; })) result.push(d);
-            }
-            return result;
+            return admin ? result : this._filterEmptyFolder(result);
         }
 
         async getBudgetProject(pid, uid, admin) {

+ 69 - 0
app/service/tender.js

@@ -342,6 +342,8 @@ module.exports = app => {
                 if (tender.spid !== postData.spid) {
                     if (postData.spid) await this.ctx.service.subProject.addRelaTender(conn, postData.spid, id);
                     if (tender.spid) await this.ctx.service.subProject.removeRelaTender(conn, tender.spid, id);
+                    const subProject = await this.ctx.service.subProject.getDataById(postData.spid);
+                    await this._addSubProjPermission(conn, subProject, [id]);
                 }
                 rowData.spid = postData.spid || '';
                 const result = await conn.update(this.tableName, rowData);
@@ -708,6 +710,7 @@ module.exports = app => {
                 await conn.updateRows(this.tableName, updateTenders);
                 await conn.update(this.ctx.service.subProject.tableName, { id: subProject.id, rela_tender: this._.uniq(orgRelaTenderId).join(',') });
                 await conn.update(this.ctx.service.budget.tableName, { id: subProject.budget_id, rela_tender: this._.uniq(orgRelaTenderId).join(',') });
+                await this._addSubProjPermission(conn, subProject, tids);
                 await conn.commit();
                 return true;
             } catch (error) {
@@ -717,6 +720,72 @@ module.exports = app => {
             // return await this.ctx.subProject.setRelaTender({ id: spid, rela_tender: newTids });
         }
 
+        async _addSubProjPermission(conn, subProject, tids) {
+            // 需要把所有审批人也迁移至项目下
+            const subProjPermissionAudits = await this.ctx.service.subProjPermission.getAllDataByCondition({ where: { spid: subProject.id } });
+            const hadUids = this._.map(subProjPermissionAudits, 'uid');
+            const newUids = this._.cloneDeep(hadUids) || [];
+            const stageAuditsSql = `SELECT aid FROM ?? WHERE tid in (${tids.join(',')}) ${newUids.length > 0 ? ` AND aid NOT IN (${newUids.join(',')})` : ''} GROUP BY aid`;
+            const stageAuditParams = [this.ctx.service.stageAudit.tableName];
+            const stageResult = await conn.query(stageAuditsSql, stageAuditParams);
+            newUids.push(...this._.map(stageResult, 'aid'));
+            const ledgerAuditsSql = `SELECT audit_id FROM ?? WHERE tender_id in (${tids.join(',')}) ${newUids.length > 0 ? ` AND audit_id NOT IN (${newUids.join(',')})` : ''} GROUP BY audit_id`;
+            const ledgerAuditParams = [this.ctx.service.ledgerAudit.tableName];
+            const ledgerResult = await conn.query(ledgerAuditsSql, ledgerAuditParams);
+            newUids.push(...this._.map(ledgerResult, 'audit_id'));
+            const auditAssAuditsSql = `SELECT ass_user_id FROM ?? WHERE tid in (${tids.join(',')}) ${newUids.length > 0 ? ` AND ass_user_id NOT IN (${newUids.join(',')})` : ''} GROUP BY ass_user_id`;
+            const auditAssAuditParams = [this.ctx.service.auditAss.tableName];
+            const auditAssResult = await conn.query(auditAssAuditsSql, auditAssAuditParams);
+            newUids.push(...this._.map(auditAssResult, 'ass_user_id'));
+            const settleAuditsSql = `SELECT audit_id FROM ?? WHERE tid in (${tids.join(',')}) ${newUids.length > 0 ? ` AND audit_id NOT IN (${newUids.join(',')})` : ''} GROUP BY audit_id`;
+            const settleAuditParams = [this.ctx.service.settleAudit.tableName];
+            const settleResult = await conn.query(settleAuditsSql, settleAuditParams);
+            newUids.push(...this._.map(settleResult, 'audit_id'));
+            const changeAuditsSql = `SELECT uid FROM ?? WHERE tid in (${tids.join(',')}) ${newUids.length > 0 ? ` AND uid NOT IN (${newUids.join(',')})` : ''} GROUP BY uid`;
+            const changeAuditParams = [this.ctx.service.changeAudit.tableName];
+            const changeResult = await conn.query(changeAuditsSql, changeAuditParams);
+            newUids.push(...this._.map(changeResult, 'uid'));
+            const changeApplyAuditsSql = `SELECT aid FROM ?? WHERE tid in (${tids.join(',')}) ${newUids.length > 0 ? ` AND aid NOT IN (${newUids.join(',')})` : ''} GROUP BY aid`;
+            const changeApplyAuditParams = [this.ctx.service.changeApplyAudit.tableName];
+            const changeApplyResult = await conn.query(changeApplyAuditsSql, changeApplyAuditParams);
+            newUids.push(...this._.map(changeApplyResult, 'aid'));
+            const changeProjectAuditsSql = `SELECT aid FROM ?? WHERE tid in (${tids.join(',')}) ${newUids.length > 0 ? ` AND aid NOT IN (${newUids.join(',')})` : ''} GROUP BY aid`;
+            const changeProjectAuditParams = [this.ctx.service.changeProjectAudit.tableName];
+            const changeProjectResult = await conn.query(changeProjectAuditsSql, changeProjectAuditParams);
+            newUids.push(...this._.map(changeProjectResult, 'aid'));
+            const changeProjectXsAuditsSql = `SELECT aid FROM ?? WHERE tid in (${tids.join(',')}) ${newUids.length > 0 ? ` AND aid NOT IN (${newUids.join(',')})` : ''} GROUP BY aid`;
+            const changeProjectXsAuditParams = [this.ctx.service.changeProjectXsAudit.tableName];
+            const changeProjectXsResult = await conn.query(changeProjectXsAuditsSql, changeProjectXsAuditParams);
+            newUids.push(...this._.map(changeProjectXsResult, 'aid'));
+            const changePlanAuditsSql = `SELECT aid FROM ?? WHERE tid in (${tids.join(',')}) ${newUids.length > 0 ? ` AND aid NOT IN (${newUids.join(',')})` : ''} GROUP BY aid`;
+            const changePlanAuditParams = [this.ctx.service.changePlanAudit.tableName];
+            const changePlanResult = await conn.query(changePlanAuditsSql, changePlanAuditParams);
+            newUids.push(...this._.map(changePlanResult, 'aid'));
+            const reviseAuditsSql = `SELECT audit_id FROM ?? WHERE tender_id in (${tids.join(',')}) ${newUids.length > 0 ? ` AND audit_id NOT IN (${newUids.join(',')})` : ''} GROUP BY audit_id`;
+            const reviseAuditParams = [this.ctx.service.reviseAudit.tableName];
+            const reviseResult = await conn.query(reviseAuditsSql, reviseAuditParams);
+            newUids.push(...this._.map(reviseResult, 'audit_id'));
+            const materialAuditsSql = `SELECT aid FROM ?? WHERE tid in (${tids.join(',')}) ${newUids.length > 0 ? ` AND aid NOT IN (${newUids.join(',')})` : ''} GROUP BY aid`;
+            const materialAuditParams = [this.ctx.service.materialAudit.tableName];
+            const materialResult = await conn.query(materialAuditsSql, materialAuditParams);
+            newUids.push(...this._.map(materialResult, 'aid'));
+            const advanceAuditsSql = `SELECT audit_id FROM ?? WHERE tid in (${tids.join(',')}) ${newUids.length > 0 ? ` AND audit_id NOT IN (${newUids.join(',')})` : ''} GROUP BY audit_id`;
+            const advanceAuditParams = [this.ctx.service.advanceAudit.tableName];
+            const advanceResult = await conn.query(advanceAuditsSql, advanceAuditParams);
+            newUids.push(...this._.map(advanceResult, 'audit_id'));
+            const tenderTouristSql = `SELECT user_id FROM ?? WHERE tid in (${tids.join(',')}) ${newUids.length > 0 ? ` AND user_id NOT IN (${newUids.join(',')})` : ''} GROUP BY user_id`;
+            const tenderTouristParams = [this.ctx.service.tenderTourist.tableName];
+            const tenderTouristResult = await conn.query(tenderTouristSql, tenderTouristParams);
+            newUids.push(...this._.map(tenderTouristResult, 'user_id'));
+            const diffUids = this._.difference(newUids, hadUids);
+            if (diffUids.length > 0) {
+                const insertData = diffUids.map(x => {
+                    return { id: this.uuid.v4(), spid: subProject.id, pid: subProject.project_id, uid: x };
+                });
+                await conn.insert(this.ctx.service.subProjPermission.tableName, insertData);
+            }
+        }
+
         async getNoSpTenders(pid) {
             const list = await this.getAllDataByCondition({ where: { project_id: pid, spid: '' }, orders: [['create_time', 'desc']] });
             const accountList = await this.ctx.service.projectAccount.getAllDataByCondition({ where: { project_id: pid } });

+ 1 - 1
app/view/sub_proj/progress.ejs

@@ -101,7 +101,7 @@
                     <a class="nav-link" content="#fujian" href="javascript: void(0);">附件</a>
                 </li>
                 <li>
-                    <a class="nav-link" content="#reference" href="javascript: void(0);">参考文件</a>
+                    <a class="nav-link" content="#reference" href="javascript: void(0);">参考目录</a>
                 </li>
             </ul>
         </div>

+ 1 - 1
app/view/tender/modal.ejs

@@ -113,7 +113,7 @@
                 </table>
                 <div class="text-danger">请勿全选(页面显示不下);谨慎修改别名(修改后,各页面概念将不一致)</div>
             </div>
-            <form class="modal-footer" action="/list/info/col-set" method="post" onsubmit="return onSetCol();">
+            <form class="modal-footer" action="/sp/<%- ctx.subProject.id %>/list/info/col-set" method="post" onsubmit="return onSetCol();">
                 <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
                 <input type="hidden" name="col_set" value="">
                 <input type="hidden" name="col_type" value="info">

+ 16 - 2
db_script/sub_project.js

@@ -40,6 +40,19 @@ const createDefaultSubProject = async function (project) {
     }
 };
 
+const copyColSet = async function(subProject) {
+    console.log(`Copy sub_project ${subProject.name}(${subProject.id}) category`);
+    const exist = await querySql('SELECT * FROM zh_project_col_set where pid = ? and spid = ?', [subProject.project_id, subProject.id]);
+    if (exist.length > 0) return;
+
+    const colSet = await querySql('SELECT * FROM zh_project_col_set where pid = ? and spid = ?', [subProject.project_id, '']);
+    for (const cs of colSet) {
+        const newCs = { pid: subProject.project_id, spid: subProject.id, info: cs.info };
+        const [sql, sqlParam] = getInsertSql('zh_project_col_set', newCs);
+        const insertResult = await querySql(sql, sqlParam);
+    }
+};
+
 const doComplete = async function(code) {
     try {
         const filter = code ? ` where code = '${code}'` : '';
@@ -112,9 +125,10 @@ const doComplete = async function(code) {
                         await querySql('UPDATE zh_tender SET category = ? WHERE id = ?', [JSON.stringify(newTCateGory), t.id]);
                     }
                 }
+            }
 
-                // await querySql('INSERT INTO zh_category (pid, spid, name, type, level) SELECT pid, ?, name, type, level FROM zh_category WHERE pid = ? and spid = ?', [sp.id, p.id, '']);
-                // await querySql('INSERT INTO zh_category_value (pid, spid, cid, value, sort) SELECT pid, ?, cid, value, sort FROM zh_category_value WHERE pid = ? and spid = ?', [sp.id, p.id, '']);
+            for (const sp of subProj) {
+                await copyColSet(sp);
             }
             console.log('END Update;');
         }

+ 8 - 0
sql/update.sql

@@ -51,8 +51,16 @@ MODIFY COLUMN `remark` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci N
 ALTER TABLE `zh_budget_std`
 ADD COLUMN `progress_template_id` varchar(255) NOT NULL DEFAULT '' COMMENT '项目概况-阶段进度-新建模板id列表(‘,’分隔)' AFTER `ht_tender_template_id`;
 
+ALTER TABLE `zh_project_col_set`
+ADD COLUMN `pid` int(11) NOT NULL DEFAULT 0 COMMENT 'zh_project.id' AFTER `id`,
+ADD COLUMN `spid` varchar(36) NOT NULL DEFAULT '' COMMENT 'zh_sub_project.id' AFTER `pid`,
+ADD COLUMN `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间' AFTER `info`,
+ADD COLUMN `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间' AFTER `create_time`;
+
 ------------------------------------
 -- 表数据
 ------------------------------------
 
 UPDATE zh_project_log pl LEFT JOIN zh_tender t ON pl.tid = t.id SET pl.spid = IF(ISNULL(t.spid),'',t.spid);
+
+Update zh_project_col_set SET pid = id;