index.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810
  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. tree = null;
  259. controller = null;
  260. sheet.setRowCount(0);
  261. alert(err);
  262. } finally {
  263. $.bootstrapLoading.end();
  264. }
  265. }
  266. // 编辑处理
  267. async function handleEdit(changedCells) {
  268. const updateData = [];
  269. changedCells.forEach(({ row, col }) => {
  270. updateData.push({
  271. row,
  272. type: UpdateType.UPDATE,
  273. filter: { ID: tree.items[row].data.ID },
  274. update: { name: sheet.getValue(row, col) }
  275. });
  276. });
  277. try {
  278. await ajaxPost('/priceInfo/editClassData', { updateData }, TIME_OUT);
  279. updateData.forEach(({ row, update: { name } }) => tree.items[row].data.name = name);
  280. } catch (err) {
  281. // 恢复各单元格数据
  282. sheetCommonObj.renderSheetFunc(sheet, () => {
  283. changedCells.forEach(({ row }) => {
  284. sheet.setValue(tree.items[row].data.name);
  285. });
  286. });
  287. }
  288. }
  289. sheet.bind(GC.Spread.Sheets.Events.ValueChanged, function (e, info) {
  290. const changedCells = [{ row: info.row, col: info.col }];
  291. handleEdit(changedCells);
  292. });
  293. sheet.bind(GC.Spread.Sheets.Events.RangeChanged, function (e, info) {
  294. handleEdit(info.changedCells);
  295. });
  296. // 树操作相关
  297. const $insert = $('#tree-insert');
  298. const $remove = $('#tree-remove');
  299. const $upLevel = $('#tree-up-level');
  300. const $downLevel = $('#tree-down-level');
  301. const $downMove = $('#tree-down-move');
  302. const $upMove = $('#tree-up-move');
  303. // 插入
  304. let canInsert = true;
  305. async function insert() {
  306. try {
  307. if (!canInsert) {
  308. return false;
  309. }
  310. canInsert = false;
  311. $.bootstrapLoading.start();
  312. const updateData = [];
  313. const selected = tree.selected;
  314. const newItem = {
  315. libID,
  316. areaID: AREA_BOOK.curArea.ID,
  317. ID: uuid.v1(),
  318. name: '',
  319. ParentID: '-1',
  320. NextSiblingID: '-1'
  321. };
  322. if (selected) {
  323. newItem.ParentID = selected.data.ParentID;
  324. updateData.push({
  325. type: UpdateType.UPDATE,
  326. filter: { ID: selected.data.ID },
  327. update: { NextSiblingID: newItem.ID }
  328. });
  329. if (selected.nextSibling) {
  330. newItem.NextSiblingID = selected.nextSibling.data.ID;
  331. }
  332. }
  333. updateData.push({
  334. type: UpdateType.CREATE,
  335. document: newItem
  336. });
  337. await ajaxPost('/priceInfo/editClassData', { updateData });
  338. controller.insertByID(newItem.ID);
  339. handleSelectionChanged(sheet.getActiveRowIndex());
  340. } catch (err) {
  341. alert(err);
  342. } finally {
  343. canInsert = true;
  344. $.bootstrapLoading.end();
  345. }
  346. }
  347. $insert.click(_.debounce(insert, DEBOUNCE_TIME, { leading: true }));
  348. // 删除
  349. let canRemove = true;
  350. async function remove() {
  351. try {
  352. if (!canRemove) {
  353. return false;
  354. }
  355. canRemove = false;
  356. $.bootstrapLoading.start();
  357. const updateData = [];
  358. const selected = tree.selected;
  359. const children = selected.getPosterity();
  360. [selected, ...children].forEach(node => updateData.push({
  361. type: UpdateType.DELETE,
  362. filter: { ID: node.data.ID }
  363. }));
  364. if (selected.preSibling) {
  365. updateData.push({
  366. type: UpdateType.UPDATE,
  367. filter: { ID: selected.preSibling.data.ID },
  368. update: { NextSiblingID: selected.data.NextSiblingID }
  369. });
  370. }
  371. await ajaxPost('/priceInfo/editClassData', { updateData });
  372. controller.delete();
  373. handleSelectionChanged(sheet.getActiveRowIndex());
  374. } catch (err) {
  375. alert(err);
  376. } finally {
  377. canRemove = true;
  378. $.bootstrapLoading.end();
  379. }
  380. }
  381. $remove.click(_.debounce(remove, DEBOUNCE_TIME, { leading: true }));
  382. // 升级
  383. let canUpLevel = true;
  384. async function upLevel() {
  385. try {
  386. if (!canUpLevel) {
  387. return false;
  388. }
  389. canUpLevel = false;
  390. $.bootstrapLoading.start();
  391. const updateData = [];
  392. const selected = tree.selected;
  393. if (selected.preSibling) {
  394. updateData.push({
  395. type: UpdateType.UPDATE,
  396. filter: { ID: selected.preSibling.data.ID },
  397. update: { NextSiblingID: -1 }
  398. });
  399. }
  400. if (selected.parent) {
  401. updateData.push({
  402. type: UpdateType.UPDATE,
  403. filter: { ID: selected.parent.data.ID },
  404. update: { NextSiblingID: selected.data.ID }
  405. });
  406. }
  407. updateData.push({
  408. type: UpdateType.UPDATE,
  409. filter: { ID: selected.data.ID },
  410. update: { ParentID: selected.parent.data.ParentID, NextSiblingID: selected.parent.data.NextSiblingID }
  411. });
  412. let curNode = selected.nextSibling;
  413. while (curNode) {
  414. updateData.push({
  415. type: UpdateType.UPDATE,
  416. filter: { ID: curNode.data.ID },
  417. update: { ParentID: selected.data.ID }
  418. });
  419. curNode = curNode.nextSibling;
  420. }
  421. await ajaxPost('/priceInfo/editClassData', { updateData });
  422. controller.upLevel();
  423. refreshTreeButton(tree.selected);
  424. } catch (err) {
  425. alert(err);
  426. } finally {
  427. canUpLevel = true;
  428. $.bootstrapLoading.end();
  429. }
  430. }
  431. $upLevel.click(_.debounce(upLevel, DEBOUNCE_TIME, { leading: true }));
  432. // 降级
  433. let canDownLevel = true;
  434. async function downLevel() {
  435. try {
  436. if (!canDownLevel) {
  437. return false;
  438. }
  439. canDownLevel = false;
  440. $.bootstrapLoading.start();
  441. const updateData = [];
  442. const selected = tree.selected;
  443. if (selected.preSibling) {
  444. updateData.push({
  445. type: UpdateType.UPDATE,
  446. filter: { ID: selected.preSibling.data.ID },
  447. update: { NextSiblingID: selected.data.NextSiblingID }
  448. });
  449. const preSiblingLastChild = selected.preSibling.children[selected.preSibling.children.length - 1];
  450. if (preSiblingLastChild) {
  451. updateData.push({
  452. type: UpdateType.UPDATE,
  453. filter: { ID: preSiblingLastChild.data.ID },
  454. update: { NextSiblingID: selected.data.ID }
  455. });
  456. }
  457. updateData.push({
  458. type: UpdateType.UPDATE,
  459. filter: { ID: selected.data.ID },
  460. update: { ParentID: selected.preSibling.data.ID, NextSiblingID: -1 }
  461. });
  462. }
  463. await ajaxPost('/priceInfo/editClassData', { updateData });
  464. controller.downLevel();
  465. refreshTreeButton(tree.selected);
  466. } catch (err) {
  467. alert(err);
  468. } finally {
  469. canDownLevel = true;
  470. $.bootstrapLoading.end();
  471. }
  472. }
  473. $downLevel.click(_.debounce(downLevel, DEBOUNCE_TIME, { leading: true }));
  474. // 下移
  475. let canDownMove = true;
  476. async function downMove() {
  477. try {
  478. if (!canDownMove) {
  479. return false;
  480. }
  481. canDownMove = false;
  482. $.bootstrapLoading.start();
  483. const updateData = [];
  484. const selected = tree.selected;
  485. if (selected.preSibling) {
  486. updateData.push({
  487. type: UpdateType.UPDATE,
  488. filter: { ID: selected.preSibling.data.ID },
  489. update: { NextSiblingID: selected.data.NextSiblingID }
  490. });
  491. }
  492. updateData.push({
  493. type: UpdateType.UPDATE,
  494. filter: { ID: selected.data.ID },
  495. update: { NextSiblingID: selected.nextSibling.data.NextSiblingID }
  496. });
  497. updateData.push({
  498. type: UpdateType.UPDATE,
  499. filter: { ID: selected.nextSibling.data.ID },
  500. update: { NextSiblingID: selected.data.ID }
  501. });
  502. await ajaxPost('/priceInfo/editClassData', { updateData });
  503. controller.downMove();
  504. refreshTreeButton(tree.selected);
  505. } catch (err) {
  506. alert(err);
  507. } finally {
  508. canDownMove = true;
  509. $.bootstrapLoading.end();
  510. }
  511. }
  512. $downMove.click(_.debounce(downMove, DEBOUNCE_TIME, { leading: true }));
  513. // 上移
  514. let canUpMove = true;
  515. async function upMove() {
  516. try {
  517. if (!canUpMove) {
  518. return false;
  519. }
  520. canUpMove = false;
  521. $.bootstrapLoading.start();
  522. const updateData = [];
  523. const selected = tree.selected;
  524. if (selected.preSibling) {
  525. updateData.push({
  526. type: UpdateType.UPDATE,
  527. filter: { ID: selected.preSibling.data.ID },
  528. update: { NextSiblingID: selected.data.NextSiblingID }
  529. });
  530. }
  531. const prePreSibling = selected.preSibling.preSibling;
  532. if (prePreSibling) {
  533. updateData.push({
  534. type: UpdateType.UPDATE,
  535. filter: { ID: prePreSibling.data.ID },
  536. update: { NextSiblingID: selected.data.ID }
  537. });
  538. }
  539. updateData.push({
  540. type: UpdateType.UPDATE,
  541. filter: { ID: selected.data.ID },
  542. update: { NextSiblingID: selected.preSibling.data.ID }
  543. });
  544. await ajaxPost('/priceInfo/editClassData', { updateData });
  545. controller.upMove();
  546. refreshTreeButton(tree.selected);
  547. } catch (err) {
  548. alert(err);
  549. } finally {
  550. canUpMove = true;
  551. $.bootstrapLoading.end();
  552. }
  553. }
  554. $upMove.click(_.debounce(upMove, DEBOUNCE_TIME, { leading: true }));
  555. // 刷新树操作按钮有效性
  556. function refreshTreeButton(selected) {
  557. if (locked) {
  558. return;
  559. }
  560. $insert.removeClass('disabled');
  561. $remove.removeClass('disabled');
  562. $upLevel.removeClass('disabled');
  563. $downLevel.removeClass('disabled');
  564. $downMove.removeClass('disabled');
  565. $upMove.removeClass('disabled');
  566. if (!selected) {
  567. $remove.addClass('disabled');
  568. $upLevel.addClass('disabled');
  569. $downLevel.addClass('disabled');
  570. $downMove.addClass('disabled');
  571. $upMove.addClass('disabled');
  572. } else {
  573. if (!selected.preSibling) {
  574. $downLevel.addClass('disabled');
  575. $upMove.addClass('disabled');
  576. }
  577. if (!selected.nextSibling) {
  578. $downMove.addClass('disabled');
  579. }
  580. if (!selected.parent) {
  581. $upLevel.addClass('disabled');
  582. }
  583. }
  584. }
  585. // 焦点变更处理
  586. const curClass = { ID: null };
  587. function handleSelectionChanged(row) {
  588. const classNode = tree.items[row] || null;
  589. tree.selected = classNode;
  590. refreshTreeButton(classNode);
  591. curClass.ID = classNode && classNode.data && classNode.data.ID || null;
  592. const classIDList = []
  593. if (classNode) {
  594. classIDList.push(classNode.data.ID);
  595. const children = classNode.getPosterity();
  596. children.forEach(child => classIDList.push(child.data.ID));
  597. }
  598. PRICE_BOOK.initData(classIDList);
  599. }
  600. const debounceSelectionChanged = _.debounce(function (e, info) {
  601. const row = info.newSelections && info.newSelections[0] ? info.newSelections[0].row : 0;
  602. handleSelectionChanged(row);
  603. }, DEBOUNCE_TIME, { leading: true });
  604. sheet.bind(GC.Spread.Sheets.Events.SelectionChanged, debounceSelectionChanged);
  605. return {
  606. initData,
  607. handleSelectionChanged,
  608. curClass,
  609. }
  610. })();
  611. // 价格信息表
  612. const PRICE_BOOK = (() => {
  613. const setting = {
  614. header: [
  615. { headerName: '编码', headerWidth: 100, dataCode: 'code', dataType: 'String', hAlign: 'left', vAlign: 'center' ,formatter: "@"},
  616. { headerName: '名称', headerWidth: 200, dataCode: 'name', dataType: 'String', hAlign: 'left', vAlign: 'center' },
  617. { headerName: '规格型号', headerWidth: 120, dataCode: 'specs', dataType: 'String', hAlign: 'left', vAlign: 'center' },
  618. { headerName: '单位', headerWidth: 80, dataCode: 'unit', dataType: 'String', hAlign: 'center', vAlign: 'center' },
  619. { headerName: '不含税价', headerWidth: 80, dataCode: 'noTaxPrice', dataType: 'String', hAlign: 'right', vAlign: 'center' },
  620. { headerName: '含税价', headerWidth: 80, dataCode: 'taxPrice', dataType: 'String', hAlign: 'right', vAlign: 'center' },
  621. ],
  622. };
  623. // 初始化表格
  624. const workBook = initSheet($('#price-spread')[0], setting);
  625. workBook.options.allowUserDragDrop = true;
  626. workBook.options.allowUserDragFill = true;
  627. lockUtil.lockSpreads([workBook], locked);
  628. const sheet = workBook.getSheet(0);
  629. let cache = [];
  630. // 清空
  631. function clear() {
  632. cache = [];
  633. sheet.setRowCount(0);
  634. }
  635. // 初始化数据
  636. async function initData(classIDList) {
  637. if (!classIDList || !classIDList.length) {
  638. return clear();
  639. }
  640. $.bootstrapLoading.start();
  641. try {
  642. cache = await ajaxPost('/priceInfo/getPriceData', { classIDList }, TIME_OUT);
  643. showData(sheet, cache, setting.header, 5);
  644. } catch (err) {
  645. cache = [];
  646. sheet.setRowCount(0);
  647. alert(err);
  648. } finally {
  649. $.bootstrapLoading.end();
  650. }
  651. }
  652. // 获取当前表中行数据
  653. function getRowData(sheet, row, headers) {
  654. const item = {};
  655. headers.forEach(({ dataCode }, index) => {
  656. const value = sheet.getValue(row, index) || '';
  657. if (value) {
  658. item[dataCode] = value;
  659. }
  660. });
  661. return item;
  662. }
  663. // 获取表数据和缓存数据的不同数据
  664. function getRowDiffData(curRowData, cacheRowData, headers) {
  665. let item = null;
  666. headers.forEach(({ dataCode }) => {
  667. const curValue = curRowData[dataCode];
  668. const cacheValue = cacheRowData[dataCode];
  669. if (!cacheValue && !curValue) {
  670. return;
  671. }
  672. if (cacheValue !== curValue) {
  673. if (!item) {
  674. item = {};
  675. }
  676. item[dataCode] = curValue || '';
  677. }
  678. });
  679. return item;
  680. }
  681. // 编辑处理
  682. async function handleEdit(changedCells) {
  683. const postData = []; // 请求用
  684. // 更新缓存用
  685. const updateData = [];
  686. const deleteData = [];
  687. const insertData = [];
  688. try {
  689. changedCells.forEach(({ row }) => {
  690. if (cache[row]) {
  691. const rowData = getRowData(sheet, row, setting.header);
  692. if (Object.keys(rowData).length) { // 还有数据,更新
  693. const diffData = getRowDiffData(rowData, cache[row], setting.header);
  694. if (diffData) {
  695. postData.push({ type: UpdateType.UPDATE, ID: cache[row].ID, data: diffData });
  696. updateData.push({ row, data: diffData });
  697. }
  698. } else { // 该行无数据了,删除
  699. postData.push({ type: UpdateType.DELETE, ID: cache[row].ID });
  700. deleteData.push(cache[row]);
  701. }
  702. } else { // 新增
  703. const rowData = getRowData(sheet, row, setting.header);
  704. if (Object.keys(rowData).length) {
  705. rowData.ID = uuid.v1();
  706. rowData.libID = libID;
  707. rowData.compilationID = compilationID;
  708. rowData.areaID = AREA_BOOK.curArea.ID;
  709. rowData.classID = CLASS_BOOK.curClass.ID;
  710. rowData.period = curLibPeriod;
  711. postData.push({ type: UpdateType.CREATE, data: rowData });
  712. insertData.push(rowData);
  713. }
  714. }
  715. });
  716. if (postData.length) {
  717. await ajaxPost('/priceInfo/editPriceData', { postData }, TIME_OUT);
  718. // 更新缓存,先更新然后删除,最后再新增,防止先新增后缓存数据的下标与更新、删除数据的下标对应不上
  719. updateData.forEach(item => {
  720. Object.assign(cache[item.row], item.data);
  721. });
  722. deleteData.forEach(item => {
  723. const index = cache.indexOf(item);
  724. if (index >= 0) {
  725. cache.splice(index, 1);
  726. }
  727. });
  728. insertData.forEach(item => cache.push(item));
  729. if (deleteData.length || insertData.length) {
  730. showData(sheet, cache, setting.header, 5);
  731. }
  732. }
  733. } catch (err) {
  734. // 恢复各单元格数据
  735. showData(sheet, cache, setting.header, 5);
  736. }
  737. }
  738. sheet.bind(GC.Spread.Sheets.Events.ValueChanged, function (e, info) {
  739. const changedCells = [{ row: info.row }];
  740. handleEdit(changedCells);
  741. });
  742. sheet.bind(GC.Spread.Sheets.Events.RangeChanged, function (e, info) {
  743. const changedRows = [];
  744. let preRow;
  745. info.changedCells.forEach(({ row }) => {
  746. if (row !== preRow) {
  747. changedRows.push({ row });
  748. }
  749. preRow = row;
  750. });
  751. handleEdit(changedRows);
  752. });
  753. return {
  754. clear,
  755. initData,
  756. }
  757. })();
  758. $(document).ready(() => {
  759. console.log('进入信息价');
  760. $('[data-toggle="tooltip"]').tooltip();
  761. AREA_BOOK.handleSelectionChanged(0);
  762. const $range = $(document.body);
  763. lockUtil.lockTools($range, locked);
  764. });