billsGuidance.js 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  1. 'use strict';
  2. /**
  3. *
  4. *
  5. * @author Zhong
  6. * @date 2018/6/1
  7. * @version
  8. */
  9. const billsGuidance = (function () {
  10. //自执行函数全局变量定义
  11. const libID = getQueryString('libID');
  12. const bills = {
  13. dom: $('#billsSpread'),
  14. workBook: null,
  15. cache: [],
  16. tree: null,
  17. controller: null,
  18. treeSetting: {
  19. treeCol: 0,
  20. emptyRows: 0,
  21. headRows: 1,
  22. headRowHeight: [40],
  23. defaultRowHeight: 21,
  24. cols: [{
  25. width: 200,
  26. readOnly: true,
  27. head: {
  28. titleNames: ["项目编码"],
  29. spanCols: [1],
  30. spanRows: [1],
  31. vAlign: [1],
  32. hAlign: [1],
  33. font: ["Arial"]
  34. },
  35. data: {
  36. field: "code",
  37. vAlign: 1,
  38. hAlign: 0,
  39. font: "Arial"
  40. }
  41. }, {
  42. width: 200,
  43. readOnly: true,
  44. head: {
  45. titleNames: ["项目名称"],
  46. spanCols: [1],
  47. spanRows: [1],
  48. vAlign: [1],
  49. hAlign: [1],
  50. font: ["Arial"]
  51. },
  52. data: {
  53. field: "name",
  54. vAlign: 1,
  55. hAlign: 0,
  56. font: "Arial"
  57. }
  58. }]
  59. },
  60. headers: [
  61. {name: '项目编码', dataCode: 'code', width: 200, vAlign: 'center', hAlign: 'left', formatter: '@'},
  62. {name: '项目名称', dataCode: 'name', width: 200, vAlign: 'center', hAlign: 'left', formatter: '@'}
  63. ],
  64. events: {
  65. SelectionChanged: function (sender, info) {
  66. billsInitSel(info.newSelections[0].row);
  67. }
  68. }
  69. };
  70. //项目指引类型
  71. const itemType = {
  72. job: 0,
  73. ration: 1
  74. };
  75. const updateType = {
  76. create: 'create',
  77. update: 'update',
  78. del: 'delete'
  79. };
  80. const guideItem = {
  81. dom: $('#guideItemSpread'),
  82. workBook: null,
  83. tree: null,
  84. controller: null,
  85. treeSetting: {
  86. treeCol: 0,
  87. emptyRows: 0,
  88. headRows: 1,
  89. headRowHeight: [40],
  90. defaultRowHeight: 21,
  91. cols: [{
  92. width: 400,
  93. readOnly: false,
  94. head: {
  95. titleNames: ["项目指引"],
  96. spanCols: [1],
  97. spanRows: [1],
  98. vAlign: [1],
  99. hAlign: [1],
  100. font: ["Arial"]
  101. },
  102. data: {
  103. field: "name",
  104. vAlign: 1,
  105. hAlign: 0,
  106. font: "Arial"
  107. }
  108. }]
  109. },
  110. headers: [
  111. {name: '项目指引', dataCode: 'name', width: 400, vAlign: 'center', hAlign: 'left', formatter: '@'},
  112. ],
  113. events: {
  114. SelectionChanged: function (sender, info) {
  115. guideItemInitSel(info.newSelections[0].row)
  116. },
  117. EditEnded: function (sender, args) {
  118. edit(args.sheet, [{row: args.row, col: args.col}]);
  119. },
  120. RangeChanged: function (sender, args) {
  121. edit(args.sheet, args.changedCells);
  122. }
  123. }
  124. };
  125. //定额章节树
  126. const section = {
  127. dom: $('#sectionSpread'),
  128. workBook: null,
  129. cache: [],
  130. tree: null,
  131. controller: null,
  132. treeSetting: {
  133. treeCol: 0,
  134. emptyRows: 0,
  135. headRows: 1,
  136. headRowHeight: [40],
  137. defaultRowHeight: 21,
  138. cols: [{
  139. width: 400,
  140. readOnly: true,
  141. head: {
  142. titleNames: ["名称"],
  143. spanCols: [1],
  144. spanRows: [1],
  145. vAlign: [1],
  146. hAlign: [1],
  147. font: ["Arial"]
  148. },
  149. data: {
  150. field: "name",
  151. vAlign: 1,
  152. hAlign: 0,
  153. font: "Arial"
  154. }
  155. }]
  156. },
  157. headers: [
  158. {name: '名称', dataCode: 'name', width: 400, vAlign: 'center', hAlign: 'left', formatter: '@'},
  159. ],
  160. events: {
  161. SelectionChanged: function (sender, info) {
  162. sectionInitSel(info.newSelections[0].row)
  163. }
  164. }
  165. };
  166. const ration = {
  167. dom: $('#rationSpread'),
  168. workBook: null,
  169. datas: [],//所有的数据,搜索定额时,从所有数据中筛选
  170. cache: [],//显示在表格上的数据,添加定额可以有效根据行识别定额
  171. headers: [
  172. {name: '选择', dataCode: 'select', width: 50, vAlign: 'center', hAlign: 'center'},
  173. {name: '编码', dataCode: 'code', width: 110, vAlign: 'center', hAlign: 'left', formatter: '@'},
  174. {name: '名称', dataCode: 'name', width: 250, vAlign: 'center', hAlign: 'left', formatter: '@'},
  175. {name: '单位', dataCode: 'unit', width: 100, vAlign: 'center', hAlign: 'left', formatter: '@'}
  176. ],
  177. events: {
  178. ButtonClicked: function (sender, args) {
  179. if(args.sheet.isEditing()){
  180. args.sheet.endEdit(true);
  181. }
  182. },
  183. CellDoubleClick: function (sender, args) {
  184. if(ration.headers[args.col].dataCode === 'name'){
  185. let insertDatas = getInsertRations([args.row]);
  186. if(insertDatas.length > 0){
  187. insert(insertDatas);
  188. }
  189. }
  190. }
  191. }
  192. };
  193. const options = {
  194. workBook: {
  195. tabStripVisible: false,
  196. allowContextMenu: false,
  197. allowCopyPasteExcelStyle : false,
  198. allowExtendPasteRange: false,
  199. allowUserDragDrop : false,
  200. allowUserDragFill: false,
  201. scrollbarMaxAlign : true
  202. },
  203. sheet: {
  204. protectionOptions: {allowResizeRows: true, allowResizeColumns: true},
  205. clipBoardOptions: GC.Spread.Sheets.ClipboardPasteOptions.values
  206. }
  207. };
  208. //渲染时方法,停止渲染
  209. //@param {Object}sheet {Function}func @return {void}
  210. function renderSheetFunc(sheet, func){
  211. sheet.suspendEvent();
  212. sheet.suspendPaint();
  213. if(func){
  214. func();
  215. }
  216. sheet.resumeEvent();
  217. sheet.resumePaint();
  218. }
  219. //设置表选项
  220. //@param {Object}workBook {Object}opts @return {void}
  221. function setOptions (workBook, opts) {
  222. for(let opt in opts.workBook){
  223. workBook.options[opt] = opts.workBook[opt];
  224. }
  225. for(let opt in opts.sheet){
  226. workBook.getActiveSheet().options[opt] = opts.sheet[opt];
  227. }
  228. }
  229. //建表头
  230. //@param {Object}sheet {Array}headers @return {void}
  231. function buildHeader(sheet, headers) {
  232. let fuc = function () {
  233. sheet.setColumnCount(headers.length);
  234. sheet.setRowHeight(0, 40, GC.Spread.Sheets.SheetArea.colHeader);
  235. for(let i = 0, len = headers.length; i < len; i++){
  236. sheet.setValue(0, i, headers[i].name, GC.Spread.Sheets.SheetArea.colHeader);
  237. sheet.setColumnWidth(i, headers[i].width, GC.Spread.Sheets.SheetArea.colHeader);
  238. if(headers[i].formatter){
  239. sheet.setFormatter(-1, i, headers[i].formatter);
  240. }
  241. sheet.getRange(-1, i, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[headers[i]['hAlign']]);
  242. sheet.getRange(-1, i, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[headers[i]['vAlign']]);
  243. }
  244. };
  245. renderSheetFunc(sheet, fuc);
  246. }
  247. //表监听事件
  248. //@param {Object}workBook @return {void}
  249. function bindEvent(workBook, events) {
  250. if(Object.keys(events).length === 0){
  251. return;
  252. }
  253. const Events = GC.Spread.Sheets.Events;
  254. let sheet = workBook.getActiveSheet();
  255. for(let event in events){
  256. workBook.bind(Events[event], events[event]);
  257. }
  258. }
  259. //建表
  260. //@param {Object}module @return {void}
  261. function buildSheet(module) {
  262. if(!module.workBook){
  263. module.workBook = new GC.Spread.Sheets.Workbook(module.dom[0], {sheetCount: 1});
  264. let sheet = module.workBook.getActiveSheet();
  265. if(module === bills){
  266. //默认初始可控制焦点在清单表中
  267. module.workBook.focus();
  268. sheet.options.isProtected = true;
  269. }
  270. else if(module === ration){
  271. sheet.options.isProtected = true;
  272. sheet.getRange(-1, 0, -1, 1).locked(false);
  273. sheet.getRange(-1, 1, -1, -1).locked(true);
  274. }
  275. else if(module === guideItem){
  276. sheetCommonObj.bindEscKey(module.workBook, [{sheet: sheet, editStarting: null, editEnded: module.events.EditEnded}]);
  277. }
  278. setOptions(module.workBook, options);
  279. buildHeader(module.workBook.getActiveSheet(), module.headers);
  280. bindEvent(module.workBook, module.events);
  281. }
  282. }
  283. //清空表数据
  284. //@param {Object}sheet {Array}headers {Number}rowCount @return {void}
  285. function cleanData(sheet, headers, rowCount){
  286. renderSheetFunc(sheet, function () {
  287. sheet.clear(-1, 0, -1, headers.length, GC.Spread.Sheets.SheetArea.viewport, GC.Spread.Sheets.StorageType.data);
  288. if (rowCount >= 0) {
  289. sheet.setRowCount(rowCount);
  290. }
  291. });
  292. }
  293. //根据清单获取项目指引
  294. //@param {String}guidanceLibID {Number}billsID {Function}callback @return {void}
  295. function getItemsByBills(guidanceLibID, billsID, callback){
  296. CommonAjax.post('/billsGuidance/api/getItemsByBills', {guidanceLibID: guidanceLibID, billsID: billsID}, function (rstData) {
  297. if(callback){
  298. callback(rstData);
  299. }
  300. });
  301. }
  302. //清单表焦点控制
  303. //@param {Number}row @return {void}
  304. function billsInitSel(row){
  305. let guideSheet = guideItem.workBook.getActiveSheet();
  306. cleanData(guideSheet, guideItem.headers, -1);
  307. let node = bills.tree.items[row];
  308. if(!node){
  309. return;
  310. }
  311. bills.tree.selected = node;
  312. if(!node.guidance.tree){
  313. getItemsByBills(libID, node.data.ID, function (rstData) {
  314. initTree(node.guidance, guideSheet, guideItem.treeSetting, rstData);
  315. //项目指引初始焦点
  316. guideItemInitSel(guideSheet.getActiveRowIndex() ? guideSheet.getActiveRowIndex() : 0);
  317. });
  318. }
  319. else{
  320. node.guidance.controller.showTreeData();
  321. //项目指引初始焦点
  322. guideItemInitSel(guideSheet.getActiveRowIndex() ? guideSheet.getActiveRowIndex() : 0);
  323. }
  324. }
  325. //选中的节点是否全是同层节点
  326. //@param {Object}sheet {Array}items @return {Boolean}
  327. function itemsSameDepth(sheet, items) {
  328. let sels = sheet.getSelections();
  329. if(sels.length === 0 || items.length === 0){
  330. return false;
  331. }
  332. let depths = [];
  333. for(let i = 0; i < sels[0].rowCount; i++){
  334. let row = sels[0].row + i;
  335. let node = items[row];
  336. if(node){
  337. depths.push(node.depth());
  338. }
  339. }
  340. }
  341. //节点子项是否全是工作内容
  342. //@param {Object}node @return {Boolean}
  343. function allJobChildren(node){
  344. for(let c of node.children){
  345. if(c.data.type === itemType.ration){
  346. return false;
  347. }
  348. }
  349. return true;
  350. }
  351. //节点子项是否全是定额
  352. //@param {Object}node @return {Boolean}
  353. function allRationChildren(node){
  354. for(let c of node.children){
  355. if(c.data.type === itemType.job){
  356. return false;
  357. }
  358. }
  359. return true;
  360. }
  361. //刷新按钮有效性
  362. //@param {Object}node @return {void}
  363. function refreshBtn(node){
  364. //全部设为无效
  365. $('.tools-btn').children().addClass('disabled');
  366. $('#insertRation').addClass('disabled');
  367. //插入
  368. if(bills.tree.selected && bills.tree.selected.guidance.tree){
  369. $('#insert').removeClass('disabled');
  370. if(node && node.data.type === itemType.ration){
  371. $('#insert').addClass('disabled');
  372. }
  373. }
  374. //删除
  375. if(node){
  376. $('#del').removeClass('disabled');
  377. }
  378. if(node && node.data.type === itemType.job){
  379. //升级
  380. if(node.parent){
  381. $('#upLevel').removeClass('disabled');
  382. if(node.nextSibling && node.children.length > 0 && !allJobChildren(node)){
  383. $('#upLevel').addClass('disabled');
  384. }
  385. }
  386. //降级
  387. if(node.preSibling){
  388. $('#downLevel').removeClass('disabled');
  389. if(node.preSibling.children.length > 0 && !allJobChildren(node.preSibling)){
  390. $('#downLevel').addClass('disabled');
  391. }
  392. }
  393. }
  394. //上移
  395. if(node && node.preSibling){
  396. $('#upMove').removeClass('disabled')
  397. }
  398. //下移
  399. if(node && node.nextSibling){
  400. $('#downMove').removeClass('disabled');
  401. }
  402. //插入定额
  403. if(node && (node.children.length === 0 || allRationChildren(node))){
  404. $('#insertRation').removeClass('disabled');
  405. }
  406. }
  407. //项目指引表焦点控制
  408. //@param {Number}row @return {void}
  409. function guideItemInitSel(row){
  410. console.log('et');
  411. let billsNode = bills.tree.selected;
  412. let node = null;
  413. if(billsNode && billsNode.guidance.tree){
  414. node = billsNode.guidance.tree.items[row];
  415. if(node){
  416. billsNode.guidance.tree.selected = node;
  417. }
  418. }
  419. refreshBtn(node);
  420. }
  421. //初始化当前库名
  422. //@param {String} @return {void}
  423. function initLibName(libName) {
  424. $('#libName')[0].outerHTML = $('#libName')[0].outerHTML.replace("XXX清单指引", libName);
  425. }
  426. //初始化各工作表
  427. //@param {Array}modules @return {void}
  428. function initWorkBooks(modules){
  429. for(let module of modules){
  430. buildSheet(module);
  431. }
  432. }
  433. function tipDivCheck(){
  434. setTimeout(function () {
  435. let tips = $('#autoTip');
  436. if(ration.tipDiv == 'show'){
  437. return;
  438. } else if(ration.tipDiv == 'hide'&&tips){
  439. tips.hide();
  440. ration._toolTipElement = null;
  441. }
  442. },600)
  443. }
  444. //获取悬浮提示单元格
  445. //@param {Object}sheet @return {Object}
  446. function getTipCellType(sheet) {
  447. let setting = {};
  448. let TipCellType = function () {};
  449. TipCellType.prototype = new GC.Spread.Sheets.CellTypes.Text();
  450. TipCellType.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) {
  451. return {
  452. x: x,
  453. y: y,
  454. row: context.row,
  455. col: context.col,
  456. cellStyle: cellStyle,
  457. cellRect: cellRect,
  458. sheet: context.sheet,
  459. sheetArea: context.sheetArea
  460. };
  461. };
  462. TipCellType.prototype.processMouseEnter = function (hitinfo) {
  463. let text = hitinfo.sheet.getText(hitinfo.row, hitinfo.col);
  464. let tag = hitinfo.sheet.getTag(hitinfo.row, hitinfo.col);
  465. /* let hintHeight = datas[hitinfo.row] ?
  466. datas[hitinfo.row].hintHeight ? datas[hitinfo.row].hintHeight : null
  467. : null; //定额库定额悬浮提示位置相关*/
  468. if(tag !== undefined && tag){
  469. text = tag;
  470. }
  471. if(sheet && sheet.getParent().qo){
  472. setting.pos = SheetDataHelper.getObjPos(sheet.getParent().qo);
  473. }
  474. if (setting.pos && text && text !== '') {
  475. //固定不显示的div,存储文本获取固定div宽度,toolTipElement由于显示和隐藏,获取宽度不正确
  476. if(!this._fixedTipElement){
  477. let div = $('#fixedTip')[0];
  478. if (!div) {
  479. div = document.createElement("div");
  480. $(div).css("padding", 5)
  481. .attr("id", 'fixedTip');
  482. $(div).hide();
  483. document.body.insertBefore(div, null);
  484. }
  485. this._fixedTipElement = div;
  486. }
  487. $(this._fixedTipElement).html(text);
  488. if (!this._toolTipElement) {
  489. let div = $('#autoTip')[0];
  490. if (!div) {
  491. div = document.createElement("div");
  492. $(div).css("position", "absolute")
  493. .css("border", "1px #C0C0C0 solid")
  494. .css("box-shadow", "1px 2px 5px rgba(0,0,0,0.4)")
  495. .css("font", "0.9rem Calibri")
  496. .css("background", "white")
  497. .css("padding", 5)
  498. .attr("id", 'autoTip');
  499. $(div).hide();
  500. document.body.insertBefore(div, null);
  501. }
  502. this._toolTipElement = div;
  503. //实时读取位置信息
  504. if(hitinfo.sheet && hitinfo.sheet.getParent().qo){
  505. setting.pos = SheetDataHelper.getObjPos(hitinfo.sheet.getParent().qo);
  506. }
  507. $(this._toolTipElement).html(text);
  508. //定额库定额特殊处理
  509. if($(hitinfo.sheet.getParent().qo).attr('id') === 'rationSpread'){
  510. let divWidth = $(this._fixedTipElement).width(),
  511. divHeight = $(this._fixedTipElement).height();
  512. $(this._toolTipElement).css("top", setting.pos.y + hitinfo.y - divHeight).css("left", setting.pos.x - divWidth);
  513. }
  514. else{
  515. $(this._toolTipElement).css("top", setting.pos.y + hitinfo.y +15).css("left", setting.pos.x + hitinfo.x + 15);
  516. }
  517. $(this._toolTipElement).show("fast");
  518. ration.tipDiv = 'show';//做个标记
  519. }
  520. }
  521. };
  522. TipCellType.prototype.processMouseLeave = function (hininfo) {
  523. ration.tipDiv = 'hide';
  524. if (this._toolTipElement) {
  525. $(this._toolTipElement).hide();
  526. this._toolTipElement = null;
  527. }
  528. tipDivCheck();//延时检查:当tips正在show的时候,就调用了hide方法,会导致tips一直存在,所以设置一个超时处理
  529. }
  530. return new TipCellType();
  531. }
  532. //输出表数据(定额表)
  533. //@param {Object}sheet {Array}headers {Array}datas @return {void}
  534. function showData(sheet, headers, datas){
  535. let fuc = function () {
  536. sheet.setRowCount(datas.length);
  537. //复选框
  538. let checkBoxType = new GC.Spread.Sheets.CellTypes.CheckBox();
  539. let tipCellType = getTipCellType(sheet);
  540. sheet.setCellType(-1, 0, checkBoxType);
  541. for(let col = 0, cLen = headers.length; col < cLen; col++){
  542. for(let row = 0, rLen = datas.length; row < rLen; row++){
  543. sheet.setValue(row, col, datas[row][headers[col]['dataCode']]);
  544. if(col === 1){
  545. sheet.setTag(row, col, datas[row]['hint']);
  546. }
  547. }
  548. }
  549. sheet.setCellType(-1, 1, tipCellType);
  550. };
  551. renderSheetFunc(sheet, fuc);
  552. }
  553. //根据定额章节树ID获取定额(从数据缓存中获取,定额数据一开始一次性拉取)
  554. //@param {Number}sectionId {Array}rations @return {Array}
  555. function getRationsBySectionId(sectionId, rations) {
  556. if(!sectionId || !rations){
  557. return [];
  558. }
  559. return _.filter(rations, {sectionId});
  560. }
  561. //定额章节树焦点控制
  562. //@param {Number}row @return {void}
  563. function sectionInitSel(row) {
  564. let rationSheet = ration.workBook.getActiveSheet();
  565. let sectionNode = section.tree ? section.tree.items[row] : null;
  566. if(sectionNode && sectionNode.children.length === 0){
  567. let sectionRations = getRationsBySectionId(sectionNode.data.ID, ration.datas);
  568. ration.cache = sectionRations;
  569. showData(rationSheet, ration.headers, sectionRations);
  570. }
  571. else {
  572. cleanData(rationSheet, ration.headers, 0);
  573. }
  574. }
  575. //初始化定额条目
  576. //@param {Number}rationLibId @return {void}
  577. function initRationItems(rationLibId){
  578. $.bootstrapLoading.start();
  579. //获取定额章节树
  580. let sectionSheet = section.workBook.getActiveSheet();
  581. CommonAjax.post('/rationRepository/api/getRationTree', {rationLibId: rationLibId}, function (sectionDatas) {
  582. //获取所有定额数据
  583. CommonAjax.post('/rationRepository/api/getRationItemsByLib', {rationLibId: rationLibId, showHint: true, returnFields: '-_id code ID sectionId name unit basePrice rationGljList'}, function (rstData) {
  584. section.cache = sectionDatas;
  585. initTree(section, section.workBook.getActiveSheet(), section.treeSetting, sectionDatas);
  586. //初始焦点在第一行(切换库)
  587. sectionSheet.setActiveCell(0, 0);
  588. rstData.sort(function (a, b) {
  589. let rst = 0;
  590. if(a.code > b.code){
  591. rst = 1;
  592. }
  593. else if(a.code < b.code){
  594. rst = -1;
  595. }
  596. return rst;
  597. });
  598. ration.datas = rstData;
  599. sectionInitSel(0);
  600. $.bootstrapLoading.end();
  601. }, function () {
  602. $.bootstrapLoading.end();
  603. });
  604. }, function () {
  605. $.bootstrapLoading.end();
  606. });
  607. }
  608. //初始化定额库选择
  609. //@param {String}compilationId @return {void}
  610. function initRationLibs(compilationId){
  611. CommonAjax.post('/rationRepository/api/getRationLibsByCompilation', {compilationId: compilationId}, function (rstData) {
  612. $('#rationLibSel').empty();
  613. for(let rationLib of rstData){
  614. let opt = `<option value="${rationLib.ID}">${rationLib.dispName}</option>`;
  615. $('#rationLibSel').append(opt);
  616. }
  617. //初始选择
  618. initRationItems(parseInt($('#rationLibSel').select().val()));
  619. $('#rationLibSel').change(function () {
  620. let rationLibId = parseInt($(this).select().val());
  621. initRationItems(rationLibId);
  622. })
  623. });
  624. }
  625. //获取指引库信息及关联的清单
  626. //@param {Number}libID {Function}callback @return {Object}
  627. function getLibWithBills(libID, callback){
  628. CommonAjax.post('/billsGuidance/api/getLibWithBills', {libID: libID}, function (rstData) {
  629. initRationLibs(rstData.guidanceLib.compilationId);
  630. bills.cache = rstData.bills;
  631. initLibName(rstData.guidanceLib.name);
  632. initTree(bills, bills.workBook.getActiveSheet(), bills.treeSetting, bills.cache);
  633. //每一棵项目指引树挂在清单节点上
  634. for(let node of bills.tree.items){
  635. node.guidance = {tree: null, controller: null};
  636. }
  637. //默认初始节点
  638. billsInitSel(0);
  639. if(callback){
  640. callback(rstData);
  641. }
  642. }, function (msg) {
  643. window.location.href = '/billsGuidance/main';
  644. });
  645. }
  646. //初始化并输出树
  647. //@param {Object}module {Object}sheet {Object}treeSetting {Array}datas
  648. function initTree(module, sheet, treeSetting, datas){
  649. module.tree = idTree.createNew({id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1, autoUpdate: true});
  650. module.controller = TREE_SHEET_CONTROLLER.createNew(module.tree, sheet, treeSetting);
  651. module.tree.loadDatas(datas);
  652. module.controller.showTreeData();
  653. }
  654. //更新项目指引
  655. //@param {Array}updateDatas {Function}callback @return {void}
  656. function updateGuideItems(updateDatas, callback){
  657. CommonAjax.post('/billsGuidance/api/updateItems', {updateDatas: updateDatas}, function (rstData) {
  658. if(callback){
  659. callback(rstData);
  660. }
  661. });
  662. }
  663. //项目指引编辑
  664. //@param {Object}sheet {Array}cells
  665. function edit(sheet, cells){
  666. let updateDatas = [];
  667. //同步节点数据
  668. let syncDatas = [];
  669. for(let cell of cells){
  670. let text = sheet.getValue(cell.row, cell.col);
  671. text = text ? text : '';
  672. let node = bills.tree.selected.guidance.tree.items[cell.row];
  673. if(node.data.name != text){
  674. syncDatas.push({node: node, text: text});
  675. updateDatas.push({updateType: updateType.update, findData: {ID: node.getID()}, updateData: {name: text}});
  676. }
  677. }
  678. if(updateDatas.length > 0){
  679. updateGuideItems(updateDatas, function () {
  680. for(let syncData of syncDatas){
  681. syncData.node.data.name = syncData.text;
  682. }
  683. }, function () {
  684. //失败恢复
  685. renderSheetFunc(sheet, function () {
  686. for(let syncData of syncDatas){
  687. sheet.setValue(syncData.node.serialNo(), 0, syncData.node.data.name ? syncData.node.data.name : '');
  688. }
  689. });
  690. });
  691. }
  692. }
  693. //项目指引插入,支持一次插入多条数据
  694. //@param {Array}datas {Function}callback @return {void}
  695. function insert(datas, callback = null){
  696. $.bootstrapLoading.start();
  697. let sheet = guideItem.workBook.getActiveSheet();
  698. let controller = bills.tree.selected.guidance.controller;
  699. let selected = bills.tree.selected.guidance.tree.selected;
  700. let updateDatas = [];
  701. //建立数组下标索引
  702. let newDataIndex = {};
  703. for(let i = 0; i < datas.length; i++){
  704. let newNodeData = {
  705. libID: libID, ID: uuid.v1(), ParentID: selected ? selected.getParentID() : -1, NextSiblingID: selected ? selected.getNextSiblingID() : -1,
  706. billsID: bills.tree.selected.getID()
  707. };
  708. //定额类型插入当前工作内容焦点行,
  709. if(selected && selected.data.type === itemType.job && datas[i].type === itemType.ration){
  710. newNodeData.ParentID = selected.getID();
  711. newNodeData.NextSiblingID = -1;
  712. }
  713. Object.assign(newNodeData, datas[i]);
  714. newDataIndex[i] = newNodeData;
  715. }
  716. for(let i = 0; i < datas.length; i++){
  717. //第一个节点
  718. if(i === 0){
  719. //非插入成子节点,更新选中节点NestSiblingID
  720. if(selected && !(selected.data.type === itemType.job && datas[i].type === itemType.ration)){
  721. updateDatas.push({updateType: updateType.update, findData: {ID: selected.getID()}, updateData: {NextSiblingID: newDataIndex[i].ID}});
  722. }
  723. }
  724. //非最后一个节点
  725. if(i !== datas.length - 1){
  726. newDataIndex[i].NextSiblingID = newDataIndex[i + 1].ID;
  727. }
  728. updateDatas.push({updateType: updateType.create, updateData: newDataIndex[i]});
  729. }
  730. updateGuideItems(updateDatas, function () {
  731. for(let updateData of updateDatas){
  732. if(updateData.updateType === updateType.create){
  733. let newNode = controller.insertByIDS(updateData.updateData.ID, updateData.updateData.ParentID, updateData.updateData.NextSiblingID);
  734. //同步data
  735. Object.assign(newNode.data, updateData.updateData);
  736. sheet.setValue(newNode.serialNo(), 0, newNode.data.name);
  737. refreshBtn(newNode);
  738. }
  739. }
  740. if(callback){
  741. callback();
  742. }
  743. $.bootstrapLoading.end();
  744. });
  745. }
  746. //项目指引删除操作
  747. //@return {void}
  748. function del(){
  749. $.bootstrapLoading.start();
  750. let controller = bills.tree.selected.guidance.controller;
  751. let selected = bills.tree.selected.guidance.tree.selected;
  752. let updateDatas = [];
  753. function getDelDatas(node){
  754. updateDatas.push({updateType: updateType.del, findData: {ID: node.getID()}, updateData: {deleted: true}});
  755. if(node.children.length > 0){
  756. for(let c of node.children){
  757. getDelDatas(c);
  758. }
  759. }
  760. }
  761. getDelDatas(selected);
  762. updateGuideItems(updateDatas, function () {
  763. controller.delete();
  764. refreshBtn(bills.tree.selected.guidance.tree.selected);
  765. $.bootstrapLoading.end();
  766. });
  767. }
  768. //项目指引升级
  769. //@return {void}
  770. function upLevel(){
  771. $.bootstrapLoading.start();
  772. let controller = bills.tree.selected.guidance.controller;
  773. let selected = bills.tree.selected.guidance.tree.selected;
  774. let updateDatas = [];
  775. //更新父节点
  776. updateDatas.push({updateType: updateType.update, findData: {ID: selected.getParentID()}, updateData: {NextSiblingID: selected.getID()}});
  777. //更新选中节点
  778. updateDatas.push({updateType: updateType.update, findData: {ID: selected.getID()},
  779. updateData: {ParentID: selected.parent.getParentID(), NextSiblingID: selected.parent.getNextSiblingID()}});
  780. if(selected.nextSibling && selected.children.length > 0){
  781. //更新选中节点最末子节点
  782. let lastChild = selected.children[selected.children.length - 1];
  783. updateDatas.push({updateType: updateType.update, findData: {ID: lastChild.getID()}, updateData: {NextSiblingID: selected.getNextSiblingID()}});
  784. }
  785. updateGuideItems(updateDatas, function () {
  786. controller.upLevel();
  787. refreshBtn(bills.tree.selected.guidance.tree.selected);
  788. $.bootstrapLoading.end();
  789. });
  790. }
  791. //项目指引降级
  792. //@return {void}
  793. function downLevel(){
  794. $.bootstrapLoading.start();
  795. let controller = bills.tree.selected.guidance.controller;
  796. let selected = bills.tree.selected.guidance.tree.selected;
  797. let updateDatas = [];
  798. //更新前兄弟节点
  799. updateDatas.push({updateType: updateType.update, findData: {ID: selected.preSibling.getID()}, updateData: {NextSiblingID: selected.getNextSiblingID()}});
  800. //更新前兄弟节点最末子节点
  801. if(selected.preSibling.children.length > 0){
  802. let lastChild = selected.preSibling.children[selected.preSibling.children.length - 1];
  803. updateDatas.push({updateType: updateType.update, findData: {ID: lastChild.getID()}, updateData: {NextSiblingID: selected.getID()}});
  804. }
  805. //更新选中节点
  806. updateDatas.push({updateType: updateType.update, findData: {ID: selected.getID()}, updateData: {ParentID: selected.preSibling.getID(), NextSiblingID: -1}});
  807. updateGuideItems(updateDatas, function () {
  808. controller.downLevel();
  809. refreshBtn(bills.tree.selected.guidance.tree.selected);
  810. $.bootstrapLoading.end();
  811. });
  812. }
  813. //项目指引上移
  814. //@return {void}
  815. function upMove(){
  816. $.bootstrapLoading.start();
  817. let controller = bills.tree.selected.guidance.controller;
  818. let selected = bills.tree.selected.guidance.tree.selected;
  819. let updateDatas = [];
  820. //更新前节点
  821. updateDatas.push({updateType: updateType.update, findData: {ID: selected.preSibling.getID()}, updateData: {NextSiblingID: selected.getNextSiblingID()}});
  822. //更新前前节点
  823. if(selected.preSibling.preSibling){
  824. updateDatas.push({updateType: updateType.update, findData: {ID: selected.preSibling.preSibling.getID()}, updateData: {NextSiblingID: selected.getID()}});
  825. }
  826. //更新选中节点
  827. updateDatas.push({updateType: updateType.update, findData: {ID: selected.getID()}, updateData: {NextSiblingID: selected.preSibling.getID()}});
  828. updateGuideItems(updateDatas, function () {
  829. controller.upMove();
  830. refreshBtn(bills.tree.selected.guidance.tree.selected);
  831. $.bootstrapLoading.end();
  832. });
  833. }
  834. //项目指引下移
  835. //@return {void}
  836. function downMove(){
  837. $.bootstrapLoading.start();
  838. let controller = bills.tree.selected.guidance.controller;
  839. let selected = bills.tree.selected.guidance.tree.selected;
  840. let updateDatas = [];
  841. //更新下节点
  842. updateDatas.push({updateType: updateType.update, findData: {ID: selected.getNextSiblingID()}, updateData: {NextSiblingID: selected.getID()}});
  843. //更新前节点
  844. if(selected.preSibling){
  845. updateDatas.push({updateType: updateType.update, findData: {ID: selected.preSibling.getID()}, updateData: {NextSiblingID: selected.getNextSiblingID()}});
  846. }
  847. //更新选中节点
  848. updateDatas.push({updateType: updateType.update, findData: {ID: selected.getID()}, updateData: {NextSiblingID: selected.nextSibling.getNextSiblingID()}});
  849. updateGuideItems(updateDatas, function () {
  850. controller.downMove();
  851. refreshBtn(bills.tree.selected.guidance.tree.selected);
  852. $.bootstrapLoading.end();
  853. });
  854. }
  855. //获取定额类型的项目指引名称,通过定额转换
  856. //@param {Object}ration @return {String}
  857. function getRationItemName(ration){
  858. let arr = [];
  859. arr.push(ration.code ? ration.code : '');
  860. arr.push(ration.name ? ration.name : '');
  861. arr.push(ration.basePrice ? ration.basePrice : '');
  862. let rst = arr.join(' ');
  863. rst += `/${ration.unit ? ration.unit : ''}`;
  864. return rst;
  865. }
  866. //获取选中的定额表行
  867. //@return {Array}
  868. function getCheckedRationRows(){
  869. let rst = [];
  870. let sheet = ration.workBook.getActiveSheet();
  871. for(let i = 0; i < sheet.getRowCount(); i++){
  872. let checked = sheet.getValue(i, 0);
  873. if(checked){
  874. rst.push(i);
  875. }
  876. }
  877. return rst;
  878. }
  879. //清空选中定额表行
  880. //@param {Array}rows @return {void}
  881. function clearCheckedRation(rows) {
  882. let sheet = ration.workBook.getActiveSheet();
  883. renderSheetFunc(sheet, function () {
  884. for(let row of rows){
  885. sheet.setValue(row, 0, 0);
  886. }
  887. });
  888. }
  889. //获取要插入的定额数据
  890. //@param {Array}rows @return {Array}
  891. function getInsertRations(rows){
  892. let rst = [];
  893. //当前已存在定额
  894. let curRationIems = [];
  895. let selected = bills.tree.selected.guidance.tree.selected;
  896. if(selected){
  897. if(selected.data.type === itemType.job){
  898. curRationIems = selected.children;
  899. }
  900. else {
  901. curRationIems = selected.parent ? selected.parent.children : selected.tree.roots;
  902. }
  903. }
  904. for(let row of rows){
  905. let selRation = ration.cache[row];
  906. if(selRation){
  907. //添加的定额是否已存在,不重复添加
  908. let isExist = false;
  909. for(let curRation of curRationIems){
  910. if(curRation.data.rationID == selRation.ID){
  911. isExist = true;
  912. break;
  913. }
  914. }
  915. if(!isExist){
  916. rst.push({type: itemType.ration, name: getRationItemName(selRation), rationID: selRation.ID});
  917. }
  918. }
  919. }
  920. return rst;
  921. }
  922. //初始化个按钮点击
  923. //@return {void}
  924. function initBtn(){
  925. $('#insert').click(function () {
  926. insert([{type: itemType.job, name: ''}]);
  927. });
  928. $('#delConfirm').click(function () {
  929. del();
  930. $('#delAlert').modal('hide');
  931. });
  932. $('#del').click(function () {
  933. $('#delAlert').modal('show');
  934. });
  935. $('#upLevel').click(function () {
  936. upLevel();
  937. });
  938. $('#downLevel').click(function () {
  939. downLevel();
  940. });
  941. $('#upMove').click(function () {
  942. upMove();
  943. });
  944. $('#downMove').click(function () {
  945. downMove();
  946. });
  947. $('#insertRation').click(function () {
  948. let checkedRows = getCheckedRationRows();
  949. let insertDatas = getInsertRations(checkedRows);
  950. if(insertDatas.length > 0){
  951. insert(insertDatas, function () {
  952. //清空选择
  953. clearCheckedRation(checkedRows);
  954. });
  955. }
  956. else {
  957. clearCheckedRation(checkedRows);
  958. }
  959. });
  960. //搜索定额
  961. $('#searchBtn').click(function () {
  962. let searchStr = $('#searchText').val();
  963. if(!searchStr || searchStr === ''){
  964. ration.cache = ration.datas;
  965. }
  966. else{
  967. let reg = new RegExp(searchStr, 'i');
  968. ration.cache = _.filter(ration.datas, function (data) {
  969. return reg.test(data.code);
  970. });
  971. }
  972. $('.top-content').hide();
  973. $('#searchCount').text(`搜索结果: ${ration.cache.length}`);
  974. $('#rationSearchResult').show();
  975. autoFlashHeight();
  976. ration.workBook.refresh();
  977. let rationSheet = ration.workBook.getActiveSheet();
  978. renderSheetFunc(rationSheet, function () {
  979. clearCheckedRation(getCheckedRationRows());
  980. showData(rationSheet, ration.headers, ration.cache);
  981. })
  982. });
  983. //关闭搜索
  984. $('#rationSearchResult a').click(function () {
  985. $('.top-content').show();
  986. $('#rationSearchResult').hide();
  987. autoFlashHeight();
  988. renderSheetFunc(ration.workBook.getActiveSheet(), function () {
  989. clearCheckedRation(getCheckedRationRows());
  990. });
  991. section.workBook.refresh();
  992. ration.workBook.refresh();
  993. $('#searchText').val('');
  994. //恢复章节树下的定额
  995. sectionInitSel(section.workBook.getActiveSheet().getActiveRowIndex());
  996. });
  997. //执行搜索
  998. $('#searchText').keyup(function (e) {
  999. $('#searchBtn').click();
  1000. });
  1001. }
  1002. //初始化视图
  1003. //@param {void} @return {void}
  1004. function initViews(){
  1005. let modules = [bills, guideItem, section, ration];
  1006. initWorkBooks(modules);
  1007. getLibWithBills(libID);
  1008. initBtn();
  1009. }
  1010. return {initViews};
  1011. })();
  1012. $(document).ready(function () {
  1013. billsGuidance.initViews();
  1014. });