revise_price.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. 'use strict';
  2. /**
  3. *
  4. *
  5. * @author Mai
  6. * @date
  7. * @version
  8. */
  9. const showSideTools = function (show) {
  10. const left = $('#left-view'), right = $('#right-view'), parent = left.parent();
  11. if (show) {
  12. right.show();
  13. autoFlashHeight();
  14. const percent = 100 - right.outerWidth() /parent.width() * 100;
  15. left.css('width', percent + '%');
  16. } else {
  17. left.width(parent.width());
  18. right.hide();
  19. }
  20. };
  21. const setPriceHint = function (show) {
  22. const hinticon = show ? 'fa-bell' : undefined;
  23. subMiniMenu.$children[2].hinticon = hinticon;
  24. subMenu.$children[2].hinticon = hinticon;
  25. };
  26. $(document).ready(() => {
  27. const ledgerGclSpreadSetting = {
  28. cols: [
  29. { title: '清单编号', colSpan: '1', rowSpan: '2', field: 'b_code', hAlign: 0, width: 80, formatter: '@' },
  30. { title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 200, formatter: '@' },
  31. { title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 60, formatter: '@' },
  32. { title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 80, type: 'Number' },
  33. ],
  34. emptyRows: 0,
  35. headRows: 1,
  36. headRowHeight: [32],
  37. headColWidth: [30],
  38. defaultRowHeight: 21,
  39. headerFont: '12px 微软雅黑',
  40. font: '12px 微软雅黑',
  41. readOnly: true,
  42. };
  43. const ledgerXmjSpreadSetting = {
  44. cols: [
  45. {title: '项目节编号', colSpan: '1', rowSpan: '1', field: 'code', hAlign: 0, width: 100, formatter: '@'},
  46. {title: '单位工程', colSpan: '1', rowSpan: '1', field: 'dwgc', hAlign: 0, width: 80, formatter: '@'},
  47. {title: '分部工程', colSpan: '1', rowSpan: '1', field: 'fbgc', hAlign: 0, width: 80, formatter: '@'},
  48. {title: '分项工程', colSpan: '1', rowSpan: '1', field: 'fxgc', hAlign: 0, width: 80, formatter: '@'},
  49. {title: '细目', colSpan: '1', rowSpan: '1', field: 'jldy', hAlign: 0, width: 80, formatter: '@'},
  50. {title: '计量单元', colSpan: '1', rowSpan: '1', field: 'bwmx', hAlign: 0, width: 80, formatter: '@'},
  51. ],
  52. emptyRows: 0,
  53. headRows: 1,
  54. headRowHeight: [32],
  55. headColWidth: [30],
  56. defaultRowHeight: 21,
  57. headerFont: '12px 微软雅黑',
  58. font: '12px 微软雅黑',
  59. readOnly: true,
  60. };
  61. const priceSpreadSetting = {
  62. cols: [
  63. { title: '清单编号', colSpan: '1', rowSpan: '2', field: 'b_code', hAlign: 0, width: 100, formatter: '@', readOnly: true },
  64. { title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 210, formatter: '@', readOnly: true },
  65. { title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 60, formatter: '@', readOnly: true },
  66. { title: '当前单价', colSpan: '1', rowSpan: '2', field: 'org_price', hAlign: 2, width: 80, type: 'Number', readOnly: true },
  67. { title: '调整后单价', colSpan: '1', rowSpan: '2', field: 'new_price', hAlign: 2, width: 80, type: 'Number' },
  68. { title: '备注', colSpan: '1', rowSpan: '2', field: 'memo', hAlign: 2, width: 150, formatter: '@' },
  69. ],
  70. emptyRows: 0,
  71. headRows: 1,
  72. headRowHeight: [32],
  73. headColWidth: [30],
  74. defaultRowHeight: 21,
  75. headerFont: '12px 微软雅黑',
  76. font: '12px 微软雅黑',
  77. readOnly,
  78. };
  79. autoFlashHeight();
  80. const priceSpread = SpreadJsObj.createNewSpread($('#price-spread')[0]);
  81. const priceSheet = priceSpread.getActiveSheet();
  82. SpreadJsObj.initSheet(priceSheet, priceSpreadSetting);
  83. class RevisePrice {
  84. constructor () {
  85. this.data = [];
  86. }
  87. resortData() {
  88. this.data.sort(function (a, b) {
  89. return a.order - b.order;
  90. });
  91. }
  92. loadDatas(datas) {
  93. this.data = datas;
  94. this.resortData();
  95. }
  96. loadUpdateData(updateData) {
  97. if (updateData.add) {
  98. for (const a of updateData.add) {
  99. this.data.push(a);
  100. }
  101. }
  102. if (updateData.update) {
  103. for (const u of updateData.update) {
  104. const d = this.data.find(function (x) {
  105. return u.id === x.id;
  106. });
  107. if (d) {
  108. _.assign(d, u);
  109. } else {
  110. this.data.push(d);
  111. }
  112. }
  113. }
  114. if (updateData.del) {
  115. _.remove(this.data, function (d) {
  116. return updateData.del.indexOf(d.id) >= 0;
  117. });
  118. }
  119. this.resortData();
  120. }
  121. }
  122. const revisePrice = new RevisePrice();
  123. const priceOprObj = {
  124. addRevisePrice(data) {
  125. const op = revisePrice.data.find(x => {
  126. return x.b_code === data.b_code && x.name === x.name && x.unit === x.unit && checkZero(ZhCalc.sub(x.org_price, data.unit_price));
  127. });
  128. if (op) {
  129. toastr.warning('已存在该单价调整');
  130. SpreadJsObj.locateData(priceSheet, op);
  131. return;
  132. }
  133. postData(window.location.pathname + '/update', { add: { b_code: data.b_code, name: data.name, unit: data.unit, unit_price: data.unit_price } }, result => {
  134. revisePrice.loadUpdateData(result);
  135. SpreadJsObj.reLoadSheetData(priceSheet);
  136. setPriceHint(revisePrice.data.length > 0);
  137. });
  138. },
  139. /**
  140. * 删除按钮响应事件
  141. * @param sheet
  142. */
  143. deletePress: function (sheet) {
  144. if (!sheet.zh_setting || readOnly) return;
  145. const sortData = sheet.zh_data;
  146. const datas = [];
  147. const sels = sheet.getSelections();
  148. if (!sels || !sels[0]) return;
  149. for (let iRow = sels[0].row; iRow < sels[0].row + sels[0].rowCount; iRow++) {
  150. let bDel = false;
  151. const node = sortData[iRow];
  152. if (node) {
  153. const data = {id: node.id};
  154. for (let iCol = sels[0].col; iCol < sels[0].col + sels[0].colCount; iCol++) {
  155. const style = sheet.getStyle(iRow, iCol);
  156. if (!style.locked) {
  157. const colSetting = sheet.zh_setting.cols[iCol];
  158. data[colSetting.field] = null;
  159. bDel = true;
  160. }
  161. }
  162. if (bDel) {
  163. datas.push(data);
  164. }
  165. }
  166. }
  167. if (datas.length > 0) {
  168. postData(window.location.pathname + '/update', {update: datas}, function (result) {
  169. revisePrice.loadUpdateData(result);
  170. SpreadJsObj.reLoadSheetData(priceSheet);
  171. }, function () {
  172. SpreadJsObj.reLoadSheetData(priceSheet);
  173. });
  174. }
  175. },
  176. delete: function (sheet) {
  177. if (!sheet.zh_setting || readOnly) return;
  178. const sortData = sheet.zh_data;
  179. const datas = [];
  180. const sels = sheet.getSelections();
  181. if (!sels || !sels[0]) return;
  182. for (let iRow = sels[0].row, iLen = sels[0].row + sels[0].rowCount; iRow < iLen; iRow++) {
  183. const node = sortData[iRow];
  184. datas.push(node.id);
  185. }
  186. if (datas.length > 0) {
  187. postData(window.location.pathname + '/update', {del: datas}, function (result) {
  188. revisePrice.loadUpdateData(result);
  189. SpreadJsObj.reLoadSheetData(priceSheet);
  190. setPriceHint(revisePrice.data.length > 0);
  191. }, function () {
  192. SpreadJsObj.reLoadSheetData(priceSheet);
  193. });
  194. }
  195. },
  196. editEnded: function (e, info) {
  197. if (!info.sheet.zh_setting || !info.sheet.zh_data) return;
  198. const node = info.sheet.zh_data[info.row];
  199. if (!node) return;
  200. const col = info.sheet.zh_setting.cols[info.col];
  201. const data = { update: { id: node.id, org_price: node.org_price } };
  202. const oldValue = node ? node[col.field] : null;
  203. const newValue = trimInvalidChar(info.editingText);
  204. if (oldValue == info.editingText || ((!oldValue || oldValue === '') && (newValue === ''))) {
  205. SpreadJsObj.reLoadRowData(info.sheet, info.row);
  206. return;
  207. }
  208. if (col.type === 'Number') {
  209. const num = _.toNumber(newValue);
  210. if (num) data.update[col.field] = num;
  211. } else {
  212. data.update[col.field] = newValue;
  213. }
  214. postData(window.location.pathname + '/update', data, function (result) {
  215. revisePrice.loadUpdateData(result);
  216. SpreadJsObj.reLoadSheetData(info.sheet);
  217. }, function () {
  218. SpreadJsObj.reLoadRowData(info.sheet, info.row);
  219. });
  220. },
  221. clipboardPasting(e, info) {
  222. const setting = info.sheet.zh_setting, sortData = info.sheet.zh_data;
  223. info.cancel = true;
  224. if (!setting || !sortData) return;
  225. const pasteData = info.pasteData.html
  226. ? SpreadJsObj.analysisPasteHtml(info.pasteData.html)
  227. : (info.pasteData.text === ''
  228. ? SpreadJsObj.Clipboard.getAnalysisPasteText()
  229. : SpreadJsObj.analysisPasteText(info.pasteData.text));
  230. const uDatas = [];
  231. for (let iRow = 0; iRow < info.cellRange.rowCount; iRow++) {
  232. const curRow = info.cellRange.row + iRow;
  233. const node = sortData[curRow];
  234. let bPaste = false;
  235. const data = {};
  236. for (let iCol = 0; iCol < info.cellRange.colCount; iCol++) {
  237. const curCol = info.cellRange.col + iCol;
  238. const colSetting = setting.cols[curCol];
  239. const value = trimInvalidChar(pasteData[iRow][iCol]);
  240. if (colSetting.type === 'Number') {
  241. const num = _.toNumber(value);
  242. if (num) {
  243. data[colSetting.field] = num;
  244. bPaste = true;
  245. }
  246. } else {
  247. data[colSetting.field] = value;
  248. bPaste = true;
  249. }
  250. }
  251. if (bPaste) {
  252. data.id = node.id;
  253. uDatas.push(data);
  254. }
  255. }
  256. const updateData = {};
  257. if (uDatas.length > 0) updateData.update = uDatas;
  258. if (uDatas.length > 0) {
  259. postData(window.location.pathname + '/update', updateData, function (result) {
  260. revisePrice.loadUpdateData(result);
  261. SpreadJsObj.reLoadSheetData(info.sheet);
  262. });
  263. } else {
  264. SpreadJsObj.reLoadSheetData(info.sheet);
  265. }
  266. },
  267. upMove: function () {
  268. const sels = priceSheet.getSelections(), sortData = priceSheet.zh_data;
  269. const node = sortData[sels[0].row];
  270. const preNode = sortData[sels[0].row - 1];
  271. const data = [
  272. {id: node.id, order: preNode.order},
  273. {id: preNode.id, order: node.order}
  274. ];
  275. postData(window.location.pathname + '/update', {update: data}, function (result) {
  276. revisePrice.loadUpdateData(result);
  277. SpreadJsObj.reLoadRowsData(priceSheet, [sels[0].row, sels[0].row - 1]);
  278. priceSheet.setSelection(sels[0].row - 1, sels[0].col, sels[0].rowCount, sels[0].colCount);
  279. });
  280. },
  281. downMove: function () {
  282. const sels = priceSheet.getSelections(), sortData = priceSheet.zh_data;
  283. const node = sortData[sels[0].row];
  284. const nextNode = sortData[sels[0].row + 1];
  285. const data = [
  286. {id: node.id, order: nextNode.order},
  287. {id: nextNode.id, order: node.order}
  288. ];
  289. postData(window.location.pathname + '/update', {update: data}, function (result) {
  290. revisePrice.loadUpdateData(result);
  291. SpreadJsObj.reLoadRowsData(priceSheet, [sels[0].row, sels[0].row + 1]);
  292. priceSheet.setSelection(sels[0].row + 1, sels[0].col, sels[0].rowCount, sels[0].colCount);
  293. });
  294. }
  295. };
  296. if (!readOnly) {
  297. priceSheet.bind(spreadNS.Events.EditEnded, priceOprObj.editEnded);
  298. priceSheet.bind(spreadNS.Events.ClipboardPasting, priceOprObj.clipboardPasting);
  299. SpreadJsObj.addDeleteBind(priceSpread, priceOprObj.deletePress);
  300. $.contextMenu({
  301. selector: '#price-spread',
  302. build: function ($trigger, e) {
  303. const target = SpreadJsObj.safeRightClickSelection($trigger, e, priceSpread);
  304. return target.hitTestType === spreadNS.SheetArea.viewport || target.hitTestType === spreadNS.SheetArea.rowHeader;
  305. },
  306. items: {
  307. del: {
  308. name: '删除',
  309. icon: 'fa-remove',
  310. callback: function (key, opt) {
  311. priceOprObj.delete(priceSheet);
  312. },
  313. disabled: function (key, opt) {
  314. const node = SpreadJsObj.getSelectObject(priceSheet);
  315. return node === undefined || node === null;
  316. },
  317. visible: function (key, opt) {
  318. return !readOnly;
  319. }
  320. },
  321. sprDel: '------------',
  322. upMove: {
  323. name: '上移',
  324. icon: 'fa-arrow-up',
  325. callback: function (key, opt) {
  326. priceOprObj.upMove();
  327. },
  328. disabled: function (key, opt) {
  329. const sels = priceSheet.getSelections();
  330. if (!sels || !sels[0] || sels[0].row === 0) return true;
  331. const row = sels[0].row;
  332. const node = revisePrice.data[row];
  333. return node === undefined || node === null;
  334. },
  335. visible: function (key, opt) {
  336. return !readOnly;
  337. }
  338. },
  339. downMove: {
  340. name: '下移',
  341. icon: 'fa-arrow-down',
  342. callback: function (key, opt) {
  343. priceOprObj.downMove();
  344. },
  345. disabled: function (key, opt) {
  346. const sels = priceSheet.getSelections();
  347. if (!sels || !sels[0] || sels[0].row >= revisePrice.data.length - 1) return true;
  348. const row = sels[0].row;
  349. const node = revisePrice.data[row];
  350. return node === undefined || node === null;
  351. },
  352. visible: function (key, opt) {
  353. return !readOnly;
  354. }
  355. }
  356. },
  357. });
  358. }
  359. class LedgerGcl {
  360. constructor(setting) {
  361. this.setting = setting;
  362. this.spread = SpreadJsObj.createNewSpread($(this.setting.selector)[0]);
  363. this.sheet = this.spread.getActiveSheet();
  364. SpreadJsObj.initSheet(this.sheet, this.setting.spreadSetting);
  365. this.xmjSpread = SpreadJsObj.createNewSpread($(this.setting.xmjSelector)[0]);
  366. this.xmjSheet = this.xmjSpread.getActiveSheet();
  367. SpreadJsObj.initSheet(this.xmjSheet, this.setting.xmjSpreadSetting);
  368. if (!readOnly) {
  369. this.spread.bind(spreadNS.Events.CellDoubleClick, function (e, info) {
  370. const gcl = SpreadJsObj.getSelectObject(info.sheet);
  371. priceOprObj.addRevisePrice(gcl);
  372. });
  373. }
  374. const self = this;
  375. this.spread.bind(spreadNS.Events.SelectionChanged, function (e, info) {
  376. self.loadLeafXmj();
  377. });
  378. }
  379. loadData(bills, pos) {
  380. gclGatherModel.loadLedgerData(bills);
  381. gclGatherModel.loadPosData(pos);
  382. this.gcl = gclGatherModel.gatherGclData();
  383. this.sheet && SpreadJsObj.loadSheetData(this.sheet, SpreadJsObj.DataType.Data, this.gcl);
  384. this.loadLeafXmj(0);
  385. }
  386. loadLeafXmj(iGclRow) {
  387. const gcl = iGclRow ? this.gcl[iGclRow] : SpreadJsObj.getSelectObject(this.sheet);
  388. SpreadJsObj.resetTopAndSelect(this.xmjSheet);
  389. if (gcl) {
  390. SpreadJsObj.loadSheetData(this.xmjSheet, SpreadJsObj.DataType.Data, gcl.leafXmjs);
  391. } else {
  392. SpreadJsObj.loadSheetData(this.xmjSheet, SpreadJsObj.DataType.Data, []);
  393. }
  394. }
  395. }
  396. const ledgerGcl = new LedgerGcl({
  397. selector: '#ledger-gcl-spread',
  398. spreadSetting: ledgerGclSpreadSetting,
  399. xmjSelector: '#ledger-xmj-spread',
  400. xmjSpreadSetting: ledgerXmjSpreadSetting,
  401. });
  402. $.subMenu({
  403. menu: '#sub-menu', miniMenu: '#sub-mini-menu', miniMenuList: '#mini-menu-list',
  404. toMenu: '#to-menu', toMiniMenu: '#to-mini-menu',
  405. key: 'menu.1.0.0',
  406. miniHint: '#sub-mini-hint', hintKey: 'menu.hint.1.0.1',
  407. callback: function (info) {
  408. if (info.mini) {
  409. $('.panel-title').addClass('fluid');
  410. $('#sub-menu').removeClass('panel-sidebar');
  411. } else {
  412. $('.panel-title').removeClass('fluid');
  413. $('#sub-menu').addClass('panel-sidebar');
  414. }
  415. autoFlashHeight();
  416. priceSpread.refresh();
  417. ledgerGcl.spread.refresh();
  418. }
  419. });
  420. $.divResizer({
  421. select: '#revise-right-spr',
  422. callback: function () {
  423. priceSpread.refresh();
  424. ledgerGcl.spread.refresh();
  425. }
  426. });
  427. $.divResizer({
  428. select: '#gcl-spr',
  429. callback: function () {
  430. priceSpread.refresh();
  431. ledgerGcl.spread.refresh();
  432. ledgerGcl.xmjSpread.refresh();
  433. }
  434. });
  435. postData('load', { filter: 'bills;pos;price' }, result => {
  436. revisePrice.loadDatas(result.price);
  437. SpreadJsObj.loadSheetData(priceSheet, SpreadJsObj.DataType.Data, revisePrice.data);
  438. ledgerGcl.loadData(result.bills, result.pos);
  439. $("[content='#ledgerGcl']").click();
  440. });
  441. $('a', '#side-menu').bind('click', function (e) {
  442. e.preventDefault();
  443. const tab = $(this), tabPanel = $(tab.attr('content'));
  444. // 展开工具栏、切换标签
  445. if (!tab.hasClass('active')) {
  446. $('a', '#side-menu').removeClass('active');
  447. tab.addClass('active');
  448. $('.tab-content .tab-pane').removeClass('active');
  449. tabPanel.addClass('active');
  450. showSideTools(tab.hasClass('active'));
  451. ledgerGcl.spread.refresh();
  452. ledgerGcl.xmjSpread.refresh();
  453. } else {// 收起工具栏
  454. tab.removeClass('active');
  455. tabPanel.removeClass('active');
  456. showSideTools(tab.hasClass('active'));
  457. }
  458. priceSpread.refresh();
  459. });
  460. });