refill_amount_stats.index.php 114 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668
  1. <?php defined('InShopNC') or exit('Access Invalid!'); ?>
  2. <style>
  3. th label {
  4. display: inline-block;
  5. width: 60px;
  6. }
  7. .page .fixed-bar .item-title h3 {
  8. margin-top: 18px !important;
  9. margin-bottom: 10px !important;
  10. font-weight: 700 !important;
  11. }
  12. .tab-base li span {
  13. font-size: 12px !important;
  14. }
  15. input::placeholder {
  16. color: #333;
  17. }
  18. .btn-container {
  19. margin-top: 10px;
  20. display: flex;
  21. justify-content: space-between;
  22. align-items: center;
  23. border: 1px solid #ccc;
  24. padding: 10px;
  25. }
  26. .btn-container div:last-child {
  27. text-align: right;
  28. }
  29. .layui-btn-sm {
  30. height: 28px !important;
  31. line-height: 28px !important;
  32. padding: 0 10px !important;
  33. }
  34. .ac-item input {
  35. width: 400px !important;
  36. height: 32px !important;
  37. line-height: 32px !important;
  38. padding: 0 10px !important;
  39. border: 1px solid #e6e6e6 !important;
  40. border-radius: 2px !important;
  41. background-color: #fff !important;
  42. box-sizing: border-box !important;
  43. margin-right: 10px;
  44. }
  45. .ac-item button {
  46. height: 32px !important;
  47. line-height: 32px !important;
  48. }
  49. .stats-panel {
  50. margin-top: 40px;
  51. margin-left: 30px;
  52. width: 1664px;
  53. overflow-x: auto;
  54. }
  55. .negative-value {
  56. color: red;
  57. }
  58. .ch-tags {
  59. display: inline-block;
  60. padding: 5px 10px;
  61. margin: 5px;
  62. background-color: #f2f2f2;
  63. border: 1px solid #dcdcdc;
  64. border-radius: 4px;
  65. position: relative;
  66. }
  67. .ch-tags .delete-btn {
  68. position: absolute;
  69. top: 0;
  70. right: 0;
  71. cursor: pointer;
  72. color: red;
  73. }
  74. .input-group {
  75. margin-top: 10px;
  76. display: flex;
  77. align-items: center;
  78. }
  79. .input-group input[type="text"] {
  80. padding: 6px 10px;
  81. border: 1px solid #d2d2d2;
  82. border-radius: 3px;
  83. font-size: 14px;
  84. outline: none;
  85. width: 200px;
  86. }
  87. .input-group .layui-btn {
  88. font-size: 14px;
  89. padding: 6px 10px;
  90. border-radius: 3px;
  91. line-height: normal;
  92. }
  93. .mch-items {
  94. display: inline-block;
  95. margin-right: 20px;
  96. min-width: 15%;
  97. line-height: 32px;
  98. }
  99. .sortable-item {
  100. cursor: move;
  101. padding: 5px;
  102. margin: 5px;
  103. background-color: #f0f0f0;
  104. border: 1px solid #ccc;
  105. display: inline-block;
  106. }
  107. .checkout-items {
  108. display: inline-block;
  109. margin-right: 20px;
  110. min-width: 15%;
  111. line-height: 32px;
  112. }
  113. .selected-items{
  114. margin-top: 20px;
  115. padding: 10px;
  116. border: 1px solid #ccc;
  117. min-height: 50px;
  118. }
  119. .layui-layer-content {
  120. padding: 20px;
  121. }
  122. .ac-item div:first-child {
  123. width: 100%;
  124. }
  125. .ac-item div:last-child {
  126. text-align: left !important;
  127. width: 100%;
  128. }
  129. #channel_names_ca, #mch_names_ca {
  130. display: inline-block;
  131. max-width: 80%;
  132. }
  133. .layui-layer-btn {
  134. text-align: center;
  135. border-top: 1px solid #F0F0F0;
  136. }
  137. .names-manager-container {
  138. margin-top: 20px;
  139. }
  140. #new_name_input {
  141. width: 360px;
  142. }
  143. .names_ca {
  144. display: inline-block;
  145. width: 80%;
  146. }
  147. .layui-table td.col-bg {
  148. background-color: #f2f2f2;
  149. }
  150. #processBar {
  151. position: fixed;
  152. top: 0;
  153. left: 0;
  154. width: 100%;
  155. height: 100%;
  156. background: rgba(0, 0, 0, 0.5);
  157. display: flex;
  158. justify-content: center;
  159. align-items: center;
  160. color: #fff;
  161. z-index: 100;
  162. }
  163. .progress-container {
  164. background-color: #f2f2f2;
  165. border-radius: 5px;
  166. overflow: hidden;
  167. height: 20px;
  168. width: 100%;
  169. margin-bottom: 10px;
  170. }
  171. .progress-bar {
  172. background-color: #5FB878;
  173. height: 100%;
  174. width: 0;
  175. line-height: 20px;
  176. color: #fff;
  177. text-align: center;
  178. white-space: nowrap;
  179. transition: width 0.4s;
  180. }
  181. #progressDescription {
  182. font-size: 16px;
  183. color:red;
  184. background-color: white;
  185. }
  186. #rechargeManual {
  187. padding: 20px;
  188. background-color: #fff;
  189. display: flex;
  190. gap: 20px;
  191. }
  192. #rechargeConfirmItems {
  193. flex: 1;
  194. }
  195. .layui-form {
  196. flex: 2;
  197. }
  198. #rechargeManual .layui-input,
  199. #rechargeManual .layui-textarea {
  200. height: 38px !important;
  201. line-height: 38px !important;
  202. }
  203. #rechargeTips {
  204. color: red;
  205. text-align: center;
  206. font-size: 14px;
  207. font-weight: 400;
  208. position: absolute;
  209. bottom: 0;
  210. left: 0;
  211. width: 100%;
  212. }
  213. .reset-bar {
  214. margin-top: 10px;
  215. width: 1532px;
  216. overflow-x: auto;
  217. white-space: nowrap;
  218. background-color: #fff;
  219. box-sizing: border-box;
  220. position: relative;
  221. height:32px;
  222. line-height: 32px;
  223. }
  224. .reset-bar button {
  225. height: 28px;
  226. line-height: 28px;
  227. display: inline-block;
  228. vertical-align: middle;
  229. }
  230. .reset-bar button:first-child {
  231. margin-left: 352px;
  232. width: 110px;
  233. }
  234. .reset-bar button:nth-child(2) {
  235. margin-left: 600px;
  236. width: 110px;
  237. }
  238. .reset-bar button:nth-child(3) {
  239. margin-left: 120px;
  240. width: 100px;
  241. }
  242. .reset-bar button:nth-child(4) {
  243. margin-left: 10px;
  244. width: 100px;
  245. }
  246. .paymodel-form .paymodel-label {
  247. width: 120px;
  248. text-align: right;
  249. white-space: nowrap;
  250. display: inline-block;
  251. vertical-align: top;
  252. }
  253. .paymodel-form .paymodel-red {
  254. vertical-align: middle;
  255. }
  256. .paymodel-form .paymodel-input-inline {
  257. width: calc(100% - 130px);
  258. display: inline-block;
  259. }
  260. .paymodel-form .paymodel-input, .paymodel-form .paymodel-textarea {
  261. width: 100%;
  262. box-sizing: border-box;
  263. }
  264. .layui-btn {
  265. position: relative;
  266. }
  267. .btn-badge {
  268. position: absolute;
  269. top: 5px;
  270. right: 5px;
  271. width: 16px;
  272. height: 16px;
  273. background-color: red;
  274. color: white;
  275. border-radius: 50%;
  276. display: flex;
  277. align-items: center;
  278. justify-content: center;
  279. font-size: 10px;
  280. font-weight: bold;
  281. }
  282. .layui-btn-light-yellow {
  283. background-color: #EF949F !important;
  284. }
  285. #rechargeManual {
  286. width: 700px;
  287. }
  288. #rechargeManualApprove {
  289. display:none;
  290. padding: 20px;
  291. width: 1210px;
  292. }
  293. </style>
  294. <div class="page" id="app">
  295. <div class="fixed-bar">
  296. <div class="item-title">
  297. <h3>上下游金额统计</h3>
  298. <ul class="tab-base">
  299. <li><a href="JavaScript:void(0);" class="current"><span>余额统计</span></a></li>
  300. <li><a href="index.php?act=refill_amount_stats&op=daily_statement"><span>日对账单</span></a></li>
  301. <li><a href="index.php?act=refill_amount_stats&op=monthly_statement"><span>月对账单</span></a></li>
  302. </ul>
  303. </div>
  304. </div>
  305. <div class="fixed-empty"></div>
  306. <!-- 顶部按钮 -->
  307. <div class="btn-container">
  308. <div class="ac-item w50pre">
  309. <up-name-select title="上游设置" type="channel_names"></up-name-select>
  310. <down-name-select title="机构设置" type="merchant_names"></down-name-select>
  311. </div>
  312. <div>
  313. <button type="button" class="layui-btn layui-bg-blue" id="btn_refresh_approve">刷新审核</button>
  314. <button type="button" class="layui-btn layui-bg-blue" id="btn_search">更新数据</button>
  315. <button type="button" class="layui-btn layui-bg-red" id="btn_copy_data">拷贝数据</button>
  316. <button type="button" class="layui-btn layui-bg-red" id="btn_import">导入数据</button>
  317. <button type="button" class="layui-btn layui-bg-red" id="btn_copy_excel">拷贝表格</button>
  318. </div>
  319. </div>
  320. <div class="layui-clear"></div>
  321. <!-- 普充上游统计区 -->
  322. <div class="stats-panel layui-font-14">
  323. <selected-channel-normal title="选择普充通道" type="KEY_CHANNEL_NORMAL" emit="updateNormalTb"></selected-channel-normal>
  324. <div class="reset-bar">
  325. <button type="button" class="layui-btn layui-btn-light-yellow reset-col" data-table="upstream_tb_normal" data-col="transfer">一键清0</button>
  326. <button type="button" class="layui-btn layui-btn-light-yellow reset-col" data-table="upstream_tb_normal" data-col="payment_design">一键清0</button>
  327. <button type="button" class="layui-btn layui-bg-orange ac-batch-deposit" data-table="upstream_tb_normal">批量加款</button>
  328. <button type="button" class="layui-btn layui-bg-red ac-approve" data-table="upstream_tb_normal">
  329. 审批
  330. <span class="btn-badge" id="approveBadgeNormal">0</span>
  331. </button>
  332. </div>
  333. <table class="layui-hide" id="upstream_tb_normal"></table>
  334. </div>
  335. <!-- 快充上游统计区 -->
  336. <div class="stats-panel layui-font-14">
  337. <selected-channel-fast title="选择快充通道" type="KEY_CHANNEL_FAST" emit="updateFastTb"></selected-channel-fast>
  338. <div class="reset-bar">
  339. <button type="button" class="layui-btn layui-btn-light-yellow reset-col" data-table="upstream_tb_fast" data-col="transfer">一键清0</button>
  340. <button type="button" class="layui-btn layui-btn-light-yellow reset-col" data-table="upstream_tb_fast" data-col="payment_design">一键清0</button>
  341. <button type="button" class="layui-btn layui-bg-orange ac-batch-deposit" data-table="upstream_tb_fast">批量加款</button>
  342. <button type="button" class="layui-btn layui-bg-red ac-approve" data-table="upstream_tb_fast">
  343. 审批
  344. <span class="btn-badge" id="approveBadgeFast">0</span>
  345. </button>
  346. </div>
  347. <table class="layui-hide" id="upstream_tb_fast"></table>
  348. </div>
  349. <!-- 机构统计区 -->
  350. <div class="stats-panel layui-font-14">
  351. <selected-merchant title="选择机构" type="KEY_MERCHANT" emit="mchsetChange"></selected-merchant>
  352. <table class="layui-hide" id="downstream_tb"></table>
  353. </div>
  354. <!-- 导入数据弹层 -->
  355. <div id="importLayer" style="display: none;">
  356. <div class="layui-form" style="padding: 20px;">
  357. <div class="layui-form-item layui-form-text">
  358. <textarea id="clipboardContent" class="layui-textarea" rows="20"></textarea>
  359. </div>
  360. </div>
  361. </div>
  362. <!-- 执行加款 -->
  363. <div id="rechargeManual" style="display:none; padding: 20px;">
  364. <div class="layui-form-item" id="rechargeConfirmItems">
  365. <table class="layui-hide" id="upstream_tb_transfer"></table>
  366. </div>
  367. <div id="rechargeTips"></div>
  368. </div>
  369. <!-- 审核 -->
  370. <div id="rechargeManualApprove">
  371. <table class="layui-hide" id="upstream_tb_approve"></table>
  372. </div>
  373. <!-- 全屏进度条 -->
  374. <div class="layui-container" style="display:none;" id="processBar">
  375. <div class="layui-row">
  376. <div class="layui-col-xs12">
  377. <div class="progress-container">
  378. <div class="progress-bar" id="progress-bar">0%</div>
  379. </div>
  380. <div id="progressDescription">初始化...</div>
  381. </div>
  382. </div>
  383. </div>
  384. </div>
  385. <script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/laydate/laydate.js"></script>
  386. <script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/jquery-ui/jquery.ui.js"></script>
  387. <script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/jquery-ui/i18n/zh-CN.js" charset="utf-8"></script>
  388. <script type="text/javascript" src="<?php echo RESOURCE_SITE_URL;?>/refill/layer.js"></script>
  389. <script type="text/javascript" src="<?php echo ADMIN_TEMPLATES_URL;?>/js/xm-select.js"></script>
  390. <script type="text/javascript" src="<?php echo ADMIN_TEMPLATES_URL;?>/layui/layui.js"></script>
  391. <link rel="stylesheet" type="text/css" href="<?php echo ADMIN_TEMPLATES_URL; ?>/layui/css/layui.css"/>
  392. <link rel="stylesheet" type="text/css" href="<?php echo RESOURCE_SITE_URL; ?>/js/jquery-ui/themes/ui-lightness/jquery.ui.css"/>
  393. <script type="text/javascript" src="<?php echo ADMIN_TEMPLATES_URL;?>/js/stats-utils.js?t=<?php echo time();?>"></script>
  394. <script type="text/javascript" src="<?php echo ADMIN_TEMPLATES_URL;?>/js/stats-amount.js?t=<?php echo time();?>"></script>
  395. <?php session_start(); ?>
  396. <script type="text/javascript">
  397. const systemTag = '<?php echo ADMIN_NAME;?>';
  398. const systemUserName = '<?php echo $output['admin_info']['name'];?>';
  399. const globalData = {};
  400. const settingsKeys = [
  401. CONSTANTS.KEY_CHANNEL_NAMES,
  402. CONSTANTS.KEY_MERCHANT_NAMES,
  403. CONSTANTS.KEY_CHANNEL_FAST,
  404. CONSTANTS.KEY_CHANNEL_NORMAL,
  405. CONSTANTS.KEY_MERCHANT
  406. ];
  407. $(function() {
  408. const app = new ComponentBase({
  409. el: '#app',
  410. componentData: {
  411. 'up-name-select': [],
  412. 'down-name-select': [],
  413. 'selected-channel-normal': [],
  414. 'selected-channel-fast': [],
  415. 'selected-merchant': []
  416. },
  417. components: {
  418. 'up-name-select': StreamNameComponent,
  419. 'down-name-select': StreamNameComponent,
  420. 'selected-channel-normal': SelectedChannelComponent,
  421. 'selected-channel-fast': SelectedChannelComponent,
  422. 'selected-merchant': SelectedMerchantComponent
  423. }
  424. });
  425. app.on('updateNormalTb', () => {
  426. initPage();
  427. });
  428. app.on('updateFastTb', () => {
  429. initPage();
  430. });
  431. app.on('mchsetChange', () => {
  432. initPage();
  433. });
  434. class GlobalData extends GlobalDataBase {
  435. static FIELD_MAP = {
  436. ...GlobalDataBase.FIELD_MAP,
  437. SYS_CHAN_NORMAL: 'sys_chan_normal',
  438. SYS_MCHS: 'sys_mchs',
  439. SYS_CHAN_FAST: 'sys_chan_fast',
  440. DATA_CHAN_NORMAL: 'chan_normal_data',
  441. DATA_CHAN_FAST: 'chan_fast_data',
  442. DATA_MERCHANT: 'mch_data',
  443. COPY_DATA: 'copy_data',
  444. PAYINFO: 'payinfo',
  445. };
  446. setPayinfo(storeId, tag, amount) {
  447. if (!isNumeric(amount)) {
  448. return;
  449. }
  450. const key = this.constructor.FIELD_MAP.PAYINFO;
  451. if (!this.data[key]) {
  452. this.data[key] = [];
  453. }
  454. const find = this.data[key].find(item => item.store_id === storeId && item.tag === tag);
  455. if (!find) {
  456. this.data[key].push({ store_id: storeId, tag: tag, amount: amount });
  457. } else {
  458. find.amount = amount;
  459. }
  460. }
  461. getPayinfo() {
  462. const key = this.constructor.FIELD_MAP.PAYINFO;
  463. return this.data[key] || [];
  464. }
  465. getPayinfoAmount(storeId, tag) {
  466. const key = this.constructor.FIELD_MAP.PAYINFO;
  467. const find = (this.data[key] || []).find(item => item.store_id === storeId && item.tag === tag);
  468. return find ? find.amount : '0';
  469. }
  470. }
  471. class ChannelTable extends LayuiTableBase{
  472. constructor(type, batchDeposit) {
  473. const tableId = type === 'normal' ? 'upstream_tb_normal' : 'upstream_tb_fast';
  474. super(tableId);
  475. this.type = type;
  476. this.batchDeposit = batchDeposit;
  477. }
  478. getChannelSettings() {
  479. if (this.type === 'normal') {
  480. return globalData.getChannelNormal();
  481. } else if(this.type === 'fast') {
  482. return globalData.getChannelFast();
  483. }
  484. }
  485. setChannelSettings(data) {
  486. if (this.type === 'normal') {
  487. return globalData.setChannelNormal(data);
  488. } else if(this.type === 'fast') {
  489. return globalData.setChannelFast(data);
  490. }
  491. }
  492. getChannelData() {
  493. if (this.type === 'normal') {
  494. return globalData.getDataChanNormal();
  495. } else if(this.type === 'fast') {
  496. return globalData.getDataChanFast();
  497. }
  498. }
  499. setChannelData(data) {
  500. if (this.type === 'normal') {
  501. return globalData.setDataChanNormal(data);
  502. } else if(this.type === 'fast') {
  503. return globalData.setDataChanFast(data);
  504. }
  505. }
  506. getCacheKey() {
  507. if (this.type === 'normal') {
  508. return CONSTANTS.KEY_CHANNEL_NORMAL;
  509. } else if(this.type === 'fast') {
  510. return CONSTANTS.KEY_CHANNEL_FAST;
  511. }
  512. }
  513. getCopyDataChan() {
  514. const copyData = globalData.getCopyData();
  515. if (copyData.length === 0) {
  516. return [];
  517. }
  518. if (this.type === 'normal') {
  519. return copyData.stats_data_normal;
  520. } else if(this.type === 'fast') {
  521. return copyData.stats_data_fast;
  522. }
  523. }
  524. getCopySortChan() {
  525. const copyData = globalData.getCopyData();
  526. if (copyData.length === 0) {
  527. return [];
  528. }
  529. if (this.type === 'normal') {
  530. return copyData.stats_channel_normal;
  531. } else if(this.type === 'fast') {
  532. return copyData.stats_channel_fast;
  533. }
  534. }
  535. async loadData() {
  536. const copyData = globalData.getCopyData();
  537. const chanCust = this.getChannelSettings();
  538. const storeIds = chanCust
  539. .filter(item => item.tag === systemTag)
  540. .map(item => item.store_id)
  541. .join(',');
  542. const params = { store_ids: storeIds };
  543. const channelFetch = await statsApi.getChannelData(params);
  544. let chanData = [];
  545. if(channelFetch.state === true) {
  546. chanData = channelFetch.list;
  547. }
  548. if (!isObjectEmpty(copyData)) {
  549. const copyDataChan = this.getCopyDataChan();
  550. copyDataChan.forEach(item => {
  551. const selfItem = chanData.find(dn => {
  552. return dn.store_id === item.store_id && dn.tag === item.tag;
  553. });
  554. if (selfItem !== undefined) {
  555. item.balance = selfItem.balance;
  556. item.available_predeposit = selfItem.available_predeposit;
  557. }
  558. });
  559. chanData = mergeData(chanData, copyDataChan, 'store_name', systemTag);
  560. }
  561. let tableData = [];
  562. for (let item of chanData) {
  563. const setting = chanCust.find(function(chan) {
  564. return chan.name === item.name && chan.tag === item.tag;
  565. });
  566. let tableItem = {}, alarm_amount = '0', payment_design = '0', pay_operation = '';
  567. if (setting) {
  568. alarm_amount = setting.alarm_amount ?? '0';
  569. payment_design = setting.payment_design ?? '0';
  570. pay_operation = setting.pay_operation ?? '';
  571. }
  572. tableItem['transfer'] = globalData.getPayinfoAmount(item.store_id, item.tag);
  573. tableItem['payment_deviation'] = '0';
  574. tableItem['tag'] = item.tag;
  575. tableItem['store_id'] = item.store_id;
  576. tableItem['store_name'] = item.store_name;
  577. tableItem['name'] = item.name;
  578. tableItem['balance'] = formatDecimals(item.balance);
  579. tableItem['available_predeposit'] = formatDecimals(item.available_predeposit);
  580. tableItem['alarm_amount'] = formatDecimals(alarm_amount);
  581. tableItem['payment_design'] = formatDecimals(payment_design);
  582. tableItem['upstream_group'] = '';
  583. tableItem['pay_operation'] = pay_operation;
  584. tableData.push(tableItem);
  585. }
  586. const that = this;
  587. tableData.forEach(item => {
  588. item.upstream_group = that.getItemGroup(item);
  589. });
  590. let sortCust = [];
  591. if (!isObjectEmpty(copyData)) {
  592. sortCust = mergeData(chanCust, this.getCopySortChan(), 'store_name', systemTag);
  593. } else {
  594. sortCust = chanCust;
  595. }
  596. this.setChannelSettings(sortCust);
  597. let chanDataSort = sortCustData(sortCust, tableData, 'upstream_group', 'store_name');
  598. chanDataSort = sortByName(chanDataSort, 'store_name');
  599. //更新统计字段的值:表格合并后是展示第一条数据的值,取值逻辑:当前组第一条不为0的数据
  600. const groupUpdates = {}, groupAvailablePredeposit = {};
  601. chanDataSort.forEach(item => {
  602. if (!groupAvailablePredeposit[item.upstream_group]) {
  603. groupAvailablePredeposit[item.upstream_group] = 0;
  604. }
  605. groupAvailablePredeposit[item.upstream_group] += parseFloat(item.available_predeposit);
  606. if (!groupUpdates[item.upstream_group]) {
  607. groupUpdates[item.upstream_group] = {
  608. alarm_amount: '0',
  609. payment_design: '0',
  610. pay_operation: ''
  611. };
  612. }
  613. if (groupUpdates[item.upstream_group].alarm_amount === '0' && item.alarm_amount !== '0') {
  614. groupUpdates[item.upstream_group].alarm_amount = item.alarm_amount;
  615. }
  616. if (groupUpdates[item.upstream_group].payment_design === '0' && item.payment_design !== '0') {
  617. groupUpdates[item.upstream_group].payment_design = item.payment_design;
  618. }
  619. if (groupUpdates[item.upstream_group].pay_operation === '' && item.pay_operation !== '') {
  620. groupUpdates[item.upstream_group].pay_operation = item.pay_operation;
  621. }
  622. });
  623. chanDataSort.forEach((item) => {
  624. if (groupUpdates[item.upstream_group] !== undefined) {
  625. item.alarm_amount = groupUpdates[item.upstream_group].alarm_amount;
  626. item.payment_design = groupUpdates[item.upstream_group].payment_design;
  627. item.pay_operation = groupUpdates[item.upstream_group].pay_operation;
  628. }
  629. });
  630. this.setChannelData(chanDataSort);
  631. }
  632. syncChannelData() {
  633. const channelCust = this.getChannelSettings();
  634. const cacheKey = this.getCacheKey();
  635. statsApi.setStatsSettings(cacheKey, channelCust)
  636. .then(function (data) {
  637. if (data.state !== true) {
  638. layer.msg('缓存失败', {
  639. icon: 1,
  640. time: 2000
  641. });
  642. }
  643. })
  644. .catch(function (error) {
  645. layer.msg('缓存失败', {
  646. icon: 1,
  647. time: 2000
  648. });
  649. });
  650. }
  651. getItemGroup(item) {
  652. const chanNames = globalData.getChannelNames();
  653. let matched = false;
  654. let groupName = '';
  655. chanNames.forEach(name => {
  656. if (item.store_name.startsWith(name)) {
  657. groupName = name;
  658. matched = true;
  659. }
  660. });
  661. if (!matched) {
  662. groupName = item.store_name;
  663. }
  664. return groupName;
  665. }
  666. updateChannelCache(itemData, action) {//action=edit/del
  667. const channelCust = this.getChannelSettings();
  668. if (action === 'edit') {
  669. channelCust.forEach(item => {
  670. const groupName = this.getItemGroup(item);
  671. if (itemData.upstream_group === groupName) {
  672. item.alarm_amount = itemData.alarm_amount;
  673. item.payment_design = itemData.payment_design;
  674. item.pay_operation = itemData.pay_operation;
  675. }
  676. });
  677. } else if (action ==='del') {
  678. let chanTmp = [];
  679. const updateFlag = itemData.name + '-' + itemData.tag;
  680. channelCust.forEach(item => {
  681. const itemFlag = item.name + '-' + item.tag;
  682. if (itemFlag !== updateFlag) {
  683. chanTmp.push(item);
  684. }
  685. });
  686. this.setChannelSettings(chanTmp);
  687. }
  688. }
  689. async renderTable() {
  690. await this.loadData();
  691. const that = this;
  692. const tableData = this.getChannelData();
  693. let tableTitle = this.type === 'normal' ? '普充' : '快充';
  694. layui.table.render({
  695. elem: '#' + this.tableId,
  696. data: tableData,
  697. limit: tableData.length,
  698. cols: [[
  699. {field: 'payment_deviation', title: '<span style="font-weight:bold">' + tableTitle + ' 加-打 差额 </span>', width: 150},
  700. {field: 'store_name', title: '上游名称', width: 200},
  701. {field: 'transfer', title: '加款金额', width: 110},
  702. {field: 'available_predeposit', title: '订单成功后余额', width: 150},
  703. {field: 'balance', title: '接口查询余额', width: 150},
  704. {field: 'alarm_amount', title: '打款预警金额', width: 150},
  705. {field: 'plan_payment_amount', title: '预计打款金额', width: 150},
  706. {field: 'payment_design', title: '打款设计', width: 110},
  707. {field: 'upstream_group', title: '需打款上游', width: 100},
  708. {field: 'pay_operation', title: '操作人姓名', width: 120},
  709. {field: 'delete', title: '删除', width: 100, templet: function(d){return '<button class="layui-btn layui-btn-sm delete-btn" data-index="'+d.LAY_TABLE_INDEX+'">删除</button>';}},
  710. {field: 'transfer_action', title: '调款', width: 160, templet: function(d){
  711. return '<button class="layui-btn layui-btn-sm transfer-btn" data-index="'+d.LAY_TABLE_INDEX+'">单个加款</button>' +
  712. '<button class="layui-btn layui-btn-sm transfer-copy-btn" data-index="'+d.LAY_TABLE_INDEX+'">复制</button>';
  713. }}
  714. ]],
  715. done: function(res, curr, count) {
  716. const tableItem = $('#' + that.tableId);
  717. const $trs = tableItem.next('.layui-table-view').find('.layui-table-body tbody tr');
  718. $trs.each(function(i, tr) {
  719. const upstreamGroup = tableData[i].upstream_group;
  720. $(tr).attr('upstream_group', upstreamGroup);
  721. $(tr).attr('store_id', tableData[i].store_id);
  722. $(tr).attr('tag', tableData[i].tag);
  723. });
  724. that.mergeCells();
  725. const editNumberColumns = ['transfer', 'alarm_amount', 'payment_design'];
  726. const editTextColumns = ['pay_operation'];
  727. $trs.each(function(i, tr) {
  728. for(let col of editNumberColumns) {
  729. const $td = $(tr).find('td[data-field="' + col + '"]').not('.layui-hide');
  730. if ($td.length > 0) {//合并隐藏的不处理
  731. const $valDiv = $td.find('div');
  732. $valDiv.attr('contenteditable', true).css('background-color', 'lightblue');
  733. $valDiv.off('input', handleInputd2)
  734. .off('keypress')
  735. .off('blur')
  736. .on('input', handleInputd2)
  737. .on('keypress', function(e) {
  738. if (e.keyCode === 13) {
  739. e.preventDefault();
  740. $(this).blur();
  741. }
  742. })
  743. .on('blur', function() {
  744. let val = $valDiv.text().trim();
  745. if (!isNumeric(val)) {
  746. $valDiv.html('0');
  747. }
  748. val = normalizeAmount(val);//过滤,比如前导 0
  749. $valDiv.html(formatDecimals(val));
  750. if (col === 'payment_design') {
  751. if (Number(val) < 0) {
  752. $valDiv.html(Number(val).toFixed(2)*-1);
  753. }
  754. that.columnSum('payment_design');
  755. that.calcGroupDeviation('transfer', 'payment_design', 'payment_deviation', 2);
  756. }
  757. if (col === 'alarm_amount') {
  758. that.calcGroupDeviation('available_predeposit', 'alarm_amount', 'plan_payment_amount', 1);
  759. }
  760. if (col === 'transfer') { //调款操作,无需表格更新和缓存处理
  761. if (Number(val) < 0) {
  762. val *= -1;
  763. $valDiv.html(formatDecimals(val));
  764. }
  765. const channelItem = tableData[i];
  766. globalData.setPayinfo(channelItem.store_id, channelItem.tag, val);
  767. //同步更新到复制源中,避免修改后更新数据被源覆盖
  768. const copyData = globalData.getCopyData() || {};
  769. if (copyData.hasOwnProperty('stats_transfer') && copyData.stats_transfer.length > 0) {
  770. const copyTransfer = copyData.stats_transfer;
  771. const copyItem = copyTransfer.find(ct => {
  772. return ct.store_id === channelItem.store_id && ct.tag === channelItem.tag;
  773. });
  774. if (copyItem !== undefined) {
  775. copyItem.amount = val;
  776. }
  777. }
  778. that.calcGroupDeviation('transfer', 'payment_design', 'payment_deviation', 2);
  779. that.setValueClass(['balance', 'available_predeposit', 'alarm_amount', 'plan_payment_amount', 'payment_design', 'payment_deviation'], ['payment_deviation']);
  780. return;
  781. }
  782. that.upstreamStatus();
  783. that.setValueClass(['balance', 'available_predeposit', 'alarm_amount', 'plan_payment_amount', 'payment_design', 'payment_deviation'], ['payment_deviation']);
  784. const index = $(this).parent().parent().data('index');
  785. that.saveEdit(index);
  786. that.syncChannelData();
  787. });
  788. }
  789. }
  790. for(let col of editTextColumns) {
  791. const $td = $(tr).find('td[data-field="' + col + '"]').not('.layui-hide');
  792. if ($td.length > 0) {//合并隐藏的不处理
  793. const $valDiv = $td.find('div');
  794. let val = $valDiv.text().trim();
  795. $valDiv.html(val);
  796. $valDiv.attr('contenteditable', true).css('background-color', 'lightblue');
  797. $valDiv.off('input')
  798. .off('keypress')
  799. .off('blur')
  800. .on('input')
  801. .on('keypress', function(e) {
  802. if (e.keyCode === 13) {
  803. e.preventDefault();
  804. $(this).blur();
  805. }
  806. })
  807. .on('blur', function() {
  808. const index = $(this).parent().parent().data('index');
  809. that.saveEdit(index);
  810. that.syncChannelData();
  811. });
  812. }
  813. }
  814. });
  815. tableItem.next('.layui-table-view').find('.layui-table-body tbody').append(
  816. '<tr>' +
  817. '<td>合计</td>' +
  818. '<td></td>' +
  819. '<td></td>' +
  820. '<td><span id="table_sum_available_predeposit_' + that.type + '">0</span></td>' +
  821. '<td></td>' +
  822. '<td></td>' +
  823. '<td></td>' +
  824. '<td><span id="table_sum_payment_design_' + that.type + '">0</span></td>' +
  825. '<td></td>' +
  826. '<td></td>' +
  827. '</tr>'
  828. );
  829. that.updateTableCalc()
  830. tableItem.next('.layui-table-view').off('click', '.delete-btn').on('click', '.delete-btn', function (){
  831. const index = $(this).data('index');
  832. that.deleteRow(index);
  833. });
  834. tableItem.next('.layui-table-view').off('click', '.transfer-btn').on('click', '.transfer-btn', function (){
  835. const index = $(this).data('index');
  836. that.transfer(index);
  837. });
  838. tableItem.next('.layui-table-view').off('click', '.transfer-copy-btn').on('click', '.transfer-copy-btn', function (){
  839. const index = $(this).data('index');
  840. that.transferCopy(index);
  841. });
  842. }
  843. });
  844. };
  845. updateTableCalc () {
  846. this.columnSum('available_predeposit');
  847. this.columnSum('payment_design');
  848. this.calcGroupDeviation('available_predeposit', 'alarm_amount', 'plan_payment_amount', 1);
  849. this.calcGroupDeviation('transfer', 'payment_design', 'payment_deviation', 2);
  850. this.setValueClass(['balance', 'available_predeposit', 'alarm_amount', 'plan_payment_amount', 'payment_design', 'payment_deviation'], ['payment_deviation']);
  851. this.upstreamStatus();
  852. }
  853. updateToCache (col, val) {
  854. const channelCust = this.getChannelSettings();
  855. channelCust.forEach(item => {
  856. item[col] = val;
  857. });
  858. this.setChannelSettings(channelCust);
  859. this.syncChannelData();
  860. }
  861. saveEdit (index) {
  862. const groupAvailablePredeposit = {}, groupTransfer = {};
  863. const channelData = this.getChannelData();
  864. if (index >= channelData.length) {
  865. return;
  866. }
  867. channelData.forEach((item) => {
  868. if (!groupAvailablePredeposit[item.upstream_group]) {
  869. groupAvailablePredeposit[item.upstream_group] = 0;
  870. }
  871. groupAvailablePredeposit[item.upstream_group] += parseFloat(item.available_predeposit);
  872. if (!groupTransfer[item.upstream_group]) {
  873. groupTransfer[item.upstream_group] = 0;
  874. }
  875. groupTransfer[item.upstream_group] += parseFloat(item.transfer);
  876. });
  877. const that = this;
  878. const $tr = $('#' + this.tableId).next('.layui-table-view').find('.layui-table-body tbody tr[data-index="' + index + '"]');
  879. const alarm_amount = $tr.find('td[data-field="alarm_amount"]').find('div').text().trim();
  880. const payment_design = $tr.find('td[data-field="payment_design"]').find('div').text().trim();
  881. const transfer = $tr.find('td[data-field="transfer"]').find('div').text().trim();
  882. const pay_operation = $tr.find('td[data-field="pay_operation"]').find('div').text().trim();
  883. //由于这几列按组合并了,在更新的时候,要给组内的每一条数据同步相同的值
  884. const groupName = channelData[index].upstream_group;
  885. channelData.forEach(function (item) {
  886. if (item.upstream_group === groupName) {
  887. item.alarm_amount = alarm_amount || "0";
  888. item.payment_design = payment_design || "0";
  889. item.transfer = transfer || "0";
  890. item.pay_operation = pay_operation || "";
  891. if (groupAvailablePredeposit[item.upstream_group] !== undefined) {
  892. const planPaymentAmount = parseFloat(groupAvailablePredeposit[item.upstream_group]) - parseFloat(item.alarm_amount);
  893. item.plan_payment_amount = planPaymentAmount < 0 ? formatDecimals(planPaymentAmount) : '0';
  894. }
  895. if (groupTransfer[item.upstream_group] !== undefined) {
  896. item.payment_deviation = parseFloat(groupTransfer[item.upstream_group]) - parseFloat(item.alarm_amount);
  897. }
  898. that.updateChannelCache(item, 'edit');
  899. }
  900. });
  901. }
  902. mergeCells() {
  903. const $tbRoot = $('#' + this.tableId);
  904. const $trs = $tbRoot.next('.layui-table-view').find('.layui-table-body tbody tr');
  905. //合并打款上游
  906. const upstreamMap = {};
  907. $trs.each(function(i, tr) {
  908. const group = $(tr).attr('upstream_group');
  909. if (group) {
  910. if (!upstreamMap[group]) {
  911. upstreamMap[group] = {count: 0, startIndex: i};
  912. }
  913. upstreamMap[group].count++;
  914. }
  915. });
  916. for (let group in upstreamMap) {
  917. const info = upstreamMap[group];
  918. if (info.count > 1) {
  919. //合并的列:打款预警金额/预计打款金额/打款设计/打款上游/调款按钮/操作人姓名
  920. const mergeColumns = ['alarm_amount', 'plan_payment_amount', 'payment_design', 'upstream_group', 'transfer_action', 'payment_deviation', 'pay_operation'];
  921. for (let col of mergeColumns) {
  922. $trs.eq(info.startIndex).find('td[data-field="' + col + '"]').attr('rowspan', info.count);
  923. for (let j = 1; j < info.count; j++) {
  924. $trs.eq(info.startIndex + j).find('td[data-field="' + col + '"]').addClass('layui-hide');
  925. }
  926. }
  927. }
  928. }
  929. };
  930. deleteRow(index) {
  931. let that = this;
  932. const channelData = this.getChannelData();
  933. const delItem = channelData[index];
  934. layer.confirm('确定要删除 ' + delItem.store_name + ' 吗?', { icon: 3, title: '删除确认' }, function (confirmIndex) {
  935. const itemData = channelData.splice(index, 1);
  936. that.updateChannelCache(itemData[0], 'del');
  937. that.syncChannelData();
  938. //删除导入数据中的项
  939. const copyData = globalData.getCopyData();
  940. if (!isObjectEmpty(copyData)) {
  941. copyData.stats_channel_fast = copyData.stats_channel_fast.filter(item => item.tag !== delItem.tag || item.name !== delItem.name );
  942. copyData.stats_channel_normal = copyData.stats_channel_normal.filter(item => item.tag !== delItem.tag || item.name !== delItem.name );
  943. copyData.stats_data_fast = copyData.stats_data_fast.filter(item => item.tag !== delItem.tag || item.name !== delItem.name );
  944. copyData.stats_data_normal = copyData.stats_data_normal.filter(item => item.tag !== delItem.tag || item.name !== delItem.name );
  945. }
  946. layui.table.reload(that.tableId, {
  947. data: channelData
  948. });
  949. layer.close(confirmIndex);
  950. });
  951. };
  952. transfer(index) {
  953. this.batchDeposit.doApplyOne(this.tableId, this.getChannelData(), index);
  954. };
  955. transferCopy(index) {
  956. const $trs = $('#' + this.tableId).next('.layui-table-view').find('.layui-table-body tbody tr');
  957. const $targetRow = $trs.eq(index);
  958. const upstreamGroup = $targetRow.attr('upstream_group');
  959. const $matchingRows = $trs.filter(function() {
  960. return $(this).attr('upstream_group') === upstreamGroup;
  961. });
  962. let copyStr = '';
  963. const that = this;
  964. $matchingRows.each(function() {
  965. const $td = $(this).find('td[data-field="transfer"]');
  966. const paymentAmount = $td.find('div').text().trim();
  967. if (!isNumeric(paymentAmount) || formatDecimals(paymentAmount) === '0') {
  968. return;
  969. }
  970. const currIndex = $(this).index();
  971. const channelData = that.getChannelData();
  972. const channelItem = channelData[currIndex] || {};
  973. if (!isObjectEmpty(channelItem)) {
  974. copyStr += `加款账号:${channelItem.name} (${channelItem.store_name})\n`;
  975. copyStr += '加款金额:' + formatDecimals(paymentAmount, 4) +'元' + '\n';
  976. }
  977. });
  978. if (copyStr === '') {
  979. showErr('请设置加款项后再复制');
  980. return;
  981. }
  982. let oInput = document.createElement("textarea");
  983. oInput.style.border = "0 none";
  984. oInput.style.color = "transparent";
  985. oInput.value = copyStr;
  986. document.body.appendChild(oInput);
  987. oInput.select();
  988. document.execCommand("Copy");
  989. oInput.parentNode.removeChild(oInput)
  990. showSuccess('拷贝成功');
  991. };
  992. columnSum(field) {
  993. const $table = $('#' + this.tableId).next('.layui-table-view');
  994. const $tr = $table.find('.layui-table-body tbody tr');
  995. let sum = 0;
  996. $tr.each(function (index, element) {
  997. const $td = $(element).find('td[data-field="' + field + '"]').not('.layui-hide').find('.layui-table-cell');
  998. if ($td.length > 0) {
  999. const paymentDesign = $td.text().trim();
  1000. if (isNumeric(paymentDesign)) {
  1001. sum += parseFloat(paymentDesign);
  1002. }
  1003. }
  1004. });
  1005. const $cell = $table.find('#table_sum_' + field + '_' + this.type);
  1006. if (sum < 0) {
  1007. $cell.css('color', 'red');
  1008. } else {
  1009. $cell.css('color', '');
  1010. }
  1011. $cell.html(formatDecimals(sum));
  1012. }
  1013. calcGroupDeviation(firstCloumn, secondCloumn, resultCloumn, special) {
  1014. let groupFirstSum = {};
  1015. let groupSecondSum = {};
  1016. const $trs = $('#' + this.tableId).next('.layui-table-view').find('.layui-table-body tbody tr');
  1017. $trs.each(function (index, element) {
  1018. const firstVal = $(element).find('td[data-field="' + firstCloumn + '"]').find('.layui-table-cell').text().trim();
  1019. const tdGroup = $(element).attr('upstream_group');
  1020. if (!tdGroup) {
  1021. return;
  1022. }
  1023. if (!groupFirstSum[tdGroup]) {
  1024. groupFirstSum[tdGroup] = 0;
  1025. }
  1026. if (isNumeric(firstVal)) {
  1027. groupFirstSum[tdGroup] += parseFloat(firstVal);
  1028. }
  1029. const $td = $(element).find('td[data-field="' + secondCloumn + '"]').not('.layui-hide').find('.layui-table-cell');
  1030. if ($td.length > 0) {
  1031. if (!groupSecondSum[tdGroup]) {
  1032. const secondVal = $td.text().trim();
  1033. if (isNumeric(secondVal)) {
  1034. groupSecondSum[tdGroup] = parseFloat(secondVal);
  1035. }
  1036. }
  1037. }
  1038. });
  1039. $trs.each(function (index, element) {
  1040. const $td = $(element).find('td[data-field="' + resultCloumn + '"]').not('.layui-hide').find('.layui-table-cell');
  1041. const tdGroup = $(element).attr('upstream_group');
  1042. if (!tdGroup) {
  1043. return;
  1044. }
  1045. if ($td.length > 0) {
  1046. const val = groupFirstSum[tdGroup] - groupSecondSum[tdGroup];
  1047. if(isNumeric(val) && special === 1 && val < 0) {
  1048. $td.html(formatDecimals(val));
  1049. } else if(isNumeric(val) && special === 2) {
  1050. $td.html(formatDecimals(val));
  1051. } else {
  1052. $td.html('0');
  1053. }
  1054. }
  1055. });
  1056. }
  1057. upstreamStatus () { //设计打款为0时,不显示分组名称
  1058. const $trs = $('#' + this.tableId).next('.layui-table-view').find('.layui-table-body tbody tr');
  1059. $trs.each(function(i, tr) {
  1060. const paymentDesignDiv = $(tr).find('td[data-field="payment_design"]').not('.layui-hide');
  1061. if (paymentDesignDiv.length > 0) {
  1062. const upstreamGroup = $(tr).attr('upstream_group');
  1063. const paymentDesign = paymentDesignDiv.text().trim();
  1064. if (!isNumeric(paymentDesign) || Number(paymentDesign) === 0) {
  1065. $(tr).find('td[data-field="upstream_group"]').find('div').html('');
  1066. } else {
  1067. $(tr).find('td[data-field="upstream_group"]').find('div').html(upstreamGroup);
  1068. }
  1069. }
  1070. });
  1071. }
  1072. }
  1073. class MchTable extends LayuiTableBase{
  1074. getCopySortMch() {
  1075. const copyData = globalData.getCopyData();
  1076. if (copyData.length === 0) {
  1077. return [];
  1078. }
  1079. return copyData.stats_merchant;
  1080. }
  1081. getCopyDataMch() {
  1082. const copyData = globalData.getCopyData();
  1083. if (copyData.length === 0) {
  1084. return [];
  1085. }
  1086. return copyData.stats_data_mch;
  1087. }
  1088. setMchData(data) {
  1089. globalData.setDataMerchant(data);
  1090. };
  1091. getMchData() {
  1092. return globalData.getDataMerchant();
  1093. };
  1094. async loadData() {
  1095. const copyData = globalData.getCopyData();
  1096. const mchCust = globalData.getMerchant();
  1097. const mchIds = mchCust
  1098. .filter(item => item.tag === systemTag)
  1099. .map(item => item.mch_id)
  1100. .join(',');
  1101. const params = { mch_ids: mchIds };
  1102. const mchFetch = await statsApi.getMchData(params);
  1103. let mchData = [];
  1104. if (mchFetch.state === true) {
  1105. mchData = mchFetch.list;
  1106. }
  1107. mchData.forEach(function(item) {
  1108. item.debt *= -1;
  1109. });
  1110. if (!isObjectEmpty(copyData)) {
  1111. const copyDataMch = this.getCopyDataMch();
  1112. copyDataMch.forEach(item => {
  1113. const selfItem = mchData.find(dn => {
  1114. return dn.mch_id === item.mch_id && dn.tag === item.tag;
  1115. });
  1116. if (selfItem !== undefined) {
  1117. item.available_predeposit = selfItem.available_predeposit;
  1118. item.debt = selfItem.debt;
  1119. }
  1120. });
  1121. mchData = mergeData(mchData, copyDataMch, 'mch_name', systemTag);
  1122. }
  1123. const tableData = [];
  1124. mchData.forEach(item => {
  1125. let remark = '';
  1126. const setting = mchCust.find(function(mch) {
  1127. return mch.name === item.name && mch.tag === item.tag;
  1128. });
  1129. if (setting) {
  1130. remark = setting.remark ?? '';
  1131. }
  1132. let tableItem = {
  1133. tag: item.tag,
  1134. mch_id: item.mch_id,
  1135. mch_name: item.mch_name,
  1136. name: item.name,
  1137. available_predeposit: item.available_predeposit,
  1138. debt: item.debt,
  1139. remark: remark
  1140. };
  1141. tableData.push(tableItem);
  1142. });
  1143. const groupNames = globalData.getMchNames();
  1144. tableData.forEach(item => {
  1145. let matched = false;
  1146. groupNames.forEach(name => {
  1147. if (item.mch_name.startsWith(name)) {
  1148. item.mch_group = name;
  1149. matched = true;
  1150. }
  1151. });
  1152. if (!matched) {
  1153. item.mch_group = item.mch_name;
  1154. }
  1155. });
  1156. let sortMch = [];
  1157. if (!isObjectEmpty(copyData)) {
  1158. sortMch = mergeData(mchCust, copyData.stats_merchant, 'mch_name', systemTag);
  1159. } else {
  1160. sortMch = mchCust;
  1161. }
  1162. globalData.setMerchant(sortMch);
  1163. let mchDataSort = sortCustData(sortMch, tableData, 'mch_group', 'mch_name');
  1164. mchDataSort = sortByName(mchDataSort, 'mch_name');
  1165. mchDataSort.forEach(function (item) {//debt<0,设置为实际欠款,debt>0,设置为实际存款
  1166. if (parseFloat(item.debt) > 0) {
  1167. item.c_deposit = item.debt;
  1168. item.c_debt = 0;
  1169. } else {
  1170. item.c_deposit = 0;
  1171. item.c_debt = item.debt;
  1172. }
  1173. });
  1174. const groupSum = {};
  1175. for (let item of mchDataSort) {
  1176. if (!groupSum[item.mch_group]) {
  1177. groupSum[item.mch_group] = {debt_sum: 0, deposit_sum: 0};
  1178. }
  1179. groupSum[item.mch_group].debt_sum += parseFloat(item.c_debt);
  1180. groupSum[item.mch_group].deposit_sum += parseFloat(item.c_deposit);
  1181. }
  1182. for (let item of mchDataSort) {
  1183. item.c_debt = formatDecimals(item.c_debt);
  1184. item.c_deposit = formatDecimals(item.c_deposit);
  1185. item.c_debt_sum = formatDecimals(groupSum[item.mch_group].debt_sum);
  1186. item.c_deposit_sum = formatDecimals(groupSum[item.mch_group].deposit_sum);
  1187. item.available_predeposit = formatDecimals(item.available_predeposit);
  1188. const total = parseFloat(item.c_debt_sum) + parseFloat(item.c_deposit_sum);
  1189. if (Number(total) < 0) {
  1190. item.c_debt_sum = formatDecimals(total);
  1191. item.c_deposit_sum = '0';
  1192. } else {
  1193. item.c_debt_sum = '0';
  1194. item.c_deposit_sum = formatDecimals(total);
  1195. }
  1196. }
  1197. this.setMchData(mchDataSort);
  1198. }
  1199. async updateMchCache(itemData, action) {//action=edit/del
  1200. const mchCust = globalData.getMerchant();
  1201. const updateFlag = itemData.name + '-' + itemData.tag;
  1202. if (action === 'edit') {
  1203. mchCust.forEach(item => {
  1204. const itemFlag = item.name + '-' + item.tag;
  1205. if (itemFlag === updateFlag) {
  1206. item.remark = itemData.remark;
  1207. }
  1208. });
  1209. } else if (action ==='del') {
  1210. let mchTmp = [];
  1211. mchCust.forEach(item => {
  1212. const itemFlag = item.name + '-' + item.tag;
  1213. if (itemFlag !== updateFlag) {
  1214. mchTmp.push(item);
  1215. }
  1216. });
  1217. globalData.setMerchant(mchTmp);
  1218. }
  1219. await this.syncMchData();
  1220. }
  1221. async syncMchData() {
  1222. const mchCust = globalData.getMerchant();
  1223. await statsApi.setStatsSettings('merchant', mchCust)
  1224. .then(function (data) {
  1225. if (data.state !== true) {
  1226. layer.msg('缓存失败', {
  1227. icon: 1,
  1228. time: 2000
  1229. });
  1230. }
  1231. })
  1232. .catch(function (error) {
  1233. layer.msg('缓存失败', {
  1234. icon: 1,
  1235. time: 2000
  1236. });
  1237. });
  1238. }
  1239. async renderTable() {
  1240. const that = this;
  1241. await this.loadData();
  1242. const tableData = this.getMchData();
  1243. layui.table.render({
  1244. elem: '#' + this.tableId,
  1245. data: tableData,
  1246. limit: tableData.length,
  1247. cols: [[
  1248. {field: 'mch_group', title: '机构', width: 100, rowspan: true},
  1249. {field: 'mch_id', title: '机构ID', width: 100},
  1250. {field: 'mch_name', title: '机构名称', width: 200},
  1251. {field: 'available_predeposit', title: '所剩余额', width: 150},
  1252. {field: 'c_deposit', title: '实际存款', width: 150},
  1253. {field: 'c_deposit_sum', title: '存款合计', width: 150},
  1254. {field: 'c_debt', title: '实际欠款', width: 150},
  1255. {field: 'c_debt_sum', title: '欠款合计', width: 150},
  1256. {field: 'remark', title: '备注', width: 150},
  1257. {
  1258. field: 'edit', title: '编辑', width: 100, templet: function (d) {
  1259. return '<button class="layui-btn layui-btn-sm edit-btn" data-index="' + d.LAY_TABLE_INDEX + '">编辑</button>';
  1260. }
  1261. },
  1262. {
  1263. field: 'delete', title: '删除', width: 100, templet: function (d) {
  1264. return '<button class="layui-btn layui-btn-sm delete-btn" data-index="' + d.LAY_TABLE_INDEX + '">删除</button>';
  1265. }
  1266. }
  1267. ]],
  1268. done: function (res, curr, count) {
  1269. that.mergeCells();
  1270. const tableItem = $('#' + that.tableId);
  1271. const $tr = tableItem.next('.layui-table-view').find('.layui-table-body tbody tr');
  1272. $tr.each((index, element) => {
  1273. $(element).find('td').eq(5).addClass('col-bg');
  1274. $(element).find('td').eq(7).addClass('col-bg');
  1275. });
  1276. tableItem.next('.layui-table-view').off('click', '.edit-btn').on('click', '.edit-btn', function () {
  1277. const index = $(this).data('index');
  1278. that.editRow(index, this);
  1279. });
  1280. tableItem.next('.layui-table-view').off('click', '.delete-btn').on('click', '.delete-btn', function () {
  1281. const index = $(this).data('index');
  1282. that.deleteRow(index);
  1283. });
  1284. tableItem.next('.layui-table-view').find('.layui-table-body tbody').append(
  1285. '<tr><td>合计</td><td></td><td></td><td><span id="mch_table_sum_available_predeposit">0</span></td><td><span id="mch_table_sum_c_deposit">0</span></td><td><span id="mch_table_sum_c_deposit_sum">0</span></td><td><span id="mch_table_sum_c_debt">0</span></td><td><span id="mch_table_sum_c_debt_sum">0</span></td><td></td><td></td><td></td></tr>'
  1286. );
  1287. that.columnSum('available_predeposit');
  1288. that.columnSum('c_deposit');
  1289. that.columnSum('c_debt');
  1290. that.columnSum('c_deposit_sum');
  1291. that.columnSum('c_debt_sum');
  1292. that.setValueClass(['available_predeposit', 'c_deposit', 'c_deposit_sum', 'c_debt', 'c_debt_sum']);
  1293. }
  1294. });
  1295. };
  1296. mergeCells() {
  1297. const $tbRoot = $('#' + this.tableId);
  1298. const $trs = $tbRoot.next('.layui-table-view').find('.layui-table-body tbody tr');
  1299. const mchGroupMap = {};
  1300. $trs.each(function (i, tr) {
  1301. const $td = $(tr).find('td[data-field="mch_group"]');
  1302. const group = $td.text().trim();
  1303. if (group) {
  1304. if (!mchGroupMap[group]) {
  1305. mchGroupMap[group] = { count: 0, startIndex: i };
  1306. }
  1307. mchGroupMap[group].count++;
  1308. }
  1309. });
  1310. for (let group in mchGroupMap) {
  1311. const info = mchGroupMap[group];
  1312. if (info.count > 1) {
  1313. const fields = ['mch_group', 'c_debt_sum', 'c_deposit_sum'];
  1314. for (let field of fields) {
  1315. $trs.eq(info.startIndex).find('td[data-field="' + field + '"]').attr('rowspan', info.count);
  1316. for (let j = 1; j < info.count; j++) {
  1317. $trs.eq(info.startIndex + j).find('td[data-field="' + field + '"]').addClass('layui-hide');
  1318. }
  1319. }
  1320. }
  1321. }
  1322. };
  1323. async editRow(index, button) {
  1324. const $tr = $('#' + this.tableId).next('.layui-table-view').find('.layui-table-body tbody tr[data-index="' + index + '"]');
  1325. const isEditing = $(button).text() === '保存';
  1326. if (isEditing) {
  1327. $(button).text('编辑');
  1328. const remark = $tr.find('td[data-field="remark"]').find('div').text();
  1329. const mchId = $tr.find('td[data-field="mch_id"]').find('div').text();
  1330. const mchName = $tr.find('td[data-field="mch_name"]').find('div').text();
  1331. const mchData = this.getMchData();
  1332. const currItem = mchData.find(function (item) {
  1333. return item.mch_id === mchId && item.mch_name === mchName;
  1334. });
  1335. currItem.remark = remark;
  1336. await this.updateMchCache(currItem, 'edit');
  1337. await mchTable.renderTable(mchData);
  1338. } else {
  1339. $(button).text('保存');
  1340. const $remarkDiv = $tr.find('td[data-field="remark"]').find('div');
  1341. $remarkDiv.attr('contenteditable', true).css('background-color', 'lightblue').focus();
  1342. }
  1343. };
  1344. deleteRow(index) {
  1345. let that = this;
  1346. const mchData = this.getMchData();
  1347. const $tr = $('#' + this.tableId).next('.layui-table-view').find('.layui-table-body tbody tr[data-index="' + index + '"]');
  1348. const mchId = $tr.find('td[data-field="mch_id"]').find('div').text();
  1349. const mchName = $tr.find('td[data-field="mch_name"]').find('div').text();
  1350. const delItem = mchData.find(function (item) {
  1351. return item.mch_id === mchId && item.mch_name === mchName;
  1352. });
  1353. const mchDataNew = mchData.filter(item => !(item.mch_id === delItem.mch_id && item.mch_name === delItem.mch_name));
  1354. this.setMchData(mchDataNew);
  1355. layer.confirm('确定要删除 ' + delItem.mch_name + ' 吗?', { icon: 3, title: '删除确认' }, async function (confirmIndex) {
  1356. await that.updateMchCache(delItem, 'del');
  1357. //删除导入数据中的项
  1358. const copyData = globalData.getCopyData();
  1359. if (!isObjectEmpty(copyData)) {
  1360. copyData.stats_merchant = copyData.stats_merchant.filter(item => item.tag !== delItem.tag || item.name !== delItem.name );
  1361. copyData.stats_data_mch = copyData.stats_data_mch.filter(item => item.tag !== delItem.tag || item.name !== delItem.name );
  1362. }
  1363. await mchTable.renderTable(that.getMchData());
  1364. layer.close(confirmIndex);
  1365. });
  1366. };
  1367. columnSum(field) {
  1368. let sum = 0;
  1369. const $table = $('#' + this.tableId).next('.layui-table-view');
  1370. const $tr = $table.find('.layui-table-body tbody tr');
  1371. $tr.each(function (index, element) {
  1372. const $td = $(element).find('td[data-field="' + field + '"]').not('.layui-hide').find('.layui-table-cell');
  1373. if ($td.length > 0) {
  1374. const paymentDesign = $td.text().trim();
  1375. if (isNumeric(paymentDesign)) {
  1376. sum += parseFloat(paymentDesign);
  1377. }
  1378. }
  1379. });
  1380. const $cell = $table.find('#mch_table_sum_' + field);
  1381. if (sum < 0) {
  1382. $cell.css('color', 'red');
  1383. } else {
  1384. $cell.css('color', '');
  1385. }
  1386. $cell.html(formatDecimals(sum));
  1387. }
  1388. }
  1389. class BatchWorkflow extends TaskManager {
  1390. constructor(prefix) {
  1391. super();
  1392. this.initializeGlobalTaskList();
  1393. this.prefix = prefix; //normal/fast
  1394. }
  1395. getTaskType() {
  1396. return 'batch_payment_' + this.prefix;
  1397. }
  1398. getPendingTasksByApprover() {
  1399. const tasks = super.getPendingTasks();
  1400. return tasks.filter(task => task.approver === 'admin');
  1401. }
  1402. getPendingTaskDetails() {
  1403. const worklist = this.getPendingTasksByApprover();
  1404. return worklist.reduce((acc, obj) => {
  1405. const formattedTime = formatDateTime(obj.time);
  1406. const itemsWithTime = obj.data.items.map(item => ({
  1407. ...item,
  1408. time: formattedTime
  1409. }));
  1410. return acc.concat(itemsWithTime);
  1411. }, []);
  1412. }
  1413. async invalidateItem(storeId, tag) {
  1414. const tasks = this.getPendingTasksByApprover();
  1415. for (const task of tasks) {
  1416. const updatedItems = task.data.items.filter(item =>
  1417. !(item.store_id === storeId && item.tag === tag)
  1418. );
  1419. if (updatedItems.length !== task.data.items.length) {
  1420. const newData = { ...task.data, items: updatedItems };
  1421. const updateSuccess = await this.updateTask(
  1422. task.id,
  1423. updatedItems.length > 0 ? newData : {}
  1424. );
  1425. if (!updateSuccess) {
  1426. console.error(`Failed to update task ${task.id} after removing item ${storeId}, ${tag}`);
  1427. return false;
  1428. }
  1429. }
  1430. }
  1431. return true;
  1432. }
  1433. }
  1434. class BatchDeposit {
  1435. constructor(type) {
  1436. if (type === 'normal') {
  1437. this.workflow = new BatchWorkflow('normal');
  1438. } else if (type === 'fast') {
  1439. this.workflow = new BatchWorkflow('fast');
  1440. }
  1441. this.type = type;
  1442. this.dv = 1; //数据版本,作用:由于需求变化导致存储的缓存数据格式发生变化,由该字段标记,审核的时候如果数据版本与当前dv版本不一致,需要手动作废审核重新操作。
  1443. }
  1444. doApplyOne(tableId, channelData, index) {
  1445. const $trs = $('#' + tableId).next('.layui-table-view').find('.layui-table-body tbody tr');
  1446. const $targetRow = $trs.eq(index);
  1447. const upstreamGroup = $targetRow.attr('upstream_group');
  1448. const $matchingRows = $trs.filter(function(i, tr) {
  1449. return $(tr).attr('upstream_group') === upstreamGroup;
  1450. });
  1451. this.doApply($matchingRows, channelData);
  1452. }
  1453. doApplyMore(tableId, channelData) {
  1454. const $trs = $('#' + tableId).next('.layui-table-view').find('.layui-table-body tbody tr').slice(0, -1);
  1455. this.doApply($trs, channelData);
  1456. }
  1457. async doApply($matchingRows, channelData) {
  1458. const that = this;
  1459. let payUnit = [];
  1460. let errsNormal = [], errsPlatform = [];
  1461. $matchingRows.each(function (i) {
  1462. const $td = $(this).find('td[data-field="transfer"]');
  1463. const paymentAmount = $td.find('div').text().trim();
  1464. const currIndex = $(this).index();
  1465. const channelItem = channelData[currIndex] || {};
  1466. if (isObjectEmpty(channelItem)) {
  1467. errsNormal.push(`第${currIndex + 1}行 数据异常`);
  1468. return;
  1469. }
  1470. if (!isNumeric(paymentAmount)) {
  1471. errsNormal.push(`${channelItem.store_name} 金额设置错误`);
  1472. return;
  1473. }
  1474. if (paymentAmount === '0') {
  1475. return;
  1476. }
  1477. if (Number(paymentAmount) < 0) {
  1478. errsNormal.push(`${channelItem.store_name} 加款金额不能小于0`);
  1479. return;
  1480. }
  1481. if (channelItem.tag !== systemTag) {
  1482. errsPlatform.push(channelItem.store_name);
  1483. return;
  1484. }
  1485. if (channelItem.tag === systemTag) {
  1486. payUnit.push({
  1487. store_id: channelItem.store_id,
  1488. store_name: channelItem.store_name,
  1489. tag: channelItem.tag,
  1490. amount: paymentAmount,
  1491. upstream_group: channelItem.upstream_group,
  1492. pay_operation: channelItem.pay_operation,
  1493. remark: ''
  1494. });
  1495. }
  1496. });
  1497. if (errsNormal.length === 0 && payUnit.length === 0) {
  1498. let platformName = '';
  1499. if (systemTag === 'YEZI') {
  1500. platformName = '椰子';
  1501. } else if (systemTag === 'YELIN') {
  1502. platformName = '椰林';
  1503. }
  1504. showErr(`这是 ${platformName} 平台,需要设计加款金额,目前是0!`);
  1505. return ;
  1506. }
  1507. await this.workflow.initializeGlobalTaskList();
  1508. const pendingTasks = this.workflow.getPendingTasksByApprover();
  1509. pendingTasks.forEach(taskItem => {
  1510. const currItems = taskItem.data.items || [];
  1511. currItems.forEach(currItem => {
  1512. const isPending = payUnit.find(payItem => {
  1513. return currItem.store_id === payItem.store_id && currItem.tag === payItem.tag;
  1514. });
  1515. if (isPending !== undefined) {
  1516. const err = `${currItem.store_name} 存在处理中的加款申请,审核后才能再次加款`;
  1517. if (!errsNormal.includes(err)) {
  1518. errsNormal.push(err);
  1519. }
  1520. }
  1521. });
  1522. });
  1523. if (errsNormal.length > 0) {
  1524. showErr(errsNormal.join('<br />'));
  1525. return;
  1526. }
  1527. const applyTrnasfer = () => {
  1528. const groupPayUnit = {};
  1529. let paySum = 0;
  1530. const sortedPayUnit = sortByName(payUnit, 'store_name');
  1531. sortedPayUnit.forEach(item => {
  1532. if (!groupPayUnit[item.upstream_group]) {
  1533. groupPayUnit[item.upstream_group] = 0;
  1534. }
  1535. groupPayUnit[item.upstream_group] += parseFloat(item.amount);
  1536. paySum += parseFloat(item.amount);
  1537. });
  1538. sortedPayUnit.forEach(item => {
  1539. item.total = groupPayUnit[item.upstream_group] || 0;
  1540. item.total = formatDecimals(item.total);
  1541. });
  1542. layui.table.render({
  1543. elem: '#upstream_tb_transfer',
  1544. data: sortedPayUnit,
  1545. limit: sortedPayUnit.length,
  1546. cols: [[
  1547. {field: 'store_name', title: '加款项', width: 200},
  1548. {field: 'amount', title: '金额', width: 100},
  1549. {field: 'total', title: '合计', width: 100},
  1550. {field: 'pay_operation', title: '操作人姓名', width: 200},
  1551. {field: 'remark', title: '备注', width: 200},
  1552. ]],
  1553. done: function (res, curr, count) {
  1554. const $tbRoot = $('#upstream_tb_transfer');
  1555. const $trs = $tbRoot.next('.layui-table-view').find('.layui-table-body tbody tr');
  1556. const setAttr = () => {
  1557. $trs.each(function (i, tr) {
  1558. const upstreamGroup = sortedPayUnit[i].upstream_group;
  1559. $(tr).attr('upstream_group', upstreamGroup);
  1560. });
  1561. };
  1562. const mergeTotal = () => {
  1563. const upstreamMap = {};
  1564. $trs.each(function (i, tr) {
  1565. const group = $(tr).attr('upstream_group');
  1566. if (group) {
  1567. if (!upstreamMap[group]) {
  1568. upstreamMap[group] = {count: 0, startIndex: i};
  1569. }
  1570. upstreamMap[group].count++;
  1571. }
  1572. });
  1573. for (let group in upstreamMap) {
  1574. const info = upstreamMap[group];
  1575. $trs.eq(info.startIndex).find('td[data-field="total"]').
  1576. attr('rowspan', info.count);
  1577. $trs.eq(info.startIndex).find('td[data-field="pay_operation"]').
  1578. attr('rowspan', info.count).
  1579. attr('contenteditable', true).
  1580. css('background-color', 'lightblue');
  1581. $trs.eq(info.startIndex).find('td[data-field="remark"]').
  1582. attr('rowspan', info.count).
  1583. attr('contenteditable', true).
  1584. css('background-color', 'lightblue');
  1585. for (let j = 1; j < info.count; j++) {
  1586. $trs.eq(info.startIndex + j).find('td[data-field="total"]').addClass('layui-hide');
  1587. $trs.eq(info.startIndex + j).find('td[data-field="pay_operation"]').addClass('layui-hide');
  1588. $trs.eq(info.startIndex + j).find('td[data-field="remark"]').addClass('layui-hide');
  1589. }
  1590. }
  1591. };
  1592. setAttr();
  1593. mergeTotal();
  1594. }
  1595. });
  1596. layer.open({
  1597. type: 1,
  1598. title: '加款确认',
  1599. area: ['900px', '500px'],
  1600. content: $('#rechargeManual'),
  1601. btn: ['确定加款', '取消'],
  1602. success: function (layero) {
  1603. let $btns = layero.find('.layui-layer-btn');
  1604. $btns.css({
  1605. 'display': 'flex',
  1606. 'justify-content': 'center',
  1607. 'align-items': 'center'
  1608. });
  1609. $btns.prepend(`<div class="total-label" style="margin-right:auto;">合计:${formatDecimals(paySum)}</div>`);
  1610. $btns.children('a').css({
  1611. 'margin-left': '10px',
  1612. 'margin-right': '10px'
  1613. });
  1614. },
  1615. btn2: function () {
  1616. let groupInput = {};
  1617. const $trs = $('#upstream_tb_transfer').next('.layui-table-view').find('.layui-table-body tbody tr');
  1618. $trs.each(function(i, tr) {
  1619. const td_pay_operation = $(tr).find('td[data-field="pay_operation"]').not('.layui-hide');
  1620. const td_remark = $(tr).find('td[data-field="remark"]').not('.layui-hide');
  1621. if (td_pay_operation.length > 0 && td_remark.length > 0) {
  1622. const currGroup = $(tr).attr('upstream_group');
  1623. if (!groupInput[currGroup]) {
  1624. groupInput[currGroup] = {
  1625. pay_operation: td_pay_operation.text().trim(),
  1626. remark: td_remark.text().trim()
  1627. };
  1628. }
  1629. }
  1630. });
  1631. for (let i = 0; i < payUnit.length; i++) {
  1632. const group = payUnit[i].upstream_group;
  1633. const unit_pay_operation = groupInput[group].pay_operation ?? '';
  1634. if (unit_pay_operation === '') {
  1635. showErr(`${ group } 未设置操作人`);
  1636. return false;
  1637. }
  1638. const unit_remark = groupInput[group].remark ?? '';
  1639. payUnit[i].pay_operation = unit_pay_operation;
  1640. payUnit[i].remark = unit_remark;
  1641. }
  1642. layer.closeAll();
  1643. //由于渲染表格过程中payUnit产生了多余的字段,进行过滤
  1644. const taskData = filterJsonFields(payUnit, ["amount", "pay_operation", "remark", "store_id", "store_name", "tag", "upstream_group"]);
  1645. const applyData = {
  1646. items: taskData,
  1647. dv: that.dv
  1648. };
  1649. that.workflow.addTask(applyData, systemUserName, 'admin')
  1650. .then(succ => {
  1651. if (succ === true) {
  1652. showSuccess('已发起加款申请,等待管理员审核后执行加款');
  1653. } else {
  1654. showErr('处理失败,请重试');
  1655. }
  1656. });
  1657. },
  1658. });
  1659. };
  1660. if (errsPlatform.length > 0) {
  1661. layer.confirm(errsPlatform.join(',') + ' 非本平台通道,忽略加款,请到复制数据后到对应平台执行加款操作', {
  1662. title: '提示',
  1663. btn: ['确定', '取消']
  1664. }, function (index) {
  1665. applyTrnasfer();
  1666. layer.close(index);
  1667. });
  1668. } else {
  1669. applyTrnasfer();
  1670. }
  1671. }
  1672. async doBatchDeposit() {
  1673. const that = this;
  1674. let sortedPayUnit = [], worklist = [], payUnit = [], paySum = 0, isCorrectVersion = true;
  1675. const loadPayUnit = async () => {
  1676. await this.workflow.initializeGlobalTaskList();
  1677. const groupPayUnit = {};
  1678. paySum = 0;
  1679. worklist = this.workflow.getPendingTasksByApprover();
  1680. for (const task of worklist) {
  1681. if (Number(task.data.dv) !== that.dv) {
  1682. isCorrectVersion = false;
  1683. break;
  1684. }
  1685. }
  1686. payUnit = this.workflow.getPendingTaskDetails();
  1687. sortedPayUnit = sortByName(payUnit, 'store_name');
  1688. sortedPayUnit.forEach(item => {
  1689. if (!groupPayUnit[item.upstream_group]) {
  1690. groupPayUnit[item.upstream_group] = 0;
  1691. }
  1692. groupPayUnit[item.upstream_group] += parseFloat(item.amount);
  1693. paySum += parseFloat(item.amount);
  1694. });
  1695. sortedPayUnit.forEach(item => {
  1696. item.total = groupPayUnit[item.upstream_group] || 0;
  1697. item.total = formatDecimals(item.total);
  1698. });
  1699. };
  1700. await loadPayUnit();
  1701. if (isCorrectVersion === false) {
  1702. setTimeout(function() {
  1703. showErr('数据与当前程序版本不匹配,请作废当前数据后重新加款');
  1704. }, 500);
  1705. }
  1706. const approveWork = async (payUnitArr) => {
  1707. await this.workflow.initializeGlobalTaskList();
  1708. worklist = this.workflow.getPendingTasksByApprover();
  1709. if (worklist.length === 0) {
  1710. showErr('没有待审核的加款申请');
  1711. return false;
  1712. }
  1713. if (isCorrectVersion === false) {
  1714. showErr('数据与当前程序版本不匹配,请作废当前数据后重新加款');
  1715. return false;
  1716. }
  1717. layer.closeAll();
  1718. const errItem = payUnitArr.find(item => {
  1719. return item.tag !== systemTag;
  1720. });
  1721. if (errItem !== undefined) {
  1722. showErr(errItem.store_name + '数据存在异常,请作废后重新申请');
  1723. return false;
  1724. }
  1725. const updateProgress = (progress, description) => {
  1726. const progressBar = document.getElementById('progress-bar');
  1727. const progressDescription = document.getElementById('progressDescription');
  1728. progressBar.style.width = progress + '%';
  1729. progressBar.textContent = progress + '%';
  1730. progressDescription.textContent = description;
  1731. }
  1732. updateProgress('0', '正在执行加款,不要刷新或关闭页面');
  1733. $('#processBar').show();
  1734. setTimeout(async function () {
  1735. const storeIds = payUnit.map(item => item.store_id).join(',');
  1736. const providersData = await statsApi.getProvidersByStore({store_ids: storeIds});
  1737. if (providersData.state !== true || providersData.list.length === 0) {
  1738. showErr('获取通道信息异常');
  1739. return;
  1740. }
  1741. const providers = providersData.list;
  1742. let errs = [];
  1743. const processNum = payUnitArr.length;
  1744. let processedCount = 0;
  1745. const payHandler = async (item) => {
  1746. const providerInfo = providers.find(p => item.store_id === p.store_id);
  1747. if (!providerInfo) {
  1748. errs.push(item.store_name + ' 加款 ' + item.amount + ' 执行失败(数据错误)');
  1749. processedCount += 1;
  1750. const progress = (processedCount / processNum) * 100;
  1751. updateProgress(progress.toFixed(2), item.store_name + '处理失败');
  1752. return false;
  1753. }
  1754. const params = {
  1755. form_submit: 'ok',
  1756. operation: item.pay_operation,
  1757. operatetype: 'add',
  1758. pointsnum: item.amount,
  1759. bz: item.remark
  1760. };
  1761. const result = await statsApi.rechargeManual(providerInfo.provider_id, params);
  1762. processedCount += 1;
  1763. const progress = (processedCount / processNum) * 100;
  1764. updateProgress(progress.toFixed(2), item.store_name + '处理完成');
  1765. return result.msg === '操作成功';
  1766. };
  1767. let rmTask = false;
  1768. const retryItems = [];
  1769. for (const payItem of payUnitArr) {
  1770. if (payItem.tag !== systemTag) {
  1771. continue;
  1772. }
  1773. for (let taskItem of worklist) {
  1774. const itemIndex = taskItem.data.items.findIndex(item => item.store_id === payItem.store_id && item.tag === payItem.tag);
  1775. if (itemIndex !== -1) {
  1776. let currTaskData = deepCloneData(taskItem.data);
  1777. currTaskData.items.splice(itemIndex, 1);
  1778. if (currTaskData.items.length === 0) {
  1779. currTaskData = {};
  1780. }
  1781. const tasked = await that.workflow.updateTask(taskItem.id, currTaskData);
  1782. if (tasked === true) {
  1783. const succ = await payHandler(payItem);
  1784. if (succ === false) {
  1785. retryItems.push(payItem);
  1786. }
  1787. }
  1788. rmTask = true;
  1789. }
  1790. }
  1791. }
  1792. if (retryItems.length > 0) {
  1793. const taskData = filterJsonFields(retryItems, ["amount", "pay_operation", "remark", "store_id", "store_name", "tag", "upstream_group"]);
  1794. const applyData = {
  1795. items: taskData,
  1796. dv: that.dv
  1797. };
  1798. const succ = await that.workflow.addTask(applyData, systemUserName, 'admin');
  1799. const resultTips = succ === true ? '已重新加入审批列表' : '重新加入审批列表失败';
  1800. retryItems.forEach(retryItem => {
  1801. errs.push(retryItem.store_name + '执行加款失败,' + resultTips);
  1802. });
  1803. }
  1804. setTimeout(() => {
  1805. $('#processBar').hide();
  1806. if (that.type === 'normal') {
  1807. channelTableNormal.renderTable();
  1808. } else {
  1809. channelTableFast.renderTable();
  1810. }
  1811. loadMsgBadge();
  1812. }, 1000);
  1813. if (errs.length > 0) {
  1814. showErr(errs.join('<br/>'));
  1815. }
  1816. }, 1000);
  1817. };
  1818. layui.table.render({
  1819. elem: '#upstream_tb_approve',
  1820. data: sortedPayUnit,
  1821. limit: sortedPayUnit.length,
  1822. cols: [[
  1823. {field: 'store_name', title: '加款通道', width: 200},
  1824. {field: 'amount', title: '加款金额', width: 150},
  1825. {field: 'time', title: '申请时间', width: 250},
  1826. {field: 'total', title: '合计', width: 150},
  1827. {field: 'pay_operation', title: '操作人姓名', width: 150},
  1828. {field: 'remark', title: '备注', width: 150},
  1829. {field: 'void_task', title: '', width: 150, templet: function(d){
  1830. return '<button class="layui-btn layui-btn-sm layui-bg-blue task-approve-btn" data-index="'+d.LAY_TABLE_INDEX+'">批准</button>' +
  1831. '<button class="layui-btn layui-btn-sm layui-btn-primary task-void-btn" data-index="'+d.LAY_TABLE_INDEX+'">作废</button>';
  1832. }}
  1833. ]],
  1834. done: function (res, curr, count) {
  1835. const $tbRoot = $('#upstream_tb_approve');
  1836. const $trs = $tbRoot.next('.layui-table-view').find('.layui-table-body tbody tr');
  1837. const setAttr = () => {
  1838. $trs.each(function (i, tr) {
  1839. $(tr).attr('upstream_group', sortedPayUnit[i].upstream_group);
  1840. $(tr).attr('store_id', sortedPayUnit[i].store_id);
  1841. $(tr).attr('tag', sortedPayUnit[i].tag);
  1842. });
  1843. };
  1844. const mergeTotal = () => {
  1845. const upstreamMap = {};
  1846. $trs.each(function (i, tr) {
  1847. const group = $(tr).attr('upstream_group');
  1848. if (group) {
  1849. if (!upstreamMap[group]) {
  1850. upstreamMap[group] = {count: 0, startIndex: i};
  1851. }
  1852. upstreamMap[group].count++;
  1853. }
  1854. });
  1855. for (let group in upstreamMap) {
  1856. const info = upstreamMap[group];
  1857. if (info.count > 1) {
  1858. $trs.eq(info.startIndex).find('td[data-field="total"]').attr('rowspan', info.count);
  1859. for (let j = 1; j < info.count; j++) {
  1860. $trs.eq(info.startIndex + j).find('td[data-field="total"]').addClass('layui-hide');
  1861. }
  1862. }
  1863. }
  1864. };
  1865. const approveOneEvent = () => {
  1866. $tbRoot.next('.layui-table-view').off('click', '.task-approve-btn').on('click', '.task-approve-btn', async function () {
  1867. const index = $(this).data('index');
  1868. const $trs = $('#upstream_tb_approve').next('.layui-table-view').find('.layui-table-body tbody tr');
  1869. const $targetRow = $trs.eq(index);
  1870. const store_id = $targetRow.attr('store_id');
  1871. const tag = $targetRow.attr('tag');
  1872. const loadIndex = layer.load(2, {shade: [0.2, '#000']});
  1873. await that.workflow.initializeGlobalTaskList();
  1874. payUnit = that.workflow.getPendingTaskDetails();
  1875. const payUnitItem = payUnit.find(item => item.store_id === store_id && item.tag === tag);
  1876. if(payUnitItem === undefined) {
  1877. showErr('处理失败');
  1878. return;
  1879. }
  1880. await approveWork([payUnitItem]);
  1881. });
  1882. };
  1883. const voidOneEvent = () => {
  1884. $tbRoot.next('.layui-table-view').off('click', '.task-void-btn').on('click', '.task-void-btn', function () {
  1885. const index = $(this).data('index');
  1886. layer.confirm(`确认作废 ${sortedPayUnit[index].store_name} 的加款申请吗?`, {
  1887. title: '提示',
  1888. btn: ['确定', '取消']
  1889. }, async (confirmIndex) => {
  1890. const $trs = $('#upstream_tb_approve').next('.layui-table-view').find('.layui-table-body tbody tr');
  1891. const $targetRow = $trs.eq(index);
  1892. const storeId = $targetRow.attr('store_id');
  1893. const tag = $targetRow.attr('tag');
  1894. const loadIndex = layer.load(2, {shade: [0.2, '#000']});
  1895. await that.workflow.initializeGlobalTaskList();
  1896. const succ = await that.workflow.invalidateItem(storeId, tag);
  1897. if (succ === true) {
  1898. await loadPayUnit();
  1899. layui.table.reload('upstream_tb_approve', {
  1900. data: sortedPayUnit
  1901. });
  1902. $('#modelPaySum').html('合计:' + formatDecimals(paySum));
  1903. } else {
  1904. showErr('作废失败');
  1905. }
  1906. layer.close(loadIndex);
  1907. layer.close(confirmIndex);
  1908. });
  1909. });
  1910. };
  1911. const textEvent = () => {
  1912. const editTextColumns = ['remark'];
  1913. $trs.each(function(i, tr) {
  1914. for(let col of editTextColumns) {
  1915. const $td = $(tr).find('td[data-field="' + col + '"]').not('.layui-hide').find('div');
  1916. let val = $td.text().trim();
  1917. $td.html(val);
  1918. $td.attr('contenteditable', true).css('background-color', 'lightblue');
  1919. $td.off('input')
  1920. .off('keypress')
  1921. .off('blur')
  1922. .on('input')
  1923. .on('keypress', function(e) {
  1924. if (e.keyCode === 13) {
  1925. e.preventDefault();
  1926. $(this).blur();
  1927. }
  1928. })
  1929. .on('blur', async function () {
  1930. const loadIndex = layer.load(2, {shade: [0.2, '#000']});
  1931. const index = $(this).parent().parent().data('index');
  1932. await saveEdit(index);
  1933. layer.close(loadIndex);
  1934. });
  1935. }
  1936. });
  1937. };
  1938. const saveEdit = async (index) => {
  1939. const $tr = $('#upstream_tb_approve').next('.layui-table-view').find('.layui-table-body tbody tr[data-index="' + index + '"]');
  1940. const remark = $tr.find('td[data-field="remark"]').find('div').text().trim();
  1941. const store_id = $tr.attr('store_id');
  1942. const tag = $tr.attr('tag');
  1943. for (const item of worklist) {
  1944. item.data.items.forEach(payment => {
  1945. if (payment.store_id === store_id && payment.tag === tag) {
  1946. payment.remark = remark;
  1947. }
  1948. });
  1949. await that.workflow.updateTask(item.id, item.data);
  1950. }
  1951. worklist = that.workflow.getPendingTasksByApprover();
  1952. payUnit = that.workflow.getPendingTaskDetails();
  1953. };
  1954. setAttr();
  1955. mergeTotal();
  1956. approveOneEvent();
  1957. voidOneEvent();
  1958. textEvent();
  1959. }
  1960. });
  1961. layer.open({
  1962. type: 1,
  1963. title: '加款审核',
  1964. area: ['1290px', '500px'],
  1965. content: $('#rechargeManualApprove'),
  1966. btn: ['批准', '作废'],
  1967. success: function (layero) {
  1968. let $btns = layero.find('.layui-layer-btn');
  1969. $btns.css({
  1970. 'display': 'flex',
  1971. 'justify-content': 'center',
  1972. 'align-items': 'center'
  1973. });
  1974. $btns.prepend(`<div class="total-label" style="margin-right:auto;" id="modelPaySum">合计:${formatDecimals(paySum)}</div>`);
  1975. $btns.children('a').css({
  1976. 'margin-left': '10px',
  1977. 'margin-right': '10px'
  1978. });
  1979. },
  1980. btn2: async function () {
  1981. layer.load(2, {shade: [0.2, '#000']});
  1982. await that.workflow.initializeGlobalTaskList();
  1983. payUnit = that.workflow.getPendingTaskDetails();
  1984. await approveWork(payUnit);
  1985. },
  1986. btn3: function () {
  1987. if (worklist.length === 0) {
  1988. showErr('没有可作废的加款申请');
  1989. return;
  1990. }
  1991. layer.confirm(`确认批量作废加款申请吗?`, {
  1992. title: '提示',
  1993. btn: ['确定', '取消']
  1994. }, async () => {
  1995. layer.load(2, {shade: [0.2, '#000']});
  1996. for (const task of worklist) {
  1997. await that.workflow.executeTask(task.id, async () => {});
  1998. }
  1999. layer.closeAll();
  2000. showSuccess('加款申请已作废');
  2001. });
  2002. return false;
  2003. }
  2004. });
  2005. }
  2006. }
  2007. const globalData = new GlobalData().proxy;
  2008. globalData.setCopyData({});
  2009. const mchTable = new MchTable('downstream_tb');
  2010. const batchDepositNormal = new BatchDeposit('normal');
  2011. const batchDepositFast = new BatchDeposit('fast');
  2012. const channelTableNormal = new ChannelTable('normal', batchDepositNormal);
  2013. const channelTableFast = new ChannelTable('fast', batchDepositFast);
  2014. function setTableColVal(tableId, col, val) { //对整列设置值
  2015. const setData = [];
  2016. const $trs = $('#' + tableId).next('.layui-table-view').find('.layui-table-body tbody tr');
  2017. $trs.each(function(i, tr) {
  2018. const $td = $(tr).find('td[data-field="' + col + '"]');
  2019. if ($td.length > 0) {
  2020. $td.find('div').html(val);
  2021. }
  2022. const storeId = $(tr).attr('store_id');
  2023. const tag = $(tr).attr('tag');
  2024. setData.push({
  2025. store_id: storeId,
  2026. tag: tag,
  2027. val: val
  2028. });
  2029. });
  2030. return setData;
  2031. }
  2032. async function importData(data) {
  2033. const namesChan1 = globalData.getChannelNames();
  2034. const namesChan2 = data.stats_channel_names;
  2035. const mergeNamesChan = mergeNames(namesChan1, namesChan2);
  2036. globalData.setChannelNames(mergeNamesChan);
  2037. const namesMch1 = globalData.getMchNames();
  2038. const namesMch2 = data.stats_mch_names;
  2039. const mergeNamesMch = mergeNames(namesMch1, namesMch2);
  2040. globalData.setMchNames(mergeNamesMch);
  2041. const statsNormal1 = globalData.getChannelNormal();
  2042. const statsNormal2 = data.stats_channel_normal;
  2043. const mergeStatsNormal = mergeData(statsNormal1, statsNormal2, 'store_name', systemTag);
  2044. globalData.setChannelNormal(mergeStatsNormal);
  2045. const statsFast1 = globalData.getChannelFast();
  2046. const statsFast2 = data.stats_channel_fast;
  2047. const mergeStatsFast = mergeData(statsFast1, statsFast2, 'store_name', systemTag);
  2048. globalData.setChannelFast(mergeStatsFast);
  2049. const statsMch1 = globalData.getMerchant();
  2050. const statsMch2 = data.stats_merchant;
  2051. const mergeStatsMch = mergeData(statsMch1, statsMch2, 'mch_name', systemTag);
  2052. globalData.setMerchant(mergeStatsMch);
  2053. if (data.stats_transfer !== undefined && data.stats_transfer.length > 0) {
  2054. data.stats_transfer.forEach(statsItem => {
  2055. globalData.setPayinfo(statsItem.store_id, statsItem.tag, statsItem.amount);
  2056. });
  2057. }
  2058. //更新到缓存中
  2059. await statsApi.setStatsSettings(CONSTANTS.KEY_CHANNEL_NAMES, globalData.getChannelNames());
  2060. await statsApi.setStatsSettings(CONSTANTS.KEY_MERCHANT_NAMES, globalData.getMchNames());
  2061. await statsApi.setStatsSettings(CONSTANTS.KEY_CHANNEL_FAST, globalData.getChannelFast());
  2062. await statsApi.setStatsSettings(CONSTANTS.KEY_CHANNEL_NORMAL, globalData.getChannelNormal());
  2063. await statsApi.setStatsSettings(CONSTANTS.KEY_MERCHANT, globalData.getMerchant());
  2064. const upSelected = app.getComponent('up-name-select');
  2065. await upSelected.loadData();
  2066. upSelected.updateUI();
  2067. const downSelected = app.getComponent('down-name-select');
  2068. await downSelected.loadData();
  2069. downSelected.updateUI();
  2070. await channelTableNormal.renderTable();
  2071. await channelTableFast.renderTable();
  2072. await mchTable.renderTable();
  2073. }
  2074. async function initPage() {
  2075. //配置项必须顺序同步加载
  2076. const loadIndex = layer.load(2, { shade: [0.2, '#000'] });
  2077. const statsSettings = await statsApi.getStatsSettings(settingsKeys);
  2078. if (statsSettings.state === true) {
  2079. globalData.setChannelNames(statsSettings[CONSTANTS.KEY_CHANNEL_NAMES]);
  2080. globalData.setMchNames(statsSettings[CONSTANTS.KEY_MERCHANT_NAMES]);
  2081. globalData.setChannelFast(statsSettings[CONSTANTS.KEY_CHANNEL_FAST]);
  2082. globalData.setChannelNormal(statsSettings[CONSTANTS.KEY_CHANNEL_NORMAL]);
  2083. globalData.setMerchant(statsSettings[CONSTANTS.KEY_MERCHANT]);
  2084. } else {
  2085. layer.close(loadIndex);
  2086. showErr('配置缓存加载失败');
  2087. return;
  2088. }
  2089. Promise.all([
  2090. new Promise((resolve, reject) => {
  2091. channelTableNormal.renderTable();
  2092. resolve();
  2093. }),
  2094. new Promise((resolve, reject) => {
  2095. channelTableFast.renderTable();
  2096. resolve();
  2097. }),
  2098. new Promise((resolve, reject) => {
  2099. mchTable.renderTable();
  2100. resolve();
  2101. })
  2102. ])
  2103. .catch(error => {
  2104. console.error('数据加载失败:', error);
  2105. });
  2106. layer.close(loadIndex);
  2107. }
  2108. initPage();
  2109. $('#btn_copy_data').on('click', function() {
  2110. let data = {};
  2111. data.stats_data_fast = globalData.getDataChanFast();
  2112. data.stats_data_normal = globalData.getDataChanNormal();
  2113. data.stats_data_mch = globalData.getDataMerchant();
  2114. data.stats_channel_names = globalData.getChannelNames();
  2115. data.stats_mch_names = globalData.getMchNames();
  2116. data.stats_channel_fast = globalData.getChannelFast();
  2117. data.stats_channel_normal = globalData.getChannelNormal();
  2118. data.stats_merchant = globalData.getMerchant();
  2119. data.stats_transfer = globalData.getPayinfo();
  2120. const jsonString = JSON.stringify(data, null, 2);
  2121. const textarea = document.createElement('textarea');
  2122. textarea.value = jsonString;
  2123. document.body.appendChild(textarea);
  2124. textarea.select();
  2125. document.execCommand('copy');
  2126. document.body.removeChild(textarea);
  2127. layer.msg('数据已经复制', {
  2128. icon: 1,
  2129. time: 2000
  2130. });
  2131. });
  2132. $('#btn_import').on('click', function() {
  2133. layer.open({
  2134. type: 1,
  2135. title: '导入数据',
  2136. area: ['500px', '620px'],
  2137. content: $('#importLayer'),
  2138. btn: ['确定', '取消'],
  2139. success: function(layero, index) {
  2140. $('#clipboardContent').focus();
  2141. },
  2142. yes: async function(index, layero) {
  2143. const importedData = $('#clipboardContent').val();
  2144. if (importedData.trim() === '') {
  2145. return;
  2146. }
  2147. const jsonObject = JSON.parse(importedData);
  2148. if (!jsonObject) {
  2149. showErr('数据格式错误');
  2150. return;
  2151. }
  2152. globalData.setCopyData(jsonObject);
  2153. layer.load(2, { shade: [0.2, '#000'] });
  2154. await importData(jsonObject);
  2155. layer.closeAll();
  2156. }
  2157. });
  2158. });
  2159. $('#btn_copy_excel').on('click', function () {
  2160. const $tempDiv = document.createElement('div');
  2161. $tempDiv.style.position = 'absolute';
  2162. $tempDiv.style.left = '-9999px';
  2163. ['upstream_tb_normal', 'upstream_tb_fast', 'downstream_tb'].forEach(function (tableId) {
  2164. const $table = $('#' + tableId);
  2165. const $tableHeaderHtml = $table.next('.layui-table-view').find('.layui-table-header table').prop('outerHTML');
  2166. const $tableBodyHtml = $table.next('.layui-table-view').find('.layui-table-body table').prop('outerHTML');
  2167. const $tempTableDiv = document.createElement('div');
  2168. $tempTableDiv.innerHTML = '<table>' + $tableHeaderHtml + $tableBodyHtml + '</table>';
  2169. $tempTableDiv.querySelectorAll('tr').forEach(function (row, rowIndex) {
  2170. row.setAttribute('data-table-id', tableId);
  2171. });
  2172. $tempDiv.innerHTML += '<br><br>' + $tempTableDiv.innerHTML;
  2173. });
  2174. document.body.appendChild($tempDiv);
  2175. $tempDiv.querySelectorAll('tr').forEach(function (row) {
  2176. const $cells = row.querySelectorAll('td, th');
  2177. const numColsToRemove = 2;
  2178. for (let i = 0; i < numColsToRemove; i++) {
  2179. const cellIndex = $cells.length - 1 - i;
  2180. if (cellIndex >= 0) {
  2181. $cells[cellIndex].parentNode.removeChild($cells[cellIndex]);
  2182. }
  2183. }
  2184. });
  2185. const range = document.createRange();
  2186. range.selectNodeContents($tempDiv);
  2187. const selection = window.getSelection();
  2188. selection.removeAllRanges();
  2189. selection.addRange(range);
  2190. try {
  2191. const successful = document.execCommand('copy');
  2192. const msg = successful ? '表格内容已复制到剪贴板,请粘贴到Excel中' : '无法复制表格内容';
  2193. layer.msg(msg);
  2194. } catch (err) {
  2195. layer.msg('无法复制表格内容:' + err);
  2196. }
  2197. document.body.removeChild($tempDiv);
  2198. });
  2199. function loadMsgBadge () {
  2200. const normalWorkflow = new BatchWorkflow('normal');
  2201. const fastWorkflow = new BatchWorkflow('fast');
  2202. const $normalBadge = $('#approveBadgeNormal');
  2203. $normalBadge.hide();
  2204. const $fastBadge = $('#approveBadgeFast');
  2205. $fastBadge.hide();
  2206. const refreshApprovalMessage = async () => {
  2207. await normalWorkflow.initializeGlobalTaskList();
  2208. const normalMsg = normalWorkflow.getPendingTaskDetails();
  2209. const normalNum = normalMsg.length || 0;
  2210. $normalBadge.html(normalNum);
  2211. if (normalNum === 0) {
  2212. $normalBadge.hide();
  2213. } else {
  2214. $normalBadge.show();
  2215. }
  2216. await fastWorkflow.initializeGlobalTaskList();
  2217. const fastMsg = fastWorkflow.getPendingTaskDetails();
  2218. const fastNum = fastMsg.length || 0;
  2219. console.log('fastNum', fastNum);
  2220. $fastBadge.html(fastNum);
  2221. if (fastNum === 0) {
  2222. $fastBadge.hide();
  2223. } else {
  2224. $fastBadge.show();
  2225. }
  2226. }
  2227. refreshApprovalMessage();
  2228. }
  2229. loadMsgBadge();
  2230. $('#btn_search').on('click', function (){
  2231. initPage();
  2232. });
  2233. $('#btn_refresh_approve').on('click', function() {
  2234. if (systemUserName !== 'admin') {
  2235. showErr('您不是管理员,无审核权限');
  2236. return;
  2237. }
  2238. loadMsgBadge();
  2239. });
  2240. $('.reset-col').on('click', function () {
  2241. const tableId = $(this).data('table');
  2242. const col = $(this).data('col');
  2243. const setData = setTableColVal(tableId, col, '0');
  2244. if (col === 'transfer') {
  2245. setData.forEach(item => {
  2246. globalData.setPayinfo(item.store_id, item.tag, formatDecimals(item.val));
  2247. });
  2248. }
  2249. if (tableId === 'upstream_tb_normal') {
  2250. channelTableNormal.updateToCache(col, '0');
  2251. channelTableNormal.updateTableCalc();
  2252. } else if (tableId === 'upstream_tb_fast') {
  2253. channelTableFast.updateToCache(col, '0');
  2254. channelTableFast.updateTableCalc();
  2255. }
  2256. });
  2257. $('.ac-batch-deposit').on('click', function () {
  2258. const tableId = $(this).data('table');
  2259. let channelData = [];
  2260. if (tableId === 'upstream_tb_normal') {
  2261. channelData = globalData.getDataChanNormal();
  2262. batchDepositNormal.doApplyMore(tableId, channelData);
  2263. } else if(tableId === 'upstream_tb_fast') {
  2264. channelData = globalData.getDataChanFast();
  2265. batchDepositFast.doApplyMore(tableId, channelData);
  2266. }
  2267. });
  2268. $('.ac-approve').on('click', function () {
  2269. if (systemUserName !== 'admin') {
  2270. showErr('您不是管理员,无审核权限');
  2271. return;
  2272. }
  2273. const tableId = $(this).data('table');
  2274. if (tableId === 'upstream_tb_normal') {
  2275. batchDepositNormal.doBatchDeposit();
  2276. } else if(tableId === 'upstream_tb_fast') {
  2277. batchDepositFast.doBatchDeposit();
  2278. }
  2279. });
  2280. });
  2281. </script>