浏览代码

解决冲突

olym 7 年之前
父节点
当前提交
1903b95103
共有 5 个文件被更改,包括 607 次插入31 次删除
  1. 16 6
      app/lib/sql_builder.js
  2. 500 15
      app/service/tender_node.js
  3. 2 2
      package.json
  4. 23 1
      test/app/lib/sql_builder.test.js
  5. 66 7
      test/app/service/tender_node.test.js

+ 16 - 6
app/lib/sql_builder.js

@@ -81,6 +81,10 @@ class SqlBuilder {
                 this.sql = 'UPDATE ?? SET ';
                 this.sql = 'UPDATE ?? SET ';
                 this.sqlParam = [tableName];
                 this.sqlParam = [tableName];
                 break;
                 break;
+            case 'delete':
+                this.sql = 'DELETE FROM ??';
+                this.sqlParam = [tableName];
+                break;
             default:
             default:
                 break;
                 break;
         }
         }
@@ -97,14 +101,20 @@ class SqlBuilder {
         }
         }
         const setDataArr = [];
         const setDataArr = [];
         for (const set of this.setData) {
         for (const set of this.setData) {
-            const tmp = set.data.selfOperate !== undefined ?
-                ' ?? = ?? ' + set.data.selfOperate + ' ' + set.data.value : ' ?? = ' + set.data.value;
-            setDataArr.push(tmp);
-            // 如果是自身操作则压多一次字段进数组
-            if (set.data.selfOperate !== undefined) {
+            if (set.data.literal) {
+                const values = set.data.value instanceof Array ? set.data.value : [set.data.value];
+                setDataArr.push(' ?? = ' + set.data.literal + '(' + values.join(',') + ')');
+                this.sqlParam.push(set.field);
+            } else {
+                const tmp = set.data.selfOperate !== undefined ?
+                    ' ?? = ?? ' + set.data.selfOperate + ' ' + set.data.value : ' ?? = ' + set.data.value;
+                setDataArr.push(tmp);
+                // 如果是自身操作则压多一次字段进数组
+                if (set.data.selfOperate !== undefined) {
+                    this.sqlParam.push(set.field);
+                }
                 this.sqlParam.push(set.field);
                 this.sqlParam.push(set.field);
             }
             }
-            this.sqlParam.push(set.field);
         }
         }
 
 
         const setString = setDataArr.join(',');
         const setString = setDataArr.join(',');

+ 500 - 15
app/service/tender_node.js

@@ -53,6 +53,7 @@ module.exports = app => {
                         insertData.push(tmp);
                         insertData.push(tmp);
                     }
                     }
                     const operate = await this.transaction.insert(this.tableName, insertData);
                     const operate = await this.transaction.insert(this.tableName, insertData);
+                    this.transaction.commit();
                     result = operate.affectedRows > 0;
                     result = operate.affectedRows > 0;
                 } else {
                 } else {
                     // 对象则单个插入
                     // 对象则单个插入
@@ -124,13 +125,114 @@ module.exports = app => {
         }
         }
 
 
         /**
         /**
+         * 获取最末的子节点
+         * @param {Number} tenderId - 标段id
+         * @param {Number} pid - 父节点id
+         * @returns {Object}
+         */
+        async getLastChildData(tenderId, pid) {
+            this.initSqlBuilder();
+            this.sqlBuilder.setAndWhere('tender_id', {
+                value: tenderId,
+                operate: '='
+            });
+            this.sqlBuilder.setAndWhere('template_pid', {
+                value: pid,
+                operate: '='
+            });
+            this.sqlBuilder.orderBy = [['order', 'DESC']];
+            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
+            const resultData = this.db.queryOne(sql, sqlParam);
+
+            return resultData;
+        }
+
+        /**
+         * 根据 父节点id 和 节点排序order 获取数据
+         *
+         * @param {Number} tenderId - 标段id
+         * @param {Number} pid - 父节点id
+         * @param {Number|Array} order - 排序
+         * @returns {Object|Array} - 查询结果
+         */
+        async getDataByParentAndOrder(tenderId, pid, order) {
+            if ((tenderId <= 0) || (pid <= 0) || (order <= 0)) {
+                return undefined;
+            }
+
+            this.initSqlBuilder();
+            this.sqlBuilder.setAndWhere('tender_id', {
+                value: tenderId,
+                operate: '='
+            });
+            this.sqlBuilder.setAndWhere('template_pid', {
+                value: pid,
+                operate: '=',
+            });
+            if (order instanceof Array) {
+                this.sqlBuilder.setAndWhere('order', {
+                    value: order,
+                    operate: 'in'
+                });
+            } else {
+                this.sqlBuilder.setAndWhere('order', {
+                    value: order,
+                    operate: '='
+                });
+            }
+
+            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
+            let data;
+            if (order instanceof Array) {
+                data = await this.db.query(sql, sqlParam);
+            } else {
+                data = await this.db.queryOne(sql, sqlParam);
+            }
+
+            return data;
+        }
+
+        /**
+         * 根据 父节点ID 和 节点排序order 获取全部后节点数据
+         * @param {Number} tenderId - 标段id
+         * @param {Number} pid - 父节点id
+         * @param {Number} order - 排序
+         * @returns {Array}
+         */
+        async getNextsData(tenderId, pid, order) {
+            if ((tenderId <= 0) || (pid <= 0) || (order <= 0)) {
+                return undefined;
+            }
+
+            this.initSqlBuilder();
+            this.sqlBuilder.setAndWhere('tender_id', {
+                value: tenderId,
+                operate: '='
+            });
+            this.sqlBuilder.setAndWhere('template_pid', {
+                value: pid,
+                operate: '=',
+            });
+            this.sqlBuilder.setAndWhere('order', {
+                value: order,
+                operate: '>'
+            });
+
+            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
+            const data = await this.db.query(sql, sqlParam);
+
+            return data;
+        }
+
+        /**
          *  select的全部后兄弟节点,Order自增
          *  select的全部后兄弟节点,Order自增
          *
          *
          * @param {Object} select - 选中的节点
          * @param {Object} select - 选中的节点
+         * @param {Number} incre - 自增值
          * @return {Array} - 自增后的数据
          * @return {Array} - 自增后的数据
          * @private
          * @private
          */
          */
-        async _updateSelectNextsOrder(select) {
+        async _updateSelectNextsOrder(select, incre = 1) {
             this.initSqlBuilder();
             this.initSqlBuilder();
             this.sqlBuilder.setAndWhere('tender_id', {
             this.sqlBuilder.setAndWhere('tender_id', {
                 value: select.tender_id,
                 value: select.tender_id,
@@ -145,8 +247,8 @@ module.exports = app => {
                 operate: '=',
                 operate: '=',
             });
             });
             this.sqlBuilder.setUpdateData('order', {
             this.sqlBuilder.setUpdateData('order', {
-                value: 1,
-                selfOperate: '+',
+                value: Math.abs(incre),
+                selfOperate: incre > 0 ? '+' : '-',
             });
             });
             // sql = update this.tableName set order = order + 1 where (tender_id = select.tender_id) && (pid = select.pid) && (order >= select.order+1)
             // sql = update this.tableName set order = order + 1 where (tender_id = select.tender_id) && (pid = select.pid) && (order >= select.order+1)
             const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');
             const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');
@@ -156,7 +258,22 @@ module.exports = app => {
         }
         }
 
 
         /**
         /**
+         * 从数据库获取标段的最大节点id
+         *
+         * @param {Number} tenderId - 标段id
+         * @return {Number}
+         * @private
+         */
+        async _getMaxNodeId(tenderId) {
+            const sql = 'SELECT Max(??) As max_id FROM ?? Where tender_id = ' + tenderId;
+            const sqlParam = ['template_id', this.tableName];
+            const queryResult = await this.db.queryOne(sql, sqlParam);
+            return queryResult.max_id;
+        }
+
+        /**
          * 根据selectData, data 新增数据
          * 根据selectData, data 新增数据
+         *
          * @param {Number} tenderId - 标段id
          * @param {Number} tenderId - 标段id
          * @param {Object} selectData - 选中节点的数据
          * @param {Object} selectData - 选中节点的数据
          * @param {Object} data - 新增节点的初始数据
          * @param {Object} data - 新增节点的初始数据
@@ -170,19 +287,29 @@ module.exports = app => {
             if (!data) {
             if (!data) {
                 data = {};
                 data = {};
             }
             }
+            const cacheKey = 'tender_node_maxId:' + tenderId;
+            let maxId = parseInt(await this.cache.get(cacheKey));
+            if (!maxId) {
+               maxId = await this._getMaxNodeId(tenderId);
+               this.cache.set(cacheKey, maxId, 'EX', this.ctx.app.config.cacheTime);
+            }
+
             data.tender_id = tenderId;
             data.tender_id = tenderId;
-            data.template_id = 15;
+            data.template_id = maxId + 1;
             data.template_pid = selectData.template_pid;
             data.template_pid = selectData.template_pid;
             data.level = selectData.level;
             data.level = selectData.level;
             data.order = selectData.order + 1;
             data.order = selectData.order + 1;
             data.full_path = selectData.full_path.replace(selectData.template_id, data.template_id);
             data.full_path = selectData.full_path.replace(selectData.template_id, data.template_id);
             const result = await this.transaction.insert(this.tableName, data);
             const result = await this.transaction.insert(this.tableName, data);
 
 
+            this.cache.set(cacheKey, maxId + 1, 'EX', this.ctx.app.config.cacheTime);
+
             return result;
             return result;
         }
         }
 
 
         /**
         /**
          * tenderId标段中, 在selectId后新增一个节点
          * tenderId标段中, 在selectId后新增一个节点
+         *
          * @param {Number} tenderId - 标段id
          * @param {Number} tenderId - 标段id
          * @param {Number} selectId - 选中节点id
          * @param {Number} selectId - 选中节点id
          * @param {Object} data - 新增节点初始化数据
          * @param {Object} data - 新增节点初始化数据
@@ -190,32 +317,390 @@ module.exports = app => {
          */
          */
         async addNode(tenderId, selectId, data) {
         async addNode(tenderId, selectId, data) {
             if ((tenderId <= 0) || (selectId <= 0)) {
             if ((tenderId <= 0) || (selectId <= 0)) {
-                return undefined;
+                return [];
             }
             }
             const selectData = await this.getDataByNodeId(tenderId, selectId);
             const selectData = await this.getDataByNodeId(tenderId, selectId);
             this.transaction = await this.db.beginTransaction();
             this.transaction = await this.db.beginTransaction();
 
 
-            let resultData = [];
             if (selectData) {
             if (selectData) {
                 try {
                 try {
                     // 选中节点的所有后兄弟节点,order+1
                     // 选中节点的所有后兄弟节点,order+1
-                    const updateData = await this._updateSelectNextsOrder(selectData);
-                    console.log(updateData);
+                    await this._updateSelectNextsOrder(selectData);
                     // 数据库创建新增节点数据
                     // 数据库创建新增节点数据
-                    const addData = await this._addNodeData(tenderId, selectData, data);
-                    console.log(addData);
-                    resultData = await this.transaction.commit();
-                    console.log(resultData);
-
-                    resultData.concat(updateData, addData);
+                    await this._addNodeData(tenderId, selectData, data);
+                    await this.transaction.commit();
                 } catch (err) {
                 } catch (err) {
                     await this.transaction.rollback();
                     await this.transaction.rollback();
                     throw err;
                     throw err;
                 }
                 }
+
+                // 查询应返回的结果
+                this.initSqlBuilder();
+                this.sqlBuilder.setAndWhere('tender_id', {
+                    value: selectData.tender_id,
+                    operate: '=',
+                });
+                this.sqlBuilder.setAndWhere('template_pid', {
+                    value: selectData.template_pid,
+                    operate: '=',
+                });
+                this.sqlBuilder.setAndWhere('order', {
+                    value: selectData.order,
+                    operate: '>',
+                });
+                const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
+                const resultData = this.db.query(sql, sqlParam);
+
+                return resultData;
             } else {
             } else {
                 throw '新增节点数据错误';
                 throw '新增节点数据错误';
             }
             }
-            return resultData;
+
+        }
+
+        /**
+         *  tenderId标段中, 删除选中节点及其子节点
+         *
+         * @param {Number} tenderId - 标段id
+         * @param {Number} selectId - 选中节点id
+         * @return {Array} - 被删除的数据
+         */
+        async deleteNode(tenderId, selectId) {
+            if ((tenderId <= 0) || (selectId <= 0)) {
+                return [];
+            }
+            const selectData = await this.getDataByNodeId(tenderId, selectId);
+            this.transaction = await this.db.beginTransaction();
+
+            let resultData = [];
+            if (selectData) {
+                try {
+                    // 获取将要被删除的数据
+                    this.initSqlBuilder();
+                    this.sqlBuilder.setAndWhere('tender_id', {
+                        value: tenderId,
+                        operate: '='
+                    });
+                    this.sqlBuilder.setAndWhere('full_path', {
+                        value: this.db.escape(selectData.full_path + '%'),
+                        operate: 'Like'
+                    });
+                    let [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
+                    resultData = await this.db.query(sql, sqlParam);
+                    // 删除
+                    this.initSqlBuilder();
+                    this.sqlBuilder.setAndWhere('tender_id', {
+                        value: tenderId,
+                        operate: '='
+                    });
+                    this.sqlBuilder.setAndWhere('full_path', {
+                        value: this.db.escape(selectData.full_path + '%'),
+                        operate: 'Like'
+                    });
+                    [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'delete');
+                    const operate = await this.transaction.query(sql, sqlParam);
+                    this.transaction.commit();
+                } catch(err) {
+                    resultData = [];
+                    await this.transaction.rollback();
+                    throw err;
+                }
+                return resultData;
+            } else {
+                throw '删除节点数据错误';
+            }
+        }
+
+        /**
+         * tenderId标段中, 选中节点selectId上移
+         *
+         * @param {Number} tenderId - 标段id
+         * @param {Number} selectId - 选中节点id
+         * @return {Array} - 发生改变的数据
+         */
+        async upMoveNode(tenderId, selectId) {
+            if ((tenderId <= 0) || (selectId <= 0)) {
+                return [];
+            }
+            const selectData = await this.getDataByNodeId(tenderId, selectId);
+            const preData = await this.getDataByParentAndOrder(tenderId, selectData.template_pid, selectData.order - 1);
+            this.transaction = await this.db.beginTransaction();
+
+            if (selectData && preData) {
+                try {
+                    const sData = await this.transaction.update(this.tableName, {id: selectData.id, order: selectData.order - 1});
+                    const pData = await this.transaction.update(this.tableName, {id: preData.id, order: preData.order + 1});
+                    this.transaction.commit();
+                } catch (err) {
+                    await this.transaction.rollback();
+                    throw err;
+                }
+
+                const resultData = await this.getDataByParentAndOrder(tenderId, selectData.template_pid, [selectData.order, preData.order]);
+                return resultData;
+            } else {
+                throw '上移节点数据错误';
+            }
+        }
+
+        /**
+         * tenderId标段中, 选中节点selectId下移
+         *
+         * @param {Number} tenderId - 标段id
+         * @param {Number} selectId - 选中节点id
+         * @return {Array} - 发生改变的数据
+         */
+        async downMoveNode(tenderId, selectId) {
+            if ((tenderId <= 0) || (selectId <= 0)) {
+                return [];
+            }
+            const selectData = await this.getDataByNodeId(tenderId, selectId);
+            const nextData = await this.getDataByParentAndOrder(tenderId, selectData.template_pid, selectData.order + 1);
+            this.transaction = await this.db.beginTransaction();
+
+            if (selectData && nextData) {
+                try {
+                    const sData = await this.transaction.update(this.tableName, {id: selectData.id, order: selectData.order + 1});
+                    const pData = await this.transaction.update(this.tableName, {id: nextData.id, order: nextData.order - 1});
+                    this.transaction.commit();
+                } catch (err) {
+                    await this.transaction.rollback();
+                    throw err;
+                }
+
+                const resultData = await this.getDataByParentAndOrder(tenderId, selectData.template_pid, [selectData.order, nextData.order]);
+                return resultData;
+            } else {
+                throw '下移节点数据错误';
+            }
+        }
+
+        /**
+         * 升级selectData, 同步修改所有子节点
+         * @param {Object} selectData - 升级操作,选中节点
+         * @return {Object}
+         * @private
+         */
+        async _syncUplevelChildren(selectData) {
+            this.initSqlBuilder();
+            this.sqlBuilder.setAndWhere('tender_id', {
+                value: selectData.tender_id,
+                operate: '='
+            });
+            this.sqlBuilder.setAndWhere('full_path', {
+                value: this.db.escape(selectData.full_path + '.%'),
+                operate: 'like'
+            });
+            this.sqlBuilder.setUpdateData('level', {
+                value: 1,
+                selfOperate: '-'
+            });
+            this.sqlBuilder.setUpdateData('full_path', {
+                value: ['`full_path`', this.db.escape(selectData.template_pid + '.'), this.db.escape('')],
+                literal: 'Replace'
+            });
+            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');
+            const data = this.transaction.query(sql, sqlParam);
+
+            return data;
+        }
+
+        /**
+         * 选中节点的后兄弟节点,全部变为当前节点的子节点
+         * @param {Object} selectData - 选中节点
+         * @return {Object}
+         * @private
+         */
+        async _syncUpLevelNexts(selectData) {
+            // 查询selectData的lastChild
+            const lastChildData = await this.getLastChildData(selectData.tender_id, selectData.template_id);
+            const nextsData = await this.getNextsData(selectData.tender_id, selectData.template_pid, selectData.order);
+            if (nextsData && nextsData.length > 0) {
+                // 修改nextsData pid, 排序
+                this.initSqlBuilder();
+                this.sqlBuilder.setUpdateData('template_pid', {
+                    value: selectData.template_id
+                });
+                const orderInc = lastChildData ? lastChildData.order - selectData.order : - selectData.order;
+                this.sqlBuilder.setUpdateData('order', {
+                    value: Math.abs(orderInc),
+                    selfOperate: orderInc > 0 ? '+' : '-'
+                });
+                this.sqlBuilder.setAndWhere('template_pid', {
+                    value: selectData.template_pid,
+                    operate: '='
+                });
+                this.sqlBuilder.setAndWhere('order', {
+                    value: selectData.order,
+                    operate: '>'
+                });
+                const [sql1, sqlParam1] = this.sqlBuilder.build(this.tableName, 'update');
+                await this.transaction.query(sql1, sqlParam1);
+
+                // 修改nextsData及其子节点的full_path
+                const oldSubStr = this.db.escape(selectData.template_pid + '.');
+                const newSubStr = this.db.escape(selectData.template_id + '.');
+                const sqlArr = [];
+                sqlArr.push('Update ?? SET `full_path` = Replace(`full_path`,' + oldSubStr + ',' + newSubStr + ') Where');
+                sqlArr.push('(`tender_id` = ' + selectData.tender_id +')');
+                sqlArr.push(' And (');
+                for (const data of nextsData) {
+                    sqlArr.push('`full_path` Like ' + this.db.escape(data.full_path + '%'));
+                    if (nextsData.indexOf(data) < nextsData.length - 1) {
+                        sqlArr.push(' Or ');
+                    }
+                }
+                sqlArr.push(')');
+                const sql = sqlArr.join('');
+                const resultData = await this.transaction.query(sql, [this.tableName]);
+                return resultData;
+            }
+        }
+
+        /**
+         * 升级节点
+         *
+         * @param {Number} tenderId - 标段id
+         * @param {Number} selectId - 选中节点id
+         * @return {Array} - 发生改变的数据
+         */
+        async upLevelNode(tenderId, selectId) {
+            if ((tenderId <= 0) || (selectId <= 0)) {
+                return [];
+            }
+            const selectData = await this.getDataByNodeId(tenderId, selectId);
+            if (!selectData) {
+                throw '升级节点数据错误';
+            }
+            const parentData = await this.getDataByNodeId(tenderId, selectData.template_pid);
+            if (!parentData) {
+                throw '升级节点数据错误'
+            }
+
+            this.transaction = await this.db.beginTransaction();
+            try {
+                // 选中节点--父节点--全部后兄弟节点 order+1
+                await this._updateSelectNextsOrder(parentData);
+                // 选中节点 修改pid, order, full_path
+                const updateData = {id: selectData.id,
+                    template_pid: parentData.template_pid,
+                    order: parentData.order + 1,
+                    level: selectData.level - 1,
+                    full_path: selectData.full_path.replace(selectData.template_pid + '.', '')
+                };
+                await this.transaction.update(this.tableName, updateData);
+                // 选中节点--全部子节点(含孙) level-1, full_path变更
+                await this._syncUplevelChildren(selectData);
+                // 选中节点--全部后兄弟节点 收编为子节点 修改pid, order, full_path
+                await this._syncUpLevelNexts(selectData);
+                this.transaction.commit();
+            } catch (err) {
+                await this.transaction.rollback();
+                throw err;
+            }
+
+            // 查询修改的数据
+            this.initSqlBuilder();
+            this.sqlBuilder.setAndWhere('tender_id', {
+                value: tenderId,
+                operate: '='
+            });
+            this.sqlBuilder.setAndWhere('full_path', {
+                value: this.db.escape(selectData.full_path.replace(selectData.template_pid + '.', '') + '%'),
+                operate: 'Like'
+            });
+            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
+            const resultData1 = await this.db.query(sql, sqlParam);
+            const resultData2 = await this.getNextsData(tenderId, parentData.template_pid, parentData.order + 1);
+            return resultData1.concat(resultData2);
+        }
+
+        /**
+         * 降级selectData, 同步修改所有子节点
+         * @param {Object} selectData - 选中节点
+         * @param {Object} preData - 选中节点的前一节点(降级后为父节点)
+         * @returns {Promise<*>}
+         * @private
+         */
+        async _syncDownlevelChildren(selectData, preData) {
+            this.initSqlBuilder();
+            this.sqlBuilder.setAndWhere('tender_id', {
+                value: selectData.tender_id,
+                operate: '='
+            });
+            this.sqlBuilder.setAndWhere('full_path', {
+                value: this.db.escape(selectData.full_path + '.%'),
+                operate: 'like'
+            });
+            this.sqlBuilder.setUpdateData('level', {
+                value: 1,
+                selfOperate: '+'
+            });
+            this.sqlBuilder.setUpdateData('full_path', {
+                value: ['`full_path`', this.db.escape(selectData.template_id), this.db.escape(preData.template_id + '.' + selectData.template_id)],
+                literal: 'Replace'
+            });
+            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');
+            const data = this.transaction.query(sql, sqlParam);
+
+            return data;
+        }
+
+        /**
+         * 降级节点
+         *
+         * @param {Number} tenderId - 标段id
+         * @param {Number} selectId - 选中节点id
+         * @return {Array} - 发生改变的数据
+         */
+        async downLevelNode(tenderId, selectId) {
+            if ((tenderId <= 0) || (selectId <= 0)) {
+                return [];
+            }
+            const selectData = await this.getDataByNodeId(tenderId, selectId);
+            if (!selectData) {
+                throw '降级节点数据错误';
+            }
+            const preData = await this.getDataByParentAndOrder(tenderId, selectData.template_pid, selectData.order-1);
+            if (!preData) {
+                throw '节点不可降级';
+            }
+            const preLastChildData = await this.getLastChildData(tenderId, preData.template_id);
+
+            this.transaction = await this.db.beginTransaction();
+            try {
+                // 选中节点--全部后节点 order--
+                await this._updateSelectNextsOrder(selectData, -1);
+                // 选中节点 修改pid, level, order, full_path
+                const updateData = {id: selectData.id,
+                    template_pid: preData.template_pid,
+                    order: preLastChildData ? preLastChildData.order + 1 : 1,
+                    level: selectData.level + 1,
+                    full_path: selectData.full_path.replace(selectData.template_id, preData.template_id + '.' + selectData.template_id)
+                };
+                await this.transaction.update(this.tableName, updateData);
+                // 选中节点--全部子节点(含孙) level++, full_path
+                await this._syncDownlevelChildren(selectData, preData);
+                this.transaction.commit();
+            } catch (err) {
+                this.transaction.rollback();
+                throw err;
+            }
+
+            // 查询修改的数据
+            this.initSqlBuilder();
+            this.sqlBuilder.setAndWhere('tender_id', {
+                value: tenderId,
+                operate: '='
+            });
+            this.sqlBuilder.setAndWhere('full_path', {
+                value: this.db.escape(selectData.full_path.replace(selectData.template_id, preData.template_id + '.' + selectData.template_id) + '%'),
+                operate: 'Like'
+            });
+            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
+            const resultData1 = await this.db.query(sql, sqlParam);
+            const resultData2 = await this.getNextsData(tenderId, preData.template_pid, preData.order);
+            return resultData1.concat(resultData2);
         }
         }
     }
     }
 
 

+ 2 - 2
package.json

@@ -35,8 +35,8 @@
     "stop": "egg-scripts stop",
     "stop": "egg-scripts stop",
     "dev": "egg-bin dev --port 7002",
     "dev": "egg-bin dev --port 7002",
     "test": "npm run lint -- --fix && npm run test-local",
     "test": "npm run lint -- --fix && npm run test-local",
-    "test-local": "egg-bin test",
-    "test-qa": "set EGG_SERVER_ENV=qa&egg-bin test",
+    "test-local": "set EGG_SERVER_ENV=local&& egg-bin test",
+    "test-qa": "set EGG_SERVER_ENV=qa&&egg-bin test",
     "cov": "egg-bin cov",
     "cov": "egg-bin cov",
     "lint": "eslint .",
     "lint": "eslint .",
     "ci": "npm run lint && npm run cov",
     "ci": "npm run lint && npm run cov",

+ 23 - 1
test/app/lib/sql_builder.test.js

@@ -67,6 +67,10 @@ describe('test/app/lib/sql_builder.test.js', () => {
         sqlBuilder.setUpdateData('office', {
         sqlBuilder.setUpdateData('office', {
             value: 2,
             value: 2,
         });
         });
+        sqlBuilder.setUpdateData('full_path', {
+            value: ['`full_path`', app.mysql.escape('1.'), app.mysql.escape('2.')],
+            literal: 'Replace'
+        });
         sqlBuilder.setAndWhere('group_id', {
         sqlBuilder.setAndWhere('group_id', {
             value: 1,
             value: 1,
             operate: '>=',
             operate: '>=',
@@ -74,7 +78,25 @@ describe('test/app/lib/sql_builder.test.js', () => {
         const [sql, sqlParam] = sqlBuilder.build('table', 'update');
         const [sql, sqlParam] = sqlBuilder.build('table', 'update');
         const finalSql = app.mysql.format(sql, sqlParam);
         const finalSql = app.mysql.format(sql, sqlParam);
 
 
-        const matchSql = 'UPDATE `table` SET  `create_time` = `create_time` + 1, `office` = 2 WHERE  `group_id` >= 1';
+        const matchSql = "UPDATE `table` SET  `create_time` = `create_time` + 1, `office` = 2, `full_path` = Replace(`full_path`,'1.','2.') WHERE  `group_id` >= 1";
+        assert(finalSql === matchSql);
+    });
+
+    it('delete sql', function* () {
+        const sqlBuilder = new SqlBuilder();
+        sqlBuilder.setAndWhere('office', {
+            value: 2,
+            operate: '='
+        });
+        const prePath = '1.2.3';
+        sqlBuilder.setAndWhere('path', {
+            value: app.mysql.escape(prePath +'%'),
+            operate: 'Like'
+        })
+        const [sql, sqlParam] = sqlBuilder.build('table', 'delete');
+        const finalSql = app.mysql.format(sql, sqlParam);
+
+        const matchSql = "DELETE FROM `table` WHERE  `office` = 2 AND  `path` Like '1.2.3%'";
         assert(finalSql === matchSql);
         assert(finalSql === matchSql);
     });
     });
 });
 });

+ 66 - 7
test/app/service/tender_node.test.js

@@ -8,7 +8,7 @@
  */
  */
 'use strict';
 'use strict';
 
 
-/*const testNodeData = [
+/* const testNodeData = [
     { template_id: 1, template_pid: -1, order: 1, level: 1, full_path: '1', code: '1' },
     { template_id: 1, template_pid: -1, order: 1, level: 1, full_path: '1', code: '1' },
     { template_id: 2, template_pid: 1, order: 1, level: 2, full_path: '1.2', code: '1-1' },
     { template_id: 2, template_pid: 1, order: 1, level: 2, full_path: '1.2', code: '1-1' },
     { template_id: 6, template_pid: 2, order: 1, level: 3, full_path: '1.2.6', code: '1-1-1' },
     { template_id: 6, template_pid: 2, order: 1, level: 3, full_path: '1.2.6', code: '1-1-1' },
@@ -24,7 +24,7 @@
     { template_id: 4, template_pid: 1, order: 3, level: 2, full_path: '1.4', code: '1-3' },
     { template_id: 4, template_pid: 1, order: 3, level: 2, full_path: '1.4', code: '1-3' },
     { template_id: 5, template_pid: 1, order: 4, level: 2, full_path: '1.5', code: '1-4' },
     { template_id: 5, template_pid: 1, order: 4, level: 2, full_path: '1.5', code: '1-4' },
 ];*/
 ];*/
-let testNodeData = [
+const testNodeData = [
     { template_id: 1, template_pid: -1, order: 1, level: 1, full_path: '1', code: '1' },
     { template_id: 1, template_pid: -1, order: 1, level: 1, full_path: '1', code: '1' },
     { template_id: 2, template_pid: 1, order: 1, level: 2, full_path: '1.2', code: '1-1' },
     { template_id: 2, template_pid: 1, order: 1, level: 2, full_path: '1.2', code: '1-1' },
     { template_id: 6, template_pid: 2, order: 1, level: 3, full_path: '1.2.6', code: '1-1-1' },
     { template_id: 6, template_pid: 2, order: 1, level: 3, full_path: '1.2.6', code: '1-1-1' },
@@ -37,27 +37,29 @@ let testNodeData = [
     { template_id: 13, template_pid: 2, order: 2, level: 3, full_path: '1.2.13', code: '1-1-2' },
     { template_id: 13, template_pid: 2, order: 2, level: 3, full_path: '1.2.13', code: '1-1-2' },
     { template_id: 14, template_pid: 2, order: 3, level: 3, full_path: '1.2.14', code: '1-1-3' },
     { template_id: 14, template_pid: 2, order: 3, level: 3, full_path: '1.2.14', code: '1-1-3' },
     { template_id: 3, template_pid: 1, order: 2, level: 2, full_path: '1.3', code: '1-2' },
     { template_id: 3, template_pid: 1, order: 2, level: 2, full_path: '1.3', code: '1-2' },
+    { template_id: 15, template_pid: 3, order: 1, level: 3, full_path: '1.3.15', code: '1-2-1'},
     { template_id: 4, template_pid: 1, order: 3, level: 2, full_path: '1.4', code: '1-3' },
     { template_id: 4, template_pid: 1, order: 3, level: 2, full_path: '1.4', code: '1-3' },
+    { template_id: 16, template_pid: 4, order: 1, level: 3, full_path: '1.4.16', code: '1-3-1'},
     { template_id: 5, template_pid: 1, order: 4, level: 2, full_path: '1.5', code: '1-4' },
     { template_id: 5, template_pid: 1, order: 4, level: 2, full_path: '1.5', code: '1-4' },
 ];
 ];
-const testTenderId = 2;
+const testTenderId = 3;
 
 
 const { app, assert } = require('egg-mock/bootstrap');
 const { app, assert } = require('egg-mock/bootstrap');
 
 
 describe('test/app/service/tender_node.test.js', () => {
 describe('test/app/service/tender_node.test.js', () => {
     it('clear history test data', function* () {
     it('clear history test data', function* () {
         const ctx = app.mockContext();
         const ctx = app.mockContext();
-        const result = yield ctx.service.tenderNode.db.delete(ctx.service.tenderNode.tableName, {"tender_id": testTenderId});
-        assert(result.affectedRows > 0);
+        const result = yield ctx.service.tenderNode.db.delete(ctx.service.tenderNode.tableName, { tender_id: testTenderId });
+        assert(result.affectedRows >= 0);
     });
     });
 
 
     it('add test data', function* () {
     it('add test data', function* () {
         const ctx = app.mockContext();
         const ctx = app.mockContext();
-        for (let data of testNodeData) {
+        for (const data of testNodeData) {
             data.tender_id = testTenderId;
             data.tender_id = testTenderId;
         }
         }
         const result = yield ctx.service.tenderNode.db.insert(ctx.service.tenderNode.tableName, testNodeData);
         const result = yield ctx.service.tenderNode.db.insert(ctx.service.tenderNode.tableName, testNodeData);
-        assert(result.affectedRows === 14);
+        assert(result.affectedRows === testNodeData.length);
     });
     });
 
 
     it('test addNode', function* () {
     it('test addNode', function* () {
@@ -66,4 +68,61 @@ describe('test/app/service/tender_node.test.js', () => {
         const resultData = yield ctx.service.tenderNode.addNode(testTenderId, 6);
         const resultData = yield ctx.service.tenderNode.addNode(testTenderId, 6);
         assert(resultData.length === 3);
         assert(resultData.length === 3);
     });
     });
+
+    it('test deleteNode', function* () {
+        const ctx = app.mockContext();
+        // 选中202-1,删除节点
+        const resultData = yield ctx.service.tenderNode.deleteNode(testTenderId, 7);
+        assert(resultData.length === 3);
+    });
+
+    it('test upMoveNode', function* () {
+        const ctx = app.mockContext();
+        // 选中202-2-e上移
+        let resultData = yield ctx.service.tenderNode.upMoveNode(testTenderId, 12);
+        resultData.sort(function (x, y) {
+            return x.order - y.order;
+        });
+        assert(resultData.length === 2);
+        assert(resultData[0].code === '202-2-e');
+    });
+
+    it('test downMoveNode', function* () {
+        const ctx = app.mockContext();
+        // 选中202-2-e下移
+        let resultData = yield ctx.service.tenderNode.downMoveNode(testTenderId, 12);
+        resultData.sort(function (x, y) {
+            return x.order - y.order;
+        });
+        assert(resultData.length === 2);
+        assert(resultData[0].code === '202-2-c');
+    });
+
+    it('test upLevelNode', function* () {
+        const ctx = app.mockContext();
+        // 选中 1-1-2 升级
+        let resultData = yield ctx.service.tenderNode.upLevelNode(testTenderId, 13);
+        assert(resultData);
+        assert(resultData.length === 5);
+        assert(resultData[0].full_path === '1.13');
+        assert(resultData[0].template_pid === 1);
+        assert(resultData[1].template_pid === 13);
+        assert(resultData[1].full_path === '1.13.14');
+        assert(resultData[2].order === 3);
+        assert(resultData[3].order === 4);
+        assert(resultData[4].order === 5);
+    });
+
+    it('test downLevelNode', function* () {
+        const ctx = app.mockContext();
+        // 选中1-3 降级
+        let resultData = yield ctx.service.tenderNode.downLevelNode(testTenderId, 4);
+        assert(resultData.length === 3);
+        assert(resultData[0].full_path === '1.3.4');
+        assert(resultData[0].level === 3);
+        assert(resultData[0].order === 2);
+        assert(resultData[1].level === 4);
+        assert(resultData[1].full_path === '1.3.4.16');
+        assert(resultData[2].order === 4);
+    })
 });
 });