Przeglądaj źródła

项目管理,移动

MaiXinRong 1 rok temu
rodzic
commit
e3ba04bd1f

+ 12 - 0
app/controller/sub_proj_controller.js

@@ -82,6 +82,18 @@ module.exports = app => {
             }
         }
 
+        async move(ctx) {
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                if (!data.id || !data.type) throw '提交数据错误';
+                const result = await ctx.service.subProject.move(data);
+                ctx.body = { err: 0, msg: '', data: result };
+            } catch (err) {
+                ctx.log(err);
+                ctx.ajaxErrorBody(err, '调整所属文件夹失败');
+            }
+        }
+
         async del(ctx) {
             try {
                 const data = JSON.parse(ctx.request.body.data);

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

@@ -51,6 +51,9 @@ $(document).ready(function() {
                 html.push(`<td>`);
                 html.push('<button class="btn btn-outline-primary btn-sm ml-1" name="edit">编辑</button>');
                 html.push('<button class="btn btn-outline-danger btn-sm ml-1" name="del">删除</button>');
+                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('');
@@ -127,6 +130,11 @@ $(document).ready(function() {
                 delete Utils.dragNode;
                 delete Utils.dropNode;
             },
+            move: function(node, type) {
+                postData('/subproj/move', { id: node.id, type }, function (result) {
+                    Utils.refreshTreeTable(result);
+                });
+            }
         };
 
         Utils.reloadTable();
@@ -163,6 +171,33 @@ $(document).ready(function() {
             }
             $('#del').modal('show');
         });
+        $('body').on('click', 'button[name=up]', function (e) {
+            const treeId = $(this).parent().parent().attr('tree_id');
+            const node = ProjectTree.getItems(treeId);
+            if (!ProjectTree.getPreSiblingNode(node)) {
+                toastr.warning('不可上移');
+                return;
+            }
+            Utils.move(node, 'up');
+        });
+        $('body').on('click', 'button[name=down]', function (e) {
+            const treeId = $(this).parent().parent().attr('tree_id');
+            const node = ProjectTree.getItems(treeId);
+            if (!ProjectTree.getNextSiblingNode(node)) {
+                toastr.warning('不可下移');
+                return;
+            }
+            Utils.move(node, 'down');
+        });
+        $('body').on('click', 'button[name=top]', function (e) {
+            const treeId = $(this).parent().parent().attr('tree_id');
+            const node = ProjectTree.getItems(treeId);
+            if (!ProjectTree.getParent(node)) {
+                toastr.warning('已是顶层节点');
+                return;
+            }
+            Utils.move(node, 'top');
+        });
         $('body').on('click', 'button[name=edit]', function(e) {
             const treeId = $(this).parent().parent().attr('tree_id');
             const node = ProjectTree.getItems(treeId);

+ 1 - 0
app/router.js

@@ -711,6 +711,7 @@ module.exports = app => {
     app.post('/subproj/addFolder', sessionAuth, projectManagerCheck, 'subProjController.addFolder');
     app.post('/subproj/addProj', sessionAuth, projectManagerCheck, 'subProjController.addProj');
     app.post('/subproj/dragTo', sessionAuth, projectManagerCheck, 'subProjController.dragTo');
+    app.post('/subproj/move', sessionAuth, projectManagerCheck, 'subProjController.move');
     app.post('/subproj/del', sessionAuth, projectManagerCheck, 'subProjController.del');
     app.post('/subproj/save', sessionAuth, projectManagerCheck, 'subProjController.save');
     app.post('/subproj/rela/save', sessionAuth, 'subProjController.saveRela');

+ 80 - 12
app/service/sub_project.js

@@ -100,6 +100,31 @@ module.exports = app => {
             return result[0];
         }
 
+        async getPosterityData(id){
+            const result = [];
+            let cur = await this.getAllDataByCondition({ where: { tree_pid: id } });
+            let iLevel = 1;
+            while (cur.length > 0 && iLevel < 6) {
+                result.push(...cur);
+                cur = await this.getAllDataByCondition({ where: { tree_pid: cur.map(x => { return x.id })} });
+                iLevel += 1;
+            }
+            return result;
+        }
+
+        async getStepNode(node, step) {
+            const tree_order = [];
+            while(step) {
+                tree_order.push(node.tree_order + step);
+                if (step > 0) {
+                    step = step - 1;
+                } else {
+                    step = step + 1;
+                }
+            }
+            return await this.getAllDataByCondition({ where: { tree_pid: node.tree_pid, tree_order }, orders: [['tree_order', 'desc']]});
+        }
+
         async addFolder(data) {
             const parent = await this.getDataById(data.tree_pid);
             if (parent && !parent.is_folder) throw '添加数据结构错误';
@@ -163,18 +188,6 @@ module.exports = app => {
             }
         }
 
-        async getPosterityData(id){
-            const result = [];
-            let cur = await this.getAllDataByCondition({ where: { tree_pid: id } });
-            let iLevel = 1;
-            while (cur.length > 0 && iLevel < 6) {
-                result.push(...cur);
-                cur = await this.getAllDataByCondition({ where: { tree_pid: cur.map(x => { return x.id })} });
-                iLevel += 1;
-            }
-            return result;
-        }
-
         async dragTo(data) {
             const dragNode = await this.getDataById(data.drag_id);
             const dropNode = await this.getDataById(data.drop_id);
@@ -206,6 +219,61 @@ module.exports = app => {
             return await this.getSubProject(this.ctx.session.sessionProject.id, this.ctx.session.sessionUser.accountId, this.ctx.session.sessionUser.is_admin);
         }
 
+        async _siblingMove(node, step) {
+            const stepNode = await this.getStepNode(node, step);
+
+            const conn = await this.db.beginTransaction();
+            try {
+                const updateData = [];
+                updateData.push({ id: node.id, tree_order: node.tree_order + step });
+                for (const sn of stepNode) {
+                    updateData.push({ id: node.id, tree_order: step > 0 ? sn.tree_order - 1 : sn.tree_order + 1 });
+                }
+                await conn.updateRows(this.tableName, updateData);
+                await conn.commit();
+            } catch (error) {
+                await conn.rollback();
+                throw error;
+            }
+        }
+
+        async _topMove(node) {
+            const lastChild = await this.getLastChild(-1);
+            const posterity = await this.getPosterityData(node.id);
+
+            const conn = await this.db.beginTransaction();
+            try {
+                const updateData = { id: node.id, tree_pid: -1, tree_level: 1, tree_order: lastChild ? lastChild.tree_order + 1 : 1 };
+                await conn.update(this.tableName, updateData);
+                if (node.tree_level !== 1 && posterity.length > 0) {
+                    const posterityUpdateData = posterity.map(x => {
+                        return { id: x.id, tree_level: x.tree_level - node.tree_level + 1 }
+                    });
+                    await conn.updateRows(this.tableName, posterityUpdateData);
+                }
+                // 升级原来的后项的order
+                await conn.query(`UPDATE ${this.tableName} SET tree_order = tree_order-1 WHERE tree_pid = ? AND tree_order > ?`, [node.tree_pid, node.tree_order]);
+                await conn.commit();
+            } catch (error) {
+                await conn.rollback();
+                throw error;
+            }
+        }
+
+        async move(data) {
+            const node = await this.getDataById(data.id);
+            if (!node) throw '移动数据结构错误';
+
+            switch(data.type) {
+                case 'up': await this._siblingMove(node, -1); break;
+                case 'down': await this._siblingMove(node, 1); break;
+                case 'top': await this._topMove(node); break;
+                default: throw '未知移动类型';
+            }
+
+            return await this.getSubProject(this.ctx.session.sessionProject.id, this.ctx.session.sessionUser.accountId, this.ctx.session.sessionUser.is_admin);
+        }
+
         async del(id) {
             const node = await this.getDataById(id);
             if (!node) throw '删除的数据不存在';