std_billsGuidance_lib.js 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178
  1. 'use strict';
  2. /**
  3. *
  4. *
  5. * @author Zhong
  6. * @date 2018/6/11
  7. * @version
  8. */
  9. const billsGuidance = (function () {
  10. let currentLib = null;
  11. //库类型
  12. const libType = {'guidance': 1, 'elf': 2}; //清单指引、清单精灵
  13. const libTypeText = {1: '清单指引', 2: '清单精灵'};
  14. const libSel = $('#stdBillsGuidanceLibSelect');
  15. //工作内容
  16. let stdBillsJobData = [];
  17. //项目特征
  18. let stdBillsFeatureData = [];
  19. const bills = {
  20. dom: $('#billsGuidance_bills'),
  21. workBook: null,
  22. cache: [],
  23. tree: null,
  24. controller: null,
  25. treeSetting: {
  26. emptyRowHeader: true,
  27. rowHeaderWidth: 15,
  28. treeCol: 0,
  29. emptyRows: 0,
  30. headRows: 1,
  31. headRowHeight: [40],
  32. defaultRowHeight: 21,
  33. cols: [{
  34. width: 160,
  35. readOnly: true,
  36. head: {
  37. titleNames: ["项目编码"],
  38. spanCols: [1],
  39. spanRows: [1],
  40. vAlign: [1],
  41. hAlign: [1],
  42. font: ["Arial"]
  43. },
  44. data: {
  45. field: "code",
  46. vAlign: 1,
  47. hAlign: 0,
  48. font: "Arial"
  49. }
  50. }, {
  51. width: 220,
  52. readOnly: true,
  53. head: {
  54. titleNames: ["项目名称"],
  55. spanCols: [1],
  56. spanRows: [1],
  57. vAlign: [1],
  58. hAlign: [1],
  59. font: ["Arial"]
  60. },
  61. data: {
  62. field: "name",
  63. vAlign: 1,
  64. hAlign: 0,
  65. font: "Arial"
  66. }
  67. },
  68. {
  69. width: 45,
  70. readOnly: true,
  71. showHint: true,
  72. head: {
  73. titleNames: ["计量单位"],
  74. spanCols: [1],
  75. spanRows: [1],
  76. vAlign: [1],
  77. hAlign: [1],
  78. font: ["Arial"]
  79. },
  80. data: {
  81. field: "unit",
  82. vAlign: 1,
  83. hAlign: 1,
  84. font: "Arial"
  85. }
  86. }
  87. ]
  88. },
  89. headers: [
  90. {name: '项目编码', dataCode: 'code', width: 160, vAlign: 'center', hAlign: 'left', formatter: '@'},
  91. {name: '项目名称', dataCode: 'name', width: 220, vAlign: 'center', hAlign: 'left', formatter: '@'},
  92. {name: '单位', dataCode: 'unit', width: 45, vAlign: 'center', hAlign: 'center', formatter: '@'},
  93. ],
  94. events: {
  95. SelectionChanging: function (sender, info) {
  96. billsInitSel(info.newSelections[0].row);
  97. },
  98. CellDoubleClick: function (sender, args) {
  99. if(!bills.tree){
  100. return;
  101. }
  102. let node = bills.tree.items[args.row];
  103. if(!node){
  104. return;
  105. }
  106. if(node.children.length === 0){
  107. //插入清单
  108. if (/\//.test(node.data.unit)) {
  109. let canAdd = true;
  110. $.bootstrapLoading.start();
  111. let existB = projectObj.project.Bills.sameStdCodeBillsData(node.data.code);
  112. if (existB) {
  113. let std = JSON.parse(JSON.stringify(node.data));
  114. std.unit = existB.unit;
  115. canAdd = ProjectController.addBills(projectObj.project, projectObj.mainController, std);
  116. if(canAdd !== null || canAdd !== false){
  117. //插入选中的定额
  118. let addRationDatas = currentLib.type && currentLib.type === libType.elf ? getInsertElfRationData() : getInsertRationData(getCheckedRows());
  119. insertRations(addRationDatas);
  120. }
  121. if(canAdd === false && $.bootstrapLoading.isLoading()){
  122. $.bootstrapLoading.end();
  123. }
  124. } else {
  125. ConfirmModal.stdBillsUnit.check(node.data, function (std) {
  126. canAdd = ProjectController.addBills(projectObj.project, projectObj.mainController, std);
  127. if(canAdd !== null || canAdd !== false){
  128. //插入选中的定额
  129. let addRationDatas = currentLib.type && currentLib.type === libType.elf ? getInsertElfRationData() : getInsertRationData(getCheckedRows());
  130. insertRations(addRationDatas);
  131. }
  132. if(canAdd === false && $.bootstrapLoading.isLoading()){
  133. $.bootstrapLoading.end();
  134. }
  135. }, function () {
  136. if($.bootstrapLoading.isLoading()){
  137. $.bootstrapLoading.end();
  138. }
  139. });
  140. }
  141. }
  142. else {
  143. let insert = billsLibObj.insertBills(stdBillsJobData, stdBillsFeatureData, node);
  144. if(insert){
  145. //插入选中的定额
  146. let addRationDatas = currentLib.type && currentLib.type === libType.elf ? getInsertElfRationData() : getInsertRationData(getCheckedRows());
  147. insertRations(addRationDatas);
  148. }
  149. }
  150. }
  151. else {
  152. node.setExpanded(!node.expanded);
  153. //设置展开收起状态
  154. sessionStorage.setItem('stdBillsGuidanceExpState', bills.tree.getExpState(bills.tree.items));
  155. renderSheetFunc(args.sheet, function () {
  156. let iCount = node.posterityCount(), i, child;
  157. for (i = 0; i < iCount; i++) {
  158. child = bills.tree.items[args.row + i + 1];
  159. args.sheet.setRowVisible(args.row + i + 1, child.visible, args.sheetArea);
  160. }
  161. args.sheet.invalidateLayout();
  162. });
  163. args.sheet.repaint();
  164. }
  165. }
  166. }
  167. };
  168. //项目指引类型
  169. const itemType = {
  170. job: 0,
  171. ration: 1
  172. };
  173. const guideItem = {
  174. dom: $('#billsGuidance_items'),
  175. workBook: null,
  176. tree: null,
  177. controller: null,
  178. treeSetting: {
  179. treeCol: 1,
  180. emptyRows: 0,
  181. headRows: 1,
  182. headRowHeight: [40],
  183. defaultRowHeight: 21,
  184. cols: [
  185. {
  186. width: 35,
  187. readOnly: false,
  188. head: {
  189. titleNames: ["选择"],
  190. spanCols: [1],
  191. spanRows: [1],
  192. vAlign: [1],
  193. hAlign: [1],
  194. font: ["Arial"]
  195. },
  196. data: {
  197. field: "select",
  198. vAlign: 1,
  199. hAlign: 1,
  200. font: "Arial"
  201. }
  202. },
  203. {
  204. width: 420,
  205. readOnly: false,
  206. head: {
  207. titleNames: ["项目指引"],
  208. spanCols: [1],
  209. spanRows: [1],
  210. vAlign: [1],
  211. hAlign: [1],
  212. font: ["Arial"]
  213. },
  214. data: {
  215. field: "name",
  216. vAlign: 1,
  217. hAlign: 0,
  218. font: "Arial"
  219. }
  220. }
  221. ]
  222. },
  223. headers: [
  224. {name: '选择', dataCode: 'select', width: 35, vAlign: 'center', hAlign: 'center', formatter: '@'},
  225. {name: '项目指引', dataCode: 'name', width: 300, vAlign: 'center', hAlign: 'left', formatter: '@'},
  226. ],
  227. events: {
  228. EditStarting: function (sender, args) {
  229. if(!bills.tree || guideItem.headers[args.col]['dataCode'] === 'name'){
  230. args.cancel = true;
  231. }
  232. },
  233. ButtonClicked: function (sender, args) {
  234. if(args.sheet.isEditing()){
  235. args.sheet.endEdit(true);
  236. }
  237. refreshInsertRation();
  238. },
  239. CellDoubleClick: function (sender, args) {
  240. if(!bills.tree || !bills.tree.selected){
  241. return;
  242. }
  243. let node = bills.tree.selected.guidance.tree.selected;
  244. if(!node){
  245. return;
  246. }
  247. if(node.children.length === 0){
  248. if(guideItem.headers[args.col]['dataCode'] === 'name'){
  249. insertRations(getInsertRationData([args.row]));
  250. }
  251. }
  252. else {
  253. node.setExpanded(!node.expanded);
  254. renderSheetFunc(args.sheet, function () {
  255. let iCount = node.posterityCount(), i, child;
  256. for (i = 0; i < iCount; i++) {
  257. child = bills.tree.selected.guidance.tree.items[args.row + i + 1];
  258. args.sheet.setRowVisible(args.row + i + 1, child.visible, args.sheetArea);
  259. }
  260. args.sheet.invalidateLayout();
  261. });
  262. args.sheet.repaint();
  263. }
  264. }
  265. }
  266. };
  267. const elfItem = {
  268. dom: $('#billsGuidance_items'),
  269. workBook: null,
  270. tree: null,
  271. controller: null,
  272. treeSetting: {
  273. treeCol: 0,
  274. emptyRows: 0,
  275. headRows: 1,
  276. headRowHeight: [40],
  277. defaultRowHeight: 21,
  278. cols: [
  279. {
  280. width: 250,
  281. readOnly: true,
  282. head: {
  283. titleNames: ["施工工序"],
  284. spanCols: [1],
  285. spanRows: [1],
  286. vAlign: [1],
  287. hAlign: [1],
  288. font: ["Arial"]
  289. },
  290. data: {
  291. field: "name",
  292. vAlign: 1,
  293. hAlign: 1,
  294. font: "Arial"
  295. }
  296. },
  297. {
  298. width: 250,
  299. readOnly: false,
  300. head: {
  301. titleNames: ["选项"],
  302. spanCols: [1],
  303. spanRows: [1],
  304. vAlign: [1],
  305. hAlign: [1],
  306. font: ["Arial"]
  307. },
  308. data: {
  309. field: "options",
  310. vAlign: 1,
  311. hAlign: 0,
  312. font: "Arial"
  313. }
  314. }
  315. ]
  316. },
  317. headers: [
  318. {name: '施工工序', dataCode: 'name', width: 250, vAlign: 'center', hAlign: 'center', formatter: '@'},
  319. {name: '选项', dataCode: 'options', width: 250, vAlign: 'center', hAlign: 'left', formatter: '@'},
  320. ],
  321. events: {
  322. CellClick: function (sender, args) {
  323. if(elfItem.headers[args.col]['dataCode'] === 'options' && args.sheetArea === 3){
  324. if(!args.sheet.getCell(args.row, args.col).locked() && !args.sheet.isEditing()){
  325. args.sheet.startEdit();
  326. }
  327. }
  328. },
  329. ClipboardPasting: function (sender, info) {
  330. info.cancel = true;
  331. }
  332. }
  333. };
  334. const options = {
  335. workBook: {
  336. tabStripVisible: false,
  337. allowContextMenu: false,
  338. allowCopyPasteExcelStyle : false,
  339. allowExtendPasteRange: false,
  340. allowUserDragDrop : false,
  341. allowUserDragFill: false,
  342. scrollbarMaxAlign : true
  343. },
  344. sheet: {
  345. protectionOptions: {allowResizeRows: true, allowResizeColumns: true},
  346. clipBoardOptions: GC.Spread.Sheets.ClipboardPasteOptions.values
  347. }
  348. };
  349. //渲染时方法,停止渲染
  350. //@param {Object}sheet {Function}func @return {void}
  351. function renderSheetFunc(sheet, func){
  352. sheet.suspendEvent();
  353. sheet.suspendPaint();
  354. if(func){
  355. func();
  356. }
  357. sheet.resumeEvent();
  358. sheet.resumePaint();
  359. }
  360. //设置表选项
  361. //@param {Object}workBook {Object}opts @return {void}
  362. function setOptions (workBook, opts) {
  363. for(let opt in opts.workBook){
  364. workBook.options[opt] = opts.workBook[opt];
  365. }
  366. for(let opt in opts.sheet){
  367. workBook.getActiveSheet().options[opt] = opts.sheet[opt];
  368. }
  369. }
  370. //建表头
  371. //@param {Object}sheet {Array}headers @return {void}
  372. function buildHeader(sheet, headers) {
  373. let fuc = function () {
  374. sheet.setColumnCount(headers.length);
  375. sheet.setRowHeight(0, 40, GC.Spread.Sheets.SheetArea.colHeader);
  376. for(let i = 0, len = headers.length; i < len; i++){
  377. sheet.setValue(0, i, headers[i].name, GC.Spread.Sheets.SheetArea.colHeader);
  378. sheet.setColumnWidth(i, headers[i].width, GC.Spread.Sheets.SheetArea.colHeader);
  379. if(headers[i].formatter){
  380. sheet.setFormatter(-1, i, headers[i].formatter);
  381. }
  382. sheet.getRange(-1, i, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[headers[i]['hAlign']]);
  383. sheet.getRange(-1, i, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[headers[i]['vAlign']]);
  384. }
  385. };
  386. renderSheetFunc(sheet, fuc);
  387. }
  388. //表监听事件
  389. //@param {Object}workBook @return {void}
  390. function bindEvent(workBook, events) {
  391. if(Object.keys(events).length === 0){
  392. return;
  393. }
  394. const Events = GC.Spread.Sheets.Events;
  395. for(let event in events){
  396. workBook.bind(Events[event], events[event]);
  397. }
  398. }
  399. //建表
  400. //@param {Object}module @return {void}
  401. function buildSheet(module) {
  402. if(!module.workBook){
  403. module.workBook = new GC.Spread.Sheets.Workbook(module.dom[0], {sheetCount: 1});
  404. sheetCommonObj.spreadDefaultStyle(module.workBook);
  405. let sheet = module.workBook.getActiveSheet();
  406. if(module === bills){
  407. //默认初始可控制焦点在清单表中
  408. module.workBook.focus();
  409. sheet.options.isProtected = true;
  410. sheet.name('stdBillsGuidance_bills');
  411. //设置悬浮提示
  412. TREE_SHEET_HELPER.initSetting(bills.dom[0], bills.treeSetting);
  413. }
  414. if(module === guideItem){
  415. sheet.options.isProtected = true;
  416. sheet.getRange(-1, 0, -1, 1).locked(false);
  417. sheet.getRange(-1, 1, -1, 1).locked(true);
  418. }
  419. if(module === elfItem){
  420. sheet.options.isProtected = true;
  421. sheet.getRange(-1, 0, -1, 1).locked(true);
  422. sheet.getRange(-1, 1, -1, 1).locked(false);
  423. }
  424. setOptions(module.workBook, options);
  425. buildHeader(module.workBook.getActiveSheet(), module.headers);
  426. bindEvent(module.workBook, module.events);
  427. }
  428. }
  429. //清空表数据
  430. //@param {Object}sheet {Array}headers {Number}rowCount @return {void}
  431. function cleanData(sheet, headers, rowCount){
  432. renderSheetFunc(sheet, function () {
  433. sheet.clear(-1, 0, -1, headers.length, GC.Spread.Sheets.SheetArea.viewport, GC.Spread.Sheets.StorageType.data);
  434. if (rowCount > 0) {
  435. sheet.setRowCount(rowCount);
  436. }
  437. });
  438. }
  439. //初始化各工作表
  440. //@param {Array}modules @return {void}
  441. function initWorkBooks(modules){
  442. for(let module of modules){
  443. buildSheet(module);
  444. }
  445. }
  446. //初始化并输出树
  447. //@param {Object}module {Object}sheet {Object}treeSetting {Array}datas
  448. function initTree(module, sheet, treeSetting, datas){
  449. module.tree = idTree.createNew({id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1, autoUpdate: true});
  450. module.controller = TREE_SHEET_CONTROLLER.createNew(module.tree, sheet, treeSetting);
  451. module.tree.loadDatas(datas);
  452. if(module === bills){
  453. initExpandStat();
  454. }
  455. module.controller.showTreeData();
  456. }
  457. //项目指引表焦点控制
  458. //@param {Number}row @return {void}
  459. function guideItemInitSel(row){
  460. let billsNode = bills.tree.selected;
  461. let node = null;
  462. if(billsNode && billsNode.guidance.tree){
  463. node = billsNode.guidance.tree.items[row];
  464. if(node){
  465. billsNode.guidance.tree.selected = node;
  466. }
  467. }
  468. }
  469. //清单精灵表焦点控制
  470. //@param {Number}row @return {void}
  471. function elfItemInitSel(row){
  472. let billsNode = bills.tree.selected;
  473. let node = null;
  474. if(billsNode && billsNode.elf.tree){
  475. node = billsNode.elf.tree.items[row];
  476. if(node){
  477. billsNode.elf.tree.selected = node;
  478. }
  479. }
  480. }
  481. //根据项目指引的类型设置单元格类型,定额类型的项目指引为复选框
  482. //@param {Array}nodes @return {void}
  483. function setItemCellType(nodes){
  484. //设置单元格类型
  485. const base = new GC.Spread.Sheets.CellTypes.Base();
  486. const checkBox = new GC.Spread.Sheets.CellTypes.CheckBox();
  487. const sheet = guideItem.workBook.getActiveSheet();
  488. renderSheetFunc(sheet, function(){
  489. for(let node of nodes){
  490. sheet.setCellType(node.serialNo(), 0, node.data.type === itemType.ration ? checkBox : base);
  491. }
  492. });
  493. }
  494. //清单表焦点控制
  495. //@param {Number}row @return {void}
  496. function billsInitSel(row){
  497. if(currentLib.type && currentLib.type === libType.elf){
  498. billsSelElf(row);
  499. }else {
  500. billsSelGuidance(row);
  501. }
  502. }
  503. //清单焦点变换-清单指引操作
  504. //@param {Number}row @return {void}
  505. function billsSelGuidance(row){
  506. let guideSheet = guideItem.workBook.getActiveSheet();
  507. cleanData(guideSheet, guideItem.headers, -1);
  508. if(!bills.tree){
  509. return;
  510. }
  511. let node = bills.tree.items[row];
  512. if(!node){
  513. return;
  514. }
  515. bills.tree.selected = node;
  516. refreshInsertRation();
  517. if(!node.guidance.tree){
  518. CommonAjax.post('/billsGuidance/api/getItemsByBills', {guidanceLibID: libSel.val(), billsID: node.getID()}, function (rstData) {
  519. initTree(node.guidance, guideSheet, guideItem.treeSetting, rstData);
  520. setItemCellType(node.guidance.tree.items);
  521. //项目指引初始焦点
  522. guideItemInitSel(guideSheet.getActiveRowIndex() ? guideSheet.getActiveRowIndex() : 0);
  523. });
  524. }
  525. else{
  526. node.guidance.controller.showTreeData();
  527. setItemCellType(node.guidance.tree.items);
  528. //项目指引初始焦点
  529. guideItemInitSel(guideSheet.getActiveRowIndex() ? guideSheet.getActiveRowIndex() : 0);
  530. }
  531. }
  532. //清单焦点变换-清单精灵操作
  533. //@param {Number}row @return {void}
  534. function billsSelElf(row) {
  535. let elfSheet = elfItem.workBook.getActiveSheet();
  536. cleanData(elfSheet, elfItem.headers, -1);
  537. if(!bills.tree){
  538. return;
  539. }
  540. let node = bills.tree.items[row];
  541. if(!node){
  542. return;
  543. }
  544. bills.tree.selected = node;
  545. refreshInsertRation();
  546. if(!node.elf.tree){
  547. CommonAjax.post('/billsGuidance/api/getItemsByBills', {guidanceLibID: libSel.val(), billsID: node.getID()}, function (rstData) {
  548. //定额数据删除编号信息
  549. for(let rData of rstData){
  550. if(rData.type === itemType.ration){
  551. let nameArr = rData.name.split(' ');
  552. if(nameArr.length > 0){
  553. nameArr.splice(0, 1);
  554. rData.name = nameArr.join(' ');
  555. }
  556. }
  557. }
  558. node.elf.datas = rstData;
  559. //第一层节点数据
  560. let firstLevelDatas = _.filter(rstData, function (data) {
  561. return data.ParentID == -1;
  562. });
  563. //初始数据的选项显示请选择
  564. for(let fData of firstLevelDatas){
  565. let options = getOptions(fData, rstData);
  566. fData.options = options.length > 0 ? '请选择' : '';
  567. }
  568. initTree(node.elf, elfSheet, elfItem.treeSetting, firstLevelDatas);
  569. setOptionsCellType(node.elf.tree.items);
  570. //elfSheet.getRange(-1, 1, -1, 1).cellType(getOptionsCellType(null, null, null));
  571. //setItemCellType(node.guidance.tree.items);
  572. //项目指引初始焦点
  573. elfItemInitSel(elfSheet.getActiveRowIndex() ? elfSheet.getActiveRowIndex() : 0);
  574. });
  575. }
  576. else{
  577. node.elf.controller.showTreeData();
  578. //elfSheet.getRange(-1, 1, -1, 1).cellType(getOptionsCellType(null, null, null));
  579. setOptionsCellType(node.elf.tree.items);
  580. //项目指引初始焦点
  581. elfItemInitSel(elfSheet.getActiveRowIndex() ? elfSheet.getActiveRowIndex() : 0);
  582. }
  583. }
  584. //获取施工工序含有的选项(即当前施工工序的子项),获取的顺序按照NextSiblingID排序
  585. //@param {Object}process {Array}datas @return {Array}
  586. function getOptions(process, datas) {
  587. let rst = [];
  588. if(!process || !process.ID){
  589. return [];
  590. }
  591. let options = _.filter(datas, function (data) {
  592. return data.ParentID == process.ID;
  593. });
  594. if(options.length === 0){
  595. return [];
  596. }
  597. //根据NextSiblingID排序
  598. let IDMapping = {};
  599. for(let opt of options){
  600. IDMapping[opt.ID] = {self: opt, next: null, pre: null};
  601. }
  602. for(let opt of options){
  603. let next = IDMapping[opt.NextSiblingID] ? IDMapping[opt.NextSiblingID] : null;
  604. if(next){
  605. next.pre = IDMapping[opt.ID];
  606. IDMapping[opt.ID]['next'] = next;
  607. }
  608. }
  609. let first = null,
  610. rank = 0;
  611. for(let ID in IDMapping){
  612. let obj = IDMapping[ID];
  613. if(!obj.pre){
  614. first = obj;
  615. }
  616. }
  617. while(first){
  618. rank++;
  619. first.self.rank = rank;
  620. rst.push(first.self);
  621. first = first.next;
  622. }
  623. return rst;
  624. }
  625. //设置清单精灵选项单元格
  626. //@param {Array}nodes @return {void}
  627. function setOptionsCellType(nodes) {
  628. let elfSheet = elfItem.workBook.getActiveSheet();
  629. for(let node of nodes){
  630. if(node.data.options !== ''){
  631. elfSheet.getCell(node.serialNo(), 1).locked(false).cellType(getOptionsCellType());
  632. }
  633. else {
  634. elfSheet.getCell(node.serialNo(), 1).locked(true).cellType(new GC.Spread.Sheets.CellTypes.Base());
  635. }
  636. }
  637. }
  638. //获取选项下拉多选单元格
  639. //@param {void} @return {void}
  640. function getOptionsCellType() {
  641. let me = this;
  642. let elfSheet= elfItem.workBook.getActiveSheet();
  643. function OptionsCellType() {
  644. this.isEscKey=false;
  645. this.displayText='';
  646. }
  647. function getHtml(node, cellRect, cellStyle) {
  648. if(!node){
  649. return '';
  650. }
  651. let height = cellRect.height;
  652. let htmlArr = [];
  653. let options = getOptions(node.data, bills.tree.selected.elf.datas);
  654. let optionsTitle = node.data.options.split(';').join('\n');
  655. htmlArr.push(`<div title="${optionsTitle}" style="height: ${height}px; background: ${cellStyle.backColor};overflow: hidden; white-space: nowrap; text-overflow: ellipsis">${node.data.options}</div><div style="background: ${cellStyle.backColor};border: 1px solid; overflow: auto; height: ${options.length > 6 ? height*6 : height*options.length+5}px; font-size: 0.9rem;">`);
  656. for(let opt of options){
  657. htmlArr.push(`<div title="${opt.name ? opt.name : ''}" class="elf-options" style="height: ${height}px;overflow: hidden; white-space: nowrap; text-overflow: ellipsis">
  658. <input rank="${opt.rank}" value="${opt.ID}" style="margin-left: 5px; vertical-align: middle" type="checkbox"
  659. ${node.data.optionChecked && _.find(node.data.optionChecked, {ID: opt.ID}) ? 'checked' : ''}> ${opt.name ? opt.name : ''}</div>`);
  660. }
  661. htmlArr.push(`</div>`);
  662. return htmlArr.join('');
  663. }
  664. //选择后处理
  665. function doAfterSel(node) {
  666. let checkedSels = $('.elf-options').find('input:checked');
  667. let checkedNameArr = [],
  668. optionChecked= [];
  669. for(let checkSel of checkedSels){
  670. let opt = _.cloneDeep(_.find(bills.tree.selected.elf.datas, {ID: $(checkSel).val()}));
  671. opt.rank = $(checkSel).attr('rank');
  672. checkedNameArr.push(opt.name);
  673. optionChecked.push(opt);
  674. }
  675. this.displayText = checkedNameArr.length > 0 ? checkedNameArr.join(';') : '请选择';
  676. node.data.options = this.displayText;
  677. node.data.optionChecked = optionChecked;
  678. //删除节点
  679. let deleteInfo = getDeleteInfo(node, optionChecked);
  680. for(let dInfo of deleteInfo){
  681. if(node.tree.delete(dInfo.node)){
  682. elfSheet.deleteRows(dInfo.deleteRow, dInfo.deleteCount);
  683. }
  684. }
  685. //插入节点
  686. for(let perCheked of optionChecked){
  687. let exist = false;
  688. for(let subNode of node.children){
  689. if(subNode.data.ID === perCheked.ID){
  690. exist = true;
  691. }
  692. }
  693. //不重复且不为定额时插入
  694. if(!exist && perCheked.type !== itemType.ration){
  695. insertNodeByData(node, perCheked);
  696. }
  697. }
  698. TREE_SHEET_HELPER.refreshTreeNodeData(elfItem.treeSetting, elfSheet, node.tree.items, false);
  699. setOptionsCellType(node.tree.items);
  700. refreshInsertRation();
  701. }
  702. //获取删除节点信息
  703. function getDeleteInfo(node, optionChecked) {
  704. let rst = [];
  705. for(let subNode of node.children){
  706. let exist = false;
  707. for(let perChecked of optionChecked){
  708. if(subNode.data.ID === perChecked.ID){
  709. exist = true;
  710. }
  711. }
  712. if(!exist){
  713. let deleteRow = subNode.serialNo(),
  714. deleteCount = subNode.posterityCount() + 1;
  715. rst.push({node: subNode, deleteRow: deleteRow, deleteCount: deleteCount});
  716. }
  717. }
  718. return rst;
  719. }
  720. //插入单个节点,node:当前操作的节点
  721. function insertNodeByData(node, data) {
  722. let sameDepthNodes = node.children;
  723. let insertNextSiblingID = -1,
  724. insertParentID = node.data.ID;
  725. data.options = getOptions(data, bills.tree.selected.elf.datas).length > 0 ? '请选择' : '';
  726. //确定插入位置
  727. for(let subNode of sameDepthNodes){
  728. if(data.rank < subNode.data.rank){
  729. insertNextSiblingID = subNode.data.ID;
  730. break;
  731. }
  732. }
  733. let newNode = node.tree.insertByData(data, insertParentID, insertNextSiblingID);
  734. elfSheet.addRows(newNode.serialNo(), 1);
  735. node.tree.selected = newNode;
  736. elfSheet.setSelection(newNode.serialNo(), elfSheet.getSelections()[0].col, 1, 1);
  737. }
  738. OptionsCellType.prototype = new GC.Spread.Sheets.CellTypes.Base();
  739. OptionsCellType.prototype.createEditorElement = function (context) {
  740. let element = document.createElement("div");//这里创建的,会自动销毁
  741. return element
  742. };
  743. OptionsCellType.prototype.activateEditor = function (editorContext, cellStyle, cellRect, context) {
  744. if (editorContext) {
  745. let $editor = $(editorContext);
  746. $editor.css("position", "fixed");
  747. $editor.css("background", "white");
  748. $editor.css("width", cellRect.width);
  749. $editor.attr("gcUIElement", "gcEditingInput");
  750. let node = bills.tree.selected.elf.tree.items[elfSheet.getActiveRowIndex()];
  751. $editor.html(getHtml(node, cellRect, cellStyle));
  752. }
  753. }
  754. OptionsCellType.prototype.deactivateEditor = function (editorContext, context) {
  755. };
  756. OptionsCellType.prototype.setEditorValue = function (editor, value, context) {
  757. this.displayText = value;
  758. };
  759. OptionsCellType.prototype.getEditorValue = function (editor, context) {
  760. let me = this;
  761. let node = bills.tree.selected.elf.tree.items[elfSheet.getActiveRowIndex()];
  762. if(this.isEscKey !=true){
  763. renderSheetFunc(elfSheet, function () {
  764. doAfterSel.call(me, node);
  765. });
  766. }
  767. this.isEscKey = false;
  768. return this.displayText;
  769. };
  770. OptionsCellType.prototype.updateEditor = function (editorContext, cellStyle, cellRect, context) {
  771. };
  772. OptionsCellType.prototype.isReservedKey = function (e, context) {
  773. //cell type handle tab key by itself
  774. this.isEscKey = e.keyCode === GC.Spread.Commands.Key.esc;
  775. return false;
  776. };
  777. /* OptionsCellType.prototype.paint = function (ctx, value, x, y, w, h, style, options) {
  778. if(style.backColor){
  779. ctx.fillStyle = style.backColor;
  780. ctx.fillRect(x, y, w, h);
  781. ctx.save();
  782. }
  783. //边长
  784. const l = 7;
  785. let leftPointX = x + w - 15,
  786. rightPointX = leftPointX + l,
  787. middlePointX = (leftPointX + rightPointX)/2;
  788. const cos30 = Math.cos(2*Math.PI * 30 / 360);
  789. let hL = l * cos30;
  790. let beginY = y + h/2 - hL;
  791. ctx.beginPath();
  792. ctx.moveTo(leftPointX, beginY);
  793. ctx.lineTo(rightPointX, beginY);
  794. ctx.lineTo(middlePointX, beginY + hL);
  795. ctx.fillStyle = 'black';
  796. ctx.fill();
  797. ctx.save();
  798. };*/
  799. // override getHitInfo to allow cell type get mouse messages
  800. OptionsCellType.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) {
  801. return {
  802. x: x,
  803. y: y,
  804. row: context.row,
  805. col: context.col,
  806. cellStyle: cellStyle,
  807. cellRect: cellRect,
  808. sheetArea: context.sheetArea
  809. };
  810. };
  811. return new OptionsCellType();
  812. }
  813. //初始化清单的工作内容和项目特征
  814. //@param {Number}billsLibId @return {void}
  815. function initJobAndCharacter(billsLibId){
  816. CommonAjax.post('/stdBillsEditor/getJobContent', {userId: userID, billsLibId: billsLibId}, function (datas) {
  817. stdBillsJobData = datas;
  818. });
  819. CommonAjax.post('/stdBillsEditor/getItemCharacter', {userId: userID, billsLibId: billsLibId}, function (datas) {
  820. stdBillsFeatureData = datas;
  821. });
  822. }
  823. //初始化清单展开收起状态
  824. //@return {void}
  825. function initExpandStat(){
  826. //读取展开收起状态
  827. let currentExpState = sessionStorage.getItem('stdBillsGuidanceExpState');
  828. if(currentExpState){
  829. bills.tree.setExpandedByState(bills.tree.items, currentExpState);
  830. }
  831. //非叶子节点默认收起
  832. else{
  833. bills.tree.setRootExpanded(bills.tree.roots, false);
  834. }
  835. }
  836. //设置tag以悬浮提示
  837. function setTagForHint(nodes){
  838. let sheet = bills.workBook.getActiveSheet();
  839. renderSheetFunc(sheet, function () {
  840. for(let node of nodes){
  841. sheet.setTag(node.serialNo(), 2, node.data.ruleText ? node.data.ruleText : '');
  842. }
  843. });
  844. }
  845. //初始选择清单指引库
  846. //@param {Number}libID @return {void}
  847. function libInitSel(libID){
  848. //获取清单
  849. $.bootstrapLoading.start();
  850. CommonAjax.post('/billsGuidance/api/getLibWithBills', {libID: libID}, function(rstData){
  851. currentLib = rstData.guidanceLib;
  852. if(guideItem.workBook){
  853. guideItem.workBook.destroy();
  854. guideItem.workBook = null;
  855. }
  856. if(elfItem.workBook){
  857. elfItem.workBook.destroy();
  858. elfItem.workBook = null;
  859. }
  860. initViews();
  861. //获取清单库中的工作内容和项目特征
  862. initJobAndCharacter(rstData.guidanceLib.billsLibId);
  863. initTree(bills, bills.workBook.getActiveSheet(), bills.treeSetting, rstData.bills);
  864. //清单精灵
  865. if(rstData.guidanceLib.type && rstData.guidanceLib.type == libType.elf){
  866. $('#stdBillsGuidanceTab').text('清单精灵');
  867. //每一个清单节点下挂载一棵清单精灵树
  868. for(let node of bills.tree.items){
  869. node.elf = {tree: null, controller: null, datas: []}; //挂载全部数据,数据不一定全成为树节点
  870. }
  871. }
  872. //清单指引
  873. else {
  874. $('#stdBillsGuidanceTab').text('清单指引');
  875. //每一棵项目指引树挂在清单节点上
  876. for(let node of bills.tree.items){
  877. node.guidance = {tree: null, controller: null};
  878. }
  879. }
  880. setTagForHint(bills.tree.items);
  881. //默认初始节点
  882. billsInitSel(0);
  883. $.bootstrapLoading.end();
  884. }, function () {
  885. $.bootstrapLoading.end();
  886. });
  887. }
  888. //初始化清单指引库
  889. //@param {Array}libDats @return {void}
  890. function initLibs(libDatas){
  891. libSel.empty();
  892. if(!libDatas){
  893. return;
  894. }
  895. let selectedLib = sessionStorage.getItem('stdBillsGuidance');
  896. for(let libData of libDatas){
  897. let opt = $('<option>').val(libData.id).text(libData.name);
  898. if(selectedLib && libData.id == selectedLib){
  899. opt.attr('selected', 'selected');
  900. }
  901. libSel.append(opt);
  902. }
  903. //初始默认选择
  904. libInitSel(libSel.select().val());
  905. }
  906. //初始化视图
  907. //@param {void} @return {void}
  908. function initViews(){
  909. //赋初始高度
  910. if($('#billsGuidance_bills').height() === 0 || $('#billsGuidance_items').height() === 0){
  911. let height = $(window).height()-$(".header").height()-$(".toolsbar").height()-$(".tools-bar-height-z").height();
  912. $('#billsGuidance_bills').height(height / 2);
  913. $('#billsGuidance_items').height(height / 2);
  914. }
  915. let modules = [bills];
  916. if(currentLib.type && currentLib.type === libType.elf){
  917. modules.push(elfItem);
  918. }
  919. else {
  920. modules.push(guideItem);
  921. }
  922. initWorkBooks(modules);
  923. }
  924. //获取选中的行
  925. //@return {Array}
  926. function getCheckedRows(){
  927. let rst = [];
  928. let itemSheet = guideItem.workBook.getActiveSheet();
  929. for(let row = 0; row < itemSheet.getRowCount(); row++){
  930. let rowV = itemSheet.getValue(row, 0);
  931. if(rowV){
  932. rst.push(row);
  933. }
  934. }
  935. return rst;
  936. }
  937. //获取清单精灵生成的定额数据
  938. //@return {Array}
  939. function getInsertElfRationData(){
  940. let rst = [];
  941. if(!bills.tree.selected){
  942. return [];
  943. }
  944. if(!bills.tree.selected.elf){
  945. return [];
  946. }
  947. let tree = bills.tree.selected.elf.tree;
  948. if(!tree){
  949. return [];
  950. }
  951. for(let node of tree.items){
  952. if(node.children.length === 0 && node.data.optionChecked){//定额数据只能在最底层节点中
  953. for(let perChecked of node.data.optionChecked){
  954. if(perChecked.type === itemType.ration){
  955. rst.push({itemQuery: {userID: userID, ID: perChecked.rationID}, rationType: rationType.ration});
  956. }
  957. }
  958. }
  959. }
  960. return rst;
  961. }
  962. //获取选中的定额数据
  963. //@param {Array}rows @return {Array}
  964. function getInsertRationData(rows){
  965. let rst = [];
  966. for(let row of rows){
  967. let node = bills.tree.selected.guidance.tree.items[row];
  968. if(node && node.data.type === itemType.ration){
  969. rst.push({itemQuery: {userID: userID, ID: node.data.rationID}, rationType: rationType.ration});
  970. }
  971. }
  972. return rst;
  973. }
  974. //插入定额
  975. //@return {void}
  976. function insertRations(addRationDatas){
  977. if(addRationDatas.length > 0){
  978. projectObj.project.Ration.addMultiRation(addRationDatas, function () {
  979. //恢复
  980. if(!currentLib.type || currentLib.type === libType.guidance){
  981. let sheet = guideItem.workBook.getActiveSheet();
  982. renderSheetFunc(sheet, function () {
  983. for(let row = 0; row < sheet.getRowCount(); row++){
  984. if(sheet.getValue(row, 0)){
  985. sheet.setValue(row, 0, false);
  986. }
  987. }
  988. });
  989. }
  990. refreshInsertRation();
  991. projectObj.setActiveCell('quantity', true);
  992. });
  993. }
  994. }
  995. //更新插入定额按钮有效性
  996. function refreshInsertRation(){
  997. if(currentLib.type && currentLib.type === libType.elf){
  998. if(getInsertElfRationData().length > 0){
  999. $('#guidanceInsertRation').removeClass('disabled');
  1000. }
  1001. else {
  1002. $('#guidanceInsertRation').addClass('disabled');
  1003. }
  1004. }
  1005. else {
  1006. //勾选了定额,插入定额按钮才有效
  1007. if(getCheckedRows().length > 0){
  1008. $('#guidanceInsertRation').removeClass('disabled');
  1009. }
  1010. else {
  1011. $('#guidanceInsertRation').addClass('disabled');
  1012. }
  1013. }
  1014. }
  1015. //展开至搜索出来点的节点
  1016. //@param {Array}nodes @return {void}
  1017. function expandSearchNodes(nodes){
  1018. let that = this;
  1019. let billsSheet = bills.workBook.getActiveSheet();
  1020. renderSheetFunc(billsSheet, function () {
  1021. function expParentNode(node){
  1022. if(node.parent && !node.parent.expanded){
  1023. node.parent.setExpanded(true);
  1024. expParentNode(node.parent);
  1025. }
  1026. }
  1027. for(let node of nodes){
  1028. expParentNode(node);
  1029. }
  1030. TREE_SHEET_HELPER.refreshTreeNodeData(bills.treeSetting, billsSheet, bills.tree.roots, true);
  1031. TREE_SHEET_HELPER.refreshNodesVisible(bills.tree.roots, billsSheet, true);
  1032. });
  1033. }
  1034. //各按钮监听事件
  1035. //@return {void}
  1036. function bindBtn(){
  1037. //打开清单指引库
  1038. $('#stdBillsGuidanceTab').click(function () {
  1039. if(libSel.children().length === 0 && !projectReadOnly && !$(this).hasClass('disabled')){
  1040. initLibs(projectInfoObj.projectInfo.engineeringInfo.billsGuidance_lib);
  1041. }
  1042. });
  1043. //更改清单指引库
  1044. $('#stdBillsGuidanceLibSelect').change(function () {
  1045. //关闭搜索窗口
  1046. $('#billsGuidanceSearchResult').hide();
  1047. billsLibObj.clearHighLight(bills.workBook);
  1048. libInitSel($(this).select().val());
  1049. //记住选项
  1050. sessionStorage.setItem('stdBillsGuidance', $(this).select().val());
  1051. //清除展开收起状态sessionStorage
  1052. sessionStorage.removeItem('stdBillsGuidanceExpState');
  1053. });
  1054. //插入定额
  1055. $('#guidanceInsertRation').click(function () {
  1056. let addRationDatas = currentLib.type && currentLib.type === libType.elf ? getInsertElfRationData() : getInsertRationData(getCheckedRows());
  1057. insertRations(addRationDatas);
  1058. });
  1059. //插入清单
  1060. $('#guidanceInsertBills').click(function () {
  1061. //插入清单
  1062. if(!bills.tree || !bills.tree.selected){
  1063. return;
  1064. }
  1065. if(bills.tree.selected.children.length === 0){
  1066. let insert = billsLibObj.insertBills(stdBillsJobData, stdBillsFeatureData, bills.tree.selected);
  1067. if(insert){
  1068. //插入选中的定额
  1069. let addRationDatas = currentLib.type && currentLib.type === libType.elf ? getInsertElfRationData() : getInsertRationData(getCheckedRows());
  1070. insertRations(addRationDatas);
  1071. }
  1072. }
  1073. });
  1074. //搜索
  1075. $('#stdBillsGuidanceSearch>div>button').click(function () {
  1076. if(!bills.tree){
  1077. return;
  1078. }
  1079. let billsSheet = bills.workBook.getActiveSheet();
  1080. billsLibObj.clearHighLight(bills.workBook);
  1081. let keyword = $('#stdBillsGuidanceSearch>input').val();
  1082. if (!keyword || keyword === '') {
  1083. $('#billsGuidanceSearchResult').hide();
  1084. return;
  1085. }
  1086. let result = bills.tree.items.filter(function (item) {
  1087. let codeIs = item.data.code ? item.data.code.indexOf(keyword) !== -1 : false;
  1088. let nameIs = item.data.name ? item.data.name.indexOf(keyword) !== -1 : false;
  1089. return codeIs || nameIs;
  1090. });
  1091. result.sort(function (x, y) {
  1092. return x.serialNo() - y.serialNo();
  1093. });
  1094. if (result.length !== 0) {
  1095. //展开搜索出来的节点
  1096. expandSearchNodes(result);
  1097. //设置记住展开
  1098. sessionStorage.setItem('stdBillsGuidanceExpState', bills.tree.getExpState(bills.tree.items));
  1099. let sel = billsSheet.getSelections();
  1100. renderSheetFunc(billsSheet, function () {
  1101. bills.controller.setTreeSelected(result[0]);
  1102. billsSheet.setSelection(result[0].serialNo(), sel[0].col, 1, 1);
  1103. billsInitSel(result[0].serialNo());
  1104. for (let node of result) {
  1105. billsSheet.getRange(node.serialNo(), -1, 1, -1).backColor('lemonChiffon');
  1106. }
  1107. });
  1108. //搜索初始定位
  1109. billsSheet.showRow(result[0].serialNo(), GC.Spread.Sheets.VerticalPosition.bottom);
  1110. $('#nextBillsGuidance').show();
  1111. $('#nextBillsGuidance').unbind('click');
  1112. $('#nextBillsGuidance').bind('click', function () {
  1113. let cur = bills.tree.selected, resultIndex = result.indexOf(cur), sel = billsSheet.getSelections();
  1114. if (resultIndex === result.length - 1) {
  1115. bills.controller.setTreeSelected(result[0]);
  1116. billsSheet.setSelection(result[0].serialNo(), sel[0].col, 1, 1);
  1117. billsInitSel(result[0].serialNo());
  1118. billsSheet.showRow(result[0].serialNo(), GC.Spread.Sheets.VerticalPosition.bottom);
  1119. } else {
  1120. bills.controller.setTreeSelected(result[resultIndex + 1]);
  1121. billsSheet.setSelection(result[resultIndex + 1].serialNo(), sel[0].col, 1, 1);
  1122. billsInitSel(result[resultIndex + 1].serialNo());
  1123. billsSheet.showRow(result[resultIndex + 1].serialNo(), GC.Spread.Sheets.VerticalPosition.bottom);
  1124. }
  1125. });
  1126. } else {
  1127. billsLibObj.clearHighLight(bills.workBook);
  1128. $('#nextBillsGuidance').hide();
  1129. }
  1130. $('#billsGuidanceSearchResultCount').text('搜索结果:' + result.length);
  1131. $('#billsGuidanceSearchResult').show();
  1132. });
  1133. //搜索框回车
  1134. $('#stdBillsGuidanceSearch>input').bind('keypress', function (event) {
  1135. if(event.keyCode === 13){
  1136. $(this).blur();
  1137. $('#stdBillsGuidanceSearch>div>button').click();
  1138. }
  1139. });
  1140. // 关闭搜索结果
  1141. $('#closeSearchBillsGuidance').click(function () {
  1142. $('#billsGuidanceSearchResult').hide();
  1143. billsLibObj.clearHighLight(bills.workBook);
  1144. refreshWorkBook();
  1145. });
  1146. }
  1147. //刷新表
  1148. //@return {void}
  1149. function refreshWorkBook(){
  1150. if(bills.workBook){
  1151. bills.workBook.refresh();
  1152. }
  1153. if(guideItem.workBook){
  1154. guideItem.workBook.refresh();
  1155. }
  1156. if(elfItem.workBook){
  1157. elfItem.workBook.refresh();
  1158. }
  1159. }
  1160. return {initViews, bindBtn, refreshWorkBook, refreshInsertRation, bills};
  1161. })();
  1162. $(document).ready(function(){
  1163. billsGuidance.bindBtn();
  1164. });