schedule_plan.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. /**
  2. * 进度台账相关js
  3. *
  4. * @author Ellisran
  5. * @date 2020/11/6
  6. * @version
  7. */
  8. function getTenderId() {
  9. return window.location.pathname.split('/')[2];
  10. }
  11. $(function () {
  12. autoFlashHeight();
  13. if(schedule && !schedule.mode) {
  14. $('#mode').modal('show');
  15. }
  16. // 初始化台账
  17. const ledgerSpread = SpreadJsObj.createNewSpread($('#ledger-spread')[0]);
  18. const treeSetting = {
  19. id: 'ledger_id',
  20. pid: 'ledger_pid',
  21. order: 'order',
  22. level: 'level',
  23. rootId: -1,
  24. fullPath: 'full_path',
  25. calcFields: ['total_price']
  26. //treeCacheKey: 'ledger_bills_fold' + '_' + getTenderId(),
  27. // markFoldKey: 'bills-fold',
  28. // markFoldSubKey: window.location.pathname.split('/')[2],
  29. };
  30. treeSetting.calcFun = function (node) {
  31. node.dgn_price = ZhCalc.round(ZhCalc.div(node.total_price, node.dgn_qty1), 2);
  32. };
  33. const ledgerTree = createNewPathTree('base', treeSetting);
  34. const static_cols = [
  35. {title: '编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 145, formatter: '@', readOnly: true, cellType: 'tree'},
  36. {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 185, formatter: '@', readOnly: true},
  37. {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 50, formatter: '@', readOnly: true},
  38. {title: '经济指标', colSpan: '1', rowSpan: '2', field: 'dgn_price', hAlign: 2, width: 60, type: 'Number', readOnly: true},
  39. {title: '总设计|工程量', colSpan: '2|1', rowSpan: '1|1', field: 'dgn_qty1', hAlign: 2, width: 70, type: 'Number', readOnly: true},
  40. {title: '|金额(万元)', colSpan: '|1', rowSpan: '|1', field: 'total_price', hAlign: 2, width: 70, type: 'Number', readOnly: true},
  41. ];
  42. const ledgerSpreadSetting = {
  43. emptyRows: 0,
  44. headRows: 2,
  45. headRowHeight: [25, 25],
  46. defaultRowHeight: 21,
  47. headerFont: '12px 微软雅黑',
  48. font: '12px 微软雅黑',
  49. // readOnly: true,
  50. localCache: {
  51. key: 'ledger-bills',
  52. colWidth: true,
  53. }
  54. };
  55. const monthsCols = [];
  56. if(scheduleMonth.length > 0) {
  57. for (const sm of scheduleMonth) {
  58. const readOnly = sm.sj_gcl !== null || sm.sj_tp !== null;
  59. const yearmonth = sm.yearmonth.split('-')[0] + '年' + parseInt(sm.yearmonth.split('-')[1]) + '月';
  60. const cols = {title: yearmonth + '|计划工程量', colSpan: '2|1', rowSpan: '1|1', field: sm.yearmonth+'_gcl', hAlign: 2, width: 90, type: 'Number', readOnly: readOnly ? readOnly : 'readOnly.gcl'};
  61. const cols2 = {title: '|计划金额(万元)', colSpan: '|1', rowSpan: '|1', field: sm.yearmonth+'_tp', hAlign: 2, width: 90, type: 'Number', readOnly: readOnly ? readOnly : 'readOnly.tp'};
  62. monthsCols.push(cols);
  63. monthsCols.push(cols2);
  64. }
  65. }
  66. const spreadHeaderCols = static_cols.concat(monthsCols);
  67. ledgerSpreadSetting.cols = spreadHeaderCols;
  68. const ledgerCol = {
  69. readOnly: {
  70. tp: function (data) {
  71. let flag = data.is_leaf;
  72. if (data.is_leaf) {
  73. flag = schedule && schedule.mode === mode.tp;
  74. }
  75. return !flag;
  76. },
  77. gcl: function (data) {
  78. let flag = data.is_leaf;
  79. if (data.is_leaf) {
  80. flag = schedule && schedule.mode === mode.gcl;
  81. }
  82. return !flag;
  83. },
  84. },
  85. };
  86. sjsSettingObj.setFxTreeStyle(ledgerSpreadSetting, sjsSettingObj.FxTreeStyle.jz);
  87. if (thousandth) sjsSettingObj.setTpThousandthFormat(ledgerSpreadSetting);
  88. SpreadJsObj.initSpreadSettingEvents(ledgerSpreadSetting, ledgerCol);
  89. SpreadJsObj.initSheet(ledgerSpread.getActiveSheet(), ledgerSpreadSetting);
  90. SpreadJsObj.selChangedRefreshBackColor(ledgerSpread.getActiveSheet());
  91. postData('/tender/' + getTenderId() + '/schedule/ledger/load', {}, function (data) {
  92. let treeData = [];
  93. for(const sl of selectedLedgerList) {
  94. const one = _.find(data, { 'ledger_id' : sl });
  95. treeData.push(one);
  96. }
  97. treeData = setLeafData(treeData);
  98. ledgerTree.loadDatas(treeData);
  99. treeCalc.calculateAll(ledgerTree);
  100. console.log(ledgerTree);
  101. SpreadJsObj.loadSheetData(ledgerSpread.getActiveSheet(), SpreadJsObj.DataType.Tree, ledgerTree);
  102. }, null, true);
  103. const ledgerSpreadObj = {
  104. refreshTree: function (sheet, data) {
  105. SpreadJsObj.massOperationSheet(sheet, function () {
  106. const tree = sheet.zh_tree;
  107. // 处理删除
  108. if (data.delete) {
  109. data.delete.sort(function (x, y) {
  110. return y.deleteIndex - x.deleteIndex;
  111. });
  112. for (const d of data.delete) {
  113. sheet.deleteRows(d.deleteIndex, 1);
  114. }
  115. }
  116. // 处理新增
  117. if (data.create) {
  118. const newNodes = data.create;
  119. if (newNodes) {
  120. newNodes.sort(function (a, b) {
  121. return a.index - b.index;
  122. });
  123. for (const node of newNodes) {
  124. sheet.addRows(node.index, 1);
  125. SpreadJsObj.reLoadRowData(sheet, tree.nodes.indexOf(node), 1);
  126. }
  127. }
  128. }
  129. // 处理更新
  130. if (data.update) {
  131. const rows = [];
  132. for (const u of data.update) {
  133. rows.push(tree.nodes.indexOf(u));
  134. }
  135. SpreadJsObj.reLoadRowsData(sheet, rows);
  136. }
  137. // 处理展开
  138. if (data.expand) {
  139. const expanded = [];
  140. for (const e of data.expand) {
  141. if (expanded.indexOf(e) === -1) {
  142. const posterity = tree.getPosterity(e);
  143. for (const p of posterity) {
  144. sheet.setRowVisible(tree.nodes.indexOf(p), p.visible);
  145. expanded.push(p);
  146. }
  147. }
  148. }
  149. }
  150. });
  151. },
  152. editEnded: function (e, info) {
  153. if (info.sheet.zh_setting) {
  154. const select = SpreadJsObj.getSelectObject(info.sheet);
  155. const col = info.sheet.zh_setting.cols[info.col];
  156. const validText = is_numeric(info.editingText) ? parseFloat(info.editingText) : (info.editingText ? trimInvalidChar(info.editingText) : null);
  157. const orgValue = select[col.field];
  158. if (orgValue == validText || ((!orgValue || orgValue === '') && (validText === ''))) {
  159. SpreadJsObj.reLoadRowData(info.sheet, info.row);
  160. return;
  161. }
  162. if (isNaN(validText)) {
  163. toastr.error('不能输入其它非数字类型字符');
  164. SpreadJsObj.reLoadRowData(info.sheet, info.row);
  165. return;
  166. }
  167. select[col.field] = validText;
  168. const yearmonth = col.field.split('_')[0];
  169. const mode = col.field.split('_')[1];
  170. let plan_gcl = 0;
  171. let plan_tp = 0;
  172. if (mode === 'tp') {
  173. plan_gcl = select.dgn_price && select.dgn_price !== 0 ? ZhCalc.round(ZhCalc.div(validText, select.dgn_price), tenderInfo.decimal.up) : 0;
  174. plan_tp = validText;
  175. select[yearmonth + '_gcl'] = plan_gcl;
  176. } else {
  177. plan_gcl = validText;
  178. plan_tp = select.dgn_price && select.dgn_price !== 0 ? ZhCalc.round(ZhCalc.mul(validText, select.dgn_price), tenderInfo.decimal.tp) : 0;
  179. select[yearmonth + '_tp'] = plan_tp;
  180. }
  181. const updateData = {
  182. lid: select.ledger_id,
  183. yearmonth,
  184. plan_gcl,
  185. plan_tp,
  186. };
  187. console.log(updateData);
  188. // postData(window.location.pathname + '/save', {type: 'mode', postData: updateData}, function (result) {
  189. // SpreadJsObj.reLoadRowData(info.sheet, info.row);
  190. // })
  191. }
  192. },
  193. deletePress: function (sheet) {
  194. return;
  195. },
  196. };
  197. ledgerSpread.bind(spreadNS.Events.EditEnded, ledgerSpreadObj.editEnded);
  198. SpreadJsObj.addDeleteBind(ledgerSpread, ledgerSpreadObj.deletePress);
  199. // 进度计算方式选择
  200. $('.mode-select').on('click', function () {
  201. const _self = $(this);
  202. postData(window.location.pathname + '/save', {type: 'mode', postData: $(this).data('mode')}, function (result) {
  203. _self.addClass('disabled').attr('disabled', true);
  204. _self.parents('.col-6').siblings('.col-6').find('button').removeClass('disabled').removeAttr('disabled');
  205. $('#mode-tips').show();
  206. $('#mode-cancel').show();
  207. $('#mode').modal('hide');
  208. schedule.mode = _self.data('mode');
  209. SpreadJsObj.reLoadSheetData(ledgerSpread.getActiveSheet());
  210. })
  211. });
  212. // 月份添加
  213. $('#add-month').click(function () {
  214. const range = $('#month-range').val();
  215. if(range === '') {
  216. toastr.error('请选择计划周期时间');
  217. return;
  218. }
  219. const addMonthList = [];
  220. const cycle = range.split(' ~ ');
  221. if(cycle.length === 1) {
  222. addMonthList.push(cycle[0]);
  223. } else {
  224. // 多个月份
  225. const back_year = parseInt(cycle[1].split('-')[0]);
  226. const back_month = parseInt(cycle[1].split('-')[1]);
  227. const front_year = parseInt(cycle[0].split('-')[0]);
  228. const front_month = parseInt(cycle[0].split('-')[1]);
  229. if(back_year > front_year) {
  230. const num = getDistanceMonth(cycle[0], cycle[1]);
  231. let j = 1;
  232. for (let i = 0; i <= num; i++) {
  233. if(front_month + i > 12*j) {
  234. j = j + 1;
  235. }
  236. const m = (front_month + i)%12 === 0 ? 12 : (front_month + i)%12;
  237. addMonthList.push((front_year + (j-1)) + '-' + (m < 10 ? '0' + m : m));
  238. }
  239. } else if (back_year === front_year) {
  240. // 小于1年并没有跨年
  241. for (let i = front_month; i <= back_month; i++) {
  242. addMonthList.push(back_year + '-' + (i < 10 ? '0' + i : i));
  243. }
  244. }
  245. }
  246. // 判断是否已添加本月份
  247. if (addMonthList.length > 0) {
  248. const hadmonth = [];
  249. for (const m of addMonthList) {
  250. const one = _.find(scheduleMonth, { yearmonth: m });
  251. console.log(one, m);
  252. if (one) {
  253. hadmonth.push(m);
  254. }
  255. }
  256. if (hadmonth.length > 0) {
  257. let html = '';
  258. for (const hm of hadmonth) {
  259. html += `<div class="alert alert-danger">${hm} 已创建</div>`;
  260. }
  261. $('#add-month-error-list').html(html);
  262. $('#add-month-error-list').show();
  263. return;
  264. }
  265. } else {
  266. toastr.error('请选择计划周期时间');
  267. return;
  268. }
  269. $('#add-month-error-list').html('');
  270. $('#add-month-error-list').hide();
  271. const _self = $(this);
  272. postData(window.location.pathname + '/save', {type: 'addmonth', postData: addMonthList}, function (result) {
  273. _self.addClass('disabled').attr('disabled', true);
  274. toastr.success('新增成功');
  275. setTimeout(function () {
  276. window.location.reload();
  277. }, 500)
  278. })
  279. });
  280. $('#month-table input[type="checkbox"]').click(function () {
  281. const selectedMonth = [];
  282. $('#month-table input:checkbox:checked').each(function () {
  283. selectedMonth.push('「' + $(this).parents('td').siblings('td').text() + '」');
  284. });
  285. if(selectedMonth.length > 0) {
  286. $('#del-month-list').text(selectedMonth.join(''));
  287. $('#del-month-list').parent().show();
  288. $('#del-month').removeAttr('disabled');
  289. } else {
  290. $('#del-month-list').parent().hide();
  291. $('#del-month').attr('disabled', true);
  292. }
  293. });
  294. $('#del-month').click(function () {
  295. const selectedMonth = [];
  296. $('#month-table input:checkbox:checked').each(function () {
  297. selectedMonth.push($(this).parents('td').siblings().text());
  298. });
  299. if (selectedMonth.length === 0) {
  300. toastr.error('请选择删除的计划周期');
  301. return;
  302. }
  303. const _self = $(this);
  304. postData(window.location.pathname + '/save', {type: 'delmonth', postData: selectedMonth}, function (result) {
  305. _self.addClass('disabled').attr('disabled', true);
  306. toastr.success('删除成功');
  307. setTimeout(function () {
  308. window.location.reload();
  309. }, 500)
  310. })
  311. });
  312. $.subMenu({
  313. menu: '#sub-menu', miniMenu: '#sub-mini-menu', miniMenuList: '#mini-menu-list',
  314. toMenu: '#to-menu', toMiniMenu: '#to-mini-menu',
  315. key: 'menu.1.0.0',
  316. miniHint: '#sub-mini-hint', hintKey: 'menu.hint.1.0.1',
  317. callback: function (info) {
  318. if (info.mini) {
  319. $('.panel-title').addClass('fluid');
  320. $('#sub-menu').removeClass('panel-sidebar');
  321. } else {
  322. $('.panel-title').removeClass('fluid');
  323. $('#sub-menu').addClass('panel-sidebar');
  324. }
  325. ledgerSpread.refresh();
  326. autoFlashHeight();
  327. }
  328. });
  329. });
  330. // 月份间隔
  331. function getDistanceMonth(startTime,endTime){
  332. startTime = new Date(startTime);
  333. endTime = new Date(endTime);
  334. var dateToMonth = 0;
  335. var startDate=startTime.getDate() + startTime.getHours()/24 + startTime.getMinutes()/24/60;
  336. var endDate=endTime.getDate() +endTime.getHours()/24 + endTime.getMinutes()/24/60;
  337. if(endDate >= startDate){
  338. dateToMonth = 0;
  339. }else{
  340. dateToMonth = -1;
  341. }
  342. let yearToMonth = (endTime.getYear() - startTime.getYear()) * 12;
  343. let monthToMonth = endTime.getMonth() - startTime.getMonth();
  344. return yearToMonth + monthToMonth + dateToMonth;
  345. }
  346. function setLeafData(tree) {
  347. const newtree = [];
  348. for (const t of tree) {
  349. const child = _.find(tree, { 'ledger_pid': t.ledger_id });
  350. if (!child && !t.is_leaf) {
  351. t.is_leaf = true;
  352. }
  353. newtree.push(t);
  354. }
  355. return newtree;
  356. }
  357. const is_numeric = (value) => {
  358. if (typeof(value) === 'object') {
  359. return false;
  360. } else {
  361. return !Number.isNaN(Number(value)) && value.toString().trim() !== '';
  362. }
  363. };