commit
3feabaf337
73 changed files with 27237 additions and 0 deletions
-
5.env.development
-
5.env.production
-
6.env.test
-
24.gitignore
-
8.vite/deps/_metadata.json
-
3.vite/deps/package.json
-
3.vscode/extensions.json
-
38README.md
-
22index.html
-
5065package-lock.json
-
46package.json
-
BINpublic/favicon.ico
-
9src/App.vue
-
13src/api/index.js
-
BINsrc/assets/avator.png
-
BINsrc/assets/background.jpg
-
86src/assets/base.css
-
72src/assets/css/common.css
-
1src/assets/logo.svg
-
35src/assets/main.css
-
1src/assets/vue.svg
-
BINsrc/assets/动漫美女.png
-
BINsrc/assets/金币管理系统logo.png
-
BINsrc/assets/韩信.png
-
41src/components/HelloWorld.vue
-
94src/components/TheWelcome.vue
-
87src/components/WelcomeItem.vue
-
7src/components/icons/IconCommunity.vue
-
7src/components/icons/IconDocumentation.vue
-
7src/components/icons/IconEcosystem.vue
-
7src/components/icons/IconSupport.vue
-
19src/components/icons/IconTooling.vue
-
34src/main.ts
-
101src/router/index.js
-
23src/router/index.ts
-
12src/store/area.js
-
12src/stores/counter.ts
-
79src/style.css
-
26src/util/http.js
-
46src/util/request.js
-
15src/views/AboutView.vue
-
9src/views/HomeView.vue
-
855src/views/audit/rechargeAudit.vue
-
889src/views/audit/refundAudit.vue
-
690src/views/consume/addConsume.vue
-
587src/views/consume/allConsume.vue
-
217src/views/goldBeen/addGoldenBeen.vue
-
253src/views/goldBeen/goldenBeenBalance.vue
-
581src/views/goldBeen/goldenBeenConsum.vue
-
794src/views/goldBeen/goldenBeenDetail.vue
-
582src/views/goldBeen/onLineDetail.vue
-
378src/views/index.vue
-
243src/views/login.vue
-
494src/views/managerecharge/activity.vue
-
849src/views/managerecharge/rate.vue
-
24src/views/noPermissionPage.vue
-
910src/views/permissions/index.vue
-
1555src/views/recharge/addRecharge.vue
-
796src/views/recharge/adminRecharge.vue
-
964src/views/recharge/allRecharge.vue
-
571src/views/refund/addRefund.vue
-
734src/views/refund/allRefund.vue
-
798src/views/usergold/index.vue
-
500src/views/usergoldInfo/index.vue
-
1668src/views/workspace/index.vue
-
140src/views/z.vue
-
1src/vite-env.d.ts
-
4949stats.html
-
41tsconfig.app.json
-
7tsconfig.json
-
28tsconfig.node.json
-
1tsconfig.tsbuildinfo
-
70vite.config.ts
@ -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/' |
@ -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/' |
|||
|
@ -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/' |
|||
|
@ -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? |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"hash": "e40e7e03", |
|||
"configHash": "30419548", |
|||
"lockfileHash": "3e0e6deb", |
|||
"browserHash": "f66225ae", |
|||
"optimized": {}, |
|||
"chunks": {} |
|||
} |
@ -0,0 +1,3 @@ |
|||
{ |
|||
"type": "module" |
|||
} |
@ -0,0 +1,3 @@ |
|||
{ |
|||
"recommendations": ["Vue.volar"] |
|||
} |
@ -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 组件,模拟服务器运行 |
@ -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
File diff suppressed because it is too large
View File
@ -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" |
|||
} |
|||
} |
@ -0,0 +1,9 @@ |
|||
<script setup> |
|||
</script> |
|||
|
|||
<template> |
|||
<router-view></router-view> |
|||
</template> |
|||
|
|||
<style scoped> |
|||
</style> |
@ -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; |
After Width: 250 | Height: 252 | Size: 90 KiB |
After Width: 928 | Height: 1133 | Size: 567 KiB |
@ -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; |
|||
} |
@ -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; |
|||
} |
@ -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> |
@ -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; |
|||
} |
|||
} |
@ -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> |
After Width: 263 | Height: 181 | Size: 95 KiB |
After Width: 47 | Height: 47 | Size: 2.0 KiB |
After Width: 256 | Height: 180 | Size: 96 KiB |
@ -0,0 +1,41 @@ |
|||
<script setup lang="ts"> |
|||
defineProps<{ |
|||
msg: string |
|||
}>() |
|||
</script> |
|||
|
|||
<template> |
|||
<div class="greetings"> |
|||
<h1 class="green">{{ msg }}</h1> |
|||
<h3> |
|||
You’ve 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> |
@ -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> |
|||
|
|||
Vue’s |
|||
<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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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) |
@ -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; |
@ -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 |
@ -0,0 +1,12 @@ |
|||
import { defineStore } from 'pinia' |
|||
// 这个也是不知道有啥用,谁给在index.vue里注了
|
|||
export const useAreaStore = defineStore('area', { |
|||
state: () => ({ |
|||
currentArea: '全部', |
|||
}), |
|||
actions: { |
|||
updateArea(newVal) { |
|||
this.currentArea = newVal |
|||
}, |
|||
}, |
|||
}) |
@ -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 } |
|||
}) |
@ -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; |
|||
} |
|||
} |
@ -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) |
|||
}) |
|||
} |
@ -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 |
@ -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> |
@ -0,0 +1,9 @@ |
|||
<script setup lang="ts"> |
|||
import TheWelcome from '../components/TheWelcome.vue' |
|||
</script> |
|||
|
|||
<template> |
|||
<main> |
|||
<TheWelcome /> |
|||
</main> |
|||
</template> |
@ -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> |
@ -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> |
@ -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; |
|||
|
|||
// 确保todayTask和todayFree是有效的数字 |
|||
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, rechargeCoin不是NaN,如果是,则设置为0 |
|||
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> |
@ -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> |
@ -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, //0是加1是减 |
|||
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> |
@ -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> |
|||
现有金豆: 付费金豆:{{ getObj.jinbiBuy }} 免费金豆:{{ |
|||
getObj.jinbiFree |
|||
}} 历史消费:{{ 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', |
|||
// 传递jwcode和ipAddress参数,可以让金币数随查询变化 |
|||
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> |
@ -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> |
@ -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> |
@ -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 |
@ -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> |
@ -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> |
|||
--> |
@ -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> |
@ -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> |
@ -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> |
@ -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
File diff suppressed because it is too large
View File
@ -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> |
@ -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> |
@ -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> |
@ -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.name默认为all |
|||
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> |
@ -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' |
|||
//get()要写在handleSortChange方法里面,不然会导致排序失效 |
|||
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> |
@ -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
File diff suppressed because it is too large
View File
@ -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> |
@ -0,0 +1 @@ |
|||
/// <reference types="vite/client" />
|
4949
stats.html
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -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" |
|||
] |
|||
} |
@ -0,0 +1,7 @@ |
|||
{ |
|||
"files": [], |
|||
"references": [ |
|||
{ "path": "./tsconfig.app.json" }, |
|||
{ "path": "./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/*"] |
|||
} |
|||
} |
|||
} |
@ -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"} |
@ -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'] |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
}) |
Write
Preview
Loading…
Cancel
Save
Reference in new issue