std_billsGuidance_lib.js 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182
  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. //更新类型
  13. const updateType = {update: 'update', create: 'create'};
  14. //库类型
  15. const libType = {'guidance': 1, 'elf': 2}; //清单指引、清单精灵
  16. const libSel = $('#stdBillsGuidanceLibSelect');
  17. //工作内容
  18. let stdBillsJobData = [];
  19. //项目特征
  20. let stdBillsFeatureData = [];
  21. //正在插入
  22. let isInserting = false;
  23. const bills = {
  24. dom: $('#billsGuidance_bills'),
  25. workBook: null,
  26. cache: [],
  27. tree: null,
  28. controller: null,
  29. treeSetting: {
  30. emptyRowHeader: true,
  31. rowHeaderWidth: 15,
  32. treeCol: 0,
  33. emptyRows: 0,
  34. headRows: 1,
  35. headRowHeight: [40],
  36. defaultRowHeight: 21,
  37. cols: [{
  38. width: 105,
  39. readOnly: true,
  40. showHint: true,
  41. head: {
  42. titleNames: ["项目编码"],
  43. spanCols: [1],
  44. spanRows: [1],
  45. vAlign: [1],
  46. hAlign: [1],
  47. font: ["Arial"]
  48. },
  49. data: {
  50. field: "code",
  51. vAlign: 1,
  52. hAlign: 0,
  53. font: "Arial"
  54. }
  55. }, {
  56. width: 190,
  57. readOnly: true,
  58. head: {
  59. titleNames: ["项目名称"],
  60. spanCols: [1],
  61. spanRows: [1],
  62. vAlign: [1],
  63. hAlign: [1],
  64. font: ["Arial"]
  65. },
  66. data: {
  67. field: "name",
  68. vAlign: 1,
  69. hAlign: 0,
  70. font: "Arial"
  71. }
  72. },
  73. {
  74. width: 60,
  75. readOnly: true,
  76. head: {
  77. titleNames: ["计量单位"],
  78. spanCols: [1],
  79. spanRows: [1],
  80. vAlign: [1],
  81. hAlign: [1],
  82. font: ["Arial"]
  83. },
  84. data: {
  85. field: "unit",
  86. vAlign: 1,
  87. hAlign: 1,
  88. font: "Arial"
  89. }
  90. }
  91. ]
  92. },
  93. headers: [
  94. {name: '项目编码', dataCode: 'code', width: 105, vAlign: 'center', hAlign: 'left', formatter: '@'},
  95. {name: '项目名称', dataCode: 'name', width: 190, vAlign: 'center', hAlign: 'left', formatter: '@'},
  96. {name: '单位', dataCode: 'unit', width: 60, vAlign: 'center', hAlign: 'center', formatter: '@'},
  97. ],
  98. rowHeaderWidth:1,
  99. events: {
  100. CellDoubleClick: function (sender, args) {
  101. if(!bills.tree){
  102. return;
  103. }
  104. let node = bills.tree.items[args.row];
  105. if(!node){
  106. return;
  107. }
  108. //展开收起(非最底层节点且双击的是第一列)
  109. if (args.col === 0 && node.children.length > 0) {
  110. node.setExpanded(!node.expanded);
  111. //设置展开收起状态
  112. sessionStorage.setItem('stdBillsGuidanceExpState', bills.tree.getExpState(bills.tree.items));
  113. renderSheetFunc(args.sheet, function () {
  114. let iCount = node.posterityCount(), i, child;
  115. for (i = 0; i < iCount; i++) {
  116. child = bills.tree.items[args.row + i + 1];
  117. args.sheet.setRowVisible(args.row + i + 1, child.visible, args.sheetArea);
  118. }
  119. args.sheet.invalidateLayout();
  120. });
  121. args.sheet.repaint();
  122. } else if (!projectReadOnly && !isInserting && !projectObj.project.isBillsLocked() && (args.col !== 0 || node.children.length === 0)) {
  123. //选中部分的最底层(只是选中部分的最底)
  124. let lowestNodes = [bills.tree.items[args.row]];
  125. insertBills(lowestNodes);
  126. }
  127. }
  128. }
  129. };
  130. // 获取对比树片段数据的方法,此方法可能会被覆盖,方法存在一个对象中,使得外部可以覆盖相关方法
  131. // 在农村公路2020中,主树对比片段与这里的逻辑是不相同的
  132. const overwrite = {
  133. getFragment() {
  134. return { parent: null, mainTreeFragment: projectObj.project.Bills.tree.roots }
  135. }
  136. };
  137. //插入清单
  138. function insertBills(lowestNodes) {
  139. let selTree = getSelTree(lowestNodes);
  140. const { errMsg, parent, mainTreeFragment } = overwrite.getFragment();
  141. if (errMsg) {
  142. alert(errMsg);
  143. return;
  144. }
  145. let compareData = compareTree(parent, mainTreeFragment, selTree.roots);
  146. let sheet = projectObj.mainSpread.getActiveSheet(),
  147. row = sheet.getActiveColumnIndex(),
  148. col = sheet.getActiveColumnIndex();
  149. if (compareData.postData.length > 0) {
  150. //如果插入的是固定清单,则需要判断该固定清单在造价书中是否已存在,造价书中不可存在相同的固定清单
  151. let fixedDatas = compareData.postData.filter((data) =>
  152. data.updateType === updateType.create && Array.isArray(data.updateData.flags));
  153. if (fixedDatas.length > 0) {
  154. //提示已存在此固定清单并且定位
  155. let firstFixed = fixedDatas[0].updateData;
  156. let existNode = projectObj.project.mainTree.items.find((node) =>
  157. node.data && node.data.flagsIndex && node.data.flagsIndex.fixed && node.data.flagsIndex.fixed.flag === firstFixed.flags[0].flag);
  158. if (existNode) {
  159. alert(`固定清单<strong>“${firstFixed.name}”</strong>已被第${existNode.serialNo() + 1}行清单占用。`);
  160. locateAtSpread(sheet, existNode.serialNo(), col);
  161. return;
  162. }
  163. }
  164. isInserting = true;
  165. CommonAjax.post('/bills/insertBills', {postData: compareData.postData}, function () {
  166. //插入
  167. let insertData = _.filter(compareData.postData, {updateType: updateType.create});
  168. let treeData = [];
  169. for (let data of insertData) {
  170. treeData.push(data.updateData);
  171. }
  172. //插入清单节点
  173. projectObj.project.Bills.tree.insertByDatas(treeData);
  174. projectObj.project.Bills.datas = projectObj.project.Bills.datas.concat(treeData);
  175. //插入主树节点
  176. let newNodes = projectObj.project.mainTree.insertByDatas(treeData);
  177. for (let node of newNodes) {
  178. node.source = projectObj.project.Bills.tree.nodes[projectObj.project.Bills.tree.prefix + node.getID()];
  179. node.data = node.source.data;
  180. node.sourceType = projectObj.project.Bills.getSourceType();
  181. }
  182. ProjectController.syncDisplayNewNodes(projectObj.mainController, newNodes, true);
  183. row = newNodes[newNodes.length - 1].serialNo();
  184. //有新的节点插入,也有可能定位至旧节点(批量选用的情况下)
  185. if (compareData.locateNode) {
  186. //该清单节点在主树的位置
  187. row = projectObj.project.mainTree.nodes[projectObj.project.mainTree.prefix + compareData.locateNode.data.ID].serialNo();
  188. }
  189. locateAtSpread(sheet, row, col);
  190. isInserting = false;
  191. }, function () {
  192. isInserting = false;
  193. });
  194. } else if (compareData.locateNode) {
  195. //该清单节点在主树的位置
  196. row = projectObj.project.mainTree.nodes[projectObj.project.mainTree.prefix + compareData.locateNode.data.ID].serialNo();
  197. locateAtSpread(sheet, row, col);
  198. }
  199. }
  200. function locateAtSpread(sheet, row, col) {
  201. sheet.setSelection(row, col, 1, 1);
  202. projectObj.mainController.setTreeSelected(projectObj.mainController.tree.items[row]);//触发树节点选中事件
  203. sheet.showRow(row, GC.Spread.Sheets.VerticalPosition.center);
  204. }
  205. /*
  206. *
  207. * 1.选中的树结构(清单规则选中的节点及其所有父项)与主树对比(主树中节点“编码-名称-单位”与选中树~组合相同视为同一节点),
  208. * 将主树中不含有的选中节点全部插入
  209. * 2.插入位置由1对比得出,主树有与选中树结构相同层次结构的片段,这个相同片段为插入位置
  210. * 3.选中树结构除去相同片段,为需要插入的节点,插入时,遇到同层节点,根据编码的字符编码值确定顺序
  211. * a.code <= b.code,则a节点在b节点前
  212. * */
  213. //获取选中的树(将选中的节点及其所有父项,组合成一棵树,没有重复节点)
  214. //@param {Array}lowestNodes(选中的最底层节点) @return {Array}
  215. function getSelTree(lowestNodes) {
  216. let allNodes = [];
  217. //获取树上所有的节点
  218. for (let node of lowestNodes) {
  219. while (node && !allNodes.includes(node)) {
  220. allNodes.push(node);
  221. node = node.parent;
  222. }
  223. }
  224. //根据原节点serialNo排序,排序后,后一项节点只可能前节点的后兄弟项,或子项(根据原节点ID-ParentID判定)
  225. allNodes.sort(function (a, b) {
  226. let aV = a.serialNo(),
  227. bV = b.serialNo();
  228. if (aV > bV) {
  229. return 1;
  230. } else if (aV < bV) {
  231. return -1;
  232. }
  233. return 0;
  234. });
  235. //生成树数据
  236. let treeData = [];
  237. //旧ID与新ID映射
  238. let IDMapping = {};
  239. for (let i = 0; i < allNodes.length; i++) {
  240. //原节点
  241. let preN = allNodes[i - 1],
  242. thisN = allNodes[i];
  243. let newNodeData = {ID: uuid.v1(), NextSiblingID: -1, ParentID: -1, orgID: thisN.data.ID};
  244. IDMapping[newNodeData.orgID] = newNodeData.ID;
  245. treeData.push(newNodeData);
  246. //新树数据
  247. let preData = treeData[i - 1],
  248. thisData = treeData[i];
  249. //节点与上节点为同层节点,则此节点设为上节点的后兄弟
  250. if (preN && preN.data.ParentID === thisN.data.ParentID) {
  251. preData.NextSiblingID = thisData.ID;
  252. //节点与上节点不为同层节点,则此节点为某上节点的子几点
  253. } else if (preN && preN.data.ParentID !== thisN.data.ParentID) {
  254. let parentID = IDMapping[thisN.data.ParentID];
  255. thisData.ParentID = parentID;
  256. }
  257. }
  258. let selTree = idTree.createNew({id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1, autoUpdate: true});
  259. selTree.loadDatas(treeData);
  260. return selTree;
  261. }
  262. /*
  263. * 选中树与清单主树进行对比,(自上而下,从roots开始)获取插入、更新数据
  264. * 找到的清单树中清单子项含有非清单项或输入了计算基数,则中止该清单的对比,不可插入数据
  265. * */
  266. //获取节点的匹配数据:编码-名称-单位
  267. //@param {Object}node @return {String}
  268. function getMatchContent(node) {
  269. return `${node.data.code ? node.data.code : '*'}-${node.data.name ? node.data.name : '*'}-${node.data.unit ? node.data.unit: '*'}`;
  270. }
  271. //**对比清单主树节点片段与选中树节点片段,获取需要更新和插入的数据**
  272. //@param {Object}parent - 主树片段的父节点 {Array}mainTreeFragment {Array}stdTreeFragment
  273. function compareTree(parent, mainTreeFragment, stdTreeFragment) {
  274. //需要插入、更新的数据
  275. let postData = [],
  276. //跟树结构自动定位至的清单节点(最近匹配到的节点)
  277. locateNode = null;
  278. if (!mainTreeFragment || !stdTreeFragment) {
  279. return postData;
  280. }
  281. comparePeer(parent, mainTreeFragment, stdTreeFragment);
  282. return {postData, locateNode};
  283. /*
  284. * 该清单节点是否可以继续往下递归匹配,即该节点是否还可插入子项(在该层匹配到的时候判断)
  285. * 1.该底层节点不能含有非清单子项
  286. * 2.该节点不能含有计算基数
  287. * todo 3.数量单价等相关概念,等有了补上
  288. * @param {Object}billsNode(清单树中的某节点) @return {Boolean}
  289. * */
  290. function canRecursive(billsNode) {
  291. //主树节点含有子节点,清单节点不含子节点,说明该节点含有非清单子项
  292. //这里需要去mainTree查,不能在清单树查,因为清单树的节点children里只会有清单,就算实际上有定额,这个children里也不含该定额
  293. let mainTreeNode = projectObj.project.mainTree.getNodeByID(billsNode.data.ID);
  294. if (!mainTreeNode) {
  295. return false;
  296. }
  297. if (mainTreeNode && mainTreeNode.children.length > 0 && billsNode.children.length === 0) {
  298. return false;
  299. } else if (billsNode.data.calcBase) {
  300. return false;
  301. }
  302. return true;
  303. }
  304. //获取某选中节点要往清单主树同层插入的位置
  305. function insertPos(peerNodes, node) {
  306. //node选中树中没有记录原清单的数据,只记录了原清单ID,需要node的数据,则要找回原清单
  307. let orgNode = bills.tree.nodes[`${bills.tree.prefix}${node.data.orgID}`];
  308. if (!orgNode) {
  309. return -1;
  310. }
  311. let insertCode = orgNode.data.code ? orgNode.data.code : '';
  312. //插入最顶层节点或者无编码,对比选中节点后兄弟节点和同层主树节点的名称,插在的匹配的节点前面
  313. function mathNext(selNode, compareNodes) {
  314. let selNext = selNode.nextSibling;
  315. while (selNext) {
  316. for (let i = 0; i < compareNodes.length; i++) {
  317. if (compareNodes[i].data.name === selNext.data.name) {
  318. return i;
  319. }
  320. }
  321. selNext = selNext.nextSibling;
  322. }
  323. return compareNodes.length;
  324. }
  325. if (orgNode.depth() === 0 || insertCode === '') {
  326. return mathNext(orgNode, peerNodes);
  327. //return peerNodes.length;
  328. }
  329. for (let i = 0; i < peerNodes.length; i++) {
  330. let thisNode = peerNodes[i];
  331. let thisCode = thisNode.data.code ? thisNode.data.code : '';
  332. //确定同层节点的顺序,编码小于等于在前,大于在后
  333. if (insertCode <= thisCode) {
  334. return i;
  335. } else if (insertCode > thisCode) {
  336. continue;
  337. }
  338. }
  339. return peerNodes.length;
  340. }
  341. //获取插入清单数据
  342. function getInsertData(insertObj) {
  343. let stdNode = bills.tree.nodes[`${bills.tree.prefix}${insertObj.orgID}`];
  344. if (!stdNode) {
  345. return null;
  346. }
  347. let stdData = {};
  348. stdData.projectID = projectObj.project.projectInfo.ID;
  349. stdData.isAdd = 1;
  350. stdData.ID = insertObj.ID;
  351. stdData.ParentID = insertObj.ParentID;
  352. stdData.NextSiblingID = insertObj.NextSiblingID;
  353. //顶层节点是大项费用
  354. stdData.type = stdNode.parent ? billType.BILL : billType.DXFY;
  355. stdData.code = stdNode.data.code;
  356. stdData.name = stdNode.data.name;
  357. stdData.unit = stdNode.data.unit;
  358. stdData.ruleText = stdNode.data.ruleText;
  359. stdData.comments = stdNode.data.comments;
  360. stdData.programID = stdNode.data.engineering;
  361. stdData.billsLibId = stdNode.data.billsLibId;
  362. if (stdNode.data.fixedFlag) {
  363. stdData.flags = [{flag : stdNode.data.fixedFlag, fieldName : 'fixed'}];
  364. stdData.flagsIndex = {fixed: {fieldName: 'fixed', flag: stdNode.data.fixedFlag}}; //前端用
  365. }
  366. return stdData;
  367. }
  368. //从同层节点中获取更新数据
  369. //@param {Object}parentNode(同层节点挂载的父节点,清单主树中) {Array}peerNodes(同层节点,含有清单树和选中树节点)
  370. // {Array}billsNodes(该层清单树节点) {Array}selNodes(该层选中树节点) @return {Array}
  371. function getUpdateDataFromPeer(parentNode, peerNodes, billsNodes, selNodes) {
  372. let rst = [];
  373. //向下获取插入数据直到最底层
  374. function getDataTillDeepest(node) {
  375. if (node) {
  376. let insertData = getInsertData(node.data);
  377. if (insertData) {
  378. rst.push({updateType: updateType.create, updateData: insertData});
  379. }
  380. for (let child of node.children) {
  381. getDataTillDeepest(child);
  382. }
  383. }
  384. }
  385. for (let i = 0; i < peerNodes.length; i++) {
  386. let thisNode = peerNodes[i],
  387. nextNode = peerNodes[i + 1];
  388. //更新原清单节点NextSiblingID
  389. if (billsNodes.includes(thisNode) && selNodes.includes(nextNode)) {
  390. rst.push({updateType: updateType.update, updateData: {ID: thisNode.data.ID, NextSiblingID: nextNode.data.ID}});
  391. } else if (selNodes.includes(thisNode) && billsNodes.includes(nextNode)) { //变更选中节点的NextSiblingID
  392. thisNode.data.NextSiblingID = nextNode.data.ID;
  393. }
  394. //所有选中的同层节点设为清单树父节点的子项,获取插入数据(插入该同层节点及其所有子节点)
  395. if (selNodes.includes(thisNode)) {
  396. thisNode.data.ParentID = parentNode ? parentNode.data.ID : -1;
  397. getDataTillDeepest(thisNode);
  398. }
  399. }
  400. return rst;
  401. }
  402. //同层节点之间比较,匹配到的则继续往下匹配,匹配不到的节点则按照规定的顺序进行排序,插入更新(更新清单树节点中NextSiblingID改变的节点)
  403. function comparePeer(parentNode, billsNodes, selNodes) {
  404. let peerNodes = [].concat(billsNodes); //同层节点
  405. let matchNode = null; //匹配到的清单主树节点
  406. for (let selNode of selNodes) {
  407. let stdNode = bills.tree.nodes[`${bills.tree.prefix}${selNode.data.orgID}`],
  408. selMatch = getMatchContent(stdNode),
  409. isMatched = false;
  410. for( let billsNode of billsNodes) {
  411. let billsMatch = getMatchContent(billsNode);
  412. if (selMatch === billsMatch) {//只进行一次成功匹配
  413. matchNode = billsNode;
  414. isMatched = true;
  415. if (selNode.children.length === 0) {//成功匹配且为选中的最底节点,则为自动定位节点
  416. locateNode = matchNode;
  417. }
  418. break;
  419. }
  420. }
  421. if (isMatched && canRecursive(matchNode)) {//匹配成功,且该匹配到的节点可插入子项,递归匹配子项
  422. comparePeer(matchNode, matchNode.children, selNode.children);
  423. } else if (!isMatched) { //匹配不成功,其节点与该层清单节点同层,根据编码插入同层数组中
  424. let pos = insertPos(peerNodes, selNode);
  425. if (pos >= 0) {
  426. peerNodes.splice(pos, 0, selNode);
  427. }
  428. }
  429. }
  430. //同层节点比清单树节点多了,说明在该层有选中节点插入清单树中
  431. if (peerNodes.length > billsNodes.length) {
  432. let updateData = getUpdateDataFromPeer(parentNode, peerNodes, billsNodes, selNodes);
  433. postData = postData.concat(updateData);
  434. }
  435. }
  436. }
  437. //项目指引类型
  438. const itemType = {
  439. job: 0,
  440. ration: 1
  441. };
  442. const guideItem = {
  443. dom: $('#billsGuidance_items'),
  444. workBook: null,
  445. tree: null,
  446. controller: null,
  447. treeSetting: {
  448. treeCol: 1,
  449. emptyRows: 0,
  450. headRows: 1,
  451. headRowHeight: [40],
  452. defaultRowHeight: 21,
  453. cols: [
  454. {
  455. width: 35,
  456. readOnly: false,
  457. head: {
  458. titleNames: ["选择"],
  459. spanCols: [1],
  460. spanRows: [1],
  461. vAlign: [1],
  462. hAlign: [1],
  463. font: ["Arial"]
  464. },
  465. data: {
  466. field: "select",
  467. vAlign: 1,
  468. hAlign: 1,
  469. font: "Arial"
  470. }
  471. },
  472. {
  473. width: 420,
  474. readOnly: false,
  475. head: {
  476. titleNames: ["项目指引"],
  477. spanCols: [1],
  478. spanRows: [1],
  479. vAlign: [1],
  480. hAlign: [1],
  481. font: ["Arial"]
  482. },
  483. data: {
  484. field: "name",
  485. vAlign: 1,
  486. hAlign: 0,
  487. font: "Arial"
  488. }
  489. }
  490. ]
  491. },
  492. headers: [
  493. {name: '选择', dataCode: 'select', width: 35, vAlign: 'center', hAlign: 'center', formatter: '@'},
  494. {name: '项目指引', dataCode: 'name', width: 300, vAlign: 'center', hAlign: 'left', formatter: '@'},
  495. ],
  496. rowHeaderWidth:25,
  497. events: {
  498. EditStarting: function (sender, args) {
  499. if(!bills.tree || guideItem.headers[args.col]['dataCode'] === 'name'){
  500. args.cancel = true;
  501. }
  502. },
  503. ButtonClicked: function (sender, args) {
  504. if(args.sheet.isEditing()){
  505. args.sheet.endEdit(true);
  506. }
  507. refreshInsertRation();
  508. },
  509. CellDoubleClick: function (sender, args) {
  510. if(!bills.tree || !bills.tree.selected){
  511. return;
  512. }
  513. let node = bills.tree.selected.guidance.tree.selected;
  514. if(!node){
  515. return;
  516. }
  517. if(node.children.length === 0){
  518. if(guideItem.headers[args.col]['dataCode'] === 'name'){
  519. insertRations(getInsertRationData([args.row]));
  520. }
  521. }
  522. else {
  523. node.setExpanded(!node.expanded);
  524. renderSheetFunc(args.sheet, function () {
  525. let iCount = node.posterityCount(), i, child;
  526. for (i = 0; i < iCount; i++) {
  527. child = bills.tree.selected.guidance.tree.items[args.row + i + 1];
  528. args.sheet.setRowVisible(args.row + i + 1, child.visible, args.sheetArea);
  529. }
  530. args.sheet.invalidateLayout();
  531. });
  532. args.sheet.repaint();
  533. }
  534. }
  535. }
  536. };
  537. const elfItem = {
  538. dom: $('#billsGuidance_items'),
  539. workBook: null,
  540. tree: null,
  541. controller: null,
  542. treeSetting: {
  543. treeCol: 0,
  544. emptyRows: 0,
  545. headRows: 1,
  546. headRowHeight: [40],
  547. defaultRowHeight: 21,
  548. cols: [
  549. {
  550. width: 250,
  551. readOnly: true,
  552. head: {
  553. titleNames: ["施工工序"],
  554. spanCols: [1],
  555. spanRows: [1],
  556. vAlign: [1],
  557. hAlign: [1],
  558. font: ["Arial"]
  559. },
  560. data: {
  561. field: "name",
  562. vAlign: 1,
  563. hAlign: 0,
  564. font: "Arial"
  565. }
  566. },
  567. {
  568. width: 250,
  569. readOnly: false,
  570. head: {
  571. titleNames: ["选项"],
  572. spanCols: [1],
  573. spanRows: [1],
  574. vAlign: [1],
  575. hAlign: [1],
  576. font: ["Arial"]
  577. },
  578. data: {
  579. field: "options",
  580. vAlign: 1,
  581. hAlign: 0,
  582. font: "Arial"
  583. }
  584. }
  585. ]
  586. },
  587. headers: [
  588. {name: '施工工序', dataCode: 'name', width: 250, rateWidth: 0.5, vAlign: 'center', hAlign: 'center', formatter: '@'},
  589. {name: '选项', dataCode: 'options', width: 250, rateWidth: 0.5, vAlign: 'center', hAlign: 'left', formatter: '@'},
  590. ],
  591. rowHeaderWidth:25,
  592. events: {
  593. CellClick: function (sender, args) {
  594. if(elfItem.headers[args.col]['dataCode'] === 'options' && args.sheetArea === 3){
  595. if(!args.sheet.getCell(args.row, args.col).locked() && !args.sheet.isEditing()){
  596. args.sheet.startEdit();
  597. }
  598. }
  599. },
  600. ClipboardPasting: function (sender, info) {
  601. info.cancel = true;
  602. }
  603. }
  604. };
  605. const options = {
  606. workBook: {
  607. tabStripVisible: false,
  608. allowContextMenu: false,
  609. allowCopyPasteExcelStyle : false,
  610. allowExtendPasteRange: false,
  611. allowUserDragDrop : false,
  612. allowUserDragFill: false,
  613. scrollbarMaxAlign : true
  614. },
  615. sheet: {
  616. protectionOptions: {allowResizeRows: true, allowResizeColumns: true},
  617. clipBoardOptions: GC.Spread.Sheets.ClipboardPasteOptions.values
  618. }
  619. };
  620. //渲染时方法,停止渲染
  621. //@param {Object}sheet {Function}func @return {void}
  622. function renderSheetFunc(sheet, func){
  623. sheet.suspendEvent();
  624. sheet.suspendPaint();
  625. if(func){
  626. func();
  627. }
  628. sheet.resumeEvent();
  629. sheet.resumePaint();
  630. }
  631. //设置表选项
  632. //@param {Object}workBook {Object}opts @return {void}
  633. function setOptions (workBook, opts) {
  634. for(let opt in opts.workBook){
  635. workBook.options[opt] = opts.workBook[opt];
  636. }
  637. for(let opt in opts.sheet){
  638. workBook.getActiveSheet().options[opt] = opts.sheet[opt];
  639. }
  640. }
  641. //建表头
  642. //@param {Object}sheet {Array}headers @return {void}
  643. function buildHeader(sheet, headers) {
  644. let fuc = function () {
  645. sheet.setColumnCount(headers.length);
  646. sheet.setRowHeight(0, 30, GC.Spread.Sheets.SheetArea.colHeader);
  647. //sheet.setColumnWidth(0, sheet.getParent() === bills.workBook ? 15 : 25, GC.Spread.Sheets.SheetArea.rowHeader);
  648. if(sheet.getParent() === elfItem.workBook || sheet.getParent() === guideItem.workBook){
  649. sheet.setRowHeight(0, 20, GC.Spread.Sheets.SheetArea.colHeader);
  650. }
  651. for(let i = 0, len = headers.length; i < len; i++){
  652. sheet.setValue(0, i, headers[i].name, GC.Spread.Sheets.SheetArea.colHeader);
  653. sheet.setColumnWidth(i, headers[i].width, GC.Spread.Sheets.SheetArea.colHeader);
  654. if(headers[i].formatter){
  655. sheet.setFormatter(-1, i, headers[i].formatter);
  656. }
  657. sheet.getRange(-1, i, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[headers[i]['hAlign']]);
  658. sheet.getRange(-1, i, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[headers[i]['vAlign']]);
  659. }
  660. };
  661. renderSheetFunc(sheet, fuc);
  662. }
  663. //表监听事件
  664. //@param {Object}workBook @return {void}
  665. function bindEvent(workBook, events) {
  666. if(Object.keys(events).length === 0){
  667. return;
  668. }
  669. const Events = GC.Spread.Sheets.Events;
  670. for(let event in events){
  671. workBook.bind(Events[event], events[event]);
  672. }
  673. }
  674. //根据宽度比例设置列宽
  675. //@param {Object}workBook {Number}workBookWidth {Array}headers @return {void}
  676. function setColumnWidthByRate(workBook, workBookWidth, headers) {
  677. if(workBook){
  678. workBookWidth -= 48;
  679. const sheet = workBook.getActiveSheet();
  680. sheet.suspendEvent();
  681. sheet.suspendPaint();
  682. for(let col = 0; col < headers.length; col++){
  683. if(headers[col]['rateWidth'] !== undefined && headers[col]['rateWidth'] !== null && headers[col]['rateWidth'] !== ''){
  684. let width = workBookWidth * headers[col]['rateWidth'];
  685. if(headers[col]['dataCode'] === 'options'){
  686. width = width;
  687. }
  688. sheet.setColumnWidth(col, width, GC.Spread.Sheets.SheetArea.colHeader)
  689. }
  690. else {
  691. if(headers[col]['headerWidth'] !== undefined && headers[col]['headerWidth'] !== null && headers[col]['headerWidth'] !== ''){
  692. sheet.setColumnWidth(col, headers[col]['headerWidth'], GC.Spread.Sheets.SheetArea.colHeader)
  693. }
  694. }
  695. }
  696. sheet.resumeEvent();
  697. sheet.resumePaint();
  698. }
  699. }
  700. //建表
  701. //@param {Object}module @return {void}
  702. function buildSheet(module) {
  703. if(!module.workBook){
  704. module.workBook = new GC.Spread.Sheets.Workbook(module.dom[0], {sheetCount: 1});
  705. sheetCommonObj.spreadDefaultStyle(module.workBook);
  706. let sheet = module.workBook.getActiveSheet();
  707. if(module === bills){
  708. //默认初始可控制焦点在清单表中
  709. sheet.options.rowHeaderVisible = false;
  710. module.workBook.focus();
  711. sheet.options.isProtected = true;
  712. sheet.name('stdBillsGuidance_bills');
  713. //设置悬浮提示
  714. TREE_SHEET_HELPER.initSetting(bills.dom[0], bills.treeSetting);
  715. }
  716. if(module === guideItem){
  717. sheet.options.isProtected = true;
  718. sheet.getRange(-1, 0, -1, 1).locked(false);
  719. sheet.getRange(-1, 1, -1, 1).locked(true);
  720. }
  721. if(module === elfItem){
  722. sheet.options.isProtected = true;
  723. sheet.getRange(-1, 0, -1, 1).locked(true);
  724. sheet.getRange(-1, 1, -1, 1).locked(false);
  725. }
  726. if(module.rowHeaderWidth) {
  727. sheet.setColumnWidth(0, module.rowHeaderWidth, GC.Spread.Sheets.SheetArea.rowHeader);
  728. }
  729. setOptions(module.workBook, options);
  730. buildHeader(module.workBook.getActiveSheet(), module.headers);
  731. if(module === elfItem){
  732. setColumnWidthByRate(elfItem.workBook, $('#zy').width(), elfItem.headers)
  733. }
  734. bindEvent(module.workBook, module.events);
  735. }
  736. }
  737. //清空表数据
  738. //@param {Object}sheet {Array}headers {Number}rowCount @return {void}
  739. function cleanData(sheet, headers, rowCount){
  740. renderSheetFunc(sheet, function () {
  741. sheet.clear(-1, 0, -1, headers.length, GC.Spread.Sheets.SheetArea.viewport, GC.Spread.Sheets.StorageType.data);
  742. if (rowCount > 0) {
  743. sheet.setRowCount(rowCount);
  744. }
  745. });
  746. }
  747. //初始化各工作表
  748. //@param {Array}modules @return {void}
  749. function initWorkBooks(modules){
  750. for(let module of modules){
  751. buildSheet(module);
  752. }
  753. }
  754. //点击清单名称后面的问号,弹出补注窗口并设置当前节点(或xxx父节点)的补注
  755. //@param {Number}row(当前焦点行) @return {void}
  756. function initRechargeModal(row) {
  757. let node = bills.tree.items[row];
  758. while (node && !node.data.recharge){
  759. node = node.parent;
  760. }
  761. let recharge = node && node.data.recharge ? node.data.recharge : '无内容';
  762. node = bills.tree.items[row];
  763. while (node && !node.data.ruleText){
  764. node = node.parent;
  765. }
  766. let ruleText = node && node.data.ruleText ? node.data.ruleText : '无内容';
  767. $('#questionTab1').text('补注');
  768. $('#questionContent1').html(recharge);
  769. $('#questionContent2').html(ruleText);
  770. $('#questionModal').modal('show');
  771. }
  772. //节点链上含有补注或工程量计算规则数据
  773. //@param {Number}row(行当前行) @return {Boolean}
  774. function hasRechargeRuleText(row) {
  775. let node = bills.tree.items[row];
  776. if (!node) {
  777. return false;
  778. }
  779. while (node) {
  780. if (node.data.recharge || node.data.ruleText) {
  781. return true;
  782. }
  783. node = node.parent;
  784. }
  785. return false;
  786. }
  787. //初始化并输出树
  788. //@param {Object}module {Object}sheet {Object}treeSetting {Array}datas
  789. function initTree(module, sheet, treeSetting, datas){
  790. module.tree = idTree.createNew({id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1, autoUpdate: true});
  791. module.controller = TREE_SHEET_CONTROLLER.createNew(module.tree, sheet, treeSetting, false);
  792. module.tree.loadDatas(datas);
  793. if(module === bills){
  794. initExpandStat();
  795. }
  796. module.controller.showTreeData();
  797. if(module === bills){
  798. module.workBook.getSheet(0).options.rowHeaderVisible = true;
  799. setBillsHint(bills.tree.items, stdBillsJobData, stdBillsFeatureData);
  800. renderSheetFunc(sheet, function () {
  801. for(let i = 0; i < bills.tree.items.length; i++){
  802. sheet.setCellType(i, 1, TREE_SHEET_HELPER.getQuestionCellType(initRechargeModal, hasRechargeRuleText));
  803. }
  804. });
  805. }
  806. }
  807. //项目指引表焦点控制
  808. //@param {Number}row @return {void}
  809. function guideItemInitSel(row){
  810. let billsNode = bills.tree.selected;
  811. let node = null;
  812. if(billsNode && billsNode.guidance.tree){
  813. node = billsNode.guidance.tree.items[row];
  814. if(node){
  815. billsNode.guidance.tree.selected = node;
  816. }
  817. }
  818. }
  819. //清单精灵表焦点控制
  820. //@param {Number}row @return {void}
  821. function elfItemInitSel(row){
  822. let billsNode = bills.tree.selected;
  823. let node = null;
  824. if(billsNode && billsNode.elf.tree){
  825. node = billsNode.elf.tree.items[row];
  826. if(node){
  827. billsNode.elf.tree.selected = node;
  828. }
  829. }
  830. }
  831. //根据项目指引的类型设置单元格类型,定额类型的项目指引为复选框
  832. //@param {Array}nodes @return {void}
  833. function setItemCellType(nodes){
  834. //设置单元格类型
  835. const base = new GC.Spread.Sheets.CellTypes.Base();
  836. const checkBox = new GC.Spread.Sheets.CellTypes.CheckBox();
  837. const sheet = guideItem.workBook.getActiveSheet();
  838. renderSheetFunc(sheet, function(){
  839. for(let node of nodes){
  840. sheet.setCellType(node.serialNo(), 0, node.data.type === itemType.ration ? checkBox : base);
  841. }
  842. });
  843. }
  844. //初始化清单的工作内容和项目特征
  845. //@param {Number}billsLibId {Function}callback @return {void}
  846. function initJobAndCharacter(billsLibId, callback){
  847. CommonAjax.post('/stdBillsEditor/getJobContent', {userId: userID, billsLibId: billsLibId}, function (datas) {
  848. stdBillsJobData = datas;
  849. CommonAjax.post('/stdBillsEditor/getItemCharacter', {userId: userID, billsLibId: billsLibId}, function (datas) {
  850. stdBillsFeatureData = datas;
  851. if(callback){
  852. callback();
  853. }
  854. });
  855. });
  856. }
  857. //初始化清单展开收起状态
  858. //@return {void}
  859. function initExpandStat(){
  860. //读取展开收起状态
  861. let currentExpState = sessionStorage.getItem('stdBillsGuidanceExpState');
  862. if(currentExpState){
  863. bills.tree.setExpandedByState(bills.tree.items, currentExpState);
  864. }
  865. //非叶子节点默认收起
  866. else{
  867. bills.tree.setRootExpanded(bills.tree.roots, false);
  868. }
  869. }
  870. //设置tag以悬浮提示
  871. function setTagForHint(nodes){
  872. let sheet = bills.workBook.getActiveSheet();
  873. renderSheetFunc(sheet, function () {
  874. for(let node of nodes){
  875. sheet.setTag(node.serialNo(), 2, node.data.ruleText ? node.data.ruleText : '');
  876. }
  877. });
  878. }
  879. //根据编码定位至清单精灵库中
  880. //@param {String}code @return {void}
  881. function locateAtBills(code) {
  882. let nineCode = code.substring(0, 9);
  883. let items = bills.tree.items;
  884. let locateBills = _.find(items, function(item){
  885. return item.data.code === nineCode;
  886. });
  887. if(locateBills){
  888. expandSearchNodes([locateBills]);
  889. sessionStorage.setItem('stdBillsGuidanceExpState', bills.tree.getExpState(bills.tree.items));
  890. }
  891. let sheet = bills.workBook.getActiveSheet();
  892. let locateRow = locateBills ? locateBills.serialNo() : 0;
  893. sheet.setActiveCell(locateRow, 0);
  894. sheet.showRow(locateRow, GC.Spread.Sheets.VerticalPosition.center);
  895. }
  896. //清单设置悬浮提示信息
  897. //@param {Array}billsNodes(清单节点) {Array}jobs(总的工作内容数据) {Array}items(总的项目特征数据)
  898. function setBillsHint(billsNodes, jobs, items) {
  899. let jobsMapping = {},
  900. itemsMapping = {};
  901. for(let job of jobs){
  902. jobsMapping[job.id] = job;
  903. }
  904. for(let item of items){
  905. itemsMapping[item.id] = item;
  906. }
  907. let tagInfo = [];
  908. for(let billsNode of billsNodes){
  909. let hintArr = [];
  910. let billsItems = billsNode.data.items;
  911. if(billsItems.length > 0){
  912. //项目特征
  913. hintArr.push('项目特征:');
  914. }
  915. let itemCount = 1,
  916. jobCount = 1;
  917. for(let billsItem of billsItems){
  918. let itemData = itemsMapping[billsItem.id];
  919. if(itemData){
  920. //特征值
  921. let eigens = [];
  922. for(let eigen of itemData.itemValue){
  923. eigens.push(eigen.value);
  924. }
  925. eigens = eigens.join(';');
  926. hintArr.push(`${itemCount}.${itemData.content}${eigens === '' ? '' : ': ' + eigens}`);
  927. itemCount ++;
  928. }
  929. }
  930. //工作内容
  931. let billsJobs = billsNode.data.jobs;
  932. if(billsJobs.length > 0){
  933. hintArr.push('工作内容:');
  934. }
  935. for(let billsJob of billsJobs){
  936. let jobData = jobsMapping[billsJob.id];
  937. if(jobData){
  938. hintArr.push(`${jobCount}.${jobData.content}`);
  939. jobCount ++;
  940. }
  941. }
  942. /*if(billsNode.data.ruleText && billsNode.data.ruleText !== ''){
  943. hintArr.push('工程量计算规则:');
  944. hintArr.push(billsNode.data.ruleText);
  945. }
  946. if(billsNode.data.recharge && billsNode.data.recharge !== ''){
  947. hintArr.push('补注:');
  948. hintArr.push(billsNode.data.recharge);
  949. }*/
  950. if(hintArr.length > 0){
  951. tagInfo.push({row: billsNode.serialNo(), value: hintArr.join('\n')});
  952. }
  953. }
  954. let sheet = bills.workBook.getActiveSheet();
  955. renderSheetFunc(sheet, function () {
  956. for(let tagI of tagInfo){
  957. sheet.setTag(tagI.row, 0, tagI.value);
  958. }
  959. });
  960. }
  961. //初始选择标准清单
  962. //@param {Number}libID @return {void}
  963. function libInitSel(libID){
  964. //获取清单
  965. $.bootstrapLoading.start();
  966. CommonAjax.post('/billsGuidance/api/getLibWithBills', {libID: libID}, function(rstData){
  967. if(guideItem.workBook){
  968. guideItem.workBook.destroy();
  969. guideItem.workBook = null;
  970. }
  971. if(elfItem.workBook){
  972. elfItem.workBook.destroy();
  973. elfItem.workBook = null;
  974. }
  975. initViews();
  976. let callback = function () {
  977. initTree(bills, bills.workBook.getActiveSheet(), bills.treeSetting, rstData.bills);
  978. if(doAfterLoadGuidance){
  979. doAfterLoadGuidance();
  980. }
  981. $.bootstrapLoading.end();
  982. };
  983. //获取清单库中的工作内容和项目特征
  984. initJobAndCharacter(libID, callback);
  985. }, function () {
  986. $.bootstrapLoading.end();
  987. });
  988. }
  989. //初始化清单指引库
  990. //@param {Array}libDats @return {void}
  991. function initLibs(libDatas){
  992. libSel.empty();
  993. if(!libDatas){
  994. return;
  995. }
  996. let selectedLib = sessionStorage.getItem('stdBillsGuidance');
  997. for(let libData of libDatas){
  998. let opt = $('<option>').val(libData.id).text(libData.name);
  999. if(selectedLib && libData.id == selectedLib){
  1000. opt.attr('selected', 'selected');
  1001. }
  1002. libSel.append(opt);
  1003. }
  1004. //初始默认选择
  1005. libInitSel(libSel.select().val());
  1006. }
  1007. //初始化视图
  1008. //@param {void} @return {void}
  1009. function initViews(){
  1010. //赋初始高度
  1011. if($('#billsGuidance_bills').height() === 0 || $('#billsGuidance_items').height() === 0){
  1012. let height = $(window).height()-$(".header").height()-$(".toolsbar").height()-$(".tools-bar-height-z").height();
  1013. $('#billsGuidance_bills').height(height / 2);
  1014. $('#billsGuidance_items').height(height / 2);
  1015. }
  1016. let modules = [bills];
  1017. modules.push(elfItem);
  1018. initWorkBooks(modules);
  1019. }
  1020. //展开至搜索出来点的节点
  1021. //@param {Array}nodes @return {void}
  1022. function expandSearchNodes(nodes){
  1023. let that = this;
  1024. let billsSheet = bills.workBook.getActiveSheet();
  1025. renderSheetFunc(billsSheet, function () {
  1026. function expParentNode(node){
  1027. if(node.parent){
  1028. if (!node.parent.expanded) {
  1029. node.parent.setExpanded(true);
  1030. }
  1031. expParentNode(node.parent);
  1032. }
  1033. }
  1034. for(let node of nodes){
  1035. expParentNode(node);
  1036. }
  1037. TREE_SHEET_HELPER.refreshTreeNodeData(bills.treeSetting, billsSheet, bills.tree.roots, true);
  1038. TREE_SHEET_HELPER.refreshNodesVisible(bills.tree.roots, billsSheet, true);
  1039. });
  1040. }
  1041. //各按钮监听事件
  1042. //@return {void}
  1043. function bindBtn(){
  1044. //打开清单指引库
  1045. $('#stdBillsGuidanceTab').click(function () {
  1046. if(libSel.children().length === 0 && !$(this).hasClass('disabled')){
  1047. initLibs(projectObj.project.projectInfo.engineeringInfo.bill_lib);
  1048. }
  1049. });
  1050. //更改清单指引库
  1051. $('#stdBillsGuidanceLibSelect').change(function () {
  1052. //关闭搜索窗口
  1053. $('#billsGuidanceSearchResult').hide();
  1054. billsLibObj.clearHighLight(bills.workBook);
  1055. libInitSel($(this).select().val());
  1056. //记住选项
  1057. sessionStorage.setItem('stdBillsGuidance', $(this).select().val());
  1058. //清除展开收起状态sessionStorage
  1059. sessionStorage.removeItem('stdBillsGuidanceExpState');
  1060. });
  1061. //搜索
  1062. $('#stdBillsGuidanceSearch>div>button').click(function () {
  1063. if(!bills.tree){
  1064. return;
  1065. }
  1066. let billsSheet = bills.workBook.getActiveSheet();
  1067. billsLibObj.clearHighLight(bills.workBook);
  1068. let keyword = $('#stdBillsGuidanceSearch>input').val();
  1069. if (!keyword || keyword === '') {
  1070. $('#billsGuidanceSearchResult').hide();
  1071. return;
  1072. }
  1073. let result = bills.tree.items.filter(function (item) {
  1074. let codeIs = item.data.code ? item.data.code.indexOf(keyword) !== -1 : false;
  1075. let nameIs = item.data.name ? item.data.name.indexOf(keyword) !== -1 : false;
  1076. return codeIs || nameIs;
  1077. });
  1078. result.sort(function (x, y) {
  1079. return x.serialNo() - y.serialNo();
  1080. });
  1081. if (result.length !== 0) {
  1082. //展开搜索出来的节点
  1083. expandSearchNodes(result);
  1084. //设置记住展开
  1085. sessionStorage.setItem('stdBillsGuidanceExpState', bills.tree.getExpState(bills.tree.items));
  1086. let sel = billsSheet.getSelections();
  1087. renderSheetFunc(billsSheet, function () {
  1088. bills.controller.setTreeSelected(result[0]);
  1089. billsSheet.setSelection(result[0].serialNo(), sel[0].col, 1, 1);
  1090. for (let node of result) {
  1091. billsSheet.getRange(node.serialNo(), -1, 1, -1).backColor('lemonChiffon');
  1092. }
  1093. });
  1094. //搜索初始定位
  1095. billsSheet.showRow(result[0].serialNo(), GC.Spread.Sheets.VerticalPosition.center);
  1096. //查找下一条
  1097. $('#nextBillsGuidance').show();
  1098. $('#nextBillsGuidance').unbind('click');
  1099. $('#nextBillsGuidance').bind('click', function () {
  1100. let cur = bills.tree.selected, resultIndex = result.indexOf(cur), sel = billsSheet.getSelections();
  1101. if (resultIndex === result.length - 1) {
  1102. bills.controller.setTreeSelected(result[0]);
  1103. billsSheet.setSelection(result[0].serialNo(), sel[0].col, 1, 1);
  1104. billsSheet.showRow(result[0].serialNo(), GC.Spread.Sheets.VerticalPosition.center);
  1105. } else {
  1106. bills.controller.setTreeSelected(result[resultIndex + 1]);
  1107. billsSheet.setSelection(result[resultIndex + 1].serialNo(), sel[0].col, 1, 1);
  1108. billsSheet.showRow(result[resultIndex + 1].serialNo(), GC.Spread.Sheets.VerticalPosition.center);
  1109. }
  1110. });
  1111. //查找上一条
  1112. $('#preBillsGuidance').show();
  1113. $('#preBillsGuidance').unbind('click');
  1114. $('#preBillsGuidance').bind('click', function () {
  1115. let cur = bills.tree.selected, resultIndex = result.indexOf(cur), sel = billsSheet.getSelections();
  1116. if (resultIndex === 0) {
  1117. bills.controller.setTreeSelected(result[result.length - 1]);
  1118. billsSheet.setSelection(result[result.length - 1].serialNo(), sel[0].col, 1, 1);
  1119. billsSheet.showRow(result[result.length - 1].serialNo(), GC.Spread.Sheets.VerticalPosition.center);
  1120. } else {
  1121. bills.controller.setTreeSelected(result[resultIndex - 1]);
  1122. billsSheet.setSelection(result[resultIndex - 1].serialNo(), sel[0].col, 1, 1);
  1123. billsSheet.showRow(result[resultIndex - 1].serialNo(), GC.Spread.Sheets.VerticalPosition.center);
  1124. }
  1125. });
  1126. } else {
  1127. billsLibObj.clearHighLight(bills.workBook);
  1128. $('#nextBillsGuidance').hide();
  1129. $('#preBillsGuidance').hide();
  1130. }
  1131. $('#billsGuidanceSearchResultCount').text('搜索结果:' + result.length);
  1132. $('#billsGuidanceSearchResult').show();
  1133. autoFlashHeight();
  1134. refreshWorkBook();
  1135. });
  1136. //搜索框回车
  1137. $('#stdBillsGuidanceSearch>input').bind('keypress', function (event) {
  1138. if(event.keyCode === 13){
  1139. $(this).blur();
  1140. $('#stdBillsGuidanceSearch>div>button').click();
  1141. }
  1142. });
  1143. // 关闭搜索结果
  1144. $('#closeSearchBillsGuidance').click(function () {
  1145. $('#billsGuidanceSearchResult').hide();
  1146. billsLibObj.clearHighLight(bills.workBook);
  1147. autoFlashHeight();
  1148. refreshWorkBook();
  1149. });
  1150. }
  1151. //刷新表
  1152. //@return {void}
  1153. function refreshWorkBook(){
  1154. if(bills.workBook){
  1155. bills.workBook.refresh();
  1156. }
  1157. if(guideItem.workBook){
  1158. guideItem.workBook.refresh();
  1159. }
  1160. if(elfItem.workBook){
  1161. elfItem.workBook.refresh();
  1162. }
  1163. }
  1164. return {initViews, bindBtn, refreshWorkBook, setColumnWidthByRate, locateAtBills, bills, elfItem, overwrite};
  1165. })();
  1166. $(document).ready(function(){
  1167. billsGuidance.bindBtn();
  1168. });