material.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. 'use strict';
  2. /**
  3. * 材料调差 - 调差工料
  4. *
  5. * @author Mai
  6. * @date 2019/1/16
  7. * @version
  8. */
  9. $(document).ready(() => {
  10. autoFlashHeight();
  11. const materialSpread = SpreadJsObj.createNewSpread($('#material-spread')[0]);
  12. SpreadJsObj.initSheet(materialSpread.getActiveSheet(), billsSpreadSetting);
  13. const paySpreadObj = {
  14. _checkExprValid(expr, invalidParam) {
  15. if (!expr) return [true, null];
  16. const param = [];
  17. let num = '', base = '';
  18. for (let i = 0, iLen = expr.length; i < iLen; i++) {
  19. if (/^[\d\.%]+/.test(expr[i])) {
  20. if (base !== '') {
  21. param.push({type: 'base', value: base});
  22. base = '';
  23. }
  24. num = num + expr[i];
  25. } else if (/^[a-z]/.test(expr[i])) {
  26. if (num !== '') {
  27. param.push({type: 'num', value: num});
  28. base = '';
  29. }
  30. base = base + expr[i];
  31. } else if (expr[i] === '(') {
  32. if (num !== '') {
  33. param.push({type: 'num', value: num});
  34. base = '';
  35. }
  36. if (base !== '') {
  37. param.push({type: 'base', value: base});
  38. base = '';
  39. }
  40. param.push({type: 'left', value: '('});
  41. } else if (expr[i] === ')') {
  42. if (num !== '') {
  43. param.push({type: 'num', value: num});
  44. base = '';
  45. }
  46. if (base !== '') {
  47. param.push({type: 'base', value: base});
  48. base = '';
  49. }
  50. param.push({type: 'right', value: ')'});
  51. } else if (/^[\+\-*\/]/.test(expr[i])) {
  52. if (num !== '') {
  53. param.push({type: 'num', value: num});
  54. base = '';
  55. }
  56. if (base !== '') {
  57. param.push({type: 'base', value: base});
  58. base = '';
  59. }
  60. param.push({type: 'calc', value: expr[i]});
  61. } else {
  62. return [false, '输入的表达式含有非法字符: ' + expr[i]];
  63. }
  64. }
  65. if (num !== '') {
  66. param.push({type: 'num', value: num});
  67. base = '';
  68. }
  69. if (base !== '') {
  70. param.push({type: 'base', value: base});
  71. base = '';
  72. }
  73. if (param.length === 0) return true;
  74. if (param.length > 1) {
  75. if (param[0].value === '-') {
  76. param[1].value = '-' + param[1];
  77. }
  78. param.unshift();
  79. }
  80. const iLen = param.length;
  81. let iLeftCount = 0, iRightCount = 0;
  82. for (const [i, p] of param.entries()) {
  83. if (p.type === 'calc') {
  84. if (i === 0 || i === iLen - 1)
  85. return [false, '输入的表达式非法:计算符号' + p.value + '前后应有数字或计算基数'];
  86. }
  87. if (p.type === 'num') {
  88. num = p.value.replace('%', '');
  89. if (p.value.length - num.length > 1)
  90. return [false, '输入的表达式非法:' + p.value + '不是一个有效的数字'];
  91. num = _.toNumber(num);
  92. if (num === undefined || num === null || _.isNaN(num))
  93. return [false, '输入的表达式非法:' + p.value + '不是一个有效的数字'];
  94. if (i > 0) {
  95. if (param[i - 1].type !== 'calc') {
  96. return [false, '输入的表达式非法:' + p.value + '前应有运算符'];
  97. } else if (param[i - 1].value === '/' && num === 0) {
  98. return [false, '输入的表达式非法:请勿除0'];
  99. }
  100. }
  101. }
  102. if (p.type === 'base') {
  103. const baseParam = _.find(calcBase, {code: p.value});
  104. if (!baseParam)
  105. return [false, '输入的表达式非法:不存在计算基数' + p.value];
  106. if (invalidParam && invalidParam.indexOf(p.value) >= 0)
  107. return [false, '不可使用计算基数' + p.value];
  108. if (i > 0 && param[i - 1].type === 'calc')
  109. return [false, '输入的表达式非法:' + p.value + '前应有运算符'];
  110. }
  111. if (p.type === 'left') {
  112. iLeftCount += 1;
  113. if (i !== 0 && param[i-1].type !== 'calc')
  114. return [false, '输入的表达式非法:(前应有运算符'];
  115. }
  116. if (p.type === 'right') {
  117. iRightCount += 1;
  118. if (i !== iLen - 1 && param[i+1].type !== 'calc')
  119. return [false, '输入的表达式非法:)后应有运算符'];
  120. if (iRightCount > iLeftCount)
  121. return [false, '输入的表达式非法:")"前无对应的"("'];
  122. }
  123. }
  124. if (iLeftCount > iRightCount)
  125. return [false, '输入的表达式非法:"("后无对应的")"'];
  126. return [true, ''];
  127. },
  128. _checkSExpr: function (payNode, text, data) {
  129. if (!payNode) return [false, '数据错误'];
  130. const num = text ? _.toNumber(text) : null;
  131. let expr = text ? (num ? null : text) : null;
  132. expr = expr ? expr.replace('=', '').toLowerCase(): null;
  133. const [valid, msg] = this._checkExprValid(expr, ['bqwc', 'ybbqwc']);
  134. if (!valid) return [valid, msg];
  135. if (payBase.isStarted(payNode)) {
  136. return [false, '已经开始计量,请勿修改起扣金额'];
  137. } else {
  138. if (stage.order > 1) {
  139. const value = expr ? payCalc.calculateExpr(expr) : num;
  140. if (wcPay.pre_tp && value < wcPay.pre_tp)
  141. return [false, '已进行到第' + stage.order + '期,起扣金额请勿少于本期完成截止上期计量金额' + wcPay.pre_tp];
  142. data.sprice = num;
  143. data.sexpr = expr;
  144. return [true, ''];
  145. } else {
  146. data.sprice = num;
  147. data.sexpr = expr;
  148. return [true, ''];
  149. }
  150. }
  151. },
  152. _checkRExpr: function (payNode, text, data) {
  153. if (!payNode) return [false, '数据错误'];
  154. const num = text ? _.toNumber(text) : null;
  155. let expr = text ? (num ? null : text) : null;
  156. expr = expr ? expr.replace('=', '').toLowerCase(): null;
  157. const [valid, msg] = this._checkExprValid(expr, ['bqwc', 'ybbqwc']);
  158. if (!valid) return [valid, msg];
  159. if (payBase.isStarted(payNode)) {
  160. if (payNode.pre_finish) return [false, '已达扣款限额,请勿修改'];
  161. const value = expr ? payCalc.calculateExpr(expr) : num;
  162. if (payNode.pre_tp && value < payNode.pre_tp) return [false, '截止上期已计量' + payNode.pre_tp + ',扣款限额请勿少于改值'];
  163. data.rprice = num;
  164. data.rexpr = expr;
  165. return [true, ''];
  166. } else {
  167. data.rprice = num;
  168. data.rexpr = expr;
  169. return [true, ''];
  170. }
  171. },
  172. _checkExpr: function (text, data) {
  173. if (text) {
  174. const num = _.toNumber(text);
  175. if (num) {
  176. data.tp = num;
  177. data.expr = null;
  178. } else {
  179. const expr = text.replace('=', '').toLowerCase();
  180. const [valid, msg] = this._checkExprValid(expr);
  181. if (!valid) return [valid, msg];
  182. data.expr = expr;
  183. data.tp = null;
  184. }
  185. } else {
  186. data.tp = null;
  187. data.expr = null;
  188. }
  189. return [true, ''];
  190. },
  191. refreshActn: function () {
  192. const setObjEnable = function (obj, enable) {
  193. if (enable) {
  194. obj.removeClass('disabled');
  195. } else {
  196. obj.addClass('disabled');
  197. }
  198. };
  199. const sheet = paySpread.getActiveSheet();
  200. const select = SpreadJsObj.getSelectObject(sheet);
  201. setObjEnable($('#add'), !readOnly);
  202. const delValid = payBase.isOld(select)
  203. ? !payBase.isStarted(select) && payBase.isYB()
  204. : payBase.isYB() || payBase.isOwner(select);
  205. setObjEnable($('#del'), !readOnly && select && delValid);
  206. setObjEnable($('#up-move'), !readOnly && select && !payBase.isSpecial(select) && dealPay.indexOf(select) > 3);
  207. setObjEnable($('#down-move'), !readOnly && select && !payBase.isSpecial(select) && dealPay.indexOf(select) < dealPay.length - 1);
  208. },
  209. add: function () {
  210. const sheet = billsSpread.getActiveSheet();
  211. postData(window.location.pathname + '/save', {type: 'add'}, function (result) {
  212. if (result) {
  213. dealPay.push(result);
  214. sheet.addRows(dealPay.length - 1, 1);
  215. SpreadJsObj.reLoadRowData(sheet, dealPay.length - 1);
  216. sheet.setSelection(dealPay.length - 1, 0, 1, 1);
  217. paySpreadObj.refreshActn();
  218. }
  219. });
  220. },
  221. del: function () {
  222. const sheet = billsSpread.getActiveSheet();
  223. const select = SpreadJsObj.getSelectObject(sheet);
  224. if (payBase.isNonZero(select.tp)) {
  225. toast('该支付(扣款)项存在数据,如需删除请先清除本期金额!');
  226. return;
  227. } else if (payBase.isOld(select)) {
  228. if (payBase.isStarted(select)) {
  229. toast('该合同支付项往期已进行计算,不允许删除');
  230. return;
  231. }
  232. }
  233. postData(window.location.pathname + '/save', {type: 'del', id: select.pid}, function (result) {
  234. const index = dealPay.indexOf(select);
  235. dealPay.splice(index, 1);
  236. sheet.deleteRows(index, 1);
  237. loadUpdateDealPays(result);
  238. SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
  239. const sel = sheet.getSelections();
  240. sheet.setSelection(index > 0 ? index - 1 : 0, sel.length > 0 ? sel[0].col : 0, 1, 1);
  241. paySpreadObj.refreshActn();
  242. });
  243. },
  244. selectionChanged: function (e, info) {
  245. paySpreadObj.refreshActn();
  246. const sel = info.sheet.getSelections()[0];
  247. const col = info.sheet.zh_setting.cols[sel.col];
  248. const data = SpreadJsObj.getSelectObject(info.sheet);
  249. if (col.field === 'tp') {
  250. $('#expr').val(data.expr).attr('field', 'expr').attr('org', data.expr)
  251. .attr('readOnly', readOnly|| payBase.isSpecial(data));
  252. } else if (col.field === 'sprice') {
  253. $('#expr').val(data.sexpr).attr('field', 'sexpr').attr('org', data.sexpr)
  254. .attr('readOnly', readOnly|| payCol.readOnly.sprice(data));
  255. } else if (col.field === 'rprice') {
  256. $('#expr').val(data.rexpr).attr('field', 'rexpr').attr('org', data.rexpr)
  257. .attr('readOnly', readOnly|| payCol.readOnly.rprice(data));
  258. } else {
  259. $('#expr').val('').attr('readOnly', true);
  260. }
  261. },
  262. editEnded: function (e, info) {
  263. if (info.sheet.zh_setting) {
  264. const select = SpreadJsObj.getSelectObject(info.sheet);
  265. const col = info.sheet.zh_setting.cols[info.col];
  266. if (col.field === 'minus') {
  267. return;
  268. }
  269. // 未改变值则不提交
  270. const validText = info.editingText ? info.editingText.replace('\n', '') : null;
  271. let orgValue;
  272. if (col.field === 'tp') {
  273. orgValue = _.toNumber(validText) ? select.tp : select.expr;
  274. } else if (col.field === 'sprice') {
  275. orgValue = _.toNumber(validText) ? select.sprice : select.sexpr;
  276. } else if (col.field === 'rprice') {
  277. orgValue = _.toNumber(validText) ? select.rexpr : select.rexpr;
  278. } else {
  279. orgValue = select[col.field];
  280. }
  281. if (orgValue == validText || ((!orgValue || orgValue === '') && (validText === ''))) {
  282. SpreadJsObj.reLoadRowData(info.sheet, info.row);
  283. return;
  284. }
  285. // 获取更新信息
  286. const data = {
  287. type: (col.field === 'tp' || col.field === 'name') ? 'stage' : 'info',
  288. updateData: {}
  289. };
  290. // 获取更新数据
  291. if (col.field === 'tp') {
  292. data.updateData.pid = select.pid;
  293. const [valid, msg] = paySpreadObj._checkExpr(validText, data.updateData);
  294. if (!valid) {
  295. toastr.warning(msg);
  296. SpreadJsObj.reLoadRowData(info.sheet, info.row);
  297. return;
  298. }
  299. } else if (col.field === 'name') {
  300. data.updateData.pid = select.pid;
  301. data.updateData.name = validText;
  302. } else {
  303. data.updateData.id = select.pid;
  304. if (validText) {
  305. if (col.field === 'sprice') {
  306. const [valid, msg] = paySpreadObj._checkSExpr(select, validText, data.updateData);
  307. if (!valid) {
  308. toastr.warning(msg);
  309. SpreadJsObj.reLoadRowData(info.sheet, info.row);
  310. return;
  311. }
  312. } else if (col.field === 'rprice') {
  313. const [valid, msg] = paySpreadObj._checkRExpr(select, validText, data.updateData);
  314. if (!valid) {
  315. toastr.warning(msg);
  316. SpreadJsObj.reLoadRowData(info.sheet, info.row);
  317. return;
  318. }
  319. } else {
  320. data.updateData[col.field] = validText;
  321. }
  322. } else {
  323. data.updateData[col.field] = null;
  324. }
  325. }
  326. // 更新至服务器
  327. postData(window.location.pathname + '/save', data, function (result) {
  328. loadUpdateDealPays(result, col.field === 'name' ? ['name'] : null);
  329. SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
  330. }, function () {
  331. SpreadJsObj.reLoadRowData(info.sheet, info.row);
  332. });
  333. }
  334. },
  335. buttonClicked: function (e, info) {
  336. if (info.sheet.zh_setting) {
  337. const select = SpreadJsObj.getSelectObject(info.sheet);
  338. const col = info.sheet.zh_setting.cols[info.col];
  339. if (payCol.readOnly.minus(select)) {
  340. return;
  341. }
  342. if (col.field === 'minus') {
  343. if (info.sheet.isEditing) {
  344. info.sheet.endEdit(true);
  345. }
  346. // 获取更新数据
  347. // 获取更新信息
  348. const data = {
  349. type: 'info',
  350. updateData: {id: select.pid},
  351. };
  352. data.updateData.minus = info.sheet.getValue(info.row, info.col) || false;
  353. // 更新至服务器
  354. postData(window.location.pathname + '/save', data, function (result) {
  355. loadUpdateDealPays(result);
  356. SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
  357. });
  358. }
  359. }
  360. },
  361. editStarting: function (e, info) {
  362. const col = info.sheet.zh_setting.cols[info.col];
  363. if (col.field === 'tp') {
  364. const select = SpreadJsObj.getSelectObject(info.sheet);
  365. if (select.expr && select.expr !== '') {
  366. info.sheet.getCell(info.row, info.col).text(select.expr);
  367. }
  368. } else if (col.field === 'sprice') {
  369. const select = SpreadJsObj.getSelectObject(info.sheet);
  370. if (select.sexpr && select.sexpr !== '') {
  371. info.sheet.getCell(info.row, info.col).text(select.sexpr);
  372. }
  373. } else if (col.field === 'rprice') {
  374. const select = SpreadJsObj.getSelectObject(info.sheet);
  375. if (select.rexpr && select.rexpr !== '') {
  376. info.sheet.getCell(info.row, info.col).text(select.rexpr);
  377. }
  378. }
  379. },
  380. deletePress: function (sheet) {
  381. if (sheet.zh_setting && sheet.zh_data) {
  382. const sel = sheet.getSelections()[0];
  383. if (!sel) return;
  384. const col = sheet.zh_setting.cols[sel.col];
  385. if (col.readOnly === true) { return; }
  386. if (sel.colCount > 1) {
  387. toast('请勿同时删除多列数据', 'warning');
  388. }
  389. const data = {type: col.field === 'tp' ? 'stage' : 'info', updateData: []};
  390. for (let iRow = sel.row; iRow < sel.row + sel.rowCount; iRow++) {
  391. const node = sheet.zh_data[iRow];
  392. if (node && (node.ptype === 1 || node.ptype === 3)) {
  393. const updateData = {};
  394. if (col.field === 'tp') {
  395. updateData.pid = node.pid;
  396. updateData.tp = null;
  397. updateData.expr = null;
  398. } else {
  399. updateData.id = node.pid;
  400. if (col.field === 'sprice') {
  401. const [valid, msg] = paySpreadObj._checkSExpr(node, null, updateData);
  402. if (!valid) {
  403. toastr.warning(msg);
  404. return;
  405. }
  406. } else if (col.field === 'rprice') {
  407. const [valid, msg] = paySpreadObj._checkRExpr(node, null, updateData);
  408. if (!valid) {
  409. toastr.warning(msg);
  410. return;
  411. }
  412. } else {
  413. updateData[col.field] = null;
  414. }
  415. }
  416. data.updateData.push(updateData);
  417. }
  418. }
  419. if (data.updateData.length > 0) {
  420. if (data.updateData.length === 1 && sel.rowCount === 1) {
  421. data.updateData = data.updateData[0];
  422. }
  423. postData(window.location.pathname + '/save', data, function (result) {
  424. loadUpdateDealPays(result, col.field === 'name' ? ['name'] : null);
  425. SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
  426. })
  427. }
  428. }
  429. },
  430. clipboardPasted: function (e, info) {
  431. if (info.sheet.zh_setting && info.sheet.zh_data) {
  432. const col = info.sheet.zh_setting.cols[info.cellRange.col];
  433. if (col.readOnly === true) {
  434. SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
  435. return;
  436. }
  437. if (info.cellRange.colCount > 1) {
  438. toast('请勿同时复制粘贴多列数据', 'warning');
  439. }
  440. const sortData = info.sheet.zh_data;
  441. const data = {type: col.field === 'tp' ? 'stage' : 'info', updateData: []};
  442. for (let iRow = 0; iRow < info.cellRange.rowCount; iRow++) {
  443. const curRow = info.cellRange.row + iRow;
  444. const node = sortData[curRow];
  445. if (node && (node.ptype === 1 || node.ptype === 3)) {
  446. const validText = info.sheet.getText(curRow, info.cellRange.col).replace('\n', '');
  447. const updateData = {};
  448. if (col.field === 'tp') {
  449. updateData.pid = node.pid;
  450. const [valid, msg] = paySpreadObj._checkExpr(validText, updateData);
  451. if (!valid) {
  452. toastr.warning(msg);
  453. SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
  454. return;
  455. }
  456. } else {
  457. updateData.id = node.pid;
  458. if (validText) {
  459. if (col.field === 'sprice') {
  460. const [valid, msg] = paySpreadObj._checkSExpr(node, validText, updateData);
  461. if (!valid) {
  462. toastr.warning(msg);
  463. SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
  464. return;
  465. }
  466. } else if (col.field === 'rprice') {
  467. const [valid, msg] = paySpreadObj._checkRExpr(node, validText, updateData);
  468. if (!valid) {
  469. toastr.warning(msg);
  470. SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
  471. return;
  472. }
  473. } else {
  474. updateData[col.field] = validText;
  475. }
  476. } else {
  477. updateData[col.field] = null;
  478. }
  479. }
  480. data.updateData.push(updateData);
  481. }
  482. if (data.updateData.length > 0) {
  483. postData(window.location.pathname + '/save', data, function (result) {
  484. loadUpdateDealPays(result, col.field === 'name' ? ['name'] : null);
  485. SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
  486. }, function () {
  487. SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
  488. });
  489. }
  490. }
  491. }
  492. },
  493. };
  494. });