ledger.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. /**
  2. * 台账相关js
  3. *
  4. * @author Mai
  5. * @date 2018/02/05
  6. * @version
  7. */
  8. $(document).ready(function() {
  9. autoFlashHeight();
  10. const ledgerSpread = SpreadJsObj.createNewSpread($('#ledger-spread')[0]);
  11. SpreadJsObj.addDeleteBind(ledgerSpread);
  12. const ledgerTree = createNewPathTree({
  13. id: 'ledger_id',
  14. pid: 'ledger_pid',
  15. order: 'order',
  16. level: 'level',
  17. rootId: -1,
  18. keys: ['id', 'tender_id', 'ledger_id']
  19. });
  20. ledgerTree.loadDatas(ledger);
  21. SpreadJsObj.initSheet(ledgerSpread.getActiveSheet(), {
  22. cols: [
  23. {title: '项目节编号', field: 'code', width: 150, cellType: 'tree'},
  24. {title: '清单编号', field: 'b_code', width: 80},
  25. {title: '名称', field: 'name', width: 230},
  26. {title: '单位', field: 'unit', width: 50},
  27. {title: '单价', field: 'unit_price', width: 60, type: 'Number'},
  28. {title: '数量', field: 'quantity', width: 60, type: 'Number'},
  29. {title: '金额', field: 'total_price', width: 60, type: 'Number'},
  30. {title: '施工图原设计', field: 'design', width: 60},
  31. {title: '图(册)号', field: 'drawingCode', width: 80},
  32. {title: '备注', field: 'memo', width: 100}
  33. ],
  34. treeCol: 0,
  35. emptyRows: 3
  36. });
  37. SpreadJsObj.loadSheetData(ledgerSpread.getActiveSheet(), 'tree', ledgerTree);
  38. const treeOperationObj = {
  39. /**
  40. * 刷新顶部按钮是否可用
  41. * @param sheet
  42. * @param selections
  43. */
  44. refreshOperationValid: function (sheet, selections) {
  45. const setObjEnable = function (obj, enable) {
  46. if (enable) {
  47. obj.removeClass('disabled');
  48. } else {
  49. obj.addClass('disabled');
  50. }
  51. };
  52. const row = selections[0].row;
  53. const tree = sheet.zh_tree;
  54. if (!tree) { return; }
  55. const node = sheet.zh_tree.nodes[row];
  56. setObjEnable($('#delete'), node);
  57. setObjEnable($('#up-move'), node && node.order > 1);
  58. setObjEnable($('#down-move'), node && !tree.isLastSibling(node));
  59. setObjEnable($('#up-level'), node && tree.getParent(node));
  60. setObjEnable($('#down-level'), node && node.order > 1);
  61. },
  62. refreshTree: function (sheet, data) {
  63. SpreadJsObj.massOperationSheet(sheet, function () {
  64. const tree = sheet.zh_tree;
  65. // 处理删除
  66. if (data.delete) {
  67. for (const d of data.delete) {
  68. sheet.deleteRows(tree.nodes.indexOf(d), 1);
  69. }
  70. }
  71. // 处理新增
  72. if (data.create) {
  73. const newNodes = data.create;
  74. if (newNodes) {
  75. newNodes.sort(function (a, b) {
  76. const aIndex = tree.nodes.indexOf(a);
  77. const bIndex = tree.nodes.indexOf(b);
  78. return aIndex - bIndex;
  79. });
  80. for (const node of newNodes) {
  81. const index = tree.nodes.indexOf(node);
  82. sheet.addRows(index, 1);
  83. SpreadJsObj.reLoadRowData(sheet, index, 1);
  84. }
  85. }
  86. }
  87. // 处理更新
  88. if (data.update) {
  89. const rows = [];
  90. for (const u of data.update) {
  91. rows.push(tree.nodes.indexOf(u));
  92. }
  93. SpreadJsObj.reLoadRowsData(sheet, rows);
  94. }
  95. // 处理展开
  96. if (data.expand) {
  97. for (const e of data.expand) {
  98. const children = tree.getChildren(e);
  99. for (const child of children) {
  100. sheet.setRowVisible(tree.nodes.indexOf(child), child.visible);
  101. }
  102. }
  103. }
  104. });
  105. },
  106. /**
  107. * 新增节点
  108. * @param spread
  109. */
  110. addNode: function (spread) {
  111. const self = this;
  112. const sheet = spread.getActiveSheet();
  113. const row = sheet.getSelections()[0].row;
  114. const tree = sheet.zh_tree;
  115. if (!tree) { return; }
  116. const node = sheet.zh_tree.nodes[row];
  117. if (!node) { return; }
  118. SpreadJsObj.massOperationSheet(sheet, function () {
  119. tree.baseOperation('base-operation', node, 'add', function (result) {
  120. self.refreshTree(sheet, result);
  121. self.refreshOperationValid(sheet, sheet.getSelections());
  122. });
  123. });
  124. },
  125. /**
  126. * 删除选中节点
  127. * @param spread
  128. */
  129. deleteNode: function (spread) {
  130. const self = this;
  131. const sheet = spread.getActiveSheet();
  132. const row = sheet.getSelections()[0].row;
  133. const tree = sheet.zh_tree;
  134. if (!tree) { return; }
  135. const node = sheet.zh_tree.nodes[row];
  136. if (!node) { return; }
  137. const count = ledgerTree.getPosterity(node).length;
  138. tree.baseOperation('base-operation', node, 'delete', function (result) {
  139. sheet.deleteRows(row, count + 1);
  140. for (const data of result.update) {
  141. SpreadJsObj.reLoadRowData(sheet, tree.nodes.indexOf(data), tree.getPosterity(data).length + 1);
  142. }
  143. self.refreshOperationValid(sheet, sheet.getSelections());
  144. });
  145. },
  146. /**
  147. * 上移选中节点
  148. * @param spread
  149. */
  150. upMove: function (spread) {
  151. const self = this;
  152. const sheet = spread.getActiveSheet();
  153. const sel = sheet.getSelections()[0];
  154. const row = sel.row;
  155. const tree = sheet.zh_tree;
  156. if (!tree) { return; }
  157. const node = tree.nodes[row];
  158. if (!node) { return; }
  159. tree.baseOperation('base-operation', node, 'up-move', function (result) {
  160. for (const data of result.update) {
  161. SpreadJsObj.reLoadRowData(sheet, tree.nodes.indexOf(data), tree.getPosterity(data).length + 1);
  162. }
  163. sheet.setSelection(tree.nodes.indexOf(node), sel.col, sel.rowCount, sel.colCount);
  164. self.refreshOperationValid(sheet, sheet.getSelections());
  165. //sheet.moveTo(row, -1, tree.nodes.indexOf(node), -1, tree.getPosterity(node).length + 1, -1, GC.Spread.Sheets.CopyToOptions.value);
  166. });
  167. },
  168. /**
  169. * 下移选中节点
  170. * @param spread
  171. */
  172. downMove: function (spread) {
  173. const self = this;
  174. const sheet = spread.getActiveSheet();
  175. const sel = sheet.getSelections()[0];
  176. const row = sel.row;
  177. const tree = sheet.zh_tree;
  178. if (!tree) { return; }
  179. const node = tree.nodes[row];
  180. if (!node) { return; }
  181. tree.baseOperation('base-operation', node, 'down-move', function (result) {
  182. for (const data of result.update) {
  183. SpreadJsObj.reLoadRowData(sheet, tree.nodes.indexOf(data), tree.getPosterity(data).length + 1);
  184. }
  185. sheet.setSelection(tree.nodes.indexOf(node), sel.col, sel.rowCount, sel.colCount);
  186. self.refreshOperationValid(sheet, sheet.getSelections());
  187. });
  188. },
  189. /**
  190. * 升级选中节点
  191. * @param spread
  192. */
  193. upLevel: function (spread) {
  194. const self = this;
  195. const sheet = spread.getActiveSheet();
  196. const row = sheet.getSelections()[0].row;
  197. const tree = sheet.zh_tree;
  198. if (!tree) { return; }
  199. const node = tree.nodes[row];
  200. if (!node) { return; }
  201. tree.baseOperation('base-operation', node, 'up-level', function (result) {
  202. self.refreshTree(sheet, result);
  203. self.refreshOperationValid(sheet, sheet.getSelections());
  204. });
  205. },
  206. /**
  207. * 降级选中节点
  208. * @param spread
  209. */
  210. downLevel: function (spread) {
  211. const self = this;
  212. const sheet = spread.getActiveSheet();
  213. const row = sheet.getSelections()[0].row;
  214. const tree = sheet.zh_tree;
  215. if (!tree) { return; }
  216. const node = tree.nodes[row];
  217. if (!node) { return; }
  218. tree.baseOperation('base-operation', node, 'down-level', function (result) {
  219. self.refreshTree(sheet, result);
  220. self.refreshOperationValid(sheet, sheet.getSelections());
  221. });
  222. },
  223. /**
  224. * 编辑单元格响应事件
  225. * @param {Object} e
  226. * @param {Object} info
  227. */
  228. editEnded: function (e, info) {
  229. if (info.sheet.zh_setting) {
  230. const col = info.sheet.zh_setting.cols[info.col];
  231. const sortData = info.sheet.zh_dataType === 'tree' ? info.sheet.zh_tree.nodes : info.sheet.zh_data;
  232. const node = sortData[info.row];
  233. const data = {
  234. id: node.id,
  235. tender_id: node.tender_id,
  236. ledger_id: node.ledger_id
  237. };
  238. data[col.field] = col.type === 'Number' ? parseFloat(info.editingText) : info.editingText;
  239. info.sheet.zh_tree.update('update', data, function (result) {
  240. const rows = [];
  241. for (const r of result) {
  242. rows.push(sortData.indexOf(r));
  243. }
  244. SpreadJsObj.reLoadRowsData(info.sheet, rows);
  245. });
  246. }
  247. },
  248. /**
  249. * 粘贴单元格响应事件
  250. * @param e
  251. * @param info
  252. */
  253. clipboardPasted: function (e, info) {
  254. if (info.sheet.zh_setting && info.sheet.zh_dataType === 'tree') {
  255. const sortData = info.sheet.zh_tree.nodes;
  256. const datas = [], nodes = [];
  257. for (let iRow = 0; iRow < info.cellRange.rowCount; iRow ++) {
  258. const curRow = info.cellRange.row + iRow;
  259. const node = sortData[curRow];
  260. if (node) {
  261. const data = info.sheet.zh_tree.getNodeKeyData(node);
  262. for (let iCol = 0; iCol < info.cellRange.colCount; iCol++) {
  263. const curCol = info.cellRange.col + iCol;
  264. const colSetting = info.sheet.zh_setting.cols[curCol];
  265. data[colSetting.field] = info.sheet.getText(curRow, curCol);
  266. }
  267. datas.push(data);
  268. nodes.push(node);
  269. }
  270. }
  271. info.sheet.zh_tree.update('update', datas, function (result) {
  272. const rows = [];
  273. for (const data of result) {
  274. rows.push(sortData.indexOf(data));
  275. }
  276. SpreadJsObj.reLoadRowsData(info.sheet, rows);
  277. });
  278. }
  279. },
  280. /**
  281. * 删除按钮响应事件
  282. * @param sheet
  283. */
  284. deletePress: function (sheet) {
  285. if (sheet.zh_setting && sheet.zh_dataType === 'tree') {
  286. const sortData = sheet.zh_tree.nodes;
  287. const datas = [], nodes = [];
  288. const sel = sheet.getSelections()[0];
  289. for (let iRow = sel.row; iRow < sel.row + sel.rowCount; iRow++) {
  290. const node = sortData[iRow];
  291. if (node) {
  292. const data = sheet.zh_tree.getNodeKeyData(node);
  293. for (let iCol = sel.col; iCol < sel.col + sel.colCount; iCol++) {
  294. const colSetting = sheet.zh_setting.cols[iCol];
  295. data[colSetting.field] = null;
  296. }
  297. datas.push(data);
  298. nodes.push(node);
  299. }
  300. }
  301. sheet.zh_tree.update('update-info', datas, function (result) {
  302. const rows = [];
  303. for (const data of result) {
  304. rows.push(sortData.indexOf(data));
  305. }
  306. SpreadJsObj.reLoadRowsData(sheet, rows);
  307. });
  308. }
  309. },
  310. /**
  311. * 粘贴整块
  312. * @param spread
  313. * @param block
  314. */
  315. pasteBlock: function (spread, block) {
  316. const self = this;
  317. const sheet = spread.getActiveSheet();
  318. const row = sheet.getSelections()[0].row;
  319. const tree = sheet.zh_tree;
  320. if (!tree) { return; }
  321. const node = tree.nodes[row];
  322. if (!node) { return; }
  323. tree.pasteBlock('paste-block', node, block, function (result) {
  324. self.refreshTree(sheet, result);
  325. self.refreshOperationValid(sheet, sheet.getSelections());
  326. });
  327. }
  328. };
  329. ledgerSpread.bind(GC.Spread.Sheets.Events.SelectionChanged, function (e, info) {
  330. treeOperationObj.refreshOperationValid(info.sheet, info.newSelections);
  331. });
  332. ledgerSpread.bind(GC.Spread.Sheets.Events.EditEnded, treeOperationObj.editEnded);
  333. ledgerSpread.bind(GC.Spread.Sheets.Events.ClipboardPasted, treeOperationObj.clipboardPasted);
  334. SpreadJsObj.addDeleteBind(ledgerSpread, treeOperationObj.deletePress);
  335. ledgerSpread.bind(GC.Spread.Sheets.Events.ClipboardChanging, function (e, info) {
  336. const copyText = SpreadJsObj.getFilterCopyText(info.sheet);
  337. });
  338. ledgerSpread.bind(GC.Spread.Sheets.Events.ClipboardChanged, function (e, info) {
  339. console.log(info.copyData.text);
  340. });
  341. ledgerSpread.bind(GC.Spread.Sheets.Events.ClipboardPasting, function (e, info) {
  342. });
  343. // 绑定 删除等 顶部按钮
  344. $('#delete').click(function () {
  345. treeOperationObj.deleteNode(ledgerSpread);
  346. });
  347. $('#up-move').click(function () {
  348. treeOperationObj.upMove(ledgerSpread);
  349. });
  350. $('#down-move').click(function () {
  351. treeOperationObj.downMove(ledgerSpread);
  352. });
  353. $('#up-level').click(function () {
  354. treeOperationObj.upLevel(ledgerSpread);
  355. });
  356. $('#down-level').click(function () {
  357. treeOperationObj.downLevel(ledgerSpread);
  358. });
  359. treeOperationObj.refreshOperationValid(ledgerSpread.getActiveSheet(), ledgerSpread.getActiveSheet().getSelections());
  360. // 右键菜单
  361. $.contextMenu({
  362. selector: '#ledger-spread',
  363. build: function ($trigger, e) {
  364. const target = SpreadJsObj.safeRightClickSelection($trigger, e, ledgerSpread);
  365. return target.hitTestType === GC.Spread.Sheets.SheetArea.viewport || target.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
  366. },
  367. items: {
  368. 'create': {
  369. name: '新增',
  370. icon: 'fa-sign-in',
  371. callback: function (key, opt) {
  372. treeOperationObj.addNode(ledgerSpread);
  373. },
  374. visible: function(key, opt){
  375. const sheet = ledgerSpread.getActiveSheet();
  376. const selection = sheet.getSelections();
  377. const row = selection[0].row;
  378. const select = ledgerTree.nodes[row];
  379. return select;
  380. }
  381. },
  382. 'delete': {
  383. name: '删除',
  384. icon: 'fa-remove',
  385. callback: function (key, opt) {
  386. treeOperationObj.deleteNode(ledgerSpread);
  387. },
  388. visible: function (key, opt) {
  389. const sheet = ledgerSpread.getActiveSheet();
  390. const selection = sheet.getSelections();
  391. const row = selection[0].row;
  392. const select = ledgerTree.nodes[row];
  393. return select;
  394. }
  395. },
  396. 'copyBlock': {
  397. name: '复制整块',
  398. icon: 'fa-files-o',
  399. callback: function (key, opt) {
  400. /*ledgerSpread.commandManager().execute({
  401. cmd:"copy",
  402. sheetName:ledgerSpread.getActiveSheet().name()
  403. });*/
  404. treeOperationObj.block = [];
  405. const copyBlockList = [];
  406. const sheet = ledgerSpread.getActiveSheet();
  407. const sel = sheet.getSelections()[0];
  408. let iRow = sel.row;
  409. const pid = sheet.zh_tree.nodes[iRow].ledger_pid;
  410. while (iRow < sel.row + sel.rowCount) {
  411. const node = sheet.zh_tree.nodes[iRow];
  412. if (node.ledger_pid !== pid) {
  413. toast('error: 仅可同时选中同层节点', 'error', 'exclamation-circle');
  414. return;
  415. }
  416. copyBlockList.push(node.ledger_id);
  417. iRow += sheet.zh_tree.getPosterity(node).length + 1;
  418. }
  419. treeOperationObj.block = copyBlockList;
  420. },
  421. visible: function (key, opt) {
  422. const sheet = ledgerSpread.getActiveSheet();
  423. const selection = sheet.getSelections();
  424. const row = selection[0].row;
  425. const select = ledgerTree.nodes[row];
  426. return select;
  427. }
  428. },
  429. 'pasteBlock': {
  430. name: '粘贴',
  431. icon: 'fa-clipboard',
  432. disabled: function (key, opt) {
  433. const block = treeOperationObj.block || [];
  434. return block.length <= 0 && false;
  435. },
  436. callback: function (key, opt) {
  437. const block = treeOperationObj.block || [];
  438. if (block.length > 0) {
  439. treeOperationObj.pasteBlock(ledgerSpread, block);
  440. } else {
  441. document.execCommand('paste');
  442. }
  443. }
  444. }
  445. }
  446. });
  447. let stdChapter, stdBills;
  448. // 展开收起标准清单
  449. $('a', '#std-lib').bind('click', function () {
  450. const tab = $(this), tabPanel = $(tab.attr('content'));
  451. const showSideTools = function (show) {
  452. if (show) {
  453. $('.c-body.col-12').removeClass('col-12').addClass('col-8');
  454. $('.c-body.col-0').removeClass('col-0').addClass('col-4').show();
  455. } else {
  456. $('.c-body.col-8').removeClass('col-8').addClass('col-12');
  457. $('.c-body.col-4').removeClass('col-4').addClass('col-0').hide();
  458. }
  459. }
  460. if (!tab.hasClass('active')) {
  461. $('a', '#std-lib').removeClass('active');
  462. tab.addClass('active');
  463. showSideTools(tab.hasClass('active'));
  464. $('.tab-content .tab-pane').hide();
  465. tabPanel.show();
  466. if (tab.attr('content') === '#std-chapter' && !stdChapter) {
  467. stdChapter = new stdLib($('#std-chapter-spread')[0], 'chapter', {
  468. id: 'chapter_id',
  469. pid: 'pid',
  470. order: 'order',
  471. level: 'level',
  472. rootId: -1,
  473. keys: ['id', 'list_id', 'chapter_id'],
  474. }, {
  475. cols: [
  476. {title: '项目节编号', field: 'code', width: 120, readOnly: true, cellType: 'tree'},
  477. {title: '名称', field: 'name', width: 230, readOnly: true},
  478. {title: '单位', field: 'unit', width: 50, readOnly: true}
  479. ],
  480. treeCol: 0,
  481. emptyRows: 0
  482. });
  483. stdChapter.loadLib(1);
  484. } else if (tab.attr('content') === '#std-bills' && !stdBills) {
  485. stdBills = new stdLib($('#std-bills-spread')[0], 'bills', {
  486. id: 'bill_id',
  487. pid: 'pid',
  488. order: 'order',
  489. level: 'level',
  490. rootId: -1,
  491. keys: ['id', 'list_id', 'bill_id']
  492. }, {
  493. cols: [
  494. {title: '清单编号', field: 'code', width: 120, readOnly: true, cellType: 'tree'},
  495. {title: '名称', field: 'name', width: 230, readOnly: true},
  496. {title: '单位', field: 'unit', width: 50, readOnly: true}
  497. ],
  498. treeCol: 0,
  499. emptyRows: 0
  500. });
  501. stdBills.loadLib(1);
  502. }
  503. } else {
  504. tab.removeClass('active');
  505. showSideTools(tab.hasClass('active'));
  506. tabPanel.hide();
  507. }
  508. ledgerSpread.refresh();
  509. });
  510. class stdLib {
  511. constructor(obj, stdType, treeSetting, spreadSetting) {
  512. this.obj = obj;
  513. this.url = '/std/' + stdType;
  514. this.treeSetting = treeSetting;
  515. treeSetting.preUrl = this.url;
  516. this.spreadSetting = spreadSetting;
  517. this.spread = SpreadJsObj.createNewSpread(this.obj);
  518. SpreadJsObj.initSheet(this.spread.getActiveSheet(), this.spreadSetting);
  519. this.spread.getActiveSheet().bind(GC.Spread.Sheets.Events.CellDoubleClick, function (e, info) {
  520. const stdSheet = info.sheet;
  521. const mainSheet = ledgerSpread.getActiveSheet();
  522. if (!stdSheet.zh_setting || !stdSheet.zh_tree || !mainSheet.zh_tree) { return; }
  523. const stdTree = stdSheet.zh_tree;
  524. const stdNode = stdTree.nodes[info.row];
  525. const mainTree = mainSheet.zh_tree;
  526. const sel = mainSheet.getSelections()[0];
  527. const mainNode = mainTree.nodes[sel.row];
  528. if (!stdNode) { return; }
  529. mainTree.postData('add-by-std', mainNode, {
  530. tender_id: mainNode.tender_id,
  531. stdType: stdType,
  532. stdLibId: stdNode.list_id,
  533. stdNode: stdTree.getNodeKey(stdNode)
  534. }, function (result) {
  535. treeOperationObj.refreshTree(mainSheet, result);
  536. treeOperationObj.refreshOperationValid(mainSheet, mainSheet.getSelections());
  537. });
  538. });
  539. this.pathTree = createNewPathTree(this.treeSetting);
  540. }
  541. loadLib (listId) {
  542. const self = this;
  543. postData(this.url+'/get-data', {list_id: listId}, function (data) {
  544. self.pathTree.loadDatas(data);
  545. SpreadJsObj.loadSheetData(self.spread.getActiveSheet(), 'tree', self.pathTree);
  546. });
  547. }
  548. };
  549. });