Compare commits
51 Commits
cb2e68cede
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| b25640036b | |||
| 776506d46f | |||
| f8df513e10 | |||
| afbc4bac90 | |||
| 77bfbf1982 | |||
| c3547feebd | |||
| 038f67ec2a | |||
| d754bd45c9 | |||
| 0ff7154101 | |||
| e0632136d7 | |||
| 16ab65df50 | |||
| edcbd2b964 | |||
| 82211679f9 | |||
| 7d379fa03c | |||
| ef0ca7ff27 | |||
| 50d10c1d53 | |||
| 9fa1a81b8a | |||
| a4c2674fbe | |||
| 1c95c1097c | |||
| 99c0541e4f | |||
| 825a4ae3ea | |||
| 2e3a445eb5 | |||
| cadb47cd22 | |||
| 1bcd417c57 | |||
| 698ecb5429 | |||
| be1bf99fc3 | |||
| 3d8f72de35 | |||
| f78140d8dd | |||
| 2f7b80f418 | |||
| c157d6024e | |||
| 587b11e1ec | |||
| ca4ec000f6 | |||
| c233ad8f5a | |||
| 0865529e10 | |||
| 3e47ee08af | |||
| 1be0710a82 | |||
| f191298dea | |||
| e5334f8977 | |||
| 04f0f65e94 | |||
| 84afb82cca | |||
| d1b8a8fc61 | |||
| 52ef8900ff | |||
| eb3c104259 | |||
| 93bda1fa29 | |||
| 1c729f1e35 | |||
| 66c4c607bc | |||
| 77f6c498a6 | |||
| e05af0b396 | |||
| 59f53fbc37 | |||
| da59528747 | |||
| 84a2881757 |
@@ -8,7 +8,12 @@ VITE_USE_MOCK=false
|
||||
VITE_USE_PROXY=true
|
||||
|
||||
# base api
|
||||
VITE_BASE_API='https://test.wanzhuanyongcheng.cn/admin'
|
||||
VITE_BASE_API='/api'
|
||||
|
||||
VITE_BASE_API_1='/api1'
|
||||
# VITE_BASE_API='https://test.wanzhuanyongcheng.cn/admin'
|
||||
|
||||
# VITE_BASE_API_1='https://api.gxwzwh.com/admin'
|
||||
|
||||
VITE_WS1_URL='game.wanzhuanyongcheng.cn/dice/home'
|
||||
|
||||
@@ -21,6 +26,3 @@ VITE_GAME_API='https://www.jdt168.com'
|
||||
# 转盘相关
|
||||
VITE_TRUN_WS_URL='test.wanzhuanyongcheng.cn/admin/turntable'
|
||||
VITE_TRUN_WS1_URL='game2.wanzhuanyongcheng.cn/turntable/home'
|
||||
|
||||
# 是否启用监控
|
||||
VITE_SENTRY=false
|
||||
|
||||
@@ -6,6 +6,7 @@ VITE_USE_MOCK=false
|
||||
|
||||
# base api
|
||||
VITE_BASE_API='//www.wanzhuanyongcheng.cn/admin'
|
||||
VITE_BASE_API_1='//api.gxwzwh.com/admin'
|
||||
|
||||
# 是否启用压缩
|
||||
VITE_USE_COMPRESS=true
|
||||
@@ -20,5 +21,6 @@ VITE_WS_URL='www.wanzhuanyongcheng.cn/admin/data'
|
||||
|
||||
VITE_MER_LOGIN_URL='//jdt-prod-mer.wanzhuanyongcheng.cn/login'
|
||||
|
||||
# 是否启用监控
|
||||
VITE_SENTRY=true
|
||||
# 转盘相关
|
||||
VITE_TRUN_WS_URL='www.wanzhuanyongcheng.cn/admin/turntable'
|
||||
VITE_TRUN_WS1_URL='turntable.jdt168.com/turntable/home'
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
# DO NOT commit this file to your repository!
|
||||
# The SENTRY_AUTH_TOKEN variable is picked up by the Sentry Build Plugin.
|
||||
# It's used for authentication when uploading source maps.
|
||||
# You can also set this env variable in your own `.env` files and remove this file.
|
||||
SENTRY_AUTH_TOKEN="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"
|
||||
@@ -24,5 +24,6 @@ VITE_GAME_API='https://game.wanzhuanyongcheng.cn'
|
||||
|
||||
VITE_MER_LOGIN_URL='//jdt-test-mer.wanzhuanyongcheng.cn/login'
|
||||
|
||||
# 是否启用监控
|
||||
VITE_SENTRY=false
|
||||
# 转盘相关
|
||||
VITE_TRUN_WS_URL='test.wanzhuanyongcheng.cn/admin/turntable'
|
||||
VITE_TRUN_WS1_URL='game2.wanzhuanyongcheng.cn/turntable/home'
|
||||
|
||||
162
.gitea/workflows/ci.yaml
Normal file
162
.gitea/workflows/ci.yaml
Normal file
@@ -0,0 +1,162 @@
|
||||
name: CI Build & Deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- test
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build-and-deploy-dev:
|
||||
if: gitea.ref_name == 'test'
|
||||
runs-on: gitea_act_runner
|
||||
container:
|
||||
image: node:24-alpine
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v3
|
||||
with:
|
||||
version: 8
|
||||
|
||||
- name: Install deps
|
||||
run: |
|
||||
npm config set registry https://registry.npmmirror.com/
|
||||
pnpm install
|
||||
|
||||
- name: Build (test)
|
||||
run: pnpm build:test
|
||||
|
||||
- name: Pack artifacts
|
||||
run: |
|
||||
rm -rf dist.tar
|
||||
tar -zcvf dist.tar ./dist ./default.conf ./Dockerfile
|
||||
|
||||
- name: Upload artifacts to server
|
||||
uses: appleboy/scp-action@v0.1.7
|
||||
with:
|
||||
host: ${{ secrets.HOST_DEV }}
|
||||
username: ${{ secrets.USER_DEV }}
|
||||
password: ${{ secrets.PWD_DEV }}
|
||||
port: 22
|
||||
source: 'dist.tar'
|
||||
target: '/www/builder'
|
||||
strip_components: 0
|
||||
|
||||
- name: Deploy over SSH
|
||||
uses: appleboy/ssh-action@v1.0.3
|
||||
with:
|
||||
host: ${{ secrets.HOST_DEV }}
|
||||
username: ${{ secrets.USER_DEV }}
|
||||
password: ${{ secrets.PWD_DEV }}
|
||||
port: 22
|
||||
script: |
|
||||
set -e
|
||||
cd /www/builder
|
||||
rm -rf jdt-admin-dev
|
||||
mkdir -p jdt-admin-dev
|
||||
tar -xzvf dist.tar -C /www/builder/jdt-admin-dev
|
||||
rm -rf dist.tar
|
||||
cd jdt-admin-dev
|
||||
docker build -t jdt-admin-dev .
|
||||
docker stop jdt-admin-dev || true
|
||||
docker rm jdt-admin-dev || true
|
||||
docker run -d -p 8085:80 --restart=always --name jdt-admin-dev jdt-admin-dev
|
||||
cd ..
|
||||
rm -rf jdt-admin-dev
|
||||
|
||||
- name: Notify WeCom (Dev)
|
||||
if: always()
|
||||
env:
|
||||
WEBHOOK_KEY: ${{ secrets.QYWX_WEBHOOK_KEY }}
|
||||
STATUS: ${{ job.status }}
|
||||
REPO: ${{ gitea.repository }}
|
||||
RUN_URL: ${{ gitea.server_url }}/${{ gitea.repository }}/actions/runs/${{ gitea.run_id }}
|
||||
BRANCH: ${{ gitea.ref_name }}
|
||||
COMMIT: ${{ gitea.sha }}
|
||||
ACTOR: ${{ gitea.actor }}
|
||||
run: |
|
||||
sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories || true
|
||||
apk add --no-cache curl jq
|
||||
EMOJI=$( [ "$STATUS" = "success" ] && echo "✅" || echo "❌" )
|
||||
MSG="$(printf "%s**%s** (Run #%s)\n>**构建结果**: %s\n>**构建详情**: [点击查看](%s)\n>**代码分支**: %s\n>**提交标识**: %s\n>**提交发起**: %s\n" "$EMOJI" "$REPO" "${{ gitea.run_number }}" "$STATUS" "$RUN_URL" "$BRANCH" "$COMMIT" "$ACTOR")"
|
||||
curl -sS -H 'Content-Type: application/json' -d "{\"msgtype\":\"markdown\",\"markdown\":{\"content\":\"$MSG\"}}" "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${WEBHOOK_KEY}"
|
||||
|
||||
build-and-deploy-prod:
|
||||
if: gitea.ref_name == 'main'
|
||||
runs-on: gitea_act_runner
|
||||
container:
|
||||
image: node:24-alpine
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v3
|
||||
with:
|
||||
version: 8
|
||||
|
||||
- name: Install deps
|
||||
run: |
|
||||
npm config set registry https://registry.npmmirror.com/
|
||||
pnpm install
|
||||
|
||||
- name: Build (prod)
|
||||
run: pnpm build:prod
|
||||
|
||||
- name: Pack artifacts
|
||||
run: |
|
||||
rm -rf dist.tar
|
||||
tar -zcvf dist.tar ./dist ./default.conf ./Dockerfile
|
||||
|
||||
- name: Upload artifacts to server
|
||||
uses: appleboy/scp-action@v0.1.7
|
||||
with:
|
||||
host: ${{ secrets.HOST_PROD }}
|
||||
username: ${{ secrets.USER_PROD }}
|
||||
password: ${{ secrets.PWD_PROD }}
|
||||
port: 22
|
||||
source: 'dist.tar'
|
||||
target: '/www/builder'
|
||||
strip_components: 0
|
||||
|
||||
- name: Deploy over SSH
|
||||
uses: appleboy/ssh-action@v1.0.3
|
||||
with:
|
||||
host: ${{ secrets.HOST_PROD }}
|
||||
username: ${{ secrets.USER_PROD }}
|
||||
password: ${{ secrets.PWD_PROD }}
|
||||
port: 22
|
||||
script: |
|
||||
set -e
|
||||
cd /www/builder
|
||||
rm -rf jdt-admin-prod
|
||||
mkdir -p jdt-admin-prod
|
||||
tar -xzvf dist.tar -C /www/builder/jdt-admin-prod
|
||||
rm -rf dist.tar
|
||||
cd jdt-admin-prod
|
||||
docker build -t jdt-admin-prod .
|
||||
docker stop jdt-admin-prod || true
|
||||
docker rm jdt-admin-prod || true
|
||||
docker run -d -p 8085:80 --restart=always --name jdt-admin-prod jdt-admin-prod
|
||||
cd ..
|
||||
rm -rf jdt-admin-prod
|
||||
|
||||
- name: Notify WeCom (Prod)
|
||||
if: always()
|
||||
env:
|
||||
WEBHOOK_KEY: ${{ secrets.QYWX_WEBHOOK_KEY }}
|
||||
STATUS: ${{ job.status }}
|
||||
REPO: ${{ gitea.repository }}
|
||||
RUN_URL: ${{ gitea.server_url }}/${{ gitea.repository }}/actions/runs/${{ gitea.run_id }}
|
||||
BRANCH: ${{ gitea.ref_name }}
|
||||
COMMIT: ${{ gitea.sha }}
|
||||
ACTOR: ${{ gitea.actor }}
|
||||
run: |
|
||||
sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories || true
|
||||
apk add --no-cache curl jq
|
||||
EMOJI=$( [ "$STATUS" = "success" ] && echo "✅" || echo "❌" )
|
||||
MSG="$(printf "%s**%s** (Run #%s)\n>**构建结果**: %s\n>**构建详情**: [点击查看](%s)\n>**代码分支**: %s\n>**提交标识**: %s\n>**提交发起**: %s\n" "$EMOJI" "$REPO" "${{ gitea.run_number }}" "$STATUS" "$RUN_URL" "$BRANCH" "$COMMIT" "$ACTOR")"
|
||||
curl -sS -H 'Content-Type: application/json' -d "{\"msgtype\":\"markdown\",\"markdown\":{\"content\":\"$MSG\"}}" "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${WEBHOOK_KEY}"
|
||||
16
.idea/codeStyles/Project.xml
generated
16
.idea/codeStyles/Project.xml
generated
@@ -1,26 +1,19 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<option name="LINE_SEPARATOR" value=" " />
|
||||
<HTMLCodeStyleSettings>
|
||||
<option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
|
||||
<option name="HTML_QUOTE_STYLE" value="Single" />
|
||||
<option name="HTML_ENFORCE_QUOTES" value="true" />
|
||||
</HTMLCodeStyleSettings>
|
||||
<JSCodeStyleSettings version="0">
|
||||
<option name="USE_SEMICOLON_AFTER_STATEMENT" value="false" />
|
||||
<option name="FORCE_SEMICOLON_STYLE" value="true" />
|
||||
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
|
||||
<option name="USE_DOUBLE_QUOTES" value="false" />
|
||||
<option name="FORCE_QUOTE_STYlE" value="true" />
|
||||
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
|
||||
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
|
||||
<option name="SPACES_WITHIN_IMPORTS" value="true" />
|
||||
</JSCodeStyleSettings>
|
||||
<TypeScriptCodeStyleSettings version="0">
|
||||
<option name="USE_SEMICOLON_AFTER_STATEMENT" value="false" />
|
||||
<option name="FORCE_SEMICOLON_STYLE" value="true" />
|
||||
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
|
||||
<option name="USE_DOUBLE_QUOTES" value="false" />
|
||||
<option name="FORCE_QUOTE_STYlE" value="true" />
|
||||
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
|
||||
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
|
||||
@@ -31,16 +24,15 @@
|
||||
<option name="INTERPOLATION_NEW_LINE_BEFORE_END_DELIMITER" value="false" />
|
||||
</VueCodeStyleSettings>
|
||||
<codeStyleSettings language="HTML">
|
||||
<option name="SOFT_MARGINS" value="100" />
|
||||
<option name="SOFT_MARGINS" value="80" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
<option name="SMART_TABS" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="JavaScript">
|
||||
<option name="SOFT_MARGINS" value="100" />
|
||||
<option name="SOFT_MARGINS" value="80" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
@@ -48,7 +40,7 @@
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="TypeScript">
|
||||
<option name="SOFT_MARGINS" value="100" />
|
||||
<option name="SOFT_MARGINS" value="80" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
@@ -56,7 +48,7 @@
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="Vue">
|
||||
<option name="SOFT_MARGINS" value="100" />
|
||||
<option name="SOFT_MARGINS" value="80" />
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
|
||||
6
.idea/git_toolbox_blame.xml
generated
Normal file
6
.idea/git_toolbox_blame.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GitToolBoxBlameSettings">
|
||||
<option name="version" value="2" />
|
||||
</component>
|
||||
</project>
|
||||
15
.idea/git_toolbox_prj.xml
generated
15
.idea/git_toolbox_prj.xml
generated
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GitToolBoxProjectSettings">
|
||||
<option name="commitMessageIssueKeyValidationOverride">
|
||||
<BoolValueOverride>
|
||||
<option name="enabled" value="true" />
|
||||
</BoolValueOverride>
|
||||
</option>
|
||||
<option name="commitMessageValidationEnabledOverride">
|
||||
<BoolValueOverride>
|
||||
<option name="enabled" value="true" />
|
||||
</BoolValueOverride>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
0
.idea/admin.iml → .idea/jdt-admin.iml
generated
0
.idea/admin.iml → .idea/jdt-admin.iml
generated
6
.idea/jsLibraryMappings.xml
generated
6
.idea/jsLibraryMappings.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptLibraryMappings">
|
||||
<includedPredefinedLibrary name="Node.js Core" />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/jsLinters/eslint.xml
generated
6
.idea/jsLinters/eslint.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="EslintConfiguration">
|
||||
<option name="fix-on-save" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
2
.idea/modules.xml
generated
2
.idea/modules.xml
generated
@@ -2,7 +2,7 @@
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/admin.iml" filepath="$PROJECT_DIR$/.idea/admin.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/jdt-admin.iml" filepath="$PROJECT_DIR$/.idea/jdt-admin.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/prettier.xml
generated
6
.idea/prettier.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PrettierConfiguration">
|
||||
<option name="myConfigurationMode" value="AUTOMATIC" />
|
||||
</component>
|
||||
</project>
|
||||
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -25,7 +25,7 @@
|
||||
},
|
||||
"eslint.validate": ["javascript", "javascriptreact", "typescript", "vue"],
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
"source.fixAll.eslint": "explicit"
|
||||
},
|
||||
"files.associations": {
|
||||
"*.env.*": "dotenv",
|
||||
|
||||
BIN
build/.DS_Store
vendored
Normal file
BIN
build/.DS_Store
vendored
Normal file
Binary file not shown.
@@ -2,32 +2,23 @@ export const OUTPUT_DIR = 'dist'
|
||||
|
||||
export const PROXY_CONFIG = {
|
||||
/**
|
||||
* @desc 替换匹配值
|
||||
* @请求路径 http://localhost:3100/api/user
|
||||
* @转发路径 http://localhost:8080/user
|
||||
* @desc 主接口代理
|
||||
* @请求路径 http://localhost:3100/api/login
|
||||
* @转发路径 http://localhost:3000/api/login
|
||||
*/
|
||||
'/admin': {
|
||||
'/api': {
|
||||
target: 'https://test.wanzhuanyongcheng.cn',
|
||||
changeOrigin: true,
|
||||
// rewrite: (path) => path.replace(new RegExp('^/api'), ''),
|
||||
rewrite: (path) => path.replace(/^\/api/, '/admin'),
|
||||
},
|
||||
/**
|
||||
* @desc 不替换匹配值
|
||||
* @请求路径 http://localhost:3100/api/v2/user
|
||||
* @转发路径 http://localhost:8080/api/v2/user
|
||||
* @desc 备用接口代理
|
||||
* @请求路径 http://localhost:3100/api1/login
|
||||
* @转发路径 http://localhost:3001/api/login
|
||||
*/
|
||||
// '/api/v2': {
|
||||
// target: 'http://localhost:8080',
|
||||
// changeOrigin: true,
|
||||
// },
|
||||
/**
|
||||
* @desc 替换部分匹配值
|
||||
* @请求路径 http://localhost:3100/api/v3/user
|
||||
* @转发路径 http://localhost:8080/user
|
||||
*/
|
||||
// '/api/v3': {
|
||||
// target: 'http://localhost:8080',
|
||||
// changeOrigin: true,
|
||||
// rewrite: (path) => path.replace(new RegExp('^/api'), ''),
|
||||
// },
|
||||
'/api1': {
|
||||
target: 'https://api.gxwzwh.com',
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/api1/, '/admin'),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ import viteCompression from 'vite-plugin-compression'
|
||||
import { configHtmlPlugin } from './html'
|
||||
import { configMockPlugin } from './mock'
|
||||
import unplugin from './unplugin'
|
||||
import { sentryVitePlugin } from '@sentry/vite-plugin'
|
||||
|
||||
export function createVitePlugins(viteEnv, isBuild) {
|
||||
const plugins = [vue(), ...unplugin, configHtmlPlugin(viteEnv, isBuild), Unocss()]
|
||||
@@ -36,21 +35,5 @@ export function createVitePlugins(viteEnv, isBuild) {
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
if (viteEnv.VITE_SENTRY) {
|
||||
plugins.push(
|
||||
sentryVitePlugin({
|
||||
authToken: process.env.SENTRY_AUTH_TOKEN,
|
||||
org: 'sentry',
|
||||
project: 'jdt-admin',
|
||||
url: 'https://w.huakk.top',
|
||||
sourcemaps: {
|
||||
ignore: ['node_modules'],
|
||||
filesToDeleteAfterUpload: ['dist/**/*.js.map'],
|
||||
},
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
return plugins
|
||||
}
|
||||
|
||||
54
package.json
54
package.json
@@ -2,7 +2,7 @@
|
||||
"name": "vue-naive-admin",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"build": "vite build",
|
||||
"build:prod": "vite build",
|
||||
"build:test": "vite build --mode test",
|
||||
"cz": "cz",
|
||||
"dev": "vite",
|
||||
@@ -15,7 +15,6 @@
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,vue}": [
|
||||
"npx prettier --write --end-of-line lf .",
|
||||
"eslint --ext .js,.vue ."
|
||||
]
|
||||
},
|
||||
@@ -32,53 +31,54 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@sentry/vite-plugin": "^2.10.2",
|
||||
"@sentry/vue": "^7.84.0",
|
||||
"@unocss/eslint-config": "^0.55.7",
|
||||
"@vueuse/core": "^10.6.1",
|
||||
"@vueuse/core": "^10.11.1",
|
||||
"@wangeditor/editor": "^5.1.23",
|
||||
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||
"axios": "^1.6.2",
|
||||
"dayjs": "^1.11.10",
|
||||
"echarts": "^5.4.3",
|
||||
"axios": "^1.13.1",
|
||||
"dayjs": "^1.11.19",
|
||||
"echarts": "^5.6.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"jszip": "^3.10.1",
|
||||
"lodash-es": "^4.17.21",
|
||||
"md-editor-v3": "^4.9.0",
|
||||
"md-editor-v3": "^4.21.3",
|
||||
"mockjs": "^1.1.0",
|
||||
"pinia": "^2.1.7",
|
||||
"vite": "^4.5.0",
|
||||
"pinia": "^2.3.1",
|
||||
"vite": "^4.5.14",
|
||||
"vue": "3.3.4",
|
||||
"vue-echarts": "^6.6.1",
|
||||
"vue-router": "^4.2.5",
|
||||
"vue-echarts": "^6.7.3",
|
||||
"vue-router": "^4.6.3",
|
||||
"xlsx": "^0.18.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^17.8.1",
|
||||
"@commitlint/config-conventional": "^17.8.1",
|
||||
"@iconify/json": "^2.2.150",
|
||||
"@iconify/vue": "^4.1.1",
|
||||
"@iconify/json": "^2.2.402",
|
||||
"@iconify/vue": "^4.3.0",
|
||||
"@unocss/preset-rem-to-px": "^0.55.7",
|
||||
"@vitejs/plugin-vue": "^4.5.1",
|
||||
"@vue/compiler-sfc": "^3.3.9",
|
||||
"@vitejs/plugin-vue": "^4.6.2",
|
||||
"@vue/compiler-sfc": "^3.5.22",
|
||||
"@zclzone/eslint-config": "^0.0.4",
|
||||
"chalk": "^5.3.0",
|
||||
"commitizen": "^4.3.0",
|
||||
"chalk": "^5.6.2",
|
||||
"commitizen": "^4.3.1",
|
||||
"cz-conventional-changelog": "^3.3.0",
|
||||
"cz-customizable": "^7.0.0",
|
||||
"dotenv": "^16.3.1",
|
||||
"cz-customizable": "^7.5.1",
|
||||
"dotenv": "^16.6.1",
|
||||
"esno": "^0.17.0",
|
||||
"fs-extra": "^11.2.0",
|
||||
"fs-extra": "^11.3.2",
|
||||
"husky": "^8.0.3",
|
||||
"lint-staged": "^13.3.0",
|
||||
"naive-ui": "^2.35.0",
|
||||
"rollup-plugin-visualizer": "^5.9.3",
|
||||
"sass": "^1.69.5",
|
||||
"naive-ui": "^2.43.1",
|
||||
"rollup-plugin-visualizer": "^5.14.0",
|
||||
"sass": "^1.93.2",
|
||||
"unocss": "0.55.0",
|
||||
"unplugin-auto-import": "^0.16.7",
|
||||
"unplugin-icons": "^0.16.6",
|
||||
"unplugin-vue-components": "^0.25.2",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-html": "^3.2.0",
|
||||
"vite-plugin-html": "^3.2.2",
|
||||
"vite-plugin-mock": "^2.9.8",
|
||||
"vite-plugin-svg-icons": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"packageManager": "pnpm@9.1.4+sha512.9df9cf27c91715646c7d675d1c9c8e41f6fce88246f1318c1aa6a1ed1aeb3c4f032fcdf4ba63cc69c4fe6d634279176b5358727d8f2cc1e65b65f43ce2f8bfb0"
|
||||
}
|
||||
|
||||
11813
pnpm-lock.yaml
generated
11813
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
BIN
src/.DS_Store
vendored
Normal file
BIN
src/.DS_Store
vendored
Normal file
Binary file not shown.
@@ -68,7 +68,7 @@ const tabs = [
|
||||
const count = ref(tabs.map((item) => item.messages).flat().length)
|
||||
|
||||
watch(activeTab, (v) => {
|
||||
if (count === 0) return
|
||||
if (count.value === 0) return
|
||||
const tabIndex = tabs.findIndex((item) => item.name === v)
|
||||
count.value -= tabs[tabIndex].messages.length
|
||||
if (count.value < 0) count.value = 0
|
||||
|
||||
@@ -9,10 +9,14 @@ import { setupRouter } from '@/router'
|
||||
import { setupStore } from '@/store'
|
||||
import App from './App.vue'
|
||||
import { setupNaiveDiscreteApi } from './utils'
|
||||
import { initApiEndpoint } from '@/utils/api-config'
|
||||
|
||||
async function setupApp() {
|
||||
const app = createApp(App)
|
||||
|
||||
// 初始化接口配置
|
||||
initApiEndpoint()
|
||||
|
||||
setupStore(app)
|
||||
setupNaiveDiscreteApi()
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { getToken, isNullOrWhitespace } from '@/utils'
|
||||
import { addDynamicRoutes } from '@/router'
|
||||
|
||||
const WHITE_LIST = ['/login', '/404']
|
||||
export function createPermissionGuard(router) {
|
||||
@@ -14,7 +15,20 @@ export function createPermissionGuard(router) {
|
||||
/** 有token的情况 */
|
||||
if (to.path === '/login') return { path: '/' }
|
||||
|
||||
// refreshAccessToken()
|
||||
// 确保动态路由已加载
|
||||
if (token && !router.hasRoute('Dashboard')) {
|
||||
try {
|
||||
await addDynamicRoutes()
|
||||
// 如果当前路径不存在,重定向到工作台
|
||||
if (to.path !== '/' && !router.hasRoute(to.name)) {
|
||||
return { path: '/workbench' }
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('动态路由加载失败:', error)
|
||||
return { path: '/login' }
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import { setupRouterGuard } from './guard'
|
||||
import { basicRoutes, EMPTY_ROUTE, NOT_FOUND_ROUTE } from './routes'
|
||||
import { getToken, isNullOrWhitespace } from '@/utils'
|
||||
import { usePermissionStore } from '@/store'
|
||||
import * as Sentry from '@sentry/vue'
|
||||
|
||||
const isHash = false
|
||||
export const router = createRouter({
|
||||
@@ -15,22 +14,6 @@ export const router = createRouter({
|
||||
export async function setupRouter(app) {
|
||||
await addDynamicRoutes()
|
||||
setupRouterGuard(router)
|
||||
if (import.meta.env.VITE_SENTRY === 'true') {
|
||||
Sentry.init({
|
||||
app,
|
||||
dsn: 'https://1c158d5f832eef396e69447959d902d2@w.huakk.top/12',
|
||||
integrations: [
|
||||
new Sentry.BrowserTracing({
|
||||
tracePropagationTargets: ['localhost', /^https:\/\/w\.huakk\.top\/api/],
|
||||
routingInstrumentation: Sentry.vueRouterInstrumentation(router),
|
||||
}),
|
||||
new Sentry.Replay(),
|
||||
],
|
||||
tracesSampleRate: 1.0,
|
||||
replaysSessionSampleRate: 0.1,
|
||||
replaysOnErrorSampleRate: 1.0,
|
||||
})
|
||||
}
|
||||
app.use(router)
|
||||
}
|
||||
|
||||
@@ -47,11 +30,44 @@ export async function addDynamicRoutes() {
|
||||
try {
|
||||
const permissionStore = usePermissionStore()
|
||||
const accessRoutes = permissionStore.generateRoutes()
|
||||
|
||||
// 确保路由按正确顺序添加
|
||||
accessRoutes.forEach((route) => {
|
||||
!router.hasRoute(route.name) && router.addRoute(route)
|
||||
if (!router.hasRoute(route.name)) {
|
||||
router.addRoute(route)
|
||||
}
|
||||
})
|
||||
router.hasRoute(EMPTY_ROUTE.name) && router.removeRoute(EMPTY_ROUTE.name)
|
||||
|
||||
// 移除空路由,添加404路由
|
||||
if (router.hasRoute(EMPTY_ROUTE.name)) {
|
||||
router.removeRoute(EMPTY_ROUTE.name)
|
||||
}
|
||||
router.addRoute(NOT_FOUND_ROUTE)
|
||||
|
||||
// 确保根路径重定向到工作台
|
||||
// if (!router.hasRoute('workbench')) {
|
||||
// const workbenchRoute = {
|
||||
// name: 'workbench',
|
||||
// path: '/',
|
||||
// component: () => import('@/views/workbench/index.vue'),
|
||||
// redirect: '/workbench',
|
||||
// // children: [
|
||||
// // {
|
||||
// // name: 'Workbench',
|
||||
// // path: 'workbench',
|
||||
// // component: () => import('@/views/workbench/index.vue'),
|
||||
// // meta: {
|
||||
// // title: '工作台',
|
||||
// // icon: 'mdi:index',
|
||||
// // order: 0,
|
||||
// // },
|
||||
// // },
|
||||
// // ],
|
||||
// }
|
||||
// router.addRoute(workbenchRoute)
|
||||
// }
|
||||
|
||||
// console.log(router)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
throw error
|
||||
|
||||
@@ -58,17 +58,17 @@ function filterAsyncRoutes(routes = [], firstRoute = true) {
|
||||
|
||||
const curRoute = {
|
||||
path: route.route,
|
||||
name: route.name,
|
||||
name: route.route,
|
||||
isHidden,
|
||||
meta,
|
||||
children: [],
|
||||
}
|
||||
|
||||
if (route.route === '/' && firstRoute) {
|
||||
curRoute['redirect'] = route.subMenu[0].route
|
||||
} else if (route.subMenu && route.type === 1) {
|
||||
curRoute['redirect'] = `${route.subMenu[0].route}`
|
||||
}
|
||||
// if (route.route === '/' && firstRoute) {
|
||||
// curRoute['redirect'] = route.subMenu[0].route
|
||||
// } else if (route.subMenu && route.type === 1) {
|
||||
// curRoute['redirect'] = `${route.subMenu[0].route}`
|
||||
// }
|
||||
|
||||
if (route.subMenu && route.subMenu.length) {
|
||||
curRoute.children = filterAsyncRoutes(route.subMenu, false)
|
||||
@@ -84,7 +84,6 @@ function filterAsyncRoutes(routes = [], firstRoute = true) {
|
||||
curRoute.component = loadRouteView(route.components)
|
||||
break
|
||||
}
|
||||
|
||||
ret.push(curRoute)
|
||||
})
|
||||
return ret
|
||||
|
||||
@@ -18,10 +18,7 @@ export const useUserStore = defineStore('user', {
|
||||
return this.userInfo?.name
|
||||
},
|
||||
avatar() {
|
||||
return (
|
||||
this.userInfo?.avatar ||
|
||||
'https://pic3.58cdn.com.cn/nowater/webim/big/n_v21bc7874294754e63a22b80febac9cf51.jpg'
|
||||
)
|
||||
return this.userInfo?.avatar || 'https://v2.xxapi.cn/api/head?return=302'
|
||||
},
|
||||
role() {
|
||||
return this.userInfo?.role || []
|
||||
|
||||
61
src/utils/api-config.js
Normal file
61
src/utils/api-config.js
Normal file
@@ -0,0 +1,61 @@
|
||||
// 判断是否为开发环境
|
||||
const isDev = import.meta.env.DEV
|
||||
|
||||
// API接口线路配置管理
|
||||
export const API_ENDPOINTS = {
|
||||
primary: {
|
||||
name: '主要线路',
|
||||
baseURL: import.meta.env.VITE_BASE_API,
|
||||
timeout: 10000,
|
||||
},
|
||||
backup1: {
|
||||
name: '备用线路',
|
||||
baseURL: import.meta.env.VITE_BASE_API_1,
|
||||
timeout: 10000,
|
||||
},
|
||||
}
|
||||
|
||||
// 调试信息
|
||||
console.log('=== 多接口配置信息 ===')
|
||||
console.log('当前环境:', isDev ? '开发环境' : '生产环境')
|
||||
console.log('API配置:', API_ENDPOINTS)
|
||||
console.log('环境变量 VITE_BASE_API:', import.meta.env.VITE_BASE_API)
|
||||
console.log('环境变量 VITE_BASE_API_1:', import.meta.env.VITE_BASE_API_1)
|
||||
console.log('是否使用代理:', import.meta.env.VITE_USE_PROXY)
|
||||
|
||||
// 当前使用的接口线路
|
||||
let currentEndpoint = 'primary'
|
||||
|
||||
// 获取当前接口配置
|
||||
export function getCurrentEndpoint() {
|
||||
return {
|
||||
key: currentEndpoint,
|
||||
...API_ENDPOINTS[currentEndpoint],
|
||||
}
|
||||
}
|
||||
|
||||
// 设置当前接口
|
||||
export function setCurrentEndpoint(endpoint) {
|
||||
if (API_ENDPOINTS[endpoint]) {
|
||||
currentEndpoint = endpoint
|
||||
localStorage.setItem('api_endpoint', endpoint)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 获取所有可用接口
|
||||
export function getAvailableEndpoints() {
|
||||
return Object.entries(API_ENDPOINTS).map(([key, config]) => ({
|
||||
key,
|
||||
...config,
|
||||
}))
|
||||
}
|
||||
|
||||
// 初始化时从本地存储恢复接口选择
|
||||
export function initApiEndpoint() {
|
||||
const savedEndpoint = localStorage.getItem('api_endpoint')
|
||||
if (savedEndpoint && API_ENDPOINTS[savedEndpoint]) {
|
||||
currentEndpoint = savedEndpoint
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import axios from 'axios'
|
||||
import { resReject, resResolve, reqReject, reqResolve } from './interceptors'
|
||||
import { getCurrentEndpoint, getAvailableEndpoints } from '../api-config'
|
||||
|
||||
export function createAxios(options = {}) {
|
||||
const defaultOptions = {
|
||||
@@ -14,6 +15,93 @@ export function createAxios(options = {}) {
|
||||
return service
|
||||
}
|
||||
|
||||
export const request = createAxios({
|
||||
baseURL: import.meta.env.VITE_BASE_API,
|
||||
})
|
||||
// 创建支持多接口的请求实例
|
||||
export function createMultiEndpointRequest() {
|
||||
let instances = null
|
||||
|
||||
// 延迟创建axios实例
|
||||
function ensureInstances() {
|
||||
if (!instances) {
|
||||
instances = {}
|
||||
const endpoints = getAvailableEndpoints()
|
||||
|
||||
console.log('创建axios实例,接口列表:', endpoints)
|
||||
|
||||
endpoints.forEach((endpoint) => {
|
||||
console.log(`创建实例 ${endpoint.key}:`, endpoint.baseURL)
|
||||
instances[endpoint.key] = createAxios({
|
||||
baseURL: endpoint.baseURL,
|
||||
timeout: endpoint.timeout,
|
||||
})
|
||||
})
|
||||
}
|
||||
return instances
|
||||
}
|
||||
|
||||
return {
|
||||
// 使用当前选中的接口发送请求
|
||||
async request(config) {
|
||||
const instances = ensureInstances()
|
||||
const currentEndpoint = getCurrentEndpoint()
|
||||
|
||||
console.log('当前接口配置:', currentEndpoint)
|
||||
console.log('可用实例:', Object.keys(instances))
|
||||
|
||||
const instance = instances[currentEndpoint.key]
|
||||
|
||||
if (!instance) {
|
||||
throw new Error(`接口实例不存在: ${currentEndpoint.key}`)
|
||||
}
|
||||
|
||||
console.log(`使用接口: ${currentEndpoint.name} (${currentEndpoint.baseURL})`)
|
||||
console.log('请求配置:', config)
|
||||
|
||||
return await instance(config)
|
||||
},
|
||||
|
||||
// 获取当前接口实例
|
||||
getCurrentInstance() {
|
||||
const instances = ensureInstances()
|
||||
const currentEndpoint = getCurrentEndpoint()
|
||||
return instances[currentEndpoint.key]
|
||||
},
|
||||
|
||||
// 获取所有接口实例
|
||||
getAllInstances() {
|
||||
return ensureInstances()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// export const request = createAxios({
|
||||
// baseURL: import.meta.env.VITE_BASE_API,
|
||||
// })
|
||||
|
||||
// 支持多接口的请求实例
|
||||
export const multiRequest = createMultiEndpointRequest()
|
||||
|
||||
// 创建自动适配多接口的request实例
|
||||
const multiEndpointInstance = createMultiEndpointRequest()
|
||||
|
||||
// 创建支持axios方法的request实例
|
||||
export const request = {
|
||||
// 基础请求方法
|
||||
request: (config) => multiEndpointInstance.request(config),
|
||||
|
||||
// 自动适配axios方法
|
||||
get: (url, config = {}) => multiEndpointInstance.request({ method: 'get', url, ...config }),
|
||||
post: (url, data, config = {}) =>
|
||||
multiEndpointInstance.request({ method: 'post', url, data, ...config }),
|
||||
put: (url, data, config = {}) =>
|
||||
multiEndpointInstance.request({ method: 'put', url, data, ...config }),
|
||||
delete: (url, config = {}) => multiEndpointInstance.request({ method: 'delete', url, ...config }),
|
||||
patch: (url, data, config = {}) =>
|
||||
multiEndpointInstance.request({ method: 'patch', url, data, ...config }),
|
||||
head: (url, config = {}) => multiEndpointInstance.request({ method: 'head', url, ...config }),
|
||||
options: (url, config = {}) =>
|
||||
multiEndpointInstance.request({ method: 'options', url, ...config }),
|
||||
|
||||
// 获取当前接口实例(用于直接访问axios实例)
|
||||
getCurrentInstance: () => multiEndpointInstance.getCurrentInstance(),
|
||||
getAllInstances: () => multiEndpointInstance.getAllInstances(),
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<n-button v-perms="['/admin/store/classify/edit']" type="primary" @click="handleAdd(1)">
|
||||
新增商户分类
|
||||
</n-button>
|
||||
<!-- {{ formValue }} -->
|
||||
|
||||
<n-data-table
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
@@ -23,7 +23,15 @@
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<!-- {{ formValue }} -->
|
||||
<n-form ref="formRef" label-placement="left" :model="formValue" :rules="rules">
|
||||
<n-form-item label="上级分类:" path="sid">
|
||||
<n-select
|
||||
v-model:value="formValue.sid"
|
||||
:options="options"
|
||||
placeholder="请选择上级分类"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item label="分类图标:" path="icon">
|
||||
<Upload v-model:list="formValue.icon" />
|
||||
</n-form-item>
|
||||
@@ -123,6 +131,8 @@ const columns = ref([
|
||||
},
|
||||
])
|
||||
|
||||
const options = ref([])
|
||||
|
||||
const data = ref([])
|
||||
|
||||
const formRef = ref(null)
|
||||
@@ -137,10 +147,15 @@ const rules = {
|
||||
type: 'array',
|
||||
message: '请上传分类图标',
|
||||
},
|
||||
sid: {
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '请选择分类',
|
||||
},
|
||||
}
|
||||
|
||||
const formValue = ref({
|
||||
ID: 0,
|
||||
sid: null,
|
||||
name: '',
|
||||
status: 1,
|
||||
icon: [],
|
||||
@@ -165,6 +180,7 @@ const pagination = ref({
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
getOptions()
|
||||
})
|
||||
|
||||
const getList = async () => {
|
||||
@@ -182,6 +198,25 @@ const getList = async () => {
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
const getOptions = async () => {
|
||||
const res = await api.getList({
|
||||
pageNum: 1,
|
||||
pageSize: 9999999999,
|
||||
})
|
||||
options.value = [
|
||||
{
|
||||
label: '顶级分类',
|
||||
value: 0,
|
||||
},
|
||||
]
|
||||
res.data.data.forEach((item) => {
|
||||
options.value.push({
|
||||
label: item.name,
|
||||
value: item.ID,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const modelTitle = ref('')
|
||||
|
||||
const handleAdd = (e) => {
|
||||
@@ -191,7 +226,7 @@ const handleAdd = (e) => {
|
||||
|
||||
const clear = () => {
|
||||
formValue.value = {
|
||||
ID: 0,
|
||||
sid: 0,
|
||||
name: '',
|
||||
status: 1,
|
||||
icon: [],
|
||||
@@ -204,6 +239,7 @@ const handleValidateClick = async (e) => {
|
||||
formRef.value?.validate(async (errors) => {
|
||||
if (!errors) {
|
||||
try {
|
||||
console.log(formValue.value)
|
||||
await api.addClass({
|
||||
...formValue.value,
|
||||
icon: formValue.value.icon[0].url,
|
||||
@@ -211,6 +247,7 @@ const handleValidateClick = async (e) => {
|
||||
$message.success('成功')
|
||||
clear()
|
||||
getList()
|
||||
getOptions()
|
||||
} catch (error) {
|
||||
$message.error(error.msg)
|
||||
}
|
||||
|
||||
@@ -128,6 +128,42 @@
|
||||
<n-form-item label="手续费比例:" path="scale">
|
||||
<n-input-number v-model:value="formValue.scale" placeholder="请输入手续费比例" />
|
||||
</n-form-item>
|
||||
<n-form-item label="提现额度:" path="withdraw_amount">
|
||||
<n-input-number
|
||||
v-model:value="formValue.withdraw_amount"
|
||||
:step="1000"
|
||||
placeholder="请输入提现额度"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item label="兑换额度:" path="exchange_amount">
|
||||
<n-input-number
|
||||
v-model:value="formValue.exchange_amount"
|
||||
:step="1000"
|
||||
placeholder="请输入兑换额度"
|
||||
/>
|
||||
</n-form-item>
|
||||
<!-- <n-form-item label="聚合积分额度:" path="quota">
|
||||
<n-input-number v-model:value="formValue.quota" placeholder="请输入聚合积分额度" />
|
||||
</n-form-item>
|
||||
<n-form-item label="聚合兑换比例:" path="ratio">
|
||||
<n-input-number
|
||||
v-model:value="formValue.ratio"
|
||||
placeholder="请输入聚合兑换比例"
|
||||
:precision="2"
|
||||
/>
|
||||
</n-form-item> -->
|
||||
<!-- <n-form-item label="聚合appid:" path="appid">
|
||||
<n-input v-model:value="formValue.appid" placeholder="请输入聚合appid" />
|
||||
</n-form-item>
|
||||
<n-form-item label="聚合appKey:" path="appkey">
|
||||
<n-input v-model:value="formValue.appkey" placeholder="请输入聚合appKey" />
|
||||
</n-form-item>
|
||||
<n-form-item label="聚合查询接口:" path="check_url">
|
||||
<n-input v-model:value="formValue.check_url" placeholder="请输入聚合查询接口" />
|
||||
</n-form-item>
|
||||
<n-form-item label="聚合扣除接口:" path="edit_url">
|
||||
<n-input v-model:value="formValue.edit_url" placeholder="请输入聚合扣除接口" />
|
||||
</n-form-item> -->
|
||||
<n-form-item label="商户状态:" path="status">
|
||||
<n-switch v-model:value="formValue.status" :checked-value="1" :unchecked-value="2" />
|
||||
</n-form-item>
|
||||
@@ -268,7 +304,7 @@ const columns = ref([
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '积分',
|
||||
title: '余额',
|
||||
align: 'center',
|
||||
key: 'integral',
|
||||
},
|
||||
@@ -300,24 +336,24 @@ const columns = ref([
|
||||
),
|
||||
[[vPerms, ['/admin/store/edit']]]
|
||||
),
|
||||
withDirectives(
|
||||
h(
|
||||
NButton,
|
||||
{
|
||||
class: 'ml-10',
|
||||
type: 'primary',
|
||||
text: true,
|
||||
size: 'small',
|
||||
onClick: () => {
|
||||
model.value.name = row.name
|
||||
model.value.bid = row.bid
|
||||
showModalJf.value = true
|
||||
},
|
||||
},
|
||||
() => '退积分'
|
||||
),
|
||||
[[vPerms, ['/admin/store/set/integral']]]
|
||||
),
|
||||
// withDirectives(
|
||||
// h(
|
||||
// NButton,
|
||||
// {
|
||||
// class: 'ml-10',
|
||||
// type: 'primary',
|
||||
// text: true,
|
||||
// size: 'small',
|
||||
// onClick: () => {
|
||||
// model.value.name = row.name
|
||||
// model.value.bid = row.bid
|
||||
// showModalJf.value = true
|
||||
// },
|
||||
// },
|
||||
// () => '退积分'
|
||||
// ),
|
||||
// [[vPerms, ['/admin/store/set/integral']]]
|
||||
// ),
|
||||
withDirectives(
|
||||
h(
|
||||
NButton,
|
||||
@@ -333,7 +369,7 @@ const columns = ref([
|
||||
window.open(
|
||||
`${import.meta.env.VITE_MER_LOGIN_URL}?redirect=/workbench&type=${
|
||||
res.data.type
|
||||
}&tk=${res.data.token}`
|
||||
}&tk=${res.data.token}&api=${localStorage.getItem('api_endpoint')}`
|
||||
)
|
||||
},
|
||||
},
|
||||
@@ -387,8 +423,12 @@ let formValue = ref({
|
||||
password: '',
|
||||
scaleType: null,
|
||||
scale: null,
|
||||
quota: null,
|
||||
ratio: null,
|
||||
status: 2,
|
||||
sort: 0,
|
||||
withdraw_amount: 0,
|
||||
exchange_amount: 0,
|
||||
})
|
||||
|
||||
const rules = {
|
||||
@@ -408,7 +448,7 @@ const rules = {
|
||||
trigger: 'blur',
|
||||
},
|
||||
mobile: {
|
||||
required: true,
|
||||
required: false,
|
||||
message: '请输入商户座机',
|
||||
trigger: 'blur',
|
||||
},
|
||||
@@ -445,6 +485,18 @@ const rules = {
|
||||
message: '请输入手续费比例',
|
||||
trigger: 'blur',
|
||||
},
|
||||
withdraw_amount: {
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '请输入提现额度',
|
||||
trigger: 'blur',
|
||||
},
|
||||
exchange_amount: {
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '请输入兑换额度',
|
||||
trigger: 'blur',
|
||||
},
|
||||
status: {
|
||||
type: 'number',
|
||||
message: '请选择商户状态',
|
||||
@@ -526,6 +578,8 @@ const handleClearValidateClick = () => {
|
||||
scaleType: null,
|
||||
scale: null,
|
||||
status: 2,
|
||||
quota: null,
|
||||
ratio: null,
|
||||
sort: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,4 +3,5 @@ import { request } from '@/utils'
|
||||
export default {
|
||||
getHotlist: (data) => request.post('/goods', data),
|
||||
getHotStatus: (data) => request.post('/goods/process', data),
|
||||
updateType: (data) => request.post('/goods/edit/activity', data),
|
||||
}
|
||||
|
||||
@@ -1,13 +1,107 @@
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<template>
|
||||
<CommonPage show-footer :title="$route.title">
|
||||
<!-- {{ queryParams }} -->
|
||||
<n-grid class="mb-10" x-gap="12">
|
||||
<n-gi span="12" mt-10 flex items-center>
|
||||
<span w-100>筛选条件:</span>
|
||||
<n-input-group>
|
||||
<n-select
|
||||
v-model:value="queryParams.selectKey"
|
||||
:style="{ width: '25%' }"
|
||||
:options="selectOptions"
|
||||
placeholder="请选择"
|
||||
/>
|
||||
<n-input v-model:value="queryParams.word" :style="{ width: '50%' }" />
|
||||
</n-input-group>
|
||||
</n-gi>
|
||||
<n-gi :span="24" mt-10>
|
||||
<div>
|
||||
<span>审核状态:</span>
|
||||
<n-radio-group v-model:value="queryParams.status">
|
||||
<n-radio-button
|
||||
v-for="song in [
|
||||
{
|
||||
label: '已审核',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: '拒绝',
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
label: '待审核',
|
||||
value: 3,
|
||||
},
|
||||
]"
|
||||
:key="song.value"
|
||||
:value="song.value"
|
||||
:label="song.label"
|
||||
/>
|
||||
</n-radio-group>
|
||||
</div>
|
||||
</n-gi>
|
||||
<n-gi :span="24" mt-10>
|
||||
<div>
|
||||
<span>商品类型:</span>
|
||||
<n-radio-group v-model:value="queryParams.type">
|
||||
<n-radio-button
|
||||
v-for="song in [
|
||||
{
|
||||
label: '普通商品',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: '活动商品',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: '积分商品',
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
label: '摇球商品',
|
||||
value: 3,
|
||||
},
|
||||
]"
|
||||
:key="song.value"
|
||||
:value="song.value"
|
||||
:label="song.label"
|
||||
/>
|
||||
</n-radio-group>
|
||||
</div>
|
||||
</n-gi>
|
||||
<n-gi span="24" mt-10 flex items-center>
|
||||
<n-button type="primary" @click="getList">查询</n-button>
|
||||
<n-button ml-10 @click="clear">重置</n-button>
|
||||
</n-gi>
|
||||
<n-gi span="24" mt-10 flex items-center>
|
||||
<n-button strong secondary type="primary" @click="veeifys()">批量审核</n-button>
|
||||
<n-button strong secondary ml-10 type="primary" @click="changeGoodsType(0)">
|
||||
设为普通商品
|
||||
</n-button>
|
||||
<n-button strong secondary ml-10 type="warning" @click="changeGoodsType(1)">
|
||||
设为活动商品
|
||||
</n-button>
|
||||
<n-button strong secondary ml-10 type="info" @click="changeGoodsType(2)">
|
||||
设为兑换商品
|
||||
</n-button>
|
||||
<n-button strong secondary ml-10 type="error" @click="changeGoodsType(3)">
|
||||
设为摇球机活动商品
|
||||
</n-button>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
|
||||
<n-data-table
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
:row-key="(row) => row.gid"
|
||||
:checked-row-keys="queryParams.checkedRowKeysRef"
|
||||
remote
|
||||
@update:checked-row-keys="handleCheck"
|
||||
/>
|
||||
<!-- 拒绝 -->
|
||||
<n-modal v-model:show="isNoteModel">
|
||||
@@ -79,6 +173,17 @@
|
||||
:min="0"
|
||||
/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="20" label="商品抵扣比例" path="discount">
|
||||
<n-input-number
|
||||
v-model:value="nowRow.discount"
|
||||
clearable
|
||||
placeholder="请输入抵扣比例...."
|
||||
:min="0"
|
||||
:precision="0"
|
||||
>
|
||||
<template #suffix>%</template>
|
||||
</n-input-number>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="20" label="豆子过期时间" path="expiration">
|
||||
<n-input-number
|
||||
v-model:value="nowRow.expiration"
|
||||
@@ -152,7 +257,7 @@
|
||||
|
||||
<script setup>
|
||||
import api from './api'
|
||||
import { NButton, NImage, NSpace, NEllipsis } from 'naive-ui'
|
||||
import { NButton, NImage, NSpace, NEllipsis, NTag } from 'naive-ui'
|
||||
import { h, withDirectives, resolveDirective } from 'vue'
|
||||
|
||||
const vPerms = resolveDirective('perms')
|
||||
@@ -171,6 +276,39 @@ const notesVal = ref('')
|
||||
|
||||
const formRef = ref(null)
|
||||
|
||||
const selectOptions = ref([
|
||||
{
|
||||
label: '商品名称',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: '商家名称',
|
||||
value: 1,
|
||||
},
|
||||
])
|
||||
|
||||
const queryParams = ref({
|
||||
selectKey: 0,
|
||||
word: '',
|
||||
type: '',
|
||||
status: 0,
|
||||
checkedRowKeysRef: [],
|
||||
})
|
||||
|
||||
const handleCheck = (row) => {
|
||||
queryParams.value.checkedRowKeysRef = row
|
||||
}
|
||||
|
||||
const changeGoodsType = async (type) => {
|
||||
if (queryParams.value.checkedRowKeysRef.length === 0) return $message.info('没有选中商品')
|
||||
await api.updateType({
|
||||
type: type,
|
||||
gid: queryParams.value.checkedRowKeysRef,
|
||||
})
|
||||
getList()
|
||||
queryParams.value.checkedRowKeysRef = []
|
||||
}
|
||||
|
||||
const rules = {
|
||||
pulse: {
|
||||
required: true,
|
||||
@@ -196,12 +334,21 @@ const rules = {
|
||||
message: '请输入分佣比例',
|
||||
trigger: 'blur',
|
||||
},
|
||||
discount: {
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '请输入抵扣比例',
|
||||
trigger: 'blur',
|
||||
},
|
||||
}
|
||||
|
||||
const nowRow = ref({})
|
||||
const nowKey = ref(null)
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
type: 'selection',
|
||||
},
|
||||
{
|
||||
title: '商品名称',
|
||||
slot: 'name',
|
||||
@@ -218,6 +365,20 @@ const columns = ref([
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '商家名称',
|
||||
slot: 'store_name',
|
||||
align: 'center',
|
||||
render: (row) => {
|
||||
return h(
|
||||
'span',
|
||||
{},
|
||||
{
|
||||
default: () => row.Store.name,
|
||||
}
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '商品封面',
|
||||
slot: 'cover',
|
||||
@@ -243,11 +404,60 @@ const columns = ref([
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '商品类型',
|
||||
slot: 'type',
|
||||
align: 'center',
|
||||
render(row) {
|
||||
const obj = {
|
||||
0: {
|
||||
type: 'success',
|
||||
text: '普通商品',
|
||||
},
|
||||
1: {
|
||||
type: 'warning',
|
||||
text: '活动商品',
|
||||
},
|
||||
2: {
|
||||
type: 'info',
|
||||
text: '兑换商品',
|
||||
},
|
||||
3: {
|
||||
type: 'error',
|
||||
text: '摇球机活动商品',
|
||||
},
|
||||
}
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
type: obj[row.type].type,
|
||||
},
|
||||
{
|
||||
default: () => obj[row.type].text,
|
||||
}
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '商品价格(元)',
|
||||
key: 'number',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '抵扣后价格(元)',
|
||||
key: 'discount_price',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '积分抵扣(元)',
|
||||
key: 'exchange',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '抵扣比例(%)',
|
||||
key: 'discount',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '商品库存',
|
||||
key: 'stock',
|
||||
@@ -408,11 +618,19 @@ onMounted(() => {
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const query_data = {
|
||||
status: queryParams.value.status,
|
||||
type: queryParams.value.type,
|
||||
}
|
||||
|
||||
query_data[queryParams.value.selectKey === 0 ? 'name' : 'store_name'] = queryParams.value.word
|
||||
|
||||
const res = await api.getHotlist({
|
||||
pageNum: pagination.value.page,
|
||||
pageSize: pagination.value.pageSize,
|
||||
...query_data,
|
||||
})
|
||||
data.value = res.data.data || []
|
||||
data.value = res.data.data.sort((a, b) => b.status - a.status) || []
|
||||
pagination.value.itemCount = res.data.total
|
||||
} catch (error) {
|
||||
$message.error(error.msg)
|
||||
@@ -425,32 +643,56 @@ const clear = () => {
|
||||
isDzModel.value = false
|
||||
notesVal.value = ''
|
||||
nowRow.value = {}
|
||||
queryParams.value = {
|
||||
selectKey: 0,
|
||||
word: '',
|
||||
type: '',
|
||||
status: 0,
|
||||
checkedRowKeysRef: [],
|
||||
}
|
||||
getList()
|
||||
}
|
||||
|
||||
const veeify = async () => {
|
||||
let data = {}
|
||||
if (nowKey.value === 1 || nowKey.value === 2) {
|
||||
data = {
|
||||
gid: nowRow.value.gid,
|
||||
status: nowKey.value,
|
||||
notes: notesVal.value,
|
||||
}
|
||||
await api.getHotStatus(data)
|
||||
await getList()
|
||||
clear()
|
||||
} else {
|
||||
formRef.value?.validate(async (errors) => {
|
||||
if (!errors) {
|
||||
data = {
|
||||
...nowRow.value,
|
||||
}
|
||||
await api.getHotStatus(data)
|
||||
await getList()
|
||||
clear()
|
||||
try {
|
||||
let data = {}
|
||||
if (nowKey.value === 1 || nowKey.value === 2) {
|
||||
data = {
|
||||
gid: [nowRow.value.gid],
|
||||
status: nowKey.value,
|
||||
notes: notesVal.value,
|
||||
}
|
||||
})
|
||||
await api.getHotStatus(data)
|
||||
await getList()
|
||||
// clear()
|
||||
} else {
|
||||
formRef.value?.validate(async (errors) => {
|
||||
if (!errors) {
|
||||
data = {
|
||||
...nowRow.value,
|
||||
gid: [nowRow.value.gid],
|
||||
}
|
||||
await api.getHotStatus(data)
|
||||
await getList()
|
||||
// clear()
|
||||
}
|
||||
})
|
||||
}
|
||||
} finally {
|
||||
isNoteModel.value = false
|
||||
isDzModel.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const veeifys = async () => {
|
||||
if (queryParams.value.checkedRowKeysRef.length === 0) return $message.info('没有选中商品')
|
||||
await api.getHotStatus({
|
||||
gid: queryParams.value.checkedRowKeysRef,
|
||||
status: 1,
|
||||
notes: '',
|
||||
})
|
||||
clear()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<img src="@/assets/images/404.webp" width="500" />
|
||||
</template>
|
||||
<template #footer>
|
||||
<n-button @click="replace('/')">返回首页</n-button>
|
||||
<n-button @click="replace('/workbench')">返回首页</n-button>
|
||||
</template>
|
||||
</n-result>
|
||||
</AppPage>
|
||||
|
||||
@@ -4,4 +4,11 @@ export default {
|
||||
getData: (data) => request.post('/store/withdraw', data),
|
||||
// 审核提现
|
||||
passAudit: (data) => request.post('/store/withdraw/edit', data),
|
||||
|
||||
getYdata: (data) => request.post('/store/amount/withdraw', data),
|
||||
ydataEdit: (data) => request.post('/store/amount/withdraw/edit', data),
|
||||
// 溯源统计
|
||||
suyuanData: (data) => request.post('/pulse/count', data),
|
||||
// 获取游戏大厅
|
||||
getGameData: (data) => request.post('/game/list', data),
|
||||
}
|
||||
|
||||
@@ -8,7 +8,18 @@
|
||||
<n-number-animation
|
||||
ref="numberAnimationInstRef"
|
||||
:from="0"
|
||||
:to="cardData.total / 100"
|
||||
:to="cardData.total"
|
||||
:precision="2"
|
||||
/>
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<n-card ml-10 w-400>
|
||||
<n-statistic label="服务费" tabular-nums>
|
||||
<n-number-animation
|
||||
ref="numberAnimationInstRef"
|
||||
:from="0"
|
||||
:to="cardData.commission || 0 / 100"
|
||||
:precision="2"
|
||||
/>
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
@@ -17,17 +28,14 @@
|
||||
<n-number-animation
|
||||
ref="numberAnimationInstRef"
|
||||
:from="0"
|
||||
:to="cardData.service / 100"
|
||||
:to="cardData.service"
|
||||
:precision="2"
|
||||
/>
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<n-card ml-10 w-400>
|
||||
<n-statistic label="已审核金额" tabular-nums>
|
||||
<n-number-animation
|
||||
ref="numberAnimationInstRef"
|
||||
:from="0"
|
||||
:to="cardData.count / 100"
|
||||
/>
|
||||
<n-number-animation ref="numberAnimationInstRef" :from="0" :to="cardData.count" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
</div>
|
||||
@@ -126,6 +134,7 @@ const cardData = ref({
|
||||
total: 0,
|
||||
service: 0,
|
||||
count: 0,
|
||||
commission: 0,
|
||||
})
|
||||
|
||||
const songs = ref([
|
||||
@@ -192,7 +201,7 @@ const columns = ref([
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '上次留存积分',
|
||||
title: '上次留存余额',
|
||||
key: 'balance',
|
||||
align: 'center',
|
||||
},
|
||||
@@ -353,6 +362,7 @@ const getList = async () => {
|
||||
pagination.value.itemCount = res.data.total
|
||||
cardData.value.total = res.data.all
|
||||
cardData.value.service = res.data.audit_integral
|
||||
cardData.value.commission = res.data.audit_commission
|
||||
cardData.value.count = res.data.success_integral
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
279
src/views/finance/suyuan.vue
Normal file
279
src/views/finance/suyuan.vue
Normal file
@@ -0,0 +1,279 @@
|
||||
<template>
|
||||
<CommonPage show-footer :title="$route.title">
|
||||
<n-grid class="mb-10" x-gap="12">
|
||||
<n-gi :span="24">
|
||||
<div flex>
|
||||
<n-card w-250>
|
||||
<n-statistic label="总赢积分" tabular-nums>
|
||||
<n-number-animation ref="numberAnimationInstRef" :from="0" :to="cardData.win" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<n-card ml-10 w-250>
|
||||
<n-statistic label="总豆子" tabular-nums>
|
||||
<n-number-animation ref="numberAnimationInstRef" :from="0" :to="cardData.pulse" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
</div>
|
||||
</n-gi>
|
||||
<n-gi :span="12">
|
||||
<div mt-10 flex items-center>
|
||||
<div w-100>筛选条件:</div>
|
||||
<n-input-group>
|
||||
<n-select
|
||||
v-model:value="queryParams.selectKey"
|
||||
:style="{ width: '30rem' }"
|
||||
:options="selectOptions"
|
||||
placeholder="请选择"
|
||||
/>
|
||||
<n-input v-model:value="queryParams.word" :style="{ width: '50rem' }" />
|
||||
</n-input-group>
|
||||
</div>
|
||||
</n-gi>
|
||||
<n-gi :span="24">
|
||||
<div mt-10 flex items-center>
|
||||
<div mr-10>游戏名称:</div>
|
||||
<n-select
|
||||
v-model:value="queryParams.hall_id"
|
||||
w-250
|
||||
:options="gamelist"
|
||||
placeholder="请选择游戏"
|
||||
/>
|
||||
</div>
|
||||
</n-gi>
|
||||
<n-gi :span="24" mt-10>
|
||||
<div>
|
||||
<span>豆子状态:</span>
|
||||
<n-radio-group v-model:value="queryParams.Status">
|
||||
<n-radio-button
|
||||
v-for="song in songs"
|
||||
:key="song.value"
|
||||
:value="song.value"
|
||||
:label="song.label"
|
||||
/>
|
||||
</n-radio-group>
|
||||
</div>
|
||||
</n-gi>
|
||||
<n-gi :span="24" mt-10>
|
||||
<div>
|
||||
<span>活动赠送:</span>
|
||||
<n-radio-group v-model:value="queryParams.Type">
|
||||
<n-radio-button
|
||||
v-for="song in songs1"
|
||||
:key="song.value"
|
||||
:value="song.value"
|
||||
:label="song.label"
|
||||
/>
|
||||
</n-radio-group>
|
||||
</div>
|
||||
</n-gi>
|
||||
<n-gi :span="24">
|
||||
<div mt-10 flex items-center>
|
||||
<div>时间筛选:</div>
|
||||
<n-date-picker
|
||||
v-model:formatted-value="queryParams.time"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
type="datetimerange"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
</n-gi>
|
||||
<n-gi span="24" mt-10 flex items-center>
|
||||
<n-button type="primary" @click="getList">查询</n-button>
|
||||
<n-button ml-10 @click="clear">重置</n-button>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
<n-data-table
|
||||
class="mt-10"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
remote
|
||||
/>
|
||||
</CommonPage>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import api from './api'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
const queryParams = ref({})
|
||||
|
||||
const cardData = ref({})
|
||||
|
||||
const selectOptions = [
|
||||
{
|
||||
label: '商家电话',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: '用户电话',
|
||||
value: 1,
|
||||
},
|
||||
]
|
||||
|
||||
const songs = ref([
|
||||
{
|
||||
value: 1,
|
||||
label: '未使用',
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
label: '用户赢',
|
||||
},
|
||||
{
|
||||
value: 4,
|
||||
label: '用户输',
|
||||
},
|
||||
{
|
||||
value: 5,
|
||||
label: '已过期',
|
||||
},
|
||||
])
|
||||
|
||||
const gamelist = ref([])
|
||||
|
||||
const songs1 = ref([
|
||||
{
|
||||
value: 5,
|
||||
label: '注册赠送',
|
||||
},
|
||||
{
|
||||
value: 6,
|
||||
label: '签到赠送',
|
||||
},
|
||||
{
|
||||
value: 7,
|
||||
label: '平台赠送',
|
||||
},
|
||||
])
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
title: '游戏名称',
|
||||
align: 'center',
|
||||
slot: 'game_name',
|
||||
render: (row) => {
|
||||
const res = gamelist.value.find((item) => item.value === Number(row.hall_id))
|
||||
return h('span', null, {
|
||||
default: () => res?.label || '',
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '订单ID',
|
||||
align: 'center',
|
||||
key: 'order_id',
|
||||
},
|
||||
{
|
||||
title: '期数',
|
||||
align: 'center',
|
||||
key: 'periods',
|
||||
},
|
||||
{
|
||||
title: '投注豆子',
|
||||
align: 'center',
|
||||
key: 'number',
|
||||
},
|
||||
{
|
||||
title: '赢积分',
|
||||
align: 'center',
|
||||
key: 'integral',
|
||||
},
|
||||
{
|
||||
title: '用户电话',
|
||||
align: 'center',
|
||||
key: 'user_phone',
|
||||
},
|
||||
{
|
||||
title: '商户电话',
|
||||
align: 'center',
|
||||
key: 'merchant_phone',
|
||||
},
|
||||
{
|
||||
title: '投注时间',
|
||||
align: 'center',
|
||||
key: 'add_time',
|
||||
},
|
||||
{
|
||||
title: '过期时间',
|
||||
align: 'center',
|
||||
slot: 'expire',
|
||||
render: (row) => {
|
||||
return h('span', null, {
|
||||
default: () => dayjs(row.expire).format('YYYY-MM-DD HH:mm:ss'),
|
||||
})
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const data = ref([])
|
||||
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
itemCount: 0,
|
||||
onChange: (page) => {
|
||||
pagination.value.page = page
|
||||
getList()
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
getGameList()
|
||||
})
|
||||
|
||||
const getGameList = async () => {
|
||||
const res = await api.getGameData({ pageSize: 9999999, pageNum: 1 })
|
||||
gamelist.value = res.data.data.map((item) => ({ value: item.ID, label: item.name }))
|
||||
}
|
||||
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
const query_data = {
|
||||
...queryParams.value,
|
||||
StartTime: queryParams.value.time?.[0] || '',
|
||||
EndTime: queryParams.value.time?.[1] || '',
|
||||
}
|
||||
|
||||
switch (queryParams.value.selectKey) {
|
||||
case 0:
|
||||
query_data['merchant_phone'] = queryParams.value.word
|
||||
break
|
||||
case 1:
|
||||
query_data['user_phone'] = queryParams.value.word
|
||||
break
|
||||
}
|
||||
|
||||
delete query_data.time
|
||||
delete query_data.word
|
||||
const res = await api.suyuanData({
|
||||
pageNum: pagination.value.page,
|
||||
pageSize: pagination.value.pageSize,
|
||||
...query_data,
|
||||
})
|
||||
data.value = res.data.result || []
|
||||
pagination.value.itemCount = res.data.count
|
||||
cardData.value.win = res.data.win
|
||||
cardData.value.pulse = res.data.pulse
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
const clear = () => {
|
||||
queryParams.value = {
|
||||
word: '',
|
||||
selectKey: null,
|
||||
Status: '',
|
||||
time: null,
|
||||
Type: '',
|
||||
hall_id: '',
|
||||
}
|
||||
getList()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
414
src/views/finance/yIndex.vue
Normal file
414
src/views/finance/yIndex.vue
Normal file
@@ -0,0 +1,414 @@
|
||||
<template>
|
||||
<CommonPage show-footer :title="$route.title">
|
||||
<n-row gutter="12">
|
||||
<n-col :span="24">
|
||||
<div flex>
|
||||
<n-card w-400>
|
||||
<n-statistic label="总提现金额(含已驳回)" tabular-nums>
|
||||
<n-number-animation
|
||||
ref="numberAnimationInstRef"
|
||||
:from="0"
|
||||
:to="cardData.total / 100"
|
||||
:precision="2"
|
||||
/>
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<n-card ml-10 w-400>
|
||||
<n-statistic label="待处理金额" tabular-nums>
|
||||
<n-number-animation
|
||||
ref="numberAnimationInstRef"
|
||||
:from="0"
|
||||
:to="cardData.service || 0 / 100"
|
||||
:precision="2"
|
||||
/>
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<n-card ml-10 w-400>
|
||||
<n-statistic label="服务费" tabular-nums>
|
||||
<n-number-animation
|
||||
ref="numberAnimationInstRef"
|
||||
:from="0"
|
||||
:to="cardData.commission || 0 / 100"
|
||||
:precision="2"
|
||||
/>
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<n-card ml-10 w-400>
|
||||
<n-statistic label="已审核金额" tabular-nums>
|
||||
<n-number-animation
|
||||
ref="numberAnimationInstRef"
|
||||
:from="0"
|
||||
:to="cardData.count || 0 / 100"
|
||||
/>
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="24">
|
||||
<div mt-10>
|
||||
<span w-80>提现状态:</span>
|
||||
<n-radio-group v-model:value="queryData.status" class="ml-10">
|
||||
<n-radio-button
|
||||
v-for="song in songs"
|
||||
:key="song.value"
|
||||
:value="song.value"
|
||||
:label="song.label"
|
||||
/>
|
||||
</n-radio-group>
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="24">
|
||||
<div mt-10 flex items-center>
|
||||
<span w-80>号码搜索:</span>
|
||||
<n-input v-model:value="queryData.word" style="width: 25%" placeholder="请输入手机号码" />
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="10">
|
||||
<div mt-10 flex items-center>
|
||||
<span w-80>申请时间:</span>
|
||||
<n-date-picker
|
||||
v-model:formatted-value="queryData.time"
|
||||
value-format="yyyy-MM-dd"
|
||||
type="daterange"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="24">
|
||||
<div mt-10>
|
||||
<n-button type="primary" @click="getList">搜索</n-button>
|
||||
<n-button ml-10 @click="clearQueryData">重置</n-button>
|
||||
</div>
|
||||
</n-col>
|
||||
</n-row>
|
||||
<n-data-table
|
||||
class="mt-10"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
remote
|
||||
/>
|
||||
<!-- 打款记录 -->
|
||||
<n-modal v-model:show="showModal">
|
||||
<n-card
|
||||
style="width: 500px"
|
||||
title="打款记录"
|
||||
:bordered="false"
|
||||
size="huge"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<n-form ref="formRef" :model="model" :rules="rules" label-placement="left">
|
||||
<n-grid :cols="1" :x-gap="24">
|
||||
<n-form-item-gi :span="12" label="打款截图" path="img">
|
||||
<Upload v-model:list="model.img" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi>
|
||||
<div w-full flex justify-center>
|
||||
<n-button type="primary" @click="ok">确定</n-button>
|
||||
<n-button class="ml-10" @click="clear">关闭</n-button>
|
||||
</div>
|
||||
</n-form-item-gi>
|
||||
</n-grid>
|
||||
</n-form>
|
||||
</n-card>
|
||||
</n-modal>
|
||||
</CommonPage>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import api from './api'
|
||||
import { NButton, NImage, NTag } from 'naive-ui'
|
||||
import Upload from '@/components/Upload.vue'
|
||||
import { h, withDirectives, resolveDirective } from 'vue'
|
||||
const vPerms = resolveDirective('perms')
|
||||
const vRole = [[vPerms, ['/admin/store/amount/withdraw/edit']]]
|
||||
|
||||
const showModal = ref(false)
|
||||
|
||||
const queryData = ref({
|
||||
status: '',
|
||||
word: '',
|
||||
time: '',
|
||||
})
|
||||
|
||||
const cardData = ref({
|
||||
total: 0,
|
||||
service: 0,
|
||||
count: 0,
|
||||
commission: 0,
|
||||
})
|
||||
|
||||
const songs = ref([
|
||||
{
|
||||
value: 1,
|
||||
label: '已审核',
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: '已驳回',
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
label: '待审核',
|
||||
},
|
||||
])
|
||||
|
||||
const nowRow = ref({})
|
||||
|
||||
const formRef = ref(null)
|
||||
|
||||
const model = ref({
|
||||
img: [],
|
||||
})
|
||||
|
||||
const rules = {
|
||||
img: { required: true, type: 'array', message: '请上传打款截图' },
|
||||
}
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
title: '名字',
|
||||
key: 'name',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '电话',
|
||||
key: 'phone',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '银行名称',
|
||||
key: 'bank',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '银行卡号',
|
||||
key: 'bank_card',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '账户名称',
|
||||
key: 'bank_name',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '法人',
|
||||
key: 'bank_user',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '提现金额',
|
||||
key: 'integral',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '服务费',
|
||||
key: 'commission',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '实际到账',
|
||||
key: 'number',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '剩余余额',
|
||||
key: 'residue',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '手续费比例',
|
||||
slot: 'commission_number',
|
||||
align: 'center',
|
||||
render: (row) => {
|
||||
return h(
|
||||
'span',
|
||||
{},
|
||||
{
|
||||
default: () => `${row.commission_number}%`,
|
||||
}
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '手续费类型',
|
||||
key: 'commission_type',
|
||||
align: 'center',
|
||||
render: (row) => {
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
type: row.commission_type === 1 ? 'success' : 'warning',
|
||||
},
|
||||
{
|
||||
default: () => (row.commission_type === 1 ? '百分比' : '固定值'),
|
||||
}
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '审核状态',
|
||||
align: 'center',
|
||||
slot: 'status',
|
||||
render: (row) => {
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
type: row.status === 1 ? 'success' : row.status === 2 ? 'error' : 'warning',
|
||||
},
|
||||
{
|
||||
default: () => (row.status === 1 ? '已审核' : row.status === 2 ? '已驳回' : '待审核'),
|
||||
}
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '申请时间',
|
||||
key: 'add_time',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '打款截图',
|
||||
slot: 'img',
|
||||
render: (row) => {
|
||||
return h(NImage, {
|
||||
src: row.status_img,
|
||||
width: '50',
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
align: 'center',
|
||||
slot: 'action',
|
||||
render: (row) => {
|
||||
if (row.status === 3) {
|
||||
return [
|
||||
withDirectives(
|
||||
h(
|
||||
NButton,
|
||||
{
|
||||
text: true,
|
||||
type: 'primary',
|
||||
onClick: () => {
|
||||
nowRow.value = row
|
||||
showModal.value = true
|
||||
},
|
||||
},
|
||||
{
|
||||
default: () => '审核',
|
||||
}
|
||||
),
|
||||
vRole
|
||||
),
|
||||
withDirectives(
|
||||
h(
|
||||
NButton,
|
||||
{
|
||||
class: 'ml-10',
|
||||
text: true,
|
||||
type: 'error',
|
||||
onClick: () => {
|
||||
nowRow.value = row
|
||||
refuse()
|
||||
},
|
||||
},
|
||||
{
|
||||
default: () => '拒绝',
|
||||
}
|
||||
),
|
||||
vRole
|
||||
),
|
||||
]
|
||||
}
|
||||
},
|
||||
},
|
||||
])
|
||||
const loading = ref(false)
|
||||
const data = ref([])
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
itemCount: 0,
|
||||
onChange: (page) => {
|
||||
pagination.value.page = page
|
||||
getList()
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
const query_data = {
|
||||
Status: queryData.value.status || '',
|
||||
Phone: queryData.value.word || '',
|
||||
StartTime: queryData.value.time === null ? '' : queryData.value.time[0] || '',
|
||||
EndTime: queryData.value.time === null ? '' : queryData.value.time[1] || '',
|
||||
}
|
||||
const res = await api.getYdata({
|
||||
pageNum: pagination.value.page,
|
||||
pageSize: pagination.value.pageSize,
|
||||
...query_data,
|
||||
})
|
||||
|
||||
data.value = res.data.data || []
|
||||
pagination.value.itemCount = res.data.total
|
||||
cardData.value.total = res.data.all
|
||||
cardData.value.service = res.data.audit_number
|
||||
cardData.value.commission = res.data.audit_commission
|
||||
cardData.value.count = res.data.success_amount
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
const clear = async () => {
|
||||
model.value = {
|
||||
img: [],
|
||||
}
|
||||
showModal.value = false
|
||||
formRef.value?.restoreValidation()
|
||||
await getList()
|
||||
}
|
||||
|
||||
const ok = () => {
|
||||
formRef.value?.validate(async (errors) => {
|
||||
if (!errors) {
|
||||
const res = await api.passAudit({
|
||||
bid: nowRow.value.bid,
|
||||
wid: nowRow.value.wid,
|
||||
img: model.value.img[0].url,
|
||||
status: 1,
|
||||
})
|
||||
$message.success(res.msg)
|
||||
clear()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const refuse = async () => {
|
||||
const res = await api.passAudit({
|
||||
bid: nowRow.value.bid,
|
||||
wid: nowRow.value.wid,
|
||||
img: model.value.img[0]?.url || '',
|
||||
status: 2,
|
||||
})
|
||||
clear()
|
||||
$message.success(res.msg)
|
||||
}
|
||||
|
||||
const clearQueryData = () => {
|
||||
queryData.value = {
|
||||
status: '',
|
||||
time: null,
|
||||
word: '',
|
||||
}
|
||||
getList()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@@ -188,6 +188,7 @@ const model = ref({
|
||||
introduction: '',
|
||||
cover: [],
|
||||
status: 2,
|
||||
sort: 0,
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
@@ -211,6 +212,7 @@ const clear = () => {
|
||||
introduction: '',
|
||||
cover: [],
|
||||
status: 2,
|
||||
sort: 0,
|
||||
}
|
||||
formRef.value?.restoreValidation()
|
||||
showModal.value = false
|
||||
@@ -266,6 +268,9 @@ const dropdownSelect = (e) => {
|
||||
<n-form-item-gi :span="16" label="是否显示:" path="status">
|
||||
<n-switch v-model:value="model.status" :unchecked-value="2" :checked-value="1" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="16" label="序号:" path="sort">
|
||||
<n-input-number v-model:value="model.sort" :min="0" placeholder="请输入游戏序号" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="12">
|
||||
<div m-auto p-10>
|
||||
<n-button type="primary" @click="submit">提交</n-button>
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
import { request } from '@/utils'
|
||||
import { request, multiRequest } from '@/utils'
|
||||
|
||||
export default {
|
||||
login: (data) => request.post('/login', data, { noNeedToken: true }),
|
||||
// 使用多接口的登录方法
|
||||
loginWithMultiEndpoint: (data) =>
|
||||
multiRequest.request({
|
||||
method: 'post',
|
||||
url: '/login',
|
||||
data,
|
||||
noNeedToken: true,
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -14,7 +14,17 @@
|
||||
<img src="@/assets/images/logo.png" height="50" class="mr-10" />
|
||||
{{ title }}
|
||||
</h5>
|
||||
<div mt-30>
|
||||
<!-- 接口线路选择 -->
|
||||
<div mt-20>
|
||||
<n-select
|
||||
v-model:value="selectedEndpoint"
|
||||
:options="endpointOptions"
|
||||
placeholder="选择接口线路"
|
||||
size="large"
|
||||
@update:value="handleEndpointChange"
|
||||
/>
|
||||
</div>
|
||||
<div mt-10>
|
||||
<n-input
|
||||
v-model:value="loginInfo.name"
|
||||
autofocus
|
||||
@@ -23,7 +33,7 @@
|
||||
:maxlength="20"
|
||||
/>
|
||||
</div>
|
||||
<div mt-30>
|
||||
<div mt-10>
|
||||
<n-input
|
||||
v-model:value="loginInfo.password"
|
||||
class="h-50 items-center pl-10 text-16"
|
||||
@@ -67,6 +77,12 @@ import { useStorage } from '@vueuse/core'
|
||||
import bgImg from '@/assets/images/login_bg.webp'
|
||||
import api from './api'
|
||||
import { addDynamicRoutes } from '@/router'
|
||||
import {
|
||||
getAvailableEndpoints,
|
||||
setCurrentEndpoint,
|
||||
getCurrentEndpoint,
|
||||
initApiEndpoint,
|
||||
} from '@/utils/api-config'
|
||||
|
||||
const title = import.meta.env.VITE_TITLE
|
||||
|
||||
@@ -90,6 +106,61 @@ function initLoginInfo() {
|
||||
|
||||
const isRemember = useStorage('isRemember', false)
|
||||
const loading = ref(false)
|
||||
|
||||
// 接口线路相关
|
||||
const selectedEndpoint = ref('primary')
|
||||
const endpointOptions = ref([])
|
||||
|
||||
// 初始化接口配置
|
||||
initApiEndpoint()
|
||||
const currentEndpoint = getCurrentEndpoint()
|
||||
selectedEndpoint.value = currentEndpoint.key
|
||||
|
||||
// 加载接口选项
|
||||
function loadEndpointOptions() {
|
||||
const endpoints = getAvailableEndpoints()
|
||||
endpointOptions.value = endpoints.map((endpoint) => ({
|
||||
label: endpoint.name,
|
||||
value: endpoint.key,
|
||||
}))
|
||||
}
|
||||
|
||||
// 处理接口切换
|
||||
function handleEndpointChange(value) {
|
||||
if (setCurrentEndpoint(value)) {
|
||||
selectedEndpoint.value = value
|
||||
$message.success(`已切换到${endpointOptions.value.find((opt) => opt.value === value)?.label}`)
|
||||
} else {
|
||||
$message.error('接口切换失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
loadEndpointOptions()
|
||||
})
|
||||
|
||||
// 获取第一个可用的路由页面
|
||||
function getFirstAvailableRoute(menuData) {
|
||||
if (!menuData || !Array.isArray(menuData)) return null
|
||||
|
||||
// 递归查找第一个type为2的路由(页面路由)
|
||||
function findFirstPageRoute(routes) {
|
||||
for (const route of routes) {
|
||||
if (route.type === 2 && route.route) {
|
||||
return route.route
|
||||
}
|
||||
if (route.subMenu && route.subMenu.length) {
|
||||
const found = findFirstPageRoute(route.subMenu)
|
||||
if (found) return found
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
return findFirstPageRoute(menuData)
|
||||
}
|
||||
|
||||
async function handleLogin() {
|
||||
const { name, password } = loginInfo.value
|
||||
if (!name || !password) {
|
||||
@@ -99,7 +170,14 @@ async function handleLogin() {
|
||||
try {
|
||||
loading.value = true
|
||||
$message.loading('正在验证...')
|
||||
const res = await api.login({ phone: name, password: password.toString() })
|
||||
|
||||
console.log('开始登录请求...')
|
||||
console.log('登录数据:', { phone: name, password: password.toString() })
|
||||
console.log('当前选中接口:', selectedEndpoint.value)
|
||||
|
||||
const res = await api.loginWithMultiEndpoint({ phone: name, password: password.toString() })
|
||||
|
||||
console.log('登录响应:', res)
|
||||
$message.success('登录成功')
|
||||
window.localStorage.setItem('menu', JSON.stringify(res.data.auth))
|
||||
setToken(res.data.token)
|
||||
@@ -108,15 +186,23 @@ async function handleLogin() {
|
||||
} else {
|
||||
lStorage.remove('loginInfo')
|
||||
}
|
||||
|
||||
// 先添加动态路由
|
||||
await addDynamicRoutes()
|
||||
|
||||
// 获取第一个可用的路由页面
|
||||
const firstRoute = getFirstAvailableRoute(res.data.auth)
|
||||
|
||||
if (query.redirect) {
|
||||
const path = query.redirect
|
||||
Reflect.deleteProperty(query, 'redirect')
|
||||
router.push({ path, query })
|
||||
} else {
|
||||
router.push('/')
|
||||
// 跳转到第一个可用路由,如果没有则跳转到工作台
|
||||
router.push(firstRoute || '/workbench')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('登录请求失败:', error)
|
||||
$message.removeMessage()
|
||||
}
|
||||
loading.value = false
|
||||
|
||||
@@ -3,4 +3,7 @@ import { request } from '@/utils'
|
||||
export default {
|
||||
getSignConfig: () => request.post('/gift/setting'),
|
||||
setSignConfig: (data) => request.post('/gift/setting/edit', data),
|
||||
getCodelist: (data) => request.post('/qrcode/list', data),
|
||||
addCode: (data) => request.post('/qrcode/add', data),
|
||||
updateCode: (data) => request.post('/qrcode/edit', data),
|
||||
}
|
||||
|
||||
494
src/views/marketing/code/index.vue
Normal file
494
src/views/marketing/code/index.vue
Normal file
@@ -0,0 +1,494 @@
|
||||
<template>
|
||||
<CommonPage show-footer :title="$route.title">
|
||||
<!-- {{ queryData }} -->
|
||||
<n-row gutter="12">
|
||||
<n-col :span="24">
|
||||
<div flex>
|
||||
<n-card w-500>
|
||||
<n-statistic label="未激活" tabular-nums>
|
||||
<n-number-animation ref="numberAnimationInstRef" :from="0" :to="cardData.total" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<n-card ml-10 w-500>
|
||||
<n-statistic label="已激活" tabular-nums>
|
||||
<n-number-animation ref="numberAnimationInstRef" :from="0" :to="cardData.service" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<n-card ml-10 w-500>
|
||||
<n-statistic label="未领取" tabular-nums>
|
||||
<n-number-animation ref="numberAnimationInstRef" :from="0" :to="cardData.count" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<n-card ml-10 w-500>
|
||||
<n-statistic label="已领取" tabular-nums>
|
||||
<n-number-animation ref="numberAnimationInstRef" :from="0" :to="cardData.count" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="24">
|
||||
<div mt-10>
|
||||
<span>激活状态:</span>
|
||||
<n-radio-group v-model:value="queryData.status">
|
||||
<n-radio-button
|
||||
v-for="song in songs"
|
||||
:key="song.value"
|
||||
:value="song.value"
|
||||
:label="song.label"
|
||||
/>
|
||||
</n-radio-group>
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="24">
|
||||
<div mt-10>
|
||||
<span>领取状态:</span>
|
||||
<n-radio-group v-model:value="queryData.status1">
|
||||
<n-radio-button
|
||||
v-for="song in songs1"
|
||||
:key="song.value"
|
||||
:value="song.value"
|
||||
:label="song.label"
|
||||
/>
|
||||
</n-radio-group>
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="24">
|
||||
<div mt-10 flex items-center>
|
||||
<div w-100>关键字搜索:</div>
|
||||
<n-input-group>
|
||||
<n-select
|
||||
v-model:value="queryData.selectKey"
|
||||
:style="{ width: '15%' }"
|
||||
:options="selectOptions"
|
||||
placeholder="请选择"
|
||||
/>
|
||||
<n-input v-model:value="queryData.word" :style="{ width: '20%' }" />
|
||||
</n-input-group>
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="10">
|
||||
<div mt-10 flex items-center>
|
||||
<span w-100>时间搜索:</span>
|
||||
<n-date-picker
|
||||
v-model:formatted-value="queryData.time"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
type="datetimerange"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="24">
|
||||
<div mt-10>
|
||||
<n-button v-perms="['/admin/qrcode/add']" mr-10 type="primary" @click="openModal(1)">
|
||||
新增二维码
|
||||
</n-button>
|
||||
<n-button v-perms="['/admin/qrcode/edit']" mr-10 type="warning" @click="openModal(2)">
|
||||
修改二维码
|
||||
</n-button>
|
||||
<n-button mr-10 type="info" @click="saveCode">下载二维码</n-button>
|
||||
<!-- <n-button mr-10 type="primary" @click="openModal(1)">新增二维码</n-button> -->
|
||||
<!-- <n-button mr-10 type="warning" @click="openModal(3)">修改二维码</n-button> -->
|
||||
<n-button type="primary" @click="getList">搜索</n-button>
|
||||
<n-button ml-10 @click="clear">重置</n-button>
|
||||
</div>
|
||||
</n-col>
|
||||
</n-row>
|
||||
<n-data-table
|
||||
class="mt-5"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
:row-key="rowKey"
|
||||
:checked-row-keys="checkedRowKeysRef"
|
||||
remote
|
||||
@update:checked-row-keys="handleCheck"
|
||||
/>
|
||||
<n-modal v-model:show="showModal" :auto-focus="false">
|
||||
<n-card
|
||||
style="width: 600px"
|
||||
:title="modelTitle"
|
||||
:bordered="false"
|
||||
size="huge"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<n-form ref="formRef" label-placement="left" :model="formValue" :rules="rules">
|
||||
<n-form-item v-if="modalType === 1" label="新增数量:" path="number">
|
||||
<n-input-number v-model:value="formValue.number" :min="1" clearable />
|
||||
</n-form-item>
|
||||
<n-form-item label="赠送豆子:" path="pulse">
|
||||
<n-input-number v-model:value="formValue.pulse" :min="1" clearable />
|
||||
</n-form-item>
|
||||
<n-form-item label="激活状态:" path="activate_status">
|
||||
<n-switch
|
||||
v-model:value="formValue.activate_status"
|
||||
:checked-value="1"
|
||||
:unchecked-value="2"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item>
|
||||
<div class="m-auto">
|
||||
<n-button
|
||||
class="m-auto"
|
||||
type="primary"
|
||||
attr-type="button"
|
||||
@click="handleValidateClick"
|
||||
>
|
||||
提交
|
||||
</n-button>
|
||||
<n-button class="ml-10" @click="handleclear">取消</n-button>
|
||||
</div>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-card>
|
||||
</n-modal>
|
||||
</CommonPage>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { NButton } from 'naive-ui'
|
||||
import JSZip from 'jszip'
|
||||
import { saveAs } from 'file-saver'
|
||||
import api from '../api'
|
||||
import { ref, resolveDirective, withDirectives } from 'vue'
|
||||
|
||||
const vPerms = resolveDirective('perms')
|
||||
|
||||
const songs = ref([
|
||||
{
|
||||
value: 1,
|
||||
label: '已激活',
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: '未激活',
|
||||
},
|
||||
])
|
||||
|
||||
const songs1 = ref([
|
||||
{
|
||||
value: 1,
|
||||
label: '已领取',
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: '未领取',
|
||||
},
|
||||
])
|
||||
|
||||
const selectOptions = ref([
|
||||
{
|
||||
value: 0,
|
||||
label: 'ID',
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
label: '手机号',
|
||||
},
|
||||
])
|
||||
const queryData = ref({
|
||||
status: '',
|
||||
status1: '',
|
||||
time: null,
|
||||
word: '',
|
||||
selectKey: null,
|
||||
})
|
||||
|
||||
const cardData = ref({})
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
type: 'selection',
|
||||
},
|
||||
{
|
||||
title: 'ID',
|
||||
align: 'center',
|
||||
key: 'qid',
|
||||
},
|
||||
{
|
||||
title: '二维码',
|
||||
align: 'center',
|
||||
slot: 'qrcode',
|
||||
render(row) {
|
||||
return h('img', {
|
||||
src: row.url,
|
||||
style: {
|
||||
width: '50px',
|
||||
height: '50px',
|
||||
},
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '用户',
|
||||
align: 'center',
|
||||
slot: 'user_name',
|
||||
render(row) {
|
||||
return h('span', row.User.nickName)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '用户电话',
|
||||
align: 'center',
|
||||
slot: 'phone',
|
||||
render(row) {
|
||||
return h('span', row.User.phone)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '赠送豆子',
|
||||
align: 'center',
|
||||
key: 'pulse',
|
||||
},
|
||||
{
|
||||
title: '激活状态',
|
||||
align: 'center',
|
||||
slot: 'status',
|
||||
render(row) {
|
||||
switch (row.activate_status) {
|
||||
case 1:
|
||||
return h('span', '已激活')
|
||||
case 2:
|
||||
return h('span', '未激活')
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '领取状态',
|
||||
align: 'center',
|
||||
slot: 'status',
|
||||
render(row) {
|
||||
switch (row.use_status) {
|
||||
case 1:
|
||||
return h('span', '已领取')
|
||||
case 2:
|
||||
return h('span', '未领取')
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '激活时间',
|
||||
align: 'center',
|
||||
key: 'activate_time',
|
||||
},
|
||||
{
|
||||
title: '领取时间',
|
||||
align: 'center',
|
||||
key: 'use_time',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
align: 'center',
|
||||
slot: 'action',
|
||||
render(row) {
|
||||
if (row.use_status === 2) {
|
||||
return withDirectives(
|
||||
h(
|
||||
NButton,
|
||||
{
|
||||
type: 'primary',
|
||||
size: 'small',
|
||||
onClick: () => openModal(2, row),
|
||||
},
|
||||
{
|
||||
default: () => '编辑',
|
||||
}
|
||||
),
|
||||
[[vPerms, ['/admin/qrcode/edit']]]
|
||||
)
|
||||
// return h(
|
||||
// NButton,
|
||||
// {
|
||||
// type: 'primary',
|
||||
// size: 'small',
|
||||
// onClick: () => {
|
||||
// openModal(2, row)
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// default: () => '编辑',
|
||||
// }
|
||||
// )
|
||||
}
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const data = ref([])
|
||||
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
itemCount: 0,
|
||||
prefix: ({ itemCount }) => {
|
||||
return `共 ${itemCount} 项`
|
||||
},
|
||||
onChange: (page) => {
|
||||
pagination.value.page = page
|
||||
getList()
|
||||
},
|
||||
onUpdatePageSize: (pageSize) => {
|
||||
pagination.value.pageSize = pageSize
|
||||
pagination.value.page = 1
|
||||
getList()
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const query_data = {
|
||||
UseStatus: queryData.value.status,
|
||||
ActivateStatus: queryData.value.status1,
|
||||
StartTime: queryData.value.time === null ? '' : queryData.value.time[0] || '',
|
||||
EndTime: queryData.value.time === null ? '' : queryData.value.time[1] || '',
|
||||
}
|
||||
switch (queryData.value.selectKey) {
|
||||
case 0:
|
||||
query_data['Qid'] = queryData.value.word
|
||||
break
|
||||
case 1:
|
||||
query_data['Phone'] = queryData.value.word
|
||||
break
|
||||
}
|
||||
const res = await api.getCodelist({
|
||||
pageNum: pagination.value.page,
|
||||
pageSize: pagination.value.pageSize,
|
||||
...query_data,
|
||||
})
|
||||
data.value = res.data.data || []
|
||||
pagination.value.itemCount = res.data.total
|
||||
cardData.value.total = res.data.number
|
||||
cardData.value.service = res.data.commission
|
||||
cardData.value.count = 0
|
||||
} catch (error) {
|
||||
$message.error(error.msg)
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
const clear = () => {
|
||||
queryData.value = {
|
||||
status: '',
|
||||
status1: '',
|
||||
time: null,
|
||||
word: '',
|
||||
selectKey: null,
|
||||
}
|
||||
getList()
|
||||
}
|
||||
|
||||
const rowKey = (row) => row.qid
|
||||
|
||||
const checkedRowKeysRef = ref([])
|
||||
|
||||
const handleCheck = (rowKeys) => {
|
||||
checkedRowKeysRef.value = rowKeys
|
||||
}
|
||||
|
||||
const showModal = ref(false)
|
||||
|
||||
const modelTitle = ref('')
|
||||
|
||||
const formValue = ref({
|
||||
number: null,
|
||||
pulse: null,
|
||||
activate_status: 2,
|
||||
})
|
||||
|
||||
const rules = {
|
||||
number: {
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '请输入生成数量',
|
||||
trigger: 'blur',
|
||||
},
|
||||
pulse: {
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '请输入豆子数量',
|
||||
trigger: 'blur',
|
||||
},
|
||||
}
|
||||
|
||||
const handleclear = () => {
|
||||
showModal.value = false
|
||||
formValue.value = {
|
||||
number: null,
|
||||
pulse: null,
|
||||
activate_status: 2,
|
||||
}
|
||||
checkedRowKeysRef.value = []
|
||||
}
|
||||
|
||||
const modalType = ref(null)
|
||||
const nowRow = ref([])
|
||||
|
||||
const openModal = (e, row) => {
|
||||
showModal.value = true
|
||||
modalType.value = e
|
||||
modelTitle.value = e === 1 ? '新增二维码' : '编辑二维码'
|
||||
if (e === 2) {
|
||||
nowRow.value = [row.qid]
|
||||
formValue.value.pulse = row.pulse
|
||||
formValue.value.activate_status = row.activate_status
|
||||
} else if (e === 3) {
|
||||
nowRow.value = checkedRowKeysRef.value
|
||||
}
|
||||
}
|
||||
|
||||
const formRef = ref(null)
|
||||
|
||||
const handleValidateClick = (e) => {
|
||||
e.preventDefault()
|
||||
formRef.value?.validate(async (errors) => {
|
||||
if (!errors) {
|
||||
try {
|
||||
if (modalType.value === 1) {
|
||||
await api.addCode(formValue.value)
|
||||
} else {
|
||||
await api.updateCode({
|
||||
qid: nowRow.value,
|
||||
...formValue.value,
|
||||
})
|
||||
}
|
||||
handleclear()
|
||||
getList()
|
||||
} catch (error) {
|
||||
// $message.error(error.msg)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 下载二维码
|
||||
const saveCode = async () => {
|
||||
if (checkedRowKeysRef.value.length === 0) return $message.error('请选择二维码')
|
||||
|
||||
const zip = new JSZip()
|
||||
|
||||
data.value.forEach((item) => {
|
||||
checkedRowKeysRef.value.forEach((id) => {
|
||||
if (item.qid === id) {
|
||||
const imageData = item.url.split(',')[1]
|
||||
zip.file(`${item.qid}.png`, imageData, {
|
||||
base64: true,
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const content = await zip.generateAsync({ type: 'blob' })
|
||||
saveAs(content, '二维码.zip')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@@ -18,6 +18,16 @@
|
||||
<n-number-animation :from="0" :to="cardData.count" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<n-card ml-10 w-500>
|
||||
<n-statistic label="赠送豆子" tabular-nums>
|
||||
<n-number-animation :from="0" :to="cardData.gift_pulse" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<n-card ml-10 w-500>
|
||||
<n-statistic label="抵扣后价格(元)" tabular-nums>
|
||||
<n-number-animation :from="0" :to="cardData.discount_number" :precision="2" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="24" mt-10>
|
||||
@@ -40,13 +50,21 @@
|
||||
<n-radio-button
|
||||
v-for="song in [
|
||||
{
|
||||
label: '微信',
|
||||
label: '微信支付',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: '积分',
|
||||
label: '平台积分',
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
label: '智多鑫积分',
|
||||
value: 3,
|
||||
},
|
||||
{
|
||||
label: '渔乐潮玩积分',
|
||||
value: 5,
|
||||
},
|
||||
]"
|
||||
:key="song.value"
|
||||
:value="song.value"
|
||||
@@ -83,24 +101,27 @@
|
||||
<n-col :span="24">
|
||||
<div mt-10>
|
||||
<n-button type="primary" @click="getList">搜索</n-button>
|
||||
<n-button type="primary" ml-10 @click="exportTable">导出表格</n-button>
|
||||
<n-button ml-10 @click="clear">重置</n-button>
|
||||
</div>
|
||||
</n-col>
|
||||
</n-row>
|
||||
<n-data-table
|
||||
ref="dataTableRef"
|
||||
class="mt-5"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
:scroll-x="1800"
|
||||
:scroll-x="2000"
|
||||
remote
|
||||
/>
|
||||
</CommonPage>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import * as XLSX from 'xlsx'
|
||||
import api from './api'
|
||||
|
||||
const loading = ref(false)
|
||||
@@ -117,6 +138,7 @@ const cardData = ref({
|
||||
total: 0,
|
||||
service: 0,
|
||||
count: 0,
|
||||
gift_pulse: 0,
|
||||
})
|
||||
|
||||
const songs = ref([
|
||||
@@ -164,12 +186,11 @@ const selectOptions = ref([
|
||||
label: '商家名称',
|
||||
},
|
||||
])
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
title: '订单号',
|
||||
align: 'center',
|
||||
key: 'oid',
|
||||
key: 'jl_oid',
|
||||
width: 200,
|
||||
fixed: 'left',
|
||||
},
|
||||
@@ -232,16 +253,26 @@ const columns = ref([
|
||||
key: 'count',
|
||||
},
|
||||
{
|
||||
title: '订单总价',
|
||||
title: '订单金额',
|
||||
align: 'center',
|
||||
slot: 'number',
|
||||
render: (row) => h('span', row.pay_type === 1 ? `${row.price}元` : `${row.exchange}积分`),
|
||||
render: (row) => h('span', `${row.price}元`),
|
||||
},
|
||||
{
|
||||
title: '抵扣后价格(元)',
|
||||
key: 'discount_price',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '积分抵扣',
|
||||
key: 'exchange',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '支付方式',
|
||||
align: 'center',
|
||||
slot: 'pay_type',
|
||||
render: (row) => h('span', row.pay_type === 1 ? '微信' : '积分'),
|
||||
render: (row) => h('span', row.PayInfo.name),
|
||||
},
|
||||
{
|
||||
title: '商家名称',
|
||||
@@ -297,6 +328,8 @@ const pagination = ref({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
itemCount: 0,
|
||||
showSizePicker: true,
|
||||
pageSizes: [10, 20, 50, 100],
|
||||
onChange: (page) => {
|
||||
pagination.value.page = page
|
||||
getList()
|
||||
@@ -311,6 +344,21 @@ const pagination = ref({
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
const dataTableRef = ref(null)
|
||||
const exportTable = () => {
|
||||
// console.log(dataTableRef.value)
|
||||
// dataTableRef.value?.downloadCsv({
|
||||
// fileName: new Date().getTime() + '.csv',
|
||||
// keepOriginalData: false,
|
||||
// })
|
||||
// 将数据转换为工作簿
|
||||
const worksheet = XLSX.utils.json_to_sheet(data.value)
|
||||
const workbook = XLSX.utils.book_new()
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1')
|
||||
|
||||
// 生成Excel文件并触发下载
|
||||
XLSX.writeFile(workbook, 'table.xlsx')
|
||||
}
|
||||
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
@@ -347,6 +395,8 @@ const getList = async () => {
|
||||
cardData.value.total = res.data.number
|
||||
cardData.value.service = res.data.commission
|
||||
cardData.value.count = res.data.total
|
||||
cardData.value.gift_pulse = res.data.gift_pulse
|
||||
cardData.value.discount_number = res.data.discount_number
|
||||
} catch (error) {
|
||||
$message.error(error.msg)
|
||||
}
|
||||
|
||||
5
src/views/order/pending_list/api.js
Normal file
5
src/views/order/pending_list/api.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import { request } from '@/utils'
|
||||
|
||||
export default {
|
||||
getList: (data) => request.post('/later/order', data),
|
||||
}
|
||||
382
src/views/order/pending_list/index.vue
Normal file
382
src/views/order/pending_list/index.vue
Normal file
@@ -0,0 +1,382 @@
|
||||
<template>
|
||||
<CommonPage show-footer :title="$route.title">
|
||||
<n-row gutter="12">
|
||||
<n-col :span="24">
|
||||
<div flex>
|
||||
<n-card w-500 rounded-5 style="background-color: #5579e9">
|
||||
<n-statistic label="交易金额(元)" tabular-nums>
|
||||
<n-number-animation :from="0" :to="cardData.payments" :precision="2" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<n-card ml-10 w-500 rounded-5 style="background-color: #e74f5b">
|
||||
<n-statistic label="订单数量(条)" tabular-nums>
|
||||
<n-number-animation :from="0" :to="cardData.count" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<n-card ml-10 w-500 rounded-5 style="background-color: #00b4c3">
|
||||
<n-statistic label="赠送豆子(个)" tabular-nums>
|
||||
<n-number-animation :from="0" :to="cardData.total_pulse" :precision="2" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<n-card ml-10 w-500 rounded-5 style="background-color: #f1b301">
|
||||
<n-statistic label="挂帐(元)" tabular-nums>
|
||||
<n-number-animation :from="0" :to="cardData.onAccount" :precision="2" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<n-card ml-10 w-500 rounded-5 style="background-color: #ffa940">
|
||||
<n-statistic label="抹零(元)" tabular-nums>
|
||||
<n-number-animation :from="0" :to="cardData.zero" :precision="2" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="24" mt-10>
|
||||
<div>
|
||||
<span>订单状态:</span>
|
||||
<n-radio-group v-model:value="queryData.status">
|
||||
<n-radio-button
|
||||
v-for="song in songs"
|
||||
:key="song.value"
|
||||
:value="song.value"
|
||||
:label="song.label"
|
||||
/>
|
||||
</n-radio-group>
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="24">
|
||||
<div mt-10 flex items-center>
|
||||
<div w-100>关键字搜索:</div>
|
||||
<n-input-group>
|
||||
<n-select
|
||||
v-model:value="queryData.selectKey"
|
||||
:style="{ width: '25rem' }"
|
||||
:options="selectOptions"
|
||||
placeholder="请选择"
|
||||
/>
|
||||
<n-input v-model:value="queryData.word" :style="{ width: '20%' }" />
|
||||
</n-input-group>
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="10">
|
||||
<div mt-10 flex items-center>
|
||||
<span w-100>订单时间:</span>
|
||||
<n-date-picker
|
||||
v-model:formatted-value="queryData.time"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
type="datetimerange"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="24">
|
||||
<div mt-10>
|
||||
<n-button type="primary" @click="getList">搜索</n-button>
|
||||
<n-button type="primary" ml-10 @click="exportTable">导出表格</n-button>
|
||||
<n-button ml-10 @click="clear">重置</n-button>
|
||||
</div>
|
||||
</n-col>
|
||||
</n-row>
|
||||
<n-data-table
|
||||
ref="tableRef"
|
||||
class="mt-5"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
:scroll-x="1800"
|
||||
remote
|
||||
/>
|
||||
</CommonPage>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import api from './api'
|
||||
import * as XLSX from 'xlsx'
|
||||
import { NEllipsis, NButton, NPopconfirm } from 'naive-ui'
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const queryData = ref({
|
||||
status: '',
|
||||
time: null,
|
||||
word: '',
|
||||
selectKey: null,
|
||||
})
|
||||
|
||||
const songs = ref([
|
||||
{
|
||||
value: 1,
|
||||
label: '未付款',
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: '已付款',
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
label: '挂帐中',
|
||||
},
|
||||
])
|
||||
|
||||
const selectOptions = ref([
|
||||
{
|
||||
value: 0,
|
||||
label: '商品名称',
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
label: '用户昵称',
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: '手机号',
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
label: '订单号',
|
||||
},
|
||||
{
|
||||
value: 4,
|
||||
label: '商家名称',
|
||||
},
|
||||
])
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
title: '桌号',
|
||||
align: 'center',
|
||||
key: 'seat',
|
||||
},
|
||||
{
|
||||
title: '订单号',
|
||||
align: 'center',
|
||||
key: 'jl_oid',
|
||||
width: 150,
|
||||
fixed: 'left',
|
||||
},
|
||||
{
|
||||
title: '用户',
|
||||
align: 'center',
|
||||
slot: 'nickName',
|
||||
render: (row) => h('span', {}, { default: () => row.User.nickName }),
|
||||
},
|
||||
{
|
||||
title: '手机号',
|
||||
align: 'center',
|
||||
key: 'phone',
|
||||
},
|
||||
{
|
||||
title: '商品名称',
|
||||
align: 'center',
|
||||
slot: 'goods_name',
|
||||
render: (row) => {
|
||||
const el = []
|
||||
row.OrderGoods.forEach((item) => {
|
||||
el.push(
|
||||
h(
|
||||
NEllipsis,
|
||||
{
|
||||
style: 'max-width: 100px',
|
||||
},
|
||||
{
|
||||
default: () => `${item.Goods.name}|${item.pay_price}元|X${item.number}`,
|
||||
}
|
||||
)
|
||||
)
|
||||
})
|
||||
return el
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '商品数量',
|
||||
align: 'center',
|
||||
key: 'count',
|
||||
},
|
||||
{
|
||||
title: '商品总价',
|
||||
align: 'center',
|
||||
key: 'payments',
|
||||
},
|
||||
{
|
||||
title: '实付金额',
|
||||
align: 'center',
|
||||
key: 'pay_amount',
|
||||
},
|
||||
{
|
||||
title: '抹零',
|
||||
align: 'center',
|
||||
key: 'zero',
|
||||
},
|
||||
{
|
||||
title: '订单状态',
|
||||
align: 'center',
|
||||
slot: 'status',
|
||||
render(row) {
|
||||
switch (row.status) {
|
||||
case 0:
|
||||
return h('span', '未付款')
|
||||
case 1:
|
||||
return h('span', '已付款')
|
||||
case 2:
|
||||
return h('span', '挂帐中')
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '下单时间',
|
||||
align: 'center',
|
||||
key: 'add_time',
|
||||
},
|
||||
{
|
||||
title: '挂帐时间',
|
||||
align: 'center',
|
||||
key: 'on_account_time',
|
||||
},
|
||||
{
|
||||
title: '付款时间',
|
||||
align: 'center',
|
||||
key: 'payment_time',
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
align: 'center',
|
||||
key: 'notes',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
align: 'center',
|
||||
slot: 'action',
|
||||
width: 100,
|
||||
fixed: 'right',
|
||||
render(row) {
|
||||
return h(
|
||||
NPopconfirm,
|
||||
{},
|
||||
{
|
||||
default: () => '确定核销吗?',
|
||||
trigger: () =>
|
||||
h(
|
||||
NButton,
|
||||
{
|
||||
text: true,
|
||||
type: 'info',
|
||||
onClick: () => {
|
||||
console.log(row)
|
||||
},
|
||||
},
|
||||
{ default: () => '核销' }
|
||||
),
|
||||
}
|
||||
)
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const data = ref([])
|
||||
|
||||
const cardData = ref({
|
||||
total: 0,
|
||||
service: 0,
|
||||
count: 0,
|
||||
})
|
||||
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
itemCount: 0,
|
||||
showSizePicker: true,
|
||||
pageSizes: [10, 20, 50, 100],
|
||||
onChange: (page) => {
|
||||
pagination.value.page = page
|
||||
getList()
|
||||
},
|
||||
onUpdatePageSize: (pageSize) => {
|
||||
pagination.value.pageSize = pageSize
|
||||
pagination.value.page = 1
|
||||
getList()
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
|
||||
const getList = async () => {
|
||||
try {
|
||||
loading.value = true
|
||||
const query_data = {
|
||||
Status: queryData.value.status,
|
||||
StartTime: queryData.value.time === null ? '' : queryData.value.time[0] || '',
|
||||
EndTime: queryData.value.time === null ? '' : queryData.value.time[1] || '',
|
||||
}
|
||||
switch (queryData.value.selectKey) {
|
||||
case 0:
|
||||
query_data['GoodName'] = queryData.value.word
|
||||
break
|
||||
case 1:
|
||||
query_data['UserName'] = queryData.value.word
|
||||
break
|
||||
case 2:
|
||||
query_data['Phone'] = queryData.value.word
|
||||
break
|
||||
case 3:
|
||||
query_data['Oid'] = queryData.value.word
|
||||
break
|
||||
case 4:
|
||||
query_data['StoreName'] = queryData.value.word
|
||||
break
|
||||
}
|
||||
const res = await api.getList({
|
||||
PageNum: pagination.value.page,
|
||||
PageSize: pagination.value.pageSize,
|
||||
...query_data,
|
||||
})
|
||||
data.value = res.data.data || []
|
||||
pagination.value.itemCount = res.data.total
|
||||
cardData.value.payments = res.data.payments
|
||||
cardData.value.onAccount = res.data.onAccount
|
||||
cardData.value.total_pulse = res.data.total_pulse
|
||||
cardData.value.count = res.data.total
|
||||
loading.value = false
|
||||
} catch (error) {
|
||||
loading.value = false
|
||||
$message.error(error.msg)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
const clear = () => {
|
||||
queryData.value = {
|
||||
status: '',
|
||||
store_name: '',
|
||||
time: null,
|
||||
word: '',
|
||||
selectKey: null,
|
||||
}
|
||||
getList()
|
||||
}
|
||||
|
||||
const tableRef = ref()
|
||||
const exportTable = () => {
|
||||
// 将数据转换为工作簿
|
||||
const worksheet = XLSX.utils.json_to_sheet(data.value)
|
||||
const workbook = XLSX.utils.book_new()
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1')
|
||||
|
||||
// 生成Excel文件并触发下载
|
||||
XLSX.writeFile(workbook, 'table.xlsx')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.n-statistic__label) {
|
||||
color: #fff !important;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
:deep(.n-statistic-value__content) {
|
||||
color: #fff !important;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
6
src/views/system/agreement/api.js
Normal file
6
src/views/system/agreement/api.js
Normal file
@@ -0,0 +1,6 @@
|
||||
import { request } from '@/utils'
|
||||
|
||||
export default {
|
||||
getAgreement: () => request.post('/agreement'),
|
||||
updateAgreement: (data) => request.post('/edit/agreement', data),
|
||||
}
|
||||
43
src/views/system/agreement/index.vue
Normal file
43
src/views/system/agreement/index.vue
Normal file
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<CommonPage show-footer :title="$route.title">
|
||||
<n-tabs type="line" animated>
|
||||
<n-tab-pane name="1" tab="用户协议">
|
||||
<Editor v-model:value-html="model.user" :height="550" />
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="2" tab="隐私政策">
|
||||
<Editor v-model:value-html="model.policy" :height="550" />
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="3" tab="积分使用规则">
|
||||
<Editor v-model:value-html="model.integral" :height="550" />
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
<n-button v-perms="['/admin/edit/agreement']" mt-10 type="primary" @click="save">保存</n-button>
|
||||
</CommonPage>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import api from './api'
|
||||
import Editor from '@/components/Editor.vue'
|
||||
|
||||
const model = ref({
|
||||
user: '',
|
||||
policy: '',
|
||||
integral: '',
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
get_agreement()
|
||||
})
|
||||
|
||||
const get_agreement = async () => {
|
||||
const res = await api.getAgreement()
|
||||
model.value = res.data.data
|
||||
}
|
||||
|
||||
const save = async () => {
|
||||
const res = await api.updateAgreement(model.value)
|
||||
$message.success(res.msg)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
7
src/views/system/msgMag/index.vue
Normal file
7
src/views/system/msgMag/index.vue
Normal file
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<CommonPage show-footer :title="$route.title"></CommonPage>
|
||||
</template>
|
||||
|
||||
<script setup></script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
7
src/views/system/payMag/api.js
Normal file
7
src/views/system/payMag/api.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import { request } from '@/utils'
|
||||
|
||||
export default {
|
||||
getData: (data) => request.post('/paytype/list', data),
|
||||
add: (data) => request.post('/paytype/add', data),
|
||||
edit: (data) => request.post('/paytype/edit', data),
|
||||
}
|
||||
283
src/views/system/payMag/index.vue
Normal file
283
src/views/system/payMag/index.vue
Normal file
@@ -0,0 +1,283 @@
|
||||
<template>
|
||||
<CommonPage show-footer :title="$route.title">
|
||||
<n-button v-perms="['/admin/paytype/add']" type="primary" @click="openModal(1)">
|
||||
添加支付方式
|
||||
</n-button>
|
||||
<n-data-table
|
||||
class="mt-5"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
remote
|
||||
/>
|
||||
|
||||
<n-modal v-model:show="showModal">
|
||||
<n-card
|
||||
style="width: 600px"
|
||||
title="添加/编辑支付方式"
|
||||
:bordered="false"
|
||||
size="huge"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<n-form ref="formRef" :model="model" :rules="rules" label-placement="left">
|
||||
<n-grid :cols="24" :x-gap="24">
|
||||
<n-form-item-gi :span="16" label="支付图标:" path="icon">
|
||||
<Upload v-model:list="model.icon" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="16" label="支付名称:" path="name">
|
||||
<n-input v-model:value="model.name" placeholder="请输入支付名称" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="16" label="启用状态:">
|
||||
<n-switch v-model:value="model.status" :checked-value="1" :unchecked-value="2" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="16" label="余额状态:" path="state">
|
||||
<n-select
|
||||
v-model:value="model.state"
|
||||
:options="[
|
||||
{
|
||||
label: '无限',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: '有限',
|
||||
value: 2,
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi v-if="model.state === 2" :span="16" label="商家余额:" path="amount">
|
||||
<n-input-number v-model:value="model.amount" placeholder="请输入商家余额" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="18">
|
||||
<div m-auto>
|
||||
<n-button type="primary" @click="handleValidateClick">保存</n-button>
|
||||
<n-button ml-10 @click="clear">取消</n-button>
|
||||
</div>
|
||||
</n-form-item-gi>
|
||||
</n-grid>
|
||||
</n-form>
|
||||
</n-card>
|
||||
</n-modal>
|
||||
</CommonPage>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { h, withDirectives, resolveDirective } from 'vue'
|
||||
import api from './api'
|
||||
import { NTag, NButton } from 'naive-ui'
|
||||
import Upload from '@/components/Upload.vue'
|
||||
|
||||
const vPerms = resolveDirective('perms')
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
title: 'icon',
|
||||
slot: 'icon',
|
||||
align: 'center',
|
||||
render: (row) => {
|
||||
return h('img', {
|
||||
src: row.icon[0].url,
|
||||
width: 50,
|
||||
height: 50,
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '支付名称',
|
||||
key: 'name',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
slot: 'status',
|
||||
align: 'center',
|
||||
render: (row) => {
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
type: row.status === 1 ? 'success' : 'warning',
|
||||
},
|
||||
{
|
||||
default: () => (row.status === 1 ? '启用' : '禁用'),
|
||||
}
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '商家余额',
|
||||
slot: 'amount',
|
||||
align: 'center',
|
||||
render: (row) => {
|
||||
return h(
|
||||
'span',
|
||||
{},
|
||||
{
|
||||
default: () => (row.state === 1 ? '无限' : row.amount),
|
||||
}
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '余额状态',
|
||||
slot: 'state',
|
||||
align: 'center',
|
||||
render: (row) => {
|
||||
return h(
|
||||
'span',
|
||||
{},
|
||||
{
|
||||
default: () => (row.state === 1 ? '无限' : '有限'),
|
||||
}
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
slot: 'action',
|
||||
align: 'center',
|
||||
render: (row) => {
|
||||
return [
|
||||
withDirectives(
|
||||
h(
|
||||
NButton,
|
||||
{
|
||||
text: true,
|
||||
onClick: () => {
|
||||
openModal(2, row)
|
||||
},
|
||||
},
|
||||
{
|
||||
default: () => '编辑',
|
||||
}
|
||||
),
|
||||
[[vPerms, ['/admin/paytype/edit']]]
|
||||
),
|
||||
]
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const data = ref([])
|
||||
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
itemCount: 0,
|
||||
onChange: (page) => {
|
||||
pagination.value.page = page
|
||||
getList()
|
||||
},
|
||||
})
|
||||
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
const res = await api.getData({
|
||||
page: pagination.value.page,
|
||||
pageSize: pagination.value.pageSize,
|
||||
})
|
||||
data.value =
|
||||
res.data.data.map((item) => ({
|
||||
...item,
|
||||
icon: [
|
||||
{
|
||||
id: item.ID,
|
||||
url: item.icon,
|
||||
status: 'finished',
|
||||
},
|
||||
],
|
||||
})) || []
|
||||
// console.log(res)
|
||||
pagination.value.itemCount = res.data.total
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
const showModal = ref(false)
|
||||
|
||||
const model = ref({
|
||||
icon: [],
|
||||
name: '',
|
||||
status: 1,
|
||||
state: 1,
|
||||
amount: 0,
|
||||
})
|
||||
|
||||
const formRef = ref(null)
|
||||
|
||||
const rules = ref({
|
||||
icon: {
|
||||
required: true,
|
||||
type: 'array',
|
||||
message: '请上传图片',
|
||||
},
|
||||
name: {
|
||||
required: true,
|
||||
message: '请输入支付名称',
|
||||
},
|
||||
state: {
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '请选择余额状态',
|
||||
},
|
||||
amount: {
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '请输入商家余额',
|
||||
},
|
||||
})
|
||||
|
||||
const nowType = ref(1)
|
||||
|
||||
const openModal = (type, row = {}) => {
|
||||
nowType.value = type
|
||||
if (type === 2) {
|
||||
model.value = {
|
||||
...row,
|
||||
}
|
||||
}
|
||||
showModal.value = true
|
||||
}
|
||||
|
||||
const handleValidateClick = async (e) => {
|
||||
e.preventDefault()
|
||||
formRef.value?.validate(async (errors) => {
|
||||
if (!errors) {
|
||||
try {
|
||||
const data = {
|
||||
...model.value,
|
||||
icon: model.value.icon[0].url,
|
||||
}
|
||||
if (nowType.value === 1) {
|
||||
await api.add(data)
|
||||
} else {
|
||||
await api.edit(data)
|
||||
}
|
||||
clear()
|
||||
getList()
|
||||
} catch (error) {
|
||||
$message.error(error.msg)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
const clear = async () => {
|
||||
model.value = {
|
||||
icon: [],
|
||||
name: '',
|
||||
status: 1,
|
||||
state: 1,
|
||||
amount: 0,
|
||||
}
|
||||
showModal.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@@ -3,21 +3,21 @@
|
||||
<n-grid class="mb-10" x-gap="12">
|
||||
<n-gi :span="24">
|
||||
<div flex>
|
||||
<n-card w-250>
|
||||
<!-- <n-card w-250>
|
||||
<n-statistic label="用户总赢积分" tabular-nums>
|
||||
<n-number-animation ref="numberAnimationInstRef" :from="0" :to="cardData.win" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<n-card ml-10 w-250>
|
||||
</n-card> -->
|
||||
<n-card w-250>
|
||||
<n-statistic label="用户积分(留存)" tabular-nums>
|
||||
<n-number-animation ref="numberAnimationInstRef" :from="0" :to="cardData.integral" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<n-card ml-10 w-250>
|
||||
<!-- <n-card ml-10 w-250>
|
||||
<n-statistic label="总豆子" tabular-nums>
|
||||
<n-number-animation ref="numberAnimationInstRef" :from="0" :to="cardData.pulse" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
</n-card> -->
|
||||
<n-card ml-10 w-250>
|
||||
<n-statistic label="今日新增用户" tabular-nums>
|
||||
<n-number-animation
|
||||
@@ -27,7 +27,7 @@
|
||||
/>
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<n-card ml-10 w-250>
|
||||
<!-- <n-card ml-10 w-250>
|
||||
<n-statistic label="用户总流水(元)" tabular-nums>
|
||||
<n-number-animation
|
||||
ref="numberAnimationInstRef"
|
||||
@@ -36,8 +36,8 @@
|
||||
:precision="2"
|
||||
/>
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<n-card ml-10 w-250>
|
||||
</n-card> -->
|
||||
<!-- <n-card ml-10 w-250>
|
||||
<n-statistic label="总佣金(积分)" tabular-nums>
|
||||
<n-number-animation
|
||||
ref="numberAnimationInstRef"
|
||||
@@ -46,7 +46,7 @@
|
||||
:precision="2"
|
||||
/>
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
</n-card> -->
|
||||
<n-card ml-10 w-250>
|
||||
<n-statistic label="平台总用户" tabular-nums>
|
||||
<n-number-animation
|
||||
@@ -58,7 +58,7 @@
|
||||
</n-card>
|
||||
</div>
|
||||
</n-gi>
|
||||
<n-gi span="12" mt-10 flex items-center>
|
||||
<n-gi :span="12" mt-10 flex items-center>
|
||||
<span w-100>筛选条件:</span>
|
||||
<n-input-group>
|
||||
<n-select
|
||||
@@ -70,7 +70,7 @@
|
||||
<n-input v-model:value="queryParams.word" :style="{ width: '30%' }" />
|
||||
</n-input-group>
|
||||
</n-gi>
|
||||
<n-gi :span="24" mt-10>
|
||||
<!-- <n-gi :span="24" mt-10>
|
||||
<div>
|
||||
<span>筛选状态:</span>
|
||||
<n-radio-group v-model:value="queryParams.status">
|
||||
@@ -95,8 +95,8 @@
|
||||
/>
|
||||
</n-radio-group>
|
||||
</div>
|
||||
</n-gi>
|
||||
<n-gi :span="10">
|
||||
</n-gi> -->
|
||||
<n-gi :span="24">
|
||||
<div mt-10 flex items-center>
|
||||
<span w-100>时间筛选:</span>
|
||||
<n-date-picker
|
||||
@@ -279,40 +279,6 @@ const cardData = ref({
|
||||
win: 0,
|
||||
})
|
||||
|
||||
const songs = ref([
|
||||
{
|
||||
value: 1,
|
||||
label: '未使用',
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
label: '用户赢',
|
||||
},
|
||||
{
|
||||
value: 4,
|
||||
label: '用户输',
|
||||
},
|
||||
{
|
||||
value: 5,
|
||||
label: '已过期',
|
||||
},
|
||||
])
|
||||
|
||||
const songs1 = ref([
|
||||
{
|
||||
value: 5,
|
||||
label: '注册赠送',
|
||||
},
|
||||
{
|
||||
value: 6,
|
||||
label: '签到赠送',
|
||||
},
|
||||
{
|
||||
value: 7,
|
||||
label: '主动赠送',
|
||||
},
|
||||
])
|
||||
|
||||
const selectOptions = [
|
||||
{
|
||||
label: '用户昵称',
|
||||
@@ -364,20 +330,20 @@ const columns = ref([
|
||||
sorter: true,
|
||||
sortOrder: false,
|
||||
},
|
||||
{
|
||||
title: '赢积分',
|
||||
align: 'center',
|
||||
key: 'win',
|
||||
sorter: true,
|
||||
sortOrder: false,
|
||||
},
|
||||
{
|
||||
title: '用户豆子',
|
||||
align: 'center',
|
||||
key: 'pulse',
|
||||
sorter: true,
|
||||
sortOrder: false,
|
||||
},
|
||||
// {
|
||||
// title: '赢积分',
|
||||
// align: 'center',
|
||||
// key: 'win',
|
||||
// sorter: true,
|
||||
// sortOrder: false,
|
||||
// },
|
||||
// {
|
||||
// title: '用户豆子',
|
||||
// align: 'center',
|
||||
// key: 'pulse',
|
||||
// sorter: true,
|
||||
// sortOrder: false,
|
||||
// },
|
||||
{
|
||||
title: '用户状态',
|
||||
align: 'center',
|
||||
|
||||
@@ -12,7 +12,7 @@ export default {
|
||||
component: () => import('./index.vue'),
|
||||
meta: {
|
||||
title: '工作台',
|
||||
icon: 'mdi:home',
|
||||
icon: 'mdi:index',
|
||||
order: 0,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -13,6 +13,13 @@ export default defineConfig(({ command, mode }) => {
|
||||
const viteEnv = convertEnv(env)
|
||||
const { VITE_PORT, VITE_PUBLIC_PATH, VITE_USE_PROXY, VITE_BASE_API, VITE_SENTRY } = viteEnv
|
||||
|
||||
// 调试代理配置
|
||||
console.log('=== Vite代理配置调试 ===')
|
||||
console.log('VITE_USE_PROXY:', VITE_USE_PROXY)
|
||||
console.log('VITE_BASE_API:', VITE_BASE_API)
|
||||
console.log('PROXY_CONFIG:', PROXY_CONFIG)
|
||||
console.log('所有环境变量:', viteEnv)
|
||||
|
||||
return {
|
||||
base: VITE_PUBLIC_PATH || '/',
|
||||
resolve: {
|
||||
@@ -26,12 +33,10 @@ export default defineConfig(({ command, mode }) => {
|
||||
host: '0.0.0.0',
|
||||
port: VITE_PORT,
|
||||
open: false,
|
||||
proxy: VITE_USE_PROXY
|
||||
? {
|
||||
[VITE_BASE_API]: PROXY_CONFIG[VITE_BASE_API],
|
||||
'/api/v2': PROXY_CONFIG['/api/v2'],
|
||||
}
|
||||
: undefined,
|
||||
proxy: {
|
||||
'/api1': PROXY_CONFIG['/api1'],
|
||||
'/api': PROXY_CONFIG['/api'],
|
||||
},
|
||||
},
|
||||
build: {
|
||||
target: 'es2015',
|
||||
|
||||
Reference in New Issue
Block a user