Browse Source

超高降效bug、清单库bug

清单库多单位清单选择界面被遮挡,无法操作
vian 5 năm trước cách đây
mục cha
commit
0877464c93

+ 20 - 8
modules/main/facade/project_facade.js

@@ -219,18 +219,30 @@ async function calcOverHeightFee(data) {
             tasks.push(ration_model.model.insertMany(ration));
         }
         // 完整的定额人材机数据
-        let completeRationGLJList = [];
-        if (rationGLJ.length) {
-            // 定额人材机需要新增项目人材机、单价文件、且返回完整的定额人材机数据
-            const rationGLJTasks = rationGLJ.map(glj => createRationGLJData(glj));
-            completeRationGLJList = await Promise.all(rationGLJTasks);
-            // 新增定额人材机
-            tasks.push(ration_glj_model.insertMany(completeRationGLJList));
+        const completeRationGLJList = [];
+        // 完整的项目人材机数据
+        const completeProjectGLJList = [];
+        // createRationGLJData方法不能并行,涉及到项目人材机的新增,如果并行可能会重复插入数据
+        for (const rGLJ of rationGLJ) {
+            const [completeRGLJ, completePGLJ] = await createRationGLJData(rGLJ);
+            completeRationGLJList.push(completeRGLJ);
+            completeProjectGLJList.push(completePGLJ);
         }
-        // 返回新的清单和定额人材机数据
+        if (completeRationGLJList.length) {
+            tasks.push(ration_glj_model.insertMany(completeRationGLJList))
+        }
+        // if (rationGLJ.length) {
+        //     // 定额人材机需要新增项目人材机、单价文件、且返回完整的定额人材机数据
+        //     const rationGLJTasks = rationGLJ.map(glj => createRationGLJData(glj));
+        //     completeRationGLJList = await Promise.all(rationGLJTasks);
+        //     // 新增定额人材机
+        //     tasks.push(ration_glj_model.insertMany(completeRationGLJList));
+        // }
+        // 返回新的清单、定额人材机、项目人材机数据数据
         const rst = {
             bills,
             rationGLJ: completeRationGLJList,
+            projectGLJ: completeProjectGLJList,
         }
         if (!tasks.length) {
             return rst;

+ 1 - 1
web/building_saas/main/html/main.html

@@ -1193,7 +1193,7 @@
         </div>
     </div>
     <!--弹出清单单位选择设置-->
-    <div class="modal fade" id="std_bills_unit" data-backdrop="static">
+    <div class="modal fade" id="std_bills_unit" data-backdrop="static" style="z-index: 3000;">
         <div class="modal-dialog" role="document">
             <div class="modal-content">
                 <div class="modal-header">

+ 122 - 79
web/building_saas/main/js/models/overHeight.js

@@ -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(() => {

+ 1 - 1
web/building_saas/main/js/models/ration_glj.js

@@ -462,7 +462,7 @@ let ration_glj = {
                     me.reCalcWhenGLJChange(recode);//触发计算定额以及父节点
                     $.bootstrapLoading.end();
                     installationFeeObj.calcInstallationFee();
-                    OVER_HEIGHT.reCalcOverHeightFee();
+                    // OVER_HEIGHT.reCalcOverHeightFee();
                 });
             };
             $.bootstrapLoading.start();