overHeight.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. const OVER_HEIGHT = (() => {
  2. // 选项类型,生成的超高子目所在位置
  3. const Option = {
  4. // 对应清单或分部下(默认)
  5. SEPARATION: 1,
  6. // 指定措施清单011704001
  7. MEASURE: 2,
  8. // 指定具体位置,显示分部分项以及措施项目的树结构显示叶子清单(分项)供勾选
  9. SPECIFIC: 3,
  10. };
  11. // 选项二时的前九位清单编号
  12. const fixedCodeReg = /^011704001/;
  13. // 源数据
  14. let sourceData;
  15. // 下拉项
  16. let comboData;
  17. function init(source) {
  18. sourceData = source || [];
  19. comboData = sourceData
  20. ? sourceData
  21. .filter(item => !item.extra)
  22. .map(item => item.name)
  23. : [];
  24. }
  25. // 获取下拉项
  26. function getComboData() {
  27. return comboData;
  28. }
  29. function getOverHeightItem(value) {
  30. return sourceData.find(item => item.name === value);
  31. }
  32. // 获取系数
  33. function getRate(overHeightItem) {
  34. return overHeightItem.labourRate
  35. || overHeightItem.machineRate
  36. || overHeightItem.labourMachineRate
  37. || null;
  38. }
  39. // 下拉项是否需要计算(生成子目)
  40. function isNeedToCalc(overHeightItem) {
  41. if (!overHeightItem) {
  42. return false;
  43. }
  44. const rate = getRate(overHeightItem);
  45. return !!rate;
  46. }
  47. // 是否是超高子目
  48. function isOverHeight(node) {
  49. return node
  50. && node.sourceType === projectObj.project.Ration.getSourceType()
  51. && node.data.type === rationType.overHeight;
  52. }
  53. function overHeightCol() {
  54. return projectObj.project.projSetting.main_tree_col.cols.findIndex(item => item.data.field === 'overHeight');
  55. }
  56. // 有效化变化节点的值,若值为无效值(下拉项中不存在),则将变化节点的值设成原值
  57. function validateData(changedData) {
  58. changedData.forEach(item => {
  59. if (!comboData.includes(item.value)) {
  60. item.value = item.node.data.overHeight;
  61. }
  62. });
  63. }
  64. // 简化变化节点:由于子项值继承父项,且变更节点中可能存在父子关系,因此需要去除子项节点
  65. function simplifyData(changedData) {
  66. const rst = [];
  67. const nodes = changedData.map(item => item.node);
  68. changedData.forEach(item => {
  69. let parent = item.parent;
  70. // 父项不存在变化节点中才将此数据放入返回数组中
  71. while (parent) {
  72. if (nodes.includes(parent)) {
  73. return;
  74. }
  75. parent = parent.parent;
  76. }
  77. rst.push(item);
  78. });
  79. return rst;
  80. }
  81. // 设置单元格文本,单元格文本数据为暂存数据,方便后续获取更新、新增数据,若后续操作失败,则可用节点数据恢复单元格文本内容。
  82. function setTexts(changedData) {
  83. const sheet = projectObj.project.mainController.sheet;
  84. const func = () => {
  85. const overHeightCol = overHeightCol();
  86. changedData.forEach(item => {
  87. // 子项值随父项
  88. const nodes = [item.node, ...item.node.getPosterity()];
  89. nodes.forEach(node => sheet.setText(node.serialNo(), overHeightCol, item.value));
  90. });
  91. };
  92. TREE_SHEET_HELPER.massOperationSheet(sheet, func);
  93. }
  94. // 获取措施项目固定的节点: 选项二时
  95. function getMeasureFixedNode() {
  96. const measureNode = projectObj.project.mainTree.items.find(node => node.getFlag() === fixedFlag.MEASURE);
  97. const measureChildren = measureNode.getPosterity();
  98. return measureChildren.find(node => node.data.code && fixedCodeReg.test(node.data.code));
  99. }
  100. // 获取指定清单节点:选项三时
  101. function getSpecificNode() {
  102. // 选项三指定清单时,指定的清单ID会存在项目属性中
  103. const specificID = projectObj.project.projectInfo.property.overHeightSpecificID;
  104. return specificID
  105. ? projectObj.project.mainTree.nodes[`id_${specificID}`]
  106. : null;
  107. }
  108. // 操作检验,若选项为2、3时,需检验指定清单是否还存在,不存在则取消操作和提示
  109. function checkAction(option = Option.SEPARATION) {
  110. if (option === Option.SEPARATION) {
  111. return true;
  112. } else if (option === Option.MEASURE) {
  113. const isValid = !!getMeasureFixedNode();
  114. if (!isValid) {
  115. $('#overHeightMeasure').modal('show');
  116. }
  117. return isValid;
  118. } else {
  119. const isValid = !!getSpecificNode();
  120. if (!isValid) {
  121. $('#overHeightSpecific').modal('show');
  122. }
  123. return isValid;
  124. }
  125. }
  126. // 超高降效下拉项或选项是否改变了
  127. function isValueChanged() {
  128. const updateData = getUpdateData();
  129. return updateData.bills.length || updateData.ration.length;
  130. }
  131. /*
  132. * 获取更新数据:对比项目节点中超高降效的新旧值,新值为暂存的单元格文本,旧值为节点data数据
  133. * @return {Object} {bills: [{ID: Number, overHeight: String}], ration: [{ID: Number, overHeight: String}]}
  134. * */
  135. function getUpdateData() {
  136. const rst = {
  137. bills: [],
  138. ration: [],
  139. };
  140. const nodes = projectObj.project.mainTree.items;
  141. const sheet = projectObj.project.mainController.sheet;
  142. const overHeightCol = overHeightCol();
  143. nodes.forEach((node, index) => {
  144. const newValue = node.data.overHeight;
  145. const oldValue = sheet.getText(index, overHeightCol);
  146. // 非严等
  147. if (newValue != oldValue) {
  148. const type = node.sourceType === projectObj.project.Bills.getSourceType()
  149. ? 'bills'
  150. : 'ration';
  151. rst[type].push({
  152. ID: node.data.ID,
  153. overHeight: newValue
  154. });
  155. }
  156. });
  157. return rst;
  158. }
  159. /*
  160. * 获取删除数据:项目中所有超高子目
  161. * @return {Array} [{ID: Number}]
  162. * */
  163. function getDeleteData() {
  164. const rations = projectObj.project.Ration.datas;
  165. return rations
  166. .filter(ration => ration.type === rationType.overHeight)
  167. .map(ration => ({ ID: ration.ID }));
  168. }
  169. // 更改了超高降效列(edited、rangeChanged),触发事件
  170. function handleValueChanged(changedData) {
  171. validateData(changedData);
  172. changedData = simplifyData(changedData);
  173. setTexts(changedData);
  174. const valuedChanged = isValueChanged();
  175. if (!valuedChanged) {
  176. return;
  177. }
  178. // 选项2、选项3情况下下拉可能会遇到,相关清单已经被删除,需要检测
  179. const actionValid = checkAction(projectObj.project.projectInfo.property.overHeightOption);
  180. // actionValid为false的时候,可能后续需要恢复单元格文本值,根据后续用户在弹窗中的选择 todo
  181. if (!actionValid) {
  182. return;
  183. }
  184. }
  185. // 获取需要生成超高子目的定额节点
  186. function getNeedCalcRationItems() {
  187. // 从整个项目中筛选当前下拉项单元格的文本是需要计算的定额节点
  188. const nodes = projectObj.project.mainTree.items;
  189. const sheet = projectObj.project.mainController.sheet;
  190. const overHeightCol = overHeightCol();
  191. const rst = [];
  192. nodes.forEach(node => {
  193. if (node.sourceType !== projectObj.project.Ration.getSourceType() || node.data.type === rationType.overHeight) {
  194. return;
  195. }
  196. const overHeight = sheet.getText(node.serialNo(), overHeightCol);
  197. const overHeightItem = getOverHeightItem(overHeight);
  198. if (isNeedToCalc(overHeightItem)) {
  199. rst.push({ node, overHeightItem});
  200. }
  201. });
  202. return rst;
  203. }
  204. function handleConfirmed(option = Option.SEPARATION) {
  205. }
  206. return {
  207. init,
  208. getComboData,
  209. isOverHeight
  210. }
  211. })();