index.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883
  1. function setAlign(sheet, headers) {
  2. const fuc = () => {
  3. headers.forEach(({ hAlign, vAlign }, index) => {
  4. sheetCommonObj.setAreaAlign(sheet.getRange(-1, index, -1, 1), hAlign, vAlign)
  5. });
  6. };
  7. sheetCommonObj.renderSheetFunc(sheet, fuc);
  8. }
  9. function setFormatter(sheet, headers) {
  10. const fuc = () => {
  11. headers.forEach(({ formatter }, index) => {
  12. if (formatter) {
  13. sheet.setFormatter(-1, index, formatter);
  14. }
  15. });
  16. };
  17. sheetCommonObj.renderSheetFunc(sheet, fuc);
  18. }
  19. function initSheet(dom, setting) {
  20. const workBook = sheetCommonObj.buildSheet(dom, setting);
  21. const sheet = workBook.getSheet(0);
  22. setAlign(sheet, setting.header);
  23. setFormatter(sheet, setting.header);
  24. return workBook;
  25. }
  26. function showData(sheet, data, headers, emptyRows) {
  27. const fuc = () => {
  28. sheet.setRowCount(data.length);
  29. data.forEach((item, row) => {
  30. headers.forEach(({ dataCode }, col) => {
  31. sheet.setValue(row, col, item[dataCode] || '');
  32. });
  33. });
  34. if (emptyRows) {
  35. sheet.addRows(data.length, emptyRows);
  36. }
  37. };
  38. sheetCommonObj.renderSheetFunc(sheet, fuc);
  39. }
  40. const TIME_OUT = 10000;
  41. const libID = window.location.search.match(/libID=([^&]+)/)[1];
  42. const UpdateType = {
  43. UPDATE: 'update',
  44. DELETE: 'delete',
  45. CREATE: 'create',
  46. };
  47. const DEBOUNCE_TIME = 200;
  48. const locked = lockUtil.getLocked();
  49. // 地区表
  50. const AREA_BOOK = (() => {
  51. const cache = areaList;
  52. const setting = {
  53. header: [{ headerName: '地区', headerWidth: $('#area-spread').width(), dataCode: 'name', dataType: 'String', hAlign: 'center', vAlign: 'center' }]
  54. };
  55. // 初始化表格
  56. const workBook = initSheet($('#area-spread')[0], setting);
  57. lockUtil.lockSpreads([workBook], locked);
  58. workBook.options.allowExtendPasteRange = false;
  59. workBook.options.allowUserDragDrop = true;
  60. workBook.options.allowUserDragFill = true;
  61. const sheet = workBook.getSheet(0);
  62. // 排序显示
  63. cache.sort((a, b) => a.serialNo - b.serialNo);
  64. // 显示数据
  65. showData(sheet, cache, setting.header);
  66. // 编辑处理
  67. async function handleEdit(changedCells) {
  68. const updateData = [];
  69. changedCells.forEach(({ row, col }) => {
  70. updateData.push({
  71. row,
  72. ID: cache[row].ID,
  73. name: sheet.getValue(row, col)
  74. });
  75. });
  76. try {
  77. await ajaxPost('/priceInfo/editArea', { updateData }, TIME_OUT);
  78. updateData.forEach(({ row, name }) => cache[row].name = name);
  79. } catch (err) {
  80. // 恢复各单元格数据
  81. sheetCommonObj.renderSheetFunc(sheet, () => {
  82. changedCells.forEach(({ row }) => {
  83. sheet.setValue(cache[row].name);
  84. });
  85. });
  86. }
  87. }
  88. sheet.bind(GC.Spread.Sheets.Events.ValueChanged, function (e, info) {
  89. const changedCells = [{ row: info.row, col: info.col }];
  90. handleEdit(changedCells);
  91. });
  92. sheet.bind(GC.Spread.Sheets.Events.RangeChanged, function (e, info) {
  93. handleEdit(info.changedCells);
  94. });
  95. const curArea = { ID: null };
  96. // 焦点变更处理
  97. const debounceSelectionChanged = _.debounce(function (e, info) {
  98. const row = info.newSelections && info.newSelections[0] ? info.newSelections[0].row : 0;
  99. handleSelectionChanged(row);
  100. }, DEBOUNCE_TIME, { leading: true }); // leading = true : 先触发再延迟
  101. function handleSelectionChanged(row) {
  102. const areaItem = cache[row];
  103. curArea.ID = areaItem && areaItem.ID || null;
  104. CLASS_BOOK.initData(libID, curArea.ID);
  105. }
  106. sheet.bind(GC.Spread.Sheets.Events.SelectionChanged, debounceSelectionChanged);
  107. // 新增
  108. async function insert() {
  109. const data = {
  110. compilationID,
  111. ID: uuid.v1(),
  112. name: '',
  113. };
  114. try {
  115. $.bootstrapLoading.start();
  116. await ajaxPost('/priceInfo/insertArea', { insertData: [data] });
  117. // 新增的数据总是添加在最后
  118. sheet.addRows(cache.length, 1);
  119. cache.push(data);
  120. const lastRow = cache.length - 1;
  121. sheet.setSelection(lastRow, 0, 1, 1);
  122. sheet.showRow(lastRow, GC.Spread.Sheets.VerticalPosition.top);
  123. handleSelectionChanged(lastRow);
  124. } catch (err) {
  125. alert(err);
  126. } finally {
  127. $.bootstrapLoading.end();
  128. }
  129. }
  130. // 删除
  131. async function del() {
  132. try {
  133. $.bootstrapLoading.start();
  134. await ajaxPost('/priceInfo/deleteArea', { deleteData: [curArea.ID] });
  135. const index = cache.findIndex(item => item.ID === curArea.ID);
  136. sheet.deleteRows(index, 1);
  137. cache.splice(index, 1);
  138. const row = sheet.getActiveRowIndex();
  139. handleSelectionChanged(row);
  140. } catch (err) {
  141. alert(err);
  142. } finally {
  143. $.bootstrapLoading.end();
  144. }
  145. }
  146. // 右键功能
  147. function buildContextMenu() {
  148. $.contextMenu({
  149. selector: '#area-spread',
  150. build: function ($triggerElement, e) {
  151. // 控制允许右键菜单在哪个位置出现
  152. const offset = $('#area-spread').offset();
  153. const x = e.pageX - offset.left;
  154. const y = e.pageY - offset.top;
  155. const target = sheet.hitTest(x, y);
  156. if (target.hitTestType === 3) { // 在表格内
  157. const sel = sheet.getSelections()[0];
  158. if (sel && sel.rowCount === 1 && typeof target.row !== 'undefined') {
  159. const orgRow = sheet.getActiveRowIndex();
  160. if (orgRow !== target.row) {
  161. sheet.setActiveCell(target.row, target.col);
  162. handleSelectionChanged(target.row);
  163. }
  164. }
  165. return {
  166. items: {
  167. insert: {
  168. name: '新增',
  169. icon: "fa-arrow-left",
  170. disabled: function () {
  171. return locked;
  172. },
  173. callback: function (key, opt) {
  174. insert();
  175. }
  176. },
  177. del: {
  178. name: '删除',
  179. icon: "fa-arrow-left",
  180. disabled: function () {
  181. return locked || !cache[target.row];
  182. },
  183. callback: function (key, opt) {
  184. del();
  185. }
  186. },
  187. }
  188. };
  189. }
  190. else {
  191. return false;
  192. }
  193. }
  194. });
  195. }
  196. buildContextMenu();
  197. return {
  198. handleSelectionChanged,
  199. curArea,
  200. }
  201. })();
  202. // 分类表
  203. const CLASS_BOOK = (() => {
  204. const setting = {
  205. header: [{ headerName: '分类', headerWidth: $('#area-spread').width(), dataCode: 'name', dataType: 'String', hAlign: 'left', vAlign: 'center' }],
  206. controller: {
  207. cols: [
  208. {
  209. data: {
  210. field: 'name',
  211. vAlign: 1,
  212. hAlign: 0,
  213. font: 'Arial'
  214. },
  215. }
  216. ],
  217. headRows: 1,
  218. headRowHeight: [30],
  219. emptyRows: 0,
  220. treeCol: 0
  221. },
  222. tree: {
  223. id: 'ID',
  224. pid: 'ParentID',
  225. nid: 'NextSiblingID',
  226. rootId: -1
  227. }
  228. };
  229. // 初始化表格
  230. const workBook = initSheet($('#class-spread')[0], setting);
  231. workBook.options.allowExtendPasteRange = false;
  232. workBook.options.allowUserDragDrop = true;
  233. workBook.options.allowUserDragFill = true;
  234. const sheet = workBook.getSheet(0);
  235. let tree;
  236. let controller;
  237. // 初始化数据
  238. async function initData(libID, areaID) {
  239. if (!areaID) {
  240. tree = null;
  241. controller = null;
  242. sheet.setRowCount(0);
  243. PRICE_BOOK.clear();
  244. return;
  245. }
  246. $.bootstrapLoading.start();
  247. try {
  248. const data = await ajaxPost('/priceInfo/getClassData', { libID, areaID }, TIME_OUT);
  249. tree = idTree.createNew(setting.tree);
  250. tree.loadDatas(data);
  251. tree.selected = tree.items.length > 0 ? tree.items[0] : null;
  252. controller = TREE_SHEET_CONTROLLER.createNew(tree, sheet, setting.controller, false);
  253. controller.showTreeData();
  254. handleSelectionChanged(0);
  255. sheet.setSelection(0, 0, 1, 1);
  256. lockUtil.lockSpreads([workBook], locked);
  257. } catch (err) {
  258. console.log(err);
  259. tree = null;
  260. controller = null;
  261. sheet.setRowCount(0);
  262. alert(err);
  263. } finally {
  264. $.bootstrapLoading.end();
  265. }
  266. }
  267. // 编辑处理
  268. async function handleEdit(changedCells) {
  269. const updateData = [];
  270. changedCells.forEach(({ row, col }) => {
  271. updateData.push({
  272. row,
  273. type: UpdateType.UPDATE,
  274. filter: { ID: tree.items[row].data.ID },
  275. update: { name: sheet.getValue(row, col) }
  276. });
  277. });
  278. try {
  279. await ajaxPost('/priceInfo/editClassData', { updateData }, TIME_OUT);
  280. updateData.forEach(({ row, update: { name } }) => tree.items[row].data.name = name);
  281. } catch (err) {
  282. // 恢复各单元格数据
  283. sheetCommonObj.renderSheetFunc(sheet, () => {
  284. changedCells.forEach(({ row }) => {
  285. sheet.setValue(tree.items[row].data.name);
  286. });
  287. });
  288. }
  289. }
  290. sheet.bind(GC.Spread.Sheets.Events.ValueChanged, function (e, info) {
  291. const changedCells = [{ row: info.row, col: info.col }];
  292. handleEdit(changedCells);
  293. });
  294. sheet.bind(GC.Spread.Sheets.Events.RangeChanged, function (e, info) {
  295. handleEdit(info.changedCells);
  296. });
  297. // 树操作相关
  298. const $insert = $('#tree-insert');
  299. const $remove = $('#tree-remove');
  300. const $upLevel = $('#tree-up-level');
  301. const $downLevel = $('#tree-down-level');
  302. const $downMove = $('#tree-down-move');
  303. const $upMove = $('#tree-up-move');
  304. const $calcPriceIndex = $('#calc-price-index');
  305. // 插入
  306. let canInsert = true;
  307. async function insert() {
  308. try {
  309. if (!canInsert) {
  310. return false;
  311. }
  312. canInsert = false;
  313. $.bootstrapLoading.start();
  314. const updateData = [];
  315. const selected = tree.selected;
  316. const newItem = {
  317. libID,
  318. areaID: AREA_BOOK.curArea.ID,
  319. ID: uuid.v1(),
  320. name: '',
  321. ParentID: '-1',
  322. NextSiblingID: '-1'
  323. };
  324. if (selected) {
  325. newItem.ParentID = selected.data.ParentID;
  326. updateData.push({
  327. type: UpdateType.UPDATE,
  328. filter: { ID: selected.data.ID },
  329. update: { NextSiblingID: newItem.ID }
  330. });
  331. if (selected.nextSibling) {
  332. newItem.NextSiblingID = selected.nextSibling.data.ID;
  333. }
  334. }
  335. updateData.push({
  336. type: UpdateType.CREATE,
  337. document: newItem
  338. });
  339. await ajaxPost('/priceInfo/editClassData', { updateData });
  340. controller.insertByID(newItem.ID);
  341. handleSelectionChanged(sheet.getActiveRowIndex());
  342. } catch (err) {
  343. console.log(err);
  344. alert(err);
  345. } finally {
  346. canInsert = true;
  347. $.bootstrapLoading.end();
  348. }
  349. }
  350. $insert.click(_.debounce(insert, DEBOUNCE_TIME, { leading: true }));
  351. // 删除
  352. let canRemove = true;
  353. async function remove() {
  354. try {
  355. if (!canRemove) {
  356. return false;
  357. }
  358. canRemove = false;
  359. $.bootstrapLoading.start();
  360. const updateData = [];
  361. const selected = tree.selected;
  362. const children = selected.getPosterity();
  363. [selected, ...children].forEach(node => updateData.push({
  364. type: UpdateType.DELETE,
  365. filter: { ID: node.data.ID }
  366. }));
  367. if (selected.preSibling) {
  368. updateData.push({
  369. type: UpdateType.UPDATE,
  370. filter: { ID: selected.preSibling.data.ID },
  371. update: { NextSiblingID: selected.data.NextSiblingID }
  372. });
  373. }
  374. await ajaxPost('/priceInfo/editClassData', { updateData });
  375. controller.delete();
  376. handleSelectionChanged(sheet.getActiveRowIndex());
  377. } catch (err) {
  378. alert(err);
  379. } finally {
  380. canRemove = true;
  381. $.bootstrapLoading.end();
  382. }
  383. }
  384. $remove.click(_.debounce(remove, DEBOUNCE_TIME, { leading: true }));
  385. // 升级
  386. let canUpLevel = true;
  387. async function upLevel() {
  388. try {
  389. if (!canUpLevel) {
  390. return false;
  391. }
  392. canUpLevel = false;
  393. $.bootstrapLoading.start();
  394. const updateData = [];
  395. const selected = tree.selected;
  396. if (selected.preSibling) {
  397. updateData.push({
  398. type: UpdateType.UPDATE,
  399. filter: { ID: selected.preSibling.data.ID },
  400. update: { NextSiblingID: -1 }
  401. });
  402. }
  403. if (selected.parent) {
  404. updateData.push({
  405. type: UpdateType.UPDATE,
  406. filter: { ID: selected.parent.data.ID },
  407. update: { NextSiblingID: selected.data.ID }
  408. });
  409. }
  410. updateData.push({
  411. type: UpdateType.UPDATE,
  412. filter: { ID: selected.data.ID },
  413. update: { ParentID: selected.parent.data.ParentID, NextSiblingID: selected.parent.data.NextSiblingID }
  414. });
  415. let curNode = selected.nextSibling;
  416. while (curNode) {
  417. updateData.push({
  418. type: UpdateType.UPDATE,
  419. filter: { ID: curNode.data.ID },
  420. update: { ParentID: selected.data.ID }
  421. });
  422. curNode = curNode.nextSibling;
  423. }
  424. await ajaxPost('/priceInfo/editClassData', { updateData });
  425. controller.upLevel();
  426. refreshTreeButton(tree.selected);
  427. } catch (err) {
  428. alert(err);
  429. } finally {
  430. canUpLevel = true;
  431. $.bootstrapLoading.end();
  432. }
  433. }
  434. $upLevel.click(_.debounce(upLevel, DEBOUNCE_TIME, { leading: true }));
  435. // 降级
  436. let canDownLevel = true;
  437. async function downLevel() {
  438. try {
  439. if (!canDownLevel) {
  440. return false;
  441. }
  442. canDownLevel = false;
  443. $.bootstrapLoading.start();
  444. const updateData = [];
  445. const selected = tree.selected;
  446. if (selected.preSibling) {
  447. updateData.push({
  448. type: UpdateType.UPDATE,
  449. filter: { ID: selected.preSibling.data.ID },
  450. update: { NextSiblingID: selected.data.NextSiblingID }
  451. });
  452. const preSiblingLastChild = selected.preSibling.children[selected.preSibling.children.length - 1];
  453. if (preSiblingLastChild) {
  454. updateData.push({
  455. type: UpdateType.UPDATE,
  456. filter: { ID: preSiblingLastChild.data.ID },
  457. update: { NextSiblingID: selected.data.ID }
  458. });
  459. }
  460. updateData.push({
  461. type: UpdateType.UPDATE,
  462. filter: { ID: selected.data.ID },
  463. update: { ParentID: selected.preSibling.data.ID, NextSiblingID: -1 }
  464. });
  465. }
  466. await ajaxPost('/priceInfo/editClassData', { updateData });
  467. controller.downLevel();
  468. refreshTreeButton(tree.selected);
  469. } catch (err) {
  470. alert(err);
  471. } finally {
  472. canDownLevel = true;
  473. $.bootstrapLoading.end();
  474. }
  475. }
  476. $downLevel.click(_.debounce(downLevel, DEBOUNCE_TIME, { leading: true }));
  477. // 下移
  478. let canDownMove = true;
  479. async function downMove() {
  480. try {
  481. if (!canDownMove) {
  482. return false;
  483. }
  484. canDownMove = false;
  485. $.bootstrapLoading.start();
  486. const updateData = [];
  487. const selected = tree.selected;
  488. if (selected.preSibling) {
  489. updateData.push({
  490. type: UpdateType.UPDATE,
  491. filter: { ID: selected.preSibling.data.ID },
  492. update: { NextSiblingID: selected.data.NextSiblingID }
  493. });
  494. }
  495. updateData.push({
  496. type: UpdateType.UPDATE,
  497. filter: { ID: selected.data.ID },
  498. update: { NextSiblingID: selected.nextSibling.data.NextSiblingID }
  499. });
  500. updateData.push({
  501. type: UpdateType.UPDATE,
  502. filter: { ID: selected.nextSibling.data.ID },
  503. update: { NextSiblingID: selected.data.ID }
  504. });
  505. await ajaxPost('/priceInfo/editClassData', { updateData });
  506. controller.downMove();
  507. refreshTreeButton(tree.selected);
  508. } catch (err) {
  509. alert(err);
  510. } finally {
  511. canDownMove = true;
  512. $.bootstrapLoading.end();
  513. }
  514. }
  515. $downMove.click(_.debounce(downMove, DEBOUNCE_TIME, { leading: true }));
  516. // 上移
  517. let canUpMove = true;
  518. async function upMove() {
  519. try {
  520. if (!canUpMove) {
  521. return false;
  522. }
  523. canUpMove = false;
  524. $.bootstrapLoading.start();
  525. const updateData = [];
  526. const selected = tree.selected;
  527. if (selected.preSibling) {
  528. updateData.push({
  529. type: UpdateType.UPDATE,
  530. filter: { ID: selected.preSibling.data.ID },
  531. update: { NextSiblingID: selected.data.NextSiblingID }
  532. });
  533. }
  534. const prePreSibling = selected.preSibling.preSibling;
  535. if (prePreSibling) {
  536. updateData.push({
  537. type: UpdateType.UPDATE,
  538. filter: { ID: prePreSibling.data.ID },
  539. update: { NextSiblingID: selected.data.ID }
  540. });
  541. }
  542. updateData.push({
  543. type: UpdateType.UPDATE,
  544. filter: { ID: selected.data.ID },
  545. update: { NextSiblingID: selected.preSibling.data.ID }
  546. });
  547. await ajaxPost('/priceInfo/editClassData', { updateData });
  548. controller.upMove();
  549. refreshTreeButton(tree.selected);
  550. } catch (err) {
  551. alert(err);
  552. } finally {
  553. canUpMove = true;
  554. $.bootstrapLoading.end();
  555. }
  556. }
  557. $upMove.click(_.debounce(upMove, DEBOUNCE_TIME, { leading: true }));
  558. // 刷新树操作按钮有效性
  559. function refreshTreeButton(selected) {
  560. if (locked) {
  561. return;
  562. }
  563. $insert.removeClass('disabled');
  564. $remove.removeClass('disabled');
  565. $upLevel.removeClass('disabled');
  566. $downLevel.removeClass('disabled');
  567. $downMove.removeClass('disabled');
  568. $upMove.removeClass('disabled');
  569. if (!selected) {
  570. $remove.addClass('disabled');
  571. $upLevel.addClass('disabled');
  572. $downLevel.addClass('disabled');
  573. $downMove.addClass('disabled');
  574. $upMove.addClass('disabled');
  575. } else {
  576. if (!selected.preSibling) {
  577. $downLevel.addClass('disabled');
  578. $upMove.addClass('disabled');
  579. }
  580. if (!selected.nextSibling) {
  581. $downMove.addClass('disabled');
  582. }
  583. if (!selected.parent) {
  584. $upLevel.addClass('disabled');
  585. }
  586. }
  587. }
  588. // 焦点变更处理
  589. const curClass = { ID: null };
  590. function handleSelectionChanged(row) {
  591. const classNode = tree.items[row] || null;
  592. tree.selected = classNode;
  593. refreshTreeButton(classNode);
  594. curClass.ID = classNode && classNode.data && classNode.data.ID || null;
  595. const classIDList = []
  596. if (classNode) {
  597. classIDList.push(classNode.data.ID);
  598. const children = classNode.getPosterity();
  599. children.forEach(child => classIDList.push(child.data.ID));
  600. }
  601. PRICE_BOOK.initData(classIDList);
  602. }
  603. const debounceSelectionChanged = _.debounce(function (e, info) {
  604. const row = info.newSelections && info.newSelections[0] ? info.newSelections[0].row : 0;
  605. handleSelectionChanged(row);
  606. }, DEBOUNCE_TIME, { leading: true });
  607. sheet.bind(GC.Spread.Sheets.Events.SelectionChanged, debounceSelectionChanged);
  608. $calcPriceIndex.click(_.debounce(async()=>{
  609. $.bootstrapLoading.start();
  610. try {
  611. const data = await ajaxPost('/priceInfo/calcPriceIndex', { libID, period:curLibPeriod,compilationID }, TIME_OUT);
  612. //alert(data);
  613. if(data){
  614. const htmlStr = data.replace(/\n/gm,'<br>'); //replaceAll('\n','<br>',data);
  615. $("#result-info-body").html(htmlStr);
  616. $("#result-info").modal('show');
  617. }else{
  618. alert('计算完成!')
  619. }
  620. } catch (error) {
  621. console.log(error);
  622. }
  623. $.bootstrapLoading.end();
  624. }, DEBOUNCE_TIME, { leading: true }));
  625. return {
  626. initData,
  627. handleSelectionChanged,
  628. curClass,
  629. }
  630. })();
  631. // 关键字表
  632. const KEYWORD_BOOK = (() => {
  633. const setting = {
  634. header: [
  635. { headerName: '关键字', headerWidth: 200, dataCode: 'keyword', dataType: 'String', hAlign: 'left', vAlign: 'center' },
  636. { headerName: '单位', headerWidth: 70, dataCode: 'unit', dataType: 'String', hAlign: 'center', vAlign: 'center' },
  637. { headerName: '关键字效果', headerWidth: 100, dataCode: 'coe', dataType: 'String', hAlign: 'center', vAlign: 'center' },
  638. { headerName: '组别', headerWidth: 50, dataCode: 'group', dataType: 'String', hAlign: 'center', vAlign: 'center' },
  639. { headerName: '选项号', headerWidth: 70, dataCode: 'optionCode', dataType: 'String', hAlign: 'center', vAlign: 'center' },
  640. ],
  641. };
  642. // 初始化表格
  643. const workBook = initSheet($('#keyword-spread')[0], setting);
  644. workBook.options.allowUserDragDrop = false;
  645. workBook.options.allowUserDragFill = false;
  646. lockUtil.lockSpreads([workBook], true);
  647. const sheet = workBook.getSheet(0);
  648. // 显示关键字数据
  649. const showKeywordData = (keywordList) => {
  650. showData(sheet, keywordList, setting.header);
  651. }
  652. return {
  653. showKeywordData
  654. }
  655. })();
  656. // 价格信息表
  657. const PRICE_BOOK = (() => {
  658. const setting = {
  659. header: [
  660. { headerName: '编码', headerWidth: 100, dataCode: 'code', dataType: 'String', hAlign: 'left', vAlign: 'center' ,formatter: "@"},
  661. { headerName: '别名编码', headerWidth: 70, dataCode: 'classCode', dataType: 'String', hAlign: 'left', vAlign: 'center' ,formatter: "@"},
  662. { headerName: '名称', headerWidth: 200, dataCode: 'name', dataType: 'String', hAlign: 'left', vAlign: 'center' },
  663. { headerName: '规格型号', headerWidth: 120, dataCode: 'specs', dataType: 'String', hAlign: 'left', vAlign: 'center' },
  664. { headerName: '单位', headerWidth: 80, dataCode: 'unit', dataType: 'String', hAlign: 'center', vAlign: 'center' },
  665. { headerName: '不含税价', headerWidth: 80, dataCode: 'noTaxPrice', dataType: 'String', hAlign: 'right', vAlign: 'center' },
  666. { headerName: '含税价', headerWidth: 80, dataCode: 'taxPrice', dataType: 'String', hAlign: 'right', vAlign: 'center' },
  667. { headerName: '月份备注', headerWidth: 140, dataCode: 'dateRemark', dataType: 'String', hAlign: 'left', vAlign: 'center' },
  668. { headerName: '计算式', headerWidth: 100, dataCode: 'expString', dataType: 'String', hAlign: 'left', vAlign: 'center' },
  669. ],
  670. };
  671. // 初始化表格
  672. const workBook = initSheet($('#price-spread')[0], setting);
  673. workBook.options.allowUserDragDrop = true;
  674. workBook.options.allowUserDragFill = true;
  675. lockUtil.lockSpreads([workBook], locked);
  676. const sheet = workBook.getSheet(0);
  677. let cache = [];
  678. // 清空
  679. function clear() {
  680. cache = [];
  681. sheet.setRowCount(0);
  682. }
  683. // 初始化数据
  684. async function initData(classIDList) {
  685. if (!classIDList || !classIDList.length) {
  686. return clear();
  687. }
  688. $.bootstrapLoading.start();
  689. try {
  690. cache = await ajaxPost('/priceInfo/getPriceData', { classIDList }, TIME_OUT);
  691. cache = _.sortBy(cache,'classCode');
  692. showData(sheet, cache, setting.header, 5);
  693. const row = sheet.getActiveRowIndex();
  694. const keywordList = cache[row] && cache[row].keywordList || [];
  695. KEYWORD_BOOK.showKeywordData(keywordList);
  696. } catch (err) {
  697. cache = [];
  698. sheet.setRowCount(0);
  699. alert(err);
  700. } finally {
  701. $.bootstrapLoading.end();
  702. }
  703. }
  704. // 获取当前表中行数据
  705. function getRowData(sheet, row, headers) {
  706. const item = {};
  707. headers.forEach(({ dataCode }, index) => {
  708. const value = sheet.getValue(row, index) || '';
  709. if (value) {
  710. item[dataCode] = value;
  711. }
  712. });
  713. return item;
  714. }
  715. // 获取表数据和缓存数据的不同数据
  716. function getRowDiffData(curRowData, cacheRowData, headers) {
  717. let item = null;
  718. headers.forEach(({ dataCode }) => {
  719. const curValue = curRowData[dataCode];
  720. const cacheValue = cacheRowData[dataCode];
  721. if (!cacheValue && !curValue) {
  722. return;
  723. }
  724. if (cacheValue !== curValue) {
  725. if (!item) {
  726. item = {};
  727. }
  728. item[dataCode] = curValue || '';
  729. }
  730. });
  731. return item;
  732. }
  733. // 编辑处理
  734. async function handleEdit(changedCells) {
  735. const postData = []; // 请求用
  736. // 更新缓存用
  737. const updateData = [];
  738. const deleteData = [];
  739. const insertData = [];
  740. try {
  741. changedCells.forEach(({ row }) => {
  742. if (cache[row]) {
  743. const rowData = getRowData(sheet, row, setting.header);
  744. if (Object.keys(rowData).length) { // 还有数据,更新
  745. const diffData = getRowDiffData(rowData, cache[row], setting.header);
  746. if (diffData) {
  747. postData.push({ type: UpdateType.UPDATE, ID: cache[row].ID, data: diffData });
  748. updateData.push({ row, data: diffData });
  749. }
  750. } else { // 该行无数据了,删除
  751. postData.push({ type: UpdateType.DELETE, ID: cache[row].ID });
  752. deleteData.push(cache[row]);
  753. }
  754. } else { // 新增
  755. const rowData = getRowData(sheet, row, setting.header);
  756. if (Object.keys(rowData).length) {
  757. rowData.ID = uuid.v1();
  758. rowData.libID = libID;
  759. rowData.compilationID = compilationID;
  760. rowData.areaID = AREA_BOOK.curArea.ID;
  761. rowData.classID = CLASS_BOOK.curClass.ID;
  762. rowData.period = curLibPeriod;
  763. postData.push({ type: UpdateType.CREATE, data: rowData });
  764. insertData.push(rowData);
  765. }
  766. }
  767. });
  768. if (postData.length) {
  769. await ajaxPost('/priceInfo/editPriceData', { postData }, TIME_OUT);
  770. // 更新缓存,先更新然后删除,最后再新增,防止先新增后缓存数据的下标与更新、删除数据的下标对应不上
  771. updateData.forEach(item => {
  772. Object.assign(cache[item.row], item.data);
  773. });
  774. deleteData.forEach(item => {
  775. const index = cache.indexOf(item);
  776. if (index >= 0) {
  777. cache.splice(index, 1);
  778. }
  779. });
  780. insertData.forEach(item => cache.push(item));
  781. if (deleteData.length || insertData.length) {
  782. showData(sheet, cache, setting.header, 5);
  783. }
  784. }
  785. } catch (err) {
  786. // 恢复各单元格数据
  787. showData(sheet, cache, setting.header, 5);
  788. }
  789. }
  790. sheet.bind(GC.Spread.Sheets.Events.ValueChanged, function (e, info) {
  791. const changedCells = [{ row: info.row }];
  792. handleEdit(changedCells);
  793. });
  794. sheet.bind(GC.Spread.Sheets.Events.SelectionChanged, function (e, info) {
  795. const row = info.newSelections && info.newSelections[0] ? info.newSelections[0].row : 0;
  796. // 显示关键字数据
  797. const keywordList = cache[row] && cache[row].keywordList || [];
  798. KEYWORD_BOOK.showKeywordData(keywordList);
  799. });
  800. sheet.bind(GC.Spread.Sheets.Events.RangeChanged, function (e, info) {
  801. const changedRows = [];
  802. let preRow;
  803. info.changedCells.forEach(({ row }) => {
  804. if (row !== preRow) {
  805. changedRows.push({ row });
  806. }
  807. preRow = row;
  808. });
  809. handleEdit(changedRows);
  810. });
  811. return {
  812. clear,
  813. initData,
  814. }
  815. })();
  816. $(document).ready(() => {
  817. console.log('进入信息价');
  818. $('[data-toggle="tooltip"]').tooltip();
  819. AREA_BOOK.handleSelectionChanged(0);
  820. const $range = $(document.body);
  821. lockUtil.lockTools($range, locked);
  822. });