You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

818 lines
26 KiB

2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
1 month ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
1 month ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
1 month ago
1 month ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
1 month ago
2 months ago
  1. <script setup>
  2. import { ref, reactive, onMounted } from 'vue'
  3. import { useRoute } from 'vue-router'
  4. import { ElMessage, ElMessageBox } from 'element-plus'
  5. import request from '@/util/http.js'
  6. import dayjs from 'dayjs'
  7. import { useI18n } from 'vue-i18n'
  8. import { Moneyfunds, refundOnline } from '@/api/cash/financialAccount.js'
  9. import { useAdminStore } from '@/store/index.js'
  10. import { storeToRefs } from 'pinia'
  11. import _ from 'lodash';
  12. const adminStore = useAdminStore()
  13. const { adminData } = storeToRefs(adminStore)
  14. const { t } = useI18n()
  15. const route = useRoute()
  16. const paytypeList = [
  17. t('cash.payMethods.stripe'),
  18. t('cash.payMethods.paymentAsia'),
  19. t('cash.payMethods.ipay88'),
  20. t('cash.payMethods.bankTransfer'),
  21. t('cash.payMethods.card'),
  22. t('cash.payMethods.cash'),
  23. t('cash.payMethods.check'),
  24. t('cash.payMethods.grabpay'),
  25. t('cash.payMethods.nets'),
  26. t('cash.payMethods.transfer'),
  27. t('cash.payMethods.paypal'),
  28. ]
  29. const payPlatformOptions = ref([...paytypeList])
  30. const statusOptions = [
  31. { label: t('common_list.received'), value: 4 },
  32. { label: t('common_list.rejected'), value: 6 }
  33. ]
  34. // 地区树
  35. const marketOptions = ref([])
  36. // 查询参数
  37. const queryParams = reactive({
  38. jwcode: '',
  39. markets: [], // 下拉多选
  40. timeRange: [], // [startTime, endTime]
  41. payType: '',
  42. orderCode: '',
  43. statuses: [],
  44. pageNum: 1,
  45. pageSize: 20
  46. })
  47. const total = ref(0)
  48. const tableData = ref([])
  49. const loading = ref(false)
  50. // 转换树形结构(参考 coinConsumeDetail.vue)
  51. const transformTree = (nodes) => {
  52. const allChildren = nodes.flatMap(node => node.children || []);
  53. return allChildren.map(child => {
  54. const grandchildren = child.children && child.children.length
  55. ? transformTree([child])
  56. : null;
  57. return {
  58. value: child.id,
  59. label: child.name,
  60. children: grandchildren
  61. };
  62. });
  63. };
  64. // 获取地区数据
  65. const getMarket = async () => {
  66. try {
  67. const result = await request({ url: '/market/selectMarket' });
  68. if (result && result.data) {
  69. marketOptions.value = transformTree(result.data)
  70. }
  71. } catch (error) {
  72. console.error('获取地区失败', error)
  73. }
  74. }
  75. // 查询列表
  76. const fetchData = async () => {
  77. loading.value = true
  78. try {
  79. // 构建请求参数
  80. const params = {
  81. pageNum: queryParams.pageNum,
  82. pageSize: queryParams.pageSize,
  83. fundsDTO: {
  84. jwcode: queryParams.jwcode,
  85. markets: queryParams.markets,
  86. startTime: queryParams.timeRange?.[0] ? dayjs(queryParams.timeRange[0]).format('YYYY-MM-DD HH:mm:ss') : '',
  87. endTime: queryParams.timeRange?.[1] ? dayjs(queryParams.timeRange[1]).format('YYYY-MM-DD HH:mm:ss') : '',
  88. payType: queryParams.payType,
  89. orderCode: queryParams.orderCode,
  90. statuses: queryParams.statuses,
  91. }
  92. }
  93. console.log('查询参数:', params)
  94. const res = await Moneyfunds(params)
  95. if (res.code == 200) {
  96. tableData.value = res.data.list || []
  97. total.value = res.data.total || 0
  98. loading.value = false
  99. } else {
  100. ElMessage.error(res.msg || t('elmessage.getDataFailed'))
  101. loading.value = false
  102. }
  103. } catch (error) {
  104. console.error(error)
  105. loading.value = false
  106. ElMessage.error(t('elmessage.getDataFailed'))
  107. }
  108. }
  109. const handleSearch = () => {
  110. queryParams.pageNum = 1
  111. fetchData()
  112. }
  113. const handleReset = () => {
  114. queryParams.jwcode = ''
  115. queryParams.markets = []
  116. queryParams.timeRange = null
  117. queryParams.payType = ''
  118. queryParams.orderCode = ''
  119. queryParams.statuses = []
  120. handleSearch()
  121. }
  122. const handlePageSizeChange = (val) => {
  123. queryParams.pageSize = val
  124. fetchData()
  125. }
  126. const handleCurrentChange = (val) => {
  127. queryParams.pageNum = val
  128. fetchData()
  129. }
  130. // 退款操作
  131. const openRefundConfirm = (row) => {
  132. textContent.value = t('common.willRefundOrder') + '?'
  133. refundConfirmDialog.value = true
  134. refundFormData.value = {
  135. ...row,
  136. oldpermanentGold: row.permanentGold,//退款永久金币
  137. oldfreeGold: row.freeGold,//退款免费金币
  138. permanentGold: null,
  139. freeGold: null,
  140. }
  141. console.log(row);
  142. }
  143. const openRefundDialog = () => {
  144. refundDialog.value = true
  145. closeConfirmRefund()
  146. }
  147. const closeConfirmRefund = () => {
  148. refundConfirmDialog.value = false
  149. textContent.value = ''
  150. }
  151. const refundConfirmDialog = ref(false)
  152. const textContent = ref('')
  153. const refundDialog = ref(false)
  154. const refundFormData = ref({})
  155. const resetRefund = () => {
  156. refundFormData.value.refundModel = ''
  157. refundFormData.value.refundReason = ''
  158. refundFormData.value.permanentGold = null
  159. refundFormData.value.freeGold = null
  160. }
  161. const handleRefund = async () => {
  162. try {
  163. if (refundFormData.value.refundModel == 1) {
  164. refundFormData.value.permanentGold = refundFormData.value.oldpermanentGold
  165. refundFormData.value.freeGold = refundFormData.value.oldfreeGold
  166. }
  167. let params = {
  168. jwcode: refundFormData.value.jwcode,
  169. name: refundFormData.value.name,
  170. market: refundFormData.value.marketName,
  171. submitterMarket: adminData.value.markets,
  172. remark: refundFormData.value.remark,
  173. originalOrderId: refundFormData.value.id,
  174. refundReason: refundFormData.value.refundReason,
  175. refundModel: refundFormData.value.refundModel,
  176. orderCode: refundFormData.value.orderCode,
  177. submitterId: adminData.value.id,
  178. submitterMarket: adminData.value.markets,
  179. permanentGold: (refundFormData.value.permanentGold) * 100 || 0,
  180. handlingCharge: refundFormData.value.handlingCharge == null ? null : refundFormData.value.handlingCharge * 100,
  181. freeGold: (refundFormData.value.freeGold) * 100 || 0,
  182. }
  183. console.log('这是退款参数:', params);
  184. const res = await refundOnline(params)
  185. if (res.code == 200) {
  186. refundDialog.value = false
  187. fetchData()
  188. } else {
  189. ElMessage.error(res.msg || '退款失败')
  190. }
  191. } catch (error) {
  192. console.error(error)
  193. }
  194. }
  195. // ==================== 导出相关逻辑 ====================
  196. const exportListVisible = ref(false)
  197. const exportList = ref([])
  198. const exportListLoading = ref(false)
  199. // 导出Excel
  200. const handleExport = async () => {
  201. try {
  202. const params = {
  203. pageNum: queryParams.pageNum,
  204. pageSize: queryParams.pageSize,
  205. fundsDTO: {
  206. jwcode: queryParams.jwcode,
  207. markets: queryParams.markets,
  208. startTime: queryParams.timeRange?.[0] ? dayjs(queryParams.timeRange[0]).format('YYYY-MM-DD HH:mm:ss') : '',
  209. endTime: queryParams.timeRange?.[1] ? dayjs(queryParams.timeRange[1]).format('YYYY-MM-DD HH:mm:ss') : '',
  210. payType: queryParams.payType,
  211. orderCode: queryParams.orderCode,
  212. statuses: queryParams.statuses,
  213. }
  214. }
  215. // TODO: 确认导出接口 URL
  216. const res = await request({ url: '/export/exportCash', data: params })
  217. if (res.code == 200) {
  218. console.log('导出参数', params)
  219. ElMessage.success(t('elmessage.exportSuccess'))
  220. }
  221. } catch (error) {
  222. console.error(error)
  223. ElMessage.error(t('elmessage.exportError'))
  224. }
  225. }
  226. // 打开导出列表弹窗
  227. const openExportList = () => {
  228. getExportList()
  229. exportListVisible.value = true
  230. }
  231. // 获取导出列表
  232. const getExportList = async () => {
  233. exportListLoading.value = true
  234. try {
  235. const result = await request({ url: '/export/export' })
  236. if (result.code === 200) {
  237. const filteredData = result.data.filter(item => item.type == 13);
  238. exportList.value = filteredData || []
  239. } else {
  240. ElMessage.error(result.msg || t('elmessage.getExportListError'))
  241. }
  242. } catch (error) {
  243. console.error('获取导出列表出错:', error)
  244. ElMessage.error(t('elmessage.getExportListError'))
  245. } finally {
  246. exportListLoading.value = false
  247. }
  248. }
  249. // 下载导出文件
  250. const downloadExportFile = (item) => {
  251. if (item.state === 2) {
  252. const link = document.createElement('a')
  253. link.href = item.url
  254. link.download = item.fileName
  255. link.click()
  256. } else {
  257. ElMessage.warning(t('elmessage.exportingInProgress'))
  258. }
  259. }
  260. // 根据状态返回对应的标签类型
  261. const getTagType = (state) => {
  262. switch (state) {
  263. case 0: return 'info';
  264. case 1: return 'primary';
  265. case 2: return 'success';
  266. case 3: return 'danger';
  267. default: return 'info';
  268. }
  269. }
  270. // 根据状态返回对应的标签文案
  271. const getTagText = (state) => {
  272. switch (state) {
  273. case 0: return t('elmessage.pendingExecution');
  274. case 1: return t('elmessage.executing');
  275. case 2: return t('elmessage.executed');
  276. case 3: return t('elmessage.errorExecution');
  277. default: return t('elmessage.unknownStatus');
  278. }
  279. }
  280. const throttledsubmitRefund = _.throttle(handleRefund, 5000, {
  281. trailing: false
  282. })
  283. // 递归查找地区ID
  284. const findValueByLabel = (options, label) => {
  285. for (const option of options) {
  286. // 简单匹配名称,防止空格等问题,可以trim一下
  287. if (option.label === label || option.label?.trim() === label?.trim()) {
  288. return option.value
  289. }
  290. if (option.children && option.children.length) {
  291. const found = findValueByLabel(option.children, label)
  292. if (found) return found
  293. }
  294. }
  295. return null
  296. }
  297. onMounted(async () => {
  298. await getMarket()
  299. // 处理从工作台跳转过来的地区参数
  300. const regionName = route.query.region
  301. if (regionName && marketOptions.value.length) {
  302. const matchedId = findValueByLabel(marketOptions.value, regionName)
  303. if (matchedId) {
  304. // el-cascader 绑定的 markets 是数组
  305. queryParams.markets = [matchedId]
  306. }
  307. }
  308. fetchData()
  309. })
  310. </script>
  311. <template>
  312. <div class="cash-flow-container">
  313. <!-- 搜索区域 -->
  314. <el-card class="search-card">
  315. <div class="search-bar">
  316. <!-- 第一行 -->
  317. <div class="search-row">
  318. <div class="search-item">
  319. <span class="label">{{ t('common.jwcode') }}</span>
  320. <el-input v-model="queryParams.jwcode" :placeholder="t('common.jwcodePlaceholder')" clearable />
  321. </div>
  322. <div class="search-item">
  323. <span class="label">{{ t('common.market') }}</span>
  324. <!-- 下拉多选使用 el-cascader 匹配地区树结构 -->
  325. <el-cascader
  326. v-model="queryParams.markets"
  327. :options="marketOptions"
  328. :props="{ multiple: true, emitPath: false }"
  329. collapse-tags
  330. collapse-tags-tooltip
  331. :placeholder="t('common.marketPlaceholder')"
  332. clearable
  333. style="width: 220px;"
  334. />
  335. </div>
  336. <div class="search-item">
  337. <span class="label">{{ t('common.payPlatform1') }}</span>
  338. <el-select v-model="queryParams.payType" :placeholder="t('common.payPlatformPlaceholder1')" clearable>
  339. <el-option v-for="item in payPlatformOptions" :key="item" :label="item" :value="item" />
  340. </el-select>
  341. </div>
  342. <div class="search-item">
  343. <span class="label">{{ t('common.status') }}</span>
  344. <el-select v-model="queryParams.statuses[0]" :placeholder="t('common.statusPlaceholder')" clearable>
  345. <el-option v-for="item in statusOptions" :key="item.value" :label="item.label" :value="item.value" />
  346. </el-select>
  347. </div>
  348. <div class="search-item">
  349. <span class="label">{{ t('common.orderNo') }}</span>
  350. <el-input v-model="queryParams.orderCode" :placeholder="t('common.orderNoPlaceholder')" clearable />
  351. </div>
  352. <div class="search-item" style="width: auto;">
  353. <span class="label">{{ t('common.payTime2') }}</span>
  354. <el-date-picker
  355. v-model="queryParams.timeRange"
  356. type="datetimerange"
  357. :range-separator="t('common.to')"
  358. :start-placeholder="t('common.startTime')"
  359. :end-placeholder="t('common.endTime')"
  360. :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
  361. style="width: 350px;"
  362. />
  363. </div>
  364. <div class="search-btn-group">
  365. <el-button type="primary" @click="handleSearch">{{ t('common.search') }}</el-button>
  366. <el-button type="primary" @click="handleExport">{{ t('common.exportExcel') }}</el-button>
  367. <el-button type="primary" @click="openExportList">{{ t('common.viewExportList') }}</el-button>
  368. <el-button type="success" @click="handleReset">{{ t('common.reset') }}</el-button>
  369. </div>
  370. </div>
  371. </div>
  372. </el-card>
  373. <!-- 表格区域 -->
  374. <el-card class="table-card">
  375. <el-table :data="tableData" v-loading="loading" style="width: 100%; flex: 1;" :cell-style="{ textAlign: 'center' }" :header-cell-style="{ background: '#F3FAFE', color: '#333',textAlign: 'center' }">
  376. <el-table-column type="index" :label="t('common_list.id')" width="60" align="center" fixed="left" />
  377. <el-table-column prop="jwcode" :label="t('common_list.jwcode')" width="120" fixed="left" />
  378. <el-table-column prop="name" :label="t('common_list.name')" width="150" show-overflow-tooltip />
  379. <el-table-column prop="market" :label="t('common_list.market')" width="120" show-overflow-tooltip />
  380. <el-table-column prop="orderCode" :label="t('common_list.orderCode')" width="280" show-overflow-tooltip />
  381. <el-table-column prop="paymentAmount" :label="t('common_list.payAmount')" width="150" align="right">
  382. <!-- <template #default="{ row }">
  383. {{ row.paymentAmount }} {{ row.paymentCurrency }}
  384. </template> -->
  385. </el-table-column>
  386. <el-table-column prop="paymentCurrencyName" :label="t('common_list.payCurrency')" width="120" show-overflow-tooltip />
  387. <el-table-column prop="receivedAmount" :label="t('common_list.receiveAmount')" width="150" align="right">
  388. <!-- <template #default="{ row }">
  389. {{ row.receivedAmount }} {{ row.receivedCurrency }}
  390. </template> -->
  391. </el-table-column>
  392. <el-table-column prop="receivedCurrencyName" :label="t('common_list.receiveCurrency')" width="120" show-overflow-tooltip />
  393. <el-table-column prop="handlingCharge" :label="t('common_list.fee')" width="100" align="right" />
  394. <el-table-column prop="payType" :label="t('common_list.payModel')" width="120" align="center" />
  395. <el-table-column prop="payTime" :label="t('common_list.payTime2')" width="180" align="center" />
  396. <el-table-column prop="status" :label="t('common_list.status')" width="100" align="center" fixed="right">
  397. <template #default="{ row }">
  398. <el-tag :type="row.status === 4 ? 'success' : 'warning'" effect="plain">
  399. {{ row.status === 4 ? t('common_list.received') : t('common_list.rejected') }}
  400. </el-tag>
  401. </template>
  402. </el-table-column>
  403. <el-table-column :label="t('common_list.operation')" width="100" fixed="right" align="center">
  404. <template #default="{ row }">
  405. <el-button v-if="row.orderCode.slice(0, 4) == 'GOLD'" type="danger" link size="small"
  406. @click="openRefundConfirm(row)">
  407. {{ t('common_list.refund') }}
  408. </el-button>
  409. </template>
  410. </el-table-column>
  411. </el-table>
  412. <!-- 分页 -->
  413. <div class="pagination-container">
  414. <el-pagination background layout="total, sizes, prev, pager, next, jumper" :total="total"
  415. :current-page="queryParams.pageNum" :page-size="queryParams.pageSize" :page-sizes="[10, 20, 50, 100]"
  416. @size-change="handlePageSizeChange" @current-change="handleCurrentChange" />
  417. </div>
  418. </el-card>
  419. <!-- 导出列表弹窗 -->
  420. <el-dialog v-model="exportListVisible" :title="t('common_export.exportList')" width="80%">
  421. <el-table :data="exportList" style="width: 100% ;height: 60vh;" :loading="exportListLoading">
  422. <el-table-column prop="fileName" :label="t('common_export.fileName')" />
  423. <el-table-column prop="state" :label="t('common_export.status')">
  424. <template #default="scope">
  425. <el-tag :type="getTagType(scope.row.state)" :effect="scope.row.state === 3 ? 'light' : 'plain'">
  426. {{ getTagText(scope.row.state) }}
  427. </el-tag>
  428. </template>
  429. </el-table-column>
  430. <el-table-column prop="createTime" :label="t('common_export.createTime')">
  431. <template #default="scope">
  432. {{ dayjs(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
  433. </template>
  434. </el-table-column>
  435. <el-table-column :label="t('common_export.operation')">
  436. <template #default="scope">
  437. <el-button type="primary" size="small" @click="downloadExportFile(scope.row)"
  438. :disabled="scope.row.state !== 2">
  439. {{ t('common_export.download') }}
  440. </el-button>
  441. </template>
  442. </el-table-column>
  443. </el-table>
  444. <template #footer>
  445. <div class="dialog-footer">
  446. <el-button text @click="exportListVisible = false">{{ t('common_export.close') }}</el-button>
  447. </div>
  448. </template>
  449. </el-dialog>
  450. <div class="recallDialog" v-show="refundConfirmDialog">
  451. <div class="close">
  452. <button @click="closeConfirmRefund" class="Btn">{{ t('common.close') }}</button>
  453. </div>
  454. <div class="text">
  455. <text class="txt">{{ textContent }}</text>
  456. </div>
  457. <div class="cancle">
  458. <button @click="closeConfirmRefund" class="Btn">{{ t('common.cancel') }}</button>
  459. </div>
  460. <div class="confirm">
  461. <button @click="openRefundDialog" class="Btn">{{ t('common.confirm') }}</button>
  462. </div>
  463. </div>
  464. <el-dialog v-model="refundDialog" :title="t('common_add.refund')" class="refundDialog" overflow draggable
  465. style="width: 40vw;" :before-close="closeRefundForm">
  466. <div style="display: flex;">
  467. <div class="left">
  468. <div class="add-item">
  469. <el-text style="width:4vw;">{{ t('common_add.jwcode') }}</el-text>
  470. <el-input v-model="refundFormData.jwcode" style="width:10vw;" disabled />
  471. </div>
  472. <div class="add-item">
  473. <el-text style="width:4vw;">{{ t('common_add.customerName') }}</el-text>
  474. <el-input v-model="refundFormData.name" style="width:10vw;" disabled />
  475. </div>
  476. <div class="add-item">
  477. <el-text style="width:4vw;">{{ t('common_add.market') }}</el-text>
  478. <el-input v-model="refundFormData.marketName" style="width:10vw;" disabled />
  479. </div>
  480. <div class="add-item">
  481. <el-text style="width:4vw;">{{ t('common_add.activity') }}</el-text>
  482. <el-input v-model="refundFormData.activity" style="width:10vw;" disabled />
  483. </div>
  484. <div class="add-item">
  485. <el-text style="width:4vw;">{{ t('common_add.productName') }}</el-text>
  486. <el-input v-model="refundFormData.goodsName" style="width:10vw;" disabled />
  487. </div>
  488. <div style="display: flex; margin-bottom: 10px;">
  489. <div style=" display: flex; align-items: center;justify-content: center; ">
  490. <span style="color: #999999; white-space: nowrap;">{{ t('common_add.permanentGold')
  491. }}</span>
  492. <el-input style="padding-right: 10px; height: 30px; width: 70px;"
  493. v-model="refundFormData.oldpermanentGold" disabled />
  494. </div>
  495. <div style=" display: flex; align-items: center;justify-content: center; ">
  496. <span style="color: #999999; white-space: nowrap;">{{ t('common_add.freeGold') }}</span>
  497. <el-input style="padding-right: 10px; height: 30px; width: 70px;" v-model="refundFormData.oldfreeGold"
  498. disabled />
  499. </div>
  500. </div>
  501. <div class="add-item">
  502. <el-text style="width:4vw;">{{ t('common_add.payCurrency') }}</el-text>
  503. <el-input v-model="refundFormData.paymentCurrency" style="width:10vw;" disabled />
  504. </div>
  505. <div class="add-item">
  506. <el-text style="width:4vw;">{{ t('common_add.payAmount') }}</el-text>
  507. <el-input v-model="refundFormData.paymentAmount" style="width:10vw;" disabled />
  508. </div>
  509. <div class="add-item">
  510. <el-text style="width:4vw;">{{ t('common_add.payMethod') }}</el-text>
  511. <el-input v-model="refundFormData.payType" style="width:10vw;" disabled />
  512. </div>
  513. <div class="add-item">
  514. <el-text style="width:4vw;">{{ t('common_add.payTime') }}</el-text>
  515. <el-date-picker v-model="refundFormData.payTime" type="datetime" style="width:10vw;" disabled />
  516. </div>
  517. <div class="add-item">
  518. <el-text style="width:4vw;" size="small">{{ t('common_add.transferVoucher') }}</el-text>
  519. <el-form-item :rules="{ required: true, message: t('common_add.uploadPhoto'), trigger: 'change' }">
  520. <el-upload ref="uploadRef" :auto-upload="false" list-type="picture-card" :show-file-list="false">
  521. <template #default>
  522. <img v-if="refundFormData.voucher" :src="refundFormData.voucher"
  523. style="width: 100%; height: 100%; object-fit: cover;">
  524. <el-icon v-else>
  525. <Plus />
  526. </el-icon>
  527. </template>
  528. </el-upload>
  529. </el-form-item>
  530. </div>
  531. <div class="add-item">
  532. <el-text style="width:4vw;">{{ t('common_add.remark') }}</el-text>
  533. <el-input v-model="refundFormData.remark" style="width:10vw;" :rows="2" type="textarea" maxLength="100"
  534. disabled show-word-limit />
  535. </div>
  536. </div>
  537. <div class="right">
  538. <div class="add-item">
  539. <el-text style="width:4vw;">{{ t('common_add.refundModel') }}</el-text>
  540. <el-radio-group v-model="refundFormData.refundModel">
  541. <el-radio value="0">{{ t('common_add.refundModelAll') }}</el-radio>
  542. <el-radio value="1">{{ t('common_add.refundModelPart') }}</el-radio>
  543. </el-radio-group>
  544. </div>
  545. <div v-show="refundFormData.refundModel == '1'" style="display: flex; margin-bottom: 10px;">
  546. <div style=" display: flex; align-items: center;justify-content: center; ">
  547. <span style="color: #999999; white-space: nowrap;">{{ t('common_add.permanentGold')
  548. }}</span>
  549. <el-input style="padding-right: 10px; height: 30px; width: 70px;"
  550. v-model="refundFormData.permanentGold" />
  551. </div>
  552. <div style=" display: flex; align-items: center;justify-content: center; ">
  553. <span style="color: #999999; white-space: nowrap;">{{ t('common_add.freeGold') }}</span>
  554. <el-input style="padding-right: 10px; height: 30px; width: 70px;" v-model="refundFormData.freeGold" />
  555. </div>
  556. </div>
  557. <div class="add-item">
  558. <el-text style="width:4vw;">{{ t('common_add.refundReason') }}</el-text>
  559. <el-input v-model="refundFormData.refundReason" style="width:10vw;" :rows="5" maxlength="150"
  560. show-word-limit type="textarea" />
  561. </div>
  562. <div>{{ t('common_add.tip') }}</div>
  563. <div style="display:flex;justify-content: center;margin-top: 5vh;">
  564. <el-button type="default" @click="resetRefund">{{ t('common.reset') }}</el-button>
  565. <el-button type="primary" @click="throttledsubmitRefund">{{ t('common.submit') }}</el-button>
  566. </div>
  567. </div>
  568. </div>
  569. </el-dialog>
  570. </div>
  571. </template>
  572. <style scoped lang="scss">
  573. .cash-flow-container {
  574. display: flex;
  575. flex-direction: column;
  576. height: 100%;
  577. }
  578. .search-card {
  579. margin-bottom: 10px;
  580. background: #F3FAFE; // 浅蓝背景
  581. border: none;
  582. :deep(.el-card__body) {
  583. padding: 15px;
  584. }
  585. }
  586. .search-bar {
  587. display: flex;
  588. flex-direction: column;
  589. gap: 15px;
  590. }
  591. .search-row {
  592. display: flex;
  593. flex-wrap: wrap;
  594. gap: 20px;
  595. align-items: center;
  596. }
  597. .search-item {
  598. display: flex;
  599. align-items: center;
  600. .label {
  601. font-size: 15px; // 参考 coinConsumeDetail 的 .text size="large"
  602. color: #000; // 或 #606266
  603. white-space: nowrap;
  604. margin-right: 8px;
  605. min-width: 60px;
  606. text-align: right;
  607. }
  608. .el-input,
  609. .el-select {
  610. width: 200px;
  611. }
  612. }
  613. .search-btn-group {
  614. margin-left: 20px; // 靠右对齐
  615. display: flex;
  616. gap: 10px;
  617. }
  618. .table-card {
  619. background: #E7F4FD;
  620. flex: 1;
  621. border: none;
  622. display: flex;
  623. flex-direction: column;
  624. :deep(.el-card__body) {
  625. padding: 20px;
  626. flex: 1;
  627. display: flex;
  628. flex-direction: column;
  629. overflow: hidden;
  630. }
  631. }
  632. .pagination-container {
  633. margin-top: 15px;
  634. display: flex;
  635. justify-content: flex-start;
  636. }
  637. // 表格样式覆盖 (参考 coinConsumeDetail)
  638. :deep(.el-table__header-wrapper),
  639. :deep(.el-table__body-wrapper),
  640. :deep(.el-table__cell),
  641. :deep(.el-table__body td) {
  642. background-color: #F3FAFE !important;
  643. }
  644. :deep(.el-table__row:hover > .el-table__cell) {
  645. background-color: #E5EBFE !important;
  646. }
  647. .refundDialog {
  648. .left {
  649. width: 50%;
  650. height: 70vh;
  651. min-height: 700px;
  652. padding: 0 2vw;
  653. .add-item {
  654. display: flex;
  655. align-items: center;
  656. margin-bottom: 1vh;
  657. }
  658. .image {
  659. width: 4vw !important;
  660. height: 4vw !important;
  661. }
  662. }
  663. .right {
  664. width: 50%;
  665. height: 50vh;
  666. .add-item {
  667. display: flex;
  668. align-items: center;
  669. margin-bottom: 1vh;
  670. }
  671. }
  672. }
  673. .recallDialog {
  674. //撤回弹窗提示
  675. height: 392px;
  676. width: 700px;
  677. background-image: url('/src/assets/receive-recall.png');
  678. position: fixed; // 固定定位,相对于浏览器窗口
  679. top: 50%; // 距离顶部50%
  680. left: 50%; // 距离左侧50%
  681. transform: translate(-50%, -50%); // 向左、向上平移自身宽高的50%,实现居中
  682. z-index: 1000; // 确保在其他元素上层显示
  683. .close {
  684. position: absolute;
  685. left: 625px;
  686. top: 20px;
  687. height: 38px;
  688. width: 38px;
  689. opacity: 0;
  690. .Btn {
  691. height: 100%;
  692. width: 100%;
  693. border-radius: 10px;
  694. }
  695. }
  696. .text {
  697. position: absolute;
  698. left: 185px;
  699. top: 190px;
  700. height: 67px;
  701. width: 500px;
  702. .txt {
  703. height: 100%;
  704. width: 100%;
  705. color: #001a42;
  706. font-family: "PingFang SC";
  707. font-size: 38px;
  708. font-style: normal;
  709. font-weight: 900;
  710. line-height: normal;
  711. }
  712. }
  713. .cancle {
  714. position: absolute;
  715. left: 185px;
  716. top: 304px;
  717. height: 55px;
  718. width: 150px;
  719. opacity: 0;
  720. .Btn {
  721. height: 100%;
  722. width: 100%;
  723. border-radius: 20px;
  724. }
  725. }
  726. .confirm {
  727. position: absolute;
  728. left: 375px;
  729. top: 304px;
  730. height: 55px;
  731. width: 150px;
  732. opacity: 0;
  733. .Btn {
  734. height: 100%;
  735. width: 100%;
  736. border-radius: 20px;
  737. }
  738. }
  739. }
  740. </style>