| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766 | 'use strict';/** * 标段--台账 数据模型 * * @author CaiAoLin * @date 2017/12/1 * @version */const needField = {    id: 'ledger_id',    pid: 'ledger_pid',    order: 'order',    level: 'level',    fullPath: 'full_path',    isLeaf: 'is_leaf',};const keyFields = {    table: ['id'],    index: ['tender_id', 'ledger_id'],};// 以下字段仅可通过树结构操作改变,不可直接通过update方式从接口提交,发现时过滤const readOnlyFields = ['id', 'tender_id', 'ledger_id', 'ledger_pid', 'order', 'level', 'full_path', 'is_leaf'];const calcFields = ['quantity', 'unit_price', 'total_price'];const zeroRange = 0.0000000001;const rootId = -1;const keyPre = 'tender_node_maxId:';module.exports = app => {    class Ledger extends app.BaseService {        /**         * 构造函数         *         * @param {Object} ctx - egg全局变量         * @return {void}         */        constructor(ctx) {            super(ctx);            this.tableName = 'ledger';        }        /**         * 新增数据(供内部或其他service类调用, controller不可直接使用)         * @param {Array|Object} data - 新增数据         * @param {Number} tenderId - 标段id         * @param {Object} transaction - 新增事务         * @returns {Promise<boolean>} - {Promise<是否正确新增成功>}         */        async innerAdd(data, tenderId, transaction) {            const datas = data instanceof Array ? data : [data];            if (tenderId <= 0) {                throw '标段id错误';            }            if (datas.length <= 0) {                throw '插入数据为空';            }            if (!transaction) {                throw '内部错误';            }            // 整理数据            const insertData = [];            for (const tmp of datas) {                tmp.ledger_id = tmp.id;                tmp.ledger_pid = tmp.pid;                tmp.tender_id = tenderId;                delete tmp.id;                delete tmp.pid;                insertData.push(tmp);            }            const operate = await transaction.insert(this.tableName, insertData);            return operate.affectedRows === datas.length;        }        /**         * 新增数据         *         * @param {Object} data - 新增的数据(可批量)         * @param {Number} tenderId - 标段id         * @return {Boolean} - 返回新增的结果         */        async add(data, tenderId) {            this.transaction = await this.db.beginTransaction();            let result = false;            try {                result = await this.innerAdd(data, tenderId, this.transaction);                if (!result) {                    throw '新增数据错误';                }                await this.transaction.commit();            } catch (error) {                await this.transaction.rollback();                result = false;            }            return result;        }        /**         * 根据层级获取数据         *         * @param {Number} tenderId - 标段id         * @param {Number} showLevel - 显示层数         * @return {Array} - 返回数据         */        async getDataByTenderId(tenderId, showLevel = 4) {            if (tenderId <= 0) {                return [];            }            this.initSqlBuilder();            this.sqlBuilder.setAndWhere('tender_id', {                value: tenderId,                operate: '=',            });            if (showLevel > 0) {                this.sqlBuilder.setAndWhere('level', {                    value: showLevel,                    operate: '<=',                });            }            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);            const data = await this.db.query(sql, sqlParam);            return data;        }        /**         * 根据节点Id获取数据         *         * @param {Number} tenderId - 标段id         * @param {Number} nodeId - 项目节/工程量清单节点id         * @return {Object} - 返回查询到的节点数据         */        async getDataByNodeId(tenderId, nodeId) {            if ((nodeId <= 0) || (tenderId <= 0)) {                return undefined;            }            this.initSqlBuilder();            this.sqlBuilder.setAndWhere('tender_id', {                value: tenderId,                operate: '=',            });            this.sqlBuilder.setAndWhere('ledger_id', {                value: nodeId,                operate: '=',            });            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);            const data = await this.db.queryOne(sql, sqlParam);            return data;        }        /**         * 根据节点Id获取数据         * @param {Number} tenderId - 标段Id         * @param {Array} nodesIds - 节点Id         * @return {Array}         */        async getDataByNodeIds(tenderId, nodesIds) {            if (tenderId <= 0) {                return [];            }            this.initSqlBuilder();            this.sqlBuilder.setAndWhere('tender_id', {                value: tenderId,                operate: '=',            });            this.sqlBuilder.setAndWhere('ledger_id', {                value: nodesIds,                operate: 'in',            });            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);            const data = await this.db.query(sql, sqlParam);            return data;        }        /**         * 根据主键id获取数据         * @param {Array|Number} id - 主键id         * @returns {Promise<*>}         */        async getDataByIds(id) {            const ids = id instanceof Array ? id : [id];            this.initSqlBuilder();            this.sqlBuilder.setAndWhere('id', {                value: ids,                operate: 'in',            });            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);            const data = await this.db.query(sql, sqlParam);            return data;        }        /**         * 根据标准清单源检索         * @param tenderId         * @param source         * @returns {Promise<*>}         */        async getDataBySource(tenderId, source) {            this.initSqlBuilder();            this.sqlBuilder.setAndWhere('tender_id', {                value: tenderId,                operate: '=',            });            this.sqlBuilder.setAndWhere('source', {                value: source,                operate: '=',            });            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);            const data = await this.db.query(sql, sqlParam);            return data;        }        /**         * 获取最末的子节点         * @param {Number} tenderId - 标段id         * @param {Number} pid - 父节点id         * @return {Object}         */        async getLastChildData(tenderId, pid) {            this.initSqlBuilder();            this.sqlBuilder.setAndWhere('tender_id', {                value: tenderId,                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} tenderId - 标段id         * @param {Number} pid - 父节点id         * @param {Number|Array} order - 排序         * @return {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('ledger_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 获取子节点         * @param tenderId         * @param nodeId         * @return {Promise<*>}         */        async getChildrenByParentId(tenderId, nodeId) {            if (tenderId <= 0 || !nodeId) {                return undefined;            }            const nodeIds = nodeId instanceof Array ? nodeId : [nodeId];            if (nodeIds.length === 0) {                return [];            }            this.initSqlBuilder();            this.sqlBuilder.setAndWhere('tender_id', {                value: tenderId,                operate: '=',            });            this.sqlBuilder.setAndWhere('ledger_pid', {                value: nodeIds,                operate: 'in',            });            this.sqlBuilder.orderBy = [['order', 'ASC']];            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);            const data = await this.db.query(sql, sqlParam);            return data;        }        /**         * 根据 父节点id 获取孙子节点         * @param tenderId         * @param nodeId         * @returns {Promise<void>}         */        async getPosterityByParentId(tenderId, nodeId) {            if (tenderId <= 0 || !nodeId) {                return undefined;            }            const node = await this.getDataByNodeId(tenderId, nodeId);            this.initSqlBuilder();            this.sqlBuilder.setAndWhere('tender_id', {                value: tenderId,                operate: '=',            });            this.sqlBuilder.setAndWhere('full_path', {                value: this.db.escape(node.full_path + '.%'),                operate: 'like',            });            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);            const data = await this.db.query(sql, sqlParam);            return data;        }        /**         * 根据 父节点ID 和 节点排序order 获取全部后节点数据         * @param {Number} tenderId - 标段id         * @param {Number} pid - 父节点id         * @param {Number} order - 排序         * @return {Array}         */        async getNextsData(tenderId, pid, order) {            if ((tenderId <= 0) || (order < 0)) {                return undefined;            }            this.initSqlBuilder();            this.sqlBuilder.setAndWhere('tender_id', {                value: tenderId,                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;        }        /**         * 根据full_path获取数据 full_path Like ‘1.2.3%’(传参full_path = '1.2.3%')         * @param {Number} tenderId - 标段id         * @param {String} full_path - 路径         * @return {Promise<void>}         */        async getDataByFullPath(tenderId, full_path) {            this.initSqlBuilder();            this.sqlBuilder.setAndWhere('tender_id', {                value: tenderId,                operate: '=',            });            this.sqlBuilder.setAndWhere('full_path', {                value: this.db.escape(full_path),                operate: 'Like',            });            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);            const resultData = await this.db.query(sql, sqlParam);            return resultData;        }        /**         * 根据full_path检索自己及所有父项         * @param {Number} tenderId - 标段id         * @param {Array|String} fullPath - 节点完整路径         * @returns {Promise<*>}         * @private         */        async getFullLevelDataByFullPath(tenderId, fullPath) {            const explodePath = this.ctx.helper.explodePath(fullPath);            this.initSqlBuilder();            this.sqlBuilder.setAndWhere('tender_id', {                value: tenderId,                operate: '=',            });            this.sqlBuilder.setAndWhere('full_path', {                value: explodePath,                operate: 'in'            });            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);            const data = await this.db.query(sql, sqlParam);            return data;        };        /**         * 获取sql条件语句片段,仅供search、searchRange方法使用         * @param {Object} where - 条件参数         * @returns {*[]}         * e.g.         * where = {type: 'And', value: 'A', operate: '=', fields: ['code', 'name']}         * return [sql: 'And (?? = \'A\' Or ?? = \'A\')', sqlParam: ['code', name]]         * @private         */        _getWhereString(where) {            const sqlParam = [], sqlPart = [];            const values = where.value instanceof Array ? where.value : [where.value];            const fields = where.fields instanceof Array ? where.fields : [where.fields];            for (const field of fields) {                for (const v of values) {                    sqlPart.push('?? ' + where.operate + ' ' + v);                    sqlParam.push(field);                }            }            const sql = ' ' + (where.type ? where.type : 'And') + ' (' + sqlPart.join(' OR ') + ')';            return [sql, sqlParam];        }        /**         * 搜索台账         *         * @param {Number} tenderId - 标段id         * @param {Object} key - 查询信息         * @returns {Promise<void>}         */        async search(tenderId, key) {            let sql = 'Select * From ?? Where';            let sqlParam = [this.tableName];            sql = sql + ' ?? = ' + tenderId;            sqlParam.push('tender_id');            const [sql1, sqlParam1] = this._getWhereString(key);            sql = sql + sql1;            sqlParam = sqlParam.concat(sqlParam1);            return this.db.query(sql, sqlParam);        }        /**         * 范围内搜索台账         *         * @param {Number} tenderId - 标段id         * @param {Object} key - 查询信息         * @param {Array} range - 查询范围         * @returns {Promise<void>}         */        async searchRange(tenderId, key, range) {            let sql = 'Select * From ?? Where';            let sqlParam = [this.tableName];            sql = sql + ' ?? = ' + tenderId;            sqlParam.push('tender_id');            let [sql1, sqlParam1] = this._getWhereString(key);            sql = sql + sql1;            sqlParam = sqlParam.concat(sqlParam1);            for (const r of range) {                [sql1, sqlParam1] = this._getWhereString(r);                sql = sql + sql1;                sqlParam = sqlParam.concat(sqlParam1);            }            return this.db.query(sql, sqlParam);        }        /**         * 统计子节点total_price         * @param {Number} tenderId - 标段id         * @param {Number} pid - 父节点id         * @param {Number} order - order取值         * @param {String} orderOperate - order比较操作符         * @returns {Promise<void>}         */        async addUpChildren(tenderId, pid, order, orderOperate) {            this.initSqlBuilder();            const sql = ['SELECT SUM(??) As value FROM ?? ', ' WHERE ']            const sqlParam = ['total_price', this.tableName];            sql.push(' ?? = ' + tenderId);            sqlParam.push('tender_id');            sql.push(' And ?? = ' + pid);            sqlParam.push('ledger_pid');            sql.push(' And ?? ' + orderOperate + ' ' + order);            sqlParam.push('order');            const result = await this.db.queryOne(sql.join(''), sqlParam);            return result.value;        }        /**         * 更新order         * @param {Number} tenderId - 标段id         * @param {Number} parentId - 父节点id         * @param {Number} order - 自增起始order(含)         * @param {Number} incre - 自增量         * @returns {Promise<*>}         * @private         */        async _updateChildrenOrderAfter(tenderId, parentId, order, incre = 1) {            this.initSqlBuilder();            this.sqlBuilder.setAndWhere('tender_id', {                value: tenderId,                operate: '='            });            this.sqlBuilder.setAndWhere('order', {                value: order,                operate: '>=',            });            this.sqlBuilder.setAndWhere('ledger_pid', {                value: parentId,                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;        }        /**         *  select的全部后兄弟节点,Order自增         *         * @param {Object} select - 选中的节点         * @param {Number} incre - 自增值         * @return {Array} - 自增后的数据         * @private         */        async _updateSelectNextsOrder(select, incre = 1) {            return await this._updateChildrenOrderAfter(select.tender_id, select.ledger_pid, select.order + 1, incre);        }        /**         * 从数据库获取标段的最大节点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 = ['ledger_id', this.tableName];            const queryResult = await this.db.queryOne(sql, sqlParam);            return queryResult.max_id;        }        /**         * 根据selectData, data 新增数据(新增为selectData的后项,该方法不可单独使用)         *         * @param {Number} tenderId - 标段id         * @param {Object} selectData - 选中节点的数据         * @param {Object} data - 新增节点的初始数据         * @return {Object} - 新增结果         * @private         */        async _addNodeData(tenderId, selectData, data) {            if (tenderId <= 0) {                return undefined;            }            if (!data) {                data = {};            }            const cacheKey = keyPre + 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.ledger_id = maxId + 1;            data.ledger_pid = selectData.ledger_pid;            data.level = selectData.level;            data.order = selectData.order + 1;            data.full_path = selectData.full_path.replace('.' + selectData.ledger_id, '.' + data.ledger_id);            data.is_leaf = true;            const result = await this.transaction.insert(this.tableName, data);            this.cache.set(cacheKey, maxId + 1, 'EX', this.ctx.app.config.cacheTime);            return result;        }        /**         * 根据parentData, data新增数据(新增为parentData的最后一个子项)         * @param {Number} tenderId - 标段id         * @param {Object} parentData - 父项数据         * @param {Object} data - 新增节点,初始数据         * @returns {Promise<*>} - 新增结果         * @private         */        async _addChildNodeData(tenderId, parentData, data) {            if (tenderId <= 0) {                return undefined;            }            if (!data) {                data = {};            }            const pid = parentData ? parentData.ledger_id : rootId;            const cacheKey = keyPre + tenderId;            let maxId = parseInt(await this.cache.get(cacheKey));            if (!maxId) {                maxId = await this._getMaxNodeId(tenderId);            }            this.cache.set(cacheKey, maxId + 1, 'EX', this.ctx.app.config.cacheTime);            data.tender_id = tenderId;            data.ledger_id = maxId + 1;            data.ledger_pid = pid;            if (data.order === undefined) {                data.order = 1;            }            data.level = parentData ? parentData.level + 1 : 1;            data.full_path = parentData ? parentData.full_path + '.' + data.ledger_id : '' + data.ledger_id;            if (data.is_leaf === undefined) {                data.is_leaf = true;            }            const result = await this.transaction.insert(this.tableName, data);            return [result, data];        }        /**         * 根据parentData, data新增数据(自动排序)         * @param tenderId         * @param parentData         * @param data         * @returns {Promise<void>}         * @private         */        async _addChildAutoOrder(tenderId, parentData, data) {            const self = this;            const findPreData = function (list, a) {                if (!list || list.length === 0) { return null; }                for (let i = 0, iLen = list.length; i < iLen; i++) {                    if (self.ctx.helper.compareCode(list[i].code, a.code) > 0) {                        return i > 0 ? list[i-1] : null;                    }                }                return list[list.length -1];            }            const pid = parentData ? parentData.ledger_id : rootId;            const children = await this.getChildrenByParentId(tenderId, pid);            const preData = findPreData(children, data);            let parent = null;            if (!preData || children.indexOf(preData) < children.length - 1) {                await this._updateChildrenOrderAfter(tenderId, pid, preData ? preData.order + 1 : 1);            }            data.order = preData ? preData.order + 1 : 1;            const [addResult, node] = await this._addChildNodeData(tenderId, parentData, data);            return [addResult, node];        }        /**         * tenderId标段中, 在selectId后新增一个节点         *         * @param {Number} tenderId - 标段id         * @param {Number} selectId - 选中节点id         * @param {Object} data - 新增节点初始化数据         * @return {Array} 新增后的数据,其他被修改的数据         */        async addNode(tenderId, selectId, data) {            if ((tenderId <= 0) || (selectId <= 0)) {                return [];            }            const selectData = await this.getDataByNodeId(tenderId, selectId);            if (!selectData) {                throw '新增节点数据错误';            }            if (!this.transaction) {                this.transaction = await this.db.beginTransaction();            }            try {                // 选中节点的所有后兄弟节点,order+1                await this._updateSelectNextsOrder(selectData);                // 数据库创建新增节点数据                const newNode = await this._addNodeData(tenderId, selectData, data);                if (!newNode) { throw '新增节点数据错误'; }                await this.transaction.commit();            } catch (err) {                await this.transaction.rollback();                this.transaction = null;                throw err;            }            this.transaction = null;            // 查询应返回的结果            const createData = await this.getDataByParentAndOrder(selectData.tender_id, selectData.ledger_pid, [selectData.order + 1]);            const updateData = await this.getNextsData(selectData.tender_id, selectData.ledger_pid, selectData.order + 1);            return { create: createData, update: updateData };        }        /**         * 从标准数据中提取有效数据         * @param {Object} stdData - 从标准库中查询所得         * @returns {name, unit, source, code, b_code}         * @private         */        _filterStdData(stdData) {            const result = {                name: stdData.name,                unit: stdData.unit,                source: stdData.source            }            result.code = stdData.code ? stdData.code : '';            result.b_code = stdData.b_code ? stdData.b_code : '';            return result;        }        /**         * 添加节点(来自标准清单)         * @param {Number} tenderId         * @param {Number} selectId         * @param {Object} stdData         * @returns {Promise<*>}         */        async addStdNode(tenderId, selectId, stdData) {            const newData = this._filterStdData(stdData);            const result = await this.addNode(tenderId, selectId, newData);            return result;        }        /**         * 添加节点,并同步添加父节点         * @param {Number} tenderId - 标段id         * @param {Number} selectId - 选中节点id         * @param {Object} stdData - 节点数据         * @param {StandardLib} stdLib - 标准库         * @returns {Promise<void>}         */        async addStdNodeWithParent(tenderId, stdData, stdLib) {            const fullLevel = await stdLib.getFullLevelDataByFullPath(stdData.list_id, stdData.full_path);            fullLevel.sort(function (x, y) {                return x.level - y.level            });            let isNew = false, node, firstNew, updateParent, addResult;            const expandIds = [];            this.transaction = await this.db.beginTransaction();            try {                for (let i = 0, len = fullLevel.length; i < len; i++) {                    const stdNode = fullLevel[i];                    if (isNew) {                        const newData = this._filterStdData(stdNode);                        newData.is_leaf = (i === len - 1);                        [addResult, node] = await this._addChildNodeData(tenderId, node, newData);                    } else {                        const parent = node;                        node = await this.getDataByCondition({                            tender_id: tenderId,                            ledger_pid: parent ? parent.ledger_id : rootId,                            code: stdNode.code,                            name: stdNode.name                        });                        if (!node) {                            isNew = true;                            const newData = this._filterStdData(stdNode);                            newData.is_leaf = (i === len - 1);                            [addResult, node] = await this._addChildAutoOrder(tenderId, parent, newData);                            if (parent && parent.is_leaf) {                                await this.transaction.update(this.tableName, {id: parent.id, is_leaf: false} );                                updateParent = parent;                            }                            firstNew = node;                        } else {                            expandIds.push(node.ledger_id);                        }                    }                }                await this.transaction.commit();            } catch (err) {                await this.transaction.rollback();                throw err;            }            // 查询应返回的结果            let createData = [], updateData = [];            if (firstNew) {                createData = await this.getDataByFullPath(tenderId, firstNew.full_path + '%');                updateData = await this.getNextsData(tenderId, firstNew.ledger_pid, firstNew.order);                if (updateParent) {                    updateData.push(await this.getDataByCondition({id: updateParent.id}));                }            }            const expandData = await this.getChildrenByParentId(tenderId, expandIds);            return { create: createData, update: updateData, expand: expandData };        }        /**         * 删除节点         * @param {Number} tenderId - 标段id         * @param {Object} deleteData - 删除节点数据         * @returns {Promise<*>}         * @private         */        async _deleteNodeData(tenderId, deleteData) {            this.initSqlBuilder();            this.sqlBuilder.setAndWhere('tender_id', {                value: tenderId,                operate: '=',            });            this.sqlBuilder.setAndWhere('full_path', {                value: this.db.escape(deleteData.full_path + '%'),                operate: 'Like',            });            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'delete');            const result = await this.transaction.query(sql, sqlParam);            return result;        }        /**         *  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);            if (!selectData) {                throw '删除节点数据错误';            }            const parentData = await this.getDataByNodeId(tenderId, selectData.ledger_pid);            this.transaction = await this.db.beginTransaction();            let deleteData = [];            try {                // 获取将要被删除的数据                deleteData = await this.getDataByFullPath(tenderId, selectData.full_path + '%');                // 删除                const operate = await this._deleteNodeData(tenderId, selectData);                // 选中节点--父节点 只有一个子节点时,应升级is_leaf                if (parentData) {                    const count = await this.db.count(this.tableName, { tender_id: tenderId, ledger_pid: selectData.ledger_pid });                    if (count === 1) {                        await this.transaction.update(this.tableName, { id: parentData.id, is_leaf: true });                    }                }                // 选中节点--全部后节点 order--                await this._updateSelectNextsOrder(selectData, -1);                // 删除部位明细                await this.transaction.delete(this.ctx.service.pos.tableName, {tid: tenderId, lid: this._.map(deleteData, 'id')});                await this.ctx.service.pos.deletePosData(this.transaction, tenderId, this._.map(deleteData, 'id'));                await this.transaction.commit();            } catch (err) {                deleteData = [];                await this.transaction.rollback();                throw err;            }            // 查询结果            let updateData = [];            if (deleteData.length > 0) {                updateData = await this.getNextsData(tenderId, selectData.ledger_pid, selectData.order - 1);                updateData = updateData ? updateData : [];                if (selectData.ledger_pid !== rootId) {                    const updateData1 = await this.getDataByNodeId(tenderId, selectData.ledger_pid);                    if (updateData1.is_leaf !== parentData.is_leaf) {                        updateData.push(updateData1);                    }                }            }            return { delete: deleteData, update: updateData };        }        /**         * 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);            if (!selectData) {                throw '上移节点数据错误';            }            const preData = await this.getDataByParentAndOrder(tenderId, selectData.ledger_pid, selectData.order - 1);            if (!preData) {                throw '节点不可上移';            }            this.transaction = await this.db.beginTransaction();            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 });                await this.transaction.commit();            } catch (err) {                await this.transaction.rollback();                throw err;            }            const resultData = await this.getDataByParentAndOrder(tenderId, selectData.ledger_pid, [selectData.order, preData.order]);            return { update: resultData };        }        /**         * 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);            if (!selectData) {                throw '下移节点数据错误';            }            const nextData = await this.getDataByParentAndOrder(tenderId, selectData.ledger_pid, selectData.order + 1);            if (!nextData) {                throw '节点不可下移';            }            this.transaction = await this.db.beginTransaction();            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 });                await this.transaction.commit();            } catch (err) {                await this.transaction.rollback();                throw err;            }            const resultData = await this.getDataByParentAndOrder(tenderId, selectData.ledger_pid, [selectData.order, nextData.order]);            return { update: resultData };        }        /**         * 升级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.ledger_pid + '.'), this.db.escape('')],                literal: 'Replace',            });            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');            const data = await 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.ledger_id);            const nextsData = await this.getNextsData(selectData.tender_id, selectData.ledger_pid, selectData.order);            if (nextsData && nextsData.length > 0) {                // 修改nextsData pid, 排序                this.initSqlBuilder();                this.sqlBuilder.setUpdateData('ledger_pid', {                    value: selectData.ledger_id,                });                const orderInc = lastChildData ? lastChildData.order - selectData.order : -selectData.order;                this.sqlBuilder.setUpdateData('order', {                    value: Math.abs(orderInc),                    selfOperate: orderInc > 0 ? '+' : '-',                });                this.sqlBuilder.setAndWhere('ledger_pid', {                    value: selectData.ledger_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);                // 选中节点 is_leaf应为false                if (selectData.is_leaf) {                    const updateData = { id: selectData.id,                        is_leaf: false,                    };                    await this.transaction.update(this.tableName, updateData);                }                // 修改nextsData及其子节点的full_path                const oldSubStr = this.db.escape(selectData.ledger_pid + '.');                const newSubStr = this.db.escape(selectData.ledger_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.ledger_pid);            if (!parentData) {                throw '升级节点数据错误';            }            this.transaction = await this.db.beginTransaction();            const newFullPath = selectData.full_path.replace(selectData.ledger_pid + '.', '');            try {                // 选中节点--父节点 选中节点为firstChild时,修改is_leaf                if (selectData.order === 1) {                    await this.transaction.update(this.tableName, {                        id: parentData.id,                        is_leaf: true                    });                }                // 选中节点--父节点--全部后兄弟节点 order+1                await this._updateSelectNextsOrder(parentData);                // 选中节点 修改pid, order, full_path                const updateData = { id: selectData.id,                    ledger_pid: parentData.ledger_pid,                    order: parentData.order + 1,                    level: selectData.level - 1,                    full_path: newFullPath                };                await this.transaction.update(this.tableName, updateData);                // 选中节点--全部子节点(含孙) level-1, full_path变更                await this._syncUplevelChildren(selectData);                // 选中节点--全部后兄弟节点 收编为子节点 修改pid, order, full_path                await this._syncUpLevelNexts(selectData);                await this.transaction.commit();            } catch (err) {                await this.transaction.rollback();                throw err;            }            // 查询修改的数据            const resultData1 = await this.getDataByFullPath(tenderId, newFullPath + '%');            const resultData2 = await this.getNextsData(tenderId, parentData.ledger_pid, parentData.order + 1);            // 默认原Parent被刷新过,不核对total_price修改            const preParent = await this.getDataByNodeId(tenderId, parentData.ledger_id);            resultData2.push(preParent);            return { update: resultData1.concat(resultData2) };        }        /**         * 降级selectData, 同步修改所有子节点         * @param {Object} selectData - 选中节点         * @param {Object} preData - 选中节点的前一节点(降级后为父节点)         * @return {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.ledger_id), this.db.escape('.' + preData.ledger_id + '.' + selectData.ledger_id)],                literal: 'Replace',            });            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');            const data = await 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.ledger_pid, selectData.order - 1);            if (!preData) {                throw '节点不可降级';            }            const preLastChildData = await this.getLastChildData(tenderId, preData.ledger_id);            this.transaction = await this.db.beginTransaction();            const orgLastPath = selectData.level === 1 ? selectData.ledger_id : '.' + selectData.ledger_id;            const newLastPath = selectData.level === 1 ? preData.ledger_id + '.' + selectData.ledger_id : '.' + preData.ledger_id + '.' + selectData.ledger_id;            const newFullPath = selectData.full_path.replace(orgLastPath, newLastPath);            try {                // 选中节点--全部后节点 order--                await this._updateSelectNextsOrder(selectData, -1);                // 选中节点 修改pid, level, order, full_path                const updateData = {                    id: selectData.id,                    ledger_pid: preData.ledger_id,                    order: preLastChildData ? preLastChildData.order + 1 : 1,                    level: selectData.level + 1,                    full_path: newFullPath,                };                await this.transaction.update(this.tableName, updateData);                // 选中节点--全部子节点(含孙) level++, full_path                await this._syncDownlevelChildren(selectData, preData);                // 选中节点--前兄弟节点 is_leaf应为false                if (preData.is_leaf) {                    const updateData2 = {                        id: preData.id,                        is_leaf: false                    };                    await this.transaction.update(this.tableName, updateData2);                }                await this.transaction.commit();            } catch (err) {                await this.transaction.rollback();                throw err;            }            // 查询修改的数据            // 选中节点及子节点            const resultData1 = await this.getDataByFullPath(tenderId, newFullPath + '%');            // 选中节点--原前兄弟节点&全部后兄弟节点            const queryOrder = (preData.is_leaf || this.ctx.helper.checkZero(selectData.total_price)) ? preData.order - 1 : preData.order;            const resultData2 = await this.getNextsData(tenderId, preData.ledger_pid, queryOrder);            return { update: resultData1.concat(resultData2) };        }        /**         * 过滤data中update方式不可提交的字段         * @param {Number} id - 主键key         * @param {Object} data         * @return {Object<{id: *}>}         * @private         */        _filterUpdateInvalidField(id, data) {            const result = {                id,            };            for (const prop in data) {                if (readOnlyFields.indexOf(prop) === -1) {                    result[prop] = data[prop];                }            }            return result;        }         /**         * newData中,以orgData为基准,过滤掉orgData中未定义或值相等的部分         * @param {Object} orgData         * @param {Object} newData         * @private         */        _filterChangedField(orgData, newData) {            const result= {};            let bChanged = false;            for (const prop in orgData) {                if (newData[prop] && newData[prop] !== orgData[prop]) {                    result[prop] = newData[prop];                    bChanged = true;                }            }            return bChanged ? result : undefined;        }        /**         * 检查data中是否含有计算字段         * @param {Object} data         * @returns {boolean}         * @private         */        _checkCalcField(data) {            for (const prop in data) {                if (calcFields.indexOf(prop) >= 0) {                    return true;                }            }            return false;        }        /**         * 提交数据 - 不影响计算等未提交项         * @param {Number} tenderId - 标段id         * @param {Object} data - 提交数据         * @return {Object} - 提交后的数据         */        async updateInfo(tenderId, data) {            // 简单校验数据            if (tenderId <= 0) {                throw '标段不存在';            }            if (tenderId !== data.tender_id) {                throw '提交数据错误';            }            try {                // 过滤不可提交字段                const updateNode = await this.getDataById(data.id);                if (!updateNode || tenderId !== updateNode.tender_id || data.ledger_id !== updateNode.ledger_id) {                    throw '提交数据错误';                }                const updateData = this._filterUpdateInvalidField(updateNode.id, data);                await this.db.update(this.tableName, updateData);            } catch (err) {                throw err;            }            const result = await this.getDataByNodeId(tenderId, data.ledger_id);            return result;        }        /**         * 提交多条数据 - 不影响计算等未提交项         * @param {Number} tenderId - 标段id         * @param {Array} datas - 提交数据         * @return {Array} - 提交后的数据         */        async updateInfos(tenderId, datas) {            if (tenderId <= 0) {                throw '标段不存在';            }            for (const data of datas) {                if (tenderId !== data.tender_id) {                    throw '提交数据错误';                }            }            this.transaction = await this.db.beginTransaction();            try {                for (const data of datas) {                    const updateNode = await this.getDataById(data.id);                    if (!updateNode || tenderId !== updateNode.tender_id || data.ledger_id !== updateNode.ledger_id) {                        throw '提交数据错误';                    }                    const updateData = this._filterUpdateInvalidField(updateNode.id, data);                    await this.transaction.update(this.tableName, updateData);                }                await this.transaction.commit();            } catch (err) {                await this.transaction.rollback();                throw err;            }            const filter = [];            for (const data of datas) {                filter.push(data.id);            }            this.initSqlBuilder();            this.sqlBuilder.setAndWhere('id', {                value: filter,                operate: 'in',            });            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);            const resultData = await this.db.query(sql, sqlParam);            return resultData;        }        /**         * 复制粘贴整块         * @param {Number} tenderId - 标段Id         * @param {Number} selectId - 选中几点Id         * @param {Array} block - 复制节点Id         * @return {Object} - 提价后的数据(其中新增粘贴数据,只返回第一层)         */        async pasteBlock(tenderId, selectId, block) {            if ((tenderId <= 0) || (selectId <= 0)) {                return [];            }            const selectData = await this.getDataByNodeId(tenderId, selectId);            if (!selectData) {                throw '位置数据错误';            }            const newParentPath = selectData.full_path.replace(selectData.ledger_id, '');            const copyNodes = await this.getDataByNodeIds(tenderId, block);            if (!copyNodes || copyNodes.length <= 0) {                throw '复制数据错误';            }            let bSameParent = true;            for (const node of copyNodes) {                if (node.ledger_pid !== copyNodes[0].ledger_pid) {                    bSameParent = false;                    break;                }            }            if (!bSameParent) {                throw '复制数据错误:仅可操作同层节点';            }            const orgParentPath = copyNodes[0].full_path.replace(copyNodes[0].ledger_id, '');            const newIds = [];            this.transaction = await this.db.beginTransaction();            try {                // 选中节点的所有后兄弟节点,order+粘贴节点个数                await this._updateSelectNextsOrder(selectData, copyNodes.length);                // 数据库创建新增节点数据                for (const node of copyNodes) {                    const datas = await this.getDataByFullPath(tenderId, node.full_path + '%');                    const cacheKey = keyPre + tenderId;                    let maxId = parseInt(await this.cache.get(cacheKey));                    if (!maxId) {                        maxId = await this._getMaxNodeId(tenderId);                    }                    this.cache.set(cacheKey, maxId + datas.length, 'EX', this.ctx.app.config.cacheTime);                    const leafBillsId = [];                    // 计算粘贴数据中需更新部分                    for (let index = 0; index < datas.length; index++) {                        const data = datas[index];                        const newId = maxId + index + 1;                        const idChange = {                            org: data.id,                        }                        delete data.id;                        if (!data.is_leaf) {                            for (const children of datas) {                                children.full_path = children.full_path.replace('.' + data.ledger_id, '.' + newId);                                if (children.ledger_pid === data.ledger_id) {                                    children.ledger_pid = newId;                                }                            }                        } else {                            data.full_path = data.full_path.replace('.' + data.ledger_id, '.' + newId);                        }                        data.ledger_id = newId;                        data.full_path = data.full_path.replace(orgParentPath, newParentPath);                        if (data.ledger_pid === copyNodes[0].ledger_pid) {                            data.ledger_pid = selectData.ledger_pid;                            data.order = selectData.order + index + 1;                        }                        data.level = data.level + selectData.level - copyNodes[0].level;                        const newData = await this.transaction.insert(this.tableName, data);                        if (data.is_leaf) {                            idChange.new = newData.insertId;                            leafBillsId.push(idChange);                        }                        newIds.push(newData.insertId);                    }                    for (const id of leafBillsId) {                        await this.ctx.service.pos.copyBillsPosData(id.org, id.new, this.transaction);                    }                }                await this.transaction.commit();            } catch (err) {                console.log(err);                await this.transaction.rollback();                throw err;            }            // 查询应返回的结果            const order = [];            for (let i = 1; i <= copyNodes.length; i++) {                order.push(selectData.order + i);            }            const createData = await this.getDataByIds(newIds);            const updateData = await this.getNextsData(selectData.tender_id, selectData.ledger_pid, selectData.order + copyNodes.length);            const posData = await this.ctx.service.pos.getPosData({lid: newIds});            return {                ledger: { create: createData, update: updateData },                pos: posData,            };        }        /**         * 增量更新父项金额         * @param {Number} tenderId - 标段id         * @param {Object} updateMap - 增量更新数,使用更新父项的full_path为索引         *        e.g: {'1.2.6.8': 30, '1.2.6.10': 40}表示'1.2.6.8'增量30,'1.2.6.10'增量40(此处同步更新'1.2.6', '1.2', '1')         * @returns {Promise<void>}         * @private         */        async _increCalcParent(tenderId, updateMap) {            for (const prop in updateMap) {                this.initSqlBuilder();                this.sqlBuilder.setAndWhere('tender_id', {                    value: tenderId,                    operate: '='                });                const fullPath = this.ctx.helper.explodePath(prop);                this.sqlBuilder.setAndWhere('full_path', {                    value: this.ctx.helper.explodePath(prop),                    operate: 'in'                });                this.sqlBuilder.setUpdateData('total_price', {                    value: updateMap[prop] > 0 ? updateMap[prop] : -updateMap[prop],                    selfOperate: updateMap[prop] > 0 ? '+' : '-'                });                const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');                await this.transaction.query(sql, sqlParam);            }        }        /**         * 提交数据 - 响应计算(增量方式计算)         * @param {Number} tenderId         * @param {Object} data         * @returns {Promise<*>}         */        async updateCalc(tenderId, data) {            // 简单验证数据            if (tenderId <= 0) {                throw '标段不存在';            }            if (!data) {                throw '提交数据错误';            }            const datas = data instanceof Array ? data : [data];            const ids = [];            for (const row of datas) {                if (tenderId !== row.tender_id) {                    throw '提交数据错误';                }                ids.push(row.id);            }            this.transaction = await this.db.beginTransaction();            try {                for (const row of datas) {                    const updateNode = await this.getDataById(row.id);                    if (!updateNode || tenderId !== updateNode.tender_id || row.ledger_id !== updateNode.ledger_id) {                        throw '提交数据错误';                    }                    let updateData;                    if (this._checkCalcField(row)) {                        const calcData = this.ctx.helper.updateObj(updateNode, row);                        if (updateNode.is_leaf) {                            calcData.total_price = calcData.quantity * calcData.unit_price;                            calcData.deal_tp = calcData.deal_qty * calcData.unit_price;                        }                        const data1 = this._filterChangedField(updateNode, calcData);                        updateData = this._filterUpdateInvalidField(updateNode.id, data1);                    } else {                        updateData = this._filterUpdateInvalidField(updateNode.id, row);                    }                    await this.transaction.update(this.tableName, updateData);                }                await this.transaction.commit();            } catch (err) {                await this.transaction.rollback();                throw err;            }            return {update: await this.getDataByIds(ids)};        }        /**         *         * @param tenderId         * @param xmj         * @param order         * @param parentData         * @returns {Promise<*[]>}         * @private         */        async _sortBatchInsertData(tenderId, xmj, order, parentData) {            const result = [], newIds = [];            let tp = 0;            const cacheKey = keyPre + tenderId;            let maxId = parseInt(await this.cache.get(cacheKey));            if (!maxId) {                maxId = await this._getMaxNodeId(tenderId);            }            this.cache.set(cacheKey, maxId + xmj.children.length + 1, 'EX', this.ctx.app.config.cacheTime);            // 添加xmj数据            const parent = {                tender_id: tenderId,                ledger_id: maxId + 1,                ledger_pid: parentData.ledger_id,                is_leaf: xmj.children.length === 0,                order: order,                level: parentData.level + 1,                name: xmj.name,            };            parent.full_path = parentData.full_path + '.' + parent.ledger_id;            // 添加gcl数据            for (let i = 0, iLen = xmj.children.length; i < iLen; i++) {                const gcl = xmj.children[i];                const child = {                    tender_id: tenderId,                    ledger_id: maxId + 1 + i + 1,                    ledger_pid: parent.ledger_id,                    is_leaf: true,                    order: i+1,                    level: parent.level + 1,                    b_code: gcl.b_code,                    name: gcl.name,                    unit: gcl.unit,                    unit_price: gcl.unit_price,                    quantity: gcl.quantity,                };                child.full_path = parent.full_path + '.' + child.ledger_id;                child.total_price = child.unit_price * child.quantity;                tp = tp + child.total_price;                result.push(child);                newIds.push(child.ledger_id);            }            parent.total_price = tp;            result.push(parent);            newIds.push(parent.ledger_id);            return [result, tp, newIds];        }        /**         * 批量插入子项         * @param {Number} tenderId - 标段Id         * @param {Number} selectId - 选中节点Id         * @param {Object} data - 批量插入数据         * @returns {Promise<void>}         */        async batchInsertChild(tenderId, selectId, data) {            const result = { ledger: {}, pos: null };            if ((tenderId <= 0) || (selectId <= 0)) {                return result;            }            const selectData = await this.getDataByNodeId(tenderId, selectId);            if (!selectData) {                throw '位置数据错误';            }            this.transaction = await this.db.beginTransaction();            let newIds = [];            try {                const lastChild = await this.getLastChildData(tenderId, selectId);                // 更新父项isLeaf                if (!lastChild) {                    await this.transaction.update(this.tableName, {                        id: selectData.id,                        is_leaf: false,                    });                }                const order = lastChild ? lastChild.order : 0;                // 计算id                const cacheKey = keyPre + tenderId;                let maxId = parseInt(await this.cache.get(cacheKey));                if (!maxId) {                    maxId = await this._getMaxNodeId(tenderId);                }                // 数据库创建新增节点数据                for (let i = 0, iLen = data.length; i < iLen; i++) {                    // 合并新增数据                    const qd = {                        tender_id: tenderId,                        ledger_id: maxId + i + 1,                        ledger_pid: selectData.ledger_id,                        is_leaf: true,                        order: order + i + 1,                        level: selectData.level + 1,                        b_code: data[i].b_code,                        name: data[i].name,                        unit: data[i].unit,                        unit_price: data[i].price,                    };                    qd.full_path = selectData.full_path + '.' + qd.ledger_id;                    const insertResult = await this.transaction.insert(this.tableName, qd);                    newIds.push(insertResult.insertId);                    await this.ctx.service.pos.insertLedgerPosData(this.transaction, tenderId, insertResult.insertId, data[i].pos);                    await this.calc(tenderId, insertResult.insertId, this.transaction);                }                this.cache.set(cacheKey, maxId + data.length + 1, 'EX', this.ctx.app.config.cacheTime);                await this.transaction.commit();            } catch(err) {                await this.transaction.rollback();                throw err;            }            // 查询应返回的结果            result.ledger.create = await this.getDataByIds(newIds);            result.pos = await this.ctx.service.pos.getPosData({lid: newIds});            return result;        }        /**         * 批量插入后项         * @param {Number} tenderId - 标段Id         * @param {Number} selectId - 选中节点Id         * @param {Object} data - 批量插入数据         * @returns {Promise<void>}         */        async batchInsertNext(tenderId, selectId, data) {            const result = { ledger: {}, pos: null };            if ((tenderId <= 0) || (selectId <= 0)) {                return result;            }            const selectData = await this.getDataByNodeId(tenderId, selectId);            if (!selectData) {                throw '位置数据错误';            }            const parentData = await this.getDataByNodeId(tenderId, selectData.ledger_pid);            if (!parentData) {                throw '位置数据错误';            }            this.transaction = await this.db.beginTransaction();            const newIds = [];            try {                // 选中节点的所有后兄弟节点,order+粘贴节点个数                await this._updateSelectNextsOrder(selectData, data.length);                // 计算id和order                const cacheKey = keyPre + tenderId;                let maxId = parseInt(await this.cache.get(cacheKey));                if (!maxId) {                    maxId = await this._getMaxNodeId(tenderId);                }                const order = selectData.order;                // 数据库创建新增节点数据                for (let i = 0, iLen = data.length; i < iLen; i++) {                    // 合并新增数据                    const qd = {                        tender_id: tenderId,                        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,                    };                    qd.full_path = parentData.full_path + '.' + qd.ledger_id;                    const insertResult = await this.transaction.insert(this.tableName, qd);                    newIds.push(insertResult.insertId);                    await this.ctx.service.pos.insertLedgerPosData(this.transaction, tenderId, insertResult.insertId, data[i].pos);                    await this.calc(tenderId, insertResult.insertId, this.transaction);                }                this.cache.set(cacheKey, maxId + data.length + 1, 'EX', this.ctx.app.config.cacheTime);                await this.transaction.commit();            } catch(err) {                await this.transaction.rollback();                throw err;            }            // 查询应返回的结果            result.ledger.create = await this.getDataByIds(newIds);            result.ledger.update = await this.getNextsData(selectData.tender_id, selectData.ledger_pid, selectData.order + data.length);            result.pos = await this.ctx.service.pos.getPosData({lid: newIds});            return result;        }        /**         *         * @param {Number} tid - 标段id         * @param {Number} id - 需要计算的节点的id         * @param {Object} transaction - 操作所属事务,没有则创建         * @returns {Promise<void>}         */        async calc(tid, id, transaction) {            const node = await this.getAllDataByCondition({id: id});            if (!node) {                throw '数据错误';            }            const calcQtySql = 'UPDATE ??' +                ' SET `quantity` = (SELECT SUM(`quantity`) FROM ?? WHERE `lid` = ?), `total_price` = `quantity` * `unit_price`' +                ' WHERE `id` = ?';            await transaction.query(this.db.format(calcQtySql, [this.tableName, this.ctx.service.pos.tableName, id, id]));        }        /**         * 查找定位 --> 废弃         * @param tenderId         * @param nodeId         * @returns {Promise<{expand: *}>}         */        async locateNode(tenderId, nodeId) {            const node = await this.getDataByNodeId(tenderId, nodeId);            if (!node) {                throw '查询数据有误'            }            const expandIds = node.full_path.split('.');            expandIds.pop();            const expandData = await this.getChildrenByParentId(tenderId, expandIds);            return { expand: expandData };        }    }    return Ledger;};
 |