ProfitShareOrder.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863
  1. <template>
  2. <div class="profit-share-apply">
  3. <!-- 搜索条件 -->
  4. <el-card class="search-card">
  5. <el-form :model="searchForm" label-width="140px" inline>
  6. <el-form-item label="商户分账指令流水号">
  7. <el-input
  8. v-model="searchForm.out_separate_no"
  9. placeholder="请输入商户分账指令流水号"
  10. clearable
  11. style="width: 300px"
  12. @keyup.enter="handleSearch"
  13. />
  14. </el-form-item>
  15. <el-form-item label="分账状态">
  16. <el-select v-model="searchForm.status" placeholder="请选择分账状态" clearable style="width: 150px">
  17. <el-option label="全部" value="" />
  18. <el-option label="待处理" value="PENDING" />
  19. <el-option label="处理中" value="PROCESSING" />
  20. <el-option label="已受理" value="ACCEPTED" />
  21. <el-option label="成功" value="SUCCESS" />
  22. <el-option label="失败" value="FAIL" />
  23. </el-select>
  24. </el-form-item>
  25. <el-form-item>
  26. <el-button type="primary" @click="handleSearch">查询</el-button>
  27. <el-button @click="handleReset">重置</el-button>
  28. </el-form-item>
  29. </el-form>
  30. </el-card>
  31. <!-- 统计数据 -->
  32. <el-card class="stats-card" v-if="statsData">
  33. <el-row :gutter="20" justify="space-between">
  34. <el-col :span="4">
  35. <div class="stat-item total">
  36. <div class="stat-label">总分账金额</div>
  37. <div class="stat-value">¥{{ formatAmountToYuan(statsData.total_amount) }}</div>
  38. </div>
  39. </el-col>
  40. <el-col :span="4">
  41. <div class="stat-item merchant">
  42. <div class="stat-label">商户最低分账</div>
  43. <div class="stat-value">¥{{ formatAmountToYuan(statsData.merchant_total_amount) }}</div>
  44. </div>
  45. </el-col>
  46. <el-col :span="4">
  47. <div class="stat-item balance">
  48. <div class="stat-label">分账账户余额</div>
  49. <div class="stat-value">¥{{statsData.profit_share_balance}}</div>
  50. </div>
  51. </el-col>
  52. <el-col :span="4">
  53. <div class="stat-item user">
  54. <div class="stat-label">用户成功分账</div>
  55. <div class="stat-value">¥{{ formatAmountToYuan(statsData.user_total_amount) }}</div>
  56. </div>
  57. </el-col>
  58. <el-col :span="4">
  59. <div class="stat-item pending">
  60. <div class="stat-label">用户待分账</div>
  61. <div class="stat-value">¥{{ formatAmountToYuan(statsData.user_pending_amount) }}</div>
  62. </div>
  63. </el-col>
  64. </el-row>
  65. </el-card>
  66. <!-- 列表数据 -->
  67. <el-card class="table-card">
  68. <template #header>
  69. <div class="table-header">
  70. <div class="header-title">分账申请记录列表</div>
  71. </div>
  72. </template>
  73. <el-table
  74. v-loading="loading"
  75. :data="tableData"
  76. border
  77. stripe
  78. style="width: 100%"
  79. :header-cell-style="{background: '#f8f9fa', color: '#606266'}"
  80. highlight-current-row
  81. >
  82. <el-table-column prop="id" label="ID" width="80" align="center" />
  83. <el-table-column label="用户信息" width="200">
  84. <template #default="{ row }">
  85. <div class="user-info">
  86. <div class="user-detail-item">
  87. <span class="label">ID:</span>
  88. <span class="value">{{ row.user_id }}</span>
  89. </div>
  90. <div class="user-detail-item">
  91. <span class="label">昵称:</span>
  92. <span class="value">{{ row.user?.nickname || '-' }}</span>
  93. </div>
  94. <div class="user-detail-item">
  95. <span class="label">用户名:</span>
  96. <span class="value">{{ row.user?.username || '-' }}</span>
  97. </div>
  98. <div class="user-detail-item">
  99. <span class="label">手机:</span>
  100. <span class="value">{{ row.user?.mobile || '-' }}</span>
  101. </div>
  102. </div>
  103. </template>
  104. </el-table-column>
  105. <el-table-column label="分账指令流水号" min-width="240">
  106. <template #default="{ row }">
  107. <div class="order-numbers">
  108. <div class="order-number-item">
  109. <span class="label">商户:</span>
  110. <span class="value">{{ row.out_separate_no }}</span>
  111. </div>
  112. <div class="order-number-item">
  113. <span class="label">平台:</span>
  114. <span class="value">{{ row.separate_no || '--'}}</span>
  115. </div>
  116. </div>
  117. </template>
  118. </el-table-column>
  119. <el-table-column prop="total_amt" label="分账总金额(元)" width="140" align="right">
  120. <template #default="{ row }">
  121. <span style="font-weight: 600; color: #e6a23c; font-size: 16px">¥{{ formatAmountToYuan(row.total_amt) }}</span>
  122. </template>
  123. </el-table-column>
  124. <el-table-column label="接收方商户信息" width="220">
  125. <template #default="{ row }">
  126. <div class="merchant-info">
  127. <div class="merchant-no" :title="row.recv_merchant_no">商户号: {{ row.recv_merchant_no }}</div>
  128. <div class="merchant-no" :title="row.merchant_no">分账商户号: {{ row.merchant_no }}</div>
  129. <div class="amount-details">
  130. <div class="amount-row">
  131. <span class="label">最低分账金额:</span>
  132. <span class="value">¥{{ formatAmountToYuan(row.total_amt - row.separate_value) }}</span>
  133. </div>
  134. </div>
  135. </div>
  136. </template>
  137. </el-table-column>
  138. <el-table-column label="分账接收方信息" width="180">
  139. <template #default="{ row }">
  140. <div class="receiver-info">
  141. <div class="receiver-no">编号: {{ row.recv_no }}</div>
  142. <div class="amount-details">
  143. <div class="amount-row">
  144. <span class="label">总金额:</span>
  145. <span class="value">¥{{ formatAmountToYuan(getTotalSeparateAmount(row)) }}</span>
  146. </div>
  147. <div class="amount-row">
  148. <span class="label">手续费:</span>
  149. <span class="value fee">-¥{{ formatAmountToYuan(row.fee_amt) }}</span>
  150. </div>
  151. <div class="divider"></div>
  152. <div class="amount-row total">
  153. <span class="label">实际分账:</span>
  154. <span class="value total">¥{{ formatAmountToYuan(row.separate_value) }}</span>
  155. </div>
  156. </div>
  157. </div>
  158. </template>
  159. </el-table-column>
  160. <el-table-column prop="status" label="分账状态" width="120" align="center">
  161. <template #default="{ row }">
  162. <span :class="['status-badge', `status-${row.status.toLowerCase()}`]">{{ getStatusText(row.status) }}</span>
  163. </template>
  164. </el-table-column>
  165. <el-table-column prop="fail_reason" label="分账失败原因" min-width="180" />
  166. <el-table-column prop="create_time" label="创建时间" width="180" align="center" />
  167. <el-table-column prop="update_time" label="更新时间" width="180" align="center" />
  168. <el-table-column label="操作" width="180" fixed="right">
  169. <template #default="{ row }">
  170. <div v-if="row.status === 'PENDING'">
  171. <el-button type="success" size="small" @click="handleApprove(row)">通过</el-button>
  172. <el-button type="danger" size="small" @click="handleReject(row)">驳回</el-button>
  173. </div>
  174. <div>
  175. <el-button
  176. type="primary"
  177. size="small"
  178. link
  179. @click="showBalanceRecordDialog(row.user_id)"
  180. >
  181. 资金明细
  182. </el-button>
  183. </div>
  184. </template>
  185. </el-table-column>
  186. </el-table>
  187. <!-- 分页 -->
  188. <el-pagination
  189. v-model:current-page="pagination.page"
  190. v-model:page-size="pagination.limit"
  191. :total="pagination.total"
  192. :page-sizes="[10, 20, 50, 100]"
  193. layout="total, sizes, prev, pager, next, jumper"
  194. @size-change="handleSizeChange"
  195. @current-change="handleCurrentChange"
  196. class="pagination"
  197. />
  198. </el-card>
  199. <!-- 驳回对话框 -->
  200. <el-dialog
  201. v-model="rejectDialogVisible"
  202. title="驳回分账申请"
  203. width="500px"
  204. destroy-on-close
  205. >
  206. <el-form label-width="100px">
  207. <el-form-item label="驳回原因" required>
  208. <el-input
  209. v-model="rejectForm.reason"
  210. type="textarea"
  211. :rows="3"
  212. placeholder="请输入驳回原因"
  213. />
  214. </el-form-item>
  215. </el-form>
  216. <template #footer>
  217. <span class="dialog-footer">
  218. <el-button @click="rejectDialogVisible = false">取消</el-button>
  219. <el-button type="primary" @click="submitReject" :loading="rejectLoading">确定</el-button>
  220. </span>
  221. </template>
  222. </el-dialog>
  223. <!-- 资金明细对话框 -->
  224. <el-dialog
  225. v-model="balanceRecordDialogVisible"
  226. title="资金明细"
  227. width="800px"
  228. @close="closeBalanceRecordDialog"
  229. >
  230. <el-table
  231. v-loading="balanceRecordLoading"
  232. :data="balanceRecords"
  233. stripe
  234. style="width: 100%"
  235. >
  236. <el-table-column prop="id" label="ID" width="80" />
  237. <el-table-column prop="type_text" label="类型" width="100" />
  238. <el-table-column prop="amount" label="金额" width="120" align="right">
  239. <template #default="scope">
  240. <span :class="scope.row.amount > 0 ? 'amount-increase' : 'amount-decrease'">
  241. {{ scope.row.amount > 0 ? '+' : '' }}{{ scope.row.amount }}
  242. </span>
  243. </template>
  244. </el-table-column>
  245. <el-table-column prop="balance" label="余额" width="120" align="right" />
  246. <el-table-column prop="description" label="描述" show-overflow-tooltip />
  247. <el-table-column prop="create_time" label="时间" width="160" />
  248. </el-table>
  249. <!-- 资金明细分页 -->
  250. <div class="pagination-container" style="margin-top: 20px;">
  251. <el-pagination
  252. v-model:current-page="balanceRecordPagination.page"
  253. v-model:page-size="balanceRecordPagination.limit"
  254. :total="balanceRecordPagination.total"
  255. :page-sizes="[10, 20, 50]"
  256. background
  257. layout="total, sizes, prev, pager, next, jumper"
  258. @size-change="handleBalanceRecordSizeChange"
  259. @current-change="handleBalanceRecordCurrentChange"
  260. />
  261. </div>
  262. <template #footer>
  263. <span class="dialog-footer">
  264. <el-button @click="closeBalanceRecordDialog">关闭</el-button>
  265. </span>
  266. </template>
  267. </el-dialog>
  268. </div>
  269. </template>
  270. <script>
  271. export default {
  272. name: "ProfitShareOrder",
  273. inheritAttrs: false,
  274. props: {
  275. axiosInstance: {
  276. type: Object,
  277. default: null
  278. }
  279. },
  280. data() {
  281. return {
  282. loading: false,
  283. rejectLoading: false,
  284. balanceRecordLoading: false,
  285. searchForm: {
  286. out_separate_no: '',
  287. status: ''
  288. },
  289. tableData: [],
  290. statsData: null,
  291. pagination: {
  292. page: 1,
  293. limit: 10,
  294. total: 0
  295. },
  296. // 驳回对话框相关
  297. rejectDialogVisible: false,
  298. rejectForm: {
  299. orderId: null,
  300. reason: ''
  301. },
  302. // 资金明细对话框相关
  303. balanceRecordDialogVisible: false,
  304. balanceRecords: [],
  305. balanceRecordPagination: {
  306. page: 1,
  307. limit: 10,
  308. total: 0
  309. },
  310. currentUserId: null
  311. }
  312. },
  313. async created() {
  314. this.fetchData()
  315. },
  316. methods: {
  317. // 计算用户分账总金额(实际分账+手续费)
  318. getTotalSeparateAmount(row) {
  319. // 处理字符串和数字类型的金额值
  320. const separateValue = parseFloat(row.separate_value) || 0;
  321. const feeAmt = parseFloat(row.fee_amt) || 0;
  322. return separateValue + feeAmt;
  323. },
  324. // 格式化金额显示(分转元)
  325. formatAmountToYuan(amount) {
  326. if (amount === null || amount === undefined || amount === '') {
  327. return '-';
  328. }
  329. // 如果是字符串,先转换为浮点数
  330. const numericAmount = typeof amount === 'string' ? parseFloat(amount) : amount;
  331. // 将分转换为元并保留两位小数
  332. return (numericAmount / 100).toFixed(2);
  333. },
  334. // 获取分账状态文本
  335. getStatusText(status) {
  336. const statusMap = {
  337. 'PENDING': '待处理',
  338. 'PROCESSING': '处理中',
  339. 'ACCEPTED': '已受理',
  340. 'SUCCESS': '成功',
  341. 'FAIL': '失败'
  342. }
  343. return statusMap[status] || status
  344. },
  345. // 获取列表数据
  346. async fetchData() {
  347. if (!this.axiosInstance) {
  348. this.$message.error('无法获取请求实例')
  349. return
  350. }
  351. this.loading = true
  352. try {
  353. const params = {
  354. page: this.pagination.page,
  355. limit: this.pagination.limit,
  356. out_separate_no: this.searchForm.out_separate_no,
  357. status: this.searchForm.status
  358. }
  359. const res = await this.axiosInstance.get('/lakala/profit_share_order', { params })
  360. if (res.code === 200) {
  361. this.tableData = res.page.data
  362. this.pagination.total = res.page.total
  363. this.pagination.limit = res.page.per_page
  364. // 获取统计数据并计算商户分账总金额
  365. if (res.data?.stats) {
  366. // 商户分账总金额 = 总分账金额 - 用户分账总金额
  367. res.data.stats.merchant_total_amount = res.data.stats.total_amount - res.data.stats.user_total_amount;
  368. this.statsData = res.data.stats;
  369. } else {
  370. this.statsData = null;
  371. }
  372. } else {
  373. this.$message.error(res.msg || res.message || '获取数据失败')
  374. }
  375. } catch (error) {
  376. console.error('获取分账申请记录列表失败:', error)
  377. this.$message.error('获取数据失败: ' + (error.message || '未知错误'))
  378. } finally {
  379. this.loading = false
  380. }
  381. },
  382. // 查询
  383. handleSearch() {
  384. this.pagination.page = 1
  385. this.fetchData()
  386. },
  387. // 重置
  388. handleReset() {
  389. this.searchForm = {
  390. out_separate_no: '',
  391. status: ''
  392. }
  393. this.pagination.page = 1
  394. this.fetchData()
  395. },
  396. // 通过分账申请
  397. async handleApprove(row) {
  398. try {
  399. await this.$confirm('确认通过该分账申请吗?', '提示', {
  400. confirmButtonText: '确定',
  401. cancelButtonText: '取消',
  402. type: 'warning'
  403. });
  404. const res = await this.axiosInstance.put(`/lakala/profit_share_order/${row.id}/approve`);
  405. if (res.code === 200) {
  406. this.$message.success('操作成功');
  407. this.fetchData(); // 刷新列表
  408. } else {
  409. this.$message.error(res.msg || res.message || '操作失败');
  410. }
  411. } catch (error) {
  412. if (error !== 'cancel') {
  413. console.error('通过分账申请失败:', error);
  414. this.$message.error('操作失败: ' + (error.message || '未知错误'));
  415. }
  416. }
  417. },
  418. // 显示驳回对话框
  419. handleReject(row) {
  420. this.rejectForm.orderId = row.id;
  421. this.rejectForm.reason = '';
  422. this.rejectDialogVisible = true;
  423. },
  424. // 提交驳回
  425. async submitReject() {
  426. if (!this.rejectForm.reason) {
  427. this.$message.warning('请输入驳回原因');
  428. return;
  429. }
  430. this.rejectLoading = true;
  431. try {
  432. const res = await this.axiosInstance.put(`/lakala/profit_share_order/${this.rejectForm.orderId}/reject`, {
  433. reason: this.rejectForm.reason
  434. });
  435. if (res.code === 200) {
  436. this.$message.success('驳回成功');
  437. this.rejectDialogVisible = false;
  438. this.fetchData(); // 刷新列表
  439. } else {
  440. this.$message.error(res.msg || res.message || '驳回失败');
  441. }
  442. } catch (error) {
  443. console.error('驳回分账申请失败:', error);
  444. this.$message.error('驳回失败: ' + (error.message || '未知错误'));
  445. } finally {
  446. this.rejectLoading = false;
  447. }
  448. },
  449. // 分页相关
  450. handleSizeChange(val) {
  451. this.pagination.limit = val;
  452. this.pagination.page = 1;
  453. this.fetchData();
  454. },
  455. handleCurrentChange(val) {
  456. this.pagination.page = val;
  457. this.fetchData();
  458. },
  459. // 显示资金明细对话框
  460. showBalanceRecordDialog(userId) {
  461. this.currentUserId = userId;
  462. this.balanceRecordDialogVisible = true;
  463. this.getBalanceRecords();
  464. },
  465. // 关闭资金明细对话框
  466. closeBalanceRecordDialog() {
  467. this.balanceRecordDialogVisible = false;
  468. this.balanceRecords = [];
  469. this.balanceRecordPagination.page = 1;
  470. this.balanceRecordPagination.total = 0;
  471. this.currentUserId = null;
  472. },
  473. // 获取资金明细
  474. async getBalanceRecords() {
  475. if (!this.axiosInstance) {
  476. this.$message.error('无法获取请求实例');
  477. return;
  478. }
  479. try {
  480. this.balanceRecordLoading = true;
  481. const params = {
  482. user_id: this.currentUserId,
  483. page: this.balanceRecordPagination.page,
  484. limit: this.balanceRecordPagination.limit
  485. };
  486. const res = await this.axiosInstance.get('/balpay/log', { params });
  487. if (res.code === 200) {
  488. this.balanceRecords = res.page?.data || [];
  489. this.balanceRecordPagination.total = res.page?.total || 0;
  490. } else {
  491. this.$message.error(res.msg || '获取资金明细失败');
  492. }
  493. } catch (error) {
  494. console.error('获取资金明细失败:', error);
  495. this.$message.error('获取资金明细失败');
  496. } finally {
  497. this.balanceRecordLoading = false;
  498. }
  499. },
  500. // 资金明细分页处理
  501. handleBalanceRecordSizeChange(size) {
  502. this.balanceRecordPagination.limit = size;
  503. this.balanceRecordPagination.page = 1;
  504. this.getBalanceRecords();
  505. },
  506. handleBalanceRecordCurrentChange(page) {
  507. this.balanceRecordPagination.page = page;
  508. this.getBalanceRecords();
  509. }
  510. }
  511. }
  512. </script>
  513. <style scoped>
  514. .profit-share-apply {
  515. padding: 20px;
  516. }
  517. .search-card {
  518. margin-bottom: 20px;
  519. box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  520. border-radius: 8px;
  521. }
  522. .search-card ::v-deep(.el-card__header) {
  523. background-color: #f5f7fa;
  524. font-weight: bold;
  525. }
  526. .stats-card {
  527. margin-bottom: 20px;
  528. box-shadow: 0 4px 20px 0 rgba(0, 0, 0, 0.1);
  529. border-radius: 12px;
  530. background: linear-gradient(120deg, #f8f9fa 0%, #e9ecef 100%) !important;
  531. border: none;
  532. overflow: hidden;
  533. }
  534. .stat-item {
  535. display: flex;
  536. flex-direction: column;
  537. align-items: center;
  538. justify-content: center;
  539. padding: 25px 10px;
  540. text-align: center;
  541. border-radius: 10px;
  542. transition: all 0.3s ease;
  543. background: white;
  544. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  545. }
  546. .stat-item:hover {
  547. transform: translateY(-5px);
  548. box-shadow: 0 6px 16px rgba(0, 0, 0, 0.15);
  549. }
  550. .stat-item.total {
  551. background: linear-gradient(135deg, #8eefe8 0%, #4db6ac 100%) !important;
  552. }
  553. .stat-item.merchant {
  554. background: linear-gradient(135deg, #a8d8ff 0%, #4da6ff 100%) !important;
  555. }
  556. .stat-item.balance {
  557. background: linear-gradient(135deg, #c1bfff 0%, #7e5bff 100%) !important;
  558. }
  559. .stat-item.user {
  560. background: linear-gradient(135deg, #bafca2 0%, #6fd649 100%) !important;
  561. }
  562. .stat-item.pending {
  563. background: linear-gradient(135deg, #ffd54f 0%, #ffb300 100%) !important;
  564. }
  565. .stat-label {
  566. font-size: 16px;
  567. font-weight: 500;
  568. color: #ffffff !important;
  569. margin-bottom: 10px;
  570. text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
  571. }
  572. .stat-value {
  573. font-size: 22px;
  574. font-weight: 700;
  575. color: #ffffff !important;
  576. text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
  577. }
  578. .table-card {
  579. margin-bottom: 20px;
  580. box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  581. border-radius: 8px;
  582. overflow: hidden;
  583. }
  584. .table-header {
  585. display: flex;
  586. justify-content: space-between;
  587. align-items: center;
  588. }
  589. .header-title {
  590. font-size: 18px;
  591. font-weight: bold;
  592. color: #303133;
  593. }
  594. .pagination {
  595. margin-top: 20px;
  596. text-align: right;
  597. }
  598. .user-info {
  599. display: flex;
  600. flex-direction: column;
  601. gap: 4px;
  602. }
  603. .user-detail-item {
  604. display: flex;
  605. font-size: 12px;
  606. }
  607. .user-detail-item .label {
  608. width: 50px;
  609. font-weight: 500;
  610. color: #606266;
  611. flex-shrink: 0;
  612. }
  613. .user-detail-item .value {
  614. flex: 1;
  615. color: #303133;
  616. word-break: break-all;
  617. }
  618. .order-numbers {
  619. display: flex;
  620. flex-direction: column;
  621. gap: 4px;
  622. }
  623. .order-number-item {
  624. display: flex;
  625. }
  626. .order-number-item .label {
  627. width: 40px;
  628. font-weight: 500;
  629. color: #606266;
  630. text-align: right;
  631. margin-right: 8px;
  632. flex-shrink: 0;
  633. }
  634. .order-number-item .value {
  635. flex: 1;
  636. color: #303133;
  637. word-break: break-all;
  638. }
  639. .amount-calculation {
  640. font-size: 12px;
  641. }
  642. .amount-calculation.detail {
  643. padding: 12px;
  644. background: linear-gradient(135deg, #f5f7fa 0%, #e4e7ed 100%);
  645. border-radius: 6px;
  646. box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  647. }
  648. .amount-calculation .main-amount,
  649. .amount-calculation .fee-amount,
  650. .amount-calculation .result-amount {
  651. display: flex;
  652. justify-content: space-between;
  653. margin-bottom: 5px;
  654. }
  655. .amount-calculation .amount {
  656. font-weight: 600;
  657. color: #303133;
  658. text-align: right;
  659. }
  660. .amount-calculation .result-amount .amount {
  661. color: #67c23a;
  662. font-weight: 700;
  663. font-size: 14px;
  664. }
  665. .amount-calculation .divider {
  666. height: 1px;
  667. background: linear-gradient(to right, transparent, #c0c4cc, transparent);
  668. margin: 6px 0;
  669. }
  670. .merchant-info {
  671. padding: 8px;
  672. background: linear-gradient(135deg, #e8f4ff 0%, #d0e6ff 100%);
  673. border-radius: 4px;
  674. font-size: 12px;
  675. }
  676. .merchant-info .merchant-no {
  677. margin-bottom: 5px;
  678. color: #606266;
  679. font-weight: 500;
  680. }
  681. .receiver-info {
  682. padding: 8px;
  683. background: linear-gradient(135deg, #e8f4ff 0%, #d0e6ff 100%);
  684. border-radius: 4px;
  685. font-size: 12px;
  686. }
  687. .amount-details {
  688. margin-top: 5px;
  689. }
  690. .amount-row {
  691. display: flex;
  692. justify-content: space-between;
  693. margin-bottom: 3px;
  694. }
  695. .amount-row .label {
  696. color: #606266;
  697. }
  698. .amount-row .value {
  699. font-weight: 500;
  700. color: #303133;
  701. }
  702. .amount-row .value.fee {
  703. color: #f56c6c;
  704. }
  705. .amount-row.total {
  706. font-weight: 700;
  707. margin-top: 3px;
  708. padding-top: 3px;
  709. border-top: 1px solid #dcdfe6;
  710. }
  711. .amount-row.total .value {
  712. color: #67c23a;
  713. font-size: 14px;
  714. }
  715. .status-badge {
  716. padding: 4px 8px;
  717. border-radius: 12px;
  718. font-size: 12px;
  719. font-weight: 500;
  720. }
  721. .status-pending {
  722. background-color: #f0f9eb;
  723. color: #67c23a;
  724. }
  725. .status-processing {
  726. background-color: #ecf5ff;
  727. color: #409eff;
  728. }
  729. .status-accepted {
  730. background-color: #e6f3ff;
  731. color: #3a86ff;
  732. }
  733. .status-success {
  734. background-color: #f0f9eb;
  735. color: #67c23a;
  736. }
  737. .status-fail {
  738. background-color: #fef0f0;
  739. color: #f56c6c;
  740. }
  741. .el-table ::v-deep(.el-table__header-wrapper) th {
  742. background-color: #f5f7fa;
  743. color: #606266;
  744. font-weight: 600;
  745. }
  746. .el-table ::v-deep(.el-table__row:hover) td {
  747. background-color: #f5f9ff !important;
  748. }
  749. .dialog-footer {
  750. display: flex;
  751. justify-content: flex-end;
  752. padding: 10px 0;
  753. }
  754. ::v-deep(.el-dialog__header) {
  755. background-color: #f5f7fa;
  756. border-bottom: 1px solid #ebeef5;
  757. font-weight: bold;
  758. }
  759. ::v-deep(.el-form-item__label) {
  760. font-weight: 500;
  761. }
  762. .amount-increase {
  763. color: #67c23a;
  764. }
  765. .amount-decrease {
  766. color: #f56c6c;
  767. }
  768. .pagination-container {
  769. display: flex;
  770. justify-content: flex-end;
  771. margin-top: 20px;
  772. }
  773. </style>