Просмотр исходного кода

批量设置账号至其他项目调整

MaiXinRong 10 месяцев назад
Родитель
Сommit
62abc12d80

+ 2 - 2
app/const/audit.js

@@ -40,9 +40,9 @@ const common = (function() {
         { key: 'checked', value: 3, title: '审批通过', class: 'text-success', btnTitle: '', btnClass: 'btn-primary' },
         { key: 'checkNo', value: 4, title: '审批退回', class: 'text-warning', btnTitle: '重新上报', btnClass: 'btn-primary' },
         { key: 'checkNoPre', value: 5, title: '审批退回', class: 'text-warning', btnTitle: '重新审批', btnClass: 'btn-primary' },
-        { key: 'checkSkip', value: 6, title: '', class: '', btnTitle: '', btnClass: '' },
+        { key: 'checkAgain', value: 6, title: '重新审批', class: 'text-warning', btnTitle: '', btnClass: '' },
         { key: 'checkCancel', value: 7, title: '撤回', class: 'text-warning', btnTitle: '', btnClass: '' },
-        { key: 'checkAgain', value: 8, title: '重新审批', class: 'text-warning', btnTitle: '', btnClass: '' },
+        { key: 'checkSkip', value: 8, title: '', class: '', btnTitle: '', btnClass: '' },
     ];
     return (function(){
         const status = {}, info = [];

+ 3 - 1
app/controller/sub_proj_setting_controller.js

@@ -250,7 +250,9 @@ module.exports = app => {
                     return { id: item.id, name: item.name, groupList };
                 }).filter(x => { return x.groupList.length > 0; });
 
-                const subProjects = await this.ctx.service.subProject.getAllDataByCondition({ where: { project_id: this.ctx.session.sessionProject.id, is_folder: 0, is_delete: 0 }});
+                // const subProjects = await this.ctx.service.subProject.getAllDataByCondition({ where: { project_id: this.ctx.session.sessionProject.id, is_delete: 0 }});
+                const subProjects = await this.ctx.service.subProject.getSubProjectTreeNodes(this.ctx.session.sessionProject.id,
+                    this.ctx.session.sessionUser.accountId, this.ctx.session.sessionUser.is_admin);
                 const renderData = {
                     pageInfo,
                     accountGroup,

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

@@ -3424,6 +3424,10 @@ $(document).ready(function() {
                             visible: function (key, opt) {
                                 return !self.sheet.zh_setting.readOnly;
                             },
+                            disabled: function (key, opt) {
+                                const select = SpreadJsObj.getSelectObject(self.sheet);
+                                return !select;
+                            },
                             callback: function (key, opt) {
                                 self.OprObj.insert(self.sheet);
                             },

+ 1 - 1
app/public/js/sp_setting_permission.js

@@ -271,7 +271,7 @@ $(document).ready(() => {
         }
     });
     $('#copy-user-batch-ok').click(function() {
-        const spCheck = $('[name=cub-sp-check]:checked');
+        const spCheck = $('[name=cub-sp-check][tree_is_folder="0"]:checked');
         if (spCheck.length === 0) {
             toastr.warning('未选择项目');
             return;

+ 128 - 0
app/service/sub_project.js

@@ -23,6 +23,121 @@ const funSet = require('../const/fun_set');
 const defaultFunSet = funSet.defaultInfo;
 const pageShowConst = require('../const/sp_page_show').defaultSetting;
 
+class DragTree {
+    /**
+     * 构造函数
+     */
+    constructor(setting) {
+        // 无索引
+        this.datas = [];
+        // 以key为索引indexedDB
+        this.items = {};
+        // 以排序为索引
+        this.nodes = [];
+        // 根节点
+        this.children = [];
+        // 树设置
+        this.setting = setting;
+        if (!this.setting.itemsPre) this.setting.itemsPre = 'id_';
+    }
+    /**
+     * 树结构根据显示排序
+     */
+    sortTreeNode(isResort) {
+        const self = this;
+        const addSortNodes = function (nodes) {
+            if (!nodes) { return }
+            for (let i = 0; i < nodes.length; i++) {
+                self.nodes.push(nodes[i]);
+                nodes[i].index = self.nodes.length - 1;
+                if (!isResort) {
+                    nodes[i].children = self.getChildren(nodes[i]);
+                } else {
+                    nodes[i].children.sort((a, b) => { return a[self.setting.order] - b[self.setting.order]; })
+                }
+                addSortNodes(nodes[i].children);
+            }
+        };
+        this.nodes = [];
+        if (!isResort) {
+            this.children = this.getChildren();
+        } else {
+            this.children.sort((a, b) => { return a[self.setting.order] - b[self.setting.order]; });
+        }
+        addSortNodes(this.children);
+    }
+    /**
+     * 加载数据(初始化), 并给数据添加部分树结构必须数据
+     * @param datas
+     */
+    loadDatas(datas) {
+        const self = this;
+        // 清空旧数据
+        this.items = {};
+        this.nodes = [];
+        this.datas = [];
+        this.children = [];
+        // 加载全部数据
+        datas.sort(function (a, b) {
+            return a[self.setting.level] - b[self.setting.level];
+        });
+        for (const data of datas) {
+            const keyName = this.setting.itemsPre + data[this.setting.id];
+            if (this.items[keyName]) continue;
+
+            const item = JSON.parse(JSON.stringify(data));
+            item.children = [];
+            item.expanded = true;
+            item.visible = true;
+            if (item[this.setting.pid] === this.setting.rootId) {
+                this.children.push(item);
+            } else {
+                const parent = this.getParent(item);
+                if (!parent) continue;
+                parent.children.push(item);
+            }
+            this.items[keyName] = item;
+            this.datas.push(item);
+        }
+        this.children.sort((a, b) => { return a[self.setting.order] - b[self.setting.order]; });
+        this.sortTreeNode(true);
+    }
+
+    getItemsByIndex(index) {
+        return this.nodes[index];
+    }
+    getItems(id) {
+        return this.items[this.setting.itemsPre + id];
+    };
+
+    getParent(node) {
+        return this.getItems(node[this.setting.pid]);
+    };
+    getChildren(node) {
+        const setting = this.setting;
+        const pid = node ? node[setting.id] : setting.rootId;
+        const children = this.datas.filter(function (x) {
+            return x[setting.pid] === pid;
+        });
+        children.sort((a, b) => { return a[setting.order] - b[setting.order]; });
+        return children;
+    };
+    isLastSibling(node) {
+        const siblings = this.getChildren(this.getParent(node));
+        return (siblings && siblings.length > 0) ? node[this.setting.order] === siblings[siblings.length - 1][this.setting.order] : false;
+    };
+
+    recursiveFun(children, fun) {
+        if (!fun) return;
+        if (!children || children.length === 0) return;
+
+        for (const c of children) {
+            this.recursiveFun(c.children, fun);
+            fun(c);
+        }
+    }
+}
+
 module.exports = app => {
     class SubProject extends app.BaseService {
 
@@ -97,6 +212,19 @@ module.exports = app => {
             return admin ? result : this._filterEmptyFolder(result);
         }
 
+        async getSubProjectTreeNodes(pid, uid, admin, filterFolder = false) {
+            const subProjects = await this.getSubProject(pid, uid, admin, filterFolder);
+            const subProjectsTree = new DragTree({ id: 'id', pid: 'tree_pid', level: 'tree_level', order: 'tree_order', rootId: '-1' });
+            subProjectsTree.loadDatas(subProjects);
+            const result = subProjectsTree.nodes.map(x => {
+                return {
+                    id: x.id, tree_pid: x.tree_pid, tree_level: x.tree_level, is_folder: x.is_folder, name: x.name,
+                    is_last_sibling: subProjectsTree.isLastSibling(x), has_children: x.children && x.children.length > 0,
+                };
+            });
+            return result;
+        }
+
         async getBudgetProject(pid, uid, admin) {
             let result = await this.getAllDataByCondition({ where: { project_id: pid, is_delete: 0 } });
 

+ 50 - 1
app/view/sp_setting/user_modal.ejs

@@ -151,7 +151,17 @@
                                 <tbody>
                                 <% for (const sp of subProjects) { %>
                                 <% if (sp.id === ctx.subProject.id) continue; %>
-                                <tr><td class="text-center"><input type="checkbox" name="cub-sp-check" spid="<%- sp.id %>"></td><td><%- sp.name %></td></tr>
+                                <tr tree_id="<%- sp.id %>" tree_pid="<%- sp.tree_pid %>" tree_expand="1" tree_leaf="<%- (sp.has_children ? 0 : 1) %>">
+                                    <td class="text-center"><input type="checkbox" name="cub-sp-check" tree_is_folder="<%- (sp.is_folder ? 1 : 0) %>" spid="<%- sp.id %>"></td>
+                                    <td class="in-<%- sp.tree_level%> d-flex">
+                                        <% if (sp.has_children) { %>
+                                        <div onselectstart="return false" style="{-moz-user-select:none}" class="fold-switch mr-1 d-inline-block" title="收起" id="<%- sp.id %>"><i class="fa fa-minus-square-o"></i></div>
+                                        <% } else { %>
+                                        <div class="text-muted mr-1 d-inline-block" style="heigth: 100%"><%- (sp.is_last_sibling ? '└' : '├') %></div>
+                                        <% } %>
+                                        <div class="d-inline-block"><%- sp.name %></div>
+                                    </td>
+                                </tr>
                                 <% } %>
                                 </tbody>
                             </table>
@@ -179,3 +189,42 @@
         </div>
     </div>
 </div>
+<script>
+    const setPosterityShow = function(id, show) {
+        const children = $(`tr[tree_pid=${id}]`);
+        for (const c of children) {
+            if (show) {
+                $(c).show();
+            } else {
+                $(c).hide();
+            }
+            if (c.getAttribute('tree_leaf') !== '1') {
+                setPosterityShow(c.getAttribute('tree_id'), c.getAttribute('tree_expand') === '1' && show);
+            }
+        }
+    }
+    $('body').on('click', '.fold-switch', function() {
+        const id = this.getAttribute('id');
+        const nodeTr = $(`tr[tree_id=${id}]`);
+        const expand = nodeTr.attr('tree_expand') === '1';
+        nodeTr.attr('tree_expand', expand ? 0 : 1);
+        if (!expand) {
+            $(this).html(`<i class="fa fa-minus-square-o"></i>`);
+        } else {
+            $(this).html(`<i class="fa fa-plus-square-o"></i>`);
+        }
+        setPosterityShow(id, !expand);
+    });
+    const setChildrenCheck = function(id, check) {
+        const children = $(`tr[tree_pid=${id}]`);
+        for (const c of children) {
+            $('input', c)[0].checked = check;
+            if (c.getAttribute('tree_leaf') !== '1') {
+                setChildrenCheck(c.getAttribute('tree_id'), check);
+            }
+        }
+    }
+    $('body').on('change', 'input[name=cub-sp-check][tree_is_folder="1"]', function() {
+        setChildrenCheck(this.getAttribute('spid'), this.checked);
+    })
+</script>