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.

906 lines
28 KiB

2 weeks ago
  1. <script setup>
  2. // 这是客户钱包页面
  3. import { useAdminStore } from "@/store/index.js"
  4. import { storeToRefs } from "pinia"
  5. import { findMenuById, permissionMapping } from "@/utils/menuTreePermission.js"
  6. const adminStore = useAdminStore()
  7. const { adminData, menuTree, flag } = storeToRefs(adminStore)
  8. // 监听全局flag状态变化(员工数据的)
  9. watch(flag, (newFlag, oldFlag) => {
  10. // 当flag状态改变时,重新发送请求
  11. if (newFlag !== oldFlag) {
  12. console.log('员工数据flag状态改变,重新加载数据', newFlag)
  13. get()
  14. }
  15. })
  16. import { onMounted, ref, watch, nextTick } from 'vue'
  17. import { ElMessage } from 'element-plus'
  18. import moment from 'moment'
  19. import API from '@/util/http.js'
  20. import { reverseMarketMapping } from "@/utils/marketMap.js";
  21. // 国际化
  22. import { useI18n } from 'vue-i18n'
  23. const { t } = useI18n()
  24. // 变量
  25. const dialogVisible = ref(false)
  26. // 定义加载状态,获取地区数据
  27. const markets = ref([])
  28. // 充值明细表格
  29. // 替换你代码中的 tableData 初始化部分
  30. const tableData = ref([]);
  31. const walletMap = {
  32. 1: 'historyGold',
  33. 2: 'hkGold',
  34. 3: 'sgHcGold',
  35. 4: 'myGold',
  36. 5: 'sgGold',
  37. 6: 'caGold',
  38. 7: 'thHsGold',
  39. 8: 'thHaGold',
  40. 9: 'vnGold',
  41. 10: 'bjGold'
  42. };
  43. const propToWalletId = {
  44. historyGold: 1,
  45. hkGold: 2,
  46. sgHcGold: 3,
  47. myGold: 4,
  48. sgGold: 5,
  49. caGold: 6,
  50. thHsGold: 7,
  51. thHaGold: 8,
  52. vnGold: 9,
  53. bjGold: 10
  54. };
  55. const tableRef = ref(null)
  56. const scrollTableTop = () => {
  57. tableRef.value?.setScrollTop?.(0)
  58. }
  59. //客户消费记录
  60. const userInfo = ref({})
  61. // 搜索===========================================
  62. //分页总条目
  63. const total = ref(100)
  64. // 搜索对象时间
  65. const getTime = ref([])
  66. // 搜索User
  67. const selectData = ref({
  68. jwcode: '',
  69. markets: [],
  70. })
  71. // 不分页的搜索对象
  72. const getAllObj = ref({})
  73. // 搜索对象
  74. const getObj = ref({
  75. pageNum: 1,
  76. pageSize: 50
  77. })
  78. // 新增排序字段和排序方式
  79. const sortField = ref('')
  80. const sortOrder = ref('')
  81. const sortWalletId = ref('')
  82. // 方法
  83. // 搜索===========================================================================
  84. // 搜索方法
  85. const get = async function (val) {
  86. try {
  87. // 搜索参数页码赋值
  88. if (typeof val === 'number') {
  89. getObj.value.pageNum = val
  90. }
  91. if (selectData.value.jwcode) {
  92. // 纯数字
  93. const numberRegex = /^\d{1,9}$/;
  94. // 检查是否不是数字
  95. if (!numberRegex.test(selectData.value.jwcode)) {
  96. ElMessage.error(t('elmessage.checkJwcodeFormat'))
  97. return
  98. }
  99. }
  100. console.log('搜索参数', getObj.value, selectData.value)
  101. // 构建请求参数
  102. const params = {
  103. pageNum: getObj.value.pageNum,
  104. pageSize: getObj.value.pageSize
  105. }
  106. // 只有当有值时才加入参数,且转换类型
  107. if (selectData.value.jwcode) {
  108. params.jwcode = Number(selectData.value.jwcode)
  109. }
  110. if (selectData.value.markets && selectData.value.markets.length > 0) {
  111. // 确保市场代码也是正确类型(根据示例是字符串)
  112. params.market = String(selectData.value.markets[0])
  113. }
  114. if (sortField.value) {
  115. params.sortField = sortField.value
  116. }
  117. if (sortOrder.value) {
  118. params.sortOrder = sortOrder.value
  119. }
  120. if (sortWalletId.value !== '') {
  121. params.sortWalletId = sortWalletId.value
  122. }
  123. console.log('最终请求参数', params)
  124. const result = await API({
  125. url: '/cashCollection/selectUserWallets',
  126. method: 'post',
  127. data: params
  128. })
  129. console.log('响应数据', result)
  130. if (result.code === 200) {
  131. tableData.value = result.data.list.map(item => {
  132. const row = {
  133. historyGold: 0,
  134. name: item.userName,
  135. jwcode: item.jwcode,
  136. market: item.marketName,
  137. hkGold: 0,
  138. sgHcGold: 0,
  139. myGold: 0,
  140. sgGold: 0,
  141. caGold: 0,
  142. thHsGold: 0,
  143. thHaGold: 0,
  144. vnGold: 0,
  145. bjGold: 0
  146. };
  147. if (item.walletList && Array.isArray(item.walletList)) {
  148. item.walletList.forEach(wallet => {
  149. const prop = walletMap[wallet.walletId];
  150. if (prop) {
  151. row[prop] = wallet.currentPermanentGold;
  152. }
  153. });
  154. }
  155. return row;
  156. });
  157. total.value = result.data.total;
  158. } else {
  159. ElMessage.error(result.msg || t('elmessage.getDataFailed'));
  160. }
  161. } catch (error) {
  162. console.log('请求失败', error)
  163. }
  164. }
  165. // 精网号去空格,同时处理 selectData 和 putExcel 中的 jwcode
  166. const trimJwCode = () => {
  167. if (selectData.value.jwcode) {
  168. selectData.value.jwcode = selectData.value.jwcode.replace(/\s/g, '');
  169. }
  170. }
  171. // 搜索
  172. const search = function () {
  173. trimJwCode();
  174. getObj.value.pageNum = 1
  175. get()
  176. }
  177. // 重置
  178. const reset = function () {
  179. selectData.value = {
  180. jwcode: '',
  181. markets: [],
  182. }
  183. sortField.value = ''
  184. sortOrder.value = ''
  185. sortWalletId.value = ''
  186. selectedMarketPath.value = []
  187. // 重置页码
  188. getObj.value.pageNum = 1
  189. get()
  190. }
  191. const cellClick = function (row, column) {
  192. console.log('cellClick', column)
  193. const walletId = propToWalletId[column.property];
  194. const propToMarketName = {
  195. historyGold: t('clientCount.market.historyGold'),
  196. hkGold: t('clientCount.market.hkGold'),
  197. sgHcGold: t('clientCount.market.sgHcGold'),
  198. myGold: t('clientCount.market.myGold'),
  199. sgGold: t('clientCount.market.sgCmGold'),
  200. caGold: t('clientCount.market.caGold'),
  201. thHsGold: t('clientCount.market.thHsGold'),
  202. thHaGold: t('clientCount.market.thHaGold'),
  203. vnGold: t('clientCount.market.vnGold'),
  204. bjGold: t('clientCount.market.bjGold')
  205. }
  206. const marketName = propToMarketName[column.property]
  207. if (marketName && walletId) {
  208. currentWalletInfo.value = {
  209. userName: row.name,
  210. jwcode: row.jwcode,
  211. marketName: row.market, // 用户所属地区
  212. walletName: marketName + t('clientCount.wallet'), // 钱包名称
  213. currentBalance: row[column.property] || 0,
  214. walletId: walletId
  215. }
  216. walletDetailQuery.value.pageNum = 1
  217. getWalletDetail()
  218. walletDetailVisible.value = true
  219. }
  220. }
  221. // 钱包明细弹窗相关
  222. const walletDetailVisible = ref(false)
  223. const walletDetailList = ref([])
  224. const walletDetailTotal = ref(0)
  225. const walletDetailLoading = ref(false)
  226. const currentWalletInfo = ref({})
  227. const walletDetailQuery = ref({
  228. pageNum: 1,
  229. pageSize: 20
  230. })
  231. const getWalletRecordTypeText = (item) => {
  232. const type = Number(item.type)
  233. if (type === 0) {
  234. return t('clientCount.recharge')
  235. }
  236. if (type === 1) {
  237. return t('clientCount.consume')
  238. }
  239. if (type === 2) {
  240. return t('clientCount.refund')
  241. }
  242. return item.typeText || t('clientCount.other')
  243. }
  244. const getWalletDetail = async () => {
  245. walletDetailLoading.value = true
  246. try {
  247. const params = {
  248. pageNum: walletDetailQuery.value.pageNum,
  249. pageSize: walletDetailQuery.value.pageSize,
  250. userWalletRecord: {
  251. jwcode: Number(currentWalletInfo.value.jwcode),
  252. walletId: currentWalletInfo.value.walletId
  253. }
  254. }
  255. const result = await API({
  256. url: '/cashCollection/selectWalletRecords',
  257. method: 'post',
  258. data: params
  259. })
  260. if (result.code === 200) {
  261. walletDetailList.value = result.data.list.map(item => ({
  262. time: moment(item.createTime).format('YYYY-MM-DD HH:mm:ss'),
  263. type: getWalletRecordTypeText(item),
  264. amount: Number(item.amount) || 0,
  265. desc: item.description || '',
  266. orderNo: item.orderCode,
  267. status: item.status === 0 ? 1 : 2
  268. }))
  269. walletDetailTotal.value = result.data.total
  270. } else {
  271. ElMessage.error(result.msg || t('elmessage.getDetailFailed'))
  272. }
  273. } catch (error) {
  274. console.error(error)
  275. } finally {
  276. walletDetailLoading.value = false
  277. }
  278. }
  279. const handleWalletDetailSizeChange = (val) => {
  280. walletDetailQuery.value.pageSize = val
  281. walletDetailQuery.value.pageNum = 1
  282. getWalletDetail()
  283. }
  284. const handleWalletDetailCurrentChange = (val) => {
  285. walletDetailQuery.value.pageNum = val
  286. getWalletDetail()
  287. }
  288. // 处理排序事件
  289. const handleSortChange = (column) => {
  290. console.log('排序字段:', column.prop)
  291. console.log('排序方式:', column.order)
  292. if (!column.prop || !column.order) {
  293. sortField.value = ''
  294. sortOrder.value = ''
  295. sortWalletId.value = ''
  296. getObj.value.pageNum = 1
  297. get()
  298. return
  299. }
  300. if (propToWalletId[column.prop]) {
  301. sortField.value = 'currentPermanentGold'
  302. sortWalletId.value = propToWalletId[column.prop]
  303. }
  304. sortOrder.value = column.order === 'ascending' ? 'ASC' : 'DESC'
  305. getObj.value.pageNum = 1
  306. get()
  307. }
  308. // 挂载
  309. onMounted(async function () {
  310. await get()
  311. await getMarket()
  312. await getExportList()
  313. })
  314. const handlePageSizeChange = function (val) {
  315. getObj.value.pageSize = val
  316. getObj.value.pageNum = 1
  317. get()
  318. }
  319. const handleCurrentChange = function (val) {
  320. getObj.value.pageNum = val
  321. get()
  322. }
  323. const exportExcel = async function () {
  324. const params = {
  325. pageNum: 1, // 导出通常从第一页开始
  326. pageSize: 10000, // 导出所有数据
  327. }
  328. // 只有当有值时才加入参数,且转换类型
  329. if (selectData.value.jwcode) {
  330. params.jwcode = Number(selectData.value.jwcode)
  331. }
  332. if (selectData.value.markets && selectData.value.markets.length > 0) {
  333. // 确保市场代码也是正确类型
  334. params.market = String(selectData.value.markets[0])
  335. }
  336. const res = await API({
  337. url: '/export/exportUserWallet',
  338. method: 'post',
  339. data: params
  340. })
  341. if (res.code === 200) {
  342. ElMessage.success(t('elmessage.exportSuccess'))
  343. // 不需要立即打开导出列表
  344. } else {
  345. ElMessage.error(res.msg || t('elmessage.exportFailed'))
  346. }
  347. }
  348. const exportWalletDetail = async () => {
  349. const params = {
  350. pageNum: walletDetailQuery.value.pageNum,
  351. pageSize: walletDetailQuery.value.pageSize,
  352. userWalletRecord: {
  353. jwcode: Number(currentWalletInfo.value.jwcode),
  354. walletId: currentWalletInfo.value.walletId
  355. }
  356. }
  357. try {
  358. const res = await API({
  359. url: '/export/exportUserWalletRecord',
  360. method: 'post',
  361. data: params
  362. })
  363. if (res.code === 200) {
  364. ElMessage.success(t('elmessage.exportSuccess'))
  365. } else {
  366. ElMessage.error(res.msg || t('elmessage.exportFailed'))
  367. }
  368. } catch (error) {
  369. console.error('导出钱包明细出错:', error)
  370. ElMessage.error(t('elmessage.exportWalletDetailError'))
  371. }
  372. }
  373. const selectWallet = async function () {
  374. selectWalletVisible.value = true
  375. }
  376. const exportExcelOnlyOne = async function () {
  377. if (!selectWalletForm.value.companyWalletId) {
  378. ElMessage.error(t('elmessage.selectCompanyWallet'))
  379. return
  380. }
  381. const params = {
  382. pageNum: 1, // 导出通常从第一页开始
  383. pageSize: 10000, // 导出大量数据,或者不传让后端处理全部?通常传大值
  384. userWalletRecord: {
  385. walletId: selectWalletForm.value.companyWalletId,
  386. jwcode: selectData.value.jwcode ? Number(selectData.value.jwcode) : null
  387. }
  388. }
  389. try {
  390. const res = await API({
  391. url: '/export/exportUserWalletRecord',
  392. method: 'post',
  393. data: params
  394. })
  395. if (res.code === 200) {
  396. ElMessage.success(t('elmessage.exportSuccess'))
  397. openExportList() // 导出成功后打开导出列表
  398. } else {
  399. ElMessage.error(res.msg || t('elmessage.exportFailed'))
  400. }
  401. } catch (error) {
  402. console.error('导出失败:', error)
  403. ElMessage.error(t('elmessage.exportFailed'))
  404. } finally {
  405. selectWalletVisible.value = false
  406. }
  407. }
  408. const exportListVisible = ref(false)
  409. const selectWalletVisible = ref(false)
  410. const selectWalletFormRef = ref(null)
  411. const selectWalletRules = {
  412. companyWalletId: [
  413. { required: true, message: t('common_list.companyWalletPlaceholder'), trigger: 'change' }
  414. ]
  415. }
  416. // 关闭选择公司钱包弹窗
  417. const closeSelectWallet = () => {
  418. // 重置表单
  419. selectWalletFormRef.value.resetFields()
  420. selectWalletForm.value = {}
  421. selectWalletVisible.value = false
  422. }
  423. const selectWalletForm = ref({})
  424. const companyWalletList = ref([
  425. {
  426. id: 2,
  427. name: t('clientCount.market.hkGold') + t('clientCount.wallet')
  428. },
  429. {
  430. id: 3,
  431. name: t('clientCount.market.sgHcGold')
  432. },
  433. {
  434. id: 4,
  435. name: t('clientCount.market.myGold')
  436. },
  437. {
  438. id: 5,
  439. name: t('clientCount.market.sgCmGold')
  440. },
  441. {
  442. id: 6,
  443. name: t('clientCount.market.caGold')
  444. },
  445. {
  446. id: 7,
  447. name: t('clientCount.market.thHsGold')
  448. },
  449. {
  450. id: 8,
  451. name: t('clientCount.market.thHaGold')
  452. },
  453. {
  454. id: 9,
  455. name: t('clientCount.market.vnGold')
  456. },
  457. {
  458. id: 10,
  459. name: t('clientCount.market.bjGold')
  460. }
  461. ])
  462. // 打开导出列表弹窗
  463. const openExportList = () => {
  464. getExportList()
  465. exportListVisible.value = true
  466. }
  467. // 导出列表数据
  468. const exportList = ref([])
  469. // 导出列表加载状态
  470. const exportListLoading = ref(false)
  471. // 获取导出列表
  472. const getExportList = async () => {
  473. exportListLoading.value = true
  474. try {
  475. const result = await API({ url: '/export/export' })
  476. if (result.code === 200) {
  477. // 过滤只显示type为16和17的导出记录
  478. const filteredData = result.data.filter(item => {
  479. return item.type === 16 || item.type === 17;
  480. });
  481. exportList.value = filteredData
  482. } else {
  483. ElMessage.error(result.msg || t('elmessage.getExportListError'))
  484. }
  485. } catch (error) {
  486. console.error('获取导出列表出错:', error)
  487. ElMessage.error(t('elmessage.getExportListError'))
  488. } finally {
  489. exportListLoading.value = false
  490. }
  491. }
  492. // 下载导出文件
  493. const downloadExportFile = (item) => {
  494. if (item.state === 2) {
  495. const link = document.createElement('a')
  496. link.href = item.url
  497. link.download = item.fileName
  498. link.click()
  499. } else {
  500. ElMessage.warning(t('elmessage.exportingInProgress'))
  501. }
  502. }
  503. //根据状态返回对应的标签类型
  504. const getTagType = (state) => {
  505. switch (state) {
  506. case 0:
  507. return 'info';
  508. case 1:
  509. return 'primary';
  510. case 2:
  511. return 'success';
  512. case 3:
  513. return 'danger';
  514. default:
  515. return 'info';
  516. }
  517. }
  518. //根据状态返回对应的标签文案
  519. const getTagText = (state) => {
  520. switch (state) {
  521. case 0:
  522. return t('elmessage.pendingExecution');
  523. case 1:
  524. return t('elmessage.executing');
  525. case 2:
  526. return t('elmessage.executed');
  527. case 3:
  528. return t('elmessage.errorExecution');
  529. default:
  530. return t('elmessage.unknownStatus');
  531. }
  532. }
  533. // 存储地区选择变化
  534. const selectedMarketPath = ref([])
  535. const handleMarketChange = (value) => {
  536. if (value && value.length > 0) {
  537. const lastValue = value[value.length - 1];
  538. // 确保返回值是数组,如果不是则包装成数组
  539. const marketValue = reverseMarketMapping[lastValue];
  540. selectData.value.markets = Array.isArray(marketValue) ? marketValue : [marketValue];
  541. } else {
  542. // 保持[]格式
  543. selectData.value.markets = [];
  544. }
  545. };
  546. // 获取地区,修改为级联下拉框
  547. const getMarket = async function () {
  548. try {
  549. // 发送POST请求
  550. const result = await API({
  551. url: '/market/selectMarket',
  552. });
  553. // 将响应结果存储到响应式数据中
  554. console.log('请求成功', result)
  555. // 递归转换树形结构为级联选择器需要的格式(跳过第一级节点)
  556. const transformTree = (nodes) => {
  557. // 直接处理第一级节点的子节点
  558. const allChildren = nodes.flatMap(node => node.children || []);
  559. return allChildren.map(child => {
  560. const grandchildren = child.children && child.children.length
  561. ? transformTree([child]) // 递归处理子节点
  562. : null;
  563. return {
  564. value: child.name,
  565. label: child.name,
  566. children: grandchildren
  567. };
  568. });
  569. };
  570. // 存储地区信息
  571. markets.value = transformTree(result.data)
  572. console.log('转换后的地区树==============', markets.value)
  573. } catch (error) {
  574. console.log('请求失败', error)
  575. }
  576. }
  577. const format3 = (num) => {
  578. // 每三位添加逗号
  579. return num.toLocaleString('en-US')
  580. }
  581. </script>
  582. <template>
  583. <el-card class="card1" style="margin-bottom: 1vh;">
  584. <div class="head-card">
  585. <div class="head-card-element">
  586. <el-text class="mx-1" size="large">{{ $t('common.jwcode') }}</el-text>
  587. <el-input v-model="selectData.jwcode" style="width: 160px" :placeholder="$t('common.jwcodePlaceholder')" clearable />
  588. </div>
  589. <div class="head-card-element">
  590. <el-text class="mx-1" size="large">{{ $t('common.market') }}</el-text>
  591. <el-cascader v-model="selectedMarketPath" :options="markets" :placeholder="$t('common.marketPlaceholder')" clearable style="width:180px"
  592. @change="handleMarketChange" />
  593. </div>
  594. <div class="head-card-element">
  595. <!-- <el-checkbox v-model="showEmployeeData" @change="search()">员工数据</el-checkbox> -->
  596. </div>
  597. <el-button type="primary" @click="search()">{{ $t('common.search') }}</el-button>
  598. <el-button @click="reset" type="success">{{ $t('common.reset') }}</el-button>
  599. <el-button type="primary" @click="exportExcel()">{{ $t('common.exportExcel') }}</el-button>
  600. <el-button type="primary" @click="selectWallet()">{{ $t('common.exportCompanyWalletDetail') }}</el-button>
  601. <el-button type="primary" @click="openExportList">{{ $t('common.viewExportList') }}</el-button>
  602. </div>
  603. <!-- </div> -->
  604. </el-card>
  605. <el-card class="card2">
  606. <!-- 设置表格容器的高度和滚动样式 -->
  607. <div style="height: 69vh; overflow-y: auto">
  608. <el-table ref="tableRef" :data="tableData" @cellClick="cellClick" style="width: 100%; height: 69vh"
  609. @sort-change="handleSortChange" :row-style="{ height: '50px' }">
  610. <el-table-column type="index" :label="$t('common_list.id')" width="100px" fixed="left">
  611. <template #default="scope">
  612. <span>{{
  613. scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
  614. }}</span>
  615. </template>
  616. </el-table-column>
  617. <el-table-column prop="name" :label="$t('common_list.name')" width="140" />
  618. <el-table-column prop="jwcode" :label="$t('common_list.jwcode')" width="140" />
  619. <el-table-column prop="market" :label="$t('common_list.market')" width="140" />
  620. <el-table-column prop="historyGold" :label="$t('clientCount.market.historyGold')" sortable="custom" min-width="140">
  621. <template #default="scope">
  622. <span>{{ (scope.row.historyGold || 0) }}</span>
  623. </template>
  624. </el-table-column>
  625. <el-table-column prop="hkGold" :label="$t('clientCount.market.hkGold')" sortable="custom" min-width="140">
  626. <template #default="scope">
  627. <span>{{ (scope.row.hkGold || 0) }}</span>
  628. </template>
  629. </el-table-column>
  630. <el-table-column prop="sgHcGold" :label="$t('clientCount.market.sgHcGold')" sortable="custom" min-width="150">
  631. <template #default="scope">
  632. <span>{{ (scope.row.sgHcGold || 0) }}</span>
  633. </template>
  634. </el-table-column>
  635. <el-table-column prop="myGold" :label="$t('clientCount.market.myGold')" sortable="custom" min-width="120">
  636. <template #default="scope">
  637. <span>{{ (scope.row.myGold || 0) }}</span>
  638. </template>
  639. </el-table-column>
  640. <el-table-column prop="sgGold" :label="$t('clientCount.market.sgCmGold')" sortable="custom" min-width="150">
  641. <template #default="scope">
  642. <span>{{ (scope.row.sgGold || 0) }}</span>
  643. </template>
  644. </el-table-column>
  645. <el-table-column prop="caGold" :label="$t('clientCount.market.caGold')" sortable="custom" min-width="120">
  646. <template #default="scope">
  647. <span>{{ (scope.row.caGold || 0) }}</span>
  648. </template>
  649. </el-table-column>
  650. <el-table-column prop="thHsGold" :label="$t('clientCount.market.thHsGold')" sortable="custom" min-width="140">
  651. <template #default="scope">
  652. <span>{{ (scope.row.thHsGold || 0) }}</span>
  653. </template>
  654. </el-table-column>
  655. <el-table-column prop="thHaGold" :label="$t('clientCount.market.thHaGold')" sortable="custom" min-width="140">
  656. <template #default="scope">
  657. <span>{{ (scope.row.thHaGold || 0) }}</span>
  658. </template>
  659. </el-table-column>
  660. <el-table-column prop="vnGold" :label="$t('clientCount.market.vnGold')" sortable="custom" min-width="120">
  661. <template #default="scope">
  662. <span>{{ (scope.row.vnGold || 0) }}</span>
  663. </template>
  664. </el-table-column>
  665. <el-table-column prop="bjGold" :label="$t('clientCount.market.bjGold')" sortable="custom" min-width="120">
  666. <template #default="scope">
  667. <span>{{ (scope.row.bjGold || 0) }}</span>
  668. </template>
  669. </el-table-column>
  670. </el-table>
  671. </div>
  672. <!-- 分页 -->
  673. <div class="pagination" style="margin-top: 20px">
  674. <el-pagination background :current-page="getObj.pageNum" :page-size="getObj.pageSize" :page-sizes="[5, 10, 20, 50, 100]"
  675. layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handlePageSizeChange"
  676. @current-change="handleCurrentChange"></el-pagination>
  677. </div>
  678. </el-card>
  679. <el-dialog v-model="exportListVisible" :title="$t('common_export.exportList')" width="80%">
  680. <el-table :data="exportList" style="width: 100% ;height: 60vh;" :loading="exportListLoading">
  681. <el-table-column prop="fileName" :label="$t('common_export.fileName')" />
  682. <el-table-column prop="state" :label="$t('common_export.status')">
  683. <template #default="scope">
  684. <el-tag :type="getTagType(scope.row.state)" :effect="scope.row.state === 3 ? 'light' : 'plain'">
  685. {{ getTagText(scope.row.state) }}
  686. </el-tag>
  687. </template>
  688. </el-table-column>
  689. <el-table-column prop="createTime" :label="$t('common_export.createTime')">
  690. <template #default="scope">
  691. {{ moment(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
  692. </template>
  693. </el-table-column>
  694. <el-table-column :label="$t('common_export.operation')">
  695. <template #default="scope">
  696. <el-button type="primary" size="small" @click="downloadExportFile(scope.row)"
  697. :disabled="scope.row.state !== 2">
  698. {{ $t('common_export.download') }}
  699. </el-button>
  700. </template>
  701. </el-table-column>
  702. </el-table>
  703. <template #footer>
  704. <div class="dialog-footer">
  705. <el-button text @click="exportListVisible = false">{{ $t('common_export.close') }}</el-button>
  706. </div>
  707. </template>
  708. </el-dialog>
  709. <el-dialog v-model="selectWalletVisible" width="30%" top="20%" :before-close="closeSelectWallet">
  710. <el-form :model="selectWalletForm" :rules="selectWalletRules" ref="selectWalletFormRef" label-width="120px">
  711. <el-form-item :label="$t('common_list.companyWallet')" prop="companyWalletId" style="margin-top: 30px;">
  712. <el-select v-model="selectWalletForm.companyWalletId" :placeholder="$t('common_list.companyWalletPlaceholder')" style="width: 80%;">
  713. <el-option v-for="item in companyWalletList" :key="item.id" :label="item.name" :value="item.id" />
  714. </el-select>
  715. </el-form-item>
  716. </el-form>
  717. <template #footer>
  718. <div style="display: flex; justify-content: flex-end;">
  719. <el-button type="primary" @click="exportExcelOnlyOne()">{{ $t('common.confirm') }}</el-button>
  720. </div>
  721. </template>
  722. </el-dialog>
  723. <el-dialog v-model="walletDetailVisible" width="70%" top="20vh">
  724. <template #header>
  725. <div class="wallet-detail-header" style="display: flex; gap: 40px; justify-content: space-between; align-items: center; font-size: 16px;">
  726. <span style="font-weight: bold; color: #F56C6C;">* {{ currentWalletInfo.walletName }}</span>
  727. <span><span style="color: #F56C6C;">*</span> {{ $t('clientCount.user') }}: {{ currentWalletInfo.userName }} (ID: {{ currentWalletInfo.jwcode }})</span>
  728. <span><span style="color: #F56C6C;">*</span> {{ $t('common.market') }}: {{ currentWalletInfo.marketName }}</span>
  729. </div>
  730. <div style="margin-top: 15px; font-size: 16px;">
  731. <span style="color: #F56C6C; font-weight: bold;">* {{ $t('clientCount.currentBalance') }}: {{ format3(currentWalletInfo.currentBalance || 0) }} {{ $t('common.goldCoin') }}</span>
  732. </div>
  733. </template>
  734. <el-table :data="walletDetailList" v-loading="walletDetailLoading" style="width: 100%; height: 50vh; overflow-y: auto;" border stripe>
  735. <el-table-column prop="time" :label="$t('clientCount.time')" align="center" width="180">
  736. <template #default="scope">{{ scope.row.time }}</template>
  737. </el-table-column>
  738. <el-table-column prop="type" :label="$t('clientCount.transactionType')" align="center" width="120" />
  739. <el-table-column prop="amount" :label="$t('common_list.money')" align="center" width="120">
  740. <template #default="scope">
  741. <span :style="{ color: scope.row.amount >= 0 ? '#67C23A' : '#F56C6C', fontWeight: 'bold' }">
  742. {{ scope.row.amount > 0 ? '+' + format3(scope.row.amount) : format3(scope.row.amount) }}
  743. </span>
  744. </template>
  745. </el-table-column>
  746. <el-table-column prop="desc" :label="$t('clientCount.transactionDesc')" align="center" />
  747. <el-table-column prop="orderNo" :label="$t('clientCount.transactionOrderNo')" align="center" width="220" />
  748. <el-table-column prop="status" :label="$t('clientCount.transactionStatus')" align="center" width="220" fixed="right">
  749. <template #default="scope">
  750. <el-tag :type="scope.row.status === 1 ? 'success' : scope.row.status === 2 ? 'danger' : 'info'" :effect="scope.row.status === 1 ? 'light' : 'plain'">
  751. {{ scope.row.status === 1 ? t('common_list.normal') : scope.row.status === 2 ? t('common_list.refunded') : t('clientCount.exceptionData') }}
  752. </el-tag>
  753. </template>
  754. </el-table-column>
  755. </el-table>
  756. <template #footer>
  757. <div class="dialog-footer" style="display: flex; justify-content: space-between; align-items: center;">
  758. <div class="pagination-container">
  759. <el-pagination
  760. background
  761. :current-page="walletDetailQuery.pageNum"
  762. :page-size="walletDetailQuery.pageSize"
  763. :page-sizes="[10, 20, 50, 100]"
  764. layout="total, sizes, prev, pager, next, jumper"
  765. :total="walletDetailTotal"
  766. @size-change="handleWalletDetailSizeChange"
  767. @current-change="handleWalletDetailCurrentChange"
  768. />
  769. </div>
  770. <div>
  771. <el-button type="primary" @click="exportWalletDetail">{{ $t('common.exportExcel') }}</el-button>
  772. <el-button text @click="walletDetailVisible = false">{{ $t('common_export.close') }}</el-button>
  773. </div>
  774. </div>
  775. </template>
  776. </el-dialog>
  777. </template>
  778. <style scoped lang="scss">
  779. // 搜索的卡片样式
  780. .card1 {
  781. background: #F3FAFE;
  782. }
  783. // 表单的卡片样式
  784. .card2 {
  785. background: #E7F4FD;
  786. flex: 1;
  787. display: flex;
  788. flex-direction: column;
  789. :deep(.el-card__body) {
  790. padding: 20px;
  791. flex: 1;
  792. display: flex;
  793. flex-direction: column;
  794. overflow: hidden;
  795. }
  796. }
  797. // 表头背景等
  798. :deep(.el-table__header-wrapper),
  799. :deep(.el-table__body-wrapper),
  800. :deep(.el-table__cell),
  801. /* 表格 */
  802. :deep(.el-table__body td) {
  803. background-color: #F3FAFE !important;
  804. }
  805. /* 表头 */
  806. :deep(.el-table__header th) {
  807. background-color: #F3FAFE !important;
  808. }
  809. /* 鼠标悬停 */
  810. :deep(.el-table__row:hover > .el-table__cell) {
  811. background-color: #E5EBFE !important;
  812. }
  813. .pagination {
  814. display: flex;
  815. }
  816. .status {
  817. display: flex;
  818. }
  819. .head-card {
  820. display: flex;
  821. }
  822. .head-card-element {
  823. margin-right: 20px;
  824. }
  825. .head-card-btn {
  826. margin-left: auto;
  827. }
  828. .custom-box {
  829. display: flex;
  830. flex-wrap: wrap;
  831. row-gap: 5px;
  832. div:nth-child(1) {
  833. flex: 1 0 100%;
  834. }
  835. div {
  836. margin-right: 20px;
  837. }
  838. }
  839. </style>