'use strict'; /** * * * @author Mai * @date * @version */ const keyPre = 'revise_bills_maxLid:'; const tidField = 'tender_id'; const lidField = 'ledger_id'; const pidField = 'ledger_pid'; const pathField = 'full_path'; module.exports = app => { class ReviseBills extends app.BaseService { /** * 构造函数 * * @param {Object} ctx - egg全局变量 * @return {void} */ constructor(ctx) { super(ctx); this.tableName = 'revise_bills'; } /** * 获取 修订 清单数据 * @param {Number}tid - 标段id * @returns {Promise} */ async getData(tid) { return await this.db.select(this.tableName, { where: {tender_id: tid} }); } /** * 获取节点数据 * @param {Number} tid - 标段id * @param {Number} lid - 标段内,台账id * @returns {Promise} */ async getDataByLid (tid, lid) { return await this.db.get(this.tableName, {tender_id: tid, ledger_id: lid}); } /** * 获取节点数据 * @param id * @returns {Promise} */ async getDataById(id) { if (id instanceof Array) { return await this.db.select(this.tableName, { where: {id: id} }); } else { return await this.db.get(this.tableName, { id: id }); } } /** * 获取最末的子节点 * @param {Number} tenderId - 标段id * @param {Number} pid - 父节点id * @return {Object} */ async getLastChildData(tid, pid) { this.initSqlBuilder(); this.sqlBuilder.setAndWhere('tender_id', { value: tid, operate: '=', }); this.sqlBuilder.setAndWhere('ledger_pid', { value: pid, operate: '=', }); this.sqlBuilder.orderBy = [['order', 'DESC']]; const [sql, sqlParam] = this.sqlBuilder.build(this.tableName); const resultData = await this.db.queryOne(sql, sqlParam); return resultData; } /** * 根据 父节点id 和 节点排序order 获取数据 * * @param {Number} tid - 标段id * @param {Number} pid - 父节点id * @param {Number|Array} order - 排序 * @return {Object|Array} - 查询结果 */ async getDataByParentAndOrder(tid, pid, order) { const result = await this.db.select(this.tableName, {where: { tender_id: tid, ledger_pid: pid, order: order }}); return order instanceof Array ? result : (result.length > 0 ? result[0] : null); } /** * 根据 父节点ID 和 节点排序order 获取全部后节点数据 * @param {Number} tid - 标段id * @param {Number} pid - 父节点id(ledger_pid) * @param {Number} order - 排序 * @return {Array} */ async getNextsData(tid, pid, order) { this.initSqlBuilder(); this.sqlBuilder.setAndWhere('tender_id', { value: tid, operate: '=', }); this.sqlBuilder.setAndWhere('ledger_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; } /** * 获取最大节点id * * @param {Number} tid - 台账id * @return {Number} * @private */ async _getMaxLid(tid) { const cacheKey = keyPre + tid; let maxId = parseInt(await this.cache.get(cacheKey)); if (!maxId) { const sql = 'SELECT Max(??) As max_id FROM ?? Where tender_id = ?'; const sqlParam = ['ledger_id', this.tableName, tid]; const queryResult = await this.db.queryOne(sql, sqlParam); maxId = queryResult.max_id || 0; this.cache.set(cacheKey, maxId, 'EX', this.ctx.app.config.cacheTime); } return maxId; } /** * 缓存最大节点id * * @param {Number} tid - 台账id * @param {Number} maxId - 当前最大节点id * @returns {Promise} * @private */ async _cacheMaxLid(tid, maxId) { this.cache.set(keyPre + tid , maxId, 'EX', this.ctx.app.config.cacheTime); } /** * 更新order * @param {Number} tid - 台账id * @param {Number} pid - 父节点id(ledger_id) * @param {Number} order - 开始更新的order * @param {Number} incre - 更新的增量 * @returns {Promise<*>} * @private */ async _updateChildrenOrder(tid, pid, order, incre = 1) { this.initSqlBuilder(); this.sqlBuilder.setAndWhere('tender_id', { value: tid, operate: '=', }); this.sqlBuilder.setAndWhere('order', { value: order, operate: '>=', }); this.sqlBuilder.setAndWhere('ledger_pid', { value: pid, operate: '=', }); this.sqlBuilder.setUpdateData('order', { value: Math.abs(incre), selfOperate: incre > 0 ? '+' : '-', }); const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update'); const data = await this.transaction.query(sql, sqlParam); return data; } /** * 新增数据(新增为selectData的后项,该方法不可单独使用) * * @param {Number} tid - 台账id * @param {uuid} rid - 修订id * @param {Object} select - 选中节点的数据 * @param {Object} data - 新增节点的初始数据 * @return {Object} - 新增结果 * @private */ async _addNodeData(tid, rid, select, data) { if (!data) { data = {}; } const maxId = await this._getMaxLid(tid); data.id = this.uuid.v4(); data.crid = rid; data.ledger_id = maxId + 1; data.ledger_pid = select.ledger_pid; data.tender_id = tid; data.level = select.level; data.order = select.order + 1; data.full_path = select.full_path.replace('.' + select.ledger_id, '.' + data.ledger_id); data.is_leaf = true; const result = await this.transaction.insert(this.tableName, data); this._cacheMaxLid(tid, maxId + 1); return result; } /** * 新增节点 * @param {Number} tid - 台账id * @param {uuid} rid - 修订id * @param {Number} lid - 清单节点id * @returns {Promise} */ async addNode(tid, rid, lid) { if (!tid || !rid || !lid) return null; const select = await this.getDataByLid(tid, lid); if (!select) { throw '新增节点数据错误'; } this.transaction = await this.db.beginTransaction(); try { await this._updateChildrenOrder(tid, select.ledger_pid, select.order+1); const newNode = await this._addNodeData(tid, rid, select); if (newNode.affectedRows !== 1) { throw '新增节点数据额错误'; } await this.transaction.commit(); this.transaction = null; } catch (err) { await this.transaction.rollback(); this.transaction = null; throw err; } const createData = await this.getDataByParentAndOrder(tid, select.ledger_pid, [select.order + 1]); const updateData = await this.getNextsData(tid, select.ledger_pid, select.order + 1); return {create: createData, update: updateData}; } /** * 上移节点 * * @param {Number} tid - 台账id * @param {Number} lid - 选中节点id * @return {Array} - 发生改变的数据 */ async upMoveNode(tid, lid) { if (!tid || !lid) return null; const select = await this.getDataByLid(tid, lid); if (!select) { throw '上移节点数据错误'; } const pre = await this.getDataByParentAndOrder(tid, select.ledger_pid, select.order - 1); if (!pre) { throw '节点不可上移'; } this.transaction = await this.db.beginTransaction(); try { const sData = await this.transaction.update(this.tableName, { id: select.id, order: select.order - 1 }); const pData = await this.transaction.update(this.tableName, { id: pre.id, order: pre.order + 1 }); await this.transaction.commit(); } catch (err) { await this.transaction.rollback(); throw err; } const resultData = await this.getDataByParentAndOrder(tid, select.ledger_pid, [select.order, pre.order]); return { update: resultData }; } /** * 下移节点 * * @param {Number} tid - 台账id * @param {Number} lid - 选中节点id * @return {Array} - 发生改变的数据 */ async downMoveNode(tid, lid) { if (!tid || !lid) return null; const select = await this.getDataByLid(tid, lid); if (!select) { throw '下移节点数据错误'; } const next = await this.getDataByParentAndOrder(tid, select.ledger_pid, select.order + 1); if (!next) { throw '节点不可下移'; } this.transaction = await this.db.beginTransaction(); try { const sData = await this.transaction.update(this.tableName, { id: select.id, order: select.order + 1 }); const pData = await this.transaction.update(this.tableName, { id: next.id, order: next.order - 1 }); await this.transaction.commit(); } catch (err) { await this.transaction.rollback(); throw err; } const resultData = await this.getDataByParentAndOrder(tid, select.ledger_pid, [select.order, next.order]); return { update: resultData }; } /** * 批量插入子项 * @param {uuid} rid - 修订id * @param {Number} lid - 节点id * @param {Object} data - 批量插入数据 * @return {Promise} */ async batchInsertChild(tid, rid, lid, data) { const result = { ledger: {}, pos: null }; if (!tid || !rid || !lid) return result; const select = await this.getDataByLid(tid, lid); if (!select) { throw '位置数据错误'; } // 计算id和order const maxId = await this._getMaxLid(tid); const lastChild = await this.getLastChildData(tid, lid); const order = lastChild ? lastChild.order : 0; // 整理数据 const bills = [], pos = [], newIds = []; for (let i = 0, iLen = data.length; i < iLen; i++) { // 合并新增数据 const qd = { crid: rid, id: this.uuid.v4(), tender_id: tid, ledger_id: maxId + i + 1, ledger_pid: select.ledger_id, is_leaf: true, order: order + i + 1, level: select.level + 1, b_code: data[i].b_code, name: data[i].name, unit: data[i].unit, unit_price: data[i].price, }; const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, bills.unit); qd.sgfh_qty = 0; for (const p of data[i].pos) { const inP = { id: this.uuid.v4(), tid: tid, lid: qd.id, crid: rid, add_stage: 0, add_times: 0, add_user: this.ctx.session.sessionUser.accountId, name: p.name, drawing_code: p.drawing_code, }; if (p.quantity) { inP.sgfh_qty = this.round(p.quantity, precision.value); inP.quantity = inP.sgfh_qty; } qd.sgfh_qty = this.ctx.helper.add(qd.sgfh_qty, inP.sgfh_qty); pos.push(inP); } qd.full_path = select.full_path + '.' + qd.ledger_id; qd.sgfh_tp = this.ctx.helper.mul(qd.sgfh_qty, qd.unit_price, this.ctx.tender.info.decimal.tp); qd.quantity = qd.sgfh_qty; qd.total_price = qd.sgfh_tp; bills.push(qd); newIds.push(qd.id); } this.transaction = await this.db.beginTransaction(); try { // 更新父项isLeaf if (!lastChild) { await this.transaction.update(this.tableName, { is_leaf: false, unit_price: null, quantity: null, total_price: null, deal_qty: null, deal_tp: null, }, {tender_id: rid, id: select.id}); } // 数据库创建新增节点数据 await this.transaction.insert(this.tableName, bills); await this.transaction.insert(this.ctx.service.revisePos.tableName, pos); this._cacheMaxLid(tid, maxId + data.length); await this.transaction.commit(); } catch (err) { await this.transaction.rollback(); throw err; } // 查询应返回的结果 result.ledger.create = await this.getDataById(newIds); if (!lastChild) { result.ledger.update = await this.getDataByLid(select.id); } result.pos = await this.ctx.service.revisePos.getDataByLid(tid, newIds); return result; } /** * 批量插入后项 * @param {Number} tid - 台账id * @param {uuid} rid - 修订id * @param {Number} lid - 节点id * @param {Object} data - 批量插入数据 * @return {Promise} */ async batchInsertNext(tid, rid, lid, data) { const result = { ledger: {}, pos: null }; if (!tid || !rid || !lid) return result; const select = await this.getDataByLid(tid, lid); if (!select) { throw '位置数据错误'; } const parentData = await this.getDataByLid(tid, select.ledger_pid); if (!parentData) { throw '位置数据错误'; } // 计算id和order const maxId = await this._getMaxLid(tid); const order = select.order; // 整理数据 const bills = [], pos = [], newIds = []; for (let i = 0, iLen = data.length; i < iLen; i++) { // 合并新增数据 const qd = { crid: rid, id: this.uuid.v4(), tender_id: tid, ledger_id: maxId + i + 1, ledger_pid: parentData.ledger_id, is_leaf: true, order: order + i + 1, level: parentData.level + 1, b_code: data[i].b_code, name: data[i].name, unit: data[i].unit, unit_price: data[i].price, }; const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, bills.unit); qd.sgfh_qty = 0; for (const p of data[i].pos) { const inP = { id: this.uuid.v4(), tid: tid, lid: qd.id, crid: rid, add_stage: 0, add_times: 0, add_user: this.ctx.session.sessionUser.accountId, name: p.name, drawing_code: p.drawing_code, }; if (p.quantity) { inP.sgfh_qty = this.round(p.quantity, precision.value); inP.quantity = inP.sgfh_qty; } qd.sgfh_qty = this.ctx.helper.add(qd.sgfh_qty, inP.sgfh_qty); pos.push(inP); } qd.full_path = parentData.full_path + '.' + qd.ledger_id; qd.sgfh_tp = this.ctx.helper.mul(qd.sgfh_qty, qd.unit_price, this.ctx.tender.info.decimal.tp); qd.quantity = qd.sgfh_qty; qd.total_price = qd.sgfh_tp; bills.push(qd); newIds.push(qd.id); } this.transaction = await this.db.beginTransaction(); try { // 选中节点的所有后兄弟节点,order+粘贴节点个数 await this._updateChildrenOrder(tid, select.ledger_pid, select.order+1); // 数据库创建新增节点数据 await this.transaction.insert(this.tableName, bills); await this.transaction.insert(this.ctx.service.revisePos.tableName, pos); this._cacheMaxLid(tid, maxId + data.length); await this.transaction.commit(); } catch (err) { await this.transaction.rollback(); throw err; } // 查询应返回的结果 result.ledger.create = await this.getDataById(newIds); result.ledger.update = await this.getNextsData(select.tender_id, select.ledger_pid, select.order + data.length); result.pos = await this.ctx.service.revisePos.getDataByLid(tid, newIds); return result; } } return ReviseBills; };