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.

545 lines
18 KiB

3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
  1. <script setup>
  2. // 这是客户金币余额页面
  3. import {ref, onMounted, reactive, computed, watch} from 'vue'
  4. import ElementPlus from 'element-plus'
  5. import { ElMessage, ElMessageBox } from 'element-plus'
  6. import axios from 'axios'
  7. import moment from 'moment'
  8. import { ta } from 'element-plus/es/locales.mjs'
  9. import API from '@/util/http'
  10. // 变量
  11. //这是获取用户信息的接口
  12. const adminData = ref({})
  13. const dialogVisible = ref(false)
  14. const getAdminData = async function () {
  15. try {
  16. const result = await API({ url: '/admin/userinfo', data: {} })
  17. adminData.value = result
  18. // console.log('请求成功', result)
  19. console.log('管理员用户信息', adminData.value)
  20. } catch (error) {
  21. console.log('请求失败', error)
  22. }
  23. }
  24. // 定义加载状态,获取地区数据
  25. const isLoadingmarket = ref(false);
  26. const market = ref([])
  27. const getmarket = async () => {
  28. isLoadingmarket.value = true;
  29. try {
  30. const result = await API({
  31. url: '/general/market'
  32. });
  33. console.log('获取地区数据成功', result)
  34. // 假设后端返回的是字符串数组,转换为 { value, label } 格式
  35. if (Array.isArray(result.data) && typeof result.data[0] === 'string') {
  36. market.value = result.data.map(item => ({ value: item, label: item }));
  37. } else {
  38. market.value = result.data;
  39. }
  40. } catch (error) {
  41. console.error('获取地区数据失败:', error);
  42. ElMessage.error('获取地区数据失败,请稍后重试');
  43. // 可以提供默认数据
  44. market.value = [];
  45. } finally {
  46. isLoadingmarket.value = false;
  47. }
  48. };
  49. // 充值明细表格
  50. const tableData = ref([])
  51. // 新增金币总数变量
  52. const goldtotal = ref(0)
  53. // 计算用户各金币总数的不分页对象
  54. const tableAllData = ref([])
  55. // 各金币字段
  56. const permanentGold = ref(0) // 修改为 currentPermanentGold 对应字段
  57. const freeJuneGold = ref(0) // 修改为 currentFreeJune 对应字段
  58. const freeDecemberGold = ref(0) // 修改为 currentFreeDecember 对应字段
  59. const taskGold = ref(0) // 修改为 currentTaskGold 对应字段
  60. const freeGold = ref(0) // 计算免费金币总数
  61. //客户消费记录
  62. const tableCountData = ref([])
  63. const userInfo = ref({})
  64. // 搜索===========================================
  65. //分页总条目
  66. const total = ref(100)
  67. // 搜索对象时间
  68. const getTime = ref([])
  69. // 搜索User
  70. const user = ref({})
  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. // 方法
  82. // 搜索===========================================================================
  83. // 搜索方法
  84. const get = async function (val) {
  85. try {
  86. // 搜索参数页码赋值
  87. if (typeof val === 'number') {
  88. getObj.value.pageNum = val
  89. }
  90. // 添加排序字段和排序方式到请求参数
  91. user.value.sortField = sortField.value
  92. user.value.sortOrder = sortOrder.value
  93. console.log('搜索参数', getObj.value)
  94. // 发送POST请求
  95. const requestData = { ...getObj.value, user: { ...user.value } };//控制台打印请求的参数
  96. console.log('最终请求参数', JSON.stringify(requestData, null, 2)); // 打印格式化后的请求参数
  97. //console.log('请求参数', requestData);
  98. const result = await API({
  99. url: '/goldDetail/getGold',
  100. method: 'post',
  101. data: { ...getObj.value, user: { ...user.value } }
  102. })
  103. console.log('响应数据', result)
  104. tableData.value = result.data.list
  105. total.value = result.data.total
  106. console.log('兄弟你是什么 user', user.value)
  107. // 获取合计数
  108. const resultGoldTotal = await API({
  109. url: '/goldDetail/goldTotal',
  110. data: {
  111. jwcode: user.value.jwcode,
  112. markets: user.value.markets
  113. }
  114. })
  115. // 判断精网号是否存在,假设精网号不存在时 result.data.list 为空数组
  116. if (result.data.list.length === 0) {
  117. // 将表格数据设置为空数组
  118. tableData.value = []
  119. // 将合计数设置为 0
  120. permanentGold.value = 0
  121. freeJuneGold.value = 0
  122. freeDecemberGold.value = 0
  123. taskGold.value = 0
  124. goldtotal.value = 0
  125. // // 新增金币总数变量
  126. // const goldtotal = ref(0)
  127. // 分页总数设置为 0
  128. total.value = 0
  129. // ElMessage.warning('精网号不存在,请检查输入')
  130. } else {
  131. // 将响应结果存储到响应式数据中
  132. console.log('总数据请求成功', result)
  133. // 存储表格数据
  134. tableData.value = result.data.list
  135. console.log('tableData', tableData.value)
  136. // 从接口返回数据中获取各金币数值
  137. if (resultGoldTotal.data) {
  138. permanentGold.value = parseFloat(resultGoldTotal.data.permanentGold.toFixed(2))
  139. freeGold.value = parseFloat(resultGoldTotal.data.freeGold.toFixed(2))
  140. taskGold.value = parseFloat(resultGoldTotal.data.taskGold.toFixed(2))
  141. goldtotal.value = parseFloat(resultGoldTotal.data.goldtotal.toFixed(2))
  142. } else {
  143. console.error('合计数数据格式错误', resultGoldTotal)
  144. ElMessage.error('获取合计数失败,请稍后重试')
  145. }
  146. // 存储分页总数
  147. total.value = result.data.total
  148. console.log('total', total.value)
  149. }
  150. } catch (error) {
  151. console.log('请求失败', error)
  152. // 在这里可以处理错误逻辑,比如显示错误提示等
  153. }
  154. }
  155. // 精网号去空格,同时处理 user 和 putExcel 中的 jwcode
  156. const trimJwCode = () => {
  157. if (user.value.jwcode) {
  158. user.value.jwcode = user.value.jwcode.replace(/\s/g, '');
  159. }
  160. }
  161. // 搜索
  162. const search = function () {
  163. trimJwCode();
  164. getObj.value.pageNum = 1
  165. get()
  166. }
  167. // 重置
  168. const reset = function () {
  169. user.value = {}
  170. sortField.value = ''
  171. sortOrder.value = ''
  172. get()
  173. }
  174. const cellClick = function (row, column) {
  175. console.log('cellClick', column.label)
  176. if (column.label === '姓名') {
  177. dialogVisible.value = true
  178. userInfo.value = row
  179. }
  180. }
  181. // 处理排序事件
  182. const handleSortChange = (column) => {
  183. console.log('排序字段:', column.prop)
  184. console.log('排序方式:', column.order)
  185. if (column.prop === 'currentPermanentGold') {
  186. sortField.value = 'current_permanent_gold'
  187. } else if (column.prop === 'currentTaskGold') {
  188. sortField.value = 'current_task_gold'
  189. } else if (column.prop === 'currentFreeJune') {
  190. sortField.value = 'current_free_june'
  191. } else if (column.prop === 'currentFreeDecember') {
  192. sortField.value = 'current_free_december'
  193. }
  194. sortOrder.value = column.order === 'ascending' ? 'ASC' : 'DESC'
  195. get()
  196. }
  197. const handleMarketChange = (val) => {
  198. if (!Array.isArray(val)) return
  199. const hasHeadquarters = val.includes('总部')
  200. const hasOther = val.some(item => item !== '总部')
  201. if (hasHeadquarters && hasOther) {
  202. if (val[val.length - 1] === '总部') {
  203. // 用户最后点的是总部,保留总部,清除其他
  204. user.value.markets = ['总部']
  205. ElMessage.warning('“总部”与其他地区不可同时选择,系统已为您保留“总部”')
  206. } else {
  207. // 用户最后点的是其他,保留其他,移除总部
  208. user.value.markets = val.filter(item => item !== '总部')
  209. ElMessage.warning('“总部”与其他地区不可同时选择,系统已为您去除“总部”')
  210. }
  211. }
  212. }
  213. // 挂载
  214. onMounted(async function () {
  215. await getAdminData()
  216. await get()
  217. await getmarket()
  218. await getExportList()
  219. })
  220. const handlePageSizeChange = function (val) {
  221. getObj.value.pageSize = val
  222. get()
  223. }
  224. const handleCurrentChange = function (val) {
  225. getObj.value.pageNum = val
  226. get()
  227. }
  228. const exportExcel = async function () {
  229. const params = {
  230. user:{
  231. jwcode: user.value.jwcode || '',
  232. markets: user.value.markets ||[]
  233. }
  234. }
  235. const res = await API({ url: '/goldDetail/exportGold', data: params })
  236. if (res.code === 200) {
  237. ElMessage.success('导出成功')
  238. }
  239. }
  240. const exportListVisible = ref(false)
  241. // 打开导出列表弹窗
  242. const openExportList = () => {
  243. getExportList()
  244. exportListVisible.value = true
  245. }
  246. // 导出列表数据
  247. const exportList = ref([])
  248. // 导出列表加载状态
  249. const exportListLoading = ref(false)
  250. // 获取导出列表
  251. const getExportList = async () => {
  252. exportListLoading.value = true
  253. try {
  254. const result = await API({ url: '/export/export' })
  255. if (result.code === 200) {
  256. const filteredData = result.data.filter(item => {
  257. return item.type === 1; //返回type為0即客户金币余额的数据
  258. });
  259. exportList.value = filteredData
  260. } else {
  261. ElMessage.error(result.msg || '获取导出列表失败')
  262. }
  263. } catch (error) {
  264. console.error('获取导出列表出错:', error)
  265. ElMessage.error('获取导出列表失败,请稍后重试')
  266. } finally {
  267. exportListLoading.value = false
  268. }
  269. }
  270. // 下载导出文件
  271. const downloadExportFile = (item) => {
  272. if (item.state === 2) {
  273. const link = document.createElement('a')
  274. link.href = item.url
  275. link.download = item.fileName
  276. link.click()
  277. } else {
  278. ElMessage.warning('文件还在导出中,请稍后再试')
  279. }
  280. }
  281. //根据状态返回对应的标签类型
  282. const getTagType = (state) => {
  283. switch (state) {
  284. case 0:
  285. return 'info';
  286. case 1:
  287. return 'primary';
  288. case 2:
  289. return 'success';
  290. case 3:
  291. return 'danger';
  292. default:
  293. return 'info';
  294. }
  295. }
  296. //根据状态返回对应的标签文案
  297. const getTagText = (state) => {
  298. switch (state) {
  299. case 0:
  300. return '待执行';
  301. case 1:
  302. return '执行中';
  303. case 2:
  304. return '执行完成';
  305. case 3:
  306. return '执行出错';
  307. default:
  308. return '未知状态';
  309. }
  310. }
  311. const handleMarketChange = (val) => {
  312. if (!Array.isArray(val)) return
  313. const hasHeadquarters = val.includes('总部')
  314. const hasOther = val.some(item => item !== '总部')
  315. if (hasHeadquarters && hasOther) {
  316. if (val[val.length - 1] === '总部') {
  317. // 用户最后点的是总部,保留总部,清除其他
  318. goldDetail.value.markets = ['总部']
  319. ElMessage.warning('“总部”与其他地区不可同时选择,系统已为您保留“总部”')
  320. } else {
  321. // 用户最后点的是其他,保留其他,移除总部
  322. goldDetail.value.markets = val.filter(item => item !== '总部')
  323. ElMessage.warning('“总部”与其他地区不可同时选择,系统已为您去除“总部”')
  324. }
  325. }
  326. }
  327. </script>
  328. <template>
  329. <el-row>
  330. <el-col>
  331. <el-card style="margin-bottom: 20px;margin-top: 10px">
  332. <div class="head-card">
  333. <div class="head-card-element">
  334. <el-text class="mx-1" size="large">精网号</el-text>
  335. <el-input v-model="user.jwcode" style="width: 160px" placeholder="请输入精网号" clearable />
  336. </div>
  337. <div class="head-card-element">
  338. <el-text class="mx-1" size="large">所属地区</el-text>
  339. <el-select v-model="user.markets" placeholder="请选择所属地区" style="width: 180px" clearable multiple @change="handleMarketChange">
  340. <el-option v-for="item in market" :key="item.value" :label="item.label" :value="item.value"/>
  341. </el-select>
  342. </div>
  343. <el-button type="primary" @click="search()">查询</el-button>
  344. <el-button @click="reset" type="success">重置</el-button>
  345. <el-button type="primary" @click="exportExcel()">导出Excel</el-button>
  346. <el-button type="primary" @click="openExportList">查看导出列表</el-button>
  347. </div>
  348. <!-- </div> -->
  349. </el-card>
  350. </el-col>
  351. </el-row>
  352. <el-row>
  353. <el-col>
  354. <el-card>
  355. <div>
  356. 金币总数{{ Math.abs(goldtotal) / 100 }}
  357. 永久金币{{ Math.abs(permanentGold) / 100 }}
  358. 免费金币{{ Math.abs(freeGold) / 100 }}
  359. 任务金币{{ Math.abs(taskGold) / 100 }}
  360. </div>
  361. <!-- 设置表格容器的高度和滚动样式 -->
  362. <div style="height: 626px; overflow-y: auto">
  363. <el-table :data="tableData" @cellClick="cellClick" style="width: 100%" height="626px"
  364. @sort-change="handleSortChange">
  365. <el-table-column type="index" label="序号" width="100px" fixed="left">
  366. <template #default="scope">
  367. <span>{{
  368. scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
  369. }}</span>
  370. </template>
  371. </el-table-column>
  372. <el-table-column prop="name" label="姓名" width="120" />
  373. <el-table-column prop="jwcode" label="精网号" width="120" />
  374. <el-table-column prop="market" label="所属地区" width="120" />
  375. <el-table-column prop="allJb" label="金币总数" width="120" aligh="center">
  376. <template #default="scope">
  377. <span>{{
  378. (scope.row.currentPermanentGold +
  379. scope.row.currentFreeJune +
  380. scope.row.currentFreeDecember +
  381. scope.row.currentTaskGold) / 100
  382. }}</span>
  383. </template>
  384. </el-table-column>
  385. <el-table-column prop="currentPermanentGold" label="永久金币" sortable="custom" width="110">
  386. <template #default="scope">
  387. <span>{{ Math.abs(scope.row.currentPermanentGold) / 100 }}</span>
  388. </template>
  389. </el-table-column>
  390. <el-table-column prop="currentFreeJune" label="6月份到期免费金币" sortable="custom" width="110">
  391. <template #default="scope">
  392. <span>{{ scope.row.currentFreeJune / 100 }}</span>
  393. </template>
  394. </el-table-column>
  395. <el-table-column prop="currentFreeDecember" label="12月份到期免费金币" sortable="custom" width="110">
  396. <template #default="scope">
  397. <span>{{ scope.row.currentFreeDecember / 100 }}</span>
  398. </template>
  399. </el-table-column>
  400. <el-table-column prop="currentTaskGold" label="任务金币" sortable="custom" width="130">
  401. <template #default="scope">
  402. <span>{{ Math.abs(scope.row.currentTaskGold) / 100 }}</span>
  403. </template>
  404. </el-table-column>
  405. <el-table-column prop="rcoin" label="历史金币总额" width="150">
  406. <template #default="scope">
  407. <el-popover trigger="hover" placement="left" width="150">
  408. <template #default>
  409. <div>
  410. <div>永久金币{{ (scope.row.sumPermanentGold || 0) / 100 }}</div>
  411. <div>免费金币{{ (scope.row.sumFreeJune || 0) + (scope.row.sumFreeDecember || 0) / 100 }}</div>
  412. <div>任务金币{{ (scope.row.sumTaskGold || 0) / 100 }}</div>
  413. </div>
  414. </template>
  415. <template #reference>
  416. <span>
  417. {{
  418. (scope.row.sumPermanentGold || 0) / 100 +
  419. (scope.row.sumFreeJune || 0) / 100 +
  420. (scope.row.sumFreeDecember || 0) / 100 +
  421. (scope.row.sumTaskGold || 0) / 100
  422. }}</span>
  423. </template>
  424. </el-popover>
  425. </template>
  426. </el-table-column>
  427. <el-table-column prop="sumConsume" label="历史消费" width="150">
  428. <template #default="scope">
  429. <span>{{ Math.abs(scope.row.sumConsume) / 100 }}</span>
  430. </template>
  431. </el-table-column>
  432. </el-table>
  433. </div>
  434. <!-- 分页 -->
  435. <div class="pagination" style="margin-top: 20px">
  436. <el-pagination background :page-size="getObj.pageSize" :page-sizes="[5, 10, 20, 50, 100]"
  437. layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handlePageSizeChange"
  438. @current-change="handleCurrentChange"></el-pagination>
  439. </div>
  440. </el-card>
  441. </el-col>
  442. </el-row>
  443. <el-dialog v-model="exportListVisible" title="导出列表" width="80%">
  444. <el-table :data="exportList" style="width: 100%" :loading="exportListLoading">
  445. <el-table-column prop="fileName" label="文件名" />
  446. <el-table-column prop="state" label="状态">
  447. <template #default="scope">
  448. <el-tag :type="getTagType(scope.row.state)" :effect="scope.row.state === 3 ? 'light' : 'plain'">
  449. {{ getTagText(scope.row.state) }}
  450. </el-tag>
  451. </template>
  452. </el-table-column>
  453. <el-table-column prop="createTime" label="创建时间">
  454. <template #default="scope">
  455. {{ moment(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
  456. </template>
  457. </el-table-column>
  458. <el-table-column label="操作">
  459. <template #default="scope">
  460. <el-button type="primary" size="small" @click="downloadExportFile(scope.row)"
  461. :disabled="scope.row.state !== 2">
  462. 下载
  463. </el-button>
  464. </template>
  465. </el-table-column>
  466. </el-table>
  467. <template #footer>
  468. <div class="dialog-footer">
  469. <el-button text @click="exportListVisible = false">关闭</el-button>
  470. </div>
  471. </template>
  472. </el-dialog>
  473. </template>
  474. <style scoped lang="scss">
  475. .pagination {
  476. display: flex;
  477. }
  478. .status {
  479. display: flex;
  480. }
  481. .head-card {
  482. display: flex;
  483. }
  484. .head-card-element {
  485. margin-right: 20px;
  486. }
  487. .head-card-btn {
  488. margin-left: auto;
  489. }
  490. .custom-box {
  491. display: flex;
  492. flex-wrap: wrap;
  493. row-gap: 5px;
  494. div:nth-child(1) {
  495. flex: 1 0 100%;
  496. }
  497. div {
  498. margin-right: 20px;
  499. }
  500. }
  501. </style>