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.

543 lines
15 KiB

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. <script setup>
  2. import { ref, onMounted, reactive, computed } from 'vue'
  3. import ElementPlus from 'element-plus'
  4. import { ElMessage, ElMessageBox } from 'element-plus'
  5. import { AiFillRead } from 'vue-icons-plus/ai'
  6. import axios from 'axios'
  7. import moment from 'moment'
  8. import API from '@/util/http.js'
  9. const defaultTime = [
  10. new Date(2000, 1, 1, 0, 0, 0),
  11. new Date(2000, 2, 1, 23, 59, 59),
  12. ]
  13. const selectData = ref({
  14. jwcode: '',
  15. market: '',
  16. startTime: '',
  17. endTime: '',
  18. })
  19. const permanentBeans = ref(0)
  20. const num = ref(0)
  21. const money = ref(0)
  22. //获取当齐全条件的金豆总数
  23. const getTotalBeans = async () => {
  24. try {
  25. const result = await API({
  26. url: '/beanRecharge/statsOnlineBean',
  27. data: {
  28. ...selectData.value,
  29. }
  30. })
  31. if (result.code == 200) {
  32. if (result.data) {
  33. permanentBeans.value = result.data.permanentBean
  34. num.value = result.data.num
  35. money.value = result.data.money
  36. } else {
  37. permanentBeans.value = 0
  38. num.value = 0
  39. money.value = 0
  40. }
  41. console.log('金豆总数获取成功');
  42. }
  43. console.log('获取金豆总数失败:', result.msg);
  44. } catch (error) {
  45. console.log('获取金豆总数出错');
  46. }
  47. }
  48. //时间格式化
  49. const formatTime = (val) => val ? moment(val).format('YYYY-MM-DD HH:mm:ss') : ''
  50. const tableData = ref([])
  51. //存储所有的地区数据
  52. const market = ref()
  53. const getTime = ref([])
  54. //记录当前选中时间按钮状态
  55. const activeTimeRange = ref('')
  56. const handleDatePickerChange = () => {
  57. activeTimeRange.value = ''
  58. console.log('当前选中时间范围', getTime.value);
  59. }
  60. //获取所有地区
  61. const getArea = async () => {
  62. const result = await API({
  63. url: '/beanRecharge/onlineMarket',
  64. data: {}
  65. })
  66. if (result.code == 200) {
  67. market.value = result.data
  68. console.log('线上充值地区获取成功', market.value)
  69. } else {
  70. ElMessage.error('线上充值地区获取失败')
  71. }
  72. }
  73. //获取今天日期
  74. const getToday = () => {
  75. const today = new Date()
  76. const startTime = new Date(
  77. today.getFullYear(),
  78. today.getMonth(),
  79. today.getDate(),
  80. )
  81. const endTime = new Date(
  82. today.getFullYear(),
  83. today.getMonth(),
  84. today.getDate(),
  85. 23, 59, 59
  86. )
  87. getTime.value = [startTime, endTime]
  88. activeTimeRange.value = 'today'
  89. search();
  90. }
  91. const getYesterday = () => {
  92. const yesterday = new Date()
  93. yesterday.setDate(yesterday.getDate() - 1)
  94. const startTime = new Date(
  95. yesterday.getFullYear(),
  96. yesterday.getMonth(),
  97. yesterday.getDate()
  98. )
  99. const endTime = new Date(
  100. yesterday.getFullYear(),
  101. yesterday.getMonth(),
  102. yesterday.getDate(),
  103. 23, 59, 59
  104. )
  105. getTime.value = [startTime, endTime]
  106. activeTimeRange.value = 'yesterday'
  107. search();
  108. }
  109. const get7Days = function () {
  110. const today = new Date()
  111. const startTime = new Date(
  112. today.getFullYear(),
  113. today.getMonth(),
  114. today.getDate() - 6
  115. )
  116. const endTime = new Date(
  117. today.getFullYear(),
  118. today.getMonth(),
  119. today.getDate(),
  120. 23, 59, 59
  121. )
  122. getTime.value = [startTime, endTime]
  123. activeTimeRange.value = '7days'
  124. search();
  125. }
  126. const reset = () => {
  127. selectData.value = {
  128. jwcode: '',
  129. market: '',
  130. startTime: '',
  131. endTime: '',
  132. }
  133. getTime.value = []
  134. activeTimeRange.value = ''
  135. search()
  136. }
  137. //查询
  138. const search = () => {
  139. getObj.value.pageNum = 1
  140. //判断精网号查询是否为数字
  141. getObj.value.pageNum = 1
  142. if (selectData.value.jwcode) {
  143. const numRef = /^\d{1,9}$/;
  144. if (!numRef.test(selectData.value.jwcode)) {
  145. ElMessage.error('请检查精网号格式')
  146. return
  147. }
  148. }
  149. get()
  150. getTotalBeans()
  151. }
  152. //获取表格数据
  153. const get = async () => {
  154. try {
  155. if (getTime.value != null) {
  156. selectData.value.startTime = formatTime(getTime.value[0])
  157. selectData.value.endTime = formatTime(getTime.value[1])
  158. } else {
  159. selectData.value.startTime = ''
  160. selectData.value.endTime = ''
  161. }
  162. const data = {
  163. ...getObj.value,
  164. beanOnlineRechargeInfo: {
  165. ...selectData.value,
  166. sortField: sortField.value,
  167. sortOrder: sortOrder.value,
  168. },
  169. }
  170. console.log('请求参数:', data);
  171. const result = await API({
  172. url: '/beanRecharge/selectByOnline',
  173. data: data
  174. })
  175. if (result.code == 200) {
  176. tableData.value = result.data.list
  177. total.value = result.data.total
  178. } else {
  179. ElMessage.error(result.message)
  180. }
  181. } catch (error) {
  182. console.log('搜索失败', error);
  183. }
  184. }
  185. //充值平台
  186. const platform = [
  187. {
  188. value: 1,
  189. label: 'PC'
  190. },
  191. {
  192. value: 2,
  193. label: '手机'
  194. }
  195. ]
  196. //排序字段
  197. //处理表格排序事件
  198. const sortField = ref('')
  199. const sortOrder = ref('')
  200. const handleSortChange = (column) => {
  201. console.log('排序字段:', column.prop)
  202. console.log('排序方式:', column.order)
  203. // 直接使用允许的排序字段列表进行过滤
  204. const allowedFields = ['money', 'num'];
  205. if (allowedFields.includes(column.prop)) {
  206. sortField.value = column.prop;
  207. }
  208. sortOrder.value = column.order === 'ascending' ? 'ASC' : 'DESC';
  209. console.log('传递给后端的排序字段:', sortField.value)
  210. console.log('传递给后端的排序方式:', sortOrder.value)
  211. get();
  212. }
  213. //========================分页===========================
  214. // 搜索对象
  215. const total = ref(0)
  216. const getObj = ref({
  217. pageNum: 1,
  218. pageSize: 50
  219. })
  220. const handlePageSizeChange = (value) => {
  221. getObj.value.pageSize = value
  222. get()
  223. }
  224. const handleCurrentChange = (value) => {
  225. getObj.value.pageNum = value
  226. get()
  227. }
  228. //======================导出=======================
  229. const exportExcel = async () => {
  230. const params = {
  231. ...getObj.value,
  232. beanOnlineRechargeInfo: {
  233. ...selectData.value,
  234. sortField: sortField.value,
  235. sortOrder: sortOrder.value,
  236. },
  237. }
  238. try {
  239. const res = await API({ url: '/export/exportol', data: params })
  240. if (res.code === 200) {
  241. ElMessage.success('导出成功')
  242. } else {
  243. ElMessage.error(res.message || '导出失败,请稍后重试')
  244. }
  245. } catch (error) {
  246. console.log('请求失败', error)
  247. ElMessage.error('导出失败,请稍后重试')
  248. }
  249. }
  250. const exportListVisible = ref(false)
  251. // 打开导出列表弹窗
  252. const openExportList = () => {
  253. getExportList()
  254. exportListVisible.value = true
  255. }
  256. // 导出列表数据
  257. const exportList = ref([])
  258. // 导出列表加载状态
  259. const exportListLoading = ref(false)
  260. // 获取导出列表
  261. const getExportList = async () => {
  262. exportListLoading.value = true
  263. try {
  264. const result = await API({ url: '/export/export' })
  265. if (result.code === 200) {
  266. const filteredData = result.data.filter(item => {
  267. return item.type === 10;
  268. });
  269. exportList.value = filteredData
  270. } else {
  271. ElMessage.error(result.msg || '获取导出列表失败')
  272. }
  273. } catch (error) {
  274. console.error('获取导出列表出错:', error)
  275. ElMessage.error('获取导出列表失败,请稍后重试')
  276. } finally {
  277. exportListLoading.value = false
  278. }
  279. }
  280. // 下载导出文件
  281. const downloadExportFile = (item) => {
  282. if (item.state === 2) {
  283. const link = document.createElement('a')
  284. link.href = item.url
  285. link.download = item.fileName
  286. link.click()
  287. } else {
  288. ElMessage.warning('文件还在导出中,请稍后再试')
  289. }
  290. }
  291. //根据状态返回对应的标签类型
  292. const getTagType = (state) => {
  293. switch (state) {
  294. case 0:
  295. return 'info';
  296. case 1:
  297. return 'primary';
  298. case 2:
  299. return 'success';
  300. case 3:
  301. return 'danger';
  302. default:
  303. return 'info';
  304. }
  305. }
  306. //根据状态返回对应的标签文案
  307. const getTagText = (state) => {
  308. switch (state) {
  309. case 0:
  310. return '待执行';
  311. case 1:
  312. return '执行中';
  313. case 2:
  314. return '执行完成';
  315. case 3:
  316. return '执行出错';
  317. default:
  318. return '未知状态';
  319. }
  320. }
  321. const format3 = (num) => {
  322. // 每三位添加逗号
  323. return num.toLocaleString('en-US')
  324. }
  325. onMounted(async function () {
  326. await get()
  327. await getArea()
  328. await getTotalBeans()
  329. })
  330. </script>
  331. <template>
  332. <el-card class="card1" style="margin-bottom: 0.5vh;">
  333. <el-col style="margin-bottom: 1vh">
  334. <div class="select">
  335. <div class="selectRow">
  336. <el-text class="text" size="large">精网号</el-text>
  337. <el-input class="selectContent" v-model="selectData.jwcode" placeholder="请输入精网号" clearable />
  338. </div>
  339. <div class="selectRow">
  340. <el-text class="text" size="large">所属地区</el-text>
  341. <el-select class="selectContent" v-model="selectData.market" placeholder="请选择所属地区" clearable>
  342. <el-option v-for="item in market" :key="item" :label="item" :value="item" />
  343. </el-select>
  344. </div>
  345. <div class="selectRow" style="width: 15vw;">
  346. <el-text class="text" size="large">订单号</el-text>
  347. <el-input class="selectContent" v-model="selectData.orderNo" placeholder="请输入订单" clearable />
  348. </div>
  349. <div class="selectRow" style="width: 15vw;">
  350. <el-text class="text" size="large">充值平台</el-text>
  351. <el-select class="selectContent" v-model="selectData.platform" placeholder="请选择充值平台" clearable>
  352. <el-option v-for="item in platform" :key="item.value" :label="item.label" :value="item.value" />
  353. </el-select>
  354. </div>
  355. </div>
  356. </el-col>
  357. <el-col>
  358. <div class="select">
  359. <div class="selectRow" style="width: 36vw;">
  360. <el-text class="text" size="large">充值时间</el-text>
  361. <el-date-picker class="selectContent" v-model="getTime" type="datetimerange" range-separator=""
  362. start-placeholder="起始时间" end-placeholder="结束时间" style="margin-right:1vw;width:25vw"
  363. @change="handleDatePickerChange" :default-time="defaultTime" />
  364. <div v-if="false">
  365. <el-button @click="getToday()" style="margin-left: 10px"
  366. :type="activeTimeRange === 'today' ? 'primary' : ''">
  367. </el-button>
  368. <el-button @click="getYesterday()" style="margin-left: 10px"
  369. :type="activeTimeRange === 'yesterday' ? 'primary' : ''">
  370. </el-button>
  371. <el-button @click="get7Days()" style="margin-left: 10px"
  372. :type="activeTimeRange === '7days' ? 'primary' : ''">
  373. 近7天
  374. </el-button>
  375. </div>
  376. </div>
  377. <div class="selectRow" style="justify-content: flex-start;">
  378. <el-button type="primary" @click="search()">查询</el-button>
  379. <el-button type="primary" @click="exportExcel()">导出Excel</el-button>
  380. <el-button type="primary" @click="openExportList">查看导出列表</el-button>
  381. <el-button type="success" @click="reset()">重置</el-button>
  382. </div>
  383. </div>
  384. </el-col>
  385. </el-card>
  386. <el-card class="card2">
  387. <div class="goldStatistics">
  388. 充值金豆数{{ format3(num) }}&nbsp;&nbsp;&nbsp;&nbsp;合计新币数{{ format3(money) }}
  389. </div>
  390. <!-- 设置表格容器的高度和滚动样式 -->
  391. <div>
  392. <el-table :data="tableData" style="width:80vw;" height="60vh" @sort-change="handleSortChange"
  393. :row-style="{ height: '50px' }">
  394. <el-table-column type="index" label="序号" width="80px" fixed="left">
  395. <template #default="scope">
  396. <span>{{
  397. scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
  398. }}</span>
  399. </template>
  400. </el-table-column>
  401. <el-table-column fixed="left" prop="name" label="姓名" min-width="120" show-overflow-tooltip />
  402. <el-table-column fixed="left" prop="jwcode" label="精网号" min-width="110px" />
  403. <el-table-column prop="market" label="所属地区" min-width="100px" />
  404. <el-table-column prop="orderNo" header-align="center" align="center" label="订单号" min-width="210px" />
  405. <el-table-column prop="num" label="数量" sortable="custom" min-width="110px" />
  406. <el-table-column prop="money" label="金额" sortable="custom" min-width="150px" />
  407. <el-table-column prop="platform" label="充值平台" min-width="150px" show-overflow-tooltip>
  408. <template #default=scope>
  409. <span v-if="scope.row.platform == 1">PC</span>
  410. <span v-else-if="scope.row.platform == 2">手机</span>
  411. <span v-else>其他</span>
  412. </template>
  413. </el-table-column>
  414. <el-table-column prop="rechargeTime" label="充值时间" min-width="200px">
  415. <template #default="scope">
  416. {{ moment(scope.row.rechargeTime).format('YYYY-MM-DD HH:mm:ss') }}
  417. </template>
  418. </el-table-column>
  419. </el-table>
  420. </div>
  421. <!-- 分页 -->
  422. <div class="pagination" style="margin-top: 20px">
  423. <el-pagination background :page-size="getObj.pageSize" :page-sizes="[5, 10, 20, 50, 100]"
  424. layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handlePageSizeChange"
  425. @current-change="handleCurrentChange"></el-pagination>
  426. </div>
  427. </el-card>
  428. <!-- 导出弹窗 -->
  429. <el-dialog v-model="exportListVisible" title="导出列表" width="80vw" class="custom-height-dialog">
  430. <el-table :data="exportList" style="width:80vw;height: 60vh;" :loading="exportListLoading">
  431. <el-table-column prop="fileName" label="文件名" />
  432. <el-table-column prop="state" label="状态">
  433. <template #default="scope">
  434. <el-tag :type="getTagType(scope.row.state)" :effect="scope.row.state === 3 ? 'light' : 'plain'">
  435. {{ getTagText(scope.row.state) }}
  436. </el-tag>
  437. </template>
  438. </el-table-column>
  439. <el-table-column prop="createTime" label="创建时间">
  440. <template #default="scope">
  441. {{ moment(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
  442. </template>
  443. </el-table-column>
  444. <el-table-column label="操作">
  445. <template #default="scope">
  446. <el-button type="primary" size="small" @click="downloadExportFile(scope.row)"
  447. :disabled="scope.row.state !== 2">
  448. 下载
  449. </el-button>
  450. </template>
  451. </el-table-column>
  452. </el-table>
  453. <template #footer>
  454. <div class="dialog-footer">
  455. <el-button text @click="exportListVisible = false">关闭</el-button>
  456. </div>
  457. </template>
  458. </el-dialog>
  459. </template>
  460. <style scoped lang="scss">
  461. // 搜索的卡片样式
  462. .card1 {
  463. background: #F3FAFE;
  464. }
  465. // 表单的卡片样式
  466. .card2 {
  467. background: #E7F4FD;
  468. }
  469. // 新币总数等等
  470. .goldStatistics {
  471. margin-left: 1vw;
  472. margin-bottom: 1vh;
  473. color: #000000;
  474. font-family: "PingFang SC";
  475. font-size: 16px;
  476. font-style: normal;
  477. font-weight: 700;
  478. line-height: 20px;
  479. }
  480. // 表头背景等
  481. :deep(.el-table__header-wrapper),
  482. :deep(.el-table__body-wrapper),
  483. :deep(.el-table__cell),
  484. /* 表格 */
  485. :deep(.el-table__body td) {
  486. background-color: #F3FAFE !important;
  487. }
  488. /* 表头 */
  489. :deep(.el-table__header th) {
  490. background-color: #F3FAFE !important;
  491. }
  492. /* 鼠标悬停 */
  493. :deep(.el-table__row:hover > .el-table__cell) {
  494. background-color: #E5EBFE !important;
  495. }
  496. /** 搜索的样式 */
  497. .select {
  498. display: flex;
  499. .selectRow {
  500. width: 17vw;
  501. display: flex;
  502. align-items: center;
  503. justify-content: center;
  504. padding: 0 0.5vw;
  505. .text {
  506. width: 5vw;
  507. font-size: 15px;
  508. }
  509. .selectContent {
  510. flex: 1;
  511. }
  512. }
  513. }
  514. </style>