Browse Source

0616

master
lihuilin 2 weeks ago
commit
3feabaf337
  1. 5
      .env.development
  2. 5
      .env.production
  3. 6
      .env.test
  4. 24
      .gitignore
  5. 8
      .vite/deps/_metadata.json
  6. 3
      .vite/deps/package.json
  7. 3
      .vscode/extensions.json
  8. 38
      README.md
  9. 22
      index.html
  10. 5065
      package-lock.json
  11. 46
      package.json
  12. BIN
      public/favicon.ico
  13. 9
      src/App.vue
  14. 13
      src/api/index.js
  15. BIN
      src/assets/avator.png
  16. BIN
      src/assets/background.jpg
  17. 86
      src/assets/base.css
  18. 72
      src/assets/css/common.css
  19. 1
      src/assets/logo.svg
  20. 35
      src/assets/main.css
  21. 1
      src/assets/vue.svg
  22. BIN
      src/assets/动漫美女.png
  23. BIN
      src/assets/金币管理系统logo.png
  24. BIN
      src/assets/韩信.png
  25. 41
      src/components/HelloWorld.vue
  26. 94
      src/components/TheWelcome.vue
  27. 87
      src/components/WelcomeItem.vue
  28. 7
      src/components/icons/IconCommunity.vue
  29. 7
      src/components/icons/IconDocumentation.vue
  30. 7
      src/components/icons/IconEcosystem.vue
  31. 7
      src/components/icons/IconSupport.vue
  32. 19
      src/components/icons/IconTooling.vue
  33. 34
      src/main.ts
  34. 101
      src/router/index.js
  35. 23
      src/router/index.ts
  36. 12
      src/store/area.js
  37. 12
      src/stores/counter.ts
  38. 79
      src/style.css
  39. 26
      src/util/http.js
  40. 46
      src/util/request.js
  41. 15
      src/views/AboutView.vue
  42. 9
      src/views/HomeView.vue
  43. 855
      src/views/audit/rechargeAudit.vue
  44. 889
      src/views/audit/refundAudit.vue
  45. 690
      src/views/consume/addConsume.vue
  46. 587
      src/views/consume/allConsume.vue
  47. 217
      src/views/goldBeen/addGoldenBeen.vue
  48. 253
      src/views/goldBeen/goldenBeenBalance.vue
  49. 581
      src/views/goldBeen/goldenBeenConsum.vue
  50. 794
      src/views/goldBeen/goldenBeenDetail.vue
  51. 582
      src/views/goldBeen/onLineDetail.vue
  52. 378
      src/views/index.vue
  53. 243
      src/views/login.vue
  54. 494
      src/views/managerecharge/activity.vue
  55. 849
      src/views/managerecharge/rate.vue
  56. 24
      src/views/noPermissionPage.vue
  57. 910
      src/views/permissions/index.vue
  58. 1555
      src/views/recharge/addRecharge.vue
  59. 796
      src/views/recharge/adminRecharge.vue
  60. 964
      src/views/recharge/allRecharge.vue
  61. 571
      src/views/refund/addRefund.vue
  62. 734
      src/views/refund/allRefund.vue
  63. 798
      src/views/usergold/index.vue
  64. 500
      src/views/usergoldInfo/index.vue
  65. 1668
      src/views/workspace/index.vue
  66. 140
      src/views/z.vue
  67. 1
      src/vite-env.d.ts
  68. 4949
      stats.html
  69. 41
      tsconfig.app.json
  70. 7
      tsconfig.json
  71. 28
      tsconfig.node.json
  72. 1
      tsconfig.tsbuildinfo
  73. 70
      vite.config.ts

5
.env.development

@ -0,0 +1,5 @@
# VITE_API_BASE='http://54.251.137.151:10704/'
VITE_API_BASE='http://192.168.8.94:8080/'
#VITE_API_BASE='https://hwjb.homilychart.com/gold_htms_dev'
# VITE_API_BASE='http://54.251.137.151:10704/'
# VITE_API_BASE='http://192.168.8.225:8080/'

5
.env.production

@ -0,0 +1,5 @@
# VITE_API_BASE='http://54.251.137.151:10702/'
VITE_API_BASE='https://hwjb.homilychart.com/gold_htms_prod'
# VITE_API_BASE='https://hwjb.homilychart.com/gold_htms_dev'
# VITE_API_BASE='http://192.168.8.232:8080/'

6
.env.test

@ -0,0 +1,6 @@
# VITE_API_BASE='https://hwjb.homilychart.com/gold_htms_prod'
#VITE_API_BASE='http://54.251.137.151:10704/'
VITE_API_BASE='http://192.168.8.94:8080/'
#VITE_API_BASE='https://hwjb.homilychart.com/gold_htms_dev'
# VITE_API_BASE='http://192.168.8.225:8080/'

24
.gitignore

@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

8
.vite/deps/_metadata.json

@ -0,0 +1,8 @@
{
"hash": "e40e7e03",
"configHash": "30419548",
"lockfileHash": "3e0e6deb",
"browserHash": "f66225ae",
"optimized": {},
"chunks": {}
}

3
.vite/deps/package.json

@ -0,0 +1,3 @@
{
"type": "module"
}

3
.vscode/extensions.json

@ -0,0 +1,3 @@
{
"recommendations": ["Vue.volar"]
}

38
README.md

@ -0,0 +1,38 @@
# Vue 3 + TypeScript + Vite
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
Learn more about the recommended Project Setup and IDE Support in the [Vue Docs TypeScript Guide](https://vuejs.org/guide/typescript/overview.html#project-setup).
npm install 下载依赖包
npm run dev 启动项目
npm install vue-router 下载 vue-router 组件
npm install axios 下载 axios 组件
npm install element-plus --save 下载 element-plus 组件
npm install @element-plus/icons-vue 下载 element-plus 图标库
npm install vue-icons-plus --save 下载外部图标库
npm install echarts 安装 echarts 组件
npm install moment 安装 moment 组件
npm install mathjs 安装 mathjs 组件,解决数据计算问题
npm install xlsx 安装 xlsx 组件,解决 excel 文件读取问题
npm install vue-json-excel 安装导出 excel 组件
npm install lodash 安装 lodash 组件,解决数据处理问题
npm install vite-plugin-lazy-import -D 安装按需加载组件
npm install vxe-pc-ui@4.3.66 vxe-table@4.10.2 vxe-utils@4.1.11 安装 vxe 组件
npm install --save-dev @types/node 安装 typescript 声明文件
npm install -g http-server 安装 http-server 组件,模拟服务器运行

22
index.html

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>财务金币管理系统</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
<style>
html,
body,
#app {
height: 100%;
margin: 0px;
padding: 0px;
}
</style>

5065
package-lock.json
File diff suppressed because it is too large
View File

46
package.json

@ -0,0 +1,46 @@
{
"name": "gold-system",
"private": true,
"version": "0.0.0",
"type": "module",
"sideEffects": false,
"scripts": {
"dev": "vite --host 0.0.0.0",
"build:test": "vite build --mode test",
"build:prod": "vite build --mode production",
"preview": "vite preview",
"serve": "vite - service serve --host 0.0.0.0 --port 8080"
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"axios": "^1.7.8",
"echarts": "^5.5.1",
"element-plus": "^2.8.8",
"lodash": "^4.17.21",
"mathjs": "^14.0.1",
"moment": "^2.30.1",
"pinia": "^3.0.2",
"pinyin-match": "^1.2.8",
"vue": "^3.5.12",
"vue-icons-plus": "^0.1.7",
"vue-json-excel": "^0.3.0",
"vue-router": "^4.5.0",
"vxe-pc-ui": "^4.3.66",
"vxe-table": "^4.10.2",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@types/node": "^22.10.5",
"@types/vue": "^2.0.0",
"@vitejs/plugin-legacy": "^6.0.2",
"@vitejs/plugin-vue": "^5.1.4",
"file-saver": "^2.0.5",
"rollup-plugin-visualizer": "^5.14.0",
"sass": "^1.86.3",
"terser": "^5.38.1",
"typescript": "~5.6.2",
"vite": "^6.1.0",
"vite-plugin-lazy-import": "^1.0.7",
"vue-tsc": "^2.1.8"
}
}

BIN
public/favicon.ico

9
src/App.vue

@ -0,0 +1,9 @@
<script setup>
</script>
<template>
<router-view></router-view>
</template>
<style scoped>
</style>

13
src/api/index.js

@ -0,0 +1,13 @@
import { pa } from 'element-plus/es/locales.mjs';
import http from '../util/http.js';
// 这个是不知道有啥用
const API={
post: function(url,data){
return http({url:url,method:'post',data:data})
},
postN: function(url,params){
return http({url:url,method:'post',params:params})
},
};
export default API;

BIN
src/assets/avator.png

After

Width: 250  |  Height: 252  |  Size: 90 KiB

BIN
src/assets/background.jpg

After

Width: 928  |  Height: 1133  |  Size: 567 KiB

86
src/assets/base.css

@ -0,0 +1,86 @@
/* color palette from <https://github.com/vuejs/theme> */
:root {
--vt-c-white: #ffffff;
--vt-c-white-soft: #f8f8f8;
--vt-c-white-mute: #f2f2f2;
--vt-c-black: #181818;
--vt-c-black-soft: #222222;
--vt-c-black-mute: #282828;
--vt-c-indigo: #2c3e50;
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
--vt-c-text-light-1: var(--vt-c-indigo);
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
--vt-c-text-dark-1: var(--vt-c-white);
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
}
/* semantic color variables for this project */
:root {
--color-background: var(--vt-c-white);
--color-background-soft: var(--vt-c-white-soft);
--color-background-mute: var(--vt-c-white-mute);
--color-border: var(--vt-c-divider-light-2);
--color-border-hover: var(--vt-c-divider-light-1);
--color-heading: var(--vt-c-text-light-1);
--color-text: var(--vt-c-text-light-1);
--section-gap: 160px;
}
@media (prefers-color-scheme: dark) {
:root {
--color-background: var(--vt-c-black);
--color-background-soft: var(--vt-c-black-soft);
--color-background-mute: var(--vt-c-black-mute);
--color-border: var(--vt-c-divider-dark-2);
--color-border-hover: var(--vt-c-divider-dark-1);
--color-heading: var(--vt-c-text-dark-1);
--color-text: var(--vt-c-text-dark-2);
}
}
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
font-weight: normal;
}
body {
min-height: 100vh;
color: var(--color-text);
background: var(--color-background);
transition:
color 0.5s,
background-color 0.5s;
line-height: 1.6;
font-family:
Inter,
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
Oxygen,
Ubuntu,
Cantarell,
'Fira Sans',
'Droid Sans',
'Helvetica Neue',
sans-serif;
font-size: 15px;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

72
src/assets/css/common.css

@ -0,0 +1,72 @@
.green-dot {
margin: 7px 5px 0px 0px;
width: 10px;
height: 10px;
border-radius: 50%;
display: block;
background-color: green;
}
.red-dot {
margin: 7px 5px 0px 0px;
width: 10px;
height: 10px;
border-radius: 50%;
display: block;
background-color: red;
}
.grey-dot {
margin: 7px 5px 0px 0px;
width: 10px;
height: 10px;
border-radius: 50%;
display: block;
background-color: grey;
}
.yellow-dot {
margin: 7px 5px 0px 0px;
width: 10px;
height: 10px;
display: block;
background-color: #ffe733;
}
.light-green-dot {
margin: 7px 5px 0px 0px;
width: 10px;
height: 10px;
display: block;
background-color: #35e383;
}
.blue-dot {
margin: 7px 5px 0px 0px;
width: 10px;
height: 10px;
display: block;
background-color: #5f8ff5;
}
.red-triangle {
width: 0;
height: 0;
border-left: 7px solid transparent;
border-right: 7px solid transparent;
border-bottom: 10px solid red;
}
.green-triangle {
width: 0;
height: 0;
border-left: 7px solid transparent;
border-right: 7px solid transparent;
border-top: 10px solid green;
}
.grey-triangle {
width: 10px;
height: 5px;
background-color: grey;
}

1
src/assets/logo.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>

35
src/assets/main.css

@ -0,0 +1,35 @@
@import './base.css';
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
font-weight: normal;
}
a,
.green {
text-decoration: none;
color: hsla(160, 100%, 37%, 1);
transition: 0.4s;
padding: 3px;
}
@media (hover: hover) {
a:hover {
background-color: hsla(160, 100%, 37%, 0.2);
}
}
@media (min-width: 1024px) {
body {
display: flex;
place-items: center;
}
#app {
display: grid;
grid-template-columns: 1fr 1fr;
padding: 0 2rem;
}
}

1
src/assets/vue.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>

BIN
src/assets/动漫美女.png

After

Width: 263  |  Height: 181  |  Size: 95 KiB

BIN
src/assets/金币管理系统logo.png

After

Width: 47  |  Height: 47  |  Size: 2.0 KiB

BIN
src/assets/韩信.png

After

Width: 256  |  Height: 180  |  Size: 96 KiB

41
src/components/HelloWorld.vue

@ -0,0 +1,41 @@
<script setup lang="ts">
defineProps<{
msg: string
}>()
</script>
<template>
<div class="greetings">
<h1 class="green">{{ msg }}</h1>
<h3>
Youve successfully created a project with
<a href="https://vite.dev/" target="_blank" rel="noopener">Vite</a> +
<a href="https://vuejs.org/" target="_blank" rel="noopener">Vue 3</a>. What's next?
</h3>
</div>
</template>
<style scoped>
h1 {
font-weight: 500;
font-size: 2.6rem;
position: relative;
top: -10px;
}
h3 {
font-size: 1.2rem;
}
.greetings h1,
.greetings h3 {
text-align: center;
}
@media (min-width: 1024px) {
.greetings h1,
.greetings h3 {
text-align: left;
}
}
</style>

94
src/components/TheWelcome.vue

@ -0,0 +1,94 @@
<script setup lang="ts">
import WelcomeItem from './WelcomeItem.vue'
import DocumentationIcon from './icons/IconDocumentation.vue'
import ToolingIcon from './icons/IconTooling.vue'
import EcosystemIcon from './icons/IconEcosystem.vue'
import CommunityIcon from './icons/IconCommunity.vue'
import SupportIcon from './icons/IconSupport.vue'
const openReadmeInEditor = () => fetch('/__open-in-editor?file=README.md')
</script>
<template>
<WelcomeItem>
<template #icon>
<DocumentationIcon />
</template>
<template #heading>Documentation</template>
Vues
<a href="https://vuejs.org/" target="_blank" rel="noopener">official documentation</a>
provides you with all information you need to get started.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<ToolingIcon />
</template>
<template #heading>Tooling</template>
This project is served and bundled with
<a href="https://vite.dev/guide/features.html" target="_blank" rel="noopener">Vite</a>. The
recommended IDE setup is
<a href="https://code.visualstudio.com/" target="_blank" rel="noopener">VSCode</a>
+
<a href="https://github.com/vuejs/language-tools" target="_blank" rel="noopener">Vue - Official</a>. If
you need to test your components and web pages, check out
<a href="https://vitest.dev/" target="_blank" rel="noopener">Vitest</a>
and
<a href="https://www.cypress.io/" target="_blank" rel="noopener">Cypress</a>
/
<a href="https://playwright.dev/" target="_blank" rel="noopener">Playwright</a>.
<br />
More instructions are available in
<a href="javascript:void(0)" @click="openReadmeInEditor"><code>README.md</code></a
>.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<EcosystemIcon />
</template>
<template #heading>Ecosystem</template>
Get official tools and libraries for your project:
<a href="https://pinia.vuejs.org/" target="_blank" rel="noopener">Pinia</a>,
<a href="https://router.vuejs.org/" target="_blank" rel="noopener">Vue Router</a>,
<a href="https://test-utils.vuejs.org/" target="_blank" rel="noopener">Vue Test Utils</a>, and
<a href="https://github.com/vuejs/devtools" target="_blank" rel="noopener">Vue Dev Tools</a>. If
you need more resources, we suggest paying
<a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">Awesome Vue</a>
a visit.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<CommunityIcon />
</template>
<template #heading>Community</template>
Got stuck? Ask your question on
<a href="https://chat.vuejs.org" target="_blank" rel="noopener">Vue Land</a>
(our official Discord server), or
<a href="https://stackoverflow.com/questions/tagged/vue.js" target="_blank" rel="noopener"
>StackOverflow</a
>. You should also follow the official
<a href="https://bsky.app/profile/vuejs.org" target="_blank" rel="noopener">@vuejs.org</a>
Bluesky account or the
<a href="https://x.com/vuejs" target="_blank" rel="noopener">@vuejs</a>
X account for latest news in the Vue world.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<SupportIcon />
</template>
<template #heading>Support Vue</template>
As an independent project, Vue relies on community backing for its sustainability. You can help
us by
<a href="https://vuejs.org/sponsor/" target="_blank" rel="noopener">becoming a sponsor</a>.
</WelcomeItem>
</template>

87
src/components/WelcomeItem.vue

@ -0,0 +1,87 @@
<template>
<div class="item">
<i>
<slot name="icon"></slot>
</i>
<div class="details">
<h3>
<slot name="heading"></slot>
</h3>
<slot></slot>
</div>
</div>
</template>
<style scoped>
.item {
margin-top: 2rem;
display: flex;
position: relative;
}
.details {
flex: 1;
margin-left: 1rem;
}
i {
display: flex;
place-items: center;
place-content: center;
width: 32px;
height: 32px;
color: var(--color-text);
}
h3 {
font-size: 1.2rem;
font-weight: 500;
margin-bottom: 0.4rem;
color: var(--color-heading);
}
@media (min-width: 1024px) {
.item {
margin-top: 0;
padding: 0.4rem 0 1rem calc(var(--section-gap) / 2);
}
i {
top: calc(50% - 25px);
left: -26px;
position: absolute;
border: 1px solid var(--color-border);
background: var(--color-background);
border-radius: 8px;
width: 50px;
height: 50px;
}
.item:before {
content: ' ';
border-left: 1px solid var(--color-border);
position: absolute;
left: 0;
bottom: calc(50% + 25px);
height: calc(50% - 25px);
}
.item:after {
content: ' ';
border-left: 1px solid var(--color-border);
position: absolute;
left: 0;
top: calc(50% + 25px);
height: calc(50% - 25px);
}
.item:first-of-type:before {
display: none;
}
.item:last-of-type:after {
display: none;
}
}
</style>

7
src/components/icons/IconCommunity.vue

@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
<path
d="M15 4a1 1 0 1 0 0 2V4zm0 11v-1a1 1 0 0 0-1 1h1zm0 4l-.707.707A1 1 0 0 0 16 19h-1zm-4-4l.707-.707A1 1 0 0 0 11 14v1zm-4.707-1.293a1 1 0 0 0-1.414 1.414l1.414-1.414zm-.707.707l-.707-.707.707.707zM9 11v-1a1 1 0 0 0-.707.293L9 11zm-4 0h1a1 1 0 0 0-1-1v1zm0 4H4a1 1 0 0 0 1.707.707L5 15zm10-9h2V4h-2v2zm2 0a1 1 0 0 1 1 1h2a3 3 0 0 0-3-3v2zm1 1v6h2V7h-2zm0 6a1 1 0 0 1-1 1v2a3 3 0 0 0 3-3h-2zm-1 1h-2v2h2v-2zm-3 1v4h2v-4h-2zm1.707 3.293l-4-4-1.414 1.414 4 4 1.414-1.414zM11 14H7v2h4v-2zm-4 0c-.276 0-.525-.111-.707-.293l-1.414 1.414C5.42 15.663 6.172 16 7 16v-2zm-.707 1.121l3.414-3.414-1.414-1.414-3.414 3.414 1.414 1.414zM9 12h4v-2H9v2zm4 0a3 3 0 0 0 3-3h-2a1 1 0 0 1-1 1v2zm3-3V3h-2v6h2zm0-6a3 3 0 0 0-3-3v2a1 1 0 0 1 1 1h2zm-3-3H3v2h10V0zM3 0a3 3 0 0 0-3 3h2a1 1 0 0 1 1-1V0zM0 3v6h2V3H0zm0 6a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1H0zm3 3h2v-2H3v2zm1-1v4h2v-4H4zm1.707 4.707l.586-.586-1.414-1.414-.586.586 1.414 1.414z"
/>
</svg>
</template>

7
src/components/icons/IconDocumentation.vue

@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" fill="currentColor">
<path
d="M11 2.253a1 1 0 1 0-2 0h2zm-2 13a1 1 0 1 0 2 0H9zm.447-12.167a1 1 0 1 0 1.107-1.666L9.447 3.086zM1 2.253L.447 1.42A1 1 0 0 0 0 2.253h1zm0 13H0a1 1 0 0 0 1.553.833L1 15.253zm8.447.833a1 1 0 1 0 1.107-1.666l-1.107 1.666zm0-14.666a1 1 0 1 0 1.107 1.666L9.447 1.42zM19 2.253h1a1 1 0 0 0-.447-.833L19 2.253zm0 13l-.553.833A1 1 0 0 0 20 15.253h-1zm-9.553-.833a1 1 0 1 0 1.107 1.666L9.447 14.42zM9 2.253v13h2v-13H9zm1.553-.833C9.203.523 7.42 0 5.5 0v2c1.572 0 2.961.431 3.947 1.086l1.107-1.666zM5.5 0C3.58 0 1.797.523.447 1.42l1.107 1.666C2.539 2.431 3.928 2 5.5 2V0zM0 2.253v13h2v-13H0zm1.553 13.833C2.539 15.431 3.928 15 5.5 15v-2c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM5.5 15c1.572 0 2.961.431 3.947 1.086l1.107-1.666C9.203 13.523 7.42 13 5.5 13v2zm5.053-11.914C11.539 2.431 12.928 2 14.5 2V0c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM14.5 2c1.573 0 2.961.431 3.947 1.086l1.107-1.666C18.203.523 16.421 0 14.5 0v2zm3.5.253v13h2v-13h-2zm1.553 12.167C18.203 13.523 16.421 13 14.5 13v2c1.573 0 2.961.431 3.947 1.086l1.107-1.666zM14.5 13c-1.92 0-3.703.523-5.053 1.42l1.107 1.666C11.539 15.431 12.928 15 14.5 15v-2z"
/>
</svg>
</template>

7
src/components/icons/IconEcosystem.vue

@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" fill="currentColor">
<path
d="M11.447 8.894a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm0 1.789a1 1 0 1 0 .894-1.789l-.894 1.789zM7.447 7.106a1 1 0 1 0-.894 1.789l.894-1.789zM10 9a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0H8zm9.447-5.606a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm2 .789a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zM18 5a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0h-2zm-5.447-4.606a1 1 0 1 0 .894-1.789l-.894 1.789zM9 1l.447-.894a1 1 0 0 0-.894 0L9 1zm-2.447.106a1 1 0 1 0 .894 1.789l-.894-1.789zm-6 3a1 1 0 1 0 .894 1.789L.553 4.106zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zm-2-.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 2.789a1 1 0 1 0 .894-1.789l-.894 1.789zM2 5a1 1 0 1 0-2 0h2zM0 7.5a1 1 0 1 0 2 0H0zm8.553 12.394a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 1a1 1 0 1 0 .894 1.789l-.894-1.789zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zM8 19a1 1 0 1 0 2 0H8zm2-2.5a1 1 0 1 0-2 0h2zm-7.447.394a1 1 0 1 0 .894-1.789l-.894 1.789zM1 15H0a1 1 0 0 0 .553.894L1 15zm1-2.5a1 1 0 1 0-2 0h2zm12.553 2.606a1 1 0 1 0 .894 1.789l-.894-1.789zM17 15l.447.894A1 1 0 0 0 18 15h-1zm1-2.5a1 1 0 1 0-2 0h2zm-7.447-5.394l-2 1 .894 1.789 2-1-.894-1.789zm-1.106 1l-2-1-.894 1.789 2 1 .894-1.789zM8 9v2.5h2V9H8zm8.553-4.894l-2 1 .894 1.789 2-1-.894-1.789zm.894 0l-2-1-.894 1.789 2 1 .894-1.789zM16 5v2.5h2V5h-2zm-4.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zm-2.894-1l-2 1 .894 1.789 2-1L8.553.106zM1.447 5.894l2-1-.894-1.789-2 1 .894 1.789zm-.894 0l2 1 .894-1.789-2-1-.894 1.789zM0 5v2.5h2V5H0zm9.447 13.106l-2-1-.894 1.789 2 1 .894-1.789zm0 1.789l2-1-.894-1.789-2 1 .894 1.789zM10 19v-2.5H8V19h2zm-6.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zM2 15v-2.5H0V15h2zm13.447 1.894l2-1-.894-1.789-2 1 .894 1.789zM18 15v-2.5h-2V15h2z"
/>
</svg>
</template>

7
src/components/icons/IconSupport.vue

@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
<path
d="M10 3.22l-.61-.6a5.5 5.5 0 0 0-7.666.105 5.5 5.5 0 0 0-.114 7.665L10 18.78l8.39-8.4a5.5 5.5 0 0 0-.114-7.665 5.5 5.5 0 0 0-7.666-.105l-.61.61z"
/>
</svg>
</template>

19
src/components/icons/IconTooling.vue

@ -0,0 +1,19 @@
<!-- This icon is from <https://github.com/Templarian/MaterialDesign>, distributed under Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) license-->
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
aria-hidden="true"
role="img"
class="iconify iconify--mdi"
width="24"
height="24"
preserveAspectRatio="xMidYMid meet"
viewBox="0 0 24 24"
>
<path
d="M20 18v-4h-3v1h-2v-1H9v1H7v-1H4v4h16M6.33 8l-1.74 4H7v-1h2v1h6v-1h2v1h2.41l-1.74-4H6.33M9 5v1h6V5H9m12.84 7.61c.1.22.16.48.16.8V18c0 .53-.21 1-.6 1.41c-.4.4-.85.59-1.4.59H4c-.55 0-1-.19-1.4-.59C2.21 19 2 18.53 2 18v-4.59c0-.32.06-.58.16-.8L4.5 7.22C4.84 6.41 5.45 6 6.33 6H7V5c0-.55.18-1 .57-1.41C7.96 3.2 8.44 3 9 3h6c.56 0 1.04.2 1.43.59c.39.41.57.86.57 1.41v1h.67c.88 0 1.49.41 1.83 1.22l2.34 5.39z"
fill="currentColor"
></path>
</svg>
</template>

34
src/main.ts

@ -0,0 +1,34 @@
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import ElementPlus from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
import 'element-plus/dist/index.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import './assets/css/common.css' // 引入公共CSS文件
import JsonExcel from 'vue-json-excel'
import { createPinia } from 'pinia'
import VxeUI from 'vxe-pc-ui'
import 'vxe-pc-ui/lib/style.css'
import VxeUITable from 'vxe-table'
import 'vxe-table/lib/style.css'
const a = createApp(App)
// 全局注册 ElementPlus 图标
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
a.component(key, component)
}
// 使用 ElementPlus 和路由器
a.use(ElementPlus, {
locale: zhCn
})
.use(router)
.use(VxeUI)
.use(VxeUITable)
.use(createPinia())
.mount('#app')
// 注册 JsonExcel 组件
a.component('downloadExcel', JsonExcel)

101
src/router/index.js

@ -0,0 +1,101 @@
import { createRouter, createWebHashHistory } from 'vue-router';
const router = createRouter({
history: createWebHashHistory(),
routes: [
{ path: '/login', name: "login", component: () => import("../views/login.vue") },
{ path: '/', redirect: "/login" },
{ path: '/test', component: () => import("../views/z.vue") },
{
meta: { requireAuth: true },
path: '/index', component: () => import("../views/index.vue"),
children: [
// 工作台
{ path: '/workspace/:area?', name: "workspace", component: () => import("../views/workspace/index.vue") },
// 充值审核
{ path: '/rechargeAudit', name: "rechargeAudit", component: () => import("../views/audit/rechargeAudit.vue") },
// 退款审核
{ path: '/refundAudit', name: "refundAudit", component: () => import("../views/audit/refundAudit.vue") },
// 新增消费
{ path: '/addConsume', name: "addConsume", component: () => import("../views/consume/addConsume.vue") },
// 所有消费明细
{ path: '/allConsume', name: "allConsume", component: () => import("../views/consume/allConsume.vue") },
// 活动管理
{ path: '/activity', name: "activity", component: () => import("../views/managerecharge/activity.vue") },
// 汇率管理
{ path: '/rate', name: "rate", component: () => import("../views/managerecharge/rate.vue") },
// 新增充值
{ path: '/addRecharge', name: "addRecharge", component: () => import("../views/recharge/addRecharge.vue") },
// 客户充值明细
{ path: '/adminRecharge', name: "adminRecharge", component: () => import("../views/recharge/adminRecharge.vue") },
// 所有充值明细
{ path: '/allRecharge', name: "allRecharge", component: () => import("../views/recharge/allRecharge.vue") },
// 新增退款
{ path: '/addRefund', name: "addRefund", component: () => import("../views/refund/addRefund.vue") },
// 退款明细
{ path: '/allRefund', name: "allRefund", component: () => import("../views/refund/allRefund.vue") },
// 客户金币明细
{ path: '/usergold', name: "usergold", component: () => import("../views/usergold/index.vue") },
// 客户金币余额
{ path: '/usergoldInfo', name: "usergoldInfo", component: () => import("../views/usergoldInfo/index.vue") },
// 权限管理
{ path: '/permissions', name: "permissions", component: () => import("../views/permissions/index.vue") },
// 没有权限
{ path: '/noPermission', name: "noPermission", component: () => import("../views/noPermissionPage.vue") },
//金豆充值
{ path: '/addGoldenBeen', name: "addGoldenBeen", component: () => import("../views/goldBeen/addGoldenBeen.vue") },
//金豆余额
{ path: '/goldenBeenBalance', name: "goldenBeenBalance", component: () => import("../views/goldBeen/goldenBeenBalance.vue") },
//金豆充值明细
{ path: '/goldenBeenDetail', name: "goldenBeenDetail", component: () => import("../views/goldBeen/goldenBeenDetail.vue") },
//线上充值明细
{ path: '/onLineDetail', name: "onLineDetail", component: () => import("../views/goldBeen/onLineDetail.vue") },
//金豆消费明细
{ path: '/goldenBeenConsum', name: "goldenBeenConsum", component: () => import("../views/goldBeen/goldenBeenConsum.vue") }
]
},
]
});
router.beforeEach((to, from, next) => {
const token = localStorage.getItem("token");
const permission = localStorage.getItem("permission");
if (to.name != "login" && !token) {
next({ name: "login" });
} else {
if (permission == "4" && to.name != "noPermission") {
next({ name: "noPermission" });
} else if (permission == "3") {
if (to.name == "addConsume" || to.name == "allConsume"
|| to.name == "addRecharge" || to.name == "adminRecharge" || to.name == "allRecharge"
|| to.name == "addRefund" || to.name == "allRefund"
|| to.name == "permissions") {
next({ name: "workspace" });
} else {
next();
}
} else if (permission == '2') {
if (to.name == "rechargeAudit" || to.name == "refundAudit"
|| to.name == "activity" || to.name == "rate"
|| to.name == "permissions") {
next({ name: "workspace" })
} else {
next();
}
} else if (permission == '5') {
if (to.name == "permissions") {
next({ name: "workspace" })
} else {
next();
}
}
else {
next();
}
}
})
export default router;

23
src/router/index.ts

@ -0,0 +1,23 @@
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView,
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (About.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import('../views/AboutView.vue'),
},
],
})
export default router

12
src/store/area.js

@ -0,0 +1,12 @@
import { defineStore } from 'pinia'
// 这个也是不知道有啥用,谁给在index.vue里注了
export const useAreaStore = defineStore('area', {
state: () => ({
currentArea: '全部',
}),
actions: {
updateArea(newVal) {
this.currentArea = newVal
},
},
})

12
src/stores/counter.ts

@ -0,0 +1,12 @@
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
return { count, doubleCount, increment }
})

79
src/style.css

@ -0,0 +1,79 @@
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
.card {
padding: 2em;
}
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}

26
src/util/http.js

@ -0,0 +1,26 @@
import request from './request'
export default function(options) {
const { method = 'post', url, data = {}, params = {}, headers = {} } = options
return request({
method,
url,
data,
params,
headers
})
.then(({ status, data, statusText }) => {
if (status === 200) {
return data
} else {
throw new Error(statusText)
}
})
.catch(error => {
if (error?.needsLogin) {
return { needsLogin: true }
}
return Promise.reject(error)
})
}

46
src/util/request.js

@ -0,0 +1,46 @@
import axios from 'axios'
// 创建axios实例
const service = axios.create({
baseURL: import.meta.env.VITE_API_BASE,
timeout: 10000,
headers: {
'Content-Type': 'application/json'
},
// 设置请求头,指定请求体的格式为 JSON
// 设置默认请求方法为 POST 这行对应的代码搁哪呢?
})
// 请求拦截器
service.interceptors.request.use(config => {
const token = localStorage.getItem('token')
if (token) {
if (config.data) {
config.data.token = token;
} else {
config.data = { token };
}
// config.headers.Authorization = `${token}`
}
return config
}, error => {
return Promise.reject(error)
})
// 响应拦截器
service.interceptors.response.use(
response => {
return response
},
error => {
// const { response } = error
// if (response && response.status === 401) {
// const machineId = localStorage.getItem('machineId')
// localStorage.removeItem('token')
// window.location.href = `/login?machineId=${machineId}`
// return Promise.resolve({ needsLogin: true })
// }
return Promise.reject(error)
}
)
export default service

15
src/views/AboutView.vue

@ -0,0 +1,15 @@
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>
<style>
@media (min-width: 1024px) {
.about {
min-height: 100vh;
display: flex;
align-items: center;
}
}
</style>

9
src/views/HomeView.vue

@ -0,0 +1,9 @@
<script setup lang="ts">
import TheWelcome from '../components/TheWelcome.vue'
</script>
<template>
<main>
<TheWelcome />
</main>
</template>

855
src/views/audit/rechargeAudit.vue

@ -0,0 +1,855 @@
<script setup>
import { ref, onMounted, reactive, computed } from 'vue'
import ElementPlus from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
import { AiFillRead } from 'vue-icons-plus/ai'
import axios from 'axios'
import request from '@/util/http'
import moment from 'moment'
import API from '../../api/index.js'
//
//
const columnOptions = ref([
{ prop: 'username', label: '姓名', width: 125 },
{ prop: 'jwcode', label: '精网号', width: 125 },
{ prop: 'area', label: '所属地区', width: 125 },
{ prop: 'activityName', label: '活动名称', width: 150 },
{ prop: 'rechargeGold', label: '充值金额', width: 125, sortable: true },
{ prop: 'rechargeWay', label: '充值方式', width: 125 },
{ prop: 'paidGold', label: '永久金币', width: 125, sortable: true },
{ prop: 'freeGold', label: '免费金币', width: 125, sortable: true },
{ prop: 'remark', label: '备注', width: 200, showOverflowTooltip: true },
{ prop: 'payWay', label: '支付方式', width: 125 },
{ prop: 'rechargeVoucher', label: '支付凭证', width: 125 },
{ prop: 'name', label: '提交人', width: 125 },
{ prop: 'status', label: '审核状态', width: 125 },
{ prop: 'reson', label: '驳回理由', width: 200 },
{ prop: 'rechargeTime', label: '交款时间', width: 200, sortable: true },
{ prop: 'createTime', label: '提交时间', width: 200, sortable: true },
{ prop: 'auditTime', label:'审核时间', width:200, sortable:true}
])
//
const defaultColumns = ['username', 'jwcode', 'area', 'activityName', 'rechargeGold', 'rechargeWay', 'paidGold', 'freeGold',
'remark', 'payWay', 'rechargeVoucher', 'name', 'status', 'reson', 'rechargeTime', 'createTime', 'auditTime']
const selectedColumns = ref([...defaultColumns])
//
const adminData = ref({})
const getAdminData = async function () {
try {
const result = await request({
url: '/admin/userinfo',
data: {}
})
adminData.value = result
console.log('请求成功', result)
console.log('用户信息', adminData.value)
} catch (error) {
console.log('请求失败', error)
}
}
//
const tableData = ref([])
// ======================================
// rechargeVo
const rechargeVo = ref({
rechargeWay: '客服充值'
})
//
const getObj = ref({
pageNum: 1,
pageSize: 50
})
//
const total = ref(100)
//
const getTime = ref([])
//
const activity = ref([])
//
const allData = ref([])
//
const area = ref([])
// ======================================
//
const rejectVisible = ref(false)
//
const rejectObj = ref({})
//
const passObj = ref({})
//
const activeName = ref('all')
//
const payWay = [
{
value: '微信',
label: '微信'
},
{
value: '支付宝',
label: '支付宝'
},
{
value: '银联',
label: '银联'
},
{
value: '信用卡',
label: '信用卡'
},
{
value: '借记卡',
label: '借记卡'
}
]
// //
// const tableHeight = computed(function () {
// return (getObj.value.pageSize + 2) * 60 + "px";
// });
// ref
const Ref = ref(null)
//
//
//
const trueGold = ref(0)
const trueCount = ref(0)
const trueRGold = ref(0)
const trueFGold = ref(0)
//
const formattedTrueGold = computed(() => trueGold.value.toFixed(2))
const formattedTrueRGold = computed(() => trueRGold.value.toFixed(2))
const formattedTrueFGold = computed(() => trueFGold.value.toFixed(2))
//
const pendingCount = ref(0)
//
const pendingGold = ref(0)
const pendingRGold = ref(0)
const pendingFGold = ref(0)
//
const approvedCount = ref(0)
//
const approvedGold = ref(0)
const approvedRGold = ref(0)
const approvedFGold = ref(0)
//
const rejectedCount = ref(0)
//
const rejectedGold = ref(0)
const rejectedRGold = ref(0)
const rejectedFGold = ref(0)
// ==============================================================
//
const get = async function (val) {
try {
//
if (adminData.value.area === '泰国') {
rechargeVo.value.areas = ['泰国', '越南']
} else if (adminData.value.area !== '总部') {
rechargeVo.value.area = adminData.value.area
}
//
if (typeof val === 'number') {
getObj.value.pageNum = val
}
//
if (getTime.value != null) {
if (getTime.value.startDate != '' && getTime.value.endDate != '') {
rechargeVo.value.startDate = getTime.value[0]
rechargeVo.value.endDate = getTime.value[1]
}
} else {
rechargeVo.value.startDate = ''
rechargeVo.value.endDate = ''
}
rechargeVo.value.sortField = sortField.value
rechargeVo.value.sortOrder = sortOrder.value
console.log('搜索参数', getObj.value)
// POST
const result = await request({
url: '/recharge/recharge',
data: {
pageNum: getObj.value.pageNum,
pageSize: getObj.value.pageSize,
rechargeVo: { ...rechargeVo.value }
}
})
//
// rechargeVo.value
const detailWithoutSort = { ...rechargeVo.value }
delete detailWithoutSort.sortField
delete detailWithoutSort.sortOrder
delete detailWithoutSort.status
const result2 = await request({
url: '/recharge/recharge/RechargeA',
data: detailWithoutSort
})
// result2.data[i].flag="" totalData.value = result2.data[i]0
//
if (result2.data) {
result2.data.forEach((item) => {
switch (item.auditStatus) {
case '待审核':
// item.raudit 0
pendingCount.value = item.raudit || 0
// item.sumRaudit 0
pendingGold.value = item.sumRaudit || 0
pendingRGold.value = item.sumRaudit1 || 0
pendingFGold.value = item.sumRaudit2 || 0
break
case '已通过':
approvedCount.value = item.raudit || 0
approvedGold.value = item.sumRaudit || 0
approvedRGold.value = item.sumRaudit1 || 0
approvedFGold.value = item.sumRaudit2 || 0
break
case '已驳回':
rejectedCount.value = item.raudit || 0
rejectedGold.value = item.sumRaudit || 0
rejectedRGold.value = item.sumRaudit1 || 0
rejectedFGold.value = item.sumRaudit2 || 0
break
}
})
}
trueGold.value = pendingGold.value + approvedGold.value + rejectedGold.value
trueCount.value =
pendingCount.value + approvedCount.value + rejectedCount.value
trueRGold.value =
pendingRGold.value + approvedRGold.value + rejectedRGold.value
trueFGold.value =
pendingFGold.value + approvedFGold.value + rejectedFGold.value
//
console.log('请求成功', result)
console.log('这是分页', getObj.value)
//
tableData.value = result.data.list
console.log('tableData', tableData.value)
//
total.value = result.data.total
console.log('total', total.value)
} catch (error) {
console.log('请求失败', error)
//
}
}
//
const search = function () {
trimJwCode();
getObj.value.pageNum = 1
get()
}
//
const reset = function () {
delete rechargeVo.value.activityId
delete rechargeVo.value.jwcode
delete rechargeVo.value.payWay
delete rechargeVo.value.area
delete rechargeVo.value.startDate
delete rechargeVo.value.endDate
getTime.value = {}
}
//
const getToday = function () {
const today = new Date()
const startDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate()
)
const endDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() + 1
)
getTime.value = [startDate, endDate]
console.log('getTime', getTime.value)
get()
}
//
const getYesterday = function () {
const yesterday = new Date()
yesterday.setDate(yesterday.getDate() - 1)
const startDate = new Date(
yesterday.getFullYear(),
yesterday.getMonth(),
yesterday.getDate()
)
const endDate = new Date(
yesterday.getFullYear(),
yesterday.getMonth(),
yesterday.getDate() + 1
)
getTime.value = [startDate, endDate]
console.log('getTime', getTime.value)
get()
}
// 7
const get7Days = function () {
const today = new Date()
const startDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() - 6
)
const endDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() + 1
)
getTime.value = [startDate, endDate]
console.log('getTime', getTime.value)
get()
}
//
const adminAll = function () {
console.log('adminAll')
rechargeVo.value.status = ''
getObj.value.pageNum = 1
get()
}
//
const adminWait = async function () {
rechargeVo.value.status = 0
getObj.value.pageNum = 1
await get()
console.log('adminWait')
trueCount.value = pendingCount.value
trueGold.value = pendingGold.value
trueRGold.value = pendingRGold.value
trueFGold.value = pendingFGold.value
}
//
const adminPass = async function () {
rechargeVo.value.status = 1
getObj.value.pageNum = 1
await get()
console.log('adminPass')
trueCount.value = approvedCount.value
trueGold.value = approvedGold.value
trueRGold.value = approvedRGold.value
trueFGold.value = approvedFGold.value
}
//
const adminReject = async function () {
rechargeVo.value.status = 2
getObj.value.pageNum = 1
await get()
console.log('adminReject')
trueCount.value = rejectedCount.value
trueGold.value = rejectedGold.value
trueRGold.value = rejectedRGold.value
trueFGold.value = rejectedFGold.value
}
//
const handleClick = function (tab, event) {
if (tab.props.name === 'all') {
adminAll()
} else if (tab.props.name === 'wait') {
adminWait()
} else if (tab.props.name === 'pass') {
adminPass()
} else if (tab.props.name === 'reject') {
adminReject()
}
}
//
const getActivity = async function () {
try {
// POST
const result = await request({
url: '/recharge/activity/select',
data: {}
})
//
console.log('请求成功', result)
//
activity.value = result.data
console.log('activity', activity.value)
} catch (error) {
console.log('请求失败', error)
//
}
}
//
const getArea = async function () {
try {
// POST
const result = await request({
url: '/recharge/user/search',
data: {}
})
//
console.log('请求成功', result)
//
area.value = result.data
console.log('地区', area.value)
} catch (error) {
console.log('请求失败', error)
//
}
}
//
const checkNumber = function () {
if (typeof parseInt(getObj.value.pageNum) === 'number') {
console.log('总共有多少页' + Math.ceil(total.value / getObj.value.pageSize))
if (
getObj.value.pageNum > 0 &&
getObj.value.pageNum <= Math.ceil(total.value / getObj.value.pageSize)
) {
console.log('输入的数字合法')
getObj.value.pageNum = parseInt(getObj.value.pageNum)
get()
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
}
const handlePageSizeChange = function (val) {
getObj.value.pageSize = val
get()
}
const handleCurrentChange = function (val) {
getObj.value.pageNum = val
get()
}
// ====================================
//
const pass = function (row) {
//
passObj.value = row
passObj.value.adminId = adminData.value.adminId
passObj.value.auditId = row.auditId
// passObj.value.status = 1
passObj.value.rechargeId = row.rechargeId
passObj.value.detailId = row.detailId
passObj.value.jwcode = row.jwcode
passObj.value.paidGold = row.paidGold
passObj.value.freeGold = row.freeGold
passObj.value.adminName = adminData.value.adminName
console.log('通过对象', passObj.value)
}
//
const passConfirm = async function () {
try {
//
passObj.value.status = 1
console.log('通过对象', passObj.value)
// POST
// passObj.value.flag = 0;
const result = await request({
url: '/audit/audit/goldedit',
data: passObj.value
})
//
console.log('请求成功', result)
//
get()
//
ElMessage({
type: 'success',
message: '通过成功!'
})
} catch (error) {
console.error('请求失败', error);
ElMessage({
type: 'error',
message: '出错了,不知道咋回事'
});
}
}
//
const openRejectVisible = function () {
rejectVisible.value = true
}
//
const closeRejectVisible = function () {
rejectVisible.value = false
}
//
const reject = function (row) {
//
rejectObj.value.adminId = adminData.value.adminId
rejectObj.value.auditId = row.auditId
rejectObj.value.status = 2
rejectObj.value.reson = ''
rejectObj.value.rechargeId = row.rechargeId
rejectObj.value.detailId = row.detailId
console.log('驳回对象', rejectObj.value)
openRejectVisible()
}
//
const rejectConfirm = async function () {
Ref.value.validate(async (valid) => {
if (valid) {
try {
console.log('驳回对象', rejectObj.value)
// POST
const result = await request({
url: '/audit/audit/goldedit',
data: rejectObj.value
})
//
console.log('请求成功', result)
//
get()
//
closeRejectVisible()
//
ElMessage({
type: 'success',
message: '驳回成功!'
})
} catch (error) {
console.log('请求失败', error)
//
}
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
})
}
//
const rules = reactive({
reson: [{ required: true, message: '请输入驳回理由', trigger: 'blur' }]
})
//
onMounted(async function () {
await getAdminData()
await getActivity()
await get()
await getArea()
})
//
const sortField = ref('')
const sortOrder = ref('')
//
const handleSortChange = (column) => {
console.log('排序字段:', column.prop)
console.log('排序方式:', column.order)
if (column.prop === 'rechargeGold') {
sortField.value = 'recharge_gold'
} else if (column.prop === 'freeGold') {
sortField.value = 'free_gold'
} else if (column.prop === 'rechargeTime') {
sortField.value = 'recharge_time'
} else if (column.prop === 'createTime') {
sortField.value = 'create_time'
} else if (column.prop === 'paidGold') {
sortField.value = 'paid_gold'
}else if (column.prop === 'auditTime') {
sortField.value = 'audit_time'
}
sortOrder.value = column.order === 'ascending' ? 'ASC' : 'DESC'
get()
}
//
const trimJwCode = () => {
if (rechargeVo.value.jwcode) {
rechargeVo.value.jwcode = rechargeVo.value.jwcode.replace(/\s/g, '');
}
}
</script>
<template>
<el-row>
<el-col>
<el-card style="margin-bottom: 20px">
<el-row style="margin-bottom: 10px">
<el-col :span="6">
<div class="head-card-element">
<el-text class="mx-1" size="large">精网号</el-text>
<el-input v-model="rechargeVo.jwcode" placeholder="请输入精网号" style="width: 240px" clearable />
</div>
</el-col>
<el-col :span="6">
<div class="head-card-element">
<el-text class="mx-1" size="large">活动名称</el-text>
<el-select v-model="rechargeVo.activityId" placeholder="请选择活动名称" style="width: 240px"
clearable>
<el-option v-for="item in activity" :key="item.activityId" :label="item.activityName"
:value="item.activityId" />
</el-select>
</div>
</el-col>
<el-col :span="6">
<div class="head-card-element">
<el-text class="mx-1" size="large">支付方式</el-text>
<el-select v-model="rechargeVo.payWay" placeholder="请选择支付方式" style="width: 240px" clearable>
<el-option v-for="item in payWay" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
</el-col>
<el-col :span="6">
<div class="head-card-element" v-if="adminData.area == '总部'">
<el-text class="mx-1" size="large">所属地区</el-text>
<el-select v-model="rechargeVo.area" placeholder="请选择所属地区" style="width: 240px" clearable>
<el-option v-for="item in area" :key="item" :label="item" :value="item" />
</el-select>
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="16">
<div class="time-controls">
<div class="time-group">
<el-text class="mx-1" size="large">充值时间</el-text>
<el-date-picker
v-model="getTime"
type="datetimerange"
range-separator="至"
start-placeholder="起始时间"
end-placeholder="结束时间"
style="width: 400px"
/>
<el-button @click="getToday()" style="margin-left: 10px"> </el-button>
<el-button @click="getYesterday()" style="margin-left: 10px"> </el-button>
<el-button @click="get7Days()" style="margin-left: 10px"> 近7天 </el-button>
</div>
</div>
</el-col>
<el-col :span="8">
<el-button @click="reset()" type="success" style="margin-right: 10px">重置</el-button>
<el-button type="primary" @click="search()">查询</el-button>
</el-col>
</el-row>
<el-row>
<el-col :span="21">
<div style="margin-top: 10px">
<el-text class="mx-1" size="large">请选择您想看到的数据</el-text>
<el-select v-model="selectedColumns" multiple placeholder="请选择您想看到的数据" size="large" style="width: 800px">
<el-option v-for="item in columnOptions" :key="item.prop" :label="item.label" :value="item.prop" />
</el-select>
</div>
</el-col>
</el-row>
</el-card>
</el-col>
</el-row>
<el-row>
<el-col>
<el-card>
<el-tabs v-model="activeName" type="card" class="demo-tabs" @tab-click="handleClick">
<el-tab-pane label="全部" name="all"></el-tab-pane>
<el-tab-pane label="待审核" name="wait"></el-tab-pane>
<el-tab-pane label="已通过" name="pass"></el-tab-pane>
<el-tab-pane label="已驳回" name="reject"></el-tab-pane>
<div>
总条数{{ trueCount }}总金币数{{
formattedTrueGold
}}金币永久金币{{ formattedTrueRGold }}金币免费金币{{ formattedTrueFGold }}金币
</div>
</el-tabs>
<div style="height: 540px; overflow-y: auto">
<el-table :data="tableData" style="width: 100%" height="540px" @sort-change="handleSortChange" :row-style="{ height: '50px' }">
<el-table-column type="index" label="序号" width="100px" fixed="left">
<template #default="scope">
<span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template>
</el-table-column>
<!-- 动态列 -->
<template v-for="col in columnOptions" :key="col.prop">
<el-table-column v-if="selectedColumns.includes(col.prop)" :prop="col.prop" :label="col.label"
:width="col.width" :sortable="col.sortable ? 'custom' : false"
:show-overflow-tooltip="true" >
<template #default="scope">
<!-- 特殊列模板 -->
<template v-if="col.prop === 'rechargeTime'">
{{ moment(scope.row.rechargeTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
<template v-else-if="col.prop === 'createTime'">
{{ moment(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
<template v-else-if="col.prop === 'auditTime'">
{{ scope.row.auditTime ? moment(scope.row.auditTime).format('YYYY-MM-DD HH:mm:ss') : '----' }}
</template>
<template v-else-if="col.prop === 'remark'">
<span>{{ scope.row[col.prop] }}</span>
</template>
<template v-else-if="col.prop === 'rechargeVoucher'">
<el-image :src="scope.row.rechargeVoucher" style="width: 50px; height: 50px" />
</template>
<template v-else-if="col.prop === 'status'">
<div class="status">
<span :class="{
'green-dot': scope.row.status === 1,
'grey-dot': scope.row.status === 0,
'red-dot': scope.row.status === 2
}"></span>
<span>{{
scope.row.status === 1 ? '已通过' :
scope.row.status === 0 ? '待审核' : '已驳回'
}}</span>
</div>
</template>
<template v-else-if="['paidGold', 'freeGold'].includes(col.prop)">
{{ scope.row[col.prop] / 100 }}
</template>
<span v-else>
{{ scope.row[col.prop] }}
</span>
</template>
</el-table-column>
</template>
<el-table-column fixed="right" prop="operation" label="操作" width="150px">
<template #default="scope">
<div class="operation">
<el-popconfirm title="确定要通过此条记录吗?" @confirm="passConfirm">
<template #reference>
<el-button :disabled="scope.row.status === 1 || scope.row.status === 2
? true
: false
" type="primary" text @click="pass(scope.row)">
通过
</el-button>
</template>
<template #actions="{ confirm, cancel }">
<el-button size="small" @click="cancel">取消</el-button>
<el-button type="primary" size="small" @click="confirm">
确定
</el-button>
</template>
</el-popconfirm>
<el-button :disabled="scope.row.status === 1 || scope.row.status === 2
? true
: false
" type="primary" text @click="reject(scope.row)">
驳回
</el-button>
</div>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页 -->
<div class="pagination">
<el-pagination background :page-size="getObj.pageSize" :page-sizes="[5, 10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handlePageSizeChange"
@current-change="handleCurrentChange"></el-pagination>
</div>
</el-card>
</el-col>
</el-row>
<!-- 驳回弹出框 -->
<el-dialog v-model="rejectVisible" title="驳回理由" width="500" :before-close="closeRejectVisible">
<template #footer>
<el-form :model="rejectObj" ref="Ref" :rules="rules" label-width="auto" style="max-width: 600px">
<el-form-item prop="reson" label="驳回理由:">
<el-input v-model="rejectObj.reson" maxlength="150" show-word-limit style="width: 350px" type="textarea"
placeholder="请输入内容" />
</el-form-item>
</el-form>
<div class="dialog-footer">
<el-button @click="closeRejectVisible()">取消</el-button>
<el-button type="primary" @click="rejectConfirm()"> 确定 </el-button>
</div>
</template>
</el-dialog>
</template>
<style scoped>
.pagination {
display: flex;
}
.operation {
display: flex;
}
.green-dot {
background-color: #67C23A;
}
.grey-dot {
background-color: #909399;
}
.red-dot {
background-color: #F56C6C;
}
.time-controls {
display: flex;
align-items: center;
}
.time-group {
display: flex;
align-items: center;
gap: 10px;
}
.quick-buttons {
display: flex;
align-items: center;
}
.status {
display: flex;
align-items: center; /* 确保子元素垂直居中对齐 */
gap: 6px; /* 设置圆点和文字之间的间距 */
}
.green-dot, .grey-dot, .red-dot {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
flex-shrink: 0; /* 防止圆点在空间不足时缩小 */
margin: 0; /* 移除原有的 margin-right */
}
/* 备注列样式 */
.remark-cell {
display: block;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* 设置单元格内容溢出隐藏 */
.el-table .el-table__cell {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>

889
src/views/audit/refundAudit.vue

@ -0,0 +1,889 @@
<script setup>
import { ref, onMounted, reactive, computed } from 'vue'
import ElementPlus from 'element-plus'
import request from '@/util/http'
import { ElMessage, ElMessageBox } from 'element-plus'
import { AiFillRead } from 'vue-icons-plus/ai'
import axios from 'axios'
import moment from 'moment'
import API from '../../api/index.js'
//
//
const admin = ref({
adminId: 1,
name: '赵刚',
area: '中国'
})
//
const adminData = ref({})
const getAdminData = async function () {
try {
const result = await request({
url: '/admin/userinfo',
data: {}
})
adminData.value = result
console.log('请求成功', result)
console.log('用户信息', adminData.value)
} catch (error) {
console.log('请求失败', error)
}
}
//
const tableData = ref([])
// ======================================
// detail
const detail = ref({})
//
const getObj = ref({
pageNum: 1,
pageSize: 50
})
//
const total = ref(100)
//
const getTime = ref([])
//
const product = ref([])
//
const allData = ref([])
//
const area = ref([])
// ======================================
//
const rejectVisible = ref(false)
//
const rejectObj = ref({})
//
const passObj = ref({})
//
const activeName = ref('all')
// 退
const refundType = [
{
value: '退款商品',
label: '退款商品'
}
]
// //
// const tableHeight = computed(function () {
// return (getObj.value.pageSize + 1) * 50 + "px";
// });
// ref
const Ref = ref(null)
//
//
//
const trueGold = ref(0)
const trueCount = ref(0)
//
const pendingCount = ref(0)
//
const pendingGold = ref(0)
//
const approvedCount = ref(0)
//
const approvedGold = ref(0)
//
const rejectedCount = ref(0)
//
const rejectedGold = ref(0)
// ==================================================================
//
const get = async function (val) {
try {
//
if (adminData.value.area === '泰国') {
rechargeVo.value.areas = ['泰国', '越南']
} else if (adminData.value.area !== '总部') {
rechargeVo.value.area = adminData.value.area
}
//
if (typeof val === 'number') {
getObj.value.pageNum = val
}
//
if (getTime.value != null) {
if (getTime.value.startDate != '' && getTime.value.endDate != '') {
detail.value.startDate = getTime.value[0]
detail.value.endDate = getTime.value[1]
}
} else {
detail.value.startDate = ''
detail.value.endDate = ''
}
detail.value.sortField = sortField.value
detail.value.sortOrder = sortOrder.value
console.log('搜索参数', getObj.value)
// POST
const result = await request({
url: '/audit/audit/refund',
data: {
pageNum: getObj.value.pageNum,
pageSize: getObj.value.pageSize,
detail: {
...detail.value
}
}
})
const detailWithoutSort = { ...detail.value }
delete detailWithoutSort.sortField
delete detailWithoutSort.sortOrder
const result2 = await request({
url: '/refund/RefundA',
data: detailWithoutSort
})
//
if (result2.data) {
result2.data.forEach((item) => {
switch (item.status) {
case '待审核':
// item.raudit 0
pendingCount.value = item.raudit || 0
// item.sumRaudit 0
pendingGold.value = item.sumRaudit || 0
break
case '已通过':
approvedCount.value = item.raudit || 0
approvedGold.value = item.sumRaudit || 0
break
case '已驳回':
rejectedCount.value = item.raudit || 0
rejectedGold.value = item.sumRaudit || 0
break
}
})
}
trueGold.value = pendingGold.value + approvedGold.value + rejectedGold.value
trueCount.value =
pendingCount.value + approvedCount.value + rejectedCount.value
//
console.log('请求成功', result)
//
tableData.value = result.data.list
console.log('tableData', tableData.value)
//
total.value = result.data.total
console.log('total', total.value)
} catch (error) {
console.log('请求失败', error)
//
}
}
//
const search = function () {
trimJwCode();
getObj.value.pageNum = 1
get()
}
//
const reset = function () {
detail.value.area = ''
detail.value.jwcode = ''
detail.value.refundType = ''
detail.value.refundGoods = ''
detail.value.startDate = ''
detail.value.endDate = ''
sortField.value = ''
sortOrder.value = ''
getTime.value = {}
}
//
const getToday = function () {
const today = new Date()
const startDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate()
)
const endDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() + 1
)
getTime.value = [startDate, endDate]
console.log('getTime', getTime.value)
get()
}
//
const getYesterday = function () {
const yesterday = new Date()
yesterday.setDate(yesterday.getDate() - 1)
const startDate = new Date(
yesterday.getFullYear(),
yesterday.getMonth(),
yesterday.getDate()
)
const endDate = new Date(
yesterday.getFullYear(),
yesterday.getMonth(),
yesterday.getDate() + 1
)
getTime.value = [startDate, endDate]
console.log('getTime', getTime.value)
get()
}
// 7
const get7Days = function () {
const today = new Date()
const startDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() - 6
)
const endDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() + 1
)
getTime.value = [startDate, endDate]
console.log('getTime', getTime.value)
get()
}
//
const adminAll = function () {
console.log('adminAll')
detail.value.status = ''
getObj.value.pageNum = 1
get()
}
//
const adminWait = async function () {
detail.value.status = 0
getObj.value.pageNum = 1
await get()
console.log('adminWait')
trueGold.value = pendingGold.value
trueCount.value = pendingCount.value
}
//
const adminPass = async function () {
detail.value.status = 1
getObj.value.pageNum = 1
await get()
console.log('adminPass')
trueGold.value = approvedGold.value
trueCount.value = approvedCount.value
}
//
const adminReject = async function () {
detail.value.status = 2
getObj.value.pageNum = 1
await get()
console.log('adminReject')
trueGold.value = rejectedGold.value
trueCount.value = rejectedCount.value
}
//
const handleClick = function (tab, event) {
if (tab.props.name === 'all') {
adminAll()
} else if (tab.props.name === 'wait') {
adminWait()
} else if (tab.props.name === 'pass') {
adminPass()
} else if (tab.props.name === 'reject') {
adminReject()
}
}
//
const getProduct = async function () {
try {
// POST
const result = await request({
url: '/product',
data: {}
})
//
console.log('请求成功', result)
//
product.value = result.data
console.log('产品', product.value)
} catch (error) {
console.log('请求失败', error)
//
}
}
//
const getArea = async function () {
try {
// POST
const result = await request({
url: '/recharge/user/search',
data: {}
})
//
console.log('请求成功', result)
//
area.value = result.data
console.log('地区', area.value)
} catch (error) {
console.log('请求失败', error)
//
}
}
//
const checkNumber = function () {
if (typeof parseInt(getObj.value.pageNum) === 'number') {
console.log('总共有多少页' + Math.ceil(total.value / getObj.value.pageSize))
if (
getObj.value.pageNum > 0 &&
getObj.value.pageNum <= Math.ceil(total.value / getObj.value.pageSize)
) {
getObj.value.pageNum = parseInt(getObj.value.pageNum)
console.log('输入的数字合法')
get()
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
}
// ====================================
//
const pass = function (row) {
//
passObj.value.adminId = adminData.value.adminId
passObj.value.auditId = row.auditId
passObj.value.status = 1
passObj.value.refundId = row.refundId
passObj.value.adminName = row.adminName
passObj.value.username = row.username
passObj.value.area = row.area
console.log('通过对象', passObj.value)
}
//
const passConfirm = async function () {
try {
console.log('通过对象', passObj.value)
// POST
const result = await request({
url: '/audit/audit/edit',
data: passObj.value
})
//
console.log('请求成功', result)
//
get()
//
ElMessage({
type: 'success',
message: '通过成功!'
})
} catch (error) {
console.log('请求失败', error)
//
}
}
//
const openRejectVisible = function () {
rejectVisible.value = true
}
//
const closeRejectVisible = function () {
rejectVisible.value = false
}
//
const reject = function (row) {
//
rejectObj.value.adminId = adminData.value.adminId
rejectObj.value.auditId = row.auditId
rejectObj.value.status = 2
rejectObj.value.reson = ''
rejectObj.value.refundId = row.refundId
console.log('驳回对象', rejectObj.value)
openRejectVisible()
}
//
const rejectConfirm = async function () {
Ref.value.validate(async (valid) => {
if (valid) {
try {
console.log('驳回对象', rejectObj.value)
// POST
const result = await request({
url: '/audit/audit/edit',
data: rejectObj.value
})
//
console.log('请求成功', result)
//
get()
//
closeRejectVisible()
//
ElMessage({
type: 'success',
message: '驳回成功!'
})
} catch (error) {
console.log('请求失败', error)
//
}
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
})
}
const handlePageSizeChange = function (val) {
getObj.value.pageSize = val
get()
}
const handleCurrentChange = function (val) {
getObj.value.pageNum = val
get()
}
//
const rules = reactive({
reson: [{ required: true, message: '请输入驳回理由', trigger: 'blur' }]
})
//
onMounted(async function () {
await getAdminData()
await get()
getProduct()
await getArea()
await getArea()
})
//
const sortField = ref('')
const sortOrder = ref('')
//
const handleSortChange = (column) => {
console.log('排序字段:', column.prop)
console.log('排序方式:', column.order)
if (column.prop === 'rechargeCoin') {
sortField.value = 'recharge_coin'
} else if (column.prop === 'taskCoin') {
sortField.value = 'task_coin'
} else if (column.prop === 'freeCoin') {
sortField.value = 'free_coin'
} else if (column.prop === 'createTime') {
sortField.value = 'create_time'
}
sortOrder.value = column.order === 'ascending' ? 'ASC' : 'DESC'
get()
}
//
const trimJwCode = () => {
if (detail.value.jwcode) {
// 使
detail.value.jwcode = detail.value.jwcode.replace(/\s/g, '');
}
}
</script>
<template>
<el-row>
<el-col>
<el-card style="margin-bottom: 20px">
<el-row style="margin-bottom: 10px">
<el-col :span="6">
<div class="head-card-element">
<el-text class="mx-1" size="large">精网号</el-text>
<el-input
v-model="detail.jwcode"
placeholder="请输入精网号"
size="large"
style="width: 240px"
clearable
/>
</div>
</el-col>
<el-col :span="6">
<div class="head-card-element">
<el-text class="mx-1" size="large">退款类型</el-text>
<el-select
v-model="detail.refundType"
placeholder="请选择退款类型"
size="large"
style="width: 240px"
clearable
>
<el-option
v-for="item in refundType"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</el-col>
<el-col :span="6">
<div class="head-card-element">
<el-text class="mx-1" size="large">退款商品</el-text>
<el-select
v-model="detail.refundGoods"
placeholder="请选择退款商品"
size="large"
style="width: 240px"
clearable
>
<el-option
v-for="item in product"
:key="item.name"
:label="item.name"
:value="item.name"
/>
</el-select>
</div>
</el-col>
<el-col :span="6">
<div class="head-card-element" v-if="adminData.area == '总部'">
<el-text class="mx-1" size="large">所属地区</el-text>
<el-select
v-model="detail.area"
placeholder="请选择所属地区"
size="large"
style="width: 240px"
clearable
>
<el-option
v-for="item in area"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="21">
<div class="head-card-element">
<el-text class="mx-1" size="large">退款时间</el-text>
<el-date-picker
v-model="getTime"
type="datetimerange"
range-separator="至"
start-placeholder="起始时间"
end-placeholder="结束时间"
/>
<el-button style="margin-left: 10px" @click="getToday()"
></el-button
>
<el-button @click="getYesterday()"></el-button>
<el-button @click="get7Days()">近7天</el-button>
</div>
</el-col>
<el-col :span="3">
<div class="head-card-btn">
<el-button type="success" @click="reset()">重置</el-button>
<el-button type="primary" @click="search()">查询</el-button>
</div>
</el-col>
</el-row>
</el-card>
</el-col>
</el-row>
<el-row>
<el-col>
<el-card>
<el-tabs
v-model="activeName"
type="card"
class="demo-tabs"
@tab-click="handleClick"
>
<el-tab-pane label="全部" name="all"></el-tab-pane>
<el-tab-pane label="待审核" name="wait"></el-tab-pane>
<el-tab-pane label="已通过" name="pass"></el-tab-pane>
<el-tab-pane label="已驳回" name="reject"></el-tab-pane>
<div>
退款记录条数{{ Math.abs(trueCount) }},退款金币总数{{
Math.abs(trueGold)
}}
</div>
</el-tabs>
<!-- 设置表格容器的高度和滚动样式 -->
<div style="height: 540px; overflow-y: auto">
<el-table
:data="tableData"
style="width: 100%"
height="540px"
@sort-change="handleSortChange"
>
<el-table-column
type="index"
label="序号"
width="100px"
fixed="left"
>
<template #default="scope">
<span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template>
</el-table-column>
<el-table-column
fixed="left"
prop="username"
label="姓名"
width="150px"
/>
<el-table-column
fixed="left"
prop="jwcode"
label="精网号"
width="110px"
/>
<el-table-column prop="area" label="所属地区" width="100px" />
<el-table-column prop="refundType" label="退款类型" width="100px" />
<el-table-column
prop="refundGoods"
label="退款商品"
width="200px"
/>
<el-table-column prop="refundCoin" label="退款金币数" width="100px">
<template #default="scope">
<span>{{
scope.row.rechargeCoin +
scope.row.freeCoin +
scope.row.taskCoin
}}</span>
</template>
</el-table-column>
<el-table-column
prop="rechargeCoin"
label="永久金币"
width="110px"
sortable="“custom”"
>
<template #default="scope">
{{ scope.row.rechargeCoin }}
</template>
</el-table-column>
<el-table-column
prop="freeCoin"
label="免费金币"
sortable="“custom”"
width="110px"
>
<template #default="scope">
{{ scope.row.freeCoin }}
</template>
</el-table-column>
<el-table-column
prop="taskCoin"
label="任务金币"
sortable="“custom”"
width="110px"
>
<template #default="scope">
{{ scope.row.taskCoin }}
</template>
</el-table-column>
<el-table-column
prop="remark"
label="备注"
width="200px"
show-overflow-tooltip
/>
<el-table-column prop="adminName" label="提交人" width="100px" />
<el-table-column prop="status" label="审核状态" width="100px">
<!-- 模板内容 -->
<template #default="scope">
<span v-if="scope.row.status == 1">
<div class="status">
<span class="green-dot"></span>
<span>已通过</span>
</div>
</span>
<span v-if="scope.row.status == 0">
<div class="status">
<span class="grey-dot"></span>
<span>待审核</span>
</div>
</span>
<span v-if="scope.row.status == 2">
<div class="status">
<span class="red-dot"></span>
<span>已驳回</span>
</div>
</span>
</template>
</el-table-column>
<el-table-column
prop="reson"
label="驳回理由"
width="200px"
show-overflow-tooltip
/>
<el-table-column
prop="createTime"
sortable="“custom”"
label="提交时间"
width="200px"
>
<template #default="scope">
{{ moment(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column
prop="auditTime"
sortable="custom"
label="审核时间"
width="200px"
>
<template #default="scope">
{{scope.row.auditTime ? moment(scope.row.auditTime).format('YYYY-MM-DD HH:mm:ss') : '------'}}
</template>
</el-table-column>
<el-table-column
fixed="right"
prop="operation"
label="操作"
width="150px"
>
<template #default="scope">
<div class="operation">
<el-popconfirm
title="确定要通过此条记录吗?"
@confirm="passConfirm"
>
<template #reference>
<el-button
:disabled="
scope.row.status === 1 || scope.row.status === 2
? true
: false
"
type="primary"
text
@click="pass(scope.row)"
>
通过
</el-button>
</template>
<template #actions="{ confirm, cancel }">
<el-button size="small" @click="cancel">取消</el-button>
<el-button type="primary" size="small" @click="confirm">
确定
</el-button>
</template>
</el-popconfirm>
<el-button
:disabled="
scope.row.status === 1 || scope.row.status === 2
? true
: false
"
type="primary"
text
@click="reject(scope.row)"
>
驳回
</el-button>
</div>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页 -->
<div class="pagination">
<el-pagination
background
:page-size="getObj.pageSize"
:page-sizes="[5, 10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handlePageSizeChange"
@current-change="handleCurrentChange"
></el-pagination>
</div>
</el-card>
</el-col>
</el-row>
<!-- 驳回弹出框 -->
<el-dialog
v-model="rejectVisible"
title="驳回理由"
width="500"
:before-close="closeRejectVisible"
>
<template #footer>
<el-form
:model="rejectObj"
ref="Ref"
:rules="rules"
label-width="auto"
style="max-width: 600px"
>
<el-form-item prop="reson" label="驳回理由:">
<el-input
v-model="rejectObj.reson"
maxlength="150"
show-word-limit
style="width: 350px"
type="textarea"
placeholder="请输入内容"
/>
</el-form-item>
</el-form>
<div class="dialog-footer">
<el-button @click="closeRejectVisible()">取消</el-button>
<el-button type="primary" @click="rejectConfirm()"> 确定 </el-button>
</div>
</template>
</el-dialog>
</template>
<style scoped>
.pagination {
display: flex;
}
.status {
display: flex;
}
.operation {
display: flex;
}
.head-card {
display: flex;
}
.head-card-element {
margin-right: 20px;
}
.head-card-btn {
margin-left: auto;
}
</style>

690
src/views/consume/addConsume.vue

@ -0,0 +1,690 @@
<script setup>
import { reactive, onMounted } from "vue";
import { ref, computed, watch } from "vue";
import { ElMessage } from "element-plus";
import { Plus } from "@element-plus/icons-vue";
import axios from "axios";
import { ElMessageBox } from "element-plus";
import API from "../../api/index.js";
import moment from "moment";
import _ from "lodash";
import request from "@/util/http";
//
const trimJwCode = () => {
if (addConsume.value.jwcode) {
addConsume.value.jwcode = addConsume.value.jwcode.replace(/\s/g, '');
}
}
//
const adminData = ref({});
const getAdminData = async function () {
try {
const result = await request({
url: "/admin/userinfo",
data: {},
});
adminData.value = result;
addConsume.value.adminId = adminData.value.adminId;
addConsume.value.name = adminData.value.name;
console.log("请求成功", result);
console.log("用户信息", adminData.value);
} catch (error) {
console.log("请求失败", error);
}
};
//
const addConsume = ref({
freeCoin: 0,
rechargeCoin: 0,
taskCoin: 0,
updateType: "1",
indexName:"", //
});
//
const add = async function () {
try {
// 使
addConsume.value.rechargeCoin = Number(addConsume.value.rechargeCoin * 100);
addConsume.value.freeCoin = Number(addConsume.value.freeCoin * 100);
addConsume.value.taskCoin = Number(addConsume.value.taskCoin * 100);
addConsume.value.productName = indexs.value.productName;
// POST
const result = await request({
url: "/consume/add",
data: addConsume.value,
});
if (result.code === 0) {
ElMessage.error(result.msg);
return;
} else {
ElMessage.success("添加成功");
}
//
addConsume.value = {};
addConsume.value.adminId = adminData.value.adminId;
addConsume.value.adminName = adminData.value.adminName;
addConsume.value.updateType = "1";
addConsume.value.freeCoin = 0;
addConsume.value.rechargeCoin = 0;
addConsume.value.taskCoin = 0;
indexs.value = {};
console.log("请求成功", result);
user.value = {};
} catch (error) {
console.log("请求失败", error);
ElMessage.error("添加失败,请检查输入内容是否正确");
//
}
};
const addBefore = () => {
Ref.value.validate(async (valid) => {
if (valid) {
ElMessageBox.confirm("确认添加?")
.then(() => {
addConsume.value.freeCoin = Number(-addConsume.value.freeCoin);
addConsume.value.rechargeCoin = Number(
-addConsume.value.rechargeCoin
);
addConsume.value.taskCoin = Number(-addConsume.value.taskCoin);
add();
console.log("添加成功");
imageUrl.value = "";
addConsume.value = {};
})
.catch(() => {
console.log("取消添加");
});
} else {
//
ElMessage({
type: "error",
message: "请检查输入内容",
});
}
});
};
//
//
const Ref = ref(null);
const checkFreeGoldRadio = function (rule, value, callback) {
if (value == "0" || value == null || value == "") {
callback(new Error("请输入消费金币总数"));
} else if (value < 0 || isNaN(value)) {
callback(new Error("请输入正确的格式"));
} else {
callback();
}
};
const rules = reactive({
jwcode: [{ required: true, message: "请输入精网号", trigger: "blur" }],
productName: [{ required: true, message: "请选择消费商品", trigger: "change" }], // change
taskCoin: [{ required: true, message: "请输入任务金币", trigger: "blur" }],
freeCoin: [{ required: true, message: "请输入免费金币", trigger: "blur" }],
rechargeCoin: [
{ required: true, message: "请输入免费金币", trigger: "blur" },
],
allGold: [
{ required: true, message: "消费金币总数不能为空", trigger: "blur" },
{ validator: checkFreeGoldRadio, trigger: "blur" },
],
indexName: [
{
required: true,
validator: (rule, value, callback) => {
if (isHC.value === 1 && !value) {
callback(new Error("请选择指标"));
} else {
callback();
}
},
trigger: ["change", "blur"],
},
]
});
//
const delteConsume = function () {
addConsume.value = {};
addConsume.value.adminId = adminData.value.adminId;
addConsume.value.adminName = adminData.value.adminName;
addConsume.value.updateType = "1";
addConsume.value.freeCoin = 0;
addConsume.value.rechargeCoin = 0;
addConsume.value.taskCoin = 0;
indexs.value = {};
isHC.value = 0;
};
//
const user = ref({
firstRechargeTime: "",
});
const getUser = async function (jwcode) {
trimJwCode();
try {
// POST
const result = await request({
url: "/recharge/user",
data: {
jwcode: addConsume.value.jwcode,
area: adminData.value.area,
},
});
console.log("请求成功", result);
if (result.code === 0) {
ElMessage.error(result.msg);
} else {
user.value = result.data;
user.value.A =
Number(user.value.pendingRechargeTimes) +
Number(user.value.pendingSpendTimes);
console.log("用户信息", user.value);
ElMessage.success(result.msg);
}
} catch (error) {
console.log("请求失败", error);
ElMessage.error("查询失败,请检查精网号是否正确");
//
}
};
//
//
const userGold = ref({});
const getUserGold = async function (jwcode) {
trimJwCode();
try {
// POST
const result = await request({
url: "/recharge/user",
data: {
jwcode: addConsume.value.jwcode,
area: adminData.value.area,
},
});
//
console.log("请求成功", result);
if (result.code === 0) {
//ElMessage.error(result.msg);
} else {
//
userGold.value = result.data;
addConsume.value.username = result.data.name;
addConsume.value.area = result.data.area;
// ElMessage.success(result.msg);
}
} catch (error) {
console.log("请求失败", error);
//ElMessage.error("");
addConsume.value.jwcode = "";
//
}
};
function calculateCoins() {
if (
(userGold.value.coreJb +
userGold.value.free6 +
userGold.value.free12 +
userGold.value.buyJb) /
100 <
addConsume.value.allGold
) {
addConsume.value.allGold = 0;
addConsume.value.taskCoin = 0;
addConsume.value.freeCoin = 0;
addConsume.value.rechargeCoin = 0;
ElMessage.error("金币不足,请充值");
return;
}
//
else {
// allGold
const originalAllGold = addConsume.value.allGold;
// todayTasktodayFree
const todayTask =
typeof userGold.value.coreJb === "number"
? userGold.value.coreJb / 100
: 0;
const todayFree =
typeof (userGold.value.free6 + userGold.value.free12) === "number"
? (userGold.value.free6 + userGold.value.free12) / 100
: 0;
//
addConsume.value.taskCoin = Math.min(originalAllGold, todayTask);
let remainingGold = originalAllGold - addConsume.value.taskCoin;
addConsume.value.freeCoin = Math.min(remainingGold, todayFree);
remainingGold -= addConsume.value.freeCoin;
addConsume.value.rechargeCoin = remainingGold; //
// allGold
addConsume.value.allGold = originalAllGold;
// taskCoin, freeCoin, rechargeCoinNaN0
if (isNaN(addConsume.value.taskCoin)) addConsume.value.taskCoin = 0;
if (isNaN(addConsume.value.freeCoin)) addConsume.value.freeCoin = 0;
if (isNaN(addConsume.value.rechargeCoin)) addConsume.value.rechargeCoin = 0;
console.log("计算结果", addConsume.value);
}
}
//
const goods = ref([]);
const getGoods = async function () {
try {
// POST
const result = await request({
url: "/product",
data: {},
});
//
console.log("请求成功", result);
//
goods.value = result.data;
} catch (error) {
console.log("请求失败", error);
//
}
};
//
const index = ref([]);
const getIndexs = async function (type) {
try {
// POST
const result = await request({
url: "/product/index",
data: {
type: type,
},
});
//
console.log("请求成功", result);
//
index.value = result.data;
} catch (error) {
console.log("请求失败", error);
//
}
};
//
const isHC = ref(0);
// const handleProductSelect = (productName) => {
// //
// // indexs.value.productName = productName;
// if (productName === "homilychart") {
// isHC.value = 1;
// addConsume.value.productName = "homilychart"; //
// addConsume.value.indexName = ""; //
// } else {
// isHC.value = 0;
// addConsume.value.productName = productName;
// addConsume.value.indexName = "";
// }
// };
const indexs = ref([]);
// const handleIndexSelect = () => {
// if (isHC.value === 1 && addConsume.value.indexName) {
// addConsume.value.productName = "homilychart" + addConsume.value.indexName;
// }
// };
//
const queryProductSearch = (queryString, cb) => {
const results = queryString
? goods.value.filter(item =>
item.name.toLowerCase().includes(queryString.toLowerCase())
)
: goods.value;
cb(results);
};
//
const queryIndexSearch = (queryString, cb) => {
const results = queryString
? index.value.filter(item => // indexData index
item.name.toLowerCase().includes(queryString.toLowerCase())
)
: index.value;
cb(results);
};
//
const handleProductSelect = async (selectedItem) => {
const productName = typeof selectedItem === 'string'
? selectedItem
: selectedItem?.name || '';
if (productName === "homilychart") {
isHC.value = 1;
addConsume.value.productName = "homilychart";
addConsume.value.indexName = "";
//
await getIndexs("homilychart");
} else {
isHC.value = 0;
addConsume.value.productName = productName;
addConsume.value.indexName = "";
}
};
//
const handleIndexSelect = (selectedItem) => {
if (isHC.value === 1) {
const indexName = typeof selectedItem === 'string'
? selectedItem
: selectedItem?.name || '';
//
addConsume.value.indexName = indexName;
}
};
//
const handleIndexBlur = (e) => {
if (isHC.value === 1 && e.target.value) {
//
addConsume.value.indexName = e.target.value;
}
};
//
onMounted(async function () {
await getAdminData();
await getGoods();
await getIndexs(1);
});
const handleSelectBlur = (value) => {
//
// v-model
if (value) {
//
if (addConsume.value.productName === value) {
addConsume.value.productName = value;
}
//
else if (indexs.value.name === value) {
indexs.value.name = value;
}
}
};
</script>
<template>
<div style="margin-bottom: 20px; font-weight: bolder">新增消费</div>
<el-form
:model="addConsume"
ref="Ref"
:rules="rules"
label-width="auto"
style="max-width: 750px;"
class="form-style"
>
<el-form-item prop="jwcode" label="精网号">
<el-input
v-model="addConsume.jwcode"
style="width: 220px"
@change="getUserGold(addConsume.jwcode)"
/>
<el-button
type="primary"
@click="getUser(addConsume.jwcode)"
style="margin-left: 20px"
>查询</el-button
>
</el-form-item>
<div style="display: flex; align-items: center; gap: 20px;">
<el-form-item prop="productName" label="商品名称" style="flex: 1; margin-right: 0px">
<el-autocomplete
v-model="addConsume.productName"
:fetch-suggestions="queryProductSearch"
placeholder="请输入或选择商品"
style="width: 300px"
@select="handleProductSelect"
value-key="name"
clearable
:trigger-on-focus="true"
>
<template #default="{ item }">
<div>{{ item.name }}</div>
</template>
</el-autocomplete>
</el-form-item>
<!-- 指标选择 -->
<!-- 使用flex布局会使页面更灵活好用修改之前选中商品名称后才会正常布局的bug -->
<el-form-item prop="indexName" label="指标" v-if="isHC == 1" style="flex: 1;margin-left: -20px">
<el-autocomplete
v-model="addConsume.indexName"
:fetch-suggestions="queryIndexSearch"
placeholder="请输入或选择指标"
style="width: 140px"
@select="handleIndexSelect"
@blur="handleIndexBlur"
value-key="name"
:disabled="isHC !== 1"
clearable
free-solo
allow-create
>
<template #default="{ item }">
<div>{{ item.name }}</div>
</template>
</el-autocomplete>
</el-form-item>
<el-form-item label="指标" v-else style="flex:1;margin-left: -5px;">
<el-input disabled placeholder="无" style="width: 100px" />
</el-form-item>
</div>
<el-form-item prop="allGold" label="消费金币总数" >
<el-input
v-model="addConsume.allGold"
style="width: 100px"
@change="calculateCoins()"
/>
</el-form-item>
<div style="display: flex; align-items: center">
<el-form-item prop="rechargeCoin" label="永久金币" style="float: left">
<el-input
disabled
v-model="addConsume.rechargeCoin"
style="width: 100px; margin-left: -5px"
/>
<p style="margin-right: 0px"></p>
</el-form-item>
<el-form-item
prop="freeCoin"
label="免费金币"
style="float: left; margin-left: -20px"
>
<el-input
disabled
v-model="addConsume.freeCoin"
style="width: 100px; margin-left: -5px"
/>
<p style="margin-right: 0px"></p>
</el-form-item>
<el-form-item prop="taskCoin" label="任务金币" style="margin-left: -20px">
<el-input
disabled
v-model="addConsume.taskCoin"
style="width: 100px; margin-left: -5px"
/>
<p style="margin-right: 20px"></p>
</el-form-item>
</div>
<el-form-item prop="remark" label="备注">
<el-input
v-model="addConsume.remark"
style="width: 300px"
:rows="2"
maxlength="100"
show-word-limit
type="textarea"
/>
</el-form-item>
<el-form-item prop="commitName" label="提交人">
<el-input
style="width: 300px"
:value="adminData.name"
disabled
placeholder="提交人姓名"
/>
</el-form-item>
<el-button type="success" @click="delteConsume" style="margin-left: 280px">重置</el-button>
<el-button type="primary" @click="addBefore"> 提交 </el-button>
</el-form>
<!-- 客户信息栏 -->
<el-card style="width: 850px; float: right" class="customer-info">
<el-form
:model="user"
label-width="auto"
style="max-width: 1200px"
label-position="left"
>
<el-text size="large" style="margin-left: 20px">客户信息</el-text>
<el-row style="margin-top: 20px">
<el-col :span="10">
<el-form-item label="姓名:">
<p>{{ user.name }}</p>
</el-form-item>
</el-col>
<el-col :span="14">
<el-form-item label="历史金币总数">
<!-- 检查 user.totalRechargeGold 是否为有效的数字 -->
<p v-if="!isNaN(Number(user.totalRechargeGold))">
{{ Number(user.totalRechargeGold / 100) }}
</p>
<!-- 如果不是有效的数字显示默认值 -->
<p v-else></p>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="精网号">
<p>{{ user.jwcode }}</p>
</el-form-item>
</el-col>
<el-col :span="14">
<el-form-item label="当前金币总数" style="width: 500px">
<span
style="color: #2fa1ff; margin-right: 5px"
v-if="user.buyJb !== undefined"
>{{
(user.buyJb + user.free6 + user.free12 + user.coreJb) / 100
}}</span
>
<span
style="display: inline; white-space: nowrap; color: #b1b1b1"
v-if="user.buyJb !== undefined"
>(永久金币:{{ user.buyJb / 100 }};免费金币:{{
(user.free6 + user.free12) / 100
}};任务金币:{{ user.coreJb / 100 }})</span
>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="首次充值日期">
<p v-if="user.firstRechargeDate">
{{ moment(user.firstRechargeDate).format("YYYY-MM-DD HH:mm:ss") }}
</p>
</el-form-item>
</el-col>
<el-col :span="14">
<el-form-item label="充值次数">
<p style="color: #2fa1ff">{{ user.rechargeTimes }}</p>
</el-form-item>
</el-col>
<!-- <el-col :span="10">
<el-form-item label="负责客服">
<p>{{ adminData.name }}</p>
</el-form-item>
</el-col> -->
<el-col :span="10">
<el-form-item label="消费次数">
<p style="color: #2fa1ff">{{ user.spendTimes }}</p>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="所属门店">
<p>{{ adminData.area }}</p>
</el-form-item>
</el-col>
<el-col :span="14">
<!-- <el-form-item label="待审核">
<p style="color: #2fa1ff">
{{ user.A }}
</p>
</el-form-item> -->
</el-col>
</el-row>
</el-form>
</el-card>
</template>
<style scoped>
p {
margin: 0px;
}
.el-form-item {
margin-left: 50px;
}
/* 上传图片的格式 */
.avatar-uploader .avatar {
width: 50px;
height: 50px;
display: block;
}
</style>
<style>
.avatar-uploader .el-upload {
border: 1px dashed var(--el-border-color);
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
transition: var(--el-transition-duration-fast);
}
.avatar-uploader .el-upload:hover {
border-color: var(--el-color-primary);
}
.el-icon.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 50px;
height: 50px;
text-align: center;
}
.form-style {
margin-top: 50px;
max-width: 50%;
float: left;
}
.form-style2 {
max-width: 60%;
}
p {
font-size: 13px;
transform: scale(1);
}
</style>

587
src/views/consume/allConsume.vue

@ -0,0 +1,587 @@
<script setup>
import { ref, onMounted, reactive, computed } from 'vue'
import ElementPlus from 'element-plus'
import { AiFillRead } from 'vue-icons-plus/ai'
import { ElMessage, ElMessageBox } from 'element-plus'
import axios from 'axios'
import API from '../../api/index.js'
import request from '@/util/http'
//
//
const adminData = ref({})
const getAdminData = async function () {
try {
const result = await request({
url: '/admin/userinfo',
data: {}
})
adminData.value = result
console.log('请求成功', result)
console.log('用户信息', adminData.value)
} catch (error) {
console.log('请求失败', error)
}
}
//
const tableData = ref([])
// ======================================
// detailVo
const detailVo = ref({})
//
const getObj = ref({
pageNum: 1,
pageSize: 50
})
//
const total = ref(100)
//
const getTime = ref([])
//
const activity = ref([])
//
const allData = ref([])
//
const area = ref([])
//
const activeName = ref('all')
//
const consumePlatform = [
{
value: '4',
label: '金币系统'
},
{
value: '1',
label: 'Homily Chart'
},
{
value: '2',
label: 'Homily Link'
},
{
value: '3',
label: 'ERP系统'
}
]
// //
// const tableHeight = computed(function () {
// return (getObj.value.pageSize + 1) * 41 + "px";
// });
//
//
const tableDataTotal = ref({})
const rechargeCoin = ref(0)
const freeCoin = ref(0)
const taskCoin = ref(0)
const totalCoin = ref(0)
// =========================================================================================================================================================
//
const get = async function (val) {
try {
//
if (adminData.value.area != '总部') {
detailVo.value.area = adminData.value.area
}
//
if (typeof val === 'number') {
getObj.value.pageNum = val
}
//
if (getTime.value != null) {
if (getTime.value.startDate != '' && getTime.value.endDate != '') {
detailVo.value.startDate = getTime.value[0]
detailVo.value.endDate = getTime.value[1]
}
} else {
detailVo.value.startDate = ''
detailVo.value.endDate = ''
}
detailVo.value.sortField = sortField.value
detailVo.value.sortOrder = sortOrder.value
console.log('搜索参数', getObj.value)
// POST
const result = await request({
url: '/consume/select',
data: {
...getObj.value,
consumeDetail: { ...detailVo.value }
}
})
//
// detail.value
const detailWithoutSort = { ...detailVo.value }
delete detailWithoutSort.sortField
delete detailWithoutSort.sortOrder
const result2 = await request({
url: '/consume/SumConsume',
data: {
...detailWithoutSort
}
})
//
console.log('请求成功', result)
console.log('请求成功2', result2)
//
tableData.value = result.data.list
tableDataTotal.value = result2.data
if (result2.data == null) {
console.log('请求成功2', result2)
tableDataTotal.value = {
sumRcion: 0,
sumFcion: 0,
sumTcion: 0,
sumcion: 0
}
}
console.log('tableDataT', tableDataTotal)
//
rechargeCoin.value = parseFloat(
(tableDataTotal.value.sumRcion / 100).toFixed(2)
)
freeCoin.value = parseFloat(
(tableDataTotal.value.sumFcion / 100).toFixed(2)
)
taskCoin.value = parseFloat(
(tableDataTotal.value.sumTcion / 100).toFixed(2)
)
totalCoin.value = parseFloat(
(tableDataTotal.value.sumcion / 100).toFixed(2)
)
console.log('tableData', tableData.value)
//
total.value = result.data.total
console.log('total', total.value)
} catch (error) {
console.log('请求失败', error)
//
}
}
//
const search = function () {
getObj.value.pageNum = 1
get()
}
//
const reset = function () {
detailVo.value.productName = ''
detailVo.value.consumePlatform = ''
detailVo.value.consumeType = ''
detailVo.value.startDate = ''
detailVo.value.endDate = ''
sortField.value = ''
sortOrder.value = ''
getTime.value = {}
}
//
const getToday = function () {
const today = new Date()
const startDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate()
)
const endDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() + 1
)
getTime.value = [startDate, endDate]
console.log('getTime', getTime.value)
get()
}
//
const getYesterday = function () {
const yesterday = new Date()
yesterday.setDate(yesterday.getDate() - 1)
const startDate = new Date(
yesterday.getFullYear(),
yesterday.getMonth(),
yesterday.getDate()
)
const endDate = new Date(
yesterday.getFullYear(),
yesterday.getMonth(),
yesterday.getDate() + 1
)
getTime.value = [startDate, endDate]
console.log('getTime', getTime.value)
get()
}
// 7
const get7Days = function () {
const today = new Date()
const startDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() - 6
)
const endDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() + 1
)
getTime.value = [startDate, endDate]
console.log('getTime', getTime.value)
get()
}
//
const handleClick = function (tab, event) {
if (tab.props.name === 'all') {
adminAll()
} else if (tab.props.name === 'wait') {
adminWait()
} else if (tab.props.name === 'pass') {
adminPass()
} else if (tab.props.name === 'reject') {
adminReject()
}
}
//
onMounted(async function () {
await getAdminData()
await get()
// getActivity();
// await getArea();
})
//
const checkNumber = function () {
if (typeof parseInt(getObj.value.pageNum) === 'number') {
console.log('总共有多少页' + Math.ceil(total.value / getObj.value.pageSize))
if (
getObj.value.pageNum > 0 &&
getObj.value.pageNum <= Math.ceil(total.value / getObj.value.pageSize)
) {
getObj.value.pageNum = parseInt(getObj.value.pageNum)
console.log('输入的数字合法')
get()
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
}
//
const goods = ref([])
const getGoods = async function () {
try {
// POST
const result = await request({
url: '/product/findProductName',
data: {}
})
//
console.log('请求成功product', result)
//
goods.value = result.data
console.log('goods 数据', goods.value) //
} catch (error) {
console.log('请求失败', error)
//
}
}
getGoods()
//
const sortField = ref('')
const sortOrder = ref('')
//
const handleSortChange = (column) => {
console.log('排序字段:', column.prop)
console.log('排序方式:', column.order)
if (column.prop === 'rechargeCoin') {
sortField.value = 'recharge_coin'
} else if (column.prop === 'taskCoin') {
sortField.value = 'task_coin'
} else if (column.prop === 'freeCoin') {
sortField.value = 'free_coin'
} else if (column.prop === 'createTime') {
sortField.value = 'create_time'
}
sortOrder.value = column.order === 'ascending' ? 'DESC' : 'ASC'
get()
}
const handlePageSizeChange = function (val) {
getObj.value.pageSize = val
get()
}
const handleCurrentChange = function (val) {
getObj.value.pageNum = val
get()
}
</script>
<template>
<el-row>
<el-col>
<el-card style="margin-bottom: 20px">
<el-row style="margin-bottom: 10px">
<el-col :span="8">
<div class="head-card-element">
<el-text class="mx-1" size="large">商品名称</el-text>
<el-select
v-model="detailVo.productName"
placeholder="请选择商品名称"
size="large"
style="width: 240px"
clearable
>
<!-- 修改 v-for 绑定逻辑 -->
<el-option
v-for="(item, index) in goods"
:key="index"
:label="item"
:value="item"
/>
</el-select>
</div>
</el-col>
<el-col :span="8">
<div class="head-card-element">
<el-text class="mx-1" size="large">消费平台</el-text>
<el-select
v-model="detailVo.consumePlatform"
placeholder="请选择消费平台"
size="large"
style="width: 240px"
clearable
>
<el-option
v-for="item in consumePlatform"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</el-col>
<el-col :span="8">
<!-- <div class="head-card-element">
<el-text class="mx-1" size="large">消费类型</el-text>
<el-select
v-model="detailVo.consumeType"
placeholder="请选择消费类型"
size="large"
style="width: 240px"
clearable
>
<el-option
v-for="item in consumeType"
:key="item"
:label="item.label"
:value="item.value"
/>
</el-select>
</div> -->
</el-col>
</el-row>
<el-row>
<el-col :span="21">
<div class="head-card-element">
<el-text class="mx-1" size="large">消费时间</el-text>
<el-date-picker
v-model="getTime"
type="datetimerange"
range-separator="至"
start-placeholder="起始时间"
end-placeholder="结束时间"
/>
<el-button style="margin-left: 10px" @click="getToday()"
></el-button
>
<el-button @click="getYesterday()"></el-button>
<el-button @click="get7Days()">近7天</el-button>
</div>
</el-col>
<el-col :span="3">
<div class="head-card-btn">
<el-button type="success" @click="reset()">重置</el-button>
<el-button type="primary" @click="search()">查询</el-button>
</div>
</el-col>
</el-row>
</el-card>
</el-col>
</el-row>
<el-row>
<el-col>
<el-card>
<div>
消费金币总数{{ Math.abs(totalCoin) }}永久金币{{
Math.abs(rechargeCoin)
}}免费金币{{ Math.abs(freeCoin) }}任务金币{{
Math.abs(taskCoin)
}}
</div>
<!-- 设置表格容器的高度和滚动样式 -->
<div style="height: 576px; overflow-y: auto">
<el-table
:data="tableData"
style="width: 100%"
height="576px"
@sort-change="handleSortChange"
>
<el-table-column
type="index"
label="序号"
width="100px"
fixed="left"
>
<template #default="scope">
<span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template>
</el-table-column>
<!-- 固定姓名列 -->
<el-table-column
prop="username"
label="姓名"
width="150px"
fixed="left"
/>
<!-- 固定精网号列 -->
<el-table-column
prop="jwcode"
label="精网号"
width="110px"
fixed="left"
/>
<el-table-column prop="area" label="所属地区" width="110px" />
<el-table-column prop="productName" label="商品" width="160px" />
<el-table-column
prop="consumePlatform"
label="消费平台"
width="120px"
>
<template #default="scope">
<!-- 使用非严格相等比较 -->
<span v-if="scope.row.consumePlatform == 1">Homily Chart</span>
<span v-if="scope.row.consumePlatform == 2">Homily Link</span>
<span v-if="scope.row.consumePlatform == 3">ERP系统</span>
<span v-if="scope.row.consumePlatform == 4">金币系统</span>
</template>
</el-table-column>
<el-table-column
prop="consumeType"
label="消费类型"
width="120px"
/>
<el-table-column
prop="rechargeTotal"
label="消费金币总数"
width="120px"
>
<template #default="scope">
{{
(scope.row.taskCoin * -1 +
scope.row.freeCoin * -1 +
scope.row.rechargeCoin * -1) /
100
}}
</template>
</el-table-column>
<el-table-column
prop="rechargeCoin"
label="永久金币"
sortable="“custom”"
width="110px"
>
<template #default="scope">
{{ (scope.row.rechargeCoin * -1) / 100 }}
</template>
</el-table-column>
<el-table-column
prop="freeCoin"
label="免费金币"
sortable="“custom”"
width="110px"
>
<template #default="scope">
{{ (scope.row.freeCoin * -1) / 100 }}
</template>
</el-table-column>
<el-table-column
prop="taskCoin"
label="任务金币"
sortable="“custom”"
width="110px"
>
<template #default="scope">
{{ (scope.row.taskCoin * -1) / 100 }}
</template>
</el-table-column>
<el-table-column
prop="remark"
label="备注"
width="200px"
show-overflow-tooltip
/>
<el-table-column prop="name" label="提交人" width="110px" />
<el-table-column
prop="createTime"
label="消费时间"
sortable="“custom”"
width="180px"
/>
</el-table>
</div>
<!-- 分页 -->
<div class="pagination">
<el-pagination
background
:page-size="getObj.pageSize"
:page-sizes="[5, 10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handlePageSizeChange"
@current-change="handleCurrentChange"
></el-pagination>
</div>
</el-card>
</el-col>
</el-row>
</template>
<style scoped>
.status {
display: flex;
}
.head-card {
display: flex;
}
.head-card-element {
margin-right: 20px;
}
.head-card-btn {
margin-left: auto;
}
.pagination {
display: flex;
margin-top: 20px;
}
</style>

217
src/views/goldBeen/addGoldenBeen.vue

@ -0,0 +1,217 @@
<template>
<div class="add-goldenbeen">
<div class="head-top">新增充值</div>
<div class="add-box">
<el-form
:model="beenObj"
ref="ruleFormRef"
:rules="rules"
label-width="auto"
style="max-width: 600px"
class="add-form"
>
<el-form-item prop="jwcode" label="精网号">
<el-input v-model="beenObj.jwcode" style="width: 220px" />
<el-button
type="primary"
@click="getUser()"
style="margin-left: 20px"
>查询</el-button
>
</el-form-item>
<el-form-item prop="type" label="充值类型">
<el-radio-group v-model="beenObj.type">
<el-radio :value="0">增加</el-radio>
<el-radio :value="1">减少</el-radio>
</el-radio-group>
</el-form-item>
<div style="display: flex">
<el-form-item prop="payBeean" label="付费金豆">
<el-input-number
v-model="beenObj.payBeean"
:controls="false"
:min="0"
/>
</el-form-item>
<el-form-item prop="freeBeean" label="免费金豆">
<el-input-number
v-model="beenObj.freeBeean"
:controls="false"
:min="0"
/>
</el-form-item>
</div>
<el-form-item prop="remark" label="备注">
<el-input
v-model="beenObj.remark"
style="width: 300px"
:rows="2"
maxlength="100"
show-word-limit
type="textarea"
/>
</el-form-item>
<!-- <el-form-item prop="submitter" label="提交人">
<el-input
style="width: 300px"
:value="beenObj.submitter"
disabled
placeholder="提交人姓名"
/>
</el-form-item> -->
<el-form-item>
<div class="btn-group">
<el-button type="success" @click="resetData(ruleFormRef)">重置</el-button>
<el-button type="primary" @click="addBean(ruleFormRef)">
提交
</el-button>
</div>
</el-form-item>
</el-form>
<!-- 客户信息栏 -->
<el-card>
<el-text size="large" style="margin-left: 20px">客户信息</el-text>
<div class="custom-box">
<el-text>姓名:{{ user.nickname }}</el-text>
<el-text>当前付费金豆:{{ user.jinbiBuy }}</el-text>
<el-text>精网号:{{ user.jwcode }}</el-text>
<el-text>当前免费金豆:{{ user.jinbiFree }}</el-text>
<!-- <el-text>负责客服:</el-text> -->
<el-text>消费次数:{{ user.number }}</el-text>
<el-text>所属门店:{{ user.masterShop }}</el-text>
</div>
</el-card>
</div>
</div>
</template>
<script setup lang="ts">
import { reactive, ref } from 'vue'
import API from '@/util/http'
import type { FormInstance } from 'element-plus'
import { ElMessage } from 'element-plus'
type userType = {
[key: string]: number | string
}
const ruleFormRef = ref<FormInstance>()
const beenObj = ref({
jwcode: '',
remark: '',
type: 0, //01
payBeean: 0,
freeBeean: 0
})
let user: userType = reactive({})
const rules = ref({
jwcode: [{ required: true, message: '请输入精网号', trigger: 'blur' }],
remark: [{ required: true, message: '请输入备注', trigger: 'blur' }],
// submitter: [{ required: true, message: '', trigger: 'blur' }],
type: [{ required: true, message: '请选择充值类型', trigger: 'change' }],
payBeean: [{ required: true, message: '请输入付费金豆', trigger: 'blur' }],
freeBeean: [{ required: true, message: '请输入免费金豆', trigger: 'blur' }]
})
const addBean = (formEl) => {
//
try {
formEl.validate(async (valid) => {
if (valid) {
//
const result = await API({
url: '/dou/add',
data: {
jwcode: beenObj.value.jwcode,
content: beenObj.value.remark,
moneyFree: Number(beenObj.value.freeBeean),
moneyBuy: Number(beenObj.value.payBeean),
time: Math.floor(Date.now() / 1000),
data: beenObj.value.type
}
})
if (result.code === 200) {
ElMessage.success('充值成功')
beenObj.value.jwcode = ''
beenObj.value.remark = ''
beenObj.value.payBeean = 0
beenObj.value.freeBeean = 0
} else if (result.code === 0) {
ElMessage.error(result.msg)
return
}
console.log('请求成功', result)
} else {
ElMessage.error('表单验证失败')
}
})
} catch (error) {
ElMessage.error('提交失败')
}
}
const resetData = (formEl) => {
if (!formEl) return
formEl.resetFields()
}
//
const trimJwCode = () => {
if (beenObj.value.jwcode) {
beenObj.value.jwcode = beenObj.value.jwcode.replace(/\s/g, '');
}
}
const getUser = async function () {
trimJwCode();
try {
// POST
const result = await API({
url: '/dou/search',
data: {
jwcode: beenObj.value.jwcode
}
})
if (result.code === 0) {
ElMessage.error(result.msg)
} else {
if (!result.data.jwcode) {
ElMessage.error('精网号不存在')
return
}
Object.assign(user, result.data)
}
} catch (error) {
console.log('请求失败', error)
ElMessage.error('查询失败,请检查精网号是否正确')
}
}
</script>
<style scoped>
.add-box {
display: flex;
justify-content: center;
align-items: center;
column-gap: 50px;
}
.btn-group {
display: flex;
justify-content: flex-end;
width: 100%;
}
.custom-box {
padding: 20px;
display: flex;
flex-wrap: wrap;
align-items: center;
row-gap: 20px;
box-sizing: border-box;
.el-text {
width: 200px;
}
}
.el-card {
width: 500px;
}
.head-top {
padding: 20px;
box-sizing: border-box;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
border-radius: 5px;
}
</style>

253
src/views/goldBeen/goldenBeenBalance.vue

@ -0,0 +1,253 @@
<template>
<!-- 这是客户金豆余额页面 -->
<div class="filter-box">
<el-form :model="detailY" ref="ruleFormRef">
<el-form-item prop="jwcode">
<el-text class="mx-1" size="large">精网号</el-text>
<el-input
v-model="detailY.jwcode"
placeholder="请输入精网号"
style="width: 220px"
/>
</el-form-item>
<el-form-item prop="area">
<el-text class="mx-1" size="large">地区</el-text>
<el-select
v-model="detailY.area"
placeholder="请选择所属地区"
style="width: 240px"
clearable
>
<el-option
v-for="item in areaArray"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="search()"
>查询</el-button
>
<el-button type="success" @click="reset(ruleFormRef)"
>重置</el-button
>
</el-form-item>
</el-form>
</div>
<div class="table-box">
<div>
现有金豆&nbsp;&nbsp;付费金豆{{ getObj.jinbiBuy }}&nbsp;&nbsp;免费金豆{{
getObj.jinbiFree
}}&nbsp;&nbsp;历史消费{{ getObj.jinbiCostTotal }}
</div>
<el-table
:data="tableData"
style="width: 100%"
:default-sort="{ prop: 'jinbiCostTotal', order: 'descending' }"
height="584px"
@sort-change="handleSortChange"
>
<el-table-column type="index" label="序号" width="100px" fixed="left">
<template #default="scope">
<span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template>
</el-table-column>
<el-table-column fixed="left" prop="nickname" label="姓名" width="150" />
<el-table-column fixed="left" prop="jwcode" label="精网号" width="120" />
<el-table-column prop="ipAddress" label="所属地区" width="120" />
<el-table-column prop="jinbi" sortable label="金豆数量" width="120">
</el-table-column>
<el-table-column prop="jinbiBuy" sortable label="付费金豆" width="120">
</el-table-column>
<el-table-column prop="jinbiFree" sortable label="免费金豆" width="120">
</el-table-column>
<el-table-column
sortable
width="120"
prop="jinbiCostTotal"
label="历史消费"
></el-table-column>
<el-table-column
sortable
prop="jinbiCostbeenTotal"
width="160"
label="历史付费金豆"
></el-table-column>
<el-table-column
sortable
prop="jinbifreebeenTotal"
width="160"
label="历史免费金豆"
></el-table-column>
</el-table>
<!-- 分页 -->
<div class="pagination">
<el-pagination
background
:page-size="getObj.pageSize"
:page-sizes="[5, 10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handlePageSizeChange"
@current-change="handleCurrentChange"
>
</el-pagination>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import type { FormInstance } from 'element-plus'
import API from '@/util/http'
//
const tableData = ref([])
//
const total = ref(100)
//
const detailY = reactive({ jwcode: '', area: '' })
const ruleFormRef = ref<FormInstance>()
let areaArray = ref<string[]>([])
let getObj = ref({
pageNum: 1,
pageSize: 50,
jinbiBuy: 0,
jinbiCostTotal: 0,
jinbiFree: 0
})
//
const trimJwCode = () => {
if (detailY.jwcode) {
detailY.jwcode = detailY.jwcode.replace(/\s/g, '');
}
}
const search = function () {
trimJwCode();
getInit({})
getCount()
}
const handleCurrentChange = function (val) {
getObj.value.pageNum = val
getInit({})
}
//
const getInit = async function ({
sortField = '',
sortOrder = ''
}: {
sortField?: string
sortOrder?: string
}) {
try {
// POST
const result = await API({
url: '/dou/getYve',
data: {
pageNum: getObj.value.pageNum,
pageSize: getObj.value.pageSize,
yve: {
jwcode: detailY.jwcode,
ipAddress: detailY.area,
sortField: sortField,
sortOrder: sortOrder
}
}
})
tableData.value = result.data.list
total.value = result.data.total
} catch (error) {
console.log('请求失败', error)
//
}
}
const handleSortChange = (column) => {
const { prop, order } = column
if (order === 'ascending') {
getInit({ sortField: prop, sortOrder: 'ASC' })
} else if (order === 'descending') {
getInit({ sortField: prop, sortOrder: 'DESC' })
}
}
const handlePageSizeChange = (val) => {
getObj.value.pageSize = val
getObj.value.pageNum = 1
getInit({})
}
//
const reset = function (formEl: FormInstance | undefined) {
if (!formEl) return
formEl.resetFields()
}
const getArea = async () => {
const result = await API({
url: '/dou/getIp'
})
console.log('获取地区', result.data)
if (result.code == 200) {
areaArray.value = result.data
}
}
const getCount = async () => {
try {
const result = await API({
url: '/dou/getYveTotal',
// jwcodeipAddress
data: {
jwcode: detailY.jwcode,
ipAddress: detailY.area
}
})
if (result.code === 200) {
const { jinbiBuy, jinbiFree, jinbiCostTotal } = result.data
getObj.value.jinbiBuy = jinbiBuy
getObj.value.jinbiFree = jinbiFree
getObj.value.jinbiCostTotal = jinbiCostTotal
}
} catch (error) {
console.log('获取统计数据失败', error)
}
}
getArea()
getCount()
getInit({})
</script>
<style scoped lang="scss">
.filter-box {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
padding-bottom: 0px;
box-sizing: border-box;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
border-radius: 5px;
.el-form {
display: flex;
flex-wrap: wrap;
row-gap: 20px;
column-gap: 20px;
}
}
.table-box {
width: 100%;
padding: 20px;
box-sizing: border-box;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
border-radius: 5px;
}
.pagination {
display: flex;
align-items: center;
margin-top: 20px;
}
</style>

581
src/views/goldBeen/goldenBeenConsum.vue

@ -0,0 +1,581 @@
<template>
<!-- 这是金豆消费明细页面 -->
<div class="filter-box">
<el-form :model="detailY" ref="ruleFormRef">
<el-form-item prop="jwcode">
<el-text class="mx-1" size="large">精网号</el-text>
<el-input
v-model="detailY.jwcode"
placeholder="请输入精网号"
style="width: 220px"
/>
</el-form-item>
<el-form-item prop="ipAddress">
<el-text class="mx-1" size="large">地区</el-text>
<el-select
v-model="detailY.ipAddress"
placeholder="请选择所属地区"
style="width: 240px"
clearable
>
<el-option
v-for="item in areaList"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item prop="sourceType">
<el-text class="mx-1" size="large">消费类型</el-text>
<el-select
v-model="detailY.sourceType"
placeholder="请选择消费类型"
style="width: 240px"
clearable
>
<el-option
v-for="item in consumList"
:key="item.value"
:label="item.text"
:value="item.value"
/>
</el-select>
</el-form-item>
<!-- <el-form-item prop="channel" label="频道">
<el-select
v-model="detailY.channel"
placeholder="请选择频道"
style="width: 240px"
clearable
filterable
>
<el-option
v-for="item in channelList"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item> -->
<el-form-item prop="sourceName">
<el-text class="mx-1" size="large">直播间</el-text>
<el-input
v-model="detailY.sourceName"
placeholder="请输入直播间"
style="width: 220px"
/>
</el-form-item>
<el-form-item prop="startTime">
<el-text class="mx-1" size="large">开始时间</el-text>
<el-date-picker
v-model="detailY.startTime"
type="date"
placeholder="开始日期"
style="width: 240px"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
/>
</el-form-item>
<el-form-item prop="endTime">
<el-text class="mx-1" size="large">结束时间</el-text>
<el-date-picker
v-model="detailY.endTime"
type="date"
placeholder="结束日期"
style="width: 240px"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
/>
<el-button style="margin-left: 10px" @click="getToday()"></el-button>
<el-button @click="getYesterday()"></el-button>
<el-button @click="get7Days()">近7天</el-button>
</el-form-item>
<el-form-item>
<el-button type="success" @click="exportExcel">导出Excel</el-button>
<el-button type="primary" @click="search">查询</el-button>
<el-button type="success" @click="reset(ruleFormRef)">重置</el-button>
</el-form-item>
</el-form>
</div>
<div class="table-box">
<div>合计数实际用户金豆数{{ beenCount }}</div>
<el-table :data="tableData" style="width: 100%" height="584px">
<el-table-column type="index" label="序号" width="100px" fixed="left">
<template #default="scope">
<span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template>
</el-table-column>
<el-table-column fixed="left" prop="nickname" label="姓名" width="150" />
<el-table-column fixed="left" prop="jwcode" label="精网号" width="120" />
<el-table-column prop="ipAddress" label="地区" width="120" />
<el-table-column prop="sourceType" label="消费类型" width="120">
<template #default="scope">
<span>{{
consumList.find((item) => item.value === scope.row.sourceType)?.text
}}</span>
</template>
</el-table-column>
<el-table-column prop="jinbiCostTotal" label="金豆价格" width="120">
</el-table-column>
<!-- <el-table-column prop="chanel" label="频道" width="120">
</el-table-column> -->
<el-table-column prop="room" label="直播间" width="120">
</el-table-column>
<el-table-column
prop="createTime"
label="消费时间"
width="210"
show-overflow-tooltip
>
<template #default="scope">
<span>{{
moment(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss')
}}</span>
</template>
</el-table-column>
<!-- <el-table-column fixed="right" label="操作" min-width="120">
<template #default>
<el-tooltip class="box-item" effect="light" placement="top-start">
<template #default>
<el-button link type="primary" size="small"> 返还金豆 </el-button>
</template>
<template #content>
<div>是否申请返还该条消费</div>
<el-button size="small">确定 </el-button>
<el-button size="small">取消 </el-button>
</template>
</el-tooltip>
</template>
</el-table-column> -->
</el-table>
<!-- 分页 -->
<div class="pagination">
<el-pagination
background
:page-size="getObj.pageSize"
:page-sizes="[5, 10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handlePageSizeChange"
@current-change="handleCurrentChange"
>
</el-pagination>
</div>
</div>
<!-- 导出信息确认对话框 -->
<el-dialog
v-model="showExportInfoPanel"
title="导出信息确认"
width="400px"
:close-on-click-modal="false"
>
<div class="info-panel-header">导出信息</div>
<div v-if="!detailY.jwcode && !detailY.ipAddress && !detailY.sourceType && !detailY.sourceName && (!detailY.startTime || !detailY.endTime)">
你正在导出所有数据
</div>
<div v-else>
你正在导出以下数据
</div>
<div v-if="detailY.jwcode">精网号{{ detailY.jwcode }}</div>
<div v-if="detailY.ipAddress">地区{{ detailY.ipAddress }}</div>
<div v-if="detailY.sourceType">
消费类型{{ consumList.value.find(item => item.value === detailY.sourceType)?.text }}
</div>
<div v-if="detailY.sourceName">直播间{{ detailY.sourceName }}</div>
<div v-if="detailY.startTime && detailY.endTime">
时间范围{{ detailY.startTime }} {{ detailY.endTime }}
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="showExportInfoPanel = false">取消</el-button>
<el-button type="primary" @click="doExportExcel">导出</el-button>
</span>
</template>
</el-dialog>
<!-- 导出进度对话框 -->
<el-dialog
v-model="isExporting"
title="正在导出"
width="400px"
:close-on-click-modal="false"
:show-close="false"
>
<el-progress
:percentage="exportProgress"
:stroke-width="15"
striped
animated
/>
<div class="export-status">
已导出 {{ Math.round((exportProgress / 100) * total) }} / {{ total }}
</div>
<template #footer>
<el-button type="danger" @click="cancelExport">取消导出</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { FormInstance } from 'element-plus'
import { ElMessage } from 'element-plus'
import moment from 'moment'
import API from '@/util/http'
import axios from 'axios'
// xlsx
import * as XLSX from 'xlsx'
const { utils, writeFile } = XLSX
//
const tableData = ref([])
//
const total = ref(100)
const areaList = ref<string[]>([])
const beenCount = ref(0)
const consumList = ref<any>([
{ value: 1, text: '发礼物' },
{ value: 2, text: '发红包' },
{ value: 3, text: '发福袋' },
{ value: 4, text: '付费直播' },
{ value: 5, text: '加⼊粉丝团' },
{ value: 6, text: '发弹幕' },
{ value: 7, text: '铁粉单次付费' },
{ value: 8, text: '铁粉连续包⽉' },
{ value: 9, text: '打赏⽂章' },
{ value: 10, text: '打赏视频' },
{ value: 11, text: '付费购买' }
])
// const channelList = ref<string[]>([])
// const liveroomList = ref<string[]>([])
const ruleFormRef = ref<FormInstance>()
//
const detailY = ref({
jwcode: '',
ipAddress: '',
startTime:'',
endTime:'',
// channel: '', //
sourceName: '', //
sourceType: '' //
})
const getObj = ref({
pageNum: 1,
pageSize: 50
})
//
const getToday = function () {
const today = new Date()
//
const startDate = moment(today).startOf('day').format('YYYY-MM-DD HH:mm:ss')
//
const endDate = moment(today).endOf('day').format('YYYY-MM-DD HH:mm:ss')
detailY.value.startTime = startDate
detailY.value.endTime = endDate
search()
}
//
const getYesterday = function () {
const yesterday = moment().subtract(1, 'days')
//
const startDate = yesterday.startOf('day').format('YYYY-MM-DD HH:mm:ss')
//
const endDate = yesterday.endOf('day').format('YYYY-MM-DD HH:mm:ss')
detailY.value.startTime = startDate
detailY.value.endTime = endDate
search()
}
// 7
const get7Days = function () {
//
const startDate = moment().subtract(6, 'days').startOf('day').format('YYYY-MM-DD HH:mm:ss')
//
const endDate = moment().endOf('day').format('YYYY-MM-DD HH:mm:ss')
detailY.value.startTime = startDate
detailY.value.endTime = endDate
search()
}
//
const getInit = async function () {
try {
console.log('搜索参数', getObj.value)
const startTime = detailY.value.startTime
const endTime = detailY.value.endTime
// POST
const result = await API({
url: '/dou/getSpend',
method: 'post',
data: {
...getObj.value,
spend: {
jwcode: detailY.value.jwcode, //
ipAddress: detailY.value.ipAddress, //
sourceName: detailY.value.sourceName, //
sourceType: detailY.value.sourceType, //
startTime, //
endTime //
}
}
})
tableData.value = result.data.list
console.log('tableData', tableData.value)
total.value = result.data.total
console.log('total', total.value)
} catch (error) {
console.log('请求失败', error)
//
}
}
//
const trimJwCode = () => {
if (detailY.value.jwcode) {
detailY.value.jwcode = detailY.value.jwcode.replace(/\s/g, '');
}
if (detailY.value.sourceName) {
detailY.value.sourceName = detailY.value.sourceName.replace(/\s/g, '');
}
}
//
const search = function () {
trimJwCode();
getObj.value.pageNum = 1
getInit()
getCount()
}
//
const reset = function (formEl) {
formEl.resetFields()
}
const handlePageSizeChange = (val) => {
getObj.value.pageSize = val
getObj.value.pageNum = 1
getInit()
}
const handleCurrentChange = function (val) {
getObj.value.pageNum = val
getInit()
}
//
const getCount = async () => {
const result = await API({
url: '/dou/getSpendTotal',
data: {
jwcode: detailY.value.jwcode,
ipAddress: detailY.value.ipAddress,
sourceName: detailY.value.sourceName,
sourceType: detailY.value.sourceType,
startTime: detailY.value.startTime,
endTime: detailY.value.endTime
}
})
if (result.code == 200) {
//const { jinbiBuy, jinbiFree, jinbiCostTotal } = result.data
console.log('合计数', result.data)
beenCount.value = result.data || 0
}
}
//
const getArea = async () => {
try {
const result = await API({
url: '/dou/getIp'
})
areaList.value = result.data
} catch (error) {
console.log('请求失败', error)
}
}
//
const showExportInfoPanel = ref(false)
const exportProgress = ref(0)
const isExporting = ref(false)
const exportCancelToken = ref<any>(null)
// Excel
const headers = [
'序号',
'姓名',
'精网号',
'地区',
'消费类型',
'金豆价格',
'直播间',
'消费时间'
]
//
const exportExcel = () => {
showExportInfoPanel.value = true
}
//
const doExportExcel = async () => {
try {
isExporting.value = true
exportProgress.value = 0
showExportInfoPanel.value = false
// Excel
const wb = utils.book_new()
const ws = utils.aoa_to_sheet([headers])
utils.book_append_sheet(wb, ws, 'Sheet1')
//
const writer = {
write: (d: any[][], o: any) => {
if (!d) return
utils.sheet_add_aoa(ws, d, { origin: -1 })
}
}
let page = 1
let totalExported = 0
const pageSize = 5000 // 5000
let totalRecords = 0
//
const firstResult = await API({
url: '/dou/getSpend',
method: 'post',
data: {
pageNum: 1,
pageSize,
spend: {
...detailY.value
}
}
})
totalRecords = firstResult.data.total
//
const CancelToken = axios.CancelToken
exportCancelToken.value = CancelToken.source()
//
const firstData = firstResult.data.list
if (firstData.length) {
const rows = firstData.map((row: any, index: number) => {
return [
totalExported + index + 1,
row.nickname || '',
row.jwcode || '',
row.ipAddress || '',
consumList.value.find(item => item.value === row.sourceType)?.text || '',
row.jinbiCostTotal || 0,
row.room || '',
moment(row.createTime).format('YYYY-MM-DD HH:mm:ss') || ''
]
})
writer.write(rows,{})
totalExported += firstData.length
exportProgress.value = Math.round((totalExported / totalRecords) * 100)
page++
}
while (totalExported < totalRecords) {
const result = await API({
url: '/dou/getSpend',
method: 'post',
data: {
pageNum: page,
pageSize,
spend: {
...detailY.value
}
},
cancelToken: exportCancelToken.value.token
})
const data = result.data.list
if (!data.length) break
//
const rows = data.map((row: any, index: number) => [
totalExported + index + 1,
row.nickname || '',
row.jwcode || '',
row.ipAddress || '',
consumList.value.find(item => item.value === row.sourceType)?.text || '',
row.jinbiCostTotal || 0,
row.room || '',
moment(row.createTime).format('YYYY-MM-DD HH:mm:ss') || ''
])
//
writer.write(rows,{})
totalExported += data.length
exportProgress.value = Math.round((totalExported / totalRecords) * 100)
// 500
if (page % 500 === 0) {
await new Promise(resolve => setTimeout(resolve, 0))
}
page++
}
//
writeFile(wb, '金豆消费明细.xlsx')
exportProgress.value = 100
isExporting.value = false
exportCancelToken.value = null
ElMessage.success(`导出成功,共${totalExported}条数据`)
} catch (error) {
if (!axios.isCancel(error)) {
ElMessage.error(`导出失败: ${error.message}`)
}
isExporting.value = false
exportCancelToken.value = null
}
}
//
const cancelExport = () => {
if (exportCancelToken.value) {
exportCancelToken.value.cancel('用户取消导出')
ElMessage.warning('导出已取消')
isExporting.value = false
}
}
//
getInit()
getCount()
getArea()
</script>
<style scoped lang="scss">
.filter-box {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
padding-bottom: 0px;
box-sizing: border-box;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
border-radius: 5px;
.el-form {
display: flex;
flex-wrap: wrap;
row-gap: 20px;
column-gap: 20px;
}
}
.table-box {
width: 100%;
padding: 20px;
box-sizing: border-box;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
border-radius: 5px;
}
.pagination {
display: flex;
align-items: center;
margin-top: 10px;
}
</style>

794
src/views/goldBeen/goldenBeenDetail.vue

@ -0,0 +1,794 @@
<template>
<!-- 这是金豆充值明细页面 -->
<div class="filter-box">
<el-form :model="detailY" ref="ruleFormRef">
<el-form-item prop="jwcode">
<el-text class="mx-1" size="large">精网号</el-text>
<el-input
v-model="detailY.jwcode"
placeholder="请输入精网号"
style="width: 220px"
/>
</el-form-item>
<el-form-item prop="deptName" >
<el-text class="mx-1" size="large">地区</el-text>
<el-select
v-model="detailY.deptName"
placeholder="请选择所属地区"
style="width: 240px"
clearable
>
<el-option
v-for="item in areaList"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item prop="orderNo" >
<el-text class="mx-1" size="large">订单号</el-text>
<el-input
v-model="detailY.orderNo"
placeholder="请输入订单号"
style="width: 220px"
/>
</el-form-item>
<el-form-item prop="type">
<el-text class="mx-1" size="large">充值类型</el-text>
<el-select
v-model="detailY.type"
placeholder="请选择充值类型"
style="width: 240px"
clearable
>
<el-option
v-for="item in typeList"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
<!-- <el-form-item prop="payStyle" label="充值平台">
<el-select
v-model="detailY.payStyle"
placeholder="请选择充值平台"
style="width: 240px"
clearable
>
<el-option
v-for="item in platformList"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item> -->
<el-row :span="24">
<el-form-item prop="startTime">
<el-text class="mx-1" size="large">开始时间</el-text>
<el-date-picker
v-model="detailY.startTime"
type="date"
placeholder="开始日期"
style="width: 240px"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
/>
</el-form-item>
<el-form-item prop="endTime">
<el-text class="mx-1" size="large">结束时间</el-text>
<el-date-picker
v-model="detailY.endTime"
type="date"
placeholder="结束日期"
style="width: 240px"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
/>
</el-form-item>
<el-button style="margin-left: 10px" @click="getToday()"></el-button>
<el-button @click="getYesterday()"></el-button>
<el-button @click="get7Days()">近7天</el-button>
</el-row>
<el-form-item>
<el-button type="primary" @click="search">查询</el-button>
<el-button type="success" @click="reset(ruleFormRef)">重置</el-button>
<el-button type="primary" @click="showExportInfoPanel = true">导出excel</el-button>
</el-form-item>
</el-form>
</div>
<!-- 导出excel提前展示的信息面板 -->
<el-dialog
v-model="showExportInfoPanel"
title="导出信息确认"
width="400px"
:close-on-click-modal="false"
>
<div class="info-panel-header">导出信息</div>
<div v-if="!detailY.jwcode && !detailY.deptName && !detailY.orderNo && !detailY.type && !detailY.startTime && !detailY.endTime">
你正在导出所有数据
</div>
<div v-else>
你正在导出以下数据
</div>
<div v-if="detailY.jwcode">精网号{{ detailY.jwcode || '' }}</div>
<div v-if="detailY.deptName">所属地区{{ detailY.deptName || '' }}</div>
<div v-if="detailY.orderNo">订单号{{ detailY.orderNo || '' }}</div>
<div v-if="detailY.type">充值类型{{ detailY.type || '' }}</div>
<div v-if="detailY.startTime || detailY.endTime">
<span>更新时间</span>
<span>{{ detailY.startTime || '无起始时间' }} {{ detailY.endTime || '无结束时间' }}</span>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="showExportInfoPanel = false">取消</el-button>
<el-button type="primary" @click="doExportExcel">导出</el-button>
</span>
</template>
</el-dialog>
<!-- 导出进度弹窗 -->
<el-dialog
v-model="isExporting"
title="正在导出"
width="400px"
:close-on-click-modal="false"
:show-close="false"
>
<el-progress
:percentage="exportProgress"
:stroke-width="15"
striped
animated
/>
<div class="export-status">
已导出 {{ exportedCount }} / {{ totalExport }}
</div>
<template #footer>
<el-button type="danger" @click="cancelExport">取消导出</el-button>
</template>
</el-dialog>
<div class="table-box">
<div
>金豆总数充值金豆总数{{ countValue }}合计金额数{{
priceValue
}}</div
>
<el-table :data="tableData" style="width: 100%" height="584px">
<el-table-column type="index" label="序号" width="100px" fixed="left">
<template #default="scope">
<span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template>
</el-table-column>
<el-table-column fixed="left" prop="nickname" label="姓名" width="150" />
<el-table-column fixed="left" prop="jwcode" label="精网号" width="120" />
<el-table-column prop="ipAddress" label="地区" width="120" />
<el-table-column prop="orderNo" label="订单号" width="120" />
<el-table-column prop="money" label="金豆数量" width="120">
</el-table-column>
<el-table-column prop="moneyBuy" label="付费金豆" width="120">
</el-table-column>
<el-table-column prop="moneyFree" label="免费金豆" width="120">
</el-table-column>
<el-table-column prop="price" label="金额"></el-table-column>
<el-table-column prop="type" label="类型"></el-table-column>
<!-- <el-table-column prop="payStyle" label="充值平台" width="140">
</el-table-column>
<el-table-column prop="notes" label="备注" width="210"></el-table-column> -->
<el-table-column
prop="time"
label="充值时间"
width="210"
show-overflow-tooltip
>
<template #default="scope">
<span>{{
!!scope.row.time
? moment.unix(scope.row.time).format('YYYY-MM-DD HH:mm:ss')
: '-'
}}</span>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="pagination">
<el-pagination
background
:page-size="getObj.pageSize"
:page-sizes="[5, 10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handlePageSizeChange"
@current-change="handleCurrentChange"
>
</el-pagination>
</div>
</div>
<!-- 这是导出excel的弹窗 -->
<!-- <el-dialog
v-model="dialogVisible"
title="请选择导出条件"
width="500"
:close-on-click-modal="false"
@close="
() => {
dialogVisible = false
isExport = false
}
"
>
<template #footer>
<el-form
ref="ruleFormRef"
style="max-width: 600px"
:model="excelData"
:rules="rules"
label-width="auto"
class="demo-ruleForm"
status-icon
>
<el-form-item prop="activityName" label="精网号:">
<el-input
v-model="excelData.jwcode"
placeholder="请输入精网号"
style="width: 220px"
/>
</el-form-item>
<el-form-item label="所属地区:"
><el-select
v-model="excelData.area"
placeholder="请选择所属地区"
style="width: 240px"
clearable
>
<el-option
v-for="item in areaList"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item label="更新时间:">
<el-radio-group v-model="excelData.timegap">
<el-radio value="1">今天</el-radio>
<el-radio value="3">近三天</el-radio>
<el-radio value="7">近一周</el-radio>
<el-radio value="30">近一个月</el-radio>
</el-radio-group>
</el-form-item>
<el-button
type="primary"
size="small"
style="margin-left: 10px"
@click="exportConfirm()"
>确定</el-button
>
</el-form>
</template>
</el-dialog> -->
</template>
<script setup lang="ts">
import { reactive, ref, onMounted, onUnmounted } from 'vue'
import { FormInstance } from 'element-plus'
import { ElMessage } from 'element-plus'
import moment from 'moment'
import API from '@/util/http'
import { utils, write } from 'xlsx'
import { saveAs } from 'file-saver'
const showExportInfoPanel = ref(false)
const isExporting = ref(false)
const exportProgress = ref(0)
const totalExport = ref(0)
const exportedCount = ref(0)
let cancelToken: any = null
let allExportData: any[] = []
//
const cancelExport = () => {
if (cancelToken) {
cancelToken.cancel('导出已取消')
}
isExporting.value = false
exportProgress.value = 0
exportedCount.value = 0
allExportData = []
ElMessage.info('导出已取消')
}
// Excel
const doExportExcel = async () => {
try {
isExporting.value = true
exportProgress.value = 0
exportedCount.value = 0
allExportData = []
//
const totalResult = await API({
url: '/dou/getPay',
data: {
pay: {
jwcode: detailY.value.jwcode,
deptName: detailY.value.deptName,
startTime: detailY.value.startTime || '',
endTime: detailY.value.endTime || '',
payStyle: detailY.value.payStyle,
type: detailY.value.type,
orderNo: detailY.value.orderNo,
sortField: '',
sortOrder: ''
},
pageNum: 1,
pageSize: 1
}
})
totalExport.value = totalResult.data.total
if (totalExport.value === 0) {
ElMessage.error('没有数据可导出')
isExporting.value = false
return
}
const pageSize = 5000 // 100
const totalPages = Math.ceil(totalExport.value / pageSize)
for (let page = 1; page <= totalPages; page++) {
if (!isExporting.value) break //
const result = await API({
url: '/dou/getPay',
data: {
pay: {
jwcode: detailY.value.jwcode,
deptName: detailY.value.deptName,
startTime: detailY.value.startTime || '',
endTime: detailY.value.endTime || '',
payStyle: detailY.value.payStyle,
type: detailY.value.type,
orderNo: detailY.value.orderNo,
sortField: '',
sortOrder: ''
},
pageNum: page,
pageSize: pageSize
}
})
const data = result.data.list
allExportData = allExportData.concat(data)
exportedCount.value = allExportData.length
exportProgress.value = Math.round((exportedCount.value / totalExport.value) * 100)
}
if (isExporting.value) {
//
const exportData = allExportData.map((item, index) => {
return {
序号: index + 1, //
姓名: item.nickname,
精网号: item.jwcode,
地区: item.ipAddress,
订单号: item.orderNo,
金豆数量: item.money,
付费金豆: item.moneyBuy,
免费金豆: item.moneyFree,
金额: item.price,
类型: item.type,
充值时间: !!item.time ? moment.unix(item.time).format('YYYY-MM-DD HH:mm:ss') : '-'
}
})
const worksheet = utils.json_to_sheet(exportData)
const workbook = utils.book_new()
utils.book_append_sheet(workbook, worksheet, 'Sheet1')
const wbout = write(workbook, { bookType: 'xlsx', type: 'array' })
saveAs(
new Blob([wbout], { type: 'application/octet-stream' }),
'金豆充值明细导出.xlsx'
)
showExportInfoPanel.value = false
isExporting.value = false
ElMessage.success('导出成功')
}
} catch (error) {
if (error.message === '导出已取消') {
return
}
console.log('导出失败', error)
isExporting.value = false
ElMessage.error('导出失败,请稍后重试')
}
}
//
const tableData = ref([])
//
const total = ref(100)
const dialogVisible = ref(false)
const excelData = reactive({
jwcode: '',
area: '',
timegap: '',
startTime: '',
endTime: ''
})
const priceValue = ref(0)
const countValue = ref(0)
// areaList
const areaList = ref<string[]>([])
const isExport = ref<boolean>(false)
const rules = ref({
jwcode: [{ required: true, message: '请输入精网号', trigger: 'blur' }],
area: [{ required: true, message: '请选择所属地区', trigger: 'change' }]
})
//
const getToday = function () {
const today = new Date()
//
const startDate = moment(today).startOf('day').format('YYYY-MM-DD HH:mm:ss')
//
const endDate = moment(today).endOf('day').format('YYYY-MM-DD HH:mm:ss')
detailY.value.startTime = startDate
detailY.value.endTime = endDate
search()
}
//
const getYesterday = function () {
const yesterday = moment().subtract(1, 'days')
//
const startDate = yesterday.startOf('day').format('YYYY-MM-DD HH:mm:ss')
//
const endDate = yesterday.endOf('day').format('YYYY-MM-DD HH:mm:ss')
detailY.value.startTime = startDate
detailY.value.endTime = endDate
search()
}
// 7
const get7Days = function () {
//
const startDate = moment().subtract(6, 'days').startOf('day').format('YYYY-MM-DD HH:mm:ss')
//
const endDate = moment().endOf('day').format('YYYY-MM-DD HH:mm:ss')
detailY.value.startTime = startDate
detailY.value.endTime = endDate
search()
}
//
const getArea = async () => {
try {
const result = await API({
url: '/dou/getPayIp'
})
areaList.value = result.data
} catch (error) {
console.log('请求失败', error)
}
}
const getType = async () => {
try {
const result = await API({
url: '/dou/getType'
})
typeList.value = result.data
} catch (error) {
console.log('请求失败', error)
}
}
const handlePageSizeChange = (val) => {
getObj.value.pageSize = val
getObj.value.pageNum = 1
getInit({})
}
const handleCurrentChange = function (val) {
getObj.value.pageNum = val
getInit({})
}
const platformList = ref<string[]>([
// 'stripe',
// 'ios',
// 'FirstData',
// 'paymentasia',
// 'system',
// ''
])
const typeList = ref<string[]>([
'金币换金豆',
'金币换免费金豆',
'赠送金豆',
'购买金豆',
'客服操作'
])
//
const detailY = ref({
jwcode: '',
deptName: '',
orderNo: '',
payStyle: '',
type: '',
startTime:'',
endTime:''
})
const getObj = ref({
pageNum: 1,
pageSize: 50
})
// const exportExcel = function () {
// dialogVisible.value = true
// isExport.value = true
// }
// const exportConfirm = function () {
// if (excelData.timegap == '1') {
// excelData.startTime = moment().startOf('day').format('YYYY-MM-DD HH:mm:ss')
// excelData.endTime = moment().endOf('day').format('YYYY-MM-DD HH:mm:ss')
// } else if (excelData.timegap == '3') {
// excelData.startTime = moment()
// .subtract(3, 'days')
// .startOf('day')
// .format('YYYY-MM-DD HH:mm:ss')
// excelData.endTime = moment().endOf('day').format('YYYY-MM-DD HH:mm:ss')
// } else if (excelData.timegap == '7') {
// excelData.startTime = moment()
// .subtract(7, 'days')
// .startOf('day')
// .format('YYYY-MM-DD')
// excelData.endTime = moment().endOf('day').format('YYYY-MM-DD HH:mm:ss')
// } else if (excelData.timegap == '30') {
// excelData.startTime = moment()
// .subtract(30, 'days')
// .startOf('day')
// .format('YYYY-MM-DD HH:mm:ss')
// excelData.endTime = moment().endOf('day').format('YYYY-MM-DD HH:mm:ss')
// }
// getInit(
// {
// sortField: '',
// sortOrder: ''
// },
// (data) => {
// console.log('', data)
// //
// data = data.map((item) => {
// return {
// : item.name,
// : item.jwcode,
// : item.deptName,
// : item.orderNo,
// : item.payStyle,
// : item.count,
// : moment(item.successTime).format('YYYY-MM-DD'),
// : item.price
// }
// })
// if (data.length == 0) {
// ElMessage.error('')
// isExport.value = false
// dialogVisible.value = false
// return
// }
// console.log('', data)
// excelExport(data)
// }
// )
// }
//excel
// const excelExport = async function (data) {
// const worksheet = utils.json_to_sheet(data)
// const workbook = utils.book_new()
// utils.book_append_sheet(workbook, worksheet, 'Sheet1')
// const wbout = write(workbook, { bookType: 'xlsx', type: 'array' })
// saveAs(
// new Blob([wbout], { type: 'application/octet-stream' }),
// '.xlsx'
// )
// isExport.value = false
// dialogVisible.value = false
// }
const ruleFormRef = ref<FormInstance>()
//
const getInit = async function (
{
sortField = '',
sortOrder = ''
}: {
sortField?: string
sortOrder?: string
},
// callback?: Function
) {
try {
console.log('搜索参数', getObj.value)
const startTime = detailY.value.startTime
const endTime = detailY.value.endTime
console.log(startTime, endTime)
// POST
const result = await API({
url: '/dou/getPay',
data: {
pay: {
jwcode: detailY.value.jwcode,
deptName: detailY.value.deptName,
startTime: detailY.value.startTime || '',
endTime: detailY.value.endTime || '',
payStyle: detailY.value.payStyle,
type: detailY.value.type,
orderNo: detailY.value.orderNo,
sortField,
sortOrder
},
pageNum: getObj.value.pageNum,
pageSize: getObj.value.pageSize
}
})
// if (isExport.value) {
// !!callback && callback(result.data)
// } else {
tableData.value = result.data.list
total.value = result.data.total
// }
} catch (error) {
console.log('请求失败', error)
//
}
}
const handleSortChange = (column) => {
const { prop, order } = column
if (order === 'ascending') {
getInit({ sortField: prop, sortOrder: 'ASC' })
} else if (order === 'descending') {
getInit({ sortField: prop, sortOrder: 'DESC' })
}
}
//
const trim = () => {
if (detailY.value.jwcode) {
detailY.value.jwcode = detailY.value.jwcode.replace(/\s/g, '');
}
if (detailY.value.orderNo) {
detailY.value.orderNo = detailY.value.orderNo.replace(/\s/g, '');
}
if (detailY.value.type) {
detailY.value.type = detailY.value.type.replace(/\s/g, '');
}
}
//
const search = function () {
trim();
getObj.value.pageNum = 1
getInit({})
getCount()
}
//
const reset = function (formEl) {
formEl.resetFields()
}
//
const getPayType = async () => {
try {
const result = await API({
url: '/dou/getStyle'
})
platformList.value = result.data
// typeList.value = result.data
} catch (error) {
console.log('请求失败', error)
}
}
//
const getCount = async () => {
try {
const result = await API({
url: '/dou/getTotal',
data: {
jwcode: detailY.value.jwcode,
deptName: detailY.value.deptName,
startTime: detailY.value.startTime,
endTime: detailY.value.endTime,
orderNo: detailY.value.orderNo,
type: detailY.value.type
// payStyle: detailY.value.payStyle
}
})
if (!!result.data) {
const { price, count } = result.data
console.log('金豆总数', price, count)
priceValue.value = price
countValue.value = count
} else {
priceValue.value = 0
countValue.value = 0
}
} catch (error) {
console.log('请求失败', error)
}
}
onMounted(() => {
getInit({})
getPayType()
getCount()
getArea()
getType()
})
</script>
<style scoped lang="scss">
.filter-box {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
padding-bottom: 0px;
box-sizing: border-box;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
border-radius: 5px;
.el-form {
display: flex;
flex-wrap: wrap;
row-gap: 20px;
column-gap: 20px;
}
}
.table-box {
width: 100%;
padding: 20px;
box-sizing: border-box;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
border-radius: 5px;
}
.pagination {
display: flex;
align-items: center;
margin-top: 10px;
}
.filter-box {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
padding-bottom: 0px;
box-sizing: border-box;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
border-radius: 5px;
.el-form {
display: flex;
flex-wrap: wrap;
row-gap: 20px;
column-gap: 20px;
}
}
.table-box {
width: 100%;
padding: 20px;
box-sizing: border-box;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
border-radius: 5px;
}
.pagination {
display: flex;
align-items: center;
margin-top: 10px;
}
</style>

582
src/views/goldBeen/onLineDetail.vue

@ -0,0 +1,582 @@
<template>
<!-- 这是线上充值明细页面 -->
<!-- 这是搜索表单 -->
<div class="filter-box">
<el-form :model="detailY" ref="ruleFormRef">
<el-form-item prop="jwcode">
<el-text class="mx-1" size="large">精网号</el-text>
<el-input
v-model="detailY.jwcode"
placeholder="请输入精网号"
style="width: 220px"
/>
</el-form-item>
<el-form-item prop="deptName">
<el-text class="mx-1" size="large">地区</el-text>
<el-select
v-model="detailY.deptName"
placeholder="请选择所属地区"
style="width: 240px"
clearable
>
<el-option
v-for="item in areaList"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item prop="orderNo">
<el-text class="mx-1" size="large">订单号</el-text>
<el-input
v-model="detailY.orderNo"
placeholder="请输入订单号"
style="width: 220px"
/>
</el-form-item>
<el-form-item prop="payStyle">
<el-text class="mx-1" size="large">充值平台</el-text>
<el-select
v-model="detailY.payStyle"
placeholder="请选择充值平台"
style="width: 240px"
clearable
>
<el-option
v-for="item in platformList"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item prop="startTime">
<el-text class="mx-1" size="large">开始时间</el-text>
<el-date-picker
v-model="detailY.startTime"
type="date"
placeholder="开始日期"
style="width: 240px"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
/>
</el-form-item>
<el-form-item prop="endTime">
<el-text class="mx-1" size="large">结束时间</el-text>
<el-date-picker
v-model="detailY.endTime"
type="date"
placeholder="结束日期"
style="width: 240px"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
/>
<el-button style="margin-left: 10px" @click="getToday()"></el-button>
<el-button @click="getYesterday()"></el-button>
<el-button @click="get7Days()">近7天</el-button>
</el-form-item>
<el-col :span="10">
<el-form-item>
<el-button type="primary" @click="search">查询</el-button>
<el-button type="success" @click="reset(ruleFormRef)">重置</el-button>
<!-- 这是重置参数formEl: FormInstance -->
<!-- 为啥要这个参数 -->
<el-button type="primary" @click="showExportInfoPanel = true">导出excel</el-button>
</el-form-item>
</el-col>
</el-form>
</div>
<div class="table-box">
<div>金豆总数充值金豆总数{{ countValue }}合计金额数{{ priceValue }}</div>
<el-table :data="tableData" style="width: 100%" height="584px">
<el-table-column type="index" label="序号" width="100px" fixed="left">
<template #default="scope">
<span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template>
</el-table-column>
<el-table-column fixed="left" prop="name" label="姓名" width="150" />
<el-table-column fixed="left" prop="jwcode" label="精网号" width="120" />
<el-table-column prop="deptName" label="地区" width="120" />
<el-table-column prop="orderNo" label="订单号" width="120" />
<el-table-column prop="count" label="金豆数量" width="120" />
<el-table-column prop="price" label="金额" />
<el-table-column prop="payStyle" label="充值平台" width="140" />
<el-table-column
prop="successTime"
label="充值时间"
width="210"
show-overflow-tooltip
>
<template #default="scope">
<span>{{
!!scope.row.successTime
? moment.unix(scope.row.successTime).format('YYYY-MM-DD HH:mm:ss')
: '-'
}}</span>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="pagination">
<el-pagination
background
:page-size="getObj.pageSize"
:page-sizes="[5, 10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handlePageSizeChange"
@current-change="handleCurrentChange"
>
</el-pagination>
</div>
</div>
<!-- 导出excel提前展示的信息面板 -->
<el-dialog
v-model="showExportInfoPanel"
title="导出信息确认"
width="400px"
:close-on-click-modal="false"
>
<div class="info-panel-header">导出信息</div>
<div v-if="!detailY.jwcode && !detailY.deptName && !detailY.orderNo && !detailY.payStyle && !detailY.startTime && !detailY.endTime">
你正在导出所有数据
</div>
<div v-else>
你正在导出以下数据
</div>
<div v-if="detailY.jwcode">精网号{{ detailY.jwcode || '' }}</div>
<div v-if="detailY.deptName">所属地区{{ detailY.deptName || '' }}</div>
<div v-if="detailY.orderNo">订单号{{ detailY.orderNo || '' }}</div>
<div v-if="detailY.payStyle">充值平台{{ platformList.find(item => item === detailY.payStyle) || '' }}</div>
<div v-if="detailY.startTime || detailY.endTime">
<span>更新时间</span>
<span>{{ detailY.startTime || '无起始时间' }} {{ detailY.endTime || '无结束时间' }}</span>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="showExportInfoPanel = false">取消</el-button>
<el-button type="primary" @click="doExportExcel">导出</el-button>
</span>
</template>
</el-dialog>
<!-- 导出进度弹窗 -->
<el-dialog
v-model="isExporting"
title="正在导出"
width="400px"
:close-on-click-modal="false"
:show-close="false"
>
<el-progress
:percentage="exportProgress"
:stroke-width="15"
striped
animated
/>
<div class="export-status">
已导出 {{ Math.round((exportProgress / 100) * totalExport) }} / {{ totalExport }}
</div>
<template #footer>
<el-button type="danger" @click="cancelExport">取消导出</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { reactive, ref, onMounted } from 'vue'
import { FormInstance } from 'element-plus'
import { ElMessage } from 'element-plus'
import moment from 'moment'
import API from '@/util/http'
import { utils, write } from 'xlsx'
import { saveAs } from 'file-saver'
//
const tableData = ref([])
//
const total = ref(100)
const priceValue = ref(0)
const countValue = ref(0)
const areaList = ref<string[]>([])
const platformList = ref<string[]>([])
//
const getToday = () => {
const today = new Date()
//
const startDate = moment(today).startOf('day').format('YYYY-MM-DD HH:mm:ss')
//
const endDate = moment(today).endOf('day').format('YYYY-MM-DD HH:mm:ss')
detailY.value.startTime = startDate
detailY.value.endTime = endDate
search()
}
//
const getYesterday = () => {
const yesterday = moment().subtract(1, 'days')
//
const startDate = yesterday.startOf('day').format('YYYY-MM-DD HH:mm:ss')
//
const endDate = yesterday.endOf('day').format('YYYY-MM-DD HH:mm:ss')
detailY.value.startTime = startDate
detailY.value.endTime = endDate
search()
}
// 7
const get7Days = () => {
//
const startDate = moment().subtract(6, 'days').startOf('day').format('YYYY-MM-DD HH:mm:ss')
//
const endDate = moment().endOf('day').format('YYYY-MM-DD HH:mm:ss')
detailY.value.startTime = startDate
detailY.value.endTime = endDate
search()
}
const handlePageSizeChange = (val: number) => {
getObj.value.pageSize = val
getObj.value.pageNum = 1
getInit({})
}
const handleCurrentChange = (val: number) => {
getObj.value.pageNum = val
getInit({})
}
//
const detailY = ref({
jwcode: '',
deptName: '',
orderNo: '',
payStyle: '',
startTime: '',
endTime: ''
})
const getObj = ref({
pageNum: 1,
pageSize: 50
})
//
const ruleFormRef = ref<FormInstance>()
//
const getInit = async (
{
sortField = '',
sortOrder = ''
}: {
sortField?: string
sortOrder?: string
}
) => {
try {
console.log('搜索参数', getObj.value)
const startTime = detailY.value.startTime
const endTime = detailY.value.endTime
console.log(startTime, endTime)
// POST
const result = await API({
url: '/dou/SearchPay',
data: {
pay: {
jwcode: detailY.value.jwcode,
deptName: detailY.value.deptName,
startTime: startTime || '',
endTime: endTime || '',
payStyle: detailY.value.payStyle,
orderNo: detailY.value.orderNo,
sortField,
sortOrder
},
pageNum: getObj.value.pageNum,
pageSize: getObj.value.pageSize
}
})
tableData.value = result.data.list
total.value = result.data.total
} catch (error) {
console.log('请求失败', error)
//
}
}
//
const trimJwCode = () => {
if (detailY.value.jwcode) {
detailY.value.jwcode = detailY.value.jwcode.replace(/\s/g, '')
}
if (detailY.value.orderNo) {
detailY.value.orderNo = detailY.value.orderNo.replace(/\s/g, '')
}
}
//
const search = () => {
trimJwCode()
getObj.value.pageNum = 1
getInit({})
getCount()
}
//
const reset = (formEl: FormInstance) => {
formEl.resetFields()
}
//
const getPayPlatform = async () => {
try {
const result = await API({
url: '/dou/SearchStyle'
})
platformList.value = result.data
} catch (error) {
console.log('请求失败', error)
}
}
//
const getArea = async () => {
try {
const result = await API({
url: '/dou/SearchPayIp'
})
areaList.value = result.data
} catch (error) {
console.log('请求失败', error)
}
}
//
const getPayType = async () => {
try {
const result = await API({
url: '/dou/getStyle'
})
platformList.value = result.data
} catch (error) {
console.log('请求失败', error)
}
}
//
const getCount = async () => {
try {
// let startTime = ''
// let endTime = ''
// if (Array.isArray(detailY.value.createTime) && detailY.value.createTime.length === 2) {
// [startTime, endTime] = detailY.value.createTime
// }
const result = await API({
url: '/dou/getRechargeTotal',
data: {
jwcode: detailY.value.jwcode,
deptName: detailY.value.deptName,
startTime: detailY.value.startTime,
endTime: detailY.value.endTime,
orderNo: detailY.value.orderNo,
payStyle: detailY.value.payStyle
}
})
if (result.data) {
console.log('合计数', result.data)
const { priceTotal, countTotal } = result.data
console.log('金豆总数', priceTotal, countTotal)
priceValue.value = priceTotal
countValue.value = countTotal
} else {
priceValue.value = 0
countValue.value = 0
}
} catch (error) {
console.log('请求失败', error)
}
}
//
const showExportInfoPanel = ref(false)
const isExporting = ref(false)
const exportProgress = ref(0)
const totalExport = ref(0)
let allExportData: any[] = []
let cancelToken: any = null
//
const cancelExport = () => {
if (cancelToken) {
cancelToken.cancel('导出已取消')
}
isExporting.value = false
exportProgress.value = 0
allExportData = []
ElMessage.info('导出已取消')
}
// Excel
const doExportExcel = async () => {
try {
isExporting.value = true
exportProgress.value = 0
allExportData = []
// let startTime = ''
// let endTime = ''
// if (Array.isArray(detailY.value.createTime) && detailY.value.createTime.length === 2) {
// [startTime, endTime] = detailY.value.createTime
// }
// startTime = detailY.value.startTime
// endTime = detailY.value.endTime
//
const totalResult = await API({
url: '/dou/SearchPay',
data: {
pay: {
jwcode: detailY.value.jwcode,
deptName: detailY.value.deptName,
startTime: detailY.value.startTime || '',
endTime: detailY.value.endTime || '',
payStyle: detailY.value.payStyle,
orderNo: detailY.value.orderNo
},
pageNum: 1,
pageSize: 1
}
})
totalExport.value = totalResult.data.total
if (totalExport.value === 0) {
ElMessage.error('没有数据可导出')
isExporting.value = false
showExportInfoPanel.value = false
return
}
const pageSize = 1000 // 100
const totalPages = Math.ceil(totalExport.value / pageSize)
for (let page = 1; page <= totalPages; page++) {
if (!isExporting.value) break //
const result = await API({
url: '/dou/SearchPay',
data: {
pay: {
jwcode: detailY.value.jwcode,
deptName: detailY.value.deptName,
startTime: detailY.value.startTime || '',
endTime: detailY.value.endTime || '',
payStyle: detailY.value.payStyle,
orderNo: detailY.value.orderNo
},
pageNum: page,
pageSize: pageSize
}
})
const data = result.data.list
allExportData = allExportData.concat(data)
const exportedCount = allExportData.length
exportProgress.value = Math.round((exportedCount / totalExport.value) * 100)
}
if (isExporting.value) {
//
const exportData = allExportData.map((item, index) => {
return {
序号: index + 1, //
姓名: item.name,
精网号: item.jwcode,
地区: item.deptName,
订单号: item.orderNo,
金豆数量: item.count,
金额: item.price,
充值平台: item.payStyle,
充值时间: !!item.successTime ? moment.unix(item.successTime).format('YYYY-MM-DD HH:mm:ss') : '-'
}
})
const worksheet = utils.json_to_sheet(exportData)
const workbook = utils.book_new()
utils.book_append_sheet(workbook, worksheet, 'Sheet1')
const wbout = write(workbook, { bookType: 'xlsx', type: 'array' })
saveAs(
new Blob([wbout], { type: 'application/octet-stream' }),
'线上充值明细导出.xlsx'
)
isExporting.value = false
showExportInfoPanel.value = false
ElMessage.success('导出成功')
}
} catch (error) {
if (error instanceof Error && error.message === '导出已取消') {
return
}
console.log('导出失败', error)
isExporting.value = false
showExportInfoPanel.value = false
ElMessage.error('导出失败,请稍后重试')
}
}
onMounted(() => {
getInit({})
getArea()
getPayType()
getCount()
getPayPlatform()
})
</script>
<style scoped lang="scss">
.filter-box {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
padding-bottom: 0px;
box-sizing: border-box;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
border-radius: 5px;
.el-form {
display: flex;
flex-wrap: wrap;
row-gap: 20px;
column-gap: 20px;
}
}
.table-box {
width: 100%;
padding: 20px;
box-sizing: border-box;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
border-radius: 5px;
}
.pagination {
display: flex;
align-items: center;
margin-top: 10px;
}
</style>
<<<<<<< HEAD
=======
>>>>>>> 703486fc8c3f87173c028d61161e502a2e07fdfc

378
src/views/index.vue

@ -0,0 +1,378 @@
<script setup>
//
// index
import { ref, onMounted, reactive, computed, watch } from 'vue'
import { useRouter } from 'vue-router'
import ElementPlus from 'element-plus'
import { VscGlobe } from 'vue-icons-plus/vsc'
import { ElMessage } from 'element-plus'
import axios from 'axios'
import { ElMessageBox } from 'element-plus'
import API from '@/util/http'
import dmmn from '../assets/avator.png'
import { useRoute } from 'vue-router'
import { storeToRefs } from 'pinia'
import { useAreaStore } from '@/store/area'
const router = useRouter()
const imgrule1 = dmmn
const messageVisible = ref(false)
const areaStore = useAreaStore()
const { currentArea, updateArea } = storeToRefs(areaStore)
//
const adminData = ref({
name: ''
})
const getAdminData = async function () {
try {
const result = await API({ url: '/admin/userinfo', data: {} })
adminData.value = result
console.log('请求成功', result)
console.log('用户信息', adminData.value)
} catch (error) {
console.log('请求失败', error)
}
}
//
const areas = ref([])
const getAreas = async function () {
try {
const result = await API({ url: '/recharge/user/search', data: {} })
areas.value = result.data
console.log('请求成功', result)
} catch (error) {
console.log('请求失败', error)
}
}
//
const openMessage = function () {
messageVisible.value = true
}
const closeMessage = function () {
messageVisible.value = false
}
const message = function () {
openMessage()
}
// machineId
function logout() {
const machineId = localStorage.getItem('machineId')
console.log('machineId:', machineId)
localStorage.removeItem('token')
// localStorage.clear();
router.push('/login?machineId=' + machineId)
//
// window.location.reload();
ElMessage.success('退出成功')
}
//
onMounted(async function () {
//
getAdminData()
//
getAreas()
})
//
const changeDataByArea = (item) => {
areaStore.updateArea(item)
}
</script>
<template>
<div class="common-layout">
<el-container>
<el-aside
style="
width: 15%;
min-width: 180px;
position: fixed; /* 固定位置 */
top: 0;
left: 0;
height: 100vh; /* 高度占满视口 */
z-index: 100; /* 确保侧边栏在其他元素之上 */
"
>
<div class="logo">
<img
src="../assets/金币管理系统logo.png"
alt="logo"
style="width: 30px; height: 30px"
/>
<div style="font-size: 16px; font-weight: bold">海外金币管理系统</div>
</div>
<el-menu
:router="true"
background-color="#08193d"
active-text-color="#ffd04b"
text-color="white"
class="el-menu-vertical-demo"
>
<el-menu-item
index="/workspace"
v-if="
adminData.permission == 1 ||
adminData.permission == 2 ||
adminData.permission == 3 ||
adminData.permission == 5
"
>
<el-icon>
<Folder />
</el-icon>
工作台
</el-menu-item>
<el-sub-menu
index="2"
v-if="
adminData.permission == 1 ||
adminData.permission == 3 ||
adminData.permission == 5
"
>
<template #title>
<el-icon>
<Folder />
</el-icon>
<span>财务审核</span>
</template>
<el-menu-item index="/rechargeAudit">充值审核</el-menu-item>
<el-menu-item index="/refundAudit">退款审核</el-menu-item>
</el-sub-menu>
<el-sub-menu
index="3"
v-if="
adminData.permission == 1 ||
adminData.permission == 3 ||
adminData.permission == 5
"
>
<template #title>
<el-icon>
<Folder />
</el-icon>
<span>充值管理</span>
</template>
<!-- <el-menu-item index="/activity">活动管理</el-menu-item> -->
<el-menu-item index="/rate">汇率管理</el-menu-item>
</el-sub-menu>
<el-sub-menu
index="4"
v-if="
adminData.permission == 1 ||
adminData.permission == 2 ||
adminData.permission == 5
"
>
<template #title>
<el-icon>
<Folder />
</el-icon>
<span>充值</span>
</template>
<el-sub-menu index="5">
<template #title>金币充值</template>
<el-menu-item index="/addRecharge">新增充值</el-menu-item>
<el-menu-item index="/adminRecharge">客服充值明细</el-menu-item>
<el-menu-item index="/allRecharge">所有充值明细</el-menu-item>
</el-sub-menu>
</el-sub-menu>
<el-sub-menu
index="6"
v-if="
adminData.permission == 1 ||
adminData.permission == 2 ||
adminData.permission == 5
"
>
<template #title>
<el-icon>
<Folder />
</el-icon>
<span>消费</span>
</template>
<el-sub-menu index="7">
<template #title>金币消费</template>
<el-menu-item index="/addConsume">新增消费</el-menu-item>
<el-menu-item index="/allConsume">所有消费明细</el-menu-item>
</el-sub-menu>
</el-sub-menu>
<el-sub-menu
index="8"
v-if="
adminData.permission == 1 ||
adminData.permission == 2 ||
adminData.permission == 5
"
>
<template #title>
<el-icon>
<Folder />
</el-icon>
<span>退款</span>
</template>
<el-sub-menu index="9">
<template #title>金币退款</template>
<el-menu-item index="/addRefund">新增退款</el-menu-item>
<el-menu-item index="/allRefund">退款明细</el-menu-item>
</el-sub-menu>
</el-sub-menu>
<!-- <el-sub-menu index="10">
<template #title
><el-icon> <Folder /> </el-icon></template
>
<el-menu-item index="/addGoldenBeen">金豆充值</el-menu-item>
<el-menu-item index="/goldenBeenDetail">金豆充值明细</el-menu-item>
<el-menu-item index="/onLineDetail">线上充值明细</el-menu-item>
<el-menu-item index="/goldenBeenConsum">金豆消费明细</el-menu-item>
<el-menu-item index="/goldenBeenBalance">客户金豆余额</el-menu-item>
</el-sub-menu> -->
<el-menu-item
index="/usergold"
v-if="
adminData.permission == 1 ||
adminData.permission == 2 ||
adminData.permission == 3 ||
adminData.permission == 5
"
>
<el-icon>
<Folder />
</el-icon>
客户金币明细
</el-menu-item>
<el-menu-item
index="/usergoldInfo"
v-if="
adminData.permission == 1 ||
adminData.permission == 2 ||
adminData.permission == 3 ||
adminData.permission == 5
"
>
<el-icon>
<Folder />
</el-icon>
客户金币余额
</el-menu-item>
<el-menu-item index="/permissions" v-if="adminData.permission == 1">
<el-icon>
<Folder />
</el-icon>
权限管理
</el-menu-item>
</el-menu>
</el-aside>
<el-container style="margin-left: 15%; min-width: 180px">
<!-- 修改 el-header 样式 -->
<el-header
style="
position: fixed;
top: 0;
left: 15%;
right: 0;
z-index: 80;
background: white;
"
>
<el-menu class="el-menu-demo" mode="horizontal" :ellipsis="false">
<el-sub-menu index="1" class="area">
<template #title>
<VscGlobe />
<!-- {{ currentArea }} -->
</template>
<!-- <el-menu-item
v-for="(item, index) in areas"
:key="index"
@click="changeDataByArea(item)"
>
{{ item }}
</el-menu-item> -->
</el-sub-menu>
</el-menu>
<el-menu class="el-menu-demo" mode="horizontal" :ellipsis="false">
<el-sub-menu index="1" class="admin">
<template #title>
<el-image
:src="imgrule1"
alt="错误"
style="width: 50px; height: 50px"
/>
<span style="margin-left: 10px">{{ adminData.name }}</span>
</template>
<el-menu-item @click="message()">查看个人信息</el-menu-item>
<el-menu-item index="1-2" @click="logout">退出登录</el-menu-item>
</el-sub-menu>
</el-menu>
</el-header>
<!-- 修改 el-main 样式 -->
<el-main style="margin-top: 60px">
<!-- 60px el-header 的大致高度可根据实际情况调整 -->
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</div>
<!-- 查看个人信息 -->
<el-dialog v-model="messageVisible" title="查看个人信息" width="500px">
<el-form :model="adminData">
<el-form-item label="用户姓名" label-width="100px" label-position="left">
<span class="message-font">{{ adminData.name }}</span>
</el-form-item>
<el-form-item label="精网号" label-width="100px" label-position="left">
<span class="message-font">{{ adminData.jwcode }}</span>
</el-form-item>
<el-form-item label="地区" label-width="100px" label-position="left">
<span class="message-font">{{ adminData.area }}</span>
</el-form-item>
<el-form-item label="注册时间" label-width="100px" label-position="left">
<span class="message-font">{{ adminData.createTime }}</span>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button text @click="closeMessage()">关闭</el-button>
</div>
</template>
</el-dialog>
</template>
<style scoped>
.message-font {
font-size: 16px;
font-weight: bold;
}
.admin {
margin-left: auto;
}
.el-aside {
background-color: #08193d;
min-height: 100vh;
width: 200px;
}
.logo {
color: white;
margin: 20px 0px 20px 20px;
display: flex;
}
.el-menu {
border: none; /* 去除边框 */
padding: 0; /* 去除内边距 */
}
.el-menu-demo {
float: right; /* 将菜单向右浮动 */
}
</style>

243
src/views/login.vue

@ -0,0 +1,243 @@
<script setup>
import { ref, onMounted, reactive, computed } from 'vue'
import { ElMessage } from 'element-plus'
import axios from 'axios'
import request from '@/util/http'
import { useRouter } from 'vue-router'
import { VscGlobe } from 'vue-icons-plus/vsc'
//
var url = window.location.href //
//machineId=
var machineId = null
// machineId
function getMachineId() {
var parts = url.split('machineId=')
if (parts.length > 1) {
machineId = parts[1].split('&')[0] // &
}
// machineId = decodeURIComponent(machineId); //machineId
console.log('MachineId字符串:', machineId) // machineId
// machineId
if (machineId) {
localStorage.setItem('machineId', machineId)
}
}
getMachineId()
const router = useRouter() //
let formData = new FormData()
// FormData
// formData.append("jwcode", form.value.jwcode);
// formData.append("password", form.value.password);
const form = ref({ jwcode: '', password: '', token: '', machineId: machineId })
//
const login = async function () {
try {
const result = await request({
url: '/admin/login',
data: form.value
})
console.log('resultresult', result)
if (result.code == 200) {
localStorage.setItem('token', result.msg)
localStorage.setItem('permission', result.data.permission)
if (
result.data.permission == '5' ||
result.data.permission == '1' ||
result.data.permission == '2' ||
result.data.permission == '3'
) {
router.push('/workspace')
} else if (result.data.permission == '4') {
router.push('/noPermission')
}
ElMessage.success('登录成功')
console.log('请求成功', result)
} else {
form.value.password = ''
form.value.jwcode = ''
ElMessage.error(result.msg)
}
} catch (error) {
console.log('请求失败', error)
ElMessage.error('登录失败,请检查账号密码')
//
}
}
</script>
<template>
<el-row class="login-page">
<img
:span="12"
src="../assets/background.jpg"
alt="logo"
class="bg"
fit="fit"
/>
<!-- <div style="height: 100vh; width: 1000px" class="container"></div> -->
<el-col :span="6" :offset="3" class="form">
<!-- 登录表单 -->
<el-form :model="form" size="large" autocomplete="off" >
<el-form-item>
<h1 style="color: #409eff">金币系统登录</h1>
</el-form-item>
<el-form-item prop="jwcode">
<el-input v-model="form.jwcode" placeholder="请输入精网号" @keyup.enter="login"></el-input>
</el-form-item>
<el-form-item prop="password" @keyup.enter="login">
<el-input
v-model="form.password"
type="password"
placeholder="请输入密码"
/>
</el-form-item>
<el-form-item class="flex"> </el-form-item>
<!-- 登录按钮 -->
<el-form-item>
<button type="button" class="button" @click="login()">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
height="30"
width="24"
>
<path
fill="white"
d="M23.15 2.587L18.21 0.210001C17.9308 0.075557 17.6167 0.031246 17.3113 0.083204C17.0058 0.135162 16.724 0.280818 16.505 0.500001L7.04499 9.13L2.92499 6.002C2.73912 5.86101 2.50976 5.78953 2.27669 5.79994C2.04363 5.81035 1.82156 5.902 1.64899 6.059L0.326993 7.261C0.223973 7.35465 0.141644 7.46878 0.0852761 7.59608C0.0289081 7.72339 -0.00025659 7.86106 -0.000350724 8.00028C-0.000444857 8.1395 0.0285336 8.27721 0.0847294 8.40459C0.140925 8.53197 0.2231 8.64621 0.325993 8.74L3.89899 12L0.325993 15.26C0.2231 15.3538 0.140925 15.468 0.0847294 15.5954C0.0285336 15.7228 -0.000444857 15.8605 -0.000350724 15.9997C-0.00025659 16.1389 0.0289081 16.2766 0.0852761 16.4039C0.141644 16.5312 0.223973 16.6454 0.326993 16.739L1.64999 17.94C1.82256 18.097 2.04463 18.1887 2.27769 18.1991C2.51076 18.2095 2.74012 18.138 2.92599 17.997L7.04599 14.869L16.506 23.499C16.7248 23.7182 17.0064 23.8639 17.3117 23.9159C17.6171 23.9679 17.931 23.9235 18.21 23.789L23.152 21.412C23.4062 21.2893 23.6207 21.0973 23.7707 20.8581C23.9207 20.619 24.0002 20.3423 24 20.06V3.939C24 3.65647 23.9203 3.37967 23.7699 3.14048C23.6195 2.90129 23.4046 2.70943 23.15 2.587ZM18.004 17.448L10.826 12L18.004 6.552V17.448Z"
></path>
</svg>
<p class="text">登录</p>
</button>
<!-- <el-button
class="button"
type="primary"
auto-insert-space
@click="login()"
>登录</el-button
> -->
</el-form-item>
</el-form>
</el-col>
</el-row>
</template>
<style scoped>
.bg {
border-radius: 0 20px 20px 0;
height: 110vh;
width: 50%;
object-fit: cover;
}
.background {
color: #fffdfd;
text-align: center;
font-size: 24px;
background-color: #08193d;
}
.form {
display: flex;
flex-direction: column;
justify-content: center;
user-select: none;
.title {
margin: 0 auto;
}
.button {
width: 100%;
}
.flex {
width: 100%;
display: flex;
justify-content: space-between;
}
}
/* From Uiverse.io by kamehame-ha */
.button {
height: 50px;
display: flex;
justify-content: center;
align-items: center;
padding: 10px 15px;
gap: 15px;
background-color: #1b95e6;
outline: 3px #1b95e6 solid;
outline-offset: -3px;
border-radius: 5px;
border: none;
cursor: pointer;
transition: 400ms;
}
.button .text {
color: white;
font-weight: 700;
font-size: 1em;
transition: 400ms;
}
.button svg path {
transition: 400ms;
}
.button:hover {
background-color: transparent;
}
.button:hover .text {
color: #007acc;
}
.button:hover svg path {
fill: #007acc;
}
/* .box {
padding: 20px;
border-radius: 10px;
background-color: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
} */
/* From Uiverse.io by marsella_3472 */
/*
More comprehensive version at shenanigans.shoghisimon.ca/collection/css
*/
/* From Uiverse.io by SelfMadeSystem */
.container {
width: 100%;
height: 100%;
background: linear-gradient(#000 1px, #0000 0),
linear-gradient(90deg, #000, #0000, #000),
linear-gradient(in oklch longer hue -2deg, #a00, #a00);
background-size: 100% 2px, 100% 100%, 100% 100%;
}
</style>
<!-- 这是补救
const run = () => {
const width = window.innerWidth;
const height = window.innerHeight;
const chartNode = document.querySelector("main");
drawChart.default(chartNode,data,width,height);
};
window.addEventListener("resize", run);
document.addEventListener("DOMContentLoaded", run);
</script>
</body>
</html>
-->

494
src/views/managerecharge/activity.vue

@ -0,0 +1,494 @@
<script setup>
//
import { ref, onMounted, reactive, computed } from 'vue'
import ElementPlus from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
import axios from 'axios'
import moment from 'moment'
import API from '../../api/index.js'
import _ from 'lodash'
import request from '@/util/http'
//
const adminData = ref({})
const getAdminData = async function () {
try {
const result = await request({
url: '/admin/userinfo',
data: {}
})
adminData.value = result
addObj.value.adminId = adminData.value.adminId
console.log('请求成功', result)
console.log('用户信息', adminData.value)
} catch (error) {
console.log('请求失败', error)
}
}
//
const tableData = ref([])
//
const total = ref(100)
//
const getTime = ref([])
//
const activity = ref({})
//
const getObj = ref({
pageNum: 1,
pageSize: 10
})
//
const addObj = ref({
add: ''
})
//
const delObj = ref({})
//
const get = async function (val) {
try {
//
if (typeof val === 'number') {
getObj.value.pageNum = val
}
//
if (getTime.value.length === 2) {
activity.value.startDate = getTime.value[0]
activity.value.endDate = getTime.value[1]
} else {
activity.value.startDate = null
activity.value.endDate = null
}
const requestData = {
pageNum: getObj.value.pageNum,
pageSize: getObj.value.pageSize,
activity: {
...activity.value,
activityName: activity.value.activityName,
status: activity.value.status
}
};
console.log('搜索参数', requestData)
// POST
const result = await request({
url: '/recharge/activity/select',
method: 'post',
data: requestData
})
//
console.log('响应数据', result);
//
console.log('请求成功', result)
//
tableData.value = result.data.list
console.log('tableData', tableData.value)
//
total.value = result.data.total
console.log('total', total.value)
} catch (error) {
console.log('请求失败', error)
ElMessage.error('请求失败')
}
}
//
const getToday = function () {
const today = new Date()
const startDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate()
)
const endDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() + 1
)
getTime.value = [startDate, endDate]
console.log('getTime', getTime.value)
get()
}
//
const getYesterday = function () {
const yesterday = new Date()
yesterday.setDate(yesterday.getDate() - 1)
const startDate = new Date(
yesterday.getFullYear(),
yesterday.getMonth(),
yesterday.getDate()
)
const endDate = new Date(
yesterday.getFullYear(),
yesterday.getMonth(),
yesterday.getDate() + 1
)
getTime.value = [startDate, endDate]
console.log('getTime', getTime.value)
get()
}
// 7
const get7Days = function () {
const today = new Date()
const startDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() - 6
)
const endDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() + 1
)
getTime.value = [startDate, endDate]
console.log('getTime', getTime.value)
get()
}
//
const trim = () => {
if (activity.value.activityName) {
activity.value.activityName = activity.value.activityName.replace(/\s/g, '');
}
}
//
const search = function () {
trim();
getObj.value.pageNum = 1
get()
}
//
const reset = function () {
getObj.value = {
pageNum: 1,
pageSize: 10
}
getTime.value = []
activity.value = {}
}
//
onMounted(async function () {
await getAdminData()
get()
})
// false
const addActivityVisible = ref(false)
// addActivity
const addActivity = () => {
console.log('点击了新增活动按钮');
// addActivityVisible true
addActivityVisible.value = true;
};
//
const closeAddActivityVisible = () => {
addActivityVisible.value = false;
};
//
const handlePageSizeChange = function (val) {
getObj.value.pageSize = val
get()
}
//
const handleCurrentChange = function (val) {
getObj.value.pageNum = val
get()
}
//
const throttledAdd = async () => {
try {
// 'add'
const { add, ...validData } = addObj.value;
// POST
const result = await request({
url: '/recharge/activity/add', //
method: 'post',
data: validData
})
console.log('新增活动成功', result)
ElMessage.success('新增活动成功')
//
closeAddActivityVisible()
//
get()
} catch (error) {
console.log('新增活动失败', error)
ElMessage.error('新增活动失败')
}
}
//
const delConfirm = async (row) => {
try {
delObj.value = row
//
const result = await request({
url: '/recharge/activity/edit', //
method: 'post',
data: delObj.value
})
console.log('删除活动成功', result)
ElMessage.success('删除活动成功')
//
get()
} catch (error) {
console.log('删除活动失败', error)
ElMessage.error('删除活动失败')
}
}
//
const del = (row) => {
delObj.value = row
}
</script>
<template>
<el-row>
<el-col>
<el-card style="margin-bottom: 20px">
<div class="head-card">
<div class="head-card-element">
<el-text class="mx-1" size="large">活动名称</el-text>
<el-input
v-model="activity.activityName"
style="width: 240px"
placeholder="请输入活动名称"
clearable
/>
</div>
<div class="head-card-element">
<el-text class="mx-1" size="large">添加时间</el-text>
<el-date-picker
v-model="getTime"
type="datetimerange"
range-separator="至"
start-placeholder="起始时间"
end-placeholder="结束时间"
/>
<el-button style="margin-left: 10px" @click="getToday()"
></el-button
>
<el-button @click="getYesterday()"></el-button>
<el-button @click="get7Days()">近7天</el-button>
</div>
<div class="head-card-btn">
<el-button type="success" @click="reset()">重置</el-button>
<el-button type="primary" @click="search()">查询</el-button>
</div>
</div>
</el-card>
</el-col>
</el-row>
<el-row>
<el-col>
<el-card>
<div>
<el-button
plain
@click="addActivity()"
style="color: #048efb; border: 1px solid #048efb"
>新增活动</el-button
>
</div>
<div>
<el-table :data="tableData" style="width: 100%">
<el-table-column
type="index"
label="序号"
width="100px"
fixed="left"
>
<template #default="scope">
<span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template>
</el-table-column>
<el-table-column prop="activityName" label="活动名称" />
<el-table-column prop="startTime" label="开始时间">
<template #default="scope">
{{ moment(scope.row.startTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column prop="endTime" label="结束时间">
<template #default="scope">
{{ moment(scope.row.endTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column prop="rechargeRatio" label="免费兑换比">
<template #default="scope">
<span>{{ scope.row.rechargeRatio }}:1</span>
</template>
</el-table-column>
<el-table-column prop="status" label="状态">
<template #default="scope">
<span v-if="scope.row.status === 1">
<div class="status">
<span class="green-dot"></span>
<span>进行中</span>
</div>
</span>
<span v-if="scope.row.status === 0">
<div class="status">
<span class="red-dot"></span>
<span>未开始</span>
</div>
</span>
<span v-if="scope.row.status === 2">
<div class="status">
<span class="grey-dot"></span>
<span>已结束</span>
</div>
</span>
</template>
</el-table-column>
<el-table-column prop="name" label="添加人" />
<el-table-column prop="createTime" label="添加时间">
<template #default="scope">
{{ moment(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column prop="operation" label="操作">
<template #default="scope">
<el-popconfirm
title="确定将此条活动删除吗?"
@confirm="delConfirm(delObj.value)"
>
<template #reference>
<el-button type="primary" text @click="del(scope.row)">
删除
</el-button>
</template>
<template #actions="{ confirm, cancel }">
<el-button size="small" @click="cancel">取消</el-button>
<el-button type="primary" size="small" @click="confirm">
确定
</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页 -->
<div class="pagination" style="margin-top: 20px">
<el-pagination
background
:page-size="getObj.pageSize"
:page-sizes="[5, 10, 20, 50]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handlePageSizeChange"
@current-change="handleCurrentChange"
></el-pagination>
</div>
</el-card>
</el-col>
</el-row>
<el-dialog
v-model="addActivityVisible"
title="新增活动"
width="500"
:before-close="closeAddActivityVisible"
:close-on-click-modal="false"
>
<template #footer>
<el-form
ref="Ref"
:model="addObj"
:rules="rules"
label-width="auto"
style="max-width: 600px"
>
<el-form-item prop="activityName" label="活动名称:">
<el-input
v-model="addObj.activityName"
placeholder="请输入活动名称"
style="width: 220px"
/>
</el-form-item>
<el-form-item prop="freeGold" label="免费金币:">
<el-radio-group v-model="addObj.freeGold">
<el-radio value="0" @change="addObj.rechargeRatio = '0'"
>无赠送</el-radio
>
<el-radio value="1">有赠送</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item prop="rechargeRatio" label="免费金币兑换比:">
<el-input
v-model="addObj.rechargeRatio"
:disabled="addObj.freeGold === '0' ? true : false"
placeholder="请输入"
style="width: 80px"
/>1
<div style="color: grey">
(提示当前规则每{{ addObj.rechargeRatio }}新币可兑换1免费金币)
</div>
</el-form-item>
<el-form-item prop="startTime" label="开始时间:">
<el-date-picker
v-model="addObj.startTime"
type="datetime"
placeholder="请选择开始时间"
@change="handleStartTimeChange"
/>
</el-form-item>
<el-form-item prop="endTime" label="结束时间:">
<el-date-picker
v-model="addObj.endTime"
type="datetime"
placeholder="请选择结束时间"
/>
</el-form-item>
<el-form-item label="添加人:">
<el-input v-model="adminData.name" disabled style="width: 220px" />
</el-form-item>
</el-form>
<div class="dialog-footer">
<el-button @click="closeAddActivityVisible">取消</el-button>
<el-button type="primary" @click="throttledAdd"> 提交 </el-button>
</div>
</template>
</el-dialog>
</template>
<style scoped>
.pagination {
display: flex;
}
.status {
display: flex;
}
.head-card {
display: flex;
}
.head-card-element {
margin-right: 20px;
}
.head-card-btn {
margin-left: auto;
}
</style>

849
src/views/managerecharge/rate.vue

@ -0,0 +1,849 @@
<script setup>
import { ref, onMounted, computed, reactive } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import axios from 'axios'
import { createApp } from 'vue'
import moment from 'moment'
import API from '../../api/index.js'
import _ from 'lodash'
import request from '@/util/http'
//
const adminData = ref({
name: ''
})
const getAdminData = async function () {
try {
const result = await request({
url: '/admin/userinfo',
data: {}
})
adminData.value = result
rateAdd.value.adminId = adminData.value.adminId
rateEdit.value.adminId = adminData.value.adminId
console.log('请求成功', result)
// console.log('', user.value)
} catch (error) {
console.log('请求失败', error)
}
}
getAdminData()
const regeAdd = ref(false)
const regeEdit = ref(false)
//
const tableData = ref([])
//
const getObj = ref({
pageNum: 1,
pageSize: 10
})
const total = ref(0)
//
// time
const timeRange = ref([])
// YYYY-MM-DD HH:mm:ss
const formatDateTime = (date) => {
return moment(date).format('YYYY-MM-DD HH:mm:ss')
}
//
const getToday = () => {
const today = new Date()
const start = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0)
const end = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1, 0, 0, 0)
timeRange.value = [formatDateTime(start), formatDateTime(end)]
search()
}
//
const getYesterday = () => {
const yesterday = new Date()
yesterday.setDate(yesterday.getDate() - 1)
const start = new Date(yesterday.getFullYear(), yesterday.getMonth(), yesterday.getDate(), 0, 0, 0)
const end = new Date(yesterday.getFullYear(), yesterday.getMonth(), yesterday.getDate() + 1, 0, 0, 0)
timeRange.value = [formatDateTime(start), formatDateTime(end)]
search()
}
// 7
const get7Days = () => {
const today = new Date()
const start = new Date(today.getFullYear(), today.getMonth(), today.getDate() - 6, 0, 0, 0)
const end = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1, 0, 0, 0)
timeRange.value = [formatDateTime(start), formatDateTime(end)]
search()
}
const get = async function (val) {
try {
//
if (typeof val === 'number') {
getObj.value.pageNum = val;
}
//
const time = {}
if (timeRange.value.length === 2) {
time.startTime = moment(timeRange.value[0]).format('YYYY-MM-DD HH:mm:ss')
time.endTime = moment(timeRange.value[1]).format('YYYY-MM-DD HH:mm:ss')
} else {
time.startTime = ''
time.endTime = ''
}
console.log('搜索参数', {
...getObj.value,
rate: { ...time }
});
// POST
const result = await request({
url: '/rates/search',
method: 'POST',
data: {
...getObj.value,
rate: { ...time }
}
});
//
console.log('请求成功', result);
//
tableData.value = result.data.list;
console.log('tableData', tableData.value);
//
total.value = result.data.total;
console.log('total', total.value);
} catch (error) {
console.log('请求失败', error);
ElMessage.error('请求失败');
}
}
//
const search = function () {
getObj.value.pageNum = 1
get()
}
//
const rateAdd = ref({})
const addRate = async function () {
rateAdd.value.adminId = adminData.value.adminId
if (rateAdd.value.startTime) {
const date = new Date(rateAdd.value.startTime)
date.setHours(0, 0, 0, 0)
rateAdd.value.startTime = `${date.getFullYear()}-${String(
date.getMonth() + 1
).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} 00:00:00`
}
if (rateAdd.value.endTime) {
const date = new Date(rateAdd.value.endTime)
date.setHours(23, 59, 59, 999)
rateAdd.value.endTime = `${date.getFullYear()}-${String(
date.getMonth() + 1
).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} 23:59:59`
}
try {
console.log('搜索参数', getObj.value)
// POST
const result = await request({
url: '/rates/add',
data: rateAdd.value
})
if (result.code == 0) {
ElMessage.error(result.msg)
}else{
ElMessage({
type: 'success',
message: '新增汇率成功'
})
}
//
console.log('请求成功', result)
get()
} catch (error) {
console.log('请求失败', error)
//
}
}
const add = () => {
Ref.value.validate(async (valid) => {
if (valid) {
ElMessageBox.confirm('确认添加?')
.then(() => {
addRate()
rateAdd.value = {}
timeRange.value = {
startTime: '',
endTime: ''
}
regeAdd.value = false
})
.catch(() => {
regeAdd.value = false
})
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
})
}
const handlePageSizeChange = function (val) {
getObj.value.pageSize = val
get()
}
const handleCurrentChange = function (val) {
getObj.value.pageNum = val
get()
}
// 使 _.throttle trailing false
const throttledAdd = _.throttle(add, 5000, { trailing: false })
//
const rateEdit = ref({})
//
const getEditData = async function (row) {
try {
console.log('搜索参数', getObj.value)
// POST
const result = await request({
url: '/rates/searchById?rateId=' + row.rateId,
data: {}
})
//
console.log('请求成功', result)
//
rateEdit.value = result.data
rateEdit.value.adminId = adminData.value.adminId
console.log('这是编辑的数值', rateEdit.value)
} catch (error) {
console.log('请求失败', error)
//
}
}
const editRate = async function () {
if (rateEdit.value.startTime) {
const date = new Date(rateEdit.value.startTime)
date.setHours(0, 0, 0, 0)
rateEdit.value.startTime = `${date.getFullYear()}-${String(
date.getMonth() + 1
).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} 00:00:00`
}
if (rateEdit.value.endTime) {
const date = new Date(rateEdit.value.endTime)
date.setHours(23, 59, 59, 999)
rateEdit.value.endTime = `${date.getFullYear()}-${String(
date.getMonth() + 1
).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} 23:59:59`
}
try {
console.log('搜索参数', rateEdit.value)
// POST
const result = await request({
url: '/rates/update',
data: rateEdit.value
})
//
console.log('请求成功', result)
get()
} catch (error) {
console.log('请求失败', error)
//
}
}
const edit = () => {
ElMessageBox.confirm('确认修改?')
.then(() => {
editRate()
regeEdit.value = false
})
.catch(() => {
regeEdit.value = false
})
}
//
const deleteRate = async function (row) {
try {
// POST
const result = await request({
url: '/rates/delete/ ' + row.rateId,
data: {}
})
//
console.log('请求成功', result)
get()
} catch (error) {
console.log('请求失败', error)
//
}
}
//
onMounted(async function () {
get()
})
//
function handlePageChange(currentPage, pageSize) {
get()
}
//
const options = [
{
value: 'USD',
label: 'USD'
},
{
value: 'HKD',
label: 'HKD'
},
{
value: 'THB',
label: 'THB'
},
{
value: 'VND',
label: 'VND'
},
{
value: 'CAD',
label: 'CAD'
},
{
value: 'MYR',
label: 'MYR'
},
{
value: 'KRW',
label: 'KRW'
},
{
value: 'JPY',
label: 'JPY'
},
{
value: 'CNY',
label: 'CNY'
}
]
function formatDate(value) {
if (!value) return ''
const date = new Date(value)
const year = date.getFullYear()
const month = (date.getMonth() + 1).toString().padStart(2, '0')
const day = date.getDate().toString().padStart(2, '0')
const hours = date.getHours().toString().padStart(2, '0')
const minutes = date.getMinutes().toString().padStart(2, '0')
const seconds = date.getSeconds().toString().padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
}
function formatDateTwe(value) {
if (!value) return ''
const date = new Date(value)
const year = date.getFullYear()
const month = (date.getMonth() + 1).toString().padStart(2, '0')
const day = date.getDate().toString().padStart(2, '0')
return `${year}-${month}-${day}`
}
// //
// const tableHeight = computed(function () {
// return (getObj.value.pageSize + 1) * 50 + "px";
// });
//
// ref
const Ref = ref(null)
const handleStartTimeChange = () => {
Ref.value.validateField('endTime')
}
const checkStartTime = function (rule, value, callback) {
if (value <= new Date()) {
callback(new Error('开始时间不能小于当前时间'))
} else {
callback()
}
}
const checkEndTime = function (rule, value, callback) {
if (value <= new Date()) {
callback(new Error('结束时间不能小于当前时间'))
} else if (value <= rateAdd.value.startTime) {
callback(new Error('结束时间不能小于开始时间'))
} else {
callback()
}
}
const checkFreeGoldRadio = function (rule, value, callback) {
if (value == '0' || value == null || value == '') {
callback(new Error('请输入汇率比'))
} else if (value < 0 || isNaN(value)) {
callback(new Error('请输入正确的格式'))
} else {
callback()
}
}
const rules = reactive({
currency: [{ required: true, message: '请选择货币名称', trigger: 'blur' }],
exchangeRate: [{ validator: checkFreeGoldRadio, trigger: 'blur' }],
startTime: [
{ required: true, message: '请选择开始时间', trigger: 'blur' },
{ validator: checkStartTime, trigger: 'blur' }
],
endTime: [
{ required: true, message: '请选择结束时间', trigger: 'blur' },
{ validator: checkEndTime, trigger: 'blur' }
]
})
//
const handledelete = function () {
timeRange.value={}
getObj.value.pageNum = 1
}
//
const checkNumber = function () {
if (typeof parseInt(getObj.value.pageNum) === 'number') {
console.log('总共有多少页' + Math.ceil(total.value / getObj.value.pageSize))
if (
getObj.value.pageNum > 0 &&
getObj.value.pageNum <= Math.ceil(total.value / getObj.value.pageSize)
) {
getObj.value.pageNum = parseInt(getObj.value.pageNum)
console.log('输入的数字合法')
get()
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
}
// =========================================================
//
//
const delConfirm = async function (row) {
try {
// POST
const result = await request({
url: '/rates/delete/ ' + row.rateId,
data: {}
})
if (result.code == 200) {
ElMessage({
type: 'success',
message: '删除成功'
})
//
console.log('请求成功', result)
//
get()
} else {
ElMessage({
type: 'error',
message: '删除失败'
})
}
} catch (error) {
console.log('请求失败', error)
//
}
}
//
function handleInput(value) {
// 7使
rateAdd.value.exchangeRate = value
.replace(/(\.\d{7})\d+/, '$1')
.replace(/^(\d+)(\.\d{0,7})?$/, '$1$2')
}
</script>
<template>
<!-- 这是主页面 -->
<el-row>
<el-col>
<el-card>
<!-- 这是时间 -->
<div class="demo-range">
<el-row>
<el-col :span="9">
<el-form-item>
<el-text class="mx-1" size="large">时间范围</el-text>
<el-date-picker
v-model="timeRange"
type="datetimerange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
style="width: 300px"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
/>
</el-form-item>
</el-col>
<el-col :span="4">
<el-button @click="getToday"></el-button>
<el-button @click="getYesterday"></el-button>
<el-button @click="get7Days">近7天</el-button>
</el-col>
<el-col :span="4">
<el-button
class="button-item"
type="success"
@click="handledelete()"
>重置</el-button>
<el-button
type="primary"
@click="search"
>查询</el-button>
</el-col>
</el-row>
</div>
</el-card>
</el-col>
</el-row>
<el-row>
<el-col>
<el-card class="box-card" style="max-width: 100%">
<!-- 添加 -->
<div class="add-item">
<el-button
style="color: #048efb; border: 1px solid #048efb"
@click="regeAdd = true"
>新增汇率</el-button
>
</div>
<!-- 表格 -->
<div>
<el-table
:data="tableData"
v-if="(tableData.flag = 1)"
:height="tableHeight"
style="width: 100%"
>
<el-table-column
type="index"
label="序号"
width="100px"
fixed="left"
>
<template #default="scope">
<span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template>
</el-table-column>
<el-table-column prop="currency" label="货币名称" :span="2" />
<el-table-column prop="exchangeRate" label="汇率" :span="2">
<template #default="scope">
<p>
{{ scope.row.exchangeRate }}{{ scope.row.currency }} 1新币
</p>
</template>
</el-table-column>
<el-table-column prop="createTime" label="添加时间" :span="3">
<template #default="scope">
<span>{{ formatDate(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column prop="adminName" label="提交人" :span="1" />
<el-table-column prop="status" label="状态">
<template #default="scope">
<span v-if="scope.row.status === 1">
<div class="status">
<span class="green-dot"></span>
<span>使用中</span>
</div>
</span>
<span v-if="scope.row.status === 0">
<div class="status">
<span class="red-dot"></span>
<span>未开始</span>
</div>
</span>
<span v-if="scope.row.status === 2">
<div class="status">
<span class="grey-dot"></span>
<span>已过期</span>
</div>
</span>
</template>
</el-table-column>
<el-table-column prop="startTime" label="持续时间" :span="10">
<template #default="scope">
<span>{{ formatDateTwe(scope.row.startTime) }}</span>
<span>---</span>
<span>{{ formatDateTwe(scope.row.endTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" :span="3">
<template #default="scope">
<el-button
type="text"
@click="
() => {
regeEdit = true
getEditData(scope.row)
}
"
>编辑</el-button
>
<el-popconfirm
title="确定将此条活动删除吗?"
@confirm="delConfirm"
>
<template #reference>
<el-button type="primary" text> 删除 </el-button>
</template>
<template #actions="{ confirm, cancel }">
<el-button size="small" @click="cancel">取消</el-button>
<el-button
type="primary"
size="small"
@click="confirm(scope.row)"
>
确定
</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页 -->
<div class="pagination">
<el-pagination
background
:page-size="getObj.pageSize"
:page-sizes="[5, 10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handlePageSizeChange"
@current-change="handleCurrentChange"
></el-pagination>
</div>
</el-card>
</el-col>
</el-row>
<!-- 这是添加弹窗 -->
<el-dialog
v-model="regeAdd"
title="新增汇率"
width="500"
:close-on-click-modal="false"
>
<template #footer>
<el-form
ref="Ref"
style="max-width: 600px"
:model="rateAdd"
:rules="rules"
label-width="auto"
class="demo-ruleForm"
:size="formSize"
status-icon
>
<el-form-item prop="currency" label="货币名称:">
<el-select
v-model.number="rateAdd.currency"
placeholder="请选择"
style="width: 240px"
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item prop="exchangeRate" label="汇率:">
<el-input
v-model="rateAdd.exchangeRate"
@update:modelValue="handleInput"
style="width: 120px"
/>
<p class="unit">:1</p>
<p>
(提示当前规则每 {{ rateAdd.exchangeRate }}
{{ rateAdd.currency }}可兑换 1 新币)
</p>
</el-form-item>
<el-form-item prop="adminId" label="提交人:">
<el-input :value="adminData.name" disabled style="width: 240px" />
</el-form-item>
<el-form-item prop="startTime" label="开始时间:">
<el-date-picker
v-model="rateAdd.startTime"
type="date"
placeholder="请选择时间"
:default-value="new Date()"
@change="handleStartTimeChange"
value-format="YYYY-MM-DD"
/>
</el-form-item>
<el-form-item prop="endTime" label="结束时间:">
<el-date-picker
v-model="rateAdd.endTime"
type="date"
placeholder="请选择时间"
:default-value="new Date()"
value-format="YYYY-MM-DD"
/>
</el-form-item>
<el-form-item>
<div class="dialog-footer">
<el-button type="primary" @click="throttledAdd">添加</el-button>
<el-button @click="regeAdd = false">取消</el-button>
</div>
</el-form-item>
</el-form>
</template>
</el-dialog>
<!-- 这是编辑弹窗 -->
<el-dialog
v-model="regeEdit"
title="修改汇率"
width="500"
:close-on-click-modal="false"
>
<template #footer>
<el-form
ref="ruleFormRef"
style="max-width: 600px"
:model="rateEdit"
:rules="rules"
label-width="auto"
class="demo-ruleForm"
:size="formSize"
status-icon
>
<el-form-item label="货币名称:">
<el-select
v-model="rateEdit.currency"
placeholder="请选择"
style="width: 240px"
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="汇率:">
<el-input v-model="rateEdit.exchangeRate" style="width: 120px" />
<p class="unit">:1</p>
<p>
(提示当前规则每 {{ rateEdit.exchangeRate }}
{{ rateEdit.currency }}可兑换 1 新币)
</p>
</el-form-item>
<el-form-item label="提交人:">
<el-input disabled :value="adminData.name" style="width: 240px" />
</el-form-item>
<el-form-item label="开始时间:">
<el-date-picker
v-model="rateEdit.startTime"
type="date"
placeholder="请选择时间"
:default-value="new Date()"
value-format="YYYY-MM-DD"
/>
</el-form-item>
<el-form-item label="结束时间:">
<el-date-picker
v-model="rateEdit.endTime"
type="date"
placeholder="请选择时间"
:default-value="new Date()"
value-format="YYYY-MM-DD"
/>
</el-form-item>
<el-form-item>
<div class="dialog-footer">
<el-button type="primary" @click="edit">修改</el-button>
<el-button @click="regeEdit = false">取消</el-button>
</div>
</el-form-item>
</el-form>
</template>
</el-dialog>
</template>
<style scoped>
p {
margin: 0px;
}
.el-form-item {
margin-left: 70px;
}
.ad {
margin-left: 10px;
}
.pagination {
margin-top: 20px;
}
.box-card {
margin-top: 20px;
}
.button-item {
margin-left: 10px;
}
.add-item {
margin-bottom: 10px;
}
el-table-column {
text-align: center;
}
p {
color: rgb(150, 150, 150);
}
.unit {
margin-left: 10px;
}
.el-card {
padding: 0px;
}
.pagination {
display: flex;
}
.status {
display: flex;
}
</style>

24
src/views/noPermissionPage.vue

@ -0,0 +1,24 @@
<script setup>
import { ref, onMounted, reactive, computed, nextTick } from "vue";
const image = "../src/assets/hqz大拇指.png";
</script>
<template>
<el-row>
<el-col>
<div>
<p style="font-size: 50px; font-weight: bold; text-align: center;">
暂无权限
</p>
<p style="font-size: 60px; font-weight: bold; text-align: center;">
请联系管理员添加权限
</p>
</div>
</el-col>
</el-row>
</template>
<style scoped></style>

910
src/views/permissions/index.vue

@ -0,0 +1,910 @@
<script setup>
import { ref, onMounted, reactive, computed } from 'vue'
import ElementPlus from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
import axios from 'axios'
import moment from 'moment'
import { ta } from 'element-plus/es/locales.mjs'
import API from '../../api/index.js'
import { UserFilled } from '@element-plus/icons-vue'
import _ from 'lodash'
import request from '@/util/http'
//
const tableData = ref([])
// ===========================================
//
const total = ref(100)
// detailY
const admin = ref({})
//
const getObj = ref({
pageNum: 1,
pageSize: 10
})
//
const permissionAddVisible = ref(false)
//
const permissionEditVisible = ref(false)
//
const area = ref([])
//
const store = ref([])
//
const permissionAddObj = ref({})
//
const addAdmin = ref({})
//
const permissionEditObj = ref({})
//
const delObj = ref({})
//
const get = async function (val) {
try {
//
if (typeof val === 'number') {
getObj.value.pageNum = val
}
console.log('搜索参数', getObj.value)
// POST
const result = await request({
url: '/admin/search',
data: {
...getObj.value,
admin: { ...admin.value }
}
})
tableData.value = result.data.list
console.log('tableData', tableData.value)
total.value = result.data.total
} catch (error) {
console.log('请求失败', error)
}
}
//
const trimJwCode = () => {
if (admin.value.jwcode) {
admin.value.jwcode = admin.value.jwcode.replace(/\s/g, '');
}
}
//
const search = function () {
trimJwCode();
getObj.value.pageNum = 1
get()
}
//
const reset = function () {
admin.value = {}
}
//
const getArea = async function () {
try {
const result = await request({
url: '/admin/area',
data: {}
})
area.value = result.data
} catch (error) {
console.log('请求失败', error)
//
}
}
//
const getStore = async function () {
try {
const result = await request({
url: '/admin/store',
data: {}
})
store.value = result.data
} catch (error) {
console.log('请求失败', error)
//
}
}
//
const checkNumber = function () {
if (typeof parseInt(getObj.value.pageNum) === 'number') {
console.log('总共有多少页' + Math.ceil(total.value / getObj.value.pageSize))
if (
getObj.value.pageNum > 0 &&
getObj.value.pageNum <= Math.ceil(total.value / getObj.value.pageSize)
) {
getObj.value.pageNum = parseInt(getObj.value.pageNum)
console.log('输入的数字合法')
get()
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
}
//
const openPermissionAddVisible = function () {
permissionAddVisible.value = true
}
//
const closePermissionAddVisible = function () {
permissionAddVisible.value = false
}
//
const permissionAddInit = function () {
permissionAddObj.value = {}
openPermissionAddVisible()
}
//
const getAdminByJwcodeWithoutPermission = async function () {
try {
const result = await request({
url: '/admin/selectNo',
data: permissionAddObj.value
})
if (result.code == 200) {
permissionAddObj.value = result.data[0]
ElMessage.success('精网号查询成功')
} else {
ElMessage.error(result.msg)
}
console.log('精网号查询没有权限的用户', permissionAddObj.value)
} catch (error) {
console.log('请求失败', error)
//
}
}
//
// const permissionAdd = async function () {
// try {
// if (
// permissionAddObj.value.jwcode == "" ||
// permissionAddObj.value.jwcode == null ||
// permissionAddObj.value.name == "" ||
// permissionAddObj.value.name == null
// ) {
// ElMessage.error("");
// return;
// }
// if (
// permissionAddObj.value.permisson == "" ||
// permissionAddObj.value.permission == null
// ) {
// ElMessage.error("");
// return;
// }
// console.log("", permissionAddObj.value);
// const result = await request(
// {
// url: "/admin/update",
// data: permissionAddObj.value}
// );
// //
// console.log("", result);
// ElMessage.success("");
// get();
// closePermissionAddVisible();
// } catch (error) {
// console.log("", error);
// //
// ElMessage.error("");
// closePermissionAddVisible();
// }
// };
const permissionAdd = async function () {
Ref.value.validate(async (valid) => {
console.log('valid', valid)
if (valid) {
try {
addAdmin.value.adminFlag = 1
addAdmin.value.status1 = 1
const result = await request({
url: '/admin/add',
data: addAdmin.value
})
if (result.code == 200) {
ElMessage.success('添加成功')
} else {
ElMessage.error(result.msg)
}
addAdmin.value = {}
get()
closePermissionAddVisible()
} catch (error) {
console.log('新增用户权限失败', error)
//
ElMessage.error('新增用户权限失败')
closePermissionAddVisible()
}
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
})
}
//
const rules = reactive({
jwcode: [{ required: true, message: '请输入精网号', trigger: 'blur' }],
name: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
store: [{ required: true, message: '请输入职称', trigger: 'blur' }],
machineId: [{ required: true, message: '请输入精网号', trigger: 'blur' }],
area: [{ required: true, message: '请选择所属地区', trigger: 'blur' }],
permission: [{ required: true, message: '请选择权限', trigger: 'blur' }]
})
//
// ref
const Ref = ref(null)
// 使 _.throttle trailing false
const throttledPermissionAdd = _.throttle(permissionAdd, 5000, {
trailing: false
})
//
const permissionList = [
{
label: '总部',
value: '1'
},
{
label: '地区经理',
value: '5'
},
{
label: '财务',
value: '3'
},
{
label: '客服',
value: '2'
}
]
//
//
const areaList = ref([])
const getAreas = async function () {
try {
// POST
const result = await request({
url: '/recharge/user/search',
data: {}
})
//
console.log('请求成功', result)
//
areaList.value = result.data
console.log('地区', area.value)
} catch (error) {
console.log('请求失败', error)
//
}
}
getAreas()
//
const openPermissionEditVisible = function () {
permissionEditVisible.value = true
}
//
const closePermissionEditVisible = function () {
permissionEditVisible.value = false
}
//
const permissionEditInit = function (row) {
permissionEditObj.value = {}
permissionEditObj.value.jwcode = row.jwcode
permissionEditObj.value.name = row.name
permissionEditObj.value.area = row.area
permissionEditObj.value.store = row.store
permissionEditObj.value.permission = row.permission
console.log('编辑用户权限', permissionEditObj.value)
openPermissionEditVisible()
}
//
const permissionEdit = async function () {
try {
const result = await request({
url: '/admin/update',
data: permissionEditObj.value
})
//
console.log('请求成功', result)
ElMessage.success('编辑用户权限成功')
get()
closePermissionEditVisible()
} catch (error) {
console.log('编辑用户权限失败', error)
//
ElMessage.error('编辑用户权限失败')
closePermissionEditVisible()
}
}
const throttledPermissionEdit = _.throttle(permissionEdit, 5000, {
trailing: false
})
//
const del = function (row) {
delObj.value = {}
console.log(row, '删除初始化')
delObj.value.jwcode = row.jwcode
}
//
const delConfirm = async function () {
try {
delObj.value.permission = '4'
console.log(delObj.value)
const result = await request({
url: '/admin/update',
data: delObj.value
})
//
console.log('请求成功', result)
ElMessage.success('删除权限成功')
delObj.value = {}
get()
} catch (error) {
console.log('删除权限失败', error)
//
ElMessage.error('删除权限失败')
}
}
//
const editStatus = async function (row) {
try {
console.log(row)
permissionEditObj.value = {}
permissionEditObj.value.jwcode = row.jwcode
permissionEditObj.value.status1 = row.status1
console.log('修改用户权限状态', permissionEditObj.value)
const result = await request({
url: '/admin/update',
data: permissionEditObj.value
})
//
console.log('请求成功', result)
ElMessage.success(
permissionEditObj.value.status1 == 1 ? '启用成功' : '禁用成功'
)
permissionEditObj.value = {}
get()
} catch (error) {
console.log('修改用户权限失败', error)
//
}
}
//
onMounted(async function () {
await get()
await getArea()
await getStore()
})
const handlePageSizeChange = function (val) {
getObj.value.pageSize = val
get()
}
const handleCurrentChange = function (val) {
getObj.value.pageNum = val
get()
}
</script>
<template>
<el-row>
<el-col>
<el-card style="margin-bottom: 20px">
<div class="head-card">
<div class="head-card-element">
<el-text class="mx-1" size="large">精网号</el-text>
<el-input
v-model="admin.jwcode"
style="width: 240px"
placeholder="请输入精网号"
clearable
/>
</div>
<div class="head-card-element" style="margin-left: 50px">
<el-text class="mx-1" size="large">所属地区</el-text>
<el-select
v-model="admin.area"
placeholder="请选择所属地区"
style="width: 240px"
clearable
>
<el-option
v-for="item in area"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</div>
<div class="head-card-element" style="margin-left: 50px">
<el-text class="mx-1" size="large">职位名称</el-text>
<el-select
v-model="admin.store"
placeholder="请选择职位名称"
style="width: 240px"
clearable
>
<el-option
v-for="item in store"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</div>
<div class="head-card-btn">
<el-button type="success" @click="reset()">重置</el-button>
<el-button type="primary" @click="search()">查询</el-button>
</div>
</div>
</el-card>
</el-col>
</el-row>
<el-row>
<el-col>
<el-card>
<!-- 添加 -->
<div class="add-item">
<el-button
style="color: #048efb; border: 1px solid #048efb"
@click="permissionAddInit()"
>新增用户</el-button
>
</div>
<div>
<el-table :data="tableData" style="width: 100%">
<el-table-column
type="index"
label="序号"
width="100px"
fixed="left"
>
<template #default="scope">
<span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template>
</el-table-column>
<el-table-column prop="jwcode" label="精网号" />
<el-table-column prop="name" label="姓名" />
<el-table-column prop="area" label="所属地区" />
<el-table-column prop="store" label="职位" />
<el-table-column prop="permission" label="部门权限">
<template #default="scope">
<span v-if="scope.row.permission === '1'"> 总部管理员 </span>
<span v-if="scope.row.permission === '2'"> 分部财务 </span>
<span v-if="scope.row.permission === '3'"> 分部客服 </span>
<span v-if="scope.row.permission === '5'"> 分部经理 </span>
</template>
</el-table-column>
<el-table-column prop="remark" label="备注" />
<el-table-column prop="operation" label="操作" width="200px">
<template #default="scope">
<el-button
type="warning"
text
@click="permissionEditInit(scope.row)"
:disabled="scope.row.status1 === 0"
>
修改权限
</el-button>
<el-popconfirm
title="确定将此用户删除吗?"
@confirm="delConfirm"
>
<template #reference>
<el-button
type="danger"
text
@click="del(scope.row)"
:disabled="scope.row.status1 === 0"
>
删除
</el-button>
</template>
<template #actions="{ confirm, cancel }">
<el-button size="small" @click="cancel">取消</el-button>
<el-button type="primary" size="small" @click="confirm">
确定
</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
<el-table-column prop="status1" label="状态">
<template #default="scope">
<el-switch
v-model="scope.row.status1"
:active-value="1"
:inactive-value="0"
size="large"
@change="editStatus(scope.row)"
style="
--el-switch-on-color: #13ce66;
--el-switch-off-color: #ff4949;
"
active-text="启用"
inactive-text="禁用"
inline-prompt
/>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页 -->
<div class="pagination" style="margin-top: 20px">
<el-pagination
background
:page-size="getObj.pageSize"
:page-sizes="[5, 10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handlePageSizeChange"
@current-change="handleCurrentChange"
></el-pagination>
</div>
</el-card>
</el-col>
</el-row>
<!-- 新增用户权限 -->
<el-dialog
v-model="permissionAddVisible"
title="新增用户权限"
width="800px"
:close-on-click-modal="false"
>
<template #footer>
<!-- 居中显示 -->
<el-form
ref="Ref"
:rules="rules"
:model="addAdmin"
label-width="auto"
style="max-width: 600px; align-items: center"
>
<el-form-item prop="jwcode" label="精网号:">
<el-input
v-model="addAdmin.jwcode"
placeholder="请输入精网号"
style="width: 220px"
/>
</el-form-item>
<el-form-item prop="name" label="用户名:">
<el-input
v-model="addAdmin.name"
placeholder="请输入用户名"
style="width: 220px"
/>
</el-form-item>
<el-form-item prop="area" label="所属地区:">
<el-select
v-model="addAdmin.area"
placeholder="请选择所属地区"
style="width: 220px"
@change="() => Ref.value.validateField('area')"
>
<el-option
v-for="item in areaList"
:key="item"
:label="item"
:value="item"
></el-option>
</el-select>
</el-form-item>
<el-form-item prop="permission" label="权限类别:">
<el-select
v-model="addAdmin.permission"
placeholder="请选择权限"
style="width: 220px"
@change="() => Ref.value.validateField('permission')"
>
<el-option
v-for="item in permissionList"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item prop="store" label="职位:">
<el-input
v-model="addAdmin.store"
placeholder="请输入职称"
style="width: 220px"
/>
</el-form-item>
<el-form-item prop="machineId" label="机器码:">
<el-input
v-model="addAdmin.machineId"
placeholder="请输入机器码"
style="width: 220px"
/>
</el-form-item>
<el-form-item prop="remark" label="备注">
<el-input
v-model="addAdmin.remark"
style="width: 300px"
:rows="2"
maxlength="100"
show-word-limit
type="textarea"
/>
</el-form-item>
</el-form>
<div>
<el-button @click="closePermissionAddVisible()">取消</el-button>
<el-button type="primary" @click="throttledPermissionAdd()">
提交
</el-button>
</div>
</template>
</el-dialog>
<!-- 这是新增用户权限弹窗
<el-dialog
v-model="permissionAddVisible"
title="新增用户权限"
width="800px"
:close-on-click-modal="false"
>
<div style="display: flex; margin: 20px 0px 20px 0px">
<span class="permissionVisible" style="margin-right: 10px">精网号:</span>
<el-input
placeholder="请输入精网号"
v-model="permissionAddObj.jwcode"
style="width: 240px; margin-right: 10px"
clearable
></el-input>
<el-button type="primary" @click="getAdminByJwcodeWithoutPermission()"
>查询</el-button
>
</div>
<el-descriptions
class="margin-top"
:column="2"
:size="size"
border
label-width="200px"
>
<el-descriptions-item>
<template #label>
<div class="permissionVisible">
<el-icon>
<UserFilled />
</el-icon>
员工精网号
</div>
</template>
{{ permissionAddObj.jwcode }}
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="permissionVisible">
<el-icon>
<User />
</el-icon>
员工姓名
</div>
</template>
{{ permissionAddObj.name }}
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="permissionVisible">
<el-icon :style="iconStyle">
<location />
</el-icon>
所属地区
</div>
</template>
{{ permissionAddObj.area }}
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="permissionVisible">
<el-icon>
<OfficeBuilding />
</el-icon>
部门
</div>
</template>
{{ permissionAddObj.store }}
</el-descriptions-item>
</el-descriptions>
<el-divider>
<el-icon><star-filled /></el-icon>
</el-divider>
<div>
<span class="permissionVisible" style="margin-right: 20px"
>权限设置:</span
>
<el-radio-group v-model="permissionAddObj.permission">
<el-radio value="1" border>总部管理员</el-radio>
<el-radio value="5" border>分部经理</el-radio>
<el-radio value="2" border>分部财务</el-radio>
<el-radio value="3" border>分部客服</el-radio>
</el-radio-group>
</div>
<template #footer>
<div>
<el-button @click="closePermissionAddVisible()">取消</el-button>
<el-button type="primary" @click="throttledPermissionAdd()">
提交
</el-button>
</div>
</template>
</el-dialog> -->
<!-- 这是编辑用户权限弹窗 -->
<el-dialog
v-model="permissionEditVisible"
title="编辑用户权限"
width="800px"
:close-on-click-modal="false"
>
<el-descriptions
class="margin-top"
:column="2"
:size="size"
border
label-width="200px"
>
<el-descriptions-item>
<template #label>
<div class="permissionVisible">
<el-icon>
<UserFilled />
</el-icon>
员工精网号
</div>
</template>
{{ permissionEditObj.jwcode }}
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="permissionVisible">
<el-icon>
<User />
</el-icon>
员工姓名
</div>
</template>
{{ permissionEditObj.name }}
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="permissionVisible">
<el-icon :style="iconStyle">
<location />
</el-icon>
所属地区
</div>
</template>
{{ permissionEditObj.area }}
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="permissionVisible">
<el-icon>
<OfficeBuilding />
</el-icon>
部门
</div>
</template>
{{ permissionEditObj.store }}
</el-descriptions-item>
</el-descriptions>
<el-divider>
<el-icon><star-filled /></el-icon>
</el-divider>
<div>
<span class="permissionVisible" style="margin-right: 20px"
>权限设置:</span
>
<el-radio-group v-model="permissionEditObj.permission">
<el-radio value="1" border>总部管理员</el-radio>
<el-radio value="5" border>分部经理</el-radio>
<el-radio value="2" border>分部财务</el-radio>
<el-radio value="3" border>分部客服</el-radio>
</el-radio-group>
</div>
<template #footer>
<div>
<el-button @click="closePermissionEditVisible()">取消</el-button>
<el-button type="primary" @click="throttledPermissionEdit()">
提交
</el-button>
</div>
</template>
</el-dialog>
</template>
<style scoped>
.permissionVisible {
font-size: 16px;
font-weight: bold;
}
.pagination {
display: flex;
}
.status {
display: flex;
}
.head-card {
display: flex;
}
.head-card-element {
margin-right: 20px;
}
.head-card-btn {
margin-left: auto;
}
/* 新增样式让弹窗内容居中 */
.el-dialog__body {
display: flex;
flex-direction: column;
align-items: center;
}
.el-dialog__footer {
display: flex;
flex-direction: column;
align-items: center;
}
</style>

1555
src/views/recharge/addRecharge.vue
File diff suppressed because it is too large
View File

796
src/views/recharge/adminRecharge.vue

@ -0,0 +1,796 @@
<script setup>
import { ref, onMounted, reactive, computed } from 'vue'
import ElementPlus from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
import { AiFillRead } from 'vue-icons-plus/ai'
import axios from 'axios'
import moment from 'moment'
import API from '@/util/http'
//
const adminData = ref({})
const getAdminData = async function () {
try {
const result = await API({ url: '/admin/userinfo', data: {} })
adminData.value = result
rechargeVo.value.adminId = adminData.value.adminId
console.log('请求成功', result)
console.log('用户信息', adminData.value)
} catch (error) {
console.log('请求失败', error)
}
}
//
//
const tableData = ref([])
// ===========================================
// recharge
const rechargeVo = ref({
adminId: adminData.value.adminId
})
//
const getObj = ref({
pageNum: 1,
pageSize: 50
})
//
const total = ref(100)
//
const getTime = ref([])
//
const activity = ref([])
//
const allData = ref([])
//
const area = ref([])
//
const activeName = ref('all')
//
const payWay = [
{
value: '微信',
label: '微信'
},
{
value: '支付宝',
label: '支付宝'
},
{
value: '银联',
label: '银联'
},
{
value: '信用卡',
label: '信用卡'
},
{
value: '借记卡',
label: '借记卡'
},
{
value: '现金充值',
label: '现金充值'
}
]
// ==========================================================
//
const delObj = ref({})
// //
// const tableHeight = computed(function () {
// return (getObj.value.pageSize + 2) * 60 + "px";
// });
//
//
const trueGold = ref(0)
const trueRGold = ref(0)
const trueFGold = ref(0)
//
const totalmoney = ref(0)
const totalRcoin = ref(0)
const totalFcoin = ref(0)
//
const pendingGold = ref(0)
const pendingRGold = ref(0)
const pendingFGold = ref(0)
//
const approvedGold = ref(0)
const approvedRGold = ref(0)
const approvedFGold = ref(0)
//
const rejectedGold = ref(0)
const rejectedRGold = ref(0)
const rejectedFGold = ref(0)
// ===========================================================================
//
const get = async function (val) {
try {
//
if (adminData.value.area === '泰国') {
rechargeVo.value.areas = ['泰国', '越南']
} else if (adminData.value.area !== '总部') {
rechargeVo.value.area = adminData.value.area
}
//
if (typeof val === 'number') {
getObj.value.pageNum = val
}
//
if (getTime.value != null) {
if (getTime.value.startDate != '' && getTime.value.endDate != '') {
rechargeVo.value.startDate = getTime.value[0]
rechargeVo.value.endDate = getTime.value[1]
}
} else {
rechargeVo.value.startDate = ''
rechargeVo.value.endDate = ''
}
//
rechargeVo.value.sortField = sortField.value
rechargeVo.value.sortOrder = sortOrder.value
console.log('搜索参数', getObj.value)
// POST
const result = await API({
url: '/recharge/recharge',
data: { ...getObj.value, rechargeVo: { ...rechargeVo.value } }
})
// rechargeVo.value
const detailWithoutSort = ref({
area: rechargeVo.value.area,
adminId: rechargeVo.value.adminId,
startDate: rechargeVo.value.startDate,
endDate: rechargeVo.value.endDate
})
const result2 = await API({
url: '/recharge/recharge/RechargeA',
data: {
...detailWithoutSort.value
}
})
// result2
if (!result2 || !result2.data || result2.data.length === 0) {
totalmoney.value = 0
totalRcoin.value = 0
totalFcoin.value = 0
}
if (result2.data) {
result2.data.forEach((item) => {
switch (item.auditStatus) {
case '待审核':
// item.raudit 0
// item.sumRaudit 0
pendingGold.value = item.sumRaudit || 0
pendingRGold.value = item.sumRaudit1 || 0
pendingFGold.value = item.sumRaudit2 || 0
break
case '已通过':
approvedGold.value = item.sumRaudit || 0
approvedRGold.value = item.sumRaudit1 || 0
approvedFGold.value = item.sumRaudit2 || 0
break
case '已驳回':
rejectedGold.value = item.sumRaudit || 0
rejectedRGold.value = item.sumRaudit1 || 0
rejectedFGold.value = item.sumRaudit2 || 0
break
}
})
}
trueGold.value = pendingGold.value + approvedGold.value + rejectedGold.value
trueRGold.value =
pendingRGold.value + approvedRGold.value + rejectedRGold.value
trueFGold.value =
pendingFGold.value + approvedFGold.value + rejectedFGold.value
//
console.log('请求成功', result)
//
tableData.value = result.data.list
console.log('tableData', tableData.value)
//
total.value = result.data.total
console.log('total', total.value)
} catch (error) {
console.log('请求失败', error)
//
}
}
//
const search = function () {
getObj.value.pageNum = 1
get()
}
//
const reset = function () {
delete rechargeVo.value.activityId
delete rechargeVo.value.payWay
delete rechargeVo.value.area
delete rechargeVo.value.startDate
delete rechargeVo.value.endDate
delete sortField.value
delete sortOrder.value
getTime.value = {}
}
//
const getToday = function () {
const today = new Date()
const startDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate()
)
const endDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() + 1
)
getTime.value = [startDate, endDate]
console.log('getTime', getTime.value)
get()
}
const handlePageSizeChange = function (val) {
getObj.value.pageSize = val
get()
}
const handleCurrentChange = function (val) {
getObj.value.pageNum = val
get()
}
//
const getYesterday = function () {
const yesterday = new Date()
yesterday.setDate(yesterday.getDate() - 1)
const startDate = new Date(
yesterday.getFullYear(),
yesterday.getMonth(),
yesterday.getDate()
)
const endDate = new Date(
yesterday.getFullYear(),
yesterday.getMonth(),
yesterday.getDate() + 1
)
getTime.value = [startDate, endDate]
console.log('getTime', getTime.value)
get()
}
// 7
const get7Days = function () {
const today = new Date()
const startDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() - 6
)
const endDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() + 1
)
getTime.value = [startDate, endDate]
console.log('getTime', getTime.value)
get()
}
//
const adminAll = function () {
console.log('adminAll')
rechargeVo.value.status = ''
getObj.value.pageNum = 1
get()
}
//
const adminWait = async function () {
rechargeVo.value.status = 0
getObj.value.pageNum = 1
await get()
console.log('adminWait')
trueGold.value = pendingGold.value
trueRGold.value = pendingRGold.value
trueFGold.value = pendingFGold.value
}
//
const adminPass = async function () {
rechargeVo.value.status = 1
getObj.value.pageNum = 1
await get()
trueGold.value = approvedGold.value
trueRGold.value = approvedRGold.value
trueFGold.value = approvedFGold.value
console.log('adminPass')
}
//
const adminReject = async function () {
rechargeVo.value.status = 2
getObj.value.pageNum = 1
await get()
console.log('adminReject')
trueGold.value = rejectedGold.value
trueRGold.value = rejectedRGold.value
trueFGold.value = rejectedFGold.value
}
//
const handleClick = function (tab, event) {
if (tab.props.name === 'all') {
adminAll()
} else if (tab.props.name === 'wait') {
adminWait()
} else if (tab.props.name === 'pass') {
adminPass()
} else if (tab.props.name === 'reject') {
adminReject()
}
}
//
const getActivity = async function () {
try {
// POST
const result = await API({ url: '/recharge/activity/select', data: {} })
//
console.log('请求成功', result)
//
activity.value = result.data
console.log('activity', activity.value)
} catch (error) {
console.log('请求失败', error)
//
}
}
//
//
const getArea = async function () {
try {
// POST
const result = await API({ url: 'recharge/user/search', data: {} })
//
console.log('请求成功', result)
//
area.value = result.data
console.log('地区', area.value)
} catch (error) {
console.log('请求失败', error)
//
}
}
// =================================
//
const del = function (row) {
delObj.value.rechargeId = row.rechargeId
console.log('delObj1', delObj.value)
}
//
const delConfirm = async function () {
try {
console.log('delObj2', delObj.value)
const result = await API({
url: '/recharge/recharge/edit',
data: delObj.value
})
console.log('删除成功', result)
//
get()
} catch (error) {
console.log('请求失败', error)
//
}
}
//
const checkNumber = function () {
if (typeof parseInt(getObj.value.pageNum) === 'number') {
console.log('总共有多少页' + Math.ceil(total.value / getObj.value.pageSize))
if (
getObj.value.pageNum > 0 &&
getObj.value.pageNum <= Math.ceil(total.value / getObj.value.pageSize)
) {
getObj.value.pageNum = parseInt(getObj.value.pageNum)
console.log('输入的数字合法')
get()
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
}
//
onMounted(async function () {
await getAdminData()
await get()
await getActivity()
await getArea()
})
//
const sortField = ref('')
const sortOrder = ref('')
//
const handleSortChange = (column) => {
console.log('排序字段:', column.prop)
console.log('排序方式:', column.order)
if (column.prop === 'paidGold') {
sortField.value = 'paid_gold'
} else if (column.prop === 'freeGold') {
sortField.value = 'free_gold'
} else if (column.prop === 'rechargeTime') {
sortField.value = 'recharge_time'
} else if (column.prop === 'createTime') {
sortField.value = 'create_time'
} else if(column.prop === 'rechargeGold'){
sortField.value = 'recharge_gold'
}
sortOrder.value = column.order === 'ascending' ? 'ASC' : 'DESC'
console.log('传递给后端的排序字段:', sortField.value)
console.log('传递给后端的排序方式:', sortOrder.value)
get()
}
</script>
<template>
<el-row>
<el-col>
<el-card style="margin-bottom: 20px">
<el-row style="margin-bottom: 10px">
<el-col :span="8">
<div class="head-card-element">
<el-text class="mx-1" size="large">活动名称</el-text>
<el-select
v-model="rechargeVo.activityId"
placeholder="请选择活动名称"
size="large"
style="width: 240px"
clearable
>
<el-option
v-for="item in activity"
:key="item.activityId"
:label="item.activityName"
:value="item.activityId"
/>
</el-select>
</div>
</el-col>
<el-col :span="8">
<!-- <div class="head-card-element">
<el-text class="mx-1" size="large">支付方式</el-text>
<el-select
v-model="rechargeVo.payWay"
placeholder="请选择支付方式"
size="large"
style="width: 240px"
clearable
>
<el-option
v-for="item in payWay"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div> -->
</el-col>
<el-col :span="8">
<div class="head-card-element" v-if="adminData.area == '总部'">
<el-text class="mx-1" size="large">所属地区</el-text>
<el-select
v-model="rechargeVo.area"
placeholder="请选择所属地区"
size="large"
style="width: 240px"
clearable
>
<el-option
v-for="item in area"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="21">
<div class="head-card-element">
<el-text class="mx-1" size="large">充值时间</el-text>
<el-date-picker
v-model="getTime"
type="datetimerange"
range-separator="至"
start-placeholder="起始时间"
end-placeholder="结束时间"
/>
<el-button style="margin-left: 10px" @click="getToday()"
></el-button
>
<el-button @click="getYesterday()"></el-button>
<el-button @click="get7Days()">近7天</el-button>
</div>
</el-col>
<el-col :span="3">
<div class="head-card-btn">
<el-button type="success" @click="reset()">重置</el-button>
<el-button type="primary" @click="search()">查询</el-button>
</div>
</el-col>
</el-row>
</el-card>
</el-col>
</el-row>
<el-row>
<el-col>
<el-card>
<el-tabs
v-model="activeName"
type="card"
class="demo-tabs"
@tab-click="handleClick"
>
<el-tab-pane label="全部" name="all"></el-tab-pane>
<el-tab-pane label="待审核" name="wait"></el-tab-pane>
<el-tab-pane label="已通过" name="pass"></el-tab-pane>
<el-tab-pane label="已驳回" name="reject"></el-tab-pane>
<div>
充值金额{{ trueRGold.toFixed(2) }}新币永久金币{{
trueRGold.toFixed(2)
}}金币免费金币{{ trueFGold }}金币
</div>
</el-tabs>
<!-- 设置表格容器的高度和滚动样式 -->
<div style="height: 520px; overflow-y: auto">
<el-table
:data="tableData"
style="width: 100%"
height="520px"
@sort-change="handleSortChange"
>
<el-table-column
type="index"
label="序号"
width="100px"
fixed="left"
>
<template #default="scope">
<span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template>
</el-table-column>
<el-table-column
fixed="left"
prop="username"
label="姓名"
width="100px"
/>
<el-table-column
fixed="left"
prop="jwcode"
label="精网号"
width="110px"
/>
<el-table-column prop="area" label="所属地区" width="100px" />
<el-table-column
prop="activityName"
label="活动名称"
width="150px"
/>
<!-- <el-table-column prop="" label="货币名称" width="120px" /> -->
<el-table-column
prop="paidGold"
sortable="custom"
label="充值金额"
width="120px"
/>
<el-table-column
prop="rechargeGold"
label="永久金币"
sortable="custom"
width="110px"
/>
<el-table-column
prop="freeGold"
label="免费金币"
sortable="custom"
width="110px"
/>
<el-table-column
prop="remark"
label="备注"
width="200px"
show-overflow-tooltip
/>
<el-table-column prop="payWay" label="支付方式" width="100px" />
<el-table-column
prop="rechargeVoucher"
label="支付凭证"
width="150px"
>
<template #default="scope">
<el-image
:preview-src-list="[scope.row.rechargeVoucher]"
preview-teleported="true"
:src="scope.row.rechargeVoucher"
alt="凭证"
style="width: 50px; height: 50px"
/>
</template>
</el-table-column>
<el-table-column prop="name" label="提交人" width="100px" />
<el-table-column prop="status" label="状态" width="100px">
<template #default="scope">
<span v-if="scope.row.status === 1">
<div class="status">
<span class="green-dot"></span>
<span>已通过</span>
</div>
</span>
<span v-if="scope.row.status === 0">
<div class="status">
<span class="grey-dot"></span>
<span>待审核</span>
</div>
</span>
<span v-if="scope.row.status === 2">
<div class="status">
<span class="red-dot"></span>
<span>已驳回</span>
</div>
</span>
</template>
</el-table-column>
<el-table-column
prop="reson"
label="驳回理由"
width="200px"
show-overflow-tooltip
/>
<el-table-column
prop="createTime"
sortable
label="交款时间"
width="200px"
>
<!-- <template #default="scope">
{{
moment(scope.row.rechargeTime).format('YYYY-MM-DD HH:mm:ss')
}}
</template> -->
</el-table-column>
<el-table-column
prop="rechargeTime"
sortable="custom"
label="提交时间"
width="200px"
/>
<el-table-column
fixed="right"
prop="operation"
label="操作"
width="150px"
>
<template #default="scope">
<el-popconfirm
title="确定将此条活动删除吗?"
@confirm="delConfirm"
>
<template #reference>
<el-button type="primary" text @click="del(scope.row)">
删除
</el-button>
</template>
<template #actions="{ confirm, cancel }">
<el-button size="small" @click="cancel">取消</el-button>
<el-button type="primary" size="small" @click="confirm">
确定
</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页 -->
<div class="pagination" style="margin-top: 20px">
<el-pagination
background
:page-size="getObj.pageSize"
:page-sizes="[5, 10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handlePageSizeChange"
@current-change="handleCurrentChange"
></el-pagination>
</div>
</el-card>
</el-col>
</el-row>
<!-- 编辑弹窗 -->
<el-dialog
v-model="editRechargeVisible"
title="新增活动"
width="500"
:before-close="closeEditRechargeVisible"
>
<template #footer>
<el-form :model="editObj" label-width="auto" style="max-width: 600px">
<el-form-item label="活动名称:">
<el-input
v-model="addObj.activityName"
placeholder="请输入活动名称"
style="width: 220px"
/>
</el-form-item>
<el-form-item label="免费金币:">
<el-radio-group v-model="addObj.freeGold">
<el-radio value="0">无赠送</el-radio>
<el-radio value="1">有赠送</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="免费金币兑换比:">
<el-input
v-model="addObj.rechargeRatio"
placeholder="请输入"
style="width: 80px"
/>1
<div style="color: grey">(提示当前规则每10新币可兑换1免费金币)</div>
</el-form-item>
<el-form-item label="开始时间:">
<el-time-picker v-model="addObj.startTime" />
</el-form-item>
<el-form-item label="结束时间:">
<el-time-picker v-model="addObj.endTime" />
</el-form-item>
<el-form-item label="添加人:">
<el-input v-model="addObj.adminName" disabled style="width: 220px" />
</el-form-item>
</el-form>
<div class="dialog-footer">
<el-button @click="closeAddActivityVisible">取消</el-button>
<el-button type="primary" @click="closeAddActivityVisible">
提交
</el-button>
</div>
</template>
</el-dialog>
</template>
<style scoped>
.pagination {
display: flex;
}
.status {
display: flex;
}
.head-card {
display: flex;
}
.head-card-element {
margin-right: 20px;
}
.head-card-btn {
margin-left: auto;
}
</style>

964
src/views/recharge/allRecharge.vue

@ -0,0 +1,964 @@
<script setup>
import { ref, onMounted, reactive, computed, nextTick } from 'vue'
import ElementPlus from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
import { AiFillRead } from 'vue-icons-plus/ai'
import axios from 'axios'
import moment from 'moment'
import API from '@/util/http'
import * as XLSX from 'xlsx' // xlsx
// XLSX
const { utils, writeFile } = XLSX
//
//
const adminData = ref({})
const getAdminData = async function () {
try {
const result = await API({ url: '/admin/userinfo', data: {} })
adminData.value = result
console.log('请求成功', result)
console.log('用户信息', adminData.value)
} catch (error) {
console.log('请求失败', error)
}
}
//
const tableData = ref([])
// ======================================
// rechargeVo
const rechargeVo = ref({
activityId: '',
rechargeWay: '',
area: '',
startDate: '',
endDate: '',
status: ''
})
//
const getObj = ref({
pageNum: 1,
pageSize: 50
})
//
const total = ref(100)
//
const getTime = ref([])
//
const activity = ref([])
//
const allData = ref([])
//
const area = ref([])
//
const activeName = ref('all')
//
const rechargeWay = ref([])
//
const getPayWay = async function () {
try {
const result = await API({ url: '/recharge/recharge/getWay', data: {} })
rechargeWay.value = result.data.filter((item) => item)
console.log('请求成功', result)
console.log('充值方式', rechargeWay.value)
} catch (error) {
console.log('请求失败', error)
}
}
//
//
const trueGold = ref(0)
const trueRGold = ref(0)
const trueFGold = ref(0)
//
const totalmoney = ref(0)
const totalRcoin = ref(0)
const totalFcoin = ref(0)
//
const pendingGold = ref(0)
const pendingRGold = ref(0)
const pendingFGold = ref(0)
//
const approvedGold = ref(0)
const approvedRGold = ref(0)
const approvedFGold = ref(0)
//
const rejectedGold = ref(0)
const rejectedRGold = ref(0)
const rejectedFGold = ref(0)
// ==============================================================
//
const get = async function (val) {
try {
//
if (adminData.value.area === '泰国') {
rechargeVo.value.areas = ['泰国', '越南']
} else if (adminData.value.area !== '总部') {
rechargeVo.value.area = adminData.value.area
}
//
if (typeof val === 'number') {
getObj.value.pageNum = val
}
//
if (getTime.value != null) {
if (getTime.value[0] && getTime.value[1]) {
rechargeVo.value.startDate = getTime.value[0]
rechargeVo.value.endDate = getTime.value[1]
}
} else {
rechargeVo.value.startDate = ''
rechargeVo.value.endDate = ''
}
//
rechargeVo.value.sortField = sortField.value
rechargeVo.value.sortOrder = sortOrder.value
console.log('搜索参数', getObj.value)
// POST
const result = await API({
url: '/recharge/recharge',
data: { ...getObj.value, rechargeVo: { ...rechargeVo.value } }
})
// rechargeVo.value
const detailWithoutSort = ref({
area: rechargeVo.value.area,
adminId: rechargeVo.value.adminId,
startDate: rechargeVo.value.startDate,
endDate: rechargeVo.value.endDate
})
const result2 = await API({
url: '/recharge/recharge/RechargeA',
data: {
...detailWithoutSort.value
}
})
// result2
if (!result2 || !result2.data || result2.data.length === 0) {
totalmoney.value = 0
totalRcoin.value = 0
totalFcoin.value = 0
}
if (result2.data) {
result2.data.forEach((item) => {
switch (item.auditStatus) {
case '待审核':
// item.raudit 0
// item.sumRaudit 0
pendingGold.value = item.sumRaudit || 0
pendingRGold.value = item.sumRaudit1 || 0
pendingFGold.value = item.sumRaudit2 || 0
break
case '已通过':
approvedGold.value = item.sumRaudit || 0
approvedRGold.value = item.sumRaudit1 || 0
approvedFGold.value = item.sumRaudit2 || 0
break
case '已驳回':
rejectedGold.value = item.sumRaudit || 0
rejectedRGold.value = item.sumRaudit1 || 0
rejectedFGold.value = item.sumRaudit2 || 0
break
}
})
}
trueGold.value = pendingGold.value + approvedGold.value + rejectedGold.value
trueRGold.value =
pendingRGold.value + approvedRGold.value + rejectedRGold.value
trueFGold.value =
pendingFGold.value + approvedFGold.value + rejectedFGold.value
//
console.log('请求成功', result)
//
tableData.value = result.data.list
console.log('tableData', tableData.value)
//
total.value = result.data.total
console.log('total', total.value)
} catch (error) {
console.log('请求失败', error)
//
}
}
//
const search = function () {
getObj.value.pageNum = 1
get()
}
//
const reset = function () {
rechargeVo.value.activityId = ''
rechargeVo.value.rechargeWay = ''
rechargeVo.value.area = ''
rechargeVo.value.startDate = ''
rechargeVo.value.endDate = ''
sortField.value = ''
sortOrder.value = ''
getTime.value = []
}
//
const getToday = function () {
const today = new Date()
const startDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate()
)
// 23:59:59
const endDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() + 1
)
getTime.value = [startDate, endDate]
//
rechargeVo.value.startDate = moment(startDate).format('YYYY-MM-DD HH:mm:ss')
rechargeVo.value.endDate = moment(endDate).format('YYYY-MM-DD HH:mm:ss')
console.log('getTime', getTime.value)
get()
}
//
const getYesterday = function () {
const yesterday = new Date()
yesterday.setDate(yesterday.getDate() - 1)
const startDate = new Date(
yesterday.getFullYear(),
yesterday.getMonth(),
yesterday.getDate()
)
// 23:59:59
const endDate = new Date(
yesterday.getFullYear(),
yesterday.getMonth(),
yesterday.getDate() + 1
)
getTime.value = [startDate, endDate]
//
rechargeVo.value.startDate = moment(startDate).format('YYYY-MM-DD HH:mm:ss')
rechargeVo.value.endDate = moment(endDate).format('YYYY-MM-DD HH:mm:ss')
console.log('getTime', getTime.value)
get()
}
// 7
const get7Days = function () {
const today = new Date()
const startDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() - 6
)
// 23:59:59
const endDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() + 1
)
getTime.value = [startDate, endDate]
//
rechargeVo.value.startDate = moment(startDate).format('YYYY-MM-DD HH:mm:ss')
rechargeVo.value.endDate = moment(endDate).format('YYYY-MM-DD HH:mm:ss')
console.log('getTime', getTime.value)
get()
}
//
const adminAll = function () {
console.log('adminAll')
rechargeVo.value.status = ''
getObj.value.pageNum = 1
get()
}
//
const adminWait = async function () {
rechargeVo.value.status = 0
getObj.value.pageNum = 1
await get()
console.log('adminWait')
trueGold.value = pendingGold.value
trueRGold.value = pendingRGold.value
trueFGold.value = pendingFGold.value
}
//
const adminPass = async function () {
rechargeVo.value.status = 1
getObj.value.pageNum = 1
await get()
console.log('adminPass')
trueGold.value = approvedGold.value
trueRGold.value = approvedRGold.value
trueFGold.value = approvedFGold.value
}
//
const adminReject = async function () {
rechargeVo.value.status = 2
getObj.value.pageNum = 1
await get()
trueGold.value = rejectedGold.value
trueRGold.value = rejectedRGold.value
trueFGold.value = rejectedFGold.value
console.log('adminReject')
}
//
const handleClick = function (tab, event) {
if (tab.props.name === 'all') {
adminAll()
} else if (tab.props.name === 'wait') {
adminWait()
} else if (tab.props.name === 'pass') {
adminPass()
} else if (tab.props.name === 'reject') {
adminReject()
}
}
//
const getActivity = async function () {
try {
// POST
const result = await API({ url: '/recharge/activity/select', data: {} })
//
console.log('请求成功', result)
//
activity.value = result.data
console.log('activity', activity.value)
} catch (error) {
console.log('请求失败', error)
//
}
}
//
const getArea = async function () {
console.log('888888888880000000')
try {
// POST
const result = await API({ url: '/recharge/user/search', data: {} })
//
console.log('请求成功地区', result.data)
//
area.value = result.data
console.log('地区', area.value)
} catch (error) {
console.log('请求失败', error)
//
}
}
//
const checkNumber = function () {
if (typeof parseInt(getObj.value.pageNum) === 'number') {
console.log('总共有多少页' + Math.ceil(total.value / getObj.value.pageSize))
if (
getObj.value.pageNum > 0 &&
getObj.value.pageNum <= Math.ceil(total.value / getObj.value.pageSize)
) {
getObj.value.pageNum = parseInt(getObj.value.pageNum)
console.log('输入的数字合法')
get()
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
}
//
onMounted(async function () {
getAdminData()
get()
getActivity()
getPayWay()
getArea()
})
const handlePageSizeChange = function (val) {
getObj.value.pageSize = val
get()
}
const handleCurrentChange = function (val) {
getObj.value.pageNum = val
get()
}
//
const sortField = ref('')
const sortOrder = ref('')
//
const handleSortChange = (column) => {
console.log('排序字段:', column.prop)
console.log('排序方式:', column.order)
if (column.prop === 'paidGold') {
sortField.value = 'paid_gold'
} else if (column.prop === 'freeGold') {
sortField.value = 'free_gold'
} else if (column.prop === 'rechargeTime') {
sortField.value = 'recharge_time'
} else if (column.prop === 'createTime') {
sortField.value = 'create_time'
} else if (column.prop === 'rechargeGold') {
sortField.value = 'recharge_gold'
}
sortOrder.value = column.order === 'ascending' ? 'ASC' : 'DESC'
get()
}
// Excel
const headers = [
'序号',
'姓名',
'精网号',
'所属地区',
'活动名称',
'货币名称',
'充值金额',
'充值方式',
'永久金币',
'免费金币',
'备注',
'支付方式',
'提交人',
'状态',
'驳回理由',
'交款时间'
]
const showExportInfoPanel = ref(false)
//
const exportExcel = async () => {
try {
console.log('点击导出按钮,尝试显示信息面板');
showExportInfoPanel.value = true;
await nextTick(); //
} catch (error) {
console.error('显示信息面板失败:', error);
ElMessage.error('显示信息面板失败,请稍后重试');
}
};
//
const exportProgress = ref(0)
const isExporting = ref(false)
const exportCancelToken = ref(null)
// 使
// const platformMap = {
// 0: '',
// 1: 'ERP',
// 2: 'Homily Chart',
// 3: 'Homily Link',
// 4: ''
// };
// const updateTypeMap = {
// 0: '',
// 1: '',
// 2: '退',
// 3: ''
// };
//
const doExportExcel = async () => {
try {
isExporting.value = true
exportProgress.value = 0
showExportInfoPanel.value = false
// Excel
const wb = utils.book_new()
const ws = utils.aoa_to_sheet([headers])
utils.book_append_sheet(wb, ws, 'Sheet1')
//
const writer = {
write: (d, o) => {
if (!d) return
utils.sheet_add_aoa(ws, d, { origin: -1 })
}
}
let page = 1
let totalExported = 0
const pageSize = 5000 // 5000
let totalRecords = 0
//
const firstResult = await API({
url: '/recharge/recharge',
method: 'post',
data: {
pageNum: 1,
pageSize,
rechargeVo: { ...rechargeVo.value }
}
})
totalRecords = firstResult.data.total
//
const CancelToken = axios.CancelToken
exportCancelToken.value = CancelToken.source()
//
const firstData = firstResult.data.list
if (firstData.length) {
const rows = firstData.map((row, index) => [
totalExported + index + 1,
row.username || '',
row.jwcode || '',
row.area || '',
row.activityName || '',
// currencyName
row.currencyName || '',
(row.paidGold / 100).toFixed(2) || '0.00',
row.rechargeWay || '',
(row.paidGold / 100).toFixed(2) || '0.00',
(row.freeGold / 100).toFixed(2) || '0.00',
row.remark || '',
row.payWay || '',
row.name || '',
//
row.status === 1 ? '已通过' : row.status === 0 ? '待审核' : row.status === 2 ? '已驳回' : '',
row.reson || '',
moment(row.rechargeTime).format('YYYY-MM-DD HH:mm:ss') || ''
])
writer.write(rows)
totalExported += firstData.length
exportProgress.value = Math.round((totalExported / totalRecords) * 100)
page++
}
while (totalExported < totalRecords) {
const result = await API({
url: '/recharge/recharge',
method: 'post',
data: {
pageNum: page,
pageSize,
rechargeVo: { ...rechargeVo.value }
},
cancelToken: exportCancelToken.value.token
})
const data = result.data.list
if (!data.length) break
//
const rows = data.map((row, index) => [
totalExported + index + 1,
row.username || '',
row.jwcode || '',
row.area || '',
row.activityName || '',
// currencyName
row.currencyName || '',
(row.paidGold / 100).toFixed(2) || '0.00',
row.rechargeWay || '',
(row.paidGold / 100).toFixed(2) || '0.00',
(row.freeGold / 100).toFixed(2) || '0.00',
row.remark || '',
row.payWay || '',
row.name || '',
//
row.status === 1 ? '已通过' : row.status === 0 ? '待审核' : row.status === 2 ? '已驳回' : '',
row.reson || '',
moment(row.rechargeTime).format('YYYY-MM-DD HH:mm:ss') || ''
])
//
writer.write(rows)
totalExported += data.length
exportProgress.value = Math.round((totalExported / totalRecords) * 100)
// 500
if (page % 500 === 0) {
await new Promise(resolve => setTimeout(resolve, 0))
}
page++
}
//
writeFile(wb, '所有充值明细.xlsx')
ElMessage.success(`导出成功,共${totalExported}条数据`)
} catch (error) {
if (!axios.isCancel(error)) {
ElMessage.error(`导出失败: ${error.message}`)
}
} finally {
isExporting.value = false
exportCancelToken.value = null
}
}
//
const cancelExport = () => {
if (exportCancelToken.value) {
exportCancelToken.value.cancel('用户取消导出')
ElMessage.warning('导出已取消')
isExporting.value = false
}
}
const putExcel = ref({
startDate: new Date(),
endDate: new Date(new Date().setDate(new Date().getDate() + 1))
})
</script>
<template>
<el-row>
<el-col>
<el-card style="margin-bottom: 20px">
<el-row style="margin-bottom: 10px">
<el-col :span="6">
<div class="head-card-element">
<el-text class="mx-1" size="large">活动名称</el-text>
<el-select
v-model="rechargeVo.activityId"
placeholder="请选择活动名称"
size="large"
style="width: 240px"
clearable
>
<el-option
v-for="item in activity"
:key="item.activityId"
:label="item.activityName"
:value="item.activityId"
/>
</el-select>
</div>
</el-col>
<!-- <el-col :span="8">
<div class="head-card-element">
<el-text class="mx-1" size="large">充值方式</el-text>
<el-select
v-model="rechargeVo.rechargeWay"
placeholder="请选择充值方式"
size="large"
style="width: 240px"
clearable
>
<el-option
v-for="item in rechargeWay"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</div>
</el-col>-->
<el-col :span="8">
<div class="head-card-element" v-if="adminData.area == '总部'">
<el-text class="mx-1" size="large">所属地区</el-text>
<el-select
v-model="rechargeVo.area"
placeholder="请选择所属地区"
size="large"
style="width: 240px"
clearable
>
<el-option
v-for="item in area"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="16">
<div class="head-card-element">
<el-text class="mx-1" size="large">充值时间</el-text>
<el-date-picker
v-model="getTime"
type="datetimerange"
range-separator="至"
start-placeholder="起始时间"
end-placeholder="结束时间"
/>
<el-button style="margin-left: 10px" @click="getToday()"
></el-button
>
<el-button @click="getYesterday()"></el-button>
<el-button @click="get7Days()">近7天</el-button>
</div>
</el-col>
<el-col :span="6">
<div class="head-card-btn">
<el-button type="success" @click="reset()">重置</el-button>
<el-button type="primary" @click="search()">查询</el-button>
<!-- 新增导出按钮 -->
<el-button type="primary" @click="exportExcel">导出excel</el-button>
</div>
</el-col>
</el-row>
</el-card>
</el-col>
</el-row>
<el-row>
<el-col>
<el-card>
<el-tabs
v-model="activeName"
type="card"
class="demo-tabs"
@tab-click="handleClick"
>
<el-tab-pane label="全部" name="all"></el-tab-pane>
<el-tab-pane label="待审核" name="wait"></el-tab-pane>
<el-tab-pane label="已通过" name="pass"></el-tab-pane>
<el-tab-pane label="已驳回" name="reject"></el-tab-pane>
<div>
充值金额{{ (trueRGold / 100).toFixed(2) }}新币永久金币{{
(trueRGold / 100).toFixed(2)
}}金币免费金币{{ (totalFcoin / 100).toFixed(2) }}金币
</div>
</el-tabs>
<!-- 设置表格容器的高度和滚动样式 -->
<div style="height: 520px; overflow-y: auto">
<el-table
:data="tableData"
style="width: 100%"
height="520px"
@sort-change="handleSortChange"
>
<el-table-column
type="index"
label="序号"
width="70px"
fixed="left"
>
<template #default="scope">
<span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template>
</el-table-column>
<el-table-column
fixed="left"
prop="username"
label="姓名"
width="100px"
/>
<el-table-column
fixed="left"
prop="jwcode"
label="精网号"
width="110px"
/>
<el-table-column prop="area" label="所属地区" width="100px" />
<el-table-column
prop="activityName"
label="活动名称"
width="150px"
/>
<el-table-column prop="" label="货币名称" width="120px" />
<el-table-column
prop="paidMoney"
label="充值金额"
width="120px"
sortable=" custom"
>
<template #default="scope">
<span>{{ scope.row.paidGold / 100 }}</span>
</template>
</el-table-column>
<el-table-column
prop="rechargeWay"
label="充值方式"
width="100px"
/>
<el-table-column
prop="paidGold"
label="永久金币"
sortable="“custom”"
width="110px"
>
<template #default="scope">
<span>{{ scope.row.paidGold / 100 }}</span>
</template>
</el-table-column>
<el-table-column
prop="freeGold"
label="免费金币"
sortable="“custom”"
width="110px"
>
<template #default="scope">
<span>{{ scope.row.freeGold / 100 }}</span>
</template>
</el-table-column>
<el-table-column
prop="remark"
label="备注"
width="200px"
show-overflow-tooltip
/>
<el-table-column prop="payWay" label="支付方式" width="100px" />
<el-table-column
prop="rechargeVoucher"
label="支付凭证"
width="150px"
>
<template #default="scope">
<el-image
:preview-src-list="[scope.row.rechargeVoucher]"
:preview-teleported="true"
:src="scope.row.rechargeVoucher"
alt="凭证"
style="width: 50px; height: 50px"
/>
</template>
</el-table-column>
<el-table-column prop="name" label="提交人" width="100px" />
<el-table-column prop="status" label="状态" width="100px">
<template #default="scope">
<span v-if="scope.row.status === 1">
<div class="status">
<span class="green-dot"></span>
<span>已通过</span>
</div>
</span>
<span v-if="scope.row.status === 0">
<div class="status">
<span class="grey-dot"></span>
<span>待审核</span>
</div>
</span>
<span v-if="scope.row.status === 2">
<div class="status">
<span class="red-dot"></span>
<span>已驳回</span>
</div>
</span>
</template>
</el-table-column>
<el-table-column
prop="reson"
label="驳回理由"
width="200px"
show-overflow-tooltip
/>
<el-table-column
prop="rechargeTime"
sortable="“custom”"
label="交款时间"
width="200px"
>
<template #default="scope">
{{
moment(scope.row.rechargeTime).format('YYYY-MM-DD HH:mm:ss')
}}
</template>
</el-table-column>
<el-table-column
prop="createTime"
sortable="“custom”"
label="提交时间"
width="200px"
/>
</el-table>
</div>
<!-- 分页 -->
<div class="pagination" style="margin-top: 20px">
<el-pagination
background
:page-size="getObj.pageSize"
:page-sizes="[5, 10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handlePageSizeChange"
@current-change="handleCurrentChange"
></el-pagination>
</div>
</el-card>
</el-col>
</el-row>
<!-- 导出excel提前展示的信息面板 -->
<el-dialog
v-model="showExportInfoPanel"
title="导出信息确认"
width="400px"
:close-on-click-modal="false"
>
<div class="info-panel-header">导出信息</div>
<div v-if="!rechargeVo.activityId && !rechargeVo.area && !rechargeVo.startDate && !rechargeVo.endDate">
你正在导出所有数据
</div>
<div v-else>
你正在导出以下数据
</div>
<div v-if="rechargeVo.activityId">活动名称{{ rechargeVo.activityId || '' }}</div>
<div v-if="rechargeVo.area">所属地区{{ rechargeVo.area || '' }}</div>
<div v-if="rechargeVo.startDate || rechargeVo.endDate">
<span>充值时间</span>
<span>{{ rechargeVo.startDate ? moment(rechargeVo.startDate).format('YYYY-MM-DD HH:mm:ss') : '无起始时间' }} {{ rechargeVo.endDate ? moment(rechargeVo.endDate).format('YYYY-MM-DD HH:mm:ss') : '无结束时间' }}</span>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="showExportInfoPanel = false">取消</el-button>
<el-button type="primary" @click="doExportExcel">导出</el-button>
</span>
</template>
</el-dialog>
<!-- 导出进度弹窗 -->
<el-dialog
v-model="isExporting"
title="正在导出"
width="400px"
:close-on-click-modal="false"
:show-close="false"
>
<el-progress
:percentage="exportProgress"
:format="(percentage) => `${percentage}%`"
/>
<template #footer>
<span class="dialog-footer">
<el-button type="danger" @click="cancelExport">取消导出</el-button>
</span>
</template>
</el-dialog>
</template>
<style scoped>
.pagination {
display: flex;
}
.status {
display: flex;
}
.head-card {
display: flex;
}
.head-card-element {
margin-right: 20px;
}
.head-card-btn {
margin-left: auto;
}
</style>

571
src/views/refund/addRefund.vue

@ -0,0 +1,571 @@
<script setup>
import { onMounted, reactive } from 'vue'
import { ref, computed, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import axios from 'axios'
import { ElMessageBox } from 'element-plus'
import API from '@/util/http'
import moment from 'moment'
// import _ from 'lodash'
const addRe = ref({
typeR: '0'
})
//
const adminData = ref({})
const getAdminData = async function () {
try {
const result = await API({ url: '/admin/userinfo', data: {} })
adminData.value = result
addRefund.value.adminId = adminData.value.adminId
console.log('请求成功', result)
console.log('用户信息', user.value)
} catch (error) {
console.log('请求失败', error)
}
}
//
const trimJwCode = () => {
if (addRefund.value.jwcode) {
addRefund.value.jwcode = addRefund.value.jwcode.replace(/\s/g, '');
}
}
// 退
const addRefund = ref({
updateType: '3',
allCoin: 0,
orderCode: '',
refundGoods: '',
freeCoin: 0,
rechargeCoin: 0,
taskCoin: 0
})
//
const cancel = function () {
addRefund.value = {}
addRefund.value.updateType = '3'
addRefund.value.rechargeCoin = 0
addRefund.value.freeCoin = 0
addRefund.value.taskCoin = 0
addRefund.value.allCoin = 0
addRe.value.typeR = 0
addRefund.value.adminId = adminData.value.adminId
}
// 退
const add = async function () {
try {
// POST
const result = await API({ url: '/refund/add', data: addRefund.value })
if (result.code === 0) {
ElMessage.error(result.msg)
return
}
console.log('请求成功', result)
ElMessage.success('添加成功')
//
addRefund.value = {}
addRefund.value.adminId = adminData.value.adminId
addRefund.value.updateType = '3'
addRefund.value.allCoin = 0
addRefund.value.orderCode = ''
addRefund.value.refundGoods = ''
addRefund.value.freeCoin = 0
addRefund.value.rechargeCoin = 0
addRefund.value.taskCoin = 0
addRefund.value.typeR = 0
user.value = {}
} catch (error) {
console.log('请求失败', error)
//
}
}
const addBefore = () => {
Ref.value.validate(async (valid) => {
if (valid) {
ElMessageBox.confirm('确认添加?')
.then(() => {
add()
console.log('添加成功')
addRefund.value.allCoin = 0
;(addRefund.value.freeCoin = 0),
(addRefund.value.rechargeCoin = 0),
(addRefund.value.taskCoin = 0),
(addRefund.value = {})
})
.catch(() => {
console.log('取消添加')
})
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
})
}
//
//
const Ref = ref(null)
const startChange = (val) => {}
const rules = reactive({
jwcode: [{ required: true, message: '请输入精网号', trigger: 'blur' }],
refundType: [{ required: true, message: '请选择退款类型', trigger: 'blur' }],
orderCode: [{ required: true, message: '请选择退款商品', trigger: 'blur' }],
taskCoin: [{ required: true, message: '请输入任务金币', trigger: 'blur' },
{
validator: (rule, value) => {
if (value < 0) {
return Promise.reject(new Error('任务金币至少为0'))
}
return Promise.resolve()
},
}
],
freeCoin: [{ required: true, message: '请输入免费金币', trigger: 'blur' },
{
validator: (rule, value) => {
if (value < 0) {
return Promise.reject(new Error('免费金币至少为0'))
}
return Promise.resolve()
},
}
],
rechargeCoin: [
{ required: true, message: '请输入永久金币', trigger: 'blur' },
{
validator: (rule, value) => {
if (value < 0) {
return Promise.reject(new Error('永久金币至少为0'))
}
return Promise.resolve()
},
}
],
allCoin: [
{ required: true, message: '请选择付款方式', trigger: 'blur' },
{
validator: (rule, value) => {
if (value === 0) {
return Promise.reject(new Error('总金币不能为0'))
}
return Promise.resolve()
},
trigger: 'blur'
}
]
})
//
const user = ref({
firstRechargeTime: ''
})
const getUser = async function (jwcode) {
trimJwCode();
try {
// POST
const result = await API({
url: '/recharge/user',
data: {
jwcode: addRefund.value.jwcode,
area: adminData.value.area
}
})
console.log('请求成功', result)
//
if (result.code === 0) {
//ElMessage.error(result.msg)
} else {
user.value = result.data
user.value.A =
Number(user.value.pendingRechargeTimes) +
Number(user.value.pendingSpendTimes)
console.log('用户信息', user.value)
//ElMessage.success(result.msg)
}
} catch (error) {
console.log('请求失败', error)
ElMessage.error('查询失败,请检查精网号是否正确')
//
}
}
const calculatedAllGold = computed(() => {
const sum =
Number(addRefund.value.freeCoin) +
Number(addRefund.value.rechargeCoin) +
Number(addRefund.value.taskCoin)
return !isNaN(sum) ? sum : 0
})
watch(calculatedAllGold, (newVal) => {
addRefund.value.allCoin = newVal
})
const AAA = computed(() => {
return addRefund.value.jwcode
})
watch(AAA, (newVal) => {})
// 退
const refundType = [
{
value: '退款商品',
label: '退款商品'
}
]
//
//
const goods = ref([])
const getGoods = async function (jwcode) {
trimJwCode();
try {
// POST
const result = await API({
url: '/consume/getDeatil',
data: {
jwcode: addRefund.value.jwcode,
area: adminData.value.area
}
})
console.log('请求成功', result)
if (result.code === 0) {
ElMessage.error(result.msg)
} else {
//
goods.value = result.data
console.log('用户信息', goods.value)
ElMessage.success(result.msg)
}
} catch (error) {
console.log('请求失败', error)
ElMessage.error('查询失败,请检查精网号是否正确')
//
}
}
const calculatedRechargeGoods = computed(() => {
return (
+addRefund.value.freeCoin +
+addRefund.value.rechargeCoin +
+addRefund.value.taskCoin
)
})
watch(calculatedRechargeGoods, (newVal) => {
addRefund.value.allCoin = newVal
})
watch(calculatedRechargeGoods, (newVal) => {
addRefund.value.allCoin = newVal
console.log('计算的总金币', newVal)
})
//
//
const getProductByOrderCode = async function (item) {
try {
// POST
const result = await API({
url: '/refund/searchByOrderCode?orderCode=' + item,
data: {}
})
addRefund.value.contactId = result.data.detailyId
addRefund.value.refundGoods = result.data.productName
addRefund.value.orderCode = result.data.orderCode
addRefund.value.taskCoin = (result.data.taskCoin * -1) / 100
addRefund.value.freeCoin = (result.data.freeCoin * -1) / 100
addRefund.value.rechargeCoin = (result.data.rechargeCoin * -1) / 100
addRefund.value.allCoin =
(result.data.taskCoin * -1 +
result.data.freeCoin * -1 +
result.data.rechargeCoin * -1) /
100
console.log('请求成功', addRefund.value)
if (result.data.code === 0) {
ElMessage.error(result.data.msg)
} else {
ElMessage.success('选择成功')
}
} catch (error) {
console.log('请求失败', error)
ElMessage.error('查询失败,请检查精网号是否正确')
//
}
}
const handleSelectionChange = (value) => {
getProductByOrderCode(value)
console.log('选择的订单号', value)
const selectedItem = goods.value.find((item) => item.detailId === value)
}
//
onMounted(async function () {
await getAdminData()
})
</script>
<template>
<div style="font-weight: bold">新增退款</div>
<el-form
:model="addRefund"
ref="Ref"
:rules="rules"
label-width="auto"
style="max-width: 750px"
class="form-style"
>
<el-form-item prop="jwcode" label="精网号">
<el-input
v-model="addRefund.jwcode"
style="width: 220px"
@change="getGoods(addRefund.jwcode)"
/>
<el-button
type="primary"
@click="getUser(addRefund.jwcode)"
style="margin-left: 20px"
>查询</el-button
>
</el-form-item>
<el-form-item prop="refundType" label="退款类型">
<el-select
v-model="addRefund.refundType"
placeholder="请选择"
style="width: 300px"
>
<el-option
v-for="item in refundType"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item prop="orderCode" label="商品名">
<el-select
v-model="addRefund.orderCode"
placeholder="请选择"
style="width: 300px"
@change="handleSelectionChange"
>
<el-option
v-for="item in goods"
:key="item.value"
:label="item.productName + item.orderCode"
:value="item.orderCode"
/>
</el-select>
</el-form-item>
<el-form-item prop="typeR" label="退款方式:">
<el-radio-group v-model="addRe.typeR">
<el-radio value="0" @change="addRe.typeR = '0'">全部退款</el-radio>
<el-radio value="1">部分退款</el-radio>
</el-radio-group>
</el-form-item>
<div style="display: flex; align-items: center">
<el-form-item prop="rechargeCoin" label="永久金币" style="float: left">
<el-input
v-model="addRefund.rechargeCoin"
style="width: 100px"
:disabled="addRe.typeR === '0' ? true : false"
>
</el-input>
<p></p>
</el-form-item>
<el-form-item
prop="freeCoin"
label="免费金币"
style="margin-left: -20px; float: left"
>
<el-input
v-model="addRefund.freeCoin"
style="float: left; width: 100px"
:disabled="addRe.typeR === '0' ? true : false"
/>
<p></p>
</el-form-item>
<el-form-item prop="taskCoin" label="任务金币" style="margin-left: -20px">
<el-input
v-model="addRefund.taskCoin"
style="float: left; width: 100px"
:disabled="addRe.typeR === '0' ? true : false"
/>
<p></p>
</el-form-item>
</div>
<el-form-item prop="allCoin" label="退款金币总数">
<el-input disabled v-model="addRefund.allCoin" style="width: 100px">
</el-input>
</el-form-item>
<el-form-item prop="remark" label="备注">
<el-input
v-model="addRefund.remark"
style="width: 300px"
:rows="2"
maxlength="100"
show-word-limit
type="textarea"
/>
</el-form-item>
<el-form-item prop="commitName" label="提交人">
<el-input
style="width: 300px"
:value="adminData.name"
disabled
placeholder="提交人姓名"
/>
</el-form-item>
<el-button type="success" @click="cancel()" style="margin-left: 280px">重置</el-button>
<el-button type="primary" @click="addBefore"> 提交 </el-button>
</el-form>
<!-- 客户信息栏 -->
<el-card style="width: 850px; float: right" class="customer-info">
<el-form
:model="user"
label-width="auto"
style="max-width: 1000px"
label-position="left"
>
<el-text size="large" style="margin-left: 20px">客户信息</el-text>
<el-row style="margin-top: 20px">
<el-col :span="10">
<el-form-item label="姓名:">
<p>{{ user.name }}</p>
</el-form-item>
</el-col>
<el-col :span="14">
<el-form-item label="历史金币总数">
<!-- 检查 user.totalRechargeGold 是否为有效的数字 -->
<p v-if="!isNaN(Number(user.totalRechargeGold))">
{{ Number(user.totalRechargeGold / 100) }}
</p>
<!-- 如果不是有效的数字显示默认值 -->
<p v-else></p>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="精网号">
<p>{{ user.jwcode }}</p>
</el-form-item>
</el-col>
<el-col :span="14">
<el-form-item label="当前金币总数" style="width: 500px">
<span
style="color: #2fa1ff; margin-right: 5px"
v-if="user.buyJb !== undefined"
>{{
(user.buyJb + user.free6 + user.free12 + user.coreJb) / 100
}}</span
>
<span
style="display: inline; white-space: nowrap; color: #b1b1b1"
v-if="user.buyJb !== undefined"
>(永久金币:{{ user.buyJb / 100 }};免费金币:{{
(user.free6 + user.free12) / 100
}};任务金币:{{ user.coreJb / 100 }})</span
>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="首次充值日期">
<p v-if="user.firstRechargeDate">
{{ moment(user.firstRechargeDate).format('YYYY-MM-DD HH:mm:ss') }}
</p>
</el-form-item>
</el-col>
<el-col :span="14">
<el-form-item label="充值次数">
<p style="color: #2fa1ff">{{ user.rechargeTimes }}</p>
</el-form-item>
</el-col>
<!-- <el-col :span="10">
<el-form-item label="负责客服">
<p>{{ adminData.name }}</p>
</el-form-item>
</el-col> -->
<el-col :span="10">
<el-form-item label="消费次数">
<p style="color: #2fa1ff">{{ user.spendTimes }}</p>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="所属门店">
<p>{{ adminData.area }}</p>
</el-form-item>
</el-col>
<el-col :span="14">
<!-- <el-form-item label="待审核">
<p style="color: #2fa1ff">
{{ user.A }}
</p>
</el-form-item> -->
</el-col>
</el-row>
</el-form>
</el-card>
</template>
<style scoped>
p {
margin: 0px;
}
.el-form-item {
margin-left: 50px;
}
/* 上传图片的格式 */
.avatar-uploader .avatar {
width: 50px;
height: 50px;
display: block;
}
</style>
<style>
.avatar-uploader .el-upload {
border: 1px dashed var(--el-border-color);
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
transition: var(--el-transition-duration-fast);
}
.avatar-uploader .el-upload:hover {
border-color: var(--el-color-primary);
}
.el-icon.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 50px;
height: 50px;
text-align: center;
}
.form-style {
margin-top: 50px;
max-width: 50%;
float: left;
}
.form-style2 {
max-width: 60%;
}
p {
font-size: 13px;
transform: scale(1);
}
</style>

734
src/views/refund/allRefund.vue

@ -0,0 +1,734 @@
<script setup>
// 退
import { ref, onMounted, reactive, computed } from 'vue'
import ElementPlus from 'element-plus'
import { AiFillRead } from 'vue-icons-plus/ai'
import { ElMessage, ElMessageBox } from 'element-plus'
import axios from 'axios'
import moment from 'moment'
import API from '@/util/http'
//
//
const adminData = ref({})
const getAdminData = async function () {
try {
const result = await API({ url: '/admin/userinfo', data: {} })
adminData.value = result
console.log('请求成功', result)
console.log('用户信息', adminData.value)
} catch (error) {
console.log('请求失败', error)
}
}
//
const tableData = ref([])
// ======================================
// detail
const detail = ref({})
//
const getObj = ref({
pageNum: 1,
pageSize: 50
})
//
const total = ref(100)
//
const getTime = ref([])
//
const allData = ref([])
//
const area = ref([])
//
const activeName = ref('all')
// 退
const consumeType = [
{
value: '退款商品',
label: '退款商品'
}
]
// //
// const tableHeight = computed(function () {
// return (getObj.value.pageSize + 2) * 45 + "px";
// });
//
//
const trueGold = ref(0)
const trueRgold = ref(0)
const trueFgold = ref(0)
const trueTgold = ref(0)
//
const pendingRgold = ref(0)
const pendingFgold = ref(0)
const pendingTgold = ref(0)
//
const pendingGold = ref(0)
//
const approvedRgold = ref(0)
const approvedFgold = ref(0)
const approvedTgold = ref(0)
//
const approvedGold = ref(0)
//
const rejectedRgold = ref(0)
const rejectedFgold = ref(0)
const rejectedTgold = ref(0)
//
const rejectedGold = ref(0)
// ==============================================================
//
const get = async function (val) {
try {
//
if (adminData.value.area === '泰国') {
detail.value.areas = ['泰国', '越南']
} else if (adminData.value.area !== '总部') {
detail.value.area = adminData.value.area
}
//
if (typeof val === 'number') {
getObj.value.pageNum = val
}
//
if (getTime.value != null) {
if (getTime.value.startDate != '' && getTime.value.endDate != '') {
detail.value.startDate = getTime.value[0]
detail.value.endDate = getTime.value[1]
}
} else {
detail.value.startDate = ''
detail.value.endDate = ''
}
//
detail.value.sortField = sortField.value
detail.value.sortOrder = sortOrder.value
console.log('搜索参数', getObj.value)
// POST
const result = await API({
url: '/refund/search',
data: {
...getObj.value,
detail: { ...detail.value }
}
})
// detail.value
const detailWithoutSort = { ...detail.value }
delete detailWithoutSort.sortField
delete detailWithoutSort.sortOrder
const result2 = await API({
url: '/refund/RefundA',
data: {
...detailWithoutSort
}
})
//
if (result2.data) {
result2.data.forEach((item) => {
switch (item.status) {
case '待审核':
// item.raudit 0
pendingRgold.value = item.sumRaudit1 || 0
pendingFgold.value = item.sumRaudit2 || 0
pendingTgold.value = item.sumRaudit3 || 0
// item.sumRaudit 0
pendingGold.value = item.sumRaudit || 0
break
case '已通过':
approvedRgold.value = item.sumRaudit1 || 0
approvedFgold.value = item.sumRaudit2 || 0
approvedTgold.value = item.sumRaudit3 || 0
approvedGold.value = item.sumRaudit || 0
break
case '已驳回':
rejectedRgold.value = item.sumRaudit1 || 0
rejectedFgold.value = item.sumRaudit2 || 0
rejectedTgold.value = item.sumRaudit3 || 0
rejectedGold.value = item.sumRaudit || 0
break
}
})
}
trueFgold.value =
pendingFgold.value + approvedFgold.value + rejectedFgold.value
trueRgold.value =
pendingRgold.value + approvedRgold.value + rejectedRgold.value
trueTgold.value =
pendingTgold.value + approvedTgold.value + rejectedTgold.value
trueGold.value = pendingGold.value + approvedGold.value + rejectedGold.value
//
console.log('请求成功', result)
//
tableData.value = result.data.list
console.log('tableData', tableData.value)
//
total.value = result.data.total
console.log('total', total.value)
//
handleClick()
} catch (error) {
console.log('请求失败', error)
//
}
}
//
const search = function () {
getObj.value.pageNum = 1
get()
}
//
const reset = function () {
detail.value.refundGoods = ''
detail.value.refundType = ''
detail.value.area = ''
detail.value.startDate = ''
detail.value.endDate = ''
sortField.value = ''
sortOrder.value = ''
getTime.value = {}
}
//
const getToday = function () {
const today = new Date()
const startDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate()
)
const endDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() + 1
)
getTime.value = [startDate, endDate]
console.log('getTime', getTime.value)
get()
}
//
const getYesterday = function () {
const yesterday = new Date()
yesterday.setDate(yesterday.getDate() - 1)
const startDate = new Date(
yesterday.getFullYear(),
yesterday.getMonth(),
yesterday.getDate()
)
const endDate = new Date(
yesterday.getFullYear(),
yesterday.getMonth(),
yesterday.getDate() + 1
)
getTime.value = [startDate, endDate]
console.log('getTime', getTime.value)
get()
}
// 7
const get7Days = function () {
const today = new Date()
const startDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() - 6
)
const endDate = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() + 1
)
getTime.value = [startDate, endDate]
console.log('getTime', getTime.value)
get()
}
//
const adminAll = function () {
console.log('adminAll')
detail.value.status = ''
getObj.value.pageNum = 1
get()
trueFgold.value =
pendingFgold.value + approvedFgold.value + rejectedFgold.value
trueRgold.value =
pendingRgold.value + approvedRgold.value + rejectedRgold.value
trueTgold.value =
pendingTgold.value + approvedTgold.value + rejectedTgold.value
trueGold.value = pendingGold.value + approvedGold.value + rejectedGold.value
}
//
const adminWait = async function () {
detail.value.status = 0
getObj.value.pageNum = 1
await get()
console.log('adminWait')
trueFgold.value = pendingFgold.value
trueRgold.value = pendingRgold.value
trueTgold.value = pendingTgold.value
trueGold.value = pendingGold.value
}
//
const adminPass = async function () {
detail.value.status = 1
getObj.value.pageNum = 1
await get()
console.log('adminPass')
trueFgold.value = approvedFgold.value
trueRgold.value = approvedRgold.value
trueTgold.value = approvedTgold.value
trueGold.value = approvedGold.value
}
//
const adminReject = async function () {
detail.value.status = 2
getObj.value.pageNum = 1
await get()
console.log('adminReject')
trueFgold.value = rejectedFgold.value
trueRgold.value = rejectedRgold.value
trueTgold.value = rejectedTgold.value
trueGold.value = rejectedGold.value
}
//
// tab.props.nameall
const tabName = ref('all')
const handleClick = function (tab, event) {
if (tab.props.name === 'all') {
adminAll()
} else if (tab.props.name === 'wait') {
adminWait()
} else if (tab.props.name === 'pass') {
adminPass()
} else if (tab.props.name === 'reject') {
adminReject()
}
}
//
const getArea = async function () {
try {
// POST
const result = await API({ url: '/recharge/user/search', data: {} })
//
console.log('请求成功', result)
//
area.value = result.data
console.log('地区', area.value)
} catch (error) {
console.log('请求失败', error)
//
}
}
//
const delObj = ref({})
const del = function (row) {
delObj.value.detailId = row.detailId
console.log('delObj', delObj.value)
}
//
const delConfirm = async function () {
try {
console.log('delObj', delObj.value)
// POST
const result = await API({
url: '/refund/softDelete?detailId=' + delObj.value.detailId,
data: {}
})
//
console.log('请求成功', result)
//
get()
} catch (error) {
console.log('请求失败', error)
//
}
}
//
const goods = ref([])
const getGoods = async function () {
try {
// POST
const result = await API({ url: '/product', data: {} })
//
console.log('请求成功', result)
//
goods.value = result.data
console.log('allData', allData.value)
console.log('地区', area.value)
} catch (error) {
console.log('请求失败', error)
//
}
}
getGoods()
//
const checkNumber = function () {
if (typeof parseInt(getObj.value.pageNum) === 'number') {
console.log('总共有多少页' + Math.ceil(total.value / getObj.value.pageSize))
if (
getObj.value.pageNum > 0 &&
getObj.value.pageNum <= Math.ceil(total.value / getObj.value.pageSize)
) {
getObj.value.pageNum = parseInt(getObj.value.pageNum)
console.log('输入的数字合法')
get()
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
}
//
onMounted(async function () {
await getAdminData()
await get()
await getArea()
})
//
const sortField = ref('')
const sortOrder = ref('')
//
const handleSortChange = (column) => {
console.log('排序字段:', column.prop)
console.log('排序方式:', column.order)
if (column.prop === 'rechargeCoin') {
sortField.value = 'recharge_coin'
} else if (column.prop === 'taskCoin') {
sortField.value = 'task_coin'
} else if (column.prop === 'freeCoin') {
sortField.value = 'free_coin'
} else if (column.prop === 'createTime') {
sortField.value = 'create_time'
} else if (column.prop === 'auditTime') {
sortField.value = 'audit_time'
}
sortOrder.value = column.order === 'ascending' ? 'ASC' : 'DESC'
get()
}
const handlePageSizeChange = function (val) {
getObj.value.pageSize = val
get()
}
const handleCurrentChange = function (val) {
getObj.value.pageNum = val
get()
}
</script>
<template>
<el-row>
<el-col>
<el-card style="margin-bottom: 20px">
<el-row style="margin-bottom: 10px">
<el-col :span="8">
<div class="head-card-element">
<el-text class="mx-1" size="large">退款类型</el-text>
<el-select
v-model="detail.refundType"
placeholder="请选择退款类型"
size="large"
style="width: 240px"
clearable
>
<el-option
v-for="item in consumeType"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</el-col>
<el-col :span="8">
<div class="head-card-element">
<el-text class="mx-1" size="large">退款商品</el-text>
<el-select
v-model="detail.refundGoods"
placeholder="请选择退款商品"
size="large"
style="width: 240px"
clearable
>
<el-option
v-for="item in goods"
:key="item.value"
:label="item.name"
:value="item.name"
/>
</el-select>
</div>
</el-col>
<el-col :span="8">
<div class="head-card-element" v-if="adminData.area == '总部'">
<el-text class="mx-1" size="large">所属地区</el-text>
<el-select
v-model="detail.area"
placeholder="请选择所属地区"
size="large"
style="width: 240px"
clearable
>
<el-option
v-for="item in area"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="21">
<div class="head-card-element">
<el-text class="mx-1" size="large">退款时间</el-text>
<el-date-picker
v-model="getTime"
type="datetimerange"
range-separator="至"
start-placeholder="起始时间"
end-placeholder="结束时间"
/>
<el-button style="margin-left: 10px" @click="getToday()"
></el-button
>
<el-button @click="getYesterday()"></el-button>
<el-button @click="get7Days()">近7天</el-button>
</div>
</el-col>
<el-col :span="3">
<div class="head-card-btn">
<el-button type="success" @click="reset()">重置</el-button>
<el-button type="primary" @click="search()">查询</el-button>
</div>
</el-col>
</el-row>
</el-card>
</el-col>
</el-row>
<el-row>
<el-col>
<el-card>
<el-tabs
v-model="activeName"
type="card"
class="demo-tabs"
@tab-click="handleClick"
>
<el-tab-pane label="全部" name="all"></el-tab-pane>
<el-tab-pane label="待审核" name="wait"></el-tab-pane>
<el-tab-pane label="已通过" name="pass"></el-tab-pane>
<el-tab-pane label="已驳回" name="reject"></el-tab-pane>
</el-tabs>
<div>
退款金币总数{{ Math.abs(trueGold) }}永久金币{{
Math.abs(trueRgold)
}}免费金币{{ Math.abs(trueFgold) }}任务金币{{
Math.abs(trueTgold)
}}
</div>
<!-- 设置表格容器的高度和滚动样式 -->
<div style="height: 520px; overflow-y: auto">
<el-table
:data="tableData"
style="width: 100%"
@sort-change="handleSortChange"
height="520px"
>
<el-table-column
type="index"
label="序号"
width="100px"
fixed="left"
>
<template #default="scope">
<span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template>
</el-table-column>
<el-table-column
prop="username"
label="姓名"
fixed="left"
width="150px"
/>
<el-table-column
prop="jwcode"
label="精网号"
fixed="left"
width="110px"
/>
<el-table-column prop="area" label="所属地区" width="110px" />
<el-table-column prop="refundType" label="退款类型" width="100px" />
<el-table-column prop="refundGoods" label="退款商品" width="110px">
</el-table-column>
<el-table-column label="退款金币数" width="110px">
<template #default="scope">
{{
scope.row.rechargeCoin +
scope.row.freeCoin +
scope.row.taskCoin
}}
</template>
</el-table-column>
<el-table-column
prop="rechargeCoin"
label="永久金币"
width="110px"
sortable="“custom”"
/>
<el-table-column
prop="freeCoin"
sortable="“custom”"
label="免费金币"
width="110px"
/>
<el-table-column
prop="taskCoin"
sortable="“custom”"
label="任务金币"
width="110px"
/>
<!-- 修改prop为taskGold -->
<el-table-column
prop="remark"
label="备注"
width="160px"
show-overflow-tooltip
/>
<el-table-column prop="adminName" label="提交人" width="100px" />
<el-table-column prop="status" label="审核状态" width="120px">
<!-- 模板内容 -->
<template #default="scope">
<span v-if="scope.row.status == 1">
<div class="status">
<span class="green-dot"></span>
<span>已通过</span>
</div>
</span>
<span v-if="scope.row.status == 0">
<div class="status">
<span class="grey-dot"></span>
<span>待审核</span>
</div>
</span>
<span v-if="scope.row.status == 2">
<div class="status">
<span class="red-dot"></span>
<span>已驳回</span>
</div>
</span>
</template>
</el-table-column>
<el-table-column
prop="reson"
label="驳回理由"
width="200px"
show-overflow-tooltip
/>
<el-table-column
prop="createTime"
sortable="“custom”"
label="提交时间"
width="180px"
>
<template #default="scope">
{{ moment(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column
prop="auditTime"
sortable="custom"
label="审核时间"
width="180px"
>
<template #default="scope">
{{ moment(scope.row.auditTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column
prop="operation"
label="操作"
fixed="right"
width="120px"
>
<template #default="scope">
<el-popconfirm
title="确定将此条活动删除吗?"
@confirm="delConfirm"
>
<template #reference>
<el-button type="primary" text @click="del(scope.row)">
删除
</el-button>
</template>
<template #actions="{ delConfirm, cancel }">
<el-button size="small" @click="cancel">取消</el-button>
<el-button type="primary" size="small" @click="delConfirm">
确定
</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页 -->
<!-- 分页 -->
<div class="pagination" style="margin-top: 20px">
<el-pagination
background
:page-size="getObj.pageSize"
:page-sizes="[5, 10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handlePageSizeChange"
@current-change="handleCurrentChange"
></el-pagination>
</div>
</el-card>
</el-col>
</el-row>
</template>
<style scoped>
.status {
display: flex;
}
.head-card {
display: flex;
}
.head-card-element {
margin-right: 20px;
}
.head-card-btn {
margin-left: auto;
}
.pagination {
display: flex;
margin-top: 20px;
}
</style>

798
src/views/usergold/index.vue

@ -0,0 +1,798 @@
<!-- 这是客户金币明细页面 -->
<script setup>
import { ref, onMounted, computed ,nextTick} from 'vue'
import { ElMessage } from 'element-plus'
import axios from 'axios'
import moment from 'moment'
import API from '@/util/http'
import { writeFile, utils } from 'xlsx'
//
const adminData = ref({})
const getAdminData = async function () {
try {
const result = await API({
url: '/admin/userinfo',
method: 'post',
data: {}
})
adminData.value = result
console.log('请求成功', result)
console.log('用户信息', adminData.value)
} catch (error) {
console.log('请求失败', error)
}
}
//
const isLoadingArea = ref(false);
const area = ref([])
const getArea = async () => {
isLoadingArea.value = true;
try {
const result = await API({
url: '/detailY/getarea'
});
// { value, label }
if (Array.isArray(result.data) && typeof result.data[0] === 'string') {
area.value = result.data.map(item => ({ value: item, label: item }));
} else {
area.value = result.data;
}
} catch (error) {
console.error('获取地区数据失败:', error);
ElMessage.error('获取地区数据失败,请稍后重试');
//
area.value = [];
} finally {
isLoadingArea.value = false;
}
};
//
const tableData = ref([])
//
const rechargeCoin = ref(0)
const freeCoin = ref(0)
const taskCoin = ref(0)
// ===========================================
//
const total = ref(100)
//
const getTime = ref([])
// detailY
const detailY = ref({})
//
const getObj = ref({
pageNum: 1,
pageSize: 50
})
// excel
const getPutEX = ref(false)
//
const num = [
{
value: '1',
label: '增加'
},
{
value: '2',
label: '减少'
}
]
//
// ===========================================================================
//
const get = async function (val) {
try {
//
if (adminData.value.area === '泰国') {
detailY.value.areas = ['泰国', '越南']
} else if (adminData.value.area !== '总部') {
detailY.value.area = adminData.value.area
}
//
if (typeof val === 'number') {
getObj.value.pageNum = val
}
if (getTime.value.length === 2) {
detailY.value.startDate = getTime.value[0]
detailY.value.endDate = getTime.value[1]
} else {
detailY.value.startDate = ''
detailY.value.endDate = ''
}
//
detailY.value.sortField = sortField.value
detailY.value.sortOrder = sortOrder.value
console.log('搜索参数', getObj.value)
// POST
const result = await API({
url: '/detailY',
method: 'post',
data: { ...getObj.value, detailY: { ...detailY.value } }
})
tableData.value = result.data.list
total.value = result.data.total
} catch (error) {
console.log('请求失败', error)
}
}
// detailY jwcode
const trimJwCode = () => {
if (detailY.value.jwcode) {
detailY.value.jwcode = detailY.value.jwcode.replace(/\s/g, '');
}
}
//
const search = function () {
trimJwCode();
getObj.value.pageNum = 1
get()
}
//
const reset = function () {
delete detailY.value.jwcode
delete detailY.value.num
delete detailY.value.startDate
delete detailY.value.endDate
delete detailY.value.area
delete sortField.value
delete sortOrder.value
getTime.value = []
delete detailY.value.consumePlatform
}
//
const getToday = function () {
const today = moment()
const startDate = today.startOf('day').toDate()
const endDate = today.add(1, 'days').startOf('day').toDate()
getTime.value = [startDate, endDate]
search()
}
//
const getYesterday = function () {
const today = moment()
const yesterday = moment().subtract(1, 'day')
const startDate = yesterday.startOf('day').toDate()
const endDate = today.startOf('day').toDate()
getTime.value = [startDate, endDate]
search()
}
// 7
const get7Days = function () {
const startDate = moment().subtract(6, 'day').startOf('day').toDate()
const endDate = moment().add(1,'days').startOf('day').toDate()
getTime.value = [startDate, endDate]
search()
}
//
const checkNumber = function () {
if (typeof parseInt(getObj.value.pageNum) === 'number') {
console.log('总共有多少页' + Math.ceil(total.value / getObj.value.pageSize))
if (
getObj.value.pageNum > 0 &&
getObj.value.pageNum <= Math.ceil(total.value / getObj.value.pageSize)
) {
getObj.value.pageNum = parseInt(getObj.value.pageNum)
console.log('输入的数字合法')
get()
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
}
//
onMounted(async function () {
await getArea()
await getAdminData()
await get()
})
// Excel
const headers = [
'序号',
'姓名',
'精网号',
'所属地区',
'平台信息',
'更新数量',
'更新类型',
'永久金币',
'免费金币',
'任务金币',
'提交人',
'更新时间'
]
const showExportInfoPanel = ref(false)
//
const exportExcel = async () => {
try {
console.log('点击导出按钮,尝试显示信息面板');
showExportInfoPanel.value = true;
await nextTick();//
} catch (error) {
console.error('显示信息面板失败:', error);
ElMessage.error('显示信息面板失败,请稍后重试');
}
};
//
const exportProgress = ref(0)
const isExporting = ref(false)
const exportCancelToken = ref(null)
//
const doExportExcel = async () => {
try {
isExporting.value = true
exportProgress.value = 0
showExportInfoPanel.value = false
// Excel
const wb = utils.book_new()
const ws = utils.aoa_to_sheet([headers])
utils.book_append_sheet(wb, ws, 'Sheet1')
//
const writer = {
write: (d, o) => {
if (!d) return
utils.sheet_add_aoa(ws, d, { origin: -1 })
}
}
let page = 1
let totalExported = 0
const pageSize = 5000 // 5000
let totalRecords = 0
//
const firstResult = await API({
url: '/detailY',
method: 'post',
data: {
pageNum: 1,
pageSize,
detailY: { ...detailY.value }
}
})
totalRecords = firstResult.data.total
//
const CancelToken = axios.CancelToken
exportCancelToken.value = CancelToken.source()
//
const platformMap = {
0: '初始化金币',
1: 'ERP系统',
2: 'Homily Chart',
3: 'Homily Link',
4: '金币系统'
};
//
const updateTypeMap = {
0: '充值',
1: '消费',
2: '退款',
3: '其他'
};
//
const firstData = firstResult.data.list
if (firstData.length) {
const rows = firstData.map((row, index) => {
const consumePlatform = parseInt(row.consumePlatform, 10); //
const platformInfo = platformMap[consumePlatform] || '';
return [
totalExported + index + 1,
row.username || '',
row.jwcode || '',
row.area || '',
platformInfo,
(row.gold / 100).toFixed(2) || '0.00',
updateTypeMap[row.updateType] || '',
(row.rechargeCoin / 100).toFixed(2) || '0.00',
(row.freeCoin / 100).toFixed(2) || '0.00',
(row.taskCoin / 100).toFixed(2) || '0.00',
row.name || '',
moment(row.createTime).format('YYYY-MM-DD HH:mm:ss') || ''
]
})
writer.write(rows)
totalExported += firstData.length
exportProgress.value = Math.round((totalExported / totalRecords) * 100)
page++
}
while (totalExported < totalRecords) {
const result = await API({
url: '/detailY',
method: 'post',
data: {
pageNum: page,
pageSize,
detailY: { ...detailY.value }
},
cancelToken: exportCancelToken.value.token
})
const data = result.data.list
if (!data.length) break
//
const rows = data.map((row, index) => [
totalExported + index + 1,
row.username || '',
row.jwcode || '',
row.area || '',
platformMap[row.consumePlatform] || '',
(row.gold / 100).toFixed(2) || '0.00',
updateTypeMap[row.updateType] || '',
(row.rechargeCoin / 100).toFixed(2) || '0.00',
(row.freeCoin / 100).toFixed(2) || '0.00',
(row.taskCoin / 100).toFixed(2) || '0.00',
row.name || '',
moment(row.createTime).format('YYYY-MM-DD HH:mm:ss') || ''
])
//
writer.write(rows)
totalExported += data.length
exportProgress.value = Math.round((totalExported / totalRecords) * 100)
// 500
if (page % 500 === 0) {
await new Promise(resolve => setTimeout(resolve, 0))
}
page++
}
//
writeFile(wb, '客户金币明细.xlsx')
ElMessage.success(`导出成功,共${totalExported}条数据`)
} catch (error) {
if (!axios.isCancel(error)) {
ElMessage.error(`导出失败: ${error.message}`)
}
} finally {
isExporting.value = false
exportCancelToken.value = null
}
}
//
const cancelExport = () => {
if (exportCancelToken.value) {
exportCancelToken.value.cancel('用户取消导出')
ElMessage.warning('导出已取消')
isExporting.value = false
}
}
const putExcel = ref({
startDate: new Date(),
endDate: new Date(new Date().setDate(new Date().getDate() + 1))
})
//
const checkJwCode = async (jwcode) => {
try {
const result = await API({
url: '/recharge/user',
method: 'post',
data: {
jwcode,
area: adminData.value.area
}
})
// code
return result.code !== 0
} catch (error) {
console.log('校验精网号失败', error)
return false
}
}
//
const platform = [
{
value: '4',
label: '金币系统'
},
{
value: '1',
label: 'ERP系统'
},
{
value: '2',
label: 'Homily Chart'
},
{
value: '3',
label: 'Homily Link'
},
{
value: '0',
label: '初始化金币'
}
]
//
const sortField = ref('')
const sortOrder = ref('')
//
const handleSortChange = (column) => {
if (column.prop === 'rechargeCoin') {
sortField.value = 'recharge_coin'
} else if (column.prop === 'taskCoin') {
sortField.value = 'task_coin'
} else if (column.prop === 'freeCoin') {
sortField.value = 'free_coin'
} else if (column.prop === 'createTime') {
sortField.value = 'create_time'
} else if (column.prop === 'gold') {
sortField.value = 'gold'
}
sortOrder.value = column.order === 'ascending' ? 'ASC' : 'DESC'
//gethandleSortChange
get()
}
const handlePageSizeChange = function (val) {
getObj.value.pageSize = val
get()
}
const handleCurrentChange = function (val) {
getObj.value.pageNum = val
get()
}
</script>
<template>
<!-- 导出excel提前展示的信息面板 -->
<el-dialog
v-model="showExportInfoPanel"
title="导出信息确认"
width="400px"
:close-on-click-modal="false"
>
<div class="info-panel-header">导出信息</div>
<!-- 直接使用 detailY 显示信息添加可选链操作符 -->
<!-- detailY是一个ref所以在模板中应该直接使用detailY.consumePlatform
而不是detailY.value.consumePlatform
因为在模板中ref变量会自动解包不需要.value
例如在代码中我们可能错误地在模板中使用了detailY.value但实际上应该直接使用detailY -->
<div v-if="!detailY.jwcode && !detailY.consumePlatform && !detailY.num && !detailY.area && (getTime.length < 2)">
你正在导出所有数据
</div>
<div v-else>
你正在导出以下数据
</div>
<div v-if="detailY.jwcode">精网号{{ detailY.jwcode || '' }}</div>
<div v-if="detailY.consumePlatform">平台信息{{ detailY.consumePlatform ? (platform.find(item => item.value === detailY.consumePlatform)?.label) : '' }}</div>
<div v-if="detailY.num">数量更新类型{{ detailY.num ? (num.find(item => item.value === detailY.num)?.label || '') : '' }}</div>
<div v-if="detailY.area">所属地区{{ detailY.area || '' }}</div>
<div v-if="Array.isArray(getTime) && getTime.length >= 2">
<span>更新时间</span>
<!-- 修改时间格式为精确到秒 -->
<span v-if="Array.isArray(getTime) && getTime.length >= 2">
{{ moment(getTime[0]).format('YYYY-MM-DD HH:mm:ss') }} {{ moment(getTime[1]).format('YYYY-MM-DD HH:mm:ss') }}
</span>
<span v-else></span>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="showExportInfoPanel = false">取消</el-button>
<el-button type="primary" @click="doExportExcel">导出</el-button>
</span>
</template>
</el-dialog>
<!-- 导出进度弹窗 -->
<el-dialog
v-model="isExporting"
title="正在导出"
width="400px"
:close-on-click-modal="false"
:show-close="false"
>
<el-progress
:percentage="exportProgress"
:stroke-width="15"
striped
animated
/>
<div class="export-status">
已导出 {{ Math.round((exportProgress / 100) * total) }} / {{ total }}
</div>
<template #footer>
<el-button type="danger" @click="cancelExport">取消导出</el-button>
</template>
</el-dialog>
<el-row>
<el-col>
<el-card style="margin-bottom: 20px">
<el-row style="margin-bottom: 10px">
<el-col :span="6">
<div class="head-card-element">
<el-text class="mx-1" size="large">精网号</el-text>
<el-input
v-model="detailY.jwcode"
style="width: 240px"
placeholder="请输入精网号"
clearable
/>
</div>
</el-col>
<el-col :span="6">
<div class="head-card-element">
<el-text class="mx-1" size="large">平台信息</el-text>
<el-select
v-model="detailY.consumePlatform"
placeholder="请选择平台信息"
style="width: 200px"
clearable
>
<el-option
v-for="item in platform"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</el-col>
<el-col :span="6">
<div class="head-card-element">
<el-text class="mx-1" size="large">数量更新类型</el-text>
<el-select
v-model="detailY.num"
placeholder="请选择更新类型"
style="width: 200px"
clearable
>
<el-option
v-for="item in num"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</el-col>
<el-col :span="6">
<div class="head-card-element">
<el-text class="mx-1" size="large">所属地区</el-text>
<el-select
v-model="detailY.area"
placeholder="请选择所属地区"
style="width: 240px"
clearable
:loading="isLoadingArea"
>
<el-option
v-for="item in area"
:key="item.value || item"
:label="item.label || item"
:value="item.value || item"
/>
</el-select>
</div>
</el-col>
</el-row>
<div class="head-card-element">
<el-text class="mx-1" size="large">更新时间</el-text>
<el-date-picker
v-model="getTime"
type="datetimerange"
range-separator="至"
start-placeholder="起始时间"
end-placeholder="结束时间"
style="margin-right: 50px"
/>
<el-button @click="getToday()"></el-button>
<el-button @click="getYesterday()"></el-button>
<el-button @click="get7Days()">近7天</el-button>
<el-button type="success" @click="exportExcel">导出Excel表格</el-button>
<el-button type="success" @click="reset()">重置</el-button>
<el-button type="primary" @click="search()">查询</el-button>
</div>
</el-card>
</el-col>
</el-row>
<el-row>
<el-col>
<el-card>
<div style="height: 584px; overflow-y: auto">
<el-table
:data="tableData"
style="width: 100%"
@sort-change="handleSortChange"
height="584px"
>
<el-table-column
type="index"
label="序号"
width="100px"
fixed="left"
>
<template #default="scope">
<span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template>
</el-table-column>
<el-table-column
fixed="left"
prop="username"
label="姓名"
width="150"
/>
<el-table-column
fixed="left"
prop="jwcode"
label="精网号"
width="120"
/>
<el-table-column prop="area" label="所属地区" width="120" />
<el-table-column
prop="consumePlatform"
label="平台信息"
width="140"
>
<template #default="scope">
<!-- 使用非严格相等比较 -->
<span v-if="scope.row.consumePlatform == 0">初始化金币</span>
<span v-if="scope.row.consumePlatform == 1">ERP系统</span>
<span v-if="scope.row.consumePlatform == 3">Homily Link</span>
<span v-if="scope.row.consumePlatform == 2">Homily Chart</span>
<span v-if="scope.row.consumePlatform == 4">金币系统</span>
</template>
</el-table-column>
<el-table-column
prop="gold"
label="更新数量"
width="120"
sortable="custom"
>
<template #default="scope">
<span>{{ scope.row.gold / 100 }}</span>
</template>
</el-table-column>
<el-table-column prop="updateType" label="更新类型" width="110">
<!-- 模板内容 -->
<template #default="scope">
<span v-if="scope.row.updateType == 1">消费</span>
<span v-if="scope.row.updateType == 0">充值</span>
<span v-if="scope.row.updateType == 2">退款</span>
<span v-if="scope.row.updateType == 3">其他</span>
</template>
</el-table-column>
<el-table-column
prop="rechargeCoin"
sortable="custom"
label="永久金币"
width="110"
>
<template #default="scope">
<span>{{ scope.row.rechargeCoin / 100 }}</span>
</template>
</el-table-column>
<el-table-column
prop="freeCoin"
sortable="custom"
label="免费金币"
width="110"
>
<template #default="scope">
<span>{{ scope.row.freeCoin / 100 }}</span>
</template>
</el-table-column>
<el-table-column
prop="taskCoin"
sortable="custom"
label="任务金币"
width="110"
>
<template #default="scope">
<span>{{ scope.row.taskCoin / 100 }}</span>
</template>
</el-table-column>
<el-table-column prop="name" label="提交人" width="110" />
<el-table-column
prop="createTime"
sortable="custom"
label="更新时间"
width="210"
show-overflow-tooltip
>
<template #default="scope">
<span>{{
moment(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss')
}}</span>
</template>
</el-table-column>
</el-table>
</div>
<!-- 此处分页 -->
<div class="pagination" style="margin-top: 20px">
<el-pagination
background
:page-size="getObj.pageSize"
:page-sizes="[5, 10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handlePageSizeChange"
@current-change="handleCurrentChange"
></el-pagination>
</div>
</el-card>
</el-col>
</el-row>
</template>
<style scoped>
.pagination {
display: flex;
}
.status {
display: flex;
}
.head-card {
display: flex;
}
.info-panel-header {
font-weight: bold;
margin-bottom: 10px;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
}
.export-status {
margin-top: 15px;
text-align: center;
color: #666;
}
.el-progress-bar__inner {
transition: width 0.5s ease;
}
</style>

500
src/views/usergoldInfo/index.vue

@ -0,0 +1,500 @@
<script setup>
//
import { ref, onMounted, reactive, computed } from 'vue'
import ElementPlus from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
import axios from 'axios'
import moment from 'moment'
import { ta } from 'element-plus/es/locales.mjs'
import API from '@/util/http'
//
//
const adminData = ref({})
const dialogVisible = ref(false)
const getAdminData = async function () {
try {
const result = await API({ url: '/admin/userinfo', data: {} })
adminData.value = result
console.log('请求成功', result)
console.log('用户信息', adminData.value)
} catch (error) {
console.log('请求失败', error)
}
}
//
const tableData = ref([])
//
const tableAllData = ref([])
//
const rechargeCoin = ref(0)
const freeCoin = ref(0)
const taskCoin = ref(0)
//
const tableCountData = ref([])
const userInfo = ref({})
// ===========================================
//
const total = ref(100)
//
const getTime = ref([])
// detailY
const detailY = ref({})
//
const getAllObj = ref({})
//
const getObj = ref({
pageNum: 1,
pageSize: 50
})
//
const sortField = ref('')
const sortOrder = ref('')
//
const updateType = [
{
value: '0',
label: '充值'
},
{
value: '1',
label: '消费'
},
{
value: '2',
label: '退款'
}
]
// //
// const tableHeight = computed(function () {
// return (getObj.value.pageSize + 2) * 38 + "px";
// });
//
// ===========================================================================
//
const get = async function (val) {
try {
//
if (adminData.value.area === '泰国') {
detailY.value.areas = ['泰国', '越南']
} else if (adminData.value.area !== '总部') {
detailY.value.area = adminData.value.area
}
//
if (typeof val === 'number') {
getObj.value.pageNum = val
}
//
if (getTime.value != null) {
if (getTime.value[0] != '' && getTime.value[1] != '') {
detailY.value.startDate = getTime.value[0]
detailY.value.endDate = getTime.value[1]
}
} else {
detailY.value.startDate = ''
detailY.value.endDate = ''
}
//
detailY.value.sortField = sortField.value
detailY.value.sortOrder = sortOrder.value
console.log('搜索参数', getObj.value)
// POST
const result = await API({
url: '/detailY/select',
data: { ...getObj.value, detailYgold: { ...detailY.value } }
})
//
const result2 = await API({
url: '/detailY',
data: {
...getAllObj.value,
detailY: { ...detailY.value }
}
})
// result.data.list
if (result.data.list.length === 0) {
//
tableData.value = []
// 0
rechargeCoin.value = 0
freeCoin.value = 0
taskCoin.value = 0
// null
tableAllData.value = null
// 0
total.value = 0
// ElMessage.warning('')
} else {
//
console.log('请求成功', result)
//
tableData.value = result.data.list
console.log('tableData', tableData.value)
tableAllData.value = result2.data
// 100
rechargeCoin.value = parseFloat((tableAllData.value.sumR / 100).toFixed(2))
freeCoin.value = parseFloat((tableAllData.value.sumF / 100).toFixed(2))
taskCoin.value = parseFloat((tableAllData.value.sumT / 100).toFixed(2))
//
total.value = result.data.total
console.log('total', total.value)
}
} catch (error) {
console.log('请求失败', error)
//
}
}
// detailY putExcel jwcode
const trimJwCode = () => {
if (detailY.value.jwcode) {
detailY.value.jwcode = detailY.value.jwcode.replace(/\s/g, '');
}
}
//
const search = function () {
trimJwCode();
getObj.value.pageNum = 1
get()
}
//
const reset = function () {
detailY.value = {}
sortField.value = ''
sortOrder.value = ''
get()
}
const cellClick = function (row, column) {
console.log('cellClick', column.label)
if (column.label == '姓名') {
dialogVisible.value = true
userInfo.value = row
}
}
//
const checkNumber = function () {
if (typeof parseInt(getObj.value.pageNum) === 'number') {
console.log('总共有多少页' + Math.ceil(total.value / getObj.value.pageSize))
if (
getObj.value.pageNum > 0 &&
getObj.value.pageNum <= Math.ceil(total.value / getObj.value.pageSize)
) {
getObj.value.pageNum = parseInt(getObj.value.pageNum)
console.log('输入的数字合法')
get()
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
} else {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
})
}
}
//
const handleSortChange = (column) => {
console.log('排序字段:', column.prop)
console.log('排序方式:', column.order)
if (column.prop === 'buyJb') {
sortField.value = 'buy_jb'
} else if (column.prop === 'coreJb') {
sortField.value = 'core_jb'
} else if (column.prop === 'free6') {
sortField.value = 'free_6'
} else if (column.prop === 'free12') {
sortField.value = 'free_12'
}
sortOrder.value = column.order === 'ascending' ? 'ASC' : 'DESC'
get()
}
//
const area = [
{
value: '马来西亚',
label: '马来西亚'
},
{
value: '新加坡',
label: '新加坡'
},
{
value: '香港',
label: '香港'
},
{
value: '泰国',
label: '泰国'
},
{
value: '加拿大',
label: '加拿大'
},
{
value: '越南HCM',
label: '越南HCM'
}
]
//
onMounted(async function () {
await getAdminData()
await get()
})
const handlePageSizeChange = function (val) {
getObj.value.pageSize = val
get()
}
const handleCurrentChange = function (val) {
getObj.value.pageNum = val
get()
}
</script>
<template>
<el-row>
<el-col>
<el-card style="margin-bottom: 20px">
<div class="head-card">
<div class="head-card-element">
<el-text class="mx-1" size="large">精网号</el-text>
<el-input
v-model="detailY.jwcode"
style="width: 240px"
placeholder="请输入精网号"
clearable
/>
</div>
<div
class="head-card-element"
style="margin-left: 50px"
v-if="adminData.area == '总部'"
>
<el-text class="mx-1" size="large">所属地区</el-text>
<el-select
v-model="detailY.area"
placeholder="请选择所属地区"
style="width: 240px"
clearable
>
<el-option
v-for="item in area"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
<div class="head-card-btn">
<el-button type="success" @click="reset()">重置</el-button>
<el-button type="primary" @click="search()">查询</el-button>
</div>
</div>
</el-card>
</el-col>
</el-row>
<el-row>
<el-col>
<el-card>
<div>
现有金币永久金币{{ Math.abs(rechargeCoin) }}免费金币{{
Math.abs(freeCoin)
}}任务金币{{ Math.abs(taskCoin) }}
</div>
<!-- 设置表格容器的高度和滚动样式 -->
<div style="height: 626px; overflow-y: auto">
<el-table
:data="tableData"
@cellClick="cellClick"
style="width: 100%"
height="715px"
@sort-change="handleSortChange"
>
<el-table-column
type="index"
label="序号"
width="100px"
fixed="left"
>
<template #default="scope">
<span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template>
</el-table-column>
<el-table-column prop="name" label="姓名" width="200" />
<el-table-column prop="jwcode" label="精网号" width="120" />
<el-table-column prop="area" label="所属地区" width="120" />
<el-table-column
prop="allJb"
label="总金币"
width="120"
aligh="center"
>
<template #default="scope">
<span>{{
(scope.row.free12 +
scope.row.free6 +
scope.row.coreJb +
scope.row.buyJb) /
100
}}</span>
</template>
</el-table-column>
<el-table-column
prop="buyJb"
label="永久金币"
sortable="custom"
width="110"
>
<template #default="scope">
<span>{{ Math.abs(scope.row.buyJb) / 100 }}</span>
</template>
</el-table-column>
<el-table-column prop="freeJb" label="免费金币" width="110">
<template #default="scope">
<span>{{
Math.abs(scope.row.free6 + scope.row.free12) / 100
}}</span>
</template>
</el-table-column>
<el-table-column
prop="free6"
label=" 6月份到期免费金币"
sortable="custom"
width="110"
>
<template #default="scope">
<span>{{ scope.row.free6 / 100 }}</span>
</template>
</el-table-column>
<el-table-column
prop="free12"
label="12月份到期免费金币"
sortable="custom"
width="110"
>
<template #default="scope">
<span>{{ scope.row.free12 / 100 }}</span>
</template>
</el-table-column>
<el-table-column
prop="coreJb"
label="任务金币"
sortable="custom"
width="130"
>
<template #default="scope">
<span>{{ Math.abs(scope.row.coreJb) / 100 }}</span>
</template>
</el-table-column>
<el-table-column prop="rcoin" label="历史充值" width="150">
<template #default="scope">
<span>{{ scope.row.rcoin / 100 }}</span>
</template>
</el-table-column>
<el-table-column prop="scoin" label="历史消费" width="150">
<template #default="scope">
<span>{{ Math.abs(scope.row.scoin) / 100 }}</span>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页 -->
<!-- 分页 -->
<div class="pagination" style="margin-top: 20px">
<el-pagination
background
:page-size="getObj.pageSize"
:page-sizes="[5, 10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handlePageSizeChange"
@current-change="handleCurrentChange"
></el-pagination>
</div>
</el-card>
</el-col>
</el-row>
<!-- 客户信息弹框 -->
<el-dialog
title="客户信息"
v-model="dialogVisible"
width="50%"
@before-close="dialogVisible = false"
>
<el-card>
<div class="custom-box">
<div>姓名{{ userInfo.name }}</div>
<br />
<div>精网号{{ userInfo.jwcode }}</div>
<div>地区{{ userInfo.area }}</div>
<div>历史充值{{ userInfo.rcoin }}</div>
<div>历史消费{{ userInfo.scoin }}</div>
</div>
</el-card>
<!-- t -->
<div style="height: 450px; overflow-y: auto">
<el-table :data="tableCountData" style="width: 100%" height="715px">
<el-table-column type="index" label="序号" width="100px" fixed="left">
<template #default="scope">
<span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template>
</el-table-column>
<el-table-column prop="" label="商品" width="120" />
<el-table-column sortable prop="" label="消费金币总数" width="180" />
<el-table-column sortable prop="" label="永久金币" width="120" />
<el-table-column sortable prop="" label="免费金币" width="120" />
<el-table-column sortable prop="" label="任务金币" width="120" />
<el-table-column sortable prop="" label="时间" width="120" />
</el-table>
</div>
</el-dialog>
</template>
<style scoped lang="scss">
.pagination {
display: flex;
}
.status {
display: flex;
}
.head-card {
display: flex;
}
.head-card-element {
margin-right: 20px;
}
.head-card-btn {
margin-left: auto;
}
.custom-box {
display: flex;
flex-wrap: wrap;
row-gap: 5px;
div:nth-child(1) {
flex: 1 0 100%;
}
div {
margin-right: 20px;
}
}
</style>

1668
src/views/workspace/index.vue
File diff suppressed because it is too large
View File

140
src/views/z.vue

@ -0,0 +1,140 @@
<script setup>
import { ref, onMounted, reactive, computed, nextTick } from 'vue'
//
const allData = ref([])
const tableData = ref([])
const elTableHeight = ref('')
const theadHeight = ref('')
const contentHeight = ref(0)
const showRowCount = ref(0)
const falseBox = ref(null)
const scollBoxHeight = ref(0)
const scrollTopRowCount = ref(0)
//
onMounted(async function () {
allData.value = []
for (let i = 0; i < 10000; i++) {
allData.value.push({
name: '张三' + i,
age: 20 + i,
address: '北京市海淀区' + i,
salary: 50000 + i,
date: '2022-01-01'
})
}
scollBoxHeight.value = 45 * allData.value.length + 45 //
nextTick(() => {
elTableHeight.value = document.querySelector(
'.table-box .el-table'
).offsetHeight
theadHeight.value = document.querySelector(
'.table-box .el-table__header-wrapper'
).offsetHeight
console.log('elTableHeight', elTableHeight.value)
console.log('theadHeight', theadHeight.value)
contentHeight.value = elTableHeight.value - theadHeight.value
console.log('contentHeight', contentHeight.value)
showRowCount.value = Math.floor(contentHeight.value / 45)
console.log('showRowCount', showRowCount.value)
// <showRowCount>
tableData.value = JSON.parse(JSON.stringify(allData.value)).splice(
0,
showRowCount.value
)
})
falseBox.value = document.querySelector('.false-box')
falseBox.value.addEventListener('scroll', function (e) {
scrollTopRowCount.value = Math.ceil(e.target.scrollTop / 45)
// <scrollTopRowCount> <showRowCount>
tableData.value = JSON.parse(JSON.stringify(allData.value)).splice(
scrollTopRowCount.value,
showRowCount.value
)
})
})
</script>
<template>
<div
class="box"
style="width: 1000px; height: 500px; overflow: hidden; position: relative"
>
<!-- false-box这是一个用来显示滚动条的方法 -->
<div
class="false-box"
style="
width: 100%;
height: 100%;
position: absolute;
top: 0%;
left: 0%;
overflow: auto;
"
>
<div class="scroll-box" :style="{ height: scollBoxHeight + 'px' }">
<!-- scroll-box是用来撑起盒子的方法 -->
</div>
</div>
<div class="table-box">
<el-table class="el-table" :data="allData" style="width: 100%">
<el-table-column prop="name" label="姓名" width="180">
</el-table-column>
<el-table-column prop="age" label="年龄" width="180"> </el-table-column>
<el-table-column prop="address" label="地址"> </el-table-column>
<el-table-column prop="salary" label="薪资" width="180">
</el-table-column>
<el-table-column prop="date" label="日期" width="180">
</el-table-column>
</el-table>
</div>
</div>
</template>
<style scoped>
.box {
width: 1000px;
height: 500px;
overflow: hidden;
position: relative;
}
.false-box {
width: 100%;
height: 100%;
position: absolute;
top: 0%;
left: 0%;
overflow: auto;
}
.scroll-box {
width: 100%;
height: 1000px;
position: absolute;
top: 0%;
left: 0%;
}
.table-box {
width: calc(100% - 20px);
height: 100%;
position: absolute;
top: 0%;
left: 0%;
}
:deep(.el-table) {
width: 100%;
height: 100%;
}
.el-table .el-table__row {
height: 45px;
}
.el-table .el-table__row td {
padding: 0px;
}
</style>

1
src/vite-env.d.ts

@ -0,0 +1 @@
/// <reference types="vite/client" />

4949
stats.html
File diff suppressed because it is too large
View File

41
tsconfig.app.json

@ -0,0 +1,41 @@
{
"compilerOptions": {
"strict": true,
"skipLibCheck": true,
"composite": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2020",
"noEmitOnError": false,
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
/* Bundler mode */
"moduleResolution": "Bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"emitDeclarationOnly": false,
"jsx": "preserve",
/* Linting */
// "strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true,
"noImplicitAny": false,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.d.ts",
"src/**/*.vue",
"src/util/http.js"
]
}

7
tsconfig.json

@ -0,0 +1,7 @@
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}

28
tsconfig.node.json

@ -0,0 +1,28 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2022",
"lib": ["ES2023"],
"module": "ESNext",
"skipLibCheck": true,
"composite": true,
"noEmitOnError": false,
/* Bundler mode */
"moduleResolution": "Bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"emitDeclarationOnly": false,
/* Linting */
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
}

1
tsconfig.tsbuildinfo

@ -0,0 +1 @@
{"root":["./src/main.ts","./src/vite-env.d.ts","./src/app.vue","./src/views/index.vue","./src/views/login.vue","./src/views/nopermissionpage.vue","./src/views/z.vue","./src/views/audit/rechargeaudit.vue","./src/views/audit/refundaudit.vue","./src/views/consume/addconsume.vue","./src/views/consume/allconsume.vue","./src/views/goldbeen/addgoldenbeen.vue","./src/views/goldbeen/goldenbeenbalance.vue","./src/views/goldbeen/goldenbeendetail.vue","./src/views/managerecharge/activity.vue","./src/views/managerecharge/rate.vue","./src/views/permissions/index.vue","./src/views/recharge/addrecharge.vue","./src/views/recharge/adminrecharge.vue","./src/views/recharge/allrecharge.vue","./src/views/refund/addrefund.vue","./src/views/refund/allrefund.vue","./src/views/usergold/index.vue","./src/views/usergoldinfo/index.vue","./src/views/workspace/index.vue"],"errors":true,"version":"5.6.3"}

70
vite.config.ts

@ -0,0 +1,70 @@
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import { lazyImport, VxeResolver } from 'vite-plugin-lazy-import'
import legacy from '@vitejs/plugin-legacy'
import path from 'path'
import { visualizer } from 'rollup-plugin-visualizer'
// https://vite.dev/config/
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd())
console.log('当前环境:', mode)
console.log('当前环境变量:', env)
return {
esbuild: {
supported: {
bigint: true
},
treeShaking: true
},
plugins: [
vue(),
visualizer({
open: true, // 打包完成后自动展示
gzipSize: true, // 显示gzip压缩后的大小
brotliSize: true // 显示brotli压缩后的大小
}),
legacy({
targets: ['defaults', 'not IE 11', 'chrome >=73'],
modernPolyfills: true
}),
lazyImport({
resolvers: [
VxeResolver({
libraryName: 'vxe-table'
}),
VxeResolver({
libraryName: 'vxe-pc-ui'
})
]
})
],
resolve: {
alias: {
'@': path.resolve(__dirname, './src')
}
},
base: process.env.NODE_ENV === 'production' ? './' : '/',
build: {
sourcemap: false, // 关闭 sourcemap
minify: 'terser',
terserOptions: {
compress: {
drop_console: true, // 生产环境去除console
drop_debugger: true // 生产环境去除 debugger
}
},
rollupOptions: {
output: {
manualChunks: {
echarts: ['echarts'],
xlsx: ['xlsx'],
lodash: ['lodash'],
vue: ['vue', 'vue-router', 'pinia'],
elementPlus: ['element-plus']
}
}
}
}
}
})
Loading…
Cancel
Save