std_billsGuidance_lib.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. 'use strict';
  2. /**
  3. *
  4. *
  5. * @author Zhong
  6. * @date 2018/6/11
  7. * @version
  8. */
  9. //清单指引/精灵获取完清单数据后的回调函数
  10. let doAfterLoadGuidance = null;
  11. const billsGuidance = (function () {
  12. let currentLib = null;
  13. const libSel = $('#stdBillsGuidanceLibSelect');
  14. //工作内容
  15. let stdBillsJobData = [];
  16. //项目特征
  17. let stdBillsFeatureData = [];
  18. const bills = {
  19. dom: $('#billsGuidance_bills'),
  20. workBook: null,
  21. cache: [],
  22. tree: null,
  23. controller: null,
  24. treeSetting: {
  25. emptyRowHeader: true,
  26. rowHeaderWidth: 15,
  27. treeCol: 0,
  28. emptyRows: 0,
  29. headRows: 1,
  30. headRowHeight: [40],
  31. defaultRowHeight: 21,
  32. cols: [{
  33. width: 140,
  34. readOnly: true,
  35. showHint: 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: 190,
  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. head: {
  72. titleNames: ["计量单位"],
  73. spanCols: [1],
  74. spanRows: [1],
  75. vAlign: [1],
  76. hAlign: [1],
  77. font: ["Arial"]
  78. },
  79. data: {
  80. field: "unit",
  81. vAlign: 1,
  82. hAlign: 1,
  83. font: "Arial"
  84. }
  85. }
  86. ]
  87. },
  88. headers: [
  89. {name: '项目编码', dataCode: 'code', width: 140, vAlign: 'center', hAlign: 'left', formatter: '@'},
  90. {name: '项目名称', dataCode: 'name', width: 190, vAlign: 'center', hAlign: 'left', formatter: '@'},
  91. {name: '单位', dataCode: 'unit', width: 45, vAlign: 'center', hAlign: 'center', formatter: '@'},
  92. ],
  93. rowHeaderWidth:1,
  94. events: {
  95. CellDoubleClick: function (sender, args) {
  96. if(!bills.tree){
  97. return;
  98. }
  99. let node = bills.tree.items[args.row];
  100. if(!node){
  101. return;
  102. }
  103. if(node.children.length > 0){
  104. node.setExpanded(!node.expanded);
  105. //设置展开收起状态
  106. sessionStorage.setItem('stdBillsGuidanceExpState', bills.tree.getExpState(bills.tree.items));
  107. renderSheetFunc(args.sheet, function () {
  108. let iCount = node.posterityCount(), i, child;
  109. for (i = 0; i < iCount; i++) {
  110. child = bills.tree.items[args.row + i + 1];
  111. args.sheet.setRowVisible(args.row + i + 1, child.visible, args.sheetArea);
  112. }
  113. args.sheet.invalidateLayout();
  114. });
  115. args.sheet.repaint();
  116. } else if(!projectReadOnly) {
  117. billsLibObj.insertBills(stdBillsJobData, stdBillsFeatureData, node);
  118. }
  119. }
  120. }
  121. };
  122. const options = {
  123. workBook: {
  124. tabStripVisible: false,
  125. allowContextMenu: false,
  126. allowCopyPasteExcelStyle : false,
  127. allowExtendPasteRange: false,
  128. allowUserDragDrop : false,
  129. allowUserDragFill: false,
  130. scrollbarMaxAlign : true
  131. },
  132. sheet: {
  133. protectionOptions: {allowResizeRows: true, allowResizeColumns: true},
  134. clipBoardOptions: GC.Spread.Sheets.ClipboardPasteOptions.values
  135. }
  136. };
  137. //渲染时方法,停止渲染
  138. //@param {Object}sheet {Function}func @return {void}
  139. function renderSheetFunc(sheet, func){
  140. sheet.suspendEvent();
  141. sheet.suspendPaint();
  142. if(func){
  143. func();
  144. }
  145. sheet.resumeEvent();
  146. sheet.resumePaint();
  147. }
  148. //设置表选项
  149. //@param {Object}workBook {Object}opts @return {void}
  150. function setOptions (workBook, opts) {
  151. for(let opt in opts.workBook){
  152. workBook.options[opt] = opts.workBook[opt];
  153. }
  154. for(let opt in opts.sheet){
  155. workBook.getActiveSheet().options[opt] = opts.sheet[opt];
  156. }
  157. }
  158. //建表头
  159. //@param {Object}sheet {Array}headers @return {void}
  160. function buildHeader(sheet, headers) {
  161. let fuc = function () {
  162. sheet.setColumnCount(headers.length);
  163. sheet.setRowHeight(0, 30, GC.Spread.Sheets.SheetArea.colHeader);
  164. for(let i = 0, len = headers.length; i < len; i++){
  165. sheet.setValue(0, i, headers[i].name, GC.Spread.Sheets.SheetArea.colHeader);
  166. sheet.setColumnWidth(i, headers[i].width, GC.Spread.Sheets.SheetArea.colHeader);
  167. if(headers[i].formatter){
  168. sheet.setFormatter(-1, i, headers[i].formatter);
  169. }
  170. sheet.getRange(-1, i, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[headers[i]['hAlign']]);
  171. sheet.getRange(-1, i, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[headers[i]['vAlign']]);
  172. }
  173. };
  174. renderSheetFunc(sheet, fuc);
  175. }
  176. //表监听事件
  177. //@param {Object}workBook @return {void}
  178. function bindEvent(workBook, events) {
  179. if(Object.keys(events).length === 0){
  180. return;
  181. }
  182. const Events = GC.Spread.Sheets.Events;
  183. for(let event in events){
  184. workBook.bind(Events[event], events[event]);
  185. }
  186. }
  187. //建表
  188. //@param {Object}module @return {void}
  189. function buildSheet(module) {
  190. if(!module.workBook){
  191. module.workBook = new GC.Spread.Sheets.Workbook(module.dom[0], {sheetCount: 1});
  192. sheetCommonObj.spreadDefaultStyle(module.workBook);
  193. let sheet = module.workBook.getActiveSheet();
  194. if(module === bills){
  195. //默认初始可控制焦点在清单表中
  196. sheet.options.rowHeaderVisible = false;
  197. module.workBook.focus();
  198. sheet.options.isProtected = true;
  199. sheet.name('stdBillsGuidance_bills');
  200. //设置悬浮提示
  201. TREE_SHEET_HELPER.initSetting(bills.dom[0], bills.treeSetting);
  202. }
  203. if(module.rowHeaderWidth) {
  204. sheet.setColumnWidth(0, module.rowHeaderWidth, GC.Spread.Sheets.SheetArea.rowHeader);
  205. }
  206. setOptions(module.workBook, options);
  207. buildHeader(module.workBook.getActiveSheet(), module.headers);
  208. bindEvent(module.workBook, module.events);
  209. }
  210. }
  211. //初始化各工作表
  212. //@param {Array}modules @return {void}
  213. function initWorkBooks(modules){
  214. for(let module of modules){
  215. buildSheet(module);
  216. }
  217. }
  218. //点击清单名称后面的问号,弹出补注窗口并设置当前节点(或xxx父节点)的补注
  219. //@param {Number}row(当前焦点行) @return {void}
  220. function initRechargeModal(row) {
  221. let node = bills.tree.items[row];
  222. while (node && !node.data.recharge){
  223. node = node.parent;
  224. }
  225. let recharge = node && node.data.recharge ? node.data.recharge : '无内容';
  226. node = bills.tree.items[row];
  227. while (node && !node.data.ruleText){
  228. node = node.parent;
  229. }
  230. let ruleText = node && node.data.ruleText ? node.data.ruleText : '无内容';
  231. $('#questionTab1').text('补注');
  232. $('#questionTab2').text('工程量计算规则');
  233. $('#questionContent1').html(recharge);
  234. $('#questionContent2').html(ruleText);
  235. $('#questionModal').modal('show');
  236. }
  237. //节点链上含有补注或工程量计算规则数据
  238. //@param {Number}row(行当前行) @return {Boolean}
  239. function hasRechargeRuleText(row) {
  240. let node = bills.tree.items[row];
  241. if (!node) {
  242. return false;
  243. }
  244. while (node) {
  245. if (node.data.recharge || node.data.ruleText) {
  246. return true;
  247. }
  248. node = node.parent;
  249. }
  250. return false;
  251. }
  252. //初始化并输出树
  253. //@param {Object}module {Object}sheet {Object}treeSetting {Array}datas
  254. function initTree(module, sheet, treeSetting, datas){
  255. module.tree = idTree.createNew({id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1, autoUpdate: true});
  256. module.controller = TREE_SHEET_CONTROLLER.createNew(module.tree, sheet, treeSetting, false);
  257. module.tree.loadDatas(datas);
  258. if(module === bills){
  259. initExpandStat();
  260. }
  261. module.controller.showTreeData();
  262. if(module === bills){
  263. module.workBook.getSheet(0).options.rowHeaderVisible = true;
  264. setBillsHint(bills.tree.items, stdBillsJobData, stdBillsFeatureData);
  265. renderSheetFunc(sheet, function () {
  266. for(let i = 0; i < bills.tree.items.length; i++){
  267. sheet.setCellType(i, 1, TREE_SHEET_HELPER.getQuestionCellType(initRechargeModal, hasRechargeRuleText));
  268. }
  269. });
  270. }
  271. }
  272. //初始化清单的工作内容和项目特征
  273. //@param {Number}billsLibId {Function}callback @return {void}
  274. function initJobAndCharacter(billsLibId, callback){
  275. CommonAjax.post('/stdBillsEditor/getJobContent', {userId: userID, billsLibId: billsLibId}, function (datas) {
  276. stdBillsJobData = datas;
  277. CommonAjax.post('/stdBillsEditor/getItemCharacter', {userId: userID, billsLibId: billsLibId}, function (datas) {
  278. stdBillsFeatureData = datas;
  279. if(callback){
  280. callback();
  281. }
  282. });
  283. });
  284. }
  285. //初始化清单展开收起状态
  286. //@return {void}
  287. function initExpandStat(){
  288. //读取展开收起状态
  289. let currentExpState = sessionStorage.getItem('stdBillsGuidanceExpState');
  290. if(currentExpState){
  291. bills.tree.setExpandedByState(bills.tree.items, currentExpState);
  292. }
  293. //非叶子节点默认收起
  294. else{
  295. bills.tree.setRootExpanded(bills.tree.roots, false);
  296. }
  297. }
  298. //设置tag以悬浮提示
  299. function setTagForHint(nodes){
  300. let sheet = bills.workBook.getActiveSheet();
  301. renderSheetFunc(sheet, function () {
  302. for(let node of nodes){
  303. sheet.setTag(node.serialNo(), 2, node.data.ruleText ? node.data.ruleText : '');
  304. }
  305. });
  306. }
  307. //根据编码定位至清单精灵库中
  308. //@param {String}code @return {void}
  309. function locateAtBills(code) {
  310. let nineCode = code.substring(0, 9);
  311. let items = bills.tree.items;
  312. let locateBills = _.find(items, function(item){
  313. return item.data.code === nineCode;
  314. });
  315. if(locateBills){
  316. expandSearchNodes([locateBills]);
  317. sessionStorage.setItem('stdBillsGuidanceExpState', bills.tree.getExpState(bills.tree.items));
  318. }
  319. let sheet = bills.workBook.getActiveSheet();
  320. let locateRow = locateBills ? locateBills.serialNo() : 0;
  321. sheet.setActiveCell(locateRow, 0);
  322. sheet.showRow(locateRow, GC.Spread.Sheets.VerticalPosition.center);
  323. }
  324. //清单设置悬浮提示信息
  325. //@param {Array}billsNodes(清单节点) {Array}jobs(总的工作内容数据) {Array}items(总的项目特征数据)
  326. function setBillsHint(billsNodes, jobs, items) {
  327. let jobsMapping = {},
  328. itemsMapping = {};
  329. for(let job of jobs){
  330. jobsMapping[job.id] = job;
  331. }
  332. for(let item of items){
  333. itemsMapping[item.id] = item;
  334. }
  335. let tagInfo = [];
  336. for(let billsNode of billsNodes){
  337. let hintArr = [];
  338. let billsItems = billsNode.data.items;
  339. if(billsItems.length > 0){
  340. //项目特征
  341. hintArr.push('项目特征:');
  342. }
  343. let itemCount = 1,
  344. jobCount = 1;
  345. for(let billsItem of billsItems){
  346. let itemData = itemsMapping[billsItem.id];
  347. if(itemData){
  348. //特征值
  349. let eigens = [];
  350. for(let eigen of itemData.itemValue){
  351. eigens.push(eigen.value);
  352. }
  353. eigens = eigens.join(';');
  354. hintArr.push(`${itemCount}.${itemData.content}${eigens === '' ? '' : ': ' + eigens}`);
  355. itemCount ++;
  356. }
  357. }
  358. //工作内容
  359. let billsJobs = billsNode.data.jobs;
  360. if(billsJobs.length > 0){
  361. hintArr.push('工作内容:');
  362. }
  363. for(let billsJob of billsJobs){
  364. let jobData = jobsMapping[billsJob.id];
  365. if(jobData){
  366. hintArr.push(`${jobCount}.${jobData.content}`);
  367. jobCount ++;
  368. }
  369. }
  370. if(hintArr.length > 0){
  371. tagInfo.push({row: billsNode.serialNo(), value: hintArr.join('\n')});
  372. }
  373. }
  374. let sheet = bills.workBook.getActiveSheet();
  375. renderSheetFunc(sheet, function () {
  376. for(let tagI of tagInfo){
  377. sheet.setTag(tagI.row, 0, tagI.value);
  378. }
  379. });
  380. }
  381. //初始选择清单指引库
  382. //@param {Number}libID @return {void}
  383. function libInitSel(libID){
  384. //获取清单
  385. $.bootstrapLoading.start();
  386. CommonAjax.post('/billsGuidance/api/getLibWithBills', {libID: libID}, function(rstData){
  387. currentLib = rstData.guidanceLib;
  388. initViews();
  389. let callback = function () {
  390. initTree(bills, bills.workBook.getActiveSheet(), bills.treeSetting, rstData.bills);
  391. if(doAfterLoadGuidance){
  392. doAfterLoadGuidance();
  393. }
  394. $.bootstrapLoading.end();
  395. };
  396. //获取清单库中的工作内容和项目特征
  397. initJobAndCharacter(rstData.guidanceLib.billsLibId, callback);
  398. }, function () {
  399. $.bootstrapLoading.end();
  400. });
  401. }
  402. //初始化清单指引库
  403. //@param {Array}libDats @return {void}
  404. function initLibs(libDatas){
  405. libSel.empty();
  406. if(!libDatas){
  407. return;
  408. }
  409. let selectedLib = sessionStorage.getItem('stdBillsGuidance');
  410. for(let libData of libDatas){
  411. let opt = $('<option>').val(libData.id).text(libData.name);
  412. if(selectedLib && libData.id == selectedLib){
  413. opt.attr('selected', 'selected');
  414. }
  415. libSel.append(opt);
  416. }
  417. //初始默认选择
  418. libInitSel(libSel.select().val());
  419. }
  420. //初始化视图
  421. //@param {void} @return {void}
  422. function initViews(){
  423. //赋初始高度
  424. if($('#billsGuidance_bills').height() === 0 || $('#billsGuidance_items').height() === 0){
  425. let height = $(window).height()-$(".header").height()-$(".toolsbar").height()-$(".tools-bar-height-z").height();
  426. $('#billsGuidance_bills').height(height / 2);
  427. $('#billsGuidance_items').height(height / 2);
  428. }
  429. let modules = [bills];
  430. initWorkBooks(modules);
  431. }
  432. //展开至搜索出来点的节点
  433. //@param {Array}nodes @return {void}
  434. function expandSearchNodes(nodes){
  435. let billsSheet = bills.workBook.getActiveSheet();
  436. renderSheetFunc(billsSheet, function () {
  437. function expParentNode(node){
  438. if(node.parent){
  439. if (!node.parent.expanded) {
  440. node.parent.setExpanded(true);
  441. }
  442. expParentNode(node.parent);
  443. }
  444. }
  445. for(let node of nodes){
  446. expParentNode(node);
  447. }
  448. TREE_SHEET_HELPER.refreshTreeNodeData(bills.treeSetting, billsSheet, bills.tree.roots, true);
  449. TREE_SHEET_HELPER.refreshNodesVisible(bills.tree.roots, billsSheet, true);
  450. });
  451. }
  452. //各按钮监听事件
  453. //@return {void}
  454. function bindBtn(){
  455. //打开清单指引库
  456. $('#stdBillsGuidanceTab').click(function () {
  457. if(libSel.children().length === 0 && !$(this).hasClass('disabled')){
  458. initLibs(projectObj.project.projectInfo.engineeringInfo.billsGuidance_lib);
  459. }
  460. });
  461. //更改清单指引库
  462. $('#stdBillsGuidanceLibSelect').change(function () {
  463. //关闭搜索窗口
  464. $('#billsGuidanceSearchResult').hide();
  465. billsLibObj.clearHighLight(bills.workBook);
  466. libInitSel($(this).select().val());
  467. //记住选项
  468. sessionStorage.setItem('stdBillsGuidance', $(this).select().val());
  469. //清除展开收起状态sessionStorage
  470. sessionStorage.removeItem('stdBillsGuidanceExpState');
  471. });
  472. //搜索
  473. $('#stdBillsGuidanceSearch>div>button').click(function () {
  474. if(!bills.tree){
  475. return;
  476. }
  477. let billsSheet = bills.workBook.getActiveSheet();
  478. billsLibObj.clearHighLight(bills.workBook);
  479. let keyword = $('#stdBillsGuidanceSearch>input').val();
  480. if (!keyword || keyword === '') {
  481. $('#billsGuidanceSearchResult').hide();
  482. return;
  483. }
  484. let result = bills.tree.items.filter(function (item) {
  485. let codeIs = item.data.code ? item.data.code.indexOf(keyword) !== -1 : false;
  486. let nameIs = item.data.name ? item.data.name.indexOf(keyword) !== -1 : false;
  487. return codeIs || nameIs;
  488. });
  489. result.sort(function (x, y) {
  490. return x.serialNo() - y.serialNo();
  491. });
  492. if (result.length !== 0) {
  493. //展开搜索出来的节点
  494. expandSearchNodes(result);
  495. //设置记住展开
  496. sessionStorage.setItem('stdBillsGuidanceExpState', bills.tree.getExpState(bills.tree.items));
  497. let sel = billsSheet.getSelections();
  498. renderSheetFunc(billsSheet, function () {
  499. bills.controller.setTreeSelected(result[0]);
  500. billsSheet.setSelection(result[0].serialNo(), sel[0].col, 1, 1);
  501. for (let node of result) {
  502. billsSheet.getRange(node.serialNo(), -1, 1, -1).backColor('lemonChiffon');
  503. }
  504. });
  505. //搜索初始定位
  506. billsSheet.showRow(result[0].serialNo(), GC.Spread.Sheets.VerticalPosition.center);
  507. //查找下一条
  508. $('#nextBillsGuidance').show();
  509. $('#nextBillsGuidance').unbind('click');
  510. $('#nextBillsGuidance').bind('click', function () {
  511. let cur = bills.tree.selected, resultIndex = result.indexOf(cur), sel = billsSheet.getSelections();
  512. if (resultIndex === result.length - 1) {
  513. bills.controller.setTreeSelected(result[0]);
  514. billsSheet.setSelection(result[0].serialNo(), sel[0].col, 1, 1);
  515. billsSheet.showRow(result[0].serialNo(), GC.Spread.Sheets.VerticalPosition.center);
  516. } else {
  517. bills.controller.setTreeSelected(result[resultIndex + 1]);
  518. billsSheet.setSelection(result[resultIndex + 1].serialNo(), sel[0].col, 1, 1);
  519. billsSheet.showRow(result[resultIndex + 1].serialNo(), GC.Spread.Sheets.VerticalPosition.center);
  520. }
  521. });
  522. //查找上一条
  523. $('#preBillsGuidance').show();
  524. $('#preBillsGuidance').unbind('click');
  525. $('#preBillsGuidance').bind('click', function () {
  526. let cur = bills.tree.selected, resultIndex = result.indexOf(cur), sel = billsSheet.getSelections();
  527. if (resultIndex === 0) {
  528. bills.controller.setTreeSelected(result[result.length - 1]);
  529. billsSheet.setSelection(result[result.length - 1].serialNo(), sel[0].col, 1, 1);
  530. billsSheet.showRow(result[result.length - 1].serialNo(), GC.Spread.Sheets.VerticalPosition.center);
  531. } else {
  532. bills.controller.setTreeSelected(result[resultIndex - 1]);
  533. billsSheet.setSelection(result[resultIndex - 1].serialNo(), sel[0].col, 1, 1);
  534. billsSheet.showRow(result[resultIndex - 1].serialNo(), GC.Spread.Sheets.VerticalPosition.center);
  535. }
  536. });
  537. } else {
  538. billsLibObj.clearHighLight(bills.workBook);
  539. $('#nextBillsGuidance').hide();
  540. $('#preBillsGuidance').hide();
  541. }
  542. $('#billsGuidanceSearchResultCount').text('搜索结果:' + result.length);
  543. $('#billsGuidanceSearchResult').show();
  544. autoFlashHeight();
  545. refreshWorkBook();
  546. });
  547. //搜索框回车
  548. $('#stdBillsGuidanceSearch>input').bind('keypress', function (event) {
  549. if(event.keyCode === 13){
  550. $(this).blur();
  551. $('#stdBillsGuidanceSearch>div>button').click();
  552. }
  553. });
  554. // 关闭搜索结果
  555. $('#closeSearchBillsGuidance').click(function () {
  556. $('#billsGuidanceSearchResult').hide();
  557. billsLibObj.clearHighLight(bills.workBook);
  558. autoFlashHeight();
  559. refreshWorkBook();
  560. });
  561. }
  562. //刷新表
  563. //@return {void}
  564. function refreshWorkBook(){
  565. if(bills.workBook){
  566. bills.workBook.refresh();
  567. }
  568. }
  569. return {
  570. initViews,
  571. bindBtn,
  572. refreshWorkBook,
  573. locateAtBills,
  574. bills
  575. };
  576. })();
  577. $(document).ready(function(){
  578. billsGuidance.bindBtn();
  579. });