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.

479 lines
16 KiB

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