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.

440 lines
14 KiB

  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'
  9. const selectData = ref({
  10. jwcode: '',
  11. market: '',
  12. startTime: '',
  13. endTime: '',
  14. })
  15. const permanentBeans = ref(0)
  16. const beanNum = ref(0)
  17. const money = ref(0)
  18. //时间格式化
  19. const formatTime = (val) => val ? moment(val).format('YYYY-MM-DD HH:mm:ss') : ''
  20. const tableData = ref([])
  21. //存储所有的地区数据
  22. const market = ref([])
  23. const getTime = ref([])
  24. //记录当前选中时间按钮状态
  25. const activeTimeRange = ref('')
  26. const handleDatePickerChange = () => {
  27. activeTimeRange.value = ''
  28. }
  29. //获取当齐全条件的金豆总数
  30. const getTotalBeans = async () => {
  31. try {
  32. const result = await API({
  33. url: '/beanRecharge/statsSystemBean',
  34. data: {
  35. ...selectData.value,
  36. }
  37. })
  38. if (result.code == 200) {
  39. permanentBeans.value = result.data.permanentBean
  40. beanNum.value = result.data.beanNum
  41. money.value = result.data.money
  42. console.log('金豆总数获取成功');
  43. }
  44. console.log('获取金豆总数失败:', result.msg);
  45. } catch (error) {
  46. console.log('获取金豆总数出错');
  47. }
  48. }
  49. //获取所有地区
  50. const getArea = async () => {
  51. const result = await API({
  52. url: '/beanRecharge/systemMarket',
  53. data: {}
  54. })
  55. if (result.code == 200) {
  56. market.value = result.data
  57. console.log('系统充值地区获取成功', market.value)
  58. } else {
  59. ElMessage.error('系统充值地区获取失败')
  60. }
  61. }
  62. //获取今天日期
  63. const getToday = () => {
  64. const today = new Date()
  65. const startTime = new Date(
  66. today.getFullYear(),
  67. today.getMonth(),
  68. today.getDate(),
  69. )
  70. const endTime = new Date(
  71. today.getFullYear(),
  72. today.getMonth(),
  73. today.getDate(),
  74. 23, 59, 59
  75. )
  76. getTime.value = [startTime, endTime]
  77. activeTimeRange.value = 'today'
  78. }
  79. const getYesterday = () => {
  80. const yesterday = new Date()
  81. yesterday.setDate(yesterday.getDate() - 1)
  82. const startTime = new Date(
  83. yesterday.getFullYear(),
  84. yesterday.getMonth(),
  85. yesterday.getDate()
  86. )
  87. const endTime = new Date(
  88. yesterday.getFullYear(),
  89. yesterday.getMonth(),
  90. yesterday.getDate(),
  91. 23, 59, 59
  92. )
  93. getTime.value = [startTime, endTime]
  94. activeTimeRange.value = 'yesterday'
  95. }
  96. const get7Days = function () {
  97. const today = new Date()
  98. const startTime = new Date(
  99. today.getFullYear(),
  100. today.getMonth(),
  101. today.getDate() - 6
  102. )
  103. const endTime = new Date(
  104. today.getFullYear(),
  105. today.getMonth(),
  106. today.getDate(),
  107. 23, 59, 59
  108. )
  109. getTime.value = [startTime, endTime]
  110. activeTimeRange.value = '7days'
  111. }
  112. const reset = () => {
  113. selectData.value = {
  114. jwcode: '',
  115. market: '',
  116. startTime: '',
  117. endTime: '',
  118. }
  119. getTime.value = []
  120. activeTimeRange.value = ''
  121. }
  122. //查询
  123. const search = () => {
  124. getObj.value.pageNum = 1
  125. get()
  126. getTotalBeans()
  127. }
  128. //获取表格数据
  129. const get = async () => {
  130. try {
  131. if (getTime.value != null) {
  132. selectData.value.startTime = formatTime(getTime.value[0])
  133. selectData.value.endTime = formatTime(getTime.value[1])
  134. } else {
  135. selectData.value.startTime = ''
  136. selectData.value.endTime = ''
  137. }
  138. const data = {
  139. ...getObj.value,
  140. "beanRechargeInfo": {
  141. ...selectData.value,
  142. sortField: sortField.value,
  143. sortOrder: sortOrder.value,
  144. },
  145. }
  146. console.log('请求参数:', data);
  147. const result = await API({
  148. url: '/beanRecharge/selectBySystem',
  149. data: data
  150. })
  151. if (result.code == 200) {
  152. tableData.value = result.data.list
  153. total.value = result.data.total
  154. } else {
  155. ElMessage.error(result.message)
  156. }
  157. } catch (error) {
  158. console.log('搜索失败', error);
  159. }
  160. }
  161. //排序字段
  162. //处理表格排序事件
  163. const sortField = ref('')
  164. const sortOrder = ref('')
  165. const handleSortChange = (column) => {
  166. console.log('排序字段:', column.prop)
  167. console.log('排序方式:', column.order)
  168. // 直接使用允许的排序字段列表进行过滤
  169. const allowedFields = ['money', 'freeBean', 'rechargeTime', 'createTime', 'permanentBean'];
  170. if (allowedFields.includes(column.prop)) {
  171. sortField.value = column.prop;
  172. }
  173. sortOrder.value = column.order === 'ascending' ? 'ASC' : 'DESC';
  174. console.log('传递给后端的排序字段:', sortField.value)
  175. console.log('传递给后端的排序方式:', sortOrder.value)
  176. get();
  177. }
  178. //========================分页===========================
  179. // 搜索对象
  180. const total = ref(0)
  181. const getObj = ref({
  182. pageNum: 1,
  183. pageSize: 20
  184. })
  185. const handlePageSizeChange = (value) => {
  186. getObj.value.pageSize = value
  187. get()
  188. }
  189. const handleCurrentChange = (value) => {
  190. getObj.value.pageNum = value
  191. get()
  192. }
  193. //======================导出=======================
  194. const exportExcel = async () => {
  195. const params = {
  196. ...getObj.value,
  197. "beanRechargeInfo": {
  198. ...selectData.value,
  199. sortField: sortField.value,
  200. sortOrder: sortOrder.value,
  201. },
  202. }
  203. try {
  204. const res = await API({ url: '/export', data: params })
  205. if (res.code === 200) {
  206. ElMessage.success('导出成功')
  207. } else {
  208. ElMessage.error(res.message || '导出失败,请稍后重试')
  209. }
  210. } catch (error) {
  211. console.log('请求失败', error)
  212. ElMessage.error('导出失败,请稍后重试')
  213. }
  214. }
  215. const exportListVisible = ref(false)
  216. // 打开导出列表弹窗
  217. const openExportList = () => {
  218. getExportList()
  219. exportListVisible.value = true
  220. }
  221. // 导出列表数据
  222. const exportList = ref([])
  223. // 导出列表加载状态
  224. const exportListLoading = ref(false)
  225. // 获取导出列表
  226. const getExportList = async () => {
  227. exportListLoading.value = true
  228. try {
  229. const result = await API({url: '/export/export'})
  230. if (result.code === 200) {
  231. // const filteredData = result.data.filter(item => {
  232. // return item.type === 2; //2表示金币充值列表
  233. // });
  234. // exportList.value = filteredData
  235. exportList.value = result.data
  236. } else {
  237. ElMessage.error(result.msg || '获取导出列表失败')
  238. }
  239. } catch (error) {
  240. console.error('获取导出列表出错:', error)
  241. ElMessage.error('获取导出列表失败,请稍后重试')
  242. } finally {
  243. exportListLoading.value = false
  244. }
  245. }
  246. // 下载导出文件
  247. const downloadExportFile = (item) => {
  248. if (item.state === 2) {
  249. const link = document.createElement('a')
  250. link.href = item.url
  251. link.download = item.fileName
  252. link.click()
  253. } else {
  254. ElMessage.warning('文件还在导出中,请稍后再试')
  255. }
  256. }
  257. //根据状态返回对应的标签类型
  258. const getTagType = (state) => {
  259. switch (state) {
  260. case 0:
  261. return 'info';
  262. case 1:
  263. return 'primary';
  264. case 2:
  265. return 'success';
  266. case 3:
  267. return 'danger';
  268. default:
  269. return 'info';
  270. }
  271. }
  272. //根据状态返回对应的标签文案
  273. const getTagText = (state) => {
  274. switch (state) {
  275. case 0:
  276. return '待执行';
  277. case 1:
  278. return '执行中';
  279. case 2:
  280. return '执行完成';
  281. case 3:
  282. return '执行出错';
  283. default:
  284. return '未知状态';
  285. }
  286. }
  287. onMounted(async function () {
  288. await get()
  289. await getArea()
  290. await getTotalBeans()
  291. })
  292. </script>
  293. <template>
  294. <el-row>
  295. <el-col>
  296. <el-card style="margin-bottom: 20px;margin-top: 10px">
  297. <el-row style="margin-bottom: 10px">
  298. <el-col :span="3">
  299. <div class="head-card-element">
  300. <el-text class="mx-1" size="large">精网号</el-text>
  301. <el-input v-model="selectData.jwcode" placeholder="请输入精网号" style="width: 115px" clearable />
  302. </div>
  303. </el-col>
  304. <el-col :span="4">
  305. <div class="head-card-element">
  306. <el-text class="mx-1" size="large">所属地区</el-text>
  307. <el-select v-model="selectData.market" placeholder="请选择所属地区" clearable style="width:150px">
  308. <el-option v-for="item in market" :key="item" :label="item" :value="item" />
  309. </el-select>
  310. </div>
  311. </el-col>
  312. <el-col :span="17">
  313. <div class="head-card-element">
  314. <el-text class="mx-1" size="large">充值时间</el-text>
  315. <el-date-picker v-model="getTime" type="datetimerange" range-separator=""
  316. start-placeholder="起始时间" end-placeholder="结束时间" style="width: 350px"
  317. @change="handleDatePickerChange" />
  318. <el-button @click="getToday()" style="margin-left: 10px"
  319. :type="activeTimeRange === 'today' ? 'primary' : ''">
  320. </el-button>
  321. <el-button @click="getYesterday()" style="margin-left: 10px"
  322. :type="activeTimeRange === 'yesterday' ? 'primary' : ''">
  323. </el-button>
  324. <el-button @click="get7Days()" style="margin-left: 10px"
  325. :type="activeTimeRange === '7days' ? 'primary' : ''"> 近7天
  326. </el-button>
  327. <el-button type="success" @click="reset()">重置</el-button>
  328. <el-button type="primary" @click="search()">查询</el-button>
  329. <el-button type="primary" style="width: 80px;" @click="exportExcel()">导出Excel</el-button>
  330. <el-button type="primary" style="width: 95px;" @click="openExportList">查看导出列表</el-button>
  331. </div>
  332. </el-col>
  333. </el-row>
  334. <el-row>
  335. </el-row>
  336. </el-card>
  337. </el-col>
  338. </el-row>
  339. <el-row>
  340. <el-col>
  341. <el-card>
  342. <div class="bean-info">
  343. <!-- 汉字用 <strong> 加粗动态数据用 <span> 包一层单独改色 -->
  344. <strong>金豆总数</strong><span class="data-text">{{ beanNum }}</span>
  345. <strong>, 充值金豆数</strong><span class="data-text">{{ permanentBeans }}</span>
  346. <strong>, 合计新币数</strong><span class="data-text">{{ money }}</span>
  347. </div>
  348. <!-- 设置表格容器的高度和滚动样式 -->
  349. <div style="height: 520px; overflow-y: auto;margin-top: 10px;">
  350. <el-table :data="tableData" style="width: 100%" height="520px" @sort-change="handleSortChange">
  351. <el-table-column type="id" prop="id" label="ID" min-width="80px" fixed="left"></el-table-column>
  352. <el-table-column fixed="left" prop="name" label="姓名" min-width="100" />
  353. <el-table-column fixed="left" prop="jwcode" label="精网号" min-width="110px" />
  354. <el-table-column prop="market" label="所属地区" min-width="100px" />
  355. <el-table-column prop="permanentBean" label="永久金豆" sortable="custom" min-width="110px" />
  356. <el-table-column prop="freeBean" label="免费金豆" sortable="custom" min-width="110px" />
  357. <el-table-column prop="remark" label="备注" min-width="150px" show-overflow-tooltip />
  358. <el-table-column prop="rechargeTime" label="充值时间" min-width="200px">
  359. <template #default="scope">
  360. {{ moment(scope.row.rechargeTime).format('YYYY-MM-DD HH:mm:ss') }}
  361. </template>
  362. </el-table-column>
  363. </el-table>
  364. </div>
  365. <!-- 分页 -->
  366. <div class="pagination" style="margin-top: 20px">
  367. <el-pagination background :page-size="getObj.pageSize" :page-sizes="[5, 10, 20, 50, 100]"
  368. layout="total, sizes, prev, pager, next, jumper" :total="total"
  369. @size-change="handlePageSizeChange" @current-change="handleCurrentChange"></el-pagination>
  370. </div>
  371. </el-card>
  372. </el-col>
  373. </el-row>
  374. <!-- 导出弹窗 -->
  375. <el-dialog v-model="exportListVisible" title="导出列表" width="80%">
  376. <el-table :data="exportList" style="width: 100% ;height: 60vh;" :loading="exportListLoading">
  377. <el-table-column prop="fileName" label="文件名"/>
  378. <el-table-column prop="state" label="状态">
  379. <template #default="scope">
  380. <el-tag :type="getTagType(scope.row.state)"
  381. :effect="scope.row.state === 3 ? 'light' : 'plain'">
  382. {{ getTagText(scope.row.state) }}
  383. </el-tag>
  384. </template>
  385. </el-table-column>
  386. <el-table-column prop="createTime" label="创建时间">
  387. <template #default="scope">
  388. {{ moment(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
  389. </template>
  390. </el-table-column>
  391. <el-table-column label="操作">
  392. <template #default="scope">
  393. <el-button type="primary" size="small" @click="downloadExportFile(scope.row)"
  394. :disabled="scope.row.state !== 2">
  395. 下载
  396. </el-button>
  397. </template>
  398. </el-table-column>
  399. </el-table>
  400. <template #footer>
  401. <div class="dialog-footer">
  402. <el-button text @click="exportListVisible = false">关闭</el-button>
  403. </div>
  404. </template>
  405. </el-dialog>
  406. </template>
  407. <style scoped>
  408. .bean-info {
  409. background-color: #eaf5ff;
  410. padding: 12px 16px;
  411. border-radius: 6px;
  412. font-size: 16px;
  413. color: #333;
  414. }
  415. .bean-info strong {
  416. font-weight: 700;
  417. }
  418. .bean-info .data-text {
  419. color: #007bff;
  420. }
  421. </style>