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.

857 lines
27 KiB

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