|
@@ -8,9 +8,8 @@
|
|
|
* 1.一个请求中
|
|
|
* {删除}所有超高子目
|
|
|
* {更新}清单、定额下拉列文本
|
|
|
- * {新增}清单、定额
|
|
|
- * 2.一个请求{刷新}项目人材机(计算需要)
|
|
|
- * 3.一个请求{重算被删除的定额清单节点、新增的定额节点
|
|
|
+ * {新增}清单、定额、定额人材机、项目人材机
|
|
|
+ * 2.一个请求{重算被删除的定额清单节点、新增的定额节点
|
|
|
*/
|
|
|
const OVER_HEIGHT = (() => {
|
|
|
// 选项类型,生成的超高子目所在位置
|
|
@@ -66,8 +65,8 @@ const OVER_HEIGHT = (() => {
|
|
|
const fixedCodeReg = new RegExp(`^${fixedCode}`);
|
|
|
|
|
|
// 取费专业名称
|
|
|
- // const programName = '超高降效';
|
|
|
- const programName = '公共建筑工程';
|
|
|
+ const programName = '超高降效';
|
|
|
+ //const programName = '公共建筑工程'; // for Test
|
|
|
|
|
|
// 指定清单表格
|
|
|
let specificSpread = null;
|
|
@@ -165,7 +164,7 @@ const OVER_HEIGHT = (() => {
|
|
|
sourceData = source || [];
|
|
|
comboData = sourceData
|
|
|
? sourceData
|
|
|
- .filter(item => !item.extra)
|
|
|
+ .filter(item => !item.extra || !JSON.parse(item.extra))
|
|
|
.map(item => item.name)
|
|
|
: [];
|
|
|
}
|
|
@@ -173,6 +172,10 @@ const OVER_HEIGHT = (() => {
|
|
|
function getComboData() {
|
|
|
return comboData;
|
|
|
}
|
|
|
+ // 根据名称获取下拉项索引
|
|
|
+ function getIndex(name) {
|
|
|
+ return comboData.findIndex(item => item === name);
|
|
|
+ }
|
|
|
function getOverHeightItem(value) {
|
|
|
return sourceData.find(item => item.name === value);
|
|
|
}
|
|
@@ -607,7 +610,7 @@ const OVER_HEIGHT = (() => {
|
|
|
return nodes[nodes.length - 1]
|
|
|
}
|
|
|
|
|
|
- // 将需要生成超高子目的定额数据按照挂载清单和超高名称进行分组
|
|
|
+ // 将需要生成超高子目的定额数据按照挂载清单和超高名称进行分组,其下数组为关联的主定额
|
|
|
// @return {Object} {'billsID@overHeight': [node: rationNode]}
|
|
|
function getGroupData(rationItems, mountedBillsID) {
|
|
|
// mapping: billsID-overHeightName
|
|
@@ -672,23 +675,32 @@ const OVER_HEIGHT = (() => {
|
|
|
contain,
|
|
|
}
|
|
|
}
|
|
|
- // 根据分组的keys获取定额serialNo值映射表
|
|
|
+ // 根据分组的keys获取定额serialNo值映射表 billsID@overHeight
|
|
|
function getSerialNoMappig(groupKeys) {
|
|
|
// 清单ID - serialNo映射
|
|
|
const billsIDMap = {};
|
|
|
// 完整的key - serialNo映射
|
|
|
const keyMap = {};
|
|
|
const nodes = projectObj.project.mainTree.nodes;
|
|
|
+ // 先给根据清单ID设置上第一个serialNo值(基准值),和超高项数据
|
|
|
groupKeys.forEach(key => {
|
|
|
- const [billsID] = key.split('@');
|
|
|
+ const [billsID, overHeight] = key.split('@');
|
|
|
if (billsIDMap[billsID]) {
|
|
|
- billsIDMap[billsID] = keyMap[key] += 1;
|
|
|
+ billsIDMap[billsID].items.push(overHeight);
|
|
|
return;
|
|
|
}
|
|
|
const billsNode = nodes[`id_${billsID}`];
|
|
|
const lastNormalRationNode = billsNode ? getLastNormalRationNode(billsNode) : null;
|
|
|
const serialNo = lastNormalRationNode ? lastNormalRationNode.data.serialNo + 1 : 1;
|
|
|
- billsIDMap[billsID] = keyMap[key] = serialNo;
|
|
|
+ billsIDMap[billsID] = { serialNo, items: [overHeight] };
|
|
|
+ });
|
|
|
+ // 将同一清单下的超高项按照下拉项位置排序
|
|
|
+ Object.entries(billsIDMap).forEach(([billsID, { serialNo, items }]) => {
|
|
|
+ items.sort((a, b) => getIndex(a) - getIndex(b));
|
|
|
+ items.forEach((overHeight, index) => {
|
|
|
+ const key = `${billsID}@${overHeight}`;
|
|
|
+ keyMap[key] = serialNo + index;
|
|
|
+ });
|
|
|
});
|
|
|
return keyMap;
|
|
|
}
|
|
@@ -841,7 +853,7 @@ const OVER_HEIGHT = (() => {
|
|
|
const postData = generatePostData(isCancelCalc, action);
|
|
|
const { addData, updateData, deleteData } = postData;
|
|
|
// 更新、删除、新增数据
|
|
|
- // 返回的是新增的清单、定额人材机 rst = {bills: [], rationGLJ: []}
|
|
|
+ // 返回的是新增的清单、定额人材机、项目人材机 rst = {bills: [], rationGLJ: [], projectGLJ: []}
|
|
|
const rst = await ajaxPost('/project/calcOverHeightFee', postData);
|
|
|
// 后续获取重算节点相关:
|
|
|
// 新增的定额节点要在同步数据后才有,删除的定额节点在同步前找不到,因此同步前先获取被删除定额节点的清单ID列表
|
|
@@ -860,7 +872,6 @@ const OVER_HEIGHT = (() => {
|
|
|
return;
|
|
|
}
|
|
|
// 获取项目人材机数据,更新缓存
|
|
|
- await projectObj.project.projectGLJ.loadDataSync();
|
|
|
$.bootstrapLoading.end(); // 重算节点相关方法里有loading,防止提前结束了loading
|
|
|
// 重算相关节点
|
|
|
projectObj.project.calcProgram.calcNodesAndSave(reCalcNodes);
|
|
@@ -893,6 +904,28 @@ const OVER_HEIGHT = (() => {
|
|
|
* @return {void}
|
|
|
*/
|
|
|
function syncData(delData, updateData, addData) {
|
|
|
+ // 被删除数据的清单ID@定额serialNo - 价格字段映射
|
|
|
+ // 在新增节点时,给上原本该行的feesIndex字段,不然会出现新增节点价格为空,重算后价格有值,造成价格字段闪烁的情况
|
|
|
+ // 新增节点赋上原本该行的feesIndex字段只是为了避免闪烁的情况。
|
|
|
+ // 新节点fees数组没有赋值,后续计算的时候节点的价格字段会被初始化(calcTools.initFees中),因此这个操作不会对计算结果有影响
|
|
|
+ function getSerialNoFeesIndexMapping({ ration }) {
|
|
|
+ const mapping = {};
|
|
|
+ const rationIDList = ration.map(item => item.ID);
|
|
|
+ projectObj.project.Ration.datas
|
|
|
+ .filter(item => rationIDList.includes(item.ID))
|
|
|
+ .forEach(item => mapping[`${item.billsItemID}@${item.serialNo}`] = item.feesIndex);
|
|
|
+ return mapping;
|
|
|
+ }
|
|
|
+ // 新增定额设置上暂时显示的价格字段
|
|
|
+ function setTemporaryFeesIndex({ ration }, feesIndexMapping) {
|
|
|
+ ration.forEach(item => {
|
|
|
+ const key = `${item.billsItemID}@${item.serialNo}`;
|
|
|
+ const oldFeesIndex = feesIndexMapping[key];
|
|
|
+ if (oldFeesIndex) {
|
|
|
+ item.feesIndex = oldFeesIndex;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
// 删除数据
|
|
|
function del({ ration }) {
|
|
|
const sheet = projectObj.mainController.sheet;
|
|
@@ -925,7 +958,7 @@ const OVER_HEIGHT = (() => {
|
|
|
});
|
|
|
}
|
|
|
// 插入数据
|
|
|
- function add({ bills, ration, rationGLJ }) {
|
|
|
+ function add({ bills, ration, rationGLJ, projectGLJ }) {
|
|
|
const sheet = projectObj.mainController.sheet;
|
|
|
const func = () => {
|
|
|
// 插入清单数据和清单节点主树节点
|
|
@@ -934,16 +967,26 @@ const OVER_HEIGHT = (() => {
|
|
|
}
|
|
|
// 插入定额数据和定额节点
|
|
|
if (ration.length) {
|
|
|
+ // 按照serialNo排序
|
|
|
+ ration.sort((a, b) => a.serialNo - b.serialNo);
|
|
|
projectObj.project.Ration.addNewDataSimply(ration);
|
|
|
}
|
|
|
// 插入定额人材机数据
|
|
|
if (rationGLJ.length) {
|
|
|
projectObj.project.ration_glj.addDatasToList(rationGLJ);
|
|
|
}
|
|
|
+ // 插入项目人材机数据
|
|
|
+ if (projectGLJ.length) {
|
|
|
+ projectObj.project.projectGLJ.loadNewProjectGLJToCaches(projectGLJ);
|
|
|
+ // 重算消耗量
|
|
|
+ projectObj.project.projectGLJ.calcQuantity();
|
|
|
+ }
|
|
|
};
|
|
|
TREE_SHEET_HELPER.massOperationSheet(sheet, func);
|
|
|
}
|
|
|
|
|
|
+ const feesIndexMapping = getSerialNoFeesIndexMapping(delData);
|
|
|
+ setTemporaryFeesIndex(addData, feesIndexMapping);
|
|
|
del(delData);
|
|
|
update(updateData);
|
|
|
add(addData);
|
|
@@ -978,76 +1021,76 @@ const OVER_HEIGHT = (() => {
|
|
|
$.bootstrapLoading.end();
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * 返回清单与超高子目和其定额人材机映射
|
|
|
- * @param {Array} rations - 全部超高子目数据
|
|
|
- * @param {Array} rationGLJs - 全部超高子目定额人材机数据
|
|
|
- * @return {Object} - {billsItemID@超高子目编码@定额人材机编码: {quanqity, rationItemQuantity}}
|
|
|
- */
|
|
|
-function getRationGLJMap(rations, rationGLJs) {
|
|
|
- const mapping = {};
|
|
|
- rationGLJs.forEach(rGLJ => {
|
|
|
- const ration = rations.find(ration => ration.ID === rGLJ.rationID);
|
|
|
- const rationCode = ration ? ration.code : '';
|
|
|
- // 由于一个清单下不会存在两个相同编号的超高子目(相同编号会被自动汇总),因此这个key能确定唯一一条定额人材机
|
|
|
- const key = `${rGLJ.billsItemID}@${rationCode}@${rGLJ.original_code}`;
|
|
|
- mapping[key] = { quantity: rGLJ.quantity, rationItemQuantity: rGLJ.rationItemQuantity };
|
|
|
- });
|
|
|
- return mapping;
|
|
|
-}
|
|
|
-
|
|
|
-// 比较两个清单与超高子目和其定额人材机映射表,看是否相同
|
|
|
-function isMappingEqual(oldMapping, newMapping) {
|
|
|
- const oldKeys = Object.keys(oldMapping);
|
|
|
- const newKeys = Object.keys(newMapping);
|
|
|
- if (oldKeys.length !== newKeys.length) {
|
|
|
- return false;
|
|
|
+ /**
|
|
|
+ * 返回清单与超高子目和其定额人材机映射
|
|
|
+ * @param {Array} rations - 全部超高子目数据
|
|
|
+ * @param {Array} rationGLJs - 全部超高子目定额人材机数据
|
|
|
+ * @return {Object} - {billsItemID@超高子目编码@定额人材机编码: {quanqity, rationItemQuantity}}
|
|
|
+ */
|
|
|
+ function getRationGLJMap(rations, rationGLJs) {
|
|
|
+ const mapping = {};
|
|
|
+ rationGLJs.forEach(rGLJ => {
|
|
|
+ const ration = rations.find(ration => ration.ID === rGLJ.rationID);
|
|
|
+ const rationCode = ration ? ration.code : '';
|
|
|
+ // 由于一个清单下不会存在两个相同编号的超高子目(相同编号会被自动汇总),因此这个key能确定唯一一条定额人材机
|
|
|
+ const key = `${rGLJ.billsItemID}@${rationCode}@${rGLJ.original_code}`;
|
|
|
+ mapping[key] = { quantity: rGLJ.quantity, rationItemQuantity: rGLJ.rationItemQuantity };
|
|
|
+ });
|
|
|
+ return mapping;
|
|
|
}
|
|
|
- const isEveryKeySame = oldKeys.every(key => {
|
|
|
- const oldData = oldMapping[key];
|
|
|
- const newData = newMapping[key];
|
|
|
- if (!newData) {
|
|
|
+
|
|
|
+ // 比较两个清单与超高子目和其定额人材机映射表,看是否相同
|
|
|
+ function isMappingEqual(oldMapping, newMapping) {
|
|
|
+ const oldKeys = Object.keys(oldMapping);
|
|
|
+ const newKeys = Object.keys(newMapping);
|
|
|
+ if (oldKeys.length !== newKeys.length) {
|
|
|
return false;
|
|
|
}
|
|
|
- const quantitySame = commonUtil.similarEqual(oldData.quantity, newData.quantity);
|
|
|
- const rationQuantitySame = commonUtil.similarEqual(oldData.rationItemQuantity, newData.rationItemQuantity);
|
|
|
- return quantitySame && rationQuantitySame;
|
|
|
- });
|
|
|
- return isEveryKeySame;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * 重新计取项目超高子目,超高子目的值与关联定额相关
|
|
|
- * 因此各种操作下改变了相关定额,都要重新计算超高子目
|
|
|
- * 为了降低复杂度和保证逻辑统一性,重新计取为重新走(删除新增逻辑)
|
|
|
- * 需要尽可能地降低操作的触发率
|
|
|
- * @param {type} -
|
|
|
- * @return: {type} -
|
|
|
- */
|
|
|
-function reCalcOverHeightFee() {
|
|
|
- const project = projectObj.project;
|
|
|
- // 如果项目没有超高降效数据,项目不可用超高降效,返回
|
|
|
- if (!project.isOverHeightProject()) {
|
|
|
- return;
|
|
|
- }
|
|
|
- // 如果没有超高定额,返回(因此删除了选项二三、指定的清单不会触发)
|
|
|
- const overHeightRations = project.Ration.datas.filter(ration => ration.type === rationType.overHeight);
|
|
|
- if (!overHeightRations.length) {
|
|
|
- return;
|
|
|
+ const isEveryKeySame = oldKeys.every(key => {
|
|
|
+ const oldData = oldMapping[key];
|
|
|
+ const newData = newMapping[key];
|
|
|
+ if (!newData) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ const quantitySame = commonUtil.similarEqual(oldData.quantity, newData.quantity);
|
|
|
+ const rationQuantitySame = commonUtil.similarEqual(oldData.rationItemQuantity, newData.rationItemQuantity);
|
|
|
+ return quantitySame && rationQuantitySame;
|
|
|
+ });
|
|
|
+ return isEveryKeySame;
|
|
|
}
|
|
|
- // 获取新旧超高数据映射表,不同才需要计算
|
|
|
- const overHeightRationIDs = overHeightRations.map(ration => ration.ID);
|
|
|
- const overHeigtRationGLJs = project.ration_glj.datas.filter(rGLJ => overHeightRationIDs.includes(rGLJ.rationID));
|
|
|
- const action = getAction();
|
|
|
- const { ration, rationGLJ } = getAddData(action);
|
|
|
- const oldMapping = getRationGLJMap(overHeightRations, overHeigtRationGLJs);
|
|
|
- const newMapping = getRationGLJMap(ration, rationGLJ);
|
|
|
- if (isMappingEqual(oldMapping, newMapping)) {
|
|
|
- return;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 重新计取项目超高子目,超高子目的值与关联定额相关
|
|
|
+ * 因此各种操作下改变了相关定额,都要重新计算超高子目
|
|
|
+ * 为了降低复杂度和保证逻辑统一性,重新计取为重新走(删除新增逻辑)
|
|
|
+ * 需要尽可能地降低操作的触发率
|
|
|
+ * @param {type} -
|
|
|
+ * @return: {type} -
|
|
|
+ */
|
|
|
+ function reCalcOverHeightFee() {
|
|
|
+ const project = projectObj.project;
|
|
|
+ // 如果项目没有超高降效数据,项目不可用超高降效,返回
|
|
|
+ if (!project.isOverHeightProject()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 如果没有超高定额,返回(因此删除了选项二三、指定的清单不会触发)
|
|
|
+ const overHeightRations = project.Ration.datas.filter(ration => ration.type === rationType.overHeight);
|
|
|
+ if (!overHeightRations.length) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 获取新旧超高数据映射表,不同才需要计算
|
|
|
+ const overHeightRationIDs = overHeightRations.map(ration => ration.ID);
|
|
|
+ const overHeigtRationGLJs = project.ration_glj.datas.filter(rGLJ => overHeightRationIDs.includes(rGLJ.rationID));
|
|
|
+ const action = getAction();
|
|
|
+ const { ration, rationGLJ } = getAddData(action);
|
|
|
+ const oldMapping = getRationGLJMap(overHeightRations, overHeigtRationGLJs);
|
|
|
+ const newMapping = getRationGLJMap(ration, rationGLJ);
|
|
|
+ if (isMappingEqual(oldMapping, newMapping)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 存在不同,重算
|
|
|
+ handleConfirmed();
|
|
|
}
|
|
|
- // 存在不同,重算
|
|
|
- handleConfirmed();
|
|
|
-}
|
|
|
|
|
|
// 事件监听
|
|
|
$(document).ready(() => {
|