revise_price.js 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077
  1. 'use strict';
  2. /**
  3. *
  4. *
  5. * @author Mai
  6. * @date
  7. * @version
  8. */
  9. const showSideTools = function (show) {
  10. const left = $('#left-view'), right = $('#right-view'), parent = left.parent();
  11. if (show) {
  12. right.show();
  13. autoFlashHeight();
  14. const percent = 100 - right.outerWidth() /parent.width() * 100;
  15. left.css('width', percent + '%');
  16. } else {
  17. left.width(parent.width());
  18. right.hide();
  19. }
  20. };
  21. const setPriceHint = function (show) {
  22. const hinticon = show ? 'fa-bell' : undefined;
  23. subMiniMenu.$children[2].hinticon = hinticon;
  24. subMenu.$children[2].hinticon = hinticon;
  25. };
  26. $(document).ready(() => {
  27. const ledgerGclSpreadSetting = {
  28. cols: [
  29. { title: '清单编号', colSpan: '1', rowSpan: '2', field: 'b_code', hAlign: 0, width: 80, formatter: '@' },
  30. { title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 200, formatter: '@' },
  31. { title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 60, formatter: '@' },
  32. { title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 80, type: 'Number' },
  33. ],
  34. emptyRows: 0,
  35. headRows: 1,
  36. headRowHeight: [32],
  37. headColWidth: [30],
  38. defaultRowHeight: 21,
  39. headerFont: '12px 微软雅黑',
  40. font: '12px 微软雅黑',
  41. readOnly: true,
  42. };
  43. const ledgerXmjSpreadSetting = {
  44. cols: [
  45. {title: '项目节编号', colSpan: '1', rowSpan: '1', field: 'code', hAlign: 0, width: 100, formatter: '@'},
  46. {title: '单位工程', colSpan: '1', rowSpan: '1', field: 'dwgc', hAlign: 0, width: 80, formatter: '@'},
  47. {title: '分部工程', colSpan: '1', rowSpan: '1', field: 'fbgc', hAlign: 0, width: 80, formatter: '@'},
  48. {title: '分项工程', colSpan: '1', rowSpan: '1', field: 'fxgc', hAlign: 0, width: 80, formatter: '@'},
  49. {title: '细目', colSpan: '1', rowSpan: '1', field: 'jldy', hAlign: 0, width: 80, formatter: '@'},
  50. {title: '计量单元', colSpan: '1', rowSpan: '1', field: 'bwmx', hAlign: 0, width: 80, formatter: '@'},
  51. ],
  52. emptyRows: 0,
  53. headRows: 1,
  54. headRowHeight: [32],
  55. headColWidth: [30],
  56. defaultRowHeight: 21,
  57. headerFont: '12px 微软雅黑',
  58. font: '12px 微软雅黑',
  59. readOnly: true,
  60. };
  61. const priceSpreadSetting = {
  62. cols: [
  63. { title: '清单编号', colSpan: '1', rowSpan: '2', field: 'b_code', hAlign: 0, width: 100, formatter: '@', readOnly: true },
  64. { title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 210, formatter: '@', readOnly: true },
  65. { title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 60, formatter: '@', readOnly: true },
  66. { title: '当前单价', colSpan: '1', rowSpan: '2', field: 'org_price', hAlign: 2, width: 80, type: 'Number', readOnly: true },
  67. { title: '调整后单价', colSpan: '1', rowSpan: '2', field: 'new_price', hAlign: 2, width: 80, type: 'Number' },
  68. { title: '备注', colSpan: '1', rowSpan: '2', field: 'memo', hAlign: 2, width: 150, formatter: '@' },
  69. ],
  70. emptyRows: 0,
  71. headRows: 1,
  72. headRowHeight: [32],
  73. headColWidth: [30],
  74. defaultRowHeight: 21,
  75. headerFont: '12px 微软雅黑',
  76. font: '12px 微软雅黑',
  77. selectedBackColor: '#fffacd',
  78. readOnly,
  79. getColor: function (sheet, data, row, col, defaultColor) {
  80. if (!data) return defaultColor;
  81. if (data.rela_lid && data.rela_cid) return '#f5deb3';
  82. }
  83. };
  84. const priceBwSpreadSetting = {
  85. cols: [
  86. {title: '项目节编号', colSpan: '1', rowSpan: '1', field: 'code', hAlign: 0, width: 150, formatter: '@', cellType: 'tree'},
  87. {title: '清单编号', colSpan: '1', rowSpan: '1', field: 'b_code', hAlign: 0, width: 80, formatter: '@'},
  88. {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 230, formatter: '@'},
  89. {title: '单位', colSpan: '1', rowSpan: '1', field: 'unit', hAlign: 1, width: 60, formatter: '@'},
  90. {title: '原单价', colSpan: '1', rowSpan: '1', field: 'unit_price', hAlign: 2, width: 60, type: 'Number'},
  91. ],
  92. headRows: 1,
  93. emptyRows: 0,
  94. headRowHeight: [25],
  95. defaultRowHeight: 21,
  96. headerFont: '12px 微软雅黑',
  97. font: '12px 微软雅黑',
  98. readOnly: true,
  99. };
  100. sjsSettingObj.setFxTreeStyle(priceBwSpreadSetting, sjsSettingObj.FxTreeStyle.jz);
  101. const priceChangeSpreadSetting = {
  102. cols: [
  103. {title: '变更令', colSpan: '1', rowSpan: '1', field: 'code', hAlign: 0, width: 80, formatter: '@'},
  104. {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 230, formatter: '@'},
  105. {title: '批复文号', colSpan: '1', rowSpan: '1', field: 'w_code', hAlign: 1, width: 80, formatter: '@'},
  106. ],
  107. headRows: 1,
  108. emptyRows: 0,
  109. headRowHeight: [25],
  110. defaultRowHeight: 21,
  111. headerFont: '12px 微软雅黑',
  112. font: '12px 微软雅黑',
  113. readOnly: true,
  114. };
  115. autoFlashHeight();
  116. const bcontent = $(".bcontent-wrap").length > 0 ? $(".bcontent-wrap").height() : 0;
  117. $(".sp-wrap").height(bcontent-30);
  118. const priceSpread = SpreadJsObj.createNewSpread($('#price-spread')[0]);
  119. const priceSheet = priceSpread.getActiveSheet();
  120. const priceBwSpread = SpreadJsObj.createNewSpread($('#price-bw-spread')[0]);
  121. const priceBwSheet = priceBwSpread.getActiveSheet();
  122. const priceChangeSpread = SpreadJsObj.createNewSpread($('#price-change-spread')[0]);
  123. const priceChangeSheet = priceChangeSpread.getActiveSheet();
  124. SpreadJsObj.initSheet(priceSheet, priceSpreadSetting);
  125. SpreadJsObj.initSheet(priceBwSheet, priceBwSpreadSetting);
  126. SpreadJsObj.initSheet(priceChangeSheet, priceChangeSpreadSetting);
  127. class RevisePrice {
  128. constructor () {
  129. this.data = [];
  130. this.tree = createNewPathTree('filter', {
  131. id: 'ledger_id',
  132. pid: 'ledger_pid',
  133. order: 'order',
  134. level: 'level',
  135. rootId: -1,
  136. fullPath: 'full_path',
  137. keys: ['id', 'tender_id', 'ledger_id'],
  138. });
  139. }
  140. resortData() {
  141. this.data.sort(function (a, b) {
  142. return a.order - b.order;
  143. });
  144. }
  145. loadDatas(datas, treeData, changeData) {
  146. this.data = datas;
  147. this.tree.loadDatas(treeData);
  148. this.resortData();
  149. this.change = changeData;
  150. this.relaChange = [];
  151. if (this.data.length > 0) this.refreshRela(this.data[0]);
  152. }
  153. loadUpdateData(updateData) {
  154. if (updateData.add) {
  155. for (const a of updateData.add) {
  156. this.data.push(a);
  157. }
  158. }
  159. if (updateData.update) {
  160. for (const u of updateData.update) {
  161. const d = this.data.find(function (x) {
  162. return u.id === x.id;
  163. });
  164. if (d) {
  165. _.assign(d, u);
  166. } else {
  167. this.data.push(d);
  168. }
  169. }
  170. }
  171. if (updateData.del) {
  172. _.remove(this.data, function (d) {
  173. return updateData.del.indexOf(d.id) >= 0;
  174. });
  175. }
  176. this.resortData();
  177. }
  178. getSamePrice(price) {
  179. return this.data.filter(x => {
  180. if (x.id === price.id) return false;
  181. return x.b_code === price.b_code && x.name === price.name && x.unit === price.unit && x.org_price === price.org_price;
  182. });
  183. }
  184. refreshTreeRela(price, samePrice) {
  185. if (!samePrice) samePrice = this.getSamePrice(price);
  186. if (price.rela_lid) {
  187. this.tree.loadFilter(price.rela_lid);
  188. } else {
  189. const invalid = [];
  190. for (const sp of samePrice) {
  191. const lid = sp.rela_lid ? sp.rela_lid.split(',') : [];
  192. invalid.push(...lid);
  193. }
  194. this.tree.loadFilter(invalid.join(','), 'filter');
  195. }
  196. console.log(this.tree.nodes.find(x => { return x.code === '1'}));
  197. console.log(this.tree.nodes.find(x => { return x.code === '1-2'}));
  198. console.log(this.tree.nodes.find(x => { return x.code === '1-2-2'}));
  199. }
  200. refreshChangeRela(price, samePrice) {
  201. if (!samePrice) samePrice = this.getSamePrice(price);
  202. if (price.rela_cid) {
  203. const choose = price.rela_cid.split(',');
  204. for (const c of this.change) {
  205. c.rela = choose.indexOf(c.cid + '') >= 0;
  206. c.valid = !!c.rela;
  207. }
  208. } else if (readOnly && price.his_rela_cid) {
  209. const his = price.his_rela_cid.split(',');
  210. for (const c of this.change) {
  211. c.rela = his.indexOf(c.cid + '') >= 0;
  212. c.valid = !!c.rela;
  213. }
  214. } else {
  215. const invalid = [];
  216. for (const sp of samePrice) {
  217. const cid = sp.rela_cid ? sp.rela_cid.split(',') : [];
  218. invalid.push(...cid);
  219. }
  220. for (const c of this.change) {
  221. c.rela = invalid.indexOf(c.cid + '') >= 0;
  222. if (c.rela) {
  223. c.valid = 0;
  224. } else {
  225. const exist = c.bills.find(x => {
  226. return x.code === price.b_code && x.name === price.name && x.unit === price.unit && x.unit_price === price.org_price;
  227. });
  228. c.valid = !!exist;
  229. }
  230. }
  231. }
  232. this.relaChange.length = 0;
  233. for (const c of this.change) {
  234. if (c.valid){
  235. this.relaChange.push(c);
  236. c.visible = true;
  237. }
  238. }
  239. }
  240. refreshRela(price) {
  241. const samePrice = this.getSamePrice(price);
  242. this.refreshTreeRela(price, samePrice);
  243. this.refreshChangeRela(price, samePrice);
  244. }
  245. }
  246. const revisePrice = new RevisePrice();
  247. const priceOprObj = {
  248. addRevisePrice(data) {
  249. const op = revisePrice.data.find(x => {
  250. return x.b_code === data.b_code && x.name === x.name && x.unit === x.unit && checkZero(ZhCalc.sub(x.org_price, data.unit_price)) && (!x.rela_lid || !x.rela_cid);
  251. });
  252. if (op) {
  253. toastr.warning('已存在该单价调整');
  254. SpreadJsObj.locateData(priceSheet, op);
  255. return;
  256. }
  257. postData(window.location.pathname + '/update', { add: { b_code: data.b_code, name: data.name, unit: data.unit, unit_price: data.unit_price } }, result => {
  258. revisePrice.loadUpdateData(result);
  259. SpreadJsObj.reLoadSheetData(priceSheet);
  260. setPriceHint(revisePrice.data.length > 0);
  261. });
  262. },
  263. addRevisePrices(datas) {
  264. if (datas.length === 0) {
  265. toastr.warning('请选择需要调整单价的清单');
  266. return;
  267. }
  268. const add = [];
  269. for (const data of datas) {
  270. const op = revisePrice.data.find(x => {
  271. return x.b_code === data.b_code && x.name === x.name && x.unit === x.unit && checkZero(ZhCalc.sub(x.org_price, data.unit_price)) && (!x.rela_lid || !x.rela_cid);
  272. });
  273. if (op) continue;
  274. add.push({ b_code: data.b_code, name: data.name, unit: data.unit, unit_price: data.unit_price });
  275. }
  276. if (add.length === 0) {
  277. toastr.warning('已存在该单价调整');
  278. return;
  279. }
  280. postData(window.location.pathname + '/update', { add }, result => {
  281. revisePrice.loadUpdateData(result);
  282. SpreadJsObj.reLoadSheetData(priceSheet);
  283. setPriceHint(revisePrice.data.length > 0);
  284. });
  285. },
  286. /**
  287. * 删除按钮响应事件
  288. * @param sheet
  289. */
  290. deletePress: function (sheet) {
  291. if (!sheet.zh_setting || readOnly) return;
  292. const sortData = sheet.zh_data;
  293. const datas = [];
  294. const sels = sheet.getSelections();
  295. if (!sels || !sels[0]) return;
  296. for (let iRow = sels[0].row; iRow < sels[0].row + sels[0].rowCount; iRow++) {
  297. let bDel = false;
  298. const node = sortData[iRow];
  299. if (node) {
  300. const data = {id: node.id};
  301. for (let iCol = sels[0].col; iCol < sels[0].col + sels[0].colCount; iCol++) {
  302. const style = sheet.getStyle(iRow, iCol);
  303. if (!style.locked) {
  304. const colSetting = sheet.zh_setting.cols[iCol];
  305. data[colSetting.field] = null;
  306. bDel = true;
  307. }
  308. }
  309. if (bDel) {
  310. datas.push(data);
  311. }
  312. }
  313. }
  314. if (datas.length > 0) {
  315. postData(window.location.pathname + '/update', {update: datas}, function (result) {
  316. revisePrice.loadUpdateData(result);
  317. SpreadJsObj.reLoadSheetData(priceSheet);
  318. }, function () {
  319. SpreadJsObj.reLoadSheetData(priceSheet);
  320. });
  321. }
  322. },
  323. delete: function (sheet) {
  324. if (!sheet.zh_setting || readOnly) return;
  325. const sortData = sheet.zh_data;
  326. const datas = [];
  327. const sels = sheet.getSelections();
  328. if (!sels || !sels[0]) return;
  329. for (let iRow = sels[0].row, iLen = sels[0].row + sels[0].rowCount; iRow < iLen; iRow++) {
  330. const node = sortData[iRow];
  331. datas.push(node.id);
  332. }
  333. if (datas.length > 0) {
  334. postData(window.location.pathname + '/update', {del: datas}, function (result) {
  335. revisePrice.loadUpdateData(result);
  336. SpreadJsObj.reLoadSheetData(priceSheet);
  337. setPriceHint(revisePrice.data.length > 0);
  338. }, function () {
  339. SpreadJsObj.reLoadSheetData(priceSheet);
  340. });
  341. }
  342. },
  343. editEnded: function (e, info) {
  344. if (!info.sheet.zh_setting || !info.sheet.zh_data) return;
  345. const node = info.sheet.zh_data[info.row];
  346. if (!node) return;
  347. const col = info.sheet.zh_setting.cols[info.col];
  348. const data = { update: { id: node.id, org_price: node.org_price } };
  349. const oldValue = node ? node[col.field] : null;
  350. const newValue = trimInvalidChar(info.editingText);
  351. if (oldValue == info.editingText || ((!oldValue || oldValue === '') && (newValue === ''))) {
  352. SpreadJsObj.reLoadRowData(info.sheet, info.row);
  353. return;
  354. }
  355. if (col.type === 'Number') {
  356. const num = _.toNumber(newValue);
  357. if (num) data.update[col.field] = num;
  358. } else {
  359. data.update[col.field] = newValue;
  360. }
  361. postData(window.location.pathname + '/update', data, function (result) {
  362. revisePrice.loadUpdateData(result);
  363. SpreadJsObj.reLoadSheetData(info.sheet);
  364. }, function () {
  365. SpreadJsObj.reLoadRowData(info.sheet, info.row);
  366. });
  367. },
  368. clipboardPasting(e, info) {
  369. const setting = info.sheet.zh_setting, sortData = info.sheet.zh_data;
  370. info.cancel = true;
  371. if (!setting || !sortData) return;
  372. const pasteData = info.pasteData.html
  373. ? SpreadJsObj.analysisPasteHtml(info.pasteData.html)
  374. : (info.pasteData.text === ''
  375. ? SpreadJsObj.Clipboard.getAnalysisPasteText()
  376. : SpreadJsObj.analysisPasteText(info.pasteData.text));
  377. const uDatas = [];
  378. for (let iRow = 0; iRow < info.cellRange.rowCount; iRow++) {
  379. const curRow = info.cellRange.row + iRow;
  380. const node = sortData[curRow];
  381. let bPaste = false;
  382. const data = {};
  383. for (let iCol = 0; iCol < info.cellRange.colCount; iCol++) {
  384. const curCol = info.cellRange.col + iCol;
  385. const colSetting = setting.cols[curCol];
  386. const value = trimInvalidChar(pasteData[iRow][iCol]);
  387. if (colSetting.type === 'Number') {
  388. const num = _.toNumber(value);
  389. if (num) {
  390. data[colSetting.field] = num;
  391. bPaste = true;
  392. }
  393. } else {
  394. data[colSetting.field] = value;
  395. bPaste = true;
  396. }
  397. }
  398. if (bPaste) {
  399. data.id = node.id;
  400. uDatas.push(data);
  401. }
  402. }
  403. const updateData = {};
  404. if (uDatas.length > 0) updateData.update = uDatas;
  405. if (uDatas.length > 0) {
  406. postData(window.location.pathname + '/update', updateData, function (result) {
  407. revisePrice.loadUpdateData(result);
  408. SpreadJsObj.reLoadSheetData(info.sheet);
  409. });
  410. } else {
  411. SpreadJsObj.reLoadSheetData(info.sheet);
  412. }
  413. },
  414. upMove: function () {
  415. const sels = priceSheet.getSelections(), sortData = priceSheet.zh_data;
  416. const node = sortData[sels[0].row];
  417. const preNode = sortData[sels[0].row - 1];
  418. const data = [
  419. {id: node.id, order: preNode.order},
  420. {id: preNode.id, order: node.order}
  421. ];
  422. postData(window.location.pathname + '/update', {update: data}, function (result) {
  423. revisePrice.loadUpdateData(result);
  424. SpreadJsObj.reLoadRowsData(priceSheet, [sels[0].row, sels[0].row - 1]);
  425. priceSheet.setSelection(sels[0].row - 1, sels[0].col, sels[0].rowCount, sels[0].colCount);
  426. });
  427. },
  428. downMove: function () {
  429. const sels = priceSheet.getSelections(), sortData = priceSheet.zh_data;
  430. const node = sortData[sels[0].row];
  431. const nextNode = sortData[sels[0].row + 1];
  432. const data = [
  433. {id: node.id, order: nextNode.order},
  434. {id: nextNode.id, order: node.order}
  435. ];
  436. postData(window.location.pathname + '/update', {update: data}, function (result) {
  437. revisePrice.loadUpdateData(result);
  438. SpreadJsObj.reLoadRowsData(priceSheet, [sels[0].row, sels[0].row + 1]);
  439. priceSheet.setSelection(sels[0].row + 1, sels[0].col, sels[0].rowCount, sels[0].colCount);
  440. });
  441. },
  442. updateRelaLid: function (price, rela_lid) {
  443. const data = { update: { id: price.id, rela_lid } };
  444. postData(window.location.pathname + '/update', data, function (result) {
  445. revisePrice.loadUpdateData(result);
  446. revisePrice.refreshTreeRela(price);
  447. SpreadJsObj.refreshTreeRowVisible(priceBwSheet);
  448. SpreadJsObj.reloadRowBackColor(priceSheet, revisePrice.data.indexOf(price));
  449. });
  450. },
  451. updateRelaCid: function (price, rela_cid) {
  452. const data = { update: { id: price.id, rela_cid } };
  453. postData(window.location.pathname + '/update', data, function (result) {
  454. revisePrice.loadUpdateData(result);
  455. revisePrice.refreshChangeRela(price);
  456. SpreadJsObj.reLoadSheetData(priceChangeSheet);
  457. SpreadJsObj.reloadRowBackColor(priceSheet, revisePrice.data.indexOf(price));
  458. });
  459. },
  460. selectionChanged: function () {
  461. const price = SpreadJsObj.getSelectObject(priceSheet);
  462. revisePrice.refreshRela(price);
  463. SpreadJsObj.refreshTreeRowVisible(priceBwSheet);
  464. SpreadJsObj.reLoadSheetData(priceChangeSheet);
  465. },
  466. };
  467. if (!readOnly) {
  468. priceSheet.bind(spreadNS.Events.EditEnded, priceOprObj.editEnded);
  469. priceSheet.bind(spreadNS.Events.ClipboardPasting, priceOprObj.clipboardPasting);
  470. SpreadJsObj.addDeleteBind(priceSpread, priceOprObj.deletePress);
  471. $.contextMenu({
  472. selector: '#price-spread',
  473. build: function ($trigger, e) {
  474. const target = SpreadJsObj.safeRightClickSelection($trigger, e, priceSpread);
  475. return target.hitTestType === spreadNS.SheetArea.viewport || target.hitTestType === spreadNS.SheetArea.rowHeader;
  476. },
  477. items: {
  478. del: {
  479. name: '删除',
  480. icon: 'fa-remove',
  481. callback: function (key, opt) {
  482. priceOprObj.delete(priceSheet);
  483. },
  484. disabled: function (key, opt) {
  485. const node = SpreadJsObj.getSelectObject(priceSheet);
  486. return node === undefined || node === null;
  487. },
  488. visible: function (key, opt) {
  489. return !readOnly;
  490. }
  491. },
  492. sprDel: '----',
  493. upMove: {
  494. name: '上移',
  495. icon: 'fa-arrow-up',
  496. callback: function (key, opt) {
  497. priceOprObj.upMove();
  498. },
  499. disabled: function (key, opt) {
  500. const sels = priceSheet.getSelections();
  501. if (!sels || !sels[0] || sels[0].row === 0) return true;
  502. const row = sels[0].row;
  503. const node = revisePrice.data[row];
  504. return node === undefined || node === null;
  505. },
  506. visible: function (key, opt) {
  507. return !readOnly;
  508. }
  509. },
  510. downMove: {
  511. name: '下移',
  512. icon: 'fa-arrow-down',
  513. callback: function (key, opt) {
  514. priceOprObj.downMove();
  515. },
  516. disabled: function (key, opt) {
  517. const sels = priceSheet.getSelections();
  518. if (!sels || !sels[0] || sels[0].row >= revisePrice.data.length - 1) return true;
  519. const row = sels[0].row;
  520. const node = revisePrice.data[row];
  521. return node === undefined || node === null;
  522. },
  523. visible: function (key, opt) {
  524. return !readOnly;
  525. }
  526. },
  527. sprMove: '----',
  528. chooseRelaBw: {
  529. name: '选择应用部位',
  530. icon: 'fa-link',
  531. callback: function (key, opt) {
  532. const price = SpreadJsObj.getSelectObject(priceSheet);
  533. const samePrice = revisePrice.getSamePrice(price);
  534. chooseRelaBw.show(price, samePrice);
  535. },
  536. disabled: function (key, opt) {
  537. const node = SpreadJsObj.getSelectObject(priceSheet);
  538. return !node;
  539. },
  540. visible: function (key, opt) {
  541. return !readOnly;
  542. }
  543. },
  544. chooseRelaChange: {
  545. name: '选择应用变更令',
  546. icon: 'fa-link',
  547. callback: function (key, opt) {
  548. const price = SpreadJsObj.getSelectObject(priceSheet);
  549. const samePrice = revisePrice.getSamePrice(price);
  550. chooseRelaChange.show(price, samePrice);
  551. },
  552. disabled: function (key, opt) {
  553. const node = SpreadJsObj.getSelectObject(priceSheet);
  554. return !node;
  555. },
  556. visible: function (key, opt) {
  557. return !readOnly;
  558. }
  559. },
  560. noRelaChange: {
  561. name: '不应用于变更令',
  562. icon: 'fa-unlink',
  563. callback: function (key, opt) {
  564. const price = SpreadJsObj.getSelectObject(priceSheet);
  565. priceOprObj.updateRelaCid(price, '-1');
  566. },
  567. disabled: function (key, opt) {
  568. const node = SpreadJsObj.getSelectObject(priceSheet);
  569. return !node;
  570. },
  571. visible: function (key, opt) {
  572. return !readOnly;
  573. }
  574. },
  575. },
  576. });
  577. }
  578. priceSpread.bind(spreadNS.Events.SelectionChanged, priceOprObj.selectionChanged);
  579. class LedgerGcl {
  580. constructor(setting) {
  581. const self = this;
  582. this.setting = setting;
  583. this.spread = SpreadJsObj.createNewSpread($(this.setting.selector)[0]);
  584. this.sheet = this.spread.getActiveSheet();
  585. SpreadJsObj.initSheet(this.sheet, this.setting.spreadSetting);
  586. this.xmjSpread = SpreadJsObj.createNewSpread($(this.setting.xmjSelector)[0]);
  587. this.xmjSheet = this.xmjSpread.getActiveSheet();
  588. SpreadJsObj.initSheet(this.xmjSheet, this.setting.xmjSpreadSetting);
  589. if (!readOnly) {
  590. this.spread.bind(spreadNS.Events.CellDoubleClick, function (e, info) {
  591. const gcl = SpreadJsObj.getSelectObject(info.sheet);
  592. priceOprObj.addRevisePrice(gcl);
  593. });
  594. $.contextMenu({
  595. selector: setting.selector,
  596. build: function ($trigger, e) {
  597. const target = SpreadJsObj.safeRightClickSelection($trigger, e, self.spread);
  598. return target.hitTestType === spreadNS.SheetArea.viewport || target.hitTestType === spreadNS.SheetArea.rowHeader;
  599. },
  600. items: {
  601. del: {
  602. name: '添加',
  603. icon: 'fa-sign-in',
  604. callback: function (key, opt) {
  605. const datas = [];
  606. const sel = self.sheet.getSelections()[0];
  607. const node = self.sheet.zh_data[sel.row];
  608. datas.push(node);
  609. if (sel.rowCount > 1) {
  610. for (let r = 1; r < sel.rowCount; r++) {
  611. const rNode = self.sheet.zh_data[sel.row + r];
  612. if (rNode) datas.push(rNode);
  613. }
  614. }
  615. priceOprObj.addRevisePrices(datas);
  616. },
  617. },
  618. },
  619. });
  620. }
  621. this.spread.bind(spreadNS.Events.SelectionChanged, function (e, info) {
  622. self.loadLeafXmj();
  623. });
  624. }
  625. loadData(bills, pos) {
  626. gclGatherModel.loadLedgerData(bills);
  627. gclGatherModel.loadPosData(pos);
  628. this.gcl = gclGatherModel.gatherGclData();
  629. this.sheet && SpreadJsObj.loadSheetData(this.sheet, SpreadJsObj.DataType.Data, this.gcl);
  630. this.loadLeafXmj(0);
  631. }
  632. loadLeafXmj(iGclRow) {
  633. const gcl = iGclRow ? this.gcl[iGclRow] : SpreadJsObj.getSelectObject(this.sheet);
  634. SpreadJsObj.resetTopAndSelect(this.xmjSheet);
  635. if (gcl) {
  636. SpreadJsObj.loadSheetData(this.xmjSheet, SpreadJsObj.DataType.Data, gcl.leafXmjs);
  637. } else {
  638. SpreadJsObj.loadSheetData(this.xmjSheet, SpreadJsObj.DataType.Data, []);
  639. }
  640. }
  641. }
  642. const ledgerGcl = new LedgerGcl({
  643. selector: '#ledger-gcl-spread',
  644. spreadSetting: ledgerGclSpreadSetting,
  645. xmjSelector: '#ledger-xmj-spread',
  646. xmjSpreadSetting: ledgerXmjSpreadSetting,
  647. });
  648. $.subMenu({
  649. menu: '#sub-menu', miniMenu: '#sub-mini-menu', miniMenuList: '#mini-menu-list',
  650. toMenu: '#to-menu', toMiniMenu: '#to-mini-menu',
  651. key: 'menu.1.0.0',
  652. miniHint: '#sub-mini-hint', hintKey: 'menu.hint.1.0.1',
  653. callback: function (info) {
  654. if (info.mini) {
  655. $('.panel-title').addClass('fluid');
  656. $('#sub-menu').removeClass('panel-sidebar');
  657. } else {
  658. $('.panel-title').removeClass('fluid');
  659. $('#sub-menu').addClass('panel-sidebar');
  660. }
  661. autoFlashHeight();
  662. priceSpread.refresh();
  663. ledgerGcl.spread.refresh();
  664. priceBwSpread.refresh();
  665. priceChangeSpread.refresh();
  666. }
  667. });
  668. $.divResizer({
  669. select: '#revise-right-spr',
  670. callback: function () {
  671. priceSpread.refresh();
  672. priceBwSpread.refresh();
  673. priceChangeSpread.refresh();
  674. ledgerGcl.spread.refresh();
  675. ledgerGcl.xmjSpread.refresh();
  676. }
  677. });
  678. $.divResizer({
  679. select: '#gcl-spr',
  680. callback: function () {
  681. ledgerGcl.spread.refresh();
  682. ledgerGcl.xmjSpread.refresh();
  683. }
  684. });
  685. $.divResizer({
  686. select: '#price-resize',
  687. callback: function () {
  688. priceSpread.refresh();
  689. let bcontent = $(".bcontent-wrap").length > 0 ? $(".bcontent-wrap").height() : 0;
  690. $(".sp-wrap").height(bcontent-30);
  691. priceBwSpread.refresh();
  692. priceChangeSpread.refresh();
  693. }
  694. });
  695. class ChooseRelaBw {
  696. constructor() {
  697. const self = this;
  698. this.tree = createNewPathTree('ledger', {
  699. id: 'ledger_id',
  700. pid: 'ledger_pid',
  701. order: 'order',
  702. level: 'level',
  703. rootId: -1,
  704. fullPath: 'full_path',
  705. keys: ['id', 'tender_id', 'ledger_id'],
  706. });
  707. $('#choose-rela-bw').on('shown.bs.modal', function() {
  708. self.initSpread();
  709. SpreadJsObj.reloadColData(self.sheet, 0, 1);
  710. SpreadJsObj.reloadRowBackColor(self.sheet, 0, self.tree.nodes.length);
  711. });
  712. $('#choose-rela-bw-ok').click(function() {
  713. const choose_lid = [];
  714. self.tree.nodes.forEach(x => {
  715. if (x.check) choose_lid.push(x.ledger_id);
  716. });
  717. priceOprObj.updateRelaLid(self.price, choose_lid.join(','));
  718. $('#choose-rela-bw').modal('hide');
  719. });
  720. }
  721. get locate() {
  722. return this._locate;
  723. }
  724. set locate(value) {
  725. if (!this.searchResult || this.searchResult.length === 0) return;
  726. this._locate = !value || value >= this.searchResult.length ? 0 : (value < 0 ? this.searchResult.length - 1 : value);
  727. SpreadJsObj.locateTreeNode(this.sheet, this.searchResult[this._locate].ledger_id, true);
  728. }
  729. search(keyword) {
  730. this.searchResult = [];
  731. for (const node of this.tree.nodes) {
  732. const code = node.code || '', name = node.name || '', b_code = node.b_code || '';
  733. if (code.indexOf(keyword) >= 0 || b_code.indexOf(keyword) >= 0 || name.indexOf(keyword) >= 0) this.searchResult.push(node);
  734. }
  735. $('#rela-bw-search-result').html(`结果:${this.searchResult.length}`);
  736. this.locate = 0;
  737. }
  738. initSpread() {
  739. if (this.spread) return;
  740. this.spread = SpreadJsObj.createNewSpread($('#rela-bw-spread')[0]);
  741. this.sheet = this.spread.getActiveSheet();
  742. const spreadSetting = {
  743. cols: [
  744. {title: '选择', colSpan: '1', rowSpan: '1', field: 'check', hAlign: 1, width: 50, formatter: '@', cellType: 'checkbox'},
  745. {title: '项目节编号', colSpan: '1', rowSpan: '1', field: 'code', hAlign: 0, width: 150, formatter: '@', cellType: 'tree'},
  746. {title: '清单编号', colSpan: '1', rowSpan: '1', field: 'b_code', hAlign: 0, width: 80, formatter: '@'},
  747. {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 230, formatter: '@'},
  748. {title: '单位', colSpan: '1', rowSpan: '1', field: 'unit', hAlign: 1, width: 60, formatter: '@'},
  749. {title: '原单价', colSpan: '1', rowSpan: '1', field: 'unit_price', hAlign: 2, width: 60, type: 'Number'},
  750. ],
  751. headRows: 1,
  752. emptyRows: 0,
  753. headRowHeight: [25],
  754. defaultRowHeight: 21,
  755. headerFont: '12px 微软雅黑',
  756. font: '12px 微软雅黑',
  757. readOnly: true,
  758. getColor: function (sheet, data, row, col, defaultColor) {
  759. return data && data.invalid ? '#dddddd' : defaultColor;
  760. }
  761. };
  762. sjsSettingObj.setFxTreeStyle(spreadSetting, sjsSettingObj.FxTreeStyle.jz);
  763. SpreadJsObj.initSheet(this.sheet, spreadSetting);
  764. const self = this;
  765. this.spread.bind(spreadNS.Events.ButtonClicked, function (e, info) {
  766. function checkInvalid(node) {
  767. if (node.invalid) return 1;
  768. if (self.tree.checkParent(node, 'invalid')) return 2;
  769. if (self.tree.checkChildren(node, 'invalid')) return 3;
  770. return 0;
  771. }
  772. const sheet = info.sheet, cellType = sheet.getCellType(info.row, info.col);
  773. if (!sheet.zh_setting) return;
  774. if (cellType instanceof spreadNS.CellTypes.CheckBox) {
  775. if (sheet.isEditing()) sheet.endEdit(true);
  776. }
  777. const col = sheet.zh_setting.cols[info.col];
  778. if (col.field !== 'check') return;
  779. const tree = sheet.zh_tree;
  780. const node = SpreadJsObj.getSelectObject(sheet);
  781. if (node.b_code) {
  782. toastr.warning('请选择部位');
  783. return;
  784. }
  785. if (!node.check) {
  786. const invalid = checkInvalid(node);
  787. const invalidHint = ['该部位已被选择,请勿重复选择', '该部位的父项已被选择,请勿选择', '该部位的子项已被选择,请勿在其子项中选择'];
  788. if (invalid) {
  789. toastr.warning(invalidHint[invalid-1]);
  790. return;
  791. }
  792. if (self.tree.checkParent(node)) {
  793. const rect = info.sheet.getCellRect(info.row, info.col);
  794. self.chooseConfirmPopover({
  795. x: rect.x + rect.width / 2 + 25,
  796. y: rect.y + rect.height / 2 + 3,
  797. }, '父项已勾选,继续将取消父项勾选。', function () {
  798. node.check = true;
  799. const parents = tree.getFullPathNodes(tree.getParent(node).full_path);
  800. const rows = [tree.nodes.indexOf(node)];
  801. for (const p of parents) {
  802. if (p.check) {
  803. p.check = false;
  804. rows.push(tree.nodes.indexOf(p));
  805. }
  806. }
  807. SpreadJsObj.reLoadRowsData(info.sheet, rows);
  808. });
  809. } else if (self.tree.checkChildren(node)) {
  810. const rect = info.sheet.getCellRect(info.row, info.col);
  811. self.chooseConfirmPopover({
  812. x: rect.x + rect.width / 2 + 25,
  813. y: rect.y + rect.height / 2 + 3,
  814. }, '子项已勾选,继续将取消子项勾选。', function () {
  815. node.check = true;
  816. const posterity = tree.getPosterity(node);
  817. const rows = [tree.nodes.indexOf(node)];
  818. for (const p of posterity) {
  819. if (p.check) {
  820. rows.push(tree.nodes.indexOf(p));
  821. p.check = false;
  822. }
  823. }
  824. SpreadJsObj.reLoadRowsData(info.sheet, rows);
  825. });
  826. } else {
  827. node.check = true;
  828. SpreadJsObj.reLoadRowsData(info.sheet, [info.row]);
  829. }
  830. } else {
  831. node.check = false;
  832. SpreadJsObj.reLoadRowsData(info.sheet, [info.row]);
  833. }
  834. });
  835. SpreadJsObj.loadSheetData(this.sheet, SpreadJsObj.DataType.Tree, this.tree);
  836. (function (select, sheet) {
  837. $(select).click(function () {
  838. if (!sheet.zh_tree) return;
  839. const tag = $(this).attr('tag');
  840. const tree = sheet.zh_tree;
  841. setTimeout(() => {
  842. showWaitingView();
  843. switch (tag) {
  844. case "1":
  845. case "2":
  846. case "3":
  847. case "4":
  848. case "5":
  849. tree.expandByLevel(parseInt(tag));
  850. SpreadJsObj.refreshTreeRowVisible(sheet);
  851. break;
  852. case "last":
  853. tree.expandByCustom(() => { return true; });
  854. SpreadJsObj.refreshTreeRowVisible(sheet);
  855. break;
  856. case "leafXmj":
  857. tree.expandToLeafXmj();
  858. SpreadJsObj.refreshTreeRowVisible(sheet);
  859. break;
  860. }
  861. closeWaitingView();
  862. }, 100);
  863. });
  864. })('a[name=showLevel]', this.sheet);
  865. $('#rela-bw-search-keyword').change(function () {
  866. self.search(this.value);
  867. });
  868. $('#rela-bw-search-pre').click(function () {
  869. self.locate = self.locate - 1;
  870. });
  871. $('#rela-bw-search-next').click(function () {
  872. self.locate = self.locate + 1;
  873. });
  874. }
  875. reBind(obj, eventName, fun) {
  876. obj.unbind(eventName);
  877. obj.bind(eventName, fun);
  878. }
  879. chooseConfirmPopover(pos, hint, okCallback) {
  880. const confirmObj = $('#choose-confirm'), hintObj = $('#choose-confirm-hint');
  881. const okObj = $('#choose-confirm-ok'), cancelObj = $('#choose-confirm-cancel');
  882. this.reBind(cancelObj, 'click', function () {
  883. confirmObj.hide();
  884. });
  885. this.reBind(okObj, 'click', function () {
  886. okCallback();
  887. confirmObj.hide();
  888. });
  889. hintObj.text(hint);
  890. confirmObj.css("top", pos.y).css("left", pos.x).show();
  891. }
  892. loadTree(data) {
  893. this.tree.loadDatas(data);
  894. }
  895. show(price, samePrice){
  896. this.price = price;
  897. this.choose = price.rela_lid ? price.rela_lid.split(',') : [];
  898. this.invalid = [];
  899. for (const sp of samePrice) {
  900. const lid = sp.rela_lid ? sp.rela_lid.split(',') : [];
  901. this.invalid.push(...lid);
  902. }
  903. for (const node of this.tree.nodes) {
  904. node.check = this.choose.indexOf(node.ledger_id + '') >= 0;
  905. node.invalid = this.invalid.indexOf(node.ledger_id + '') >= 0;
  906. }
  907. $('#choose-rela-bw').modal('show');
  908. }
  909. }
  910. const chooseRelaBw = new ChooseRelaBw();
  911. class ChooseRelaChange {
  912. constructor (){
  913. const self = this;
  914. $('#choose-rela-change').on('shown.bs.modal', function() {
  915. self.initSpread();
  916. SpreadJsObj.reloadColData(self.sheet, 0, 1);
  917. SpreadJsObj.reloadRowBackColor(self.sheet, 0, self.change.length);
  918. });
  919. $('#choose-rela-change-ok').click(function() {
  920. const choose_cid = [];
  921. self.change.forEach(x => {
  922. if (x.check) choose_cid.push(x.cid);
  923. });
  924. priceOprObj.updateRelaCid(self.price, choose_cid.join(','));
  925. $('#choose-rela-change').modal('hide');
  926. });
  927. }
  928. initSpread() {
  929. if (this.spread) return;
  930. this.spread = SpreadJsObj.createNewSpread($('#rela-change-spread')[0]);
  931. this.sheet = this.spread.getActiveSheet();
  932. const spreadSetting = {
  933. cols: [
  934. {title: '选择', colSpan: '1', rowSpan: '1', field: 'check', hAlign: 1, width: 50, formatter: '@', cellType: 'checkbox'},
  935. {title: '变更令', colSpan: '1', rowSpan: '1', field: 'code', hAlign: 0, width: 150, formatter: '@'},
  936. {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 230, formatter: '@'},
  937. {title: '单位', colSpan: '1', rowSpan: '1', field: 'unit', hAlign: 1, width: 60, formatter: '@'},
  938. ],
  939. headRows: 1,
  940. emptyRows: 0,
  941. headRowHeight: [25],
  942. defaultRowHeight: 21,
  943. headerFont: '12px 微软雅黑',
  944. font: '12px 微软雅黑',
  945. readOnly: true,
  946. getColor: function (sheet, data, row, col, defaultColor) {
  947. return data && data.invalid ? '#dddddd' : defaultColor;
  948. }
  949. };
  950. SpreadJsObj.initSheet(this.sheet, spreadSetting);
  951. this.spread.bind(spreadNS.Events.ButtonClicked, function (e, info) {
  952. const sheet = info.sheet, cellType = sheet.getCellType(info.row, info.col);
  953. if (!sheet.zh_setting) return;
  954. if (cellType instanceof spreadNS.CellTypes.CheckBox) {
  955. if (sheet.isEditing()) sheet.endEdit(true);
  956. }
  957. const col = sheet.zh_setting.cols[info.col];
  958. if (col.field !== 'check') return;
  959. const node = SpreadJsObj.getSelectObject(sheet);
  960. if (!node.check) {
  961. if (node.invalid) return;
  962. node.check = true;
  963. SpreadJsObj.reLoadRowsData(info.sheet, [info.row]);
  964. } else {
  965. node.check = false;
  966. SpreadJsObj.reLoadRowsData(info.sheet, [info.row]);
  967. }
  968. });
  969. SpreadJsObj.loadSheetData(this.sheet, SpreadJsObj.DataType.Data, this.change);
  970. }
  971. loadChange(data) {
  972. this.change = data;
  973. }
  974. show(price, samePrice) {
  975. this.price = price;
  976. this.choose = price.rela_cid ? price.rela_cid.split(',') : [];
  977. this.invalid = [];
  978. for (const sp of samePrice) {
  979. const cid = sp.rela_cid ? sp.rela_cid.split(',') : [];
  980. this.invalid.push(...cid);
  981. }
  982. for (const c of this.change) {
  983. c.visible = true;
  984. c.check = this.choose.indexOf(c.cid + '') >= 0;
  985. c.invalid = this.invalid.indexOf(c.cid + '') >= 0;
  986. if (!c.check && !c.invalid) {
  987. const exist = c.bills.find(x => {
  988. return x.code === price.b_code && x.name === price.name && x.unit === price.unit && x.unit_price === price.org_price;
  989. });
  990. c.visible = !!exist;
  991. }
  992. }
  993. if (this.sheet) SpreadJsObj.refreshTreeRowVisible(this.sheet);
  994. $('#choose-rela-change').modal('show');
  995. }
  996. }
  997. const chooseRelaChange = new ChooseRelaChange();
  998. postData('load', { filter: 'bills;pos;price;change' }, result => {
  999. revisePrice.loadDatas(result.price, result.bills, result.change);
  1000. SpreadJsObj.loadSheetData(priceSheet, SpreadJsObj.DataType.Data, revisePrice.data);
  1001. ledgerGcl.loadData(result.bills, result.pos);
  1002. chooseRelaBw.loadTree(result.bills);
  1003. chooseRelaChange.loadChange(result.change);
  1004. SpreadJsObj.loadSheetData(priceBwSheet, SpreadJsObj.DataType.Tree, revisePrice.tree);
  1005. SpreadJsObj.loadSheetData(priceChangeSheet, SpreadJsObj.DataType.Data, revisePrice.relaChange);
  1006. $("[content='#ledgerGcl']").click();
  1007. });
  1008. $('a', '#side-menu').bind('click', function (e) {
  1009. e.preventDefault();
  1010. const tab = $(this), tabPanel = $(tab.attr('content'));
  1011. // 展开工具栏、切换标签
  1012. if (!tab.hasClass('active')) {
  1013. $('a', '#side-menu').removeClass('active');
  1014. tab.addClass('active');
  1015. $('#right-view .tab-pane').removeClass('active');
  1016. tabPanel.addClass('active');
  1017. showSideTools(tab.hasClass('active'));
  1018. ledgerGcl.spread.refresh();
  1019. ledgerGcl.xmjSpread.refresh();
  1020. } else {// 收起工具栏
  1021. tab.removeClass('active');
  1022. tabPanel.removeClass('active');
  1023. showSideTools(tab.hasClass('active'));
  1024. }
  1025. priceSpread.refresh();
  1026. priceBwSpread.refresh();
  1027. priceChangeSpread.refresh();
  1028. });
  1029. $('a', '.bcontent-wrap').click(function() {
  1030. $('[name=priceRela]').removeClass('active');
  1031. $(this).addClass('active');
  1032. $('#priceRelaTab').children().removeClass('active');
  1033. $(this.getAttribute('href')).addClass('active');
  1034. priceBwSpread.refresh();
  1035. priceChangeSpread.refresh();
  1036. });
  1037. });