priceClass.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. // 分类表
  2. const CLASS_BOOK = (() => {
  3. const setting = {
  4. header: [{ headerName: '分类', headerWidth: $('#area-spread').width(), dataCode: 'name', dataType: 'String', hAlign: 'left', vAlign: 'center' }],
  5. controller: {
  6. cols: [
  7. {
  8. data: {
  9. field: 'name',
  10. vAlign: 1,
  11. hAlign: 0,
  12. font: 'Arial'
  13. },
  14. }
  15. ],
  16. headRows: 1,
  17. headRowHeight: [30],
  18. emptyRows: 0,
  19. treeCol: 0
  20. },
  21. tree: {
  22. id: 'ID',
  23. pid: 'ParentID',
  24. nid: 'NextSiblingID',
  25. rootId: -1
  26. }
  27. };
  28. // 初始化表格
  29. const workBook = initSheet($('#class-spread')[0], setting);
  30. workBook.options.allowExtendPasteRange = false;
  31. workBook.options.allowUserDragDrop = true;
  32. workBook.options.allowUserDragFill = true;
  33. const sheet = workBook.getSheet(0);
  34. let tree;
  35. let controller;
  36. // 初始化数据
  37. async function initData(libID, areaID) {
  38. if (!areaID) {
  39. tree = null;
  40. controller = null;
  41. sheet.setRowCount(0);
  42. PRICE_BOOK.clear();
  43. return;
  44. }
  45. $.bootstrapLoading.start();
  46. try {
  47. const data = await ajaxPost('/priceInfo/getClassData', { libID, areaID }, TIME_OUT);
  48. tree = idTree.createNew(setting.tree);
  49. tree.loadDatas(data);
  50. tree.selected = tree.items.length > 0 ? tree.items[0] : null;
  51. controller = TREE_SHEET_CONTROLLER.createNew(tree, sheet, setting.controller, false);
  52. controller.showTreeData();
  53. handleSelectionChanged(0);
  54. sheet.setSelection(0, 0, 1, 1);
  55. lockUtil.lockSpreads([workBook], locked);
  56. } catch (err) {
  57. tree = null;
  58. controller = null;
  59. sheet.setRowCount(0);
  60. alert(err);
  61. } finally {
  62. $.bootstrapLoading.end();
  63. }
  64. }
  65. // 编辑处理
  66. async function handleEdit(changedCells) {
  67. const updateData = [];
  68. changedCells.forEach(({ row, col }) => {
  69. updateData.push({
  70. row,
  71. type: UpdateType.UPDATE,
  72. filter: { ID: tree.items[row].data.ID },
  73. update: { name: sheet.getValue(row, col) }
  74. });
  75. });
  76. try {
  77. await ajaxPost('/priceInfo/editClassData', { updateData }, TIME_OUT);
  78. updateData.forEach(({ row, update: { name } }) => tree.items[row].data.name = name);
  79. } catch (err) {
  80. // 恢复各单元格数据
  81. sheetCommonObj.renderSheetFunc(sheet, () => {
  82. changedCells.forEach(({ row }) => {
  83. sheet.setValue(tree.items[row].data.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. // 树操作相关
  96. const $insert = $('#tree-insert');
  97. const $remove = $('#tree-remove');
  98. const $upLevel = $('#tree-up-level');
  99. const $downLevel = $('#tree-down-level');
  100. const $downMove = $('#tree-down-move');
  101. const $upMove = $('#tree-up-move');
  102. const $calcPriceIndex = $('#calc-price-index');
  103. const $matchSummary = $('#match-summary');
  104. const $showEmpty = $('#show-empty');
  105. // 插入
  106. let canInsert = true;
  107. async function insert() {
  108. try {
  109. if (!canInsert) {
  110. return false;
  111. }
  112. canInsert = false;
  113. $.bootstrapLoading.start();
  114. const updateData = [];
  115. const selected = tree.selected;
  116. const newItem = {
  117. libID,
  118. areaID: AREA_BOOK.curArea.ID,
  119. ID: uuid.v1(),
  120. name: '',
  121. ParentID: '-1',
  122. NextSiblingID: '-1'
  123. };
  124. if (selected) {
  125. newItem.ParentID = selected.data.ParentID;
  126. updateData.push({
  127. type: UpdateType.UPDATE,
  128. filter: { ID: selected.data.ID },
  129. update: { NextSiblingID: newItem.ID }
  130. });
  131. if (selected.nextSibling) {
  132. newItem.NextSiblingID = selected.nextSibling.data.ID;
  133. }
  134. }
  135. updateData.push({
  136. type: UpdateType.CREATE,
  137. document: newItem
  138. });
  139. await ajaxPost('/priceInfo/editClassData', { updateData });
  140. controller.insertByID(newItem.ID);
  141. handleSelectionChanged(sheet.getActiveRowIndex());
  142. } catch (err) {
  143. alert(err);
  144. } finally {
  145. canInsert = true;
  146. $.bootstrapLoading.end();
  147. }
  148. }
  149. $insert.click(_.debounce(insert, DEBOUNCE_TIME, { leading: true }));
  150. // 删除
  151. let canRemove = true;
  152. async function remove() {
  153. try {
  154. if (!canRemove) {
  155. return false;
  156. }
  157. canRemove = false;
  158. $.bootstrapLoading.start();
  159. const updateData = [];
  160. const selected = tree.selected;
  161. const children = selected.getPosterity();
  162. [selected, ...children].forEach(node => updateData.push({
  163. type: UpdateType.DELETE,
  164. filter: { ID: node.data.ID }
  165. }));
  166. if (selected.preSibling) {
  167. updateData.push({
  168. type: UpdateType.UPDATE,
  169. filter: { ID: selected.preSibling.data.ID },
  170. update: { NextSiblingID: selected.data.NextSiblingID }
  171. });
  172. }
  173. await ajaxPost('/priceInfo/editClassData', { updateData });
  174. controller.delete();
  175. handleSelectionChanged(sheet.getActiveRowIndex());
  176. } catch (err) {
  177. alert(err);
  178. } finally {
  179. canRemove = true;
  180. $.bootstrapLoading.end();
  181. }
  182. }
  183. $remove.click(_.debounce(remove, DEBOUNCE_TIME, { leading: true }));
  184. // 升级
  185. let canUpLevel = true;
  186. async function upLevel() {
  187. try {
  188. if (!canUpLevel) {
  189. return false;
  190. }
  191. canUpLevel = false;
  192. $.bootstrapLoading.start();
  193. const updateData = [];
  194. const selected = tree.selected;
  195. if (selected.preSibling) {
  196. updateData.push({
  197. type: UpdateType.UPDATE,
  198. filter: { ID: selected.preSibling.data.ID },
  199. update: { NextSiblingID: -1 }
  200. });
  201. }
  202. if (selected.parent) {
  203. updateData.push({
  204. type: UpdateType.UPDATE,
  205. filter: { ID: selected.parent.data.ID },
  206. update: { NextSiblingID: selected.data.ID }
  207. });
  208. }
  209. updateData.push({
  210. type: UpdateType.UPDATE,
  211. filter: { ID: selected.data.ID },
  212. update: { ParentID: selected.parent.data.ParentID, NextSiblingID: selected.parent.data.NextSiblingID }
  213. });
  214. let curNode = selected.nextSibling;
  215. while (curNode) {
  216. updateData.push({
  217. type: UpdateType.UPDATE,
  218. filter: { ID: curNode.data.ID },
  219. update: { ParentID: selected.data.ID }
  220. });
  221. curNode = curNode.nextSibling;
  222. }
  223. await ajaxPost('/priceInfo/editClassData', { updateData });
  224. controller.upLevel();
  225. refreshTreeButton(tree.selected);
  226. } catch (err) {
  227. alert(err);
  228. } finally {
  229. canUpLevel = true;
  230. $.bootstrapLoading.end();
  231. }
  232. }
  233. $upLevel.click(_.debounce(upLevel, DEBOUNCE_TIME, { leading: true }));
  234. // 降级
  235. let canDownLevel = true;
  236. async function downLevel() {
  237. try {
  238. if (!canDownLevel) {
  239. return false;
  240. }
  241. canDownLevel = false;
  242. $.bootstrapLoading.start();
  243. const updateData = [];
  244. const selected = tree.selected;
  245. if (selected.preSibling) {
  246. updateData.push({
  247. type: UpdateType.UPDATE,
  248. filter: { ID: selected.preSibling.data.ID },
  249. update: { NextSiblingID: selected.data.NextSiblingID }
  250. });
  251. const preSiblingLastChild = selected.preSibling.children[selected.preSibling.children.length - 1];
  252. if (preSiblingLastChild) {
  253. updateData.push({
  254. type: UpdateType.UPDATE,
  255. filter: { ID: preSiblingLastChild.data.ID },
  256. update: { NextSiblingID: selected.data.ID }
  257. });
  258. }
  259. updateData.push({
  260. type: UpdateType.UPDATE,
  261. filter: { ID: selected.data.ID },
  262. update: { ParentID: selected.preSibling.data.ID, NextSiblingID: -1 }
  263. });
  264. }
  265. await ajaxPost('/priceInfo/editClassData', { updateData });
  266. controller.downLevel();
  267. refreshTreeButton(tree.selected);
  268. } catch (err) {
  269. alert(err);
  270. } finally {
  271. canDownLevel = true;
  272. $.bootstrapLoading.end();
  273. }
  274. }
  275. $downLevel.click(_.debounce(downLevel, DEBOUNCE_TIME, { leading: true }));
  276. // 下移
  277. let canDownMove = true;
  278. async function downMove() {
  279. try {
  280. if (!canDownMove) {
  281. return false;
  282. }
  283. canDownMove = false;
  284. $.bootstrapLoading.start();
  285. const updateData = [];
  286. const selected = tree.selected;
  287. if (selected.preSibling) {
  288. updateData.push({
  289. type: UpdateType.UPDATE,
  290. filter: { ID: selected.preSibling.data.ID },
  291. update: { NextSiblingID: selected.data.NextSiblingID }
  292. });
  293. }
  294. updateData.push({
  295. type: UpdateType.UPDATE,
  296. filter: { ID: selected.data.ID },
  297. update: { NextSiblingID: selected.nextSibling.data.NextSiblingID }
  298. });
  299. updateData.push({
  300. type: UpdateType.UPDATE,
  301. filter: { ID: selected.nextSibling.data.ID },
  302. update: { NextSiblingID: selected.data.ID }
  303. });
  304. await ajaxPost('/priceInfo/editClassData', { updateData });
  305. controller.downMove();
  306. refreshTreeButton(tree.selected);
  307. } catch (err) {
  308. alert(err);
  309. } finally {
  310. canDownMove = true;
  311. $.bootstrapLoading.end();
  312. }
  313. }
  314. $downMove.click(_.debounce(downMove, DEBOUNCE_TIME, { leading: true }));
  315. // 上移
  316. let canUpMove = true;
  317. async function upMove() {
  318. try {
  319. if (!canUpMove) {
  320. return false;
  321. }
  322. canUpMove = false;
  323. $.bootstrapLoading.start();
  324. const updateData = [];
  325. const selected = tree.selected;
  326. if (selected.preSibling) {
  327. updateData.push({
  328. type: UpdateType.UPDATE,
  329. filter: { ID: selected.preSibling.data.ID },
  330. update: { NextSiblingID: selected.data.NextSiblingID }
  331. });
  332. }
  333. const prePreSibling = selected.preSibling.preSibling;
  334. if (prePreSibling) {
  335. updateData.push({
  336. type: UpdateType.UPDATE,
  337. filter: { ID: prePreSibling.data.ID },
  338. update: { NextSiblingID: selected.data.ID }
  339. });
  340. }
  341. updateData.push({
  342. type: UpdateType.UPDATE,
  343. filter: { ID: selected.data.ID },
  344. update: { NextSiblingID: selected.preSibling.data.ID }
  345. });
  346. await ajaxPost('/priceInfo/editClassData', { updateData });
  347. controller.upMove();
  348. refreshTreeButton(tree.selected);
  349. } catch (err) {
  350. alert(err);
  351. } finally {
  352. canUpMove = true;
  353. $.bootstrapLoading.end();
  354. }
  355. }
  356. $upMove.click(_.debounce(upMove, DEBOUNCE_TIME, { leading: true }));
  357. // 刷新树操作按钮有效性
  358. function refreshTreeButton(selected) {
  359. if (locked) {
  360. return;
  361. }
  362. $insert.removeClass('disabled');
  363. $remove.removeClass('disabled');
  364. $upLevel.removeClass('disabled');
  365. $downLevel.removeClass('disabled');
  366. $downMove.removeClass('disabled');
  367. $upMove.removeClass('disabled');
  368. if (!selected) {
  369. $remove.addClass('disabled');
  370. $upLevel.addClass('disabled');
  371. $downLevel.addClass('disabled');
  372. $downMove.addClass('disabled');
  373. $upMove.addClass('disabled');
  374. } else {
  375. if (!selected.preSibling) {
  376. $downLevel.addClass('disabled');
  377. $upMove.addClass('disabled');
  378. }
  379. if (!selected.nextSibling) {
  380. $downMove.addClass('disabled');
  381. }
  382. if (!selected.parent) {
  383. $upLevel.addClass('disabled');
  384. }
  385. }
  386. }
  387. // 焦点变更处理
  388. const curClass = { ID: null };
  389. function handleSelectionChanged(row) {
  390. curRow = row;
  391. const classNode = tree.items[row] || null;
  392. tree.selected = classNode;
  393. refreshTreeButton(classNode);
  394. curClass.ID = classNode && classNode.data && classNode.data.ID || null;
  395. const classIDList = []
  396. if (classNode) {
  397. classIDList.push(classNode.data.ID);
  398. const children = classNode.getPosterity();
  399. children.forEach(child => classIDList.push(child.data.ID));
  400. }
  401. PRICE_BOOK.initData(classIDList);
  402. }
  403. const debounceSelectionChanged = _.debounce(function (e, info) {
  404. const row = info.newSelections && info.newSelections[0] ? info.newSelections[0].row : 0;
  405. handleSelectionChanged(row);
  406. }, DEBOUNCE_TIME, { leading: true });
  407. sheet.bind(GC.Spread.Sheets.Events.SelectionChanged, debounceSelectionChanged);
  408. const reload = () => {
  409. if (curClass.ID) {
  410. const node = tree.nodes[tree.prefix + curClass.ID];
  411. if (node) {
  412. handleSelectionChanged(node.serialNo())
  413. }
  414. }
  415. }
  416. $calcPriceIndex.click(_.debounce(async () => {
  417. $.bootstrapLoading.start();
  418. try {
  419. const data = await ajaxPost('/priceInfo/calcPriceIndex', { libID, period: curLibPeriod, compilationID }, TIME_OUT);
  420. //alert(data);
  421. if (data) {
  422. const htmlStr = data.replace(/\n/gm, '<br>'); //replaceAll('\n','<br>',data);
  423. $("#result-info-body").html(htmlStr);
  424. $("#result-info").modal('show');
  425. } else {
  426. alert('计算完成!')
  427. }
  428. } catch (error) {
  429. console.log(error);
  430. }
  431. $.bootstrapLoading.end();
  432. }, DEBOUNCE_TIME, { leading: true }));
  433. // 匹配总表
  434. $matchSummary.click(_.debounce(async () => {
  435. $.bootstrapLoading.progressStart('匹配总表', true);
  436. $("#progress_modal_body").text('正在匹配总表,请稍后...');
  437. try {
  438. await ajaxPost('/priceInfo/matchSummary', { libID, compilationID }, 1000 * 60 * 10);
  439. $.bootstrapLoading.progressEnd();
  440. window.location.reload()
  441. } catch (error) {
  442. alert(error)
  443. console.log(error);
  444. $.bootstrapLoading.progressEnd();
  445. }
  446. }, DEBOUNCE_TIME, { leading: true }));
  447. // 显示空数据
  448. $showEmpty.click(() => {
  449. $('#empty-area').modal('show');
  450. });
  451. return {
  452. initData,
  453. handleSelectionChanged,
  454. curClass,
  455. reload,
  456. }
  457. })();