common_util.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /**
  2. * Created by CSL on 2017-06-06.
  3. * public functions.
  4. */
  5. function deleteEmptyObject(arr) {
  6. function isEmptyObject(e) {
  7. var t;
  8. for (t in e)
  9. return !1;
  10. return !0
  11. };
  12. for (var i = 0; i < arr.length; i++) {
  13. if (isEmptyObject(arr[i])) {
  14. arr.splice(i, 1);
  15. i = i - 1;
  16. };
  17. };
  18. };
  19. ((factory) => {
  20. if (typeof module !== 'undefined') {
  21. module.exports = factory();
  22. } else {
  23. window.commonUtil = factory();
  24. }
  25. })(() => {
  26. // 是否定义
  27. function isDef(val) {
  28. return typeof val !== 'undefined' && val !== null;
  29. }
  30. // 是否空值
  31. function isEmptyVal(val) {
  32. return val === null || val === undefined || val === '';
  33. }
  34. // 是否数值
  35. function isNumber(val) {
  36. return !isEmptyVal(val) && !isNaN(val);
  37. }
  38. // 是否是有值得对象(至少要有一个可枚举属性)
  39. function isNotEmptyObject(obj) {
  40. return Object.prototype.toString.call(obj) === '[object Object]' && Object.keys(obj).length > 0;
  41. }
  42. // 是否近似相等(null = undefined = '', 1 = '1'...)
  43. function similarEqual(a, b) {
  44. // null == '' 为false,所以不能用非严等
  45. if (isEmptyVal(a) && isEmptyVal(b)) {
  46. return true;
  47. }
  48. return a == b;
  49. }
  50. // 递归获取必填项(基本信息、工程特征)
  51. function getRequired(rst, datas) {
  52. if (!datas) {
  53. return rst;
  54. }
  55. for (const data of datas) {
  56. const required = typeof data.required === 'string' ? JSON.parse(data.required) : data.required;
  57. const readOnly = typeof data.readOnly === 'string' ? JSON.parse(data.readOnly) : data.readOnly;
  58. if (required && !readOnly) {
  59. rst.push(data);
  60. }
  61. if (data.items && data.items.length) {
  62. getRequired(rst, data.items);
  63. }
  64. }
  65. return rst;
  66. }
  67. // 将树数据排序好
  68. function getSortedTreeData(rootID, items) {
  69. return sortSameDedth(rootID, items).reverse();
  70. function sortSameDedth(parentID, items) {
  71. const sameDepthItems = items.filter(item => item.ParentID == parentID);
  72. if (!sameDepthItems.length) {
  73. return [];
  74. }
  75. const NextIDMapping = {};
  76. sameDepthItems.forEach(item => NextIDMapping[item.NextSiblingID] = item);
  77. let curItem = sameDepthItems.length > 1 ? sameDepthItems.find(item => +item.NextSiblingID == -1) : sameDepthItems[0];
  78. const sorted = [];
  79. while (curItem) {
  80. sorted.push(...sortSameDedth(curItem.ID, items));
  81. sorted.push(curItem);
  82. curItem = NextIDMapping[curItem.ID] || null;
  83. }
  84. return sorted;
  85. }
  86. }
  87. function getSortedSeqTreeData(rootID, items) {
  88. const parentMap = {};
  89. items.forEach(item => {
  90. (parentMap[item.ParentID] || (parentMap[item.ParentID] = [])).push(item);
  91. });
  92. Object.values(parentMap).forEach(data => data.sort((a, b) => a.seq - b.seq));
  93. const rst = [];
  94. function extractItems(data) {
  95. if (data && data.length) {
  96. for (const item of data) {
  97. rst.push(item);
  98. const children = parentMap[item.ID];
  99. if (children && children.length) {
  100. extractItems(children);
  101. }
  102. }
  103. }
  104. }
  105. extractItems(parentMap[rootID]);
  106. return rst;
  107. }
  108. // 控制全屏(浏览器有限制)
  109. // Element.requestFullscreen的全屏和“F11”的全屏是不一样的。前者是将相关Element变成全屏显示。后者是将浏览器导航、标签等隐藏。
  110. // Fullscreen API对于全屏的判断和监听都是基于Element.requestFullscreen的,比如Document.fullscreenElement。通过F11触发的全屏Document.fullscreenElement返回null,无法正确返回全屏状态。
  111. // F11全屏后,无法通过Fullscreen API对全屏状态判断,会导致F11全屏后点击按钮变成了再次调用api全屏。因此,使用window.innerHeight和window.screen.height作为判断。(打开了控制台后,此方法可能会失效:无法正确或缺innerHeight)
  112. // 通过F11打开全屏后,没有办法通过代码退出全屏,只能通过F11退出:
  113. // https://stackoverflow.com/questions/51114885/combining-requestfullscreen-and-f11; https://stackoverflow.com/questions/43392583/fullscreen-api-not-working-if-triggered-with-f11/44368592#44368592;
  114. function handleFullscreen() {
  115. if (isFullscreen()) {
  116. const p = exitFullscreen();
  117. if (Object.prototype.toString.call(p) === '[object Promise]') {
  118. p.catch(() => alert('按F11即可退出全屏模式'));
  119. }
  120. } else {
  121. fullscreen(document.documentElement);
  122. }
  123. }
  124. function isFullscreen() {
  125. return window.innerHeight === window.screen.height;
  126. }
  127. function fullscreen(ele) {
  128. if (ele.requestFullscreen) {
  129. ele.requestFullscreen();
  130. } else if (ele.mozRequestFullscreen) {
  131. ele.mozRequestFullScreen();
  132. } else if (ele.webkitRequestFullscreen) {
  133. ele.webkitRequestFullscreen();
  134. } else if (ele.msRequestFullscreen) {
  135. ele.msRequestFullscreen();
  136. }
  137. }
  138. function exitFullscreen() {
  139. if (document.exitFullscreen) {
  140. return document.exitFullscreen();
  141. } else if (document.mozCancelFullscreen) {
  142. return document.mozCancelFullscreen();
  143. } else if (document.webkitExitFullscreen) {
  144. return document.webkitExitFullscreen();
  145. } else if (document.msExitFullscreen) {
  146. return document.msExitFullscreen();
  147. }
  148. }
  149. // 判断单位工程的工程专业的金额所属是“建筑工程费”还是“安装工程费”
  150. const getEngineeringFeeType = (engineeringName) => {
  151. if (['房屋建筑工程', '装配式混合结构建筑工程', '装配式钢结构建筑工程', '装饰工程', '构筑物', '市政工程', '市政绿化工程', '机械(爆破)土石方工程',
  152. '人工土石方工程', '围墙工程', '幕墙工程', '城市轨道交通工程'].includes(engineeringName)) {
  153. return 'building';
  154. }
  155. if (['安装工程', '市政安装工程', '城市轨道交通安装']) {
  156. return 'installation'
  157. }
  158. return null;
  159. };
  160. // 获取造价书树或概算汇总树
  161. const getActiveTree = () => {
  162. return $('#tab-budget-summary').hasClass('active') ? budgetSummaryObj.getTree() : projectObj.project.mainTree;
  163. }
  164. return {
  165. isDef,
  166. isEmptyVal,
  167. isNumber,
  168. similarEqual,
  169. getRequired,
  170. getSortedTreeData,
  171. isNotEmptyObject,
  172. handleFullscreen,
  173. getEngineeringFeeType,
  174. getActiveTree,
  175. };
  176. });