spss_gather_ledger.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. const billsCompareField = ['quantity', 'total_price', ];
  2. const posCompareField = ['quantity'];
  3. $(document).ready(() => {
  4. autoFlashHeight();
  5. let isCache = false, selectTenders = [];
  6. const billsSpreadSetting = {
  7. cols: [
  8. {title: '项目节编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 185, formatter: '@', cellType: 'tree'},
  9. {title: '清单编号', colSpan: '1', rowSpan: '2', field: 'b_code', hAlign: 0, width: 100, formatter: '@'},
  10. {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 235, formatter: '@'},
  11. {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 60, formatter: '@'},
  12. {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 60, type: 'Number'},
  13. {title: '合计|数量', colSpan: '2|1', rowSpan: '1|1', field: 'sum_quantity', hAlign: 2, width: 80, type: 'Number'},
  14. {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'sum_total_price', hAlign: 2, width: 80, type: 'Number'},
  15. ],
  16. baseCols: [
  17. {title: '项目节编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 185, formatter: '@', cellType: 'tree'},
  18. {title: '清单编号', colSpan: '1', rowSpan: '2', field: 'b_code', hAlign: 0, width: 100, formatter: '@'},
  19. {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 235, formatter: '@'},
  20. {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 60, formatter: '@'},
  21. {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 60, type: 'Number'},
  22. ],
  23. extraCols: [
  24. {title: '标段1|数量', colSpan: '2|1', rowSpan: '1|1', field: 'quantity_1', hAlign: 2, width: 80, type: 'Number', formatTitle: '%s|数量', formatField: 'quantity_%d'},
  25. {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'total_price_1', hAlign: 2, width: 80, type: 'Number', formatField: 'total_price_%d'},
  26. ],
  27. endCols: [
  28. {title: '合计|数量', colSpan: '2|1', rowSpan: '1|1', field: 'sum_quantity', hAlign: 2, width: 80, type: 'Number'},
  29. {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'sum_total_price', hAlign: 2, width: 80, type: 'Number'},
  30. ],
  31. emptyRows: 0,
  32. headRows: 2,
  33. headRowHeight: [32, 25],
  34. defaultRowHeight: 21,
  35. headerFont: '12px 微软雅黑',
  36. font: '12px 微软雅黑',
  37. readOnly: true,
  38. frozenColCount: 5,
  39. frozenLineColor: '#93b5e4',
  40. };
  41. const posSpreadSetting = {
  42. cols: [
  43. {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 235, formatter: '@'},
  44. {title: '差值', colSpan: '1', rowSpan: '1', field: 'su,_quantity', hAlign: 2, width: 100, type: 'Number'},
  45. ],
  46. baseCols: [
  47. {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 235, formatter: '@'},
  48. ],
  49. extraCols: [
  50. {title: '标段1', colSpan: '1', rowSpan: '1', field: 'quantity_1', hAlign: 2, width: 100, type: 'Number', formatTitle: '%s', formatField: 'quantity_%d'},
  51. ],
  52. endCols: [
  53. {title: '合计', colSpan: '1', rowSpan: '1', field: 'sum_quantity', hAlign: 2, width: 100, type: 'Number'},
  54. ],
  55. emptyRows: 0,
  56. headRows: 1,
  57. headRowHeight: [32],
  58. defaultRowHeight: 21,
  59. headerFont: '12px 微软雅黑',
  60. font: '12px 微软雅黑',
  61. readOnly: true,
  62. };
  63. const billsSpread = SpreadJsObj.createNewSpread($('#bills-spread')[0]);
  64. const billsSheet = billsSpread.getActiveSheet();
  65. sjsSettingObj.setFxTreeStyle(billsSpreadSetting, sjsSettingObj.FxTreeStyle.jz);
  66. SpreadJsObj.initSheet(billsSheet, billsSpreadSetting);
  67. const posSpread = SpreadJsObj.createNewSpread($('#pos-spread')[0]);
  68. const posSheet = posSpread.getActiveSheet();
  69. SpreadJsObj.initSheet(posSheet, posSpreadSetting);
  70. const treeSetting = {
  71. id: 'ledger_id',
  72. pid: 'ledger_pid',
  73. order: 'order',
  74. level: 'level',
  75. full_path: 'full_path',
  76. rootId: -1,
  77. keys: ['id', 'tender_id', 'ledger_id'],
  78. calcFields: ['sum_tp'],
  79. // todo 判断同一清单时,是否应区分 清单是否含计量单元?
  80. // findNode: function(tree, node, parent, source) {
  81. // const siblings = parent ? parent.children : tree.children;
  82. // const checkData = { code: node.code || '', b_code: node.b_code || '', name: node.name || '', unit: node.unit || '', unit_price: node.unit_price || 0 };
  83. // return siblings.find(function (x) {
  84. // if (!checkData.b_code) return x.code === checkData.code && x.name === checkData.name;
  85. // const posRange = source.pos.getLedgerPos(node.id);
  86. // const hasPos = posRange && posRange.length > 0;
  87. // const xHasPos = x.pos && x.pos.length > 0;
  88. // return hasPos === xHasPos && x.b_code === checkData.b_code && x.name === checkData.name && x.unit === checkData.unit && x.unit_price === checkData.unit_price;
  89. // });
  90. // },
  91. loadInfo: function (node, sourceNode, index, source) {
  92. for (const f of billsCompareField) {
  93. node[f + '_' + index] = sourceNode[f];
  94. }
  95. const posRange = source.pos.getLedgerPos(sourceNode.id);
  96. if (posRange && posRange.length > 0) {
  97. if (!node.pos) node.pos = [];
  98. for (const p of posRange) {
  99. let nP = _.find(node.pos, {name: p.name || ''});
  100. if (!nP) {
  101. nP = {name: p.name || ''};
  102. node.pos.push(nP);
  103. }
  104. for (const f of posCompareField) {
  105. nP[f + '_' + index] = p[f];
  106. }
  107. }
  108. }
  109. },
  110. calcSum: function(data, count) {
  111. for (const f of billsCompareField) {
  112. data['sum_' + f] = 0;
  113. for (let i = 1; i <= count; i++) {
  114. data['sum_' + f] = ZhCalc.add(data['sum_' + f], data[f + '_' + i]);
  115. }
  116. }
  117. for (const p of data.pos) {
  118. for (const f of posCompareField) {
  119. p['sum_' + f] = 0;
  120. for (let i = 1; i <= count; i++) {
  121. p['sum_' + f] = ZhCalc.add(p['sum_' + f], p[f + '_' + i]);
  122. }
  123. }
  124. }
  125. },
  126. };
  127. const billsTree = createNewPathTree('tree-gather', treeSetting);
  128. const billsTreeSpreadObj = {
  129. selectionChanged: function (e, info) {
  130. if (info.newSelections) {
  131. if (!info.oldSelections || info.newSelections[0].row !== info.oldSelections[0].row) {
  132. posSpreadObj.loadCurPosData();
  133. }
  134. }
  135. },
  136. rebuildSpreadSetting(tenders) {
  137. billsSpreadSetting.cols = [...billsSpreadSetting.baseCols];
  138. posSpreadSetting.cols = [...posSpreadSetting.baseCols];
  139. for (const [i, tender] of tenders.entries()) {
  140. for (const col of billsSpreadSetting.extraCols) {
  141. const newCol = JSON.parse(JSON.stringify(col));
  142. if (newCol.formatTitle) newCol.title = newCol.formatTitle.replace('%s', tender.name);
  143. if (newCol.formatField) newCol.field = newCol.formatField.replace('%d', i + 1);
  144. billsSpreadSetting.cols.push(newCol);
  145. }
  146. for (const col of posSpreadSetting.extraCols) {
  147. const newCol = JSON.parse(JSON.stringify(col));
  148. if (newCol.formatTitle) newCol.title = newCol.formatTitle.replace('%s', tender.name);
  149. if (newCol.formatField) newCol.field = newCol.formatField.replace('%d', i + 1);
  150. posSpreadSetting.cols.push(newCol)
  151. }
  152. }
  153. billsSpreadSetting.cols.push(...billsSpreadSetting.endCols);
  154. posSpreadSetting.cols.push(...posSpreadSetting.endCols);
  155. }
  156. };
  157. billsSpread.bind(spreadNS.Events.SelectionChanged, billsTreeSpreadObj.selectionChanged);
  158. const posSpreadObj = {
  159. loadCurPosData: function () {
  160. const node = SpreadJsObj.getSelectObject(billsSheet);
  161. if (node) {
  162. SpreadJsObj.loadSheetData(posSheet, 'data', node.pos || []);
  163. } else {
  164. SpreadJsObj.loadSheetData(posSheet, 'data', []);
  165. }
  166. },
  167. };
  168. const tenderSelect = TenderSelectMulti({
  169. title: '汇总标段',
  170. type: 'gather',
  171. dataType: 'ledger',
  172. afterSelect: function(select) {
  173. const data = { filter: 'ledger', tender: select };
  174. postData(`/sp/${spid}/spss/load`, data, function(result) {
  175. isCache = false;
  176. billsTreeSpreadObj.rebuildSpreadSetting(result);
  177. SpreadJsObj.reLoadSheetHeader(billsSheet);
  178. SpreadJsObj.reLoadSheetHeader(posSheet);
  179. treeSetting.calcFields = ['sum_total_price'];
  180. for (let i = 1; i <= result.length; i++) {
  181. treeSetting.calcFields.push('total_price_' + i);
  182. }
  183. const tenderTreeSetting = {
  184. id: 'ledger_id', pid: 'ledger_pid', order: 'order', level: 'level',
  185. rootId: -1,
  186. keys: ['id', 'tender_id', 'ledger_id'],
  187. calcFields: ['total_price'],
  188. };
  189. const posSetting = { id: 'id', ledgerId: 'lid' };
  190. const tenders = [];
  191. for (const t of result) {
  192. selectTenders.push({ id: t.id, name: t.name, stage_filter: t.stage_filter });
  193. const tender = {
  194. billsTree: createNewPathTree('ledger', tenderTreeSetting),
  195. pos: new PosData(posSetting),
  196. };
  197. tender.billsTree.loadDatas(t.bills);
  198. tender.pos.loadDatas(t.pos);
  199. tenders.push(tender);
  200. }
  201. billsTree.clearDatas();
  202. billsTree.loadGatherData(tenders);
  203. treeCalc.calculateAll(billsTree);
  204. SpreadJsObj.loadSheetData(billsSheet, SpreadJsObj.DataType.Tree, billsTree, true);
  205. posSpreadObj.loadCurPosData();
  206. $('#stash-hint').html(`当前显示:${moment(data.create_time).format('YYYY-MM-DD HH:mm:ss')} (${data.user_name})`);
  207. });
  208. },
  209. });
  210. $('#gather-select').click(tenderSelect.showSelect);
  211. $('#export-excel').click(function() {
  212. const excelData = [];
  213. for (const node of billsTree.nodes) {
  214. const data = {};
  215. for (const c of billsSpreadSetting.cols) {
  216. data[c.field] = node[c.field];
  217. }
  218. excelData.push(data);
  219. for (const p of node.pos) {
  220. const pData = {};
  221. for (const c of posSpreadSetting.cols) {
  222. pData[c.field] = p[c.field];
  223. }
  224. excelData.push(pData);
  225. }
  226. }
  227. SpreadExcelObj.exportSimpleXlsxSheet(billsSpreadSetting, excelData, "台账汇总.xlsx");
  228. });
  229. $.divResizer({
  230. select: '#pos-resize',
  231. callback: function () {
  232. billsSpread.refresh();
  233. let bcontent = $(".bcontent-wrap") ? $(".bcontent-wrap").height() : 0;
  234. $(".sp-wrap").height(bcontent-30);
  235. posSpread.refresh();
  236. }
  237. });
  238. // 显示层次
  239. (function (select, sheet) {
  240. $(select).click(function () {
  241. if (!sheet.zh_tree) return;
  242. const tag = $(this).attr('tag');
  243. const tree = sheet.zh_tree;
  244. switch (tag) {
  245. case "1":
  246. case "2":
  247. case "3":
  248. case "4":
  249. case "5":
  250. tree.expandByLevel(parseInt(tag));
  251. SpreadJsObj.refreshTreeRowVisible(sheet);
  252. break;
  253. case "last":
  254. tree.expandByCustom(() => { return true; });
  255. SpreadJsObj.refreshTreeRowVisible(sheet);
  256. break;
  257. case "leafXmj":
  258. tree.expandToLeafXmj();
  259. SpreadJsObj.refreshTreeRowVisible(sheet);
  260. break;
  261. case "differ":
  262. tree.expandByCustom(function (x) {
  263. const posterity = tree.getPosterity(x);
  264. if (posterity.length === 0) return x.differ_qty || x.differ_tp;
  265. for (const p of posterity) {
  266. if (x.differ_qty || x.differ_tp) return true;
  267. }
  268. return false;
  269. });
  270. SpreadJsObj.refreshTreeRowVisible(sheet);
  271. }
  272. });
  273. })('a[name=showLevel]', billsSheet);
  274. $.subMenu({
  275. menu: '#sub-menu', miniMenu: '#sub-mini-menu', miniMenuList: '#mini-menu-list',
  276. toMenu: '#to-menu', toMiniMenu: '#to-mini-menu',
  277. key: 'menu.1.0.0',
  278. miniHint: '#sub-mini-hint', hintKey: 'menu.hint.1.0.1',
  279. callback: function (info) {
  280. if (info.mini) {
  281. $('.panel-title').addClass('fluid');
  282. $('#sub-menu').removeClass('panel-sidebar');
  283. $('.c-body table thead').css('left', '56px');
  284. } else {
  285. $('.panel-title').removeClass('fluid');
  286. $('#sub-menu').addClass('panel-sidebar');
  287. $('.c-body table thead').css('left', '176px');
  288. }
  289. autoFlashHeight();
  290. billsSpread.refresh();
  291. posSpread.refresh();
  292. }
  293. });
  294. const spssStash = SpssStash({
  295. type: 'gather_ledger',
  296. url: `/sp/${spid}/spss/stash`,
  297. getCurStashData: function() {
  298. if (!billsTree || billsTree.nodes.length === 0) {
  299. toastr.warning('当前无数据可暂存,请先汇总标段后,再操作');
  300. return null;
  301. }
  302. if (isCache) {
  303. toastr.warning('当前数据为暂存数据,请勿重复保存');
  304. return null;
  305. }
  306. const data = { result: { bills: billsTree.getDefaultData(billsTree.nodes) } };
  307. data.select = selectTenders;
  308. return data;
  309. },
  310. loadStashData: function(data) {
  311. isCache = true;
  312. billsTreeSpreadObj.rebuildSpreadSetting(data.spss_select);
  313. SpreadJsObj.reLoadSheetHeader(billsSheet);
  314. SpreadJsObj.reLoadSheetHeader(posSheet);
  315. billsTree.clearDatas();
  316. billsTree.loadDatas(data.spss_result.bills);
  317. SpreadJsObj.loadSheetData(billsSheet, SpreadJsObj.DataType.Tree, billsTree, true);
  318. posSpreadObj.loadCurPosData();
  319. $('#stash-hint').html(`当前显示:${moment(data.create_time).format('YYYY-MM-DD HH:mm:ss')} (${data.user_name})`);
  320. }
  321. });
  322. $('#stash').click(() => { spssStash.showStash(); });
  323. });