phase_pay_detail.js 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132
  1. 'use strict';
  2. const showSideTools = function (show) {
  3. const left = $('#left-view'), right = $('#right-view'), parent = left.parent();
  4. if (show) {
  5. right.show();
  6. autoFlashHeight();
  7. /**
  8. * right.show()后, parent被撑开成2倍left.height, 导致parent.width减少了10px
  9. * 第一次left.width调整后,parent的缩回left.height, 此时parent.width又增加了10px
  10. * 故需要通过最终的parent.width再计算一次left.width
  11. *
  12. * Q: 为什么不通过先计算left.width的宽度,以避免计算两次left.width?
  13. * A: 右侧工具栏不一定显示,当右侧工具栏显示过一次后,就必须使用parent和right来计算left.width
  14. *
  15. */
  16. //left.css('width', parent.width() - right.outerWidth());
  17. //left.css('width', parent.width() - right.outerWidth());
  18. const percent = 100 - right.outerWidth() /parent.width() * 100;
  19. left.css('width', percent + '%');
  20. } else {
  21. left.width(parent.width());
  22. right.hide();
  23. }
  24. };
  25. $(document).ready(() => {
  26. autoFlashHeight();
  27. const payUtils = {
  28. tips: {
  29. name: function(data) {
  30. const tips = [];
  31. if (data) {
  32. if (data.pause) tips.push('当前项已停用');
  33. if (!data.is_yf) tips.push('当前项不参与本期应付计算');
  34. }
  35. return tips.join('<br/>');
  36. },
  37. range_tp: function (data) {
  38. if (!data || (!data.range_expr && !data.range_tp) || !data.dl_type) return '';
  39. if (data.dl_type === 1) {
  40. return '计提期限为(当 计量期数 ≥ ' + data.dl_count + ')';
  41. } else if (data.dl_type === 2) {
  42. switch (data.dl_tp_type) {
  43. case 'contract':
  44. return '计提期限为(累计合同计量 ≥ ' + data.dl_tp + ')';
  45. case 'qc':
  46. return '计提期限为(累计变更计量 ≥ ' + data.dl_tp + ')';
  47. case 'gather':
  48. return '计提期限为(累计完成计量 ≥ ' + data.dl_tp + ')';
  49. }
  50. }
  51. }
  52. },
  53. check: {
  54. isFixed: function(data) {
  55. return data.is_fixed;
  56. },
  57. isStarted: function (data) {
  58. return data.pre_used;
  59. },
  60. isYf: function(data) {
  61. return data.pay_type === 'bqyf';
  62. },
  63. isSf: function(data) {
  64. return data.pay_type === 'bqsf';
  65. },
  66. isGatherValid: function(data) {
  67. return !data.pay_type && (!data.children || data.children.length === 0);
  68. },
  69. isOwner: function(data) {
  70. return data.create_user_id === userID;
  71. },
  72. isFinish: function(data) {
  73. return data.pre_finish;
  74. },
  75. isYB: function() {
  76. return userID === phasePay.create_user_id;
  77. },
  78. isOld: function(data) {
  79. return data.phase_id !== data.create_phase_id;
  80. },
  81. isLock: function (data) {
  82. const result = !!lockPayExpr && payUtils.check.isStarted(data) && payCalc.hasBase(data.expr);
  83. return result;
  84. },
  85. tpReadOnly: function(data) {
  86. return payUtils.check.isYf(data) || payUtils.check.isLock(data);
  87. },
  88. startTpReadOnly: function(data) {
  89. if (payUtils.check.isOld(data)) {
  90. return payUtils.check.isStarted(data) || !payUtils.check.isYB(data) || payUtils.check.isLock(data);
  91. } else {
  92. return payUtils.check.isWC(data) || payUtils.check.isSF(data) || payUtils.check.isYf(data) || !(payUtils.check.isOwner(data) || payUtils.check.isYB());
  93. }
  94. },
  95. rangeTpReadOnly: function(data) {
  96. if (payUtils.check.isOld(data)) {
  97. return !payUtils.check.isYB(data) || payUtils.check.isLock(data);
  98. } else {
  99. return payUtils.check.isWC(data) || payUtils.check.isYF(data) || !(payUtils.check.isOwner(data) || payUtils.check.isYB());
  100. }
  101. },
  102. },
  103. menuVisible: {
  104. pause: function (data) {
  105. if (payUtils.check.isOld(data)) {
  106. return payUtils.check.isYB();
  107. } else {
  108. return payUtils.check.isOwner(data) || payUtils.check.isYB();
  109. }
  110. },
  111. deadline: function (data) {
  112. if (payUtils.check.isOld(data)) {
  113. return !payUtils.check.isFinish(data) && payUtils.check.isYB();
  114. } else {
  115. return payUtils.check.isOwner(data) || payUtils.check.isYB();
  116. }
  117. }
  118. },
  119. };
  120. const payCalc = (function (b, a) {
  121. class PayCalc {
  122. constructor (bases, add) {
  123. this.percentReg = /((\d+)|((\d+)(\.\d+)))%/g;
  124. this.bases = bases;
  125. this.bases.sort(function (a, b) {
  126. return a.sort - b.sort;
  127. });
  128. for (const b of this.bases) {
  129. b.reg = new RegExp(b.code, 'igm');
  130. }
  131. this.addBase = add;
  132. this.orderReg = /f\d+/ig;
  133. this.nodeReg = /<<[a-z0-9\-]+>>/ig;
  134. }
  135. hasBase(expr) {
  136. if (!expr) return false;
  137. for (const b of this.bases) {
  138. if (data.expr.indexOf(b.code) >= 0) return true;
  139. }
  140. return false;
  141. }
  142. trans2OrderExpr(expr, payTree) {
  143. const nodeParam = expr.match(this.nodeReg);
  144. if (nodeParam) {
  145. for (const op of nodeParam) {
  146. const id = op.substring(2, op.length - 2);
  147. const payNode = payTree.nodes.find(x => { return x.uuid === id; });
  148. expr = expr.replace(op, payNode ? `f${payTree.getNodeIndex(payNode) + 1}` || '' : 0);
  149. }
  150. }
  151. return expr;
  152. }
  153. trans2NodeExpr(expr, payTree) {
  154. const orderParam = expr.match(this.orderReg);
  155. if (orderParam) {
  156. for (const op of orderParam) {
  157. const order = parseInt(op.substring(1, op.length));
  158. const payNode = payTree.nodes[order - 1];
  159. expr = expr.replace(op, payNode ? `<<${payNode.uuid}>>` || '' : 0);
  160. }
  161. }
  162. return expr;
  163. }
  164. checkExprValid(expr, invalidParam, selfId, payTree) {
  165. if (!expr) return [true, ''];
  166. const param = [];
  167. let num = '', base = '';
  168. let fixedIdParam;
  169. for (let i = 0, iLen = expr.length; i < iLen; i++) {
  170. const subExpr = expr.substring(i, expr.length);
  171. if (/^[\d\.%]+/.test(expr[i])) {
  172. if (base !== '') {
  173. param.push({type: 'base', value: base});
  174. base = '';
  175. }
  176. num = num + expr[i];
  177. } else if (this.nodeReg.test(subExpr)) {
  178. if (num !== '') {
  179. param.push({type: 'num', value: num});
  180. num = '';
  181. }
  182. if (base !== '') {
  183. param.push({type: 'base', value: base});
  184. base = '';
  185. }
  186. // const node = this.nodeReg.exec(subExpr);
  187. const node = subExpr.match(this.nodeReg);
  188. param.push({type: 'node', value: node[0]});
  189. i = i + node[0].length - 1;
  190. } else if (/^[a-z]/.test(expr[i])) {
  191. if (num !== '') {
  192. param.push({type: 'num', value: num});
  193. num = '';
  194. }
  195. base = base + expr[i];
  196. } else if (expr[i] === '(') {
  197. if (num !== '') {
  198. param.push({type: 'num', value: num});
  199. num = '';
  200. }
  201. if (base !== '') {
  202. param.push({type: 'base', value: base});
  203. base = '';
  204. }
  205. param.push({type: 'left', value: '('});
  206. } else if (expr[i] === ')') {
  207. if (num !== '') {
  208. param.push({type: 'num', value: num});
  209. num = '';
  210. }
  211. if (base !== '') {
  212. param.push({type: 'base', value: base});
  213. base = '';
  214. }
  215. param.push({type: 'right', value: ')'});
  216. } else if (/^[\+\-*\/]/.test(expr[i])) {
  217. if (num !== '') {
  218. param.push({type: 'num', value: num});
  219. num = '';
  220. }
  221. if (base !== '') {
  222. param.push({type: 'base', value: base});
  223. base = '';
  224. }
  225. param.push({type: 'calc', value: expr[i]});
  226. } else {
  227. return [false, '输入的表达式含有非法字符: ' + expr[i]];
  228. }
  229. }
  230. if (num !== '') {
  231. param.push({type: 'num', value: num});
  232. num = '';
  233. }
  234. if (base !== '') {
  235. param.push({type: 'base', value: base});
  236. base = '';
  237. }
  238. if (param.length === 0) return [true, ''];
  239. if (param.length > 1) {
  240. if (param[0].value === '-' && param[1].type === 'num') {
  241. param[1].value = '-' + param[1].value;
  242. param.shift();
  243. }
  244. }
  245. const iLen = param.length;
  246. let iLeftCount = 0, iRightCount = 0;
  247. for (const [i, p] of param.entries()) {
  248. if (p.type === 'calc') {
  249. if (i === 0 || i === iLen - 1)
  250. return [false, '输入的表达式非法:计算符号' + p.value + '前后应有数字或计算基数'];
  251. }
  252. if (p.type === 'num') {
  253. num = p.value.replace('%', '');
  254. if (p.value.length - num.length > 1)
  255. return [false, '输入的表达式非法:' + p.value + '不是一个有效的数字'];
  256. num = _.toNumber(num);
  257. if (num === undefined || num === null || _.isNaN(num))
  258. return [false, '输入的表达式非法:' + p.value + '不是一个有效的数字'];
  259. if (i > 0) {
  260. if (param[i - 1].type !== 'calc' && param[i - 1].type !== 'left') {
  261. return [false, '输入的表达式非法:' + p.value + '前应有运算符'];
  262. } else if (param[i - 1].value === '/' && num === 0) {
  263. return [false, '输入的表达式非法:请勿除0'];
  264. }
  265. }
  266. }
  267. if (p.type === 'base') {
  268. const baseParam = _.find(calcBase, {code: p.value});
  269. if (!baseParam)
  270. return [false, '输入的表达式非法:不存在计算基数' + p.value];
  271. if (invalidParam && invalidParam.indexOf(p.value) >= 0)
  272. return [false, '不可使用计算基数' + p.value];
  273. if (i > 0 && (param[i - 1].type === 'num' || param[i - 1].type === 'right'))
  274. return [false, '输入的表达式非法:' + p.value + '前应有运算符'];
  275. }
  276. if (p.type === 'node') {
  277. if (!selfId) return [false, '输入的表达式错误:不支持行号引用'];
  278. if ([`<<${selfId}>>`].indexOf(p.value) >= 0) return [false, '输入的表达式非法:请勿引用自己'];
  279. if (!fixedIdParam) {
  280. fixedIdParam = payTree.nodes.filter(x => { return x.is_fixed; }).map(x => { return `<<${x.uuid}>>`});
  281. }
  282. if (fixedIdParam.indexOf(p.value) >= 0) return [false, '输入的表达式非法:请勿引用固定项'];
  283. }
  284. if (p.type === 'left') {
  285. iLeftCount += 1;
  286. if (i !== 0 && param[i-1].type !== 'calc')
  287. return [false, '输入的表达式非法:(前应有运算符'];
  288. }
  289. if (p.type === 'right') {
  290. iRightCount += 1;
  291. if (i !== iLen - 1 && param[i+1].type !== 'calc')
  292. return [false, '输入的表达式非法:)后应有运算符'];
  293. if (iRightCount > iLeftCount)
  294. return [false, '输入的表达式非法:")"前无对应的"("'];
  295. }
  296. }
  297. if (iLeftCount > iRightCount)
  298. return [false, '输入的表达式非法:"("后无对应的")"'];
  299. if (selfId) {
  300. const circular = payCalc.checkCircularExpr(expr, selfId, payTree);
  301. // 当前循环计算不检查父项
  302. if (circular) return [false, '输入的表达式非法:循环引用'];
  303. }
  304. return [true, ''];
  305. }
  306. checkSfExpr(text, data, payNode, payTree) {
  307. if (text) {
  308. const num = _.toNumber(text);
  309. if (num) {
  310. data.expr = num;
  311. } else {
  312. const expr = this.trans2NodeExpr($.trim(text).replace('\t', '').replace('=', '').toLowerCase(), payTree);
  313. const [valid, msg] = this.checkExprValid(expr, [], payNode.uuid, payTree);
  314. if (!valid) return [valid, msg];
  315. data.expr = expr;
  316. }
  317. } else {
  318. data.tp = 0;
  319. data.expr = '';
  320. }
  321. return [true, ''];
  322. }
  323. checkExpr(text, data, payNode, payTree) {
  324. if (text) {
  325. const num = _.toNumber(text);
  326. if (num) {
  327. data.tp = num;
  328. data.expr = '';
  329. } else {
  330. const expr = this.trans2NodeExpr($.trim(text).replace('\t', '').replace('=', '').toLowerCase(), payTree);
  331. const [valid, msg] = this.checkExprValid(expr, ['bqyf'], payNode.uuid, payTree);
  332. if (!valid) return [valid, msg];
  333. data.expr = expr;
  334. data.tp = 0;
  335. }
  336. } else {
  337. data.tp = 0;
  338. data.expr = '';
  339. }
  340. return [true, ''];
  341. }
  342. checkRangeExpr(payNode, text, data) {
  343. if (!payNode) return [false, '数据错误'];
  344. const num = text ? _.toNumber(text) : 0;
  345. let expr = text ? (num ? '' : text) : '';
  346. expr = expr ? $.trim(expr).replace('\t', '').replace('=', '').toLowerCase() : '';
  347. const [valid, msg] = this.checkExprValid(expr, ['bqwc', 'ybbqwc', 'bqht', 'bqbg', 'bqyf']);
  348. if (!valid) return [valid, msg];
  349. if (payUtils.check.isStarted(payNode)) {
  350. if (payUtils.check.isSf(payNode)) {
  351. const value = expr ? payCalc.calculateExpr(expr) : num;
  352. if (payNode.pre_tp && value < payNode.pre_tp) return [false, '截止上期已计量' + payNode.pre_tp + ',扣款限额请勿少于改值'];
  353. data.range_tp = num;
  354. data.range_expr = expr;
  355. return [true, ''];
  356. } else {
  357. // if (payNode.pre_finish) return [false, '已达扣款限额,请勿修改'];
  358. // const value = expr ? payCalc.calculateExpr(expr) : num;
  359. // if (payNode.pre_tp && value < payNode.pre_tp) return [false, '截止上期已计量' + payNode.pre_tp + ',扣款限额请勿少于改值'];
  360. // data.range_tp = num;
  361. // data.range_expr = expr;
  362. return [false, '已经开始使用,请勿修改扣款限额'];
  363. }
  364. } else {
  365. data.range_tp = num;
  366. data.range_expr = expr;
  367. return [true, ''];
  368. }
  369. }
  370. checkStartExpr(payNode, text, data) {
  371. if (!payNode) return [false, '数据错误'];
  372. const num = text ? _.toNumber(text) : 0;
  373. let expr = text ? (num ? '' : text) : '';
  374. expr = expr ? $.trim(expr).replace('\t', '').replace('=', '').toLowerCase() : '';
  375. const [valid, msg] = this.checkExprValid(expr, ['bqwc', 'ybbqwc', 'bqht', 'bqbg', 'bqyf']);
  376. if (!valid) return [valid, msg];
  377. if (payUtils.check.isStarted(payNode)) {
  378. return [false, '已经开始计量,请勿修改起扣金额'];
  379. } else {
  380. if (this.addBase.pre_gather_tp) {
  381. const value = expr ? payCalc.calculateExpr(expr) : num;
  382. if (this.addBase.pre_gather_tp && value < this.addBase.pre_gather_tp)
  383. return [false, '起扣金额请勿少于本期完成截止上期计量金额' + this.addBase.pre_gather_tp];
  384. data.start_tp = num;
  385. data.start_expr = expr;
  386. return [true, ''];
  387. } else {
  388. data.start_tp = num;
  389. data.start_expr = expr;
  390. return [true, ''];
  391. }
  392. }
  393. }
  394. getExprInfo(field, converse = false) {
  395. const exprField = [
  396. {qty: 'tp', expr: 'expr'},
  397. {qty: 'start_tp', expr: 'start_expr'},
  398. {qty: 'range_qty', expr: 'range_expr'},
  399. ];
  400. if (converse) return _.find(exprField, { expr: field });
  401. return _.find(exprField, {qty: field});
  402. }
  403. getLeafOrder(data, parentReg, tree) {
  404. if (!data) return [];
  405. const defaultResult = data.uuid ? [`<<${data.uuid}>>`] : [];
  406. if (!data.expr) return defaultResult;
  407. const nodeParam = data.expr.match(this.nodeReg);
  408. if (!nodeParam || nodeParam.length === 0) return defaultResult;
  409. const result = [];
  410. for (const op of nodeParam) {
  411. const id = op.substring(2, op.length - 2);
  412. if (data.uuid === id || op === parentReg) {
  413. result.push(op);
  414. } else {
  415. const payNode = tree.nodes.find(x => {return x.uuid === id; });
  416. const subOrderParam = this.getLeafOrder(payNode, data.uuid ? `<<${data.uuid}>>` : parentReg, tree);
  417. result.push(...subOrderParam);
  418. }
  419. }
  420. return result;
  421. }
  422. checkCircularExpr(expr, selfId, tree) {
  423. const leafOrder = this.getLeafOrder({expr}, `<<${selfId}>>`, tree);
  424. if (leafOrder.indexOf(`<<${selfId}>>`) >= 0) return true;
  425. return false;
  426. }
  427. calculateExpr(expr) {
  428. let formula = expr;
  429. for (const b of this.bases) {
  430. formula = formula.replace(b.reg, b.value);
  431. }
  432. const percent = formula.match(this.percentReg);
  433. if (percent) {
  434. for (const p of percent) {
  435. const v = math.evaluate(p.replace(new RegExp('%', 'gm'), '/100'));
  436. formula = formula.replace(p, v);
  437. }
  438. }
  439. try {
  440. const value = ZhCalc.mathCalcExpr(formula);
  441. return value;
  442. } catch(err) {
  443. return 0;
  444. }
  445. }
  446. refreshBaseHtml() {
  447. const html = [];
  448. for (const [i, b] of this.bases.entries()) {
  449. html.push('<tr>');
  450. html.push(`<td>${i+1}</td><td>${b.name}</td><td>${b.code}</td>`);
  451. if (b.code === 'bqyf') {
  452. html.push('<td class="text-right">--</td>');
  453. } else {
  454. html.push(`<td class="text-right">${b.formatValue}</td>`);
  455. }
  456. html.push('</tr>');
  457. }
  458. $('#base-list').html(html.join(''));
  459. }
  460. reloadBase(bases, add) {
  461. this.bases = bases;
  462. this.refreshBaseHtml();
  463. this.bases.sort(function (a, b) {
  464. return a.sort - b.sort;
  465. });
  466. for (const b of this.bases) {
  467. b.reg = new RegExp(b.code, 'igm');
  468. }
  469. this.addBase = add;
  470. }
  471. }
  472. return new PayCalc(b, a);
  473. })(calcBase, addBase);
  474. const payObj = (function() {
  475. const spread = SpreadJsObj.createNewSpread($('#pay-spread')[0]);
  476. const sheet = spread.getActiveSheet();
  477. const spreadSetting = {
  478. cols: [
  479. {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 230, formatter: '@', cellType: 'tree', getTip: payUtils.tips.name},
  480. {title: '本期金额(F)', colSpan: '1', rowSpan: '1', field: 'tp', hAlign: 2, width: 100, type: 'Number'},
  481. {title: '截止上期金额', colSpan: '1', rowSpan: '1', field: 'pre_tp', hAlign: 2, width: 100, readOnly: true, type: 'Number'},
  482. {title: '截止本期金额', colSpan: '1', rowSpan: '1', field: 'end_tp', hAlign: 2, width: 100, readOnly: true, type: 'Number'},
  483. {title: '起扣金额', colSpan: '1', rowSpan: '1', field: 'start_tp', hAlign: 2, width: 100, type: 'Number'},
  484. {title: '付(扣)款限额', colSpan: '1', rowSpan: '1', field: 'range_tp', hAlign: 2, width: 100, cellType: 'tip', type: 'Number', getTip: payUtils.tips.range_tp},
  485. {title: '汇总', colSpan: '1', rowSpan: '1', field: 'is_gather', hAlign: 1, width: 60, cellType: 'signalCheckbox', show: payUtils.check.isGatherValid},
  486. {title: '本期批注', colSpan: '1', rowSpan: '1', field: 'postil', hAlign: 0, width: 120, formatter: '@', cellType: 'autoTip'},
  487. ],
  488. emptyRows: 0,
  489. headRows: 1,
  490. headRowHeight: [32],
  491. headColWidth: [30],
  492. defaultRowHeight: 21,
  493. headerFont: '12px 微软雅黑',
  494. font: '12px 微软雅黑',
  495. readOnly: readOnly,
  496. localCache: {
  497. key: 'phase-pay',
  498. colWidth: true,
  499. },
  500. pos: SpreadJsObj.getObjPos($('#pay-spread')[0]),
  501. };
  502. sjsSettingObj.setFxTreeStyle(spreadSetting, sjsSettingObj.FxTreeStyle.phasePay);
  503. SpreadJsObj.initSheet(sheet, spreadSetting);
  504. const payTree = createNewPathTree('base', {
  505. id: 'tree_id', pid: 'tree_pid', order: 'tree_order',
  506. level: 'tree_level', isLeaf: 'tree_is_leaf', fullPath: 'tree_full_path',
  507. rootId: -1,
  508. });
  509. const payEvent = {
  510. refreshActn: function() {
  511. const setObjEnable = function (obj, enable) {
  512. if (enable) {
  513. obj.removeClass('disabled');
  514. } else {
  515. obj.addClass('disabled');
  516. }
  517. };
  518. const select = SpreadJsObj.getSelectObject(sheet);
  519. if (!select) {
  520. setObjEnable($('a[name=base-opr][type=add]'), false);
  521. setObjEnable($('a[name=base-opr][type=del]'), false);
  522. setObjEnable($('a[name=base-opr][type=up-move]'), false);
  523. setObjEnable($('a[name=base-opr][type=down-move]'), false);
  524. return;
  525. }
  526. const preNode = payTree.getPreSiblingNode(select);
  527. setObjEnable($('a[name=base-opr][type=add]'), !readOnly && !payUtils.check.isSf(select) && !payUtils.check.isYf(select));
  528. const delValid = !payUtils.check.isFixed(select) && !payUtils.check.isStarted(select);
  529. setObjEnable($('a[name=base-opr][type=delete]'), !readOnly && delValid);
  530. setObjEnable($('a[name=base-opr][type=up-move]'), !readOnly && !payUtils.check.isFixed(select) && preNode);
  531. setObjEnable($('a[name=base-opr][type=down-move]'), !readOnly && !payUtils.check.isFixed(select) && !payTree.isLastSibling(select));
  532. },
  533. loadExprToInput: function() {
  534. const sel = sheet.getSelections()[0];
  535. const col = sheet.zh_setting.cols[sel.col];
  536. const data = SpreadJsObj.getSelectObject(sheet);
  537. if (data && (!data.children || data.children.length === 0)) {
  538. if (col.field === 'tp') {
  539. const expr = payCalc.trans2OrderExpr(data.expr, payTree);
  540. $('#pay-expr').val(expr).attr('field', 'expr').attr('org', expr)
  541. .attr('readOnly', readOnly|| payUtils.check.tpReadOnly(data));
  542. } else if (col.field === 'start_tp') {
  543. const expr = payCalc.trans2OrderExpr(data.start_expr, payTree) || data.start_tp;
  544. $('#pay-expr').val(expr).attr('field', 'start_expr').attr('org', expr)
  545. .attr('readOnly', readOnly|| payUtils.check.startTpReadOnly(data) || payUtils.check.isYf(data));
  546. } else if (col.field === 'range_tp') {
  547. const expr = payCalc.trans2OrderExpr(data.range_expr, payTree);
  548. $('#pay-expr').val(expr).attr('field', 'range_expr').attr('org', expr)
  549. .attr('readOnly', readOnly|| payUtils.check.rangeTpReadOnly(data) || payUtils.check.isYf(data));
  550. } else {
  551. $('#pay-expr').val('').attr('readOnly', true);
  552. }
  553. $('#pay-expr').attr('data-row', sel.row);
  554. } else {
  555. $('#pay-expr').val('').attr('readOnly', true);
  556. $('#pay-expr').removeAttr('data-row');
  557. }
  558. },
  559. refreshTree: function (data) {
  560. SpreadJsObj.massOperationSheet(sheet, function () {
  561. const tree = sheet.zh_tree;
  562. // 处理删除
  563. if (data.delete) {
  564. data.delete.sort(function (a, b) {
  565. return b.deleteIndex - a.deleteIndex;
  566. });
  567. for (const d of data.delete) {
  568. sheet.deleteRows(d.deleteIndex, 1);
  569. }
  570. }
  571. // 处理新增
  572. if (data.create) {
  573. const newNodes = data.create;
  574. if (newNodes) {
  575. newNodes.sort(function (a, b) {
  576. return a.index - b.index;
  577. });
  578. for (const node of newNodes) {
  579. sheet.addRows(node.index, 1);
  580. SpreadJsObj.reLoadRowData(sheet, tree.nodes.indexOf(node), 1);
  581. }
  582. }
  583. }
  584. // 处理更新
  585. if (data.update) {
  586. const rows = [];
  587. for (const u of data.update) {
  588. rows.push(tree.nodes.indexOf(u));
  589. }
  590. SpreadJsObj.reLoadRowsData(sheet, rows);
  591. }
  592. });
  593. },
  594. editStarting: function(e, info) {
  595. const col = info.sheet.zh_setting.cols[info.col];
  596. const select = SpreadJsObj.getSelectObject(info.sheet);
  597. switch (col.field) {
  598. case 'name':
  599. info.cancel = payUtils.check.isFixed(select);
  600. break;
  601. case 'tp':
  602. case 'is_gather':
  603. info.cancel = select.children && select.children.length > 0;
  604. break;
  605. case 'start_tp':
  606. case 'range_tp':
  607. info.cancel = (select.children && select.children.length > 0) || payUtils.check.isYf(select);
  608. break;
  609. case 'is_gather':
  610. info.cancel = true;
  611. break;
  612. }
  613. if (col.field === 'tp') {
  614. if (select.expr && select.expr !== '') {
  615. info.sheet.getCell(info.row, info.col).text(payCalc.trans2OrderExpr(select.expr, payTree));
  616. }
  617. } else if (col.field === 'start_tp') {
  618. if (select.start_expr && select.start_expr !== '') {
  619. info.sheet.getCell(info.row, info.col).text(select.start_expr);
  620. }
  621. } else if (col.field === 'range_tp') {
  622. if (select.range_expr && select.range_expr !== '') {
  623. info.sheet.getCell(info.row, info.col).text(select.range_expr);
  624. }
  625. }
  626. },
  627. editEnded: function(e, info) {
  628. if (!info.sheet.zh_setting) return;
  629. const select = SpreadJsObj.getSelectObject(info.sheet);
  630. const col = info.sheet.zh_setting.cols[info.col];
  631. if (col.field === 'is_gather') return;
  632. // 未改变值则不提交
  633. const validText = info.editingText ? info.editingText.replace('\n', '') : '';
  634. let orgValue;
  635. if (col.field === 'tp') {
  636. orgValue = select.expr ? payCalc.trans2OrderExpr(select.expr, payTree) : select.tp;
  637. } else if (col.field === 'start_tp') {
  638. orgValue = select.start_expr ? select.start_expr : select.start_tp;
  639. } else if (col.field === 'range_tp') {
  640. orgValue = select.range_expr ? select.range_expr : select.range_tp;
  641. } else {
  642. orgValue = select[col.field];
  643. }
  644. orgValue = orgValue || '';
  645. if (orgValue == validText) {
  646. SpreadJsObj.reLoadRowData(info.sheet, info.row);
  647. return;
  648. }
  649. const data = { postType: 'update', postData: { id: select.id } };
  650. switch(col.field) {
  651. case 'tp':
  652. const [tpValid, tpMsg] = payUtils.check.isSf(select)
  653. ? payCalc.checkSfExpr(validText, data.postData, select, payTree)
  654. : payCalc.checkExpr(validText, data.postData, select, payTree);
  655. if (!tpValid) {
  656. toastr.warning(tpMsg);
  657. SpreadJsObj.reLoadRowData(info.sheet, info.row);
  658. return;
  659. }
  660. break;
  661. case 'start_tp':
  662. const [sValid, sMsg] = payCalc.checkStartExpr(select, validText, data.postData);
  663. if (!sValid) {
  664. toastr.warning(sMsg);
  665. SpreadJsObj.reLoadRowData(info.sheet, info.row);
  666. return;
  667. }
  668. break;
  669. case 'range_tp':
  670. const [rValid, rMsg] = payCalc.checkRangeExpr(select, validText, data.postData);
  671. if (!rValid) {
  672. toastr.warning(rMsg);
  673. SpreadJsObj.reLoadRowData(info.sheet, info.row);
  674. return;
  675. }
  676. break;
  677. default:
  678. if (col.type === 'Number') {
  679. data.postData[col.field] = _.toNumber(validText) || 0;
  680. } else {
  681. data.postData[col.field] = validText || '';
  682. }
  683. break;
  684. }
  685. postData('update', data, function (result) {
  686. if (result.reload) {
  687. payEvent.reloadPays(result.reload);
  688. } else {
  689. const refreshData = payTree.loadPostData(result);
  690. payEvent.refreshTree(refreshData);
  691. }
  692. }, function () {
  693. SpreadJsObj.reLoadRowData(info.sheet, info.row);
  694. });
  695. },
  696. selectionChanged: function(e, info) {
  697. if (info.newSelections) {
  698. if (!info.oldSelections || info.newSelections[0].row !== info.oldSelections[0].row) {
  699. payEvent.refreshActn();
  700. }
  701. }
  702. payEvent.loadExprToInput();
  703. },
  704. buttonClicked: function (e, info) {
  705. if (!info.sheet.zh_setting) return;
  706. const select = SpreadJsObj.getSelectObject(info.sheet);
  707. const col = info.sheet.zh_setting.cols[info.col];
  708. if (col.field !== 'is_gather') return;
  709. if (!payUtils.check.isGatherValid(select)) return;
  710. if (info.sheet.isEditing()) info.sheet.endEdit(true);
  711. const data = {
  712. postType: 'update',
  713. postData: { id: select.id },
  714. };
  715. data.postData[col.field] = info.sheet.getValue(info.row, info.col) || 0;
  716. // 更新至服务器
  717. postData('update', data, function (result) {
  718. if (result.reload) payEvent.reloadPays(result.reload);
  719. });
  720. },
  721. deletePress: function (sheet) {
  722. if (!sheet.zh_setting) return;
  723. const sel = sheet.getSelections()[0];
  724. if (!sel) return;
  725. const col = sheet.zh_setting.cols[sel.col];
  726. if (col.readOnly === true) return;
  727. if (sel.colCount > 1) toastr.warning('请勿同时删除多列数据');
  728. const data = { postType: 'update', postData: [] };
  729. for (let iRow = sel.row; iRow < sel.row + sel.rowCount; iRow ++) {
  730. const node = sheet.zh_tree.nodes[iRow];
  731. if (node && (!node.pay_type || col.field === 'postil')) {
  732. const updateData = { id: node.id };
  733. switch(col.field) {
  734. case 'tp':
  735. updateData.tp = 0;
  736. updateData.expr = '';
  737. break;
  738. case 'start_tp':
  739. updateData.start_tp = 0;
  740. updateData.start_expr = '';
  741. break;
  742. case 'range_tp':
  743. updateData.range_tp = 0;
  744. updateData.range_expr = '';
  745. break;
  746. case 'is_gather':
  747. updateData.is_gather = 0;
  748. break;
  749. default:
  750. updateData[col.field] = col.type === 'Number' ? 0 : '';
  751. }
  752. data.postData.push(updateData);
  753. }
  754. }
  755. postData('update', data, function (result) {
  756. if (result.reload) {
  757. payEvent.reloadPays(result.reload);
  758. } else {
  759. const refreshData = payTree.loadPostData(result);
  760. payEvent.refreshTree(refreshData);
  761. }
  762. }, function () {
  763. SpreadJsObj.reLoadRowData(sheet, sel.row, sel.rowCount);
  764. });
  765. },
  766. baseOpr: function(type) {
  767. const self = this;
  768. const node = SpreadJsObj.getSelectObject(sheet);
  769. if (type === 'delete') {
  770. postData('update', { postType: 'delete', postData: { id: node.tree_id }}, function(result) {
  771. payEvent.reloadPays(result.reload);
  772. });
  773. } else {
  774. postData('update', { postType: type, postData: { id: node.tree_id }}, function (result) {
  775. const refreshData = payTree.loadPostData(result);
  776. payEvent.refreshTree(refreshData);
  777. const sel = sheet.getSelections()[0];
  778. if (sel) {
  779. if (['up-move', 'down-move'].indexOf(type) > -1) {
  780. sheet.setSelection(payTree.getNodeIndex(node), sel.col, sel.rowCount, sel.colCount);
  781. SpreadJsObj.reloadRowsBackColor(sheet, [sel.row, payTree.getNodeIndex(node)]);
  782. } else if (type === 'add') {
  783. sheet.setSelection(payTree.getNodeIndex(refreshData.create[0]), sel.col, sel.rowCount, sel.colCount);
  784. SpreadJsObj.reloadRowsBackColor(sheet, [sel.row, payTree.getNodeIndex(refreshData.create[0])]);
  785. }
  786. }
  787. self.refreshActn(sheet);
  788. });
  789. }
  790. },
  791. calculateAll: function() {
  792. postData('update', { postType: 'calc', postData: {}}, function (result) {
  793. payEvent.reloadPays(result.reload);
  794. });
  795. },
  796. reloadCalcBase: function() {
  797. postData('update', { postType: 'refreshBase', postData: {}}, function (result) {
  798. payEvent.reloadPays(result.reload);
  799. payCalc.reloadBase(result.calcBase, result.addBase);
  800. });
  801. },
  802. reloadPays: function(datas){
  803. payTree.loadDatas(datas);
  804. SpreadJsObj.loadSheetData(sheet, SpreadJsObj.DataType.Tree, payTree);
  805. payEvent.refreshActn();
  806. }
  807. };
  808. spread.bind(spreadNS.Events.SelectionChanged, payEvent.selectionChanged);
  809. if (!readOnly) {
  810. spread.bind(spreadNS.Events.EditStarting, payEvent.editStarting);
  811. spread.bind(spreadNS.Events.EditEnded, payEvent.editEnded);
  812. spread.bind(spreadNS.Events.ButtonClicked, payEvent.buttonClicked);
  813. SpreadJsObj.addDeleteBind(spread, payEvent.deletePress);
  814. $('a[name="base-opr"]').click(function () {
  815. payEvent.baseOpr(this.getAttribute('type'));
  816. });
  817. $('#pay-expr').bind('change onblur', function () {
  818. if (this.readOnly) return;
  819. const expr = $(this);
  820. const row = expr.attr('data-row') ? _.toInteger(expr.attr('data-row')) : -1;
  821. const select = payTree.nodes[row];
  822. const field = expr.attr('field'), orgValue = expr.attr('org'), newValue = expr.val();
  823. if (orgValue === newValue || (!orgValue && newValue == '')) { return; }
  824. const data = { postType: 'update' };
  825. if (field === 'expr') {
  826. data.postData = { id: select.id, tp: 0, expr: newValue };
  827. const [valid, msg] = payUtils.check.isSf(select)
  828. ? payCalc.checkSfExpr(newValue, data.postData, select, payTree)
  829. : payCalc.checkExpr(newValue, data.postData, select, payTree);
  830. if (!valid) {
  831. toastr.warning(msg);
  832. this.value = select.expr;
  833. return;
  834. }
  835. } else if (field === 'start_expr') {
  836. data.updateData = {id: select.id};
  837. const [valid, msg] = payCalc.checkStartExpr(select, newValue, data.postData);
  838. if (!valid) {
  839. toastr.warning(msg);
  840. this.value = select.start_expr;
  841. return;
  842. }
  843. } else if (field === 'range_expr') {
  844. data.updateData = {id: select.id};
  845. const [valid, msg] = payCalc.checkRangeExpr(select, newValue, data.postData);
  846. if (!valid) {
  847. toastr.warning(msg);
  848. this.value = select.range_expr;
  849. return;
  850. }
  851. } else {
  852. expr.val('');
  853. return;
  854. }
  855. // 更新至服务器
  856. postData('update', data, function (result) {
  857. if (result.reload) {
  858. payEvent.reloadPays(result.reload);
  859. } else {
  860. const refreshData = payTree.loadPostData(result);
  861. payEvent.refreshTree(refreshData);
  862. }
  863. });
  864. });
  865. $('#calc-all').click(function() {
  866. payEvent.calculateAll();
  867. });
  868. $('#reload-calc-base').click(function() {
  869. payEvent.reloadCalcBase();
  870. });
  871. const deadlineObj = {
  872. payNode: null,
  873. refreshHint: function() {
  874. const dlType = $('[name=dl-type]:checked').val();
  875. const dt = deadlineType[dlType];
  876. if (dlType && dt) {
  877. const dlValue = $('#dl-value').val();
  878. $('#range-hint').text(`当 ${dt.name} >= ${dlValue} 时 `);
  879. $('#dl-hint').show();
  880. } else {
  881. $('#dl-hint').hide();
  882. }
  883. },
  884. initView: function(data) {
  885. this.payNode = data;
  886. $('#dl-pay-name').html(data.name);
  887. // 模式
  888. if (data.dl_type) {
  889. $('[name=dl-type][value=' + data.dl_type +']')[0].checked = true;
  890. } else {
  891. $('#dl-type-none')[0].checked = true;
  892. }
  893. $('#dl-value').val(data.dl_value);
  894. this.refreshHint();
  895. },
  896. getDlCount: function() {
  897. try {
  898. const result = parseInt($('#dl-value').val());
  899. if (result <= 0) throw '限制值请输入正整数';
  900. return result;
  901. } catch (err) {
  902. toastr.warning('限制值请输入正整数');
  903. return 0;
  904. }
  905. },
  906. getDlTp: function() {
  907. try {
  908. const result = parseFloat($('#dl-value').val());
  909. return result;
  910. } catch (err) {
  911. toastr.warning('限制值请输入数值');
  912. return 0;
  913. }
  914. },
  915. getUpdateData: function() {
  916. const result = { postType: 'update', postData: { id: this.payNode.id } };
  917. result.postData.dl_type = $('[name=dl-type]:checked').val();
  918. if (result.postData.dl_type) {
  919. if (result.postData.dl_type === deadlineType.phaseCount.key) {
  920. result.postData.dl_value = this.getDlCount();
  921. if (result.postData.dl_value < phasePay.phase_order) {
  922. toastr.warning(`已计量至第${phasePay.phase_order}期,计提期限不可小于该期`);
  923. return null;
  924. }
  925. } else if (result.postData.dl_type === deadlineType.stageCount.key) {
  926. result.postData.dl_value = this.getDlCount();
  927. if (result.postData.dl_value < maxStageOrder) {
  928. toastr.warning(`已计量至第${maxStageOrder}期,计提期限不可小于该期`);
  929. return null;
  930. }
  931. } else {
  932. result.postData.dl_value = this.getDlTp();
  933. const dt = deadlineType[result.postData.dl_type];
  934. if (!dt) {
  935. toastr.warning('限制模式错误,请刷新页面重试');
  936. return null;
  937. }
  938. const compareValue = payCalc.addBase[`pre_${dt.key}_tp`];
  939. if (result.postData.dl_type < compareValue) {
  940. toastr.warning(`截止上期,${dt.name}已计量${compareValue},计提期限不可小于该值`);
  941. return null;
  942. }
  943. }
  944. } else {
  945. result.postData.dl_value = 0;
  946. }
  947. return result;
  948. },
  949. };
  950. $('[name=dl-type]').change(deadlineObj.refreshHint);
  951. $('#dl-value').change(deadlineObj.refreshHint);
  952. $('#deadline-ok').click(function() {
  953. const updateData = deadlineObj.getUpdateData();
  954. if (!updateData) return;
  955. postData('update', updateData, function(result) {
  956. payEvent.reloadPays(result.reload);
  957. $('#deadline').modal('hide');
  958. });
  959. });
  960. // 右键菜单
  961. $.contextMenu({
  962. selector: '#pay-spread',
  963. build: function ($trigger, e) {
  964. const target = SpreadJsObj.safeRightClickSelection($trigger, e, spread);
  965. return target.hitTestType === GC.Spread.Sheets.SheetArea.viewport || target.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
  966. },
  967. items: {
  968. 'start': {
  969. name: '启用',
  970. icon: 'fa-play',
  971. callback: function (key, opt) {
  972. const select = SpreadJsObj.getSelectObject(sheet);
  973. const data = {
  974. postType: 'update',
  975. postData: { id: select.id, is_pause: 0 }
  976. };
  977. // 更新至服务器
  978. postData('update', data, function (result) {
  979. payEvent.reloadPays(result.reload);
  980. });
  981. },
  982. visible: function (key, opt) {
  983. const select = SpreadJsObj.getSelectObject(sheet);
  984. return (!select.children || select.children.length ===0) && !readOnly && select.is_pause && payUtils.menuVisible.pause(select);
  985. }
  986. },
  987. 'stop': {
  988. name: '停用',
  989. icon: 'fa-pause',
  990. callback: function (key, opt) {
  991. const select = SpreadJsObj.getSelectObject(sheet);
  992. const data = {
  993. postType: 'update',
  994. postData: { id: select.id, is_pause: 1 }
  995. };
  996. // 更新至服务器
  997. postData('update', data, function (result) {
  998. payEvent.reloadPays(result.reload);
  999. });
  1000. },
  1001. visible: function (key, opt) {
  1002. const select = SpreadJsObj.getSelectObject(sheet);
  1003. return (!select.children || select.children.length === 0) && !readOnly && !select.is_pause && payUtils.menuVisible.pause(select);
  1004. },
  1005. },
  1006. 'setDeadline': {
  1007. name: '设置计提期限',
  1008. icon: 'fa-clipboard',
  1009. callback: function (key, opt) {
  1010. const select = SpreadJsObj.getSelectObject(sheet);
  1011. if (select.range_tp) {
  1012. deadlineObj.initView(select);
  1013. $('#deadline').modal('show');
  1014. } else {
  1015. toastr.warning('计提期限用于达到条件时,即刻计量至付(扣)款限额,应先设置付(扣)款限额');
  1016. }
  1017. },
  1018. visible: function (key, opt) {
  1019. const select = SpreadJsObj.getSelectObject(sheet);
  1020. return (!select.children || select.children.length === 0) && !readOnly && payUtils.menuVisible.deadline(select);
  1021. }
  1022. },
  1023. }
  1024. });
  1025. }
  1026. return { spread, sheet, payTree, loadDatas: payEvent.reloadPays }
  1027. })();
  1028. payObj.loadDatas(details);
  1029. const payFile = $.ledger_att({
  1030. selector: '#fujian',
  1031. key: 'uuid',
  1032. masterKey: 'rela_id',
  1033. uploadUrl: 'file/upload',
  1034. deleteUrl: 'file/delete',
  1035. checked: false,
  1036. zipName: `附件.zip`,
  1037. readOnly: false,
  1038. fileIdType: 'string',
  1039. fileInfo: {
  1040. user_name: 'user_name',
  1041. user_id: 'user_id',
  1042. create_time: 'create_time',
  1043. },
  1044. getCurHint: function(node) {
  1045. return`${node.name || ''}`;
  1046. },
  1047. locate: function (att) {
  1048. if (!att) return;
  1049. SpreadJsObj.locateTreeNode(payObj.sheet, att.node.tree_id, true);
  1050. payFile.getCurAttHtml(att.node);
  1051. }
  1052. });
  1053. // 展开收起标准清单
  1054. $('a', '#side-menu').bind('click', function (e) {
  1055. e.preventDefault();
  1056. const tab = $(this), tabPanel = $(tab.attr('content'));
  1057. // 展开工具栏、切换标签
  1058. if (!tab.hasClass('active')) {
  1059. // const close = $('.active', '#side-menu').length === 0;
  1060. $('a', '#side-menu').removeClass('active');
  1061. $('.tab-content .tab-select-show.tab-pane.active').removeClass('active');
  1062. tab.addClass('active');
  1063. tabPanel.addClass('active');
  1064. // $('.tab-content .tab-pane').removeClass('active');
  1065. showSideTools(tab.hasClass('active'));
  1066. } else { // 收起工具栏
  1067. tab.removeClass('active');
  1068. tabPanel.removeClass('active');
  1069. showSideTools(tab.hasClass('active'));
  1070. }
  1071. payObj.spread.refresh();
  1072. });
  1073. postData('load', {filter: 'file'}, function(result) {
  1074. for (const f of result.file) {
  1075. f.node = payObj.payTree.datas.find(x => { return x.uuid === f.rela_id; });
  1076. }
  1077. payFile.loadDatas(result.file);
  1078. payFile.getCurAttHtml(SpreadJsObj.getSelectObject(payObj.sheet));
  1079. });
  1080. // 工具栏spr
  1081. $.divResizer({
  1082. select: '#right-spr',
  1083. callback: function () {
  1084. payObj.spread.refresh();
  1085. }
  1086. });
  1087. // todo 加载审批列表
  1088. $.subMenu({
  1089. menu: '#sub-menu', miniMenu: '#sub-mini-menu', miniMenuList: '#mini-menu-list',
  1090. toMenu: '#to-menu', toMiniMenu: '#to-mini-menu',
  1091. key: 'menu.1.0.0',
  1092. miniHint: '#sub-mini-hint', hintKey: 'menu.hint.1.0.1',
  1093. callback: function (info) {
  1094. if (info.mini) {
  1095. $('.panel-title').addClass('fluid');
  1096. $('#sub-menu').removeClass('panel-sidebar');
  1097. } else {
  1098. $('.panel-title').removeClass('fluid');
  1099. $('#sub-menu').addClass('panel-sidebar');
  1100. }
  1101. autoFlashHeight();
  1102. payObj.spread.refresh();
  1103. }
  1104. });
  1105. });