first commit
21
.env
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
VITE_API_URL=
|
||||||
|
VITE_API_PREFIX=/api/v1
|
||||||
|
|
||||||
|
VITE_COMPANY_NAME=北京正信环宇科技有限公司
|
||||||
|
VITE_APP_NAME=愉悦查
|
||||||
|
|
||||||
|
VITE_INQUIRE_AES_KEY=ff83609b2b24fc73196aac3d3dfb874f
|
||||||
|
|
||||||
|
VITE_WECHAT_APP_ID=wxb786749edb73eb04
|
||||||
|
|
||||||
|
VITE_ICP_RECORD=京ICP备2025158088号-1
|
||||||
|
VITE_PUBLIC_SECURITY_RECORD=xxxxxxxxxxxxxx
|
||||||
|
VITE_SHOW_PUBLIC_SECURITY_RECORD=false
|
||||||
|
VITE_SERVICE_URL=https://work.weixin.qq.com/kfid/kfc93b53b25551b611d
|
||||||
|
VITE_CHAT_AES_KEY=qw5w6SFE2D1jmxyd
|
||||||
|
VITE_CHAT_AES_IV=345GDFED433223DF
|
||||||
|
|
||||||
|
VITE_SHARE_TITLE=愉悦查|大数据风险报告查询与代理平台,支持个人和企业多场景风控应用
|
||||||
|
VITE_SHARE_DESC=提供个人信用评估、入职背调、信贷风控、企业风险监测等服务
|
||||||
|
VITE_SHARE_IMG=https://www.yuyuecha.com/logo.png
|
||||||
|
VITE_TOKEN_VERSION=1.0
|
||||||
30
.gitignore
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
.DS_Store
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
coverage
|
||||||
|
*.local
|
||||||
|
|
||||||
|
/cypress/videos/
|
||||||
|
/cypress/screenshots/
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
|
|
||||||
|
*.tsbuildinfo
|
||||||
3
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"recommendations": ["Vue.volar"]
|
||||||
|
}
|
||||||
29
README.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# bdqr-webview-v2
|
||||||
|
|
||||||
|
This template should help get you started developing with Vue 3 in Vite.
|
||||||
|
|
||||||
|
## Recommended IDE Setup
|
||||||
|
|
||||||
|
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
|
||||||
|
|
||||||
|
## Customize configuration
|
||||||
|
|
||||||
|
See [Vite Configuration Reference](https://vite.dev/config/).
|
||||||
|
|
||||||
|
## Project Setup
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pnpm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compile and Hot-Reload for Development
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pnpm dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compile and Minify for Production
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pnpm build
|
||||||
|
```
|
||||||
23
env.example
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
VITE_API_URL=
|
||||||
|
VITE_API_PREFIX=/api/v1
|
||||||
|
|
||||||
|
VITE_COMPANY_NAME=北京正信环宇科技有限公司
|
||||||
|
VITE_APP_NAME=愉悦查
|
||||||
|
|
||||||
|
VITE_ICP_RECORD=京ICP备2025158088号-1
|
||||||
|
VITE_PUBLIC_SECURITY_RECORD=
|
||||||
|
VITE_SHOW_PUBLIC_SECURITY_RECORD=false
|
||||||
|
|
||||||
|
VITE_SERVICE_URL=https://work.weixin.qq.com/kfid/kfc93b53b25551b611d
|
||||||
|
VITE_INQUIRE_AES_KEY=ff83609b2b24fc73196aac3d3dfb874f
|
||||||
|
|
||||||
|
VITE_WECHAT_APP_ID=wx442ee1ac1ee75917
|
||||||
|
|
||||||
|
|
||||||
|
VITE_CHAT_AES_KEY=qw5w6SFE2D1jmxyd
|
||||||
|
VITE_CHAT_AES_IV=345GDFED433223DF
|
||||||
|
|
||||||
|
VITE_SHARE_TITLE=愉悦查|大数据风险报告查询与代理平台,支持个人和企业多场景风控应用
|
||||||
|
VITE_SHARE_DESC=提供个人信用评估、入职背调、信贷风控、企业风险监测等服务
|
||||||
|
VITE_SHARE_IMG=https://www.yuyuecha.com/logo.png
|
||||||
|
VITE_TOKEN_VERSION=1.0
|
||||||
213
index.html
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" href="/favicon.ico" />
|
||||||
|
<link
|
||||||
|
rel="apple-touch-icon"
|
||||||
|
sizes="180x180"
|
||||||
|
href="/apple-touch-icon.png"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="icon"
|
||||||
|
type="image/png"
|
||||||
|
sizes="32x32"
|
||||||
|
href="/favicon-32x32.png"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="icon"
|
||||||
|
type="image/png"
|
||||||
|
sizes="16x16"
|
||||||
|
href="/favicon-16x16.png"
|
||||||
|
/>
|
||||||
|
<link rel="manifest" href="/site.webmanifest" />
|
||||||
|
<meta
|
||||||
|
name="viewport"
|
||||||
|
content="width=device-width, initial-scale=1, maximum-scale=3, user-scalable=no"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 基础SEO信息 -->
|
||||||
|
<title>
|
||||||
|
愉悦查|大数据风险报告查询与代理平台,支持个人和企业多场景风控应用
|
||||||
|
</title>
|
||||||
|
<meta
|
||||||
|
name="description"
|
||||||
|
content="愉悦查,专业大数据风险报告查询与代理平台,支持个人信用查询、小微企业风控、贷前风险背调等多场景报告应用,免费开通代理权限,助力高效识别信用与风险。"
|
||||||
|
/>
|
||||||
|
<meta
|
||||||
|
name="keywords"
|
||||||
|
content="大数据风险报告查询、大数据风险评估、大数据分析报告、个人大数据风险查询、小微企业风险、贷前风险背调、代理管理平台、免费开通代理、风险管控平台、信用风险分析、企业风险报告、贷前信用审核、失信人名单查询、被执行人信息、信用黑名单查询"
|
||||||
|
/>
|
||||||
|
<meta name="author" content="愉悦查" />
|
||||||
|
<meta name="robots" content="index, follow" />
|
||||||
|
<meta name="googlebot" content="index, follow" />
|
||||||
|
<meta name="baidu-site-verification" content="" />
|
||||||
|
|
||||||
|
<!-- Open Graph / Facebook -->
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:url" content="https://www.zhinengcha.cn/" />
|
||||||
|
<meta
|
||||||
|
property="og:title"
|
||||||
|
content="愉悦查|大数据风险报告查询与代理平台,支持个人和企业多场景风控应用"
|
||||||
|
/>
|
||||||
|
<meta
|
||||||
|
property="og:description"
|
||||||
|
content="愉悦查,专业大数据风险报告查询与代理平台,支持个人信用查询、小微企业风控、贷前风险背调等多场景报告应用,免费开通代理权限,助力高效识别信用与风险。"
|
||||||
|
/>
|
||||||
|
<meta property="og:site_name" content="愉悦查" />
|
||||||
|
<meta property="og:locale" content="zh_CN" />
|
||||||
|
|
||||||
|
<!-- Twitter -->
|
||||||
|
<meta property="twitter:card" content="summary" />
|
||||||
|
<meta property="twitter:url" content="https://www.zhinengcha.cn/" />
|
||||||
|
<meta
|
||||||
|
property="twitter:title"
|
||||||
|
content="愉悦查|大数据风险报告查询与代理平台,支持个人和企业多场景风控应用"
|
||||||
|
/>
|
||||||
|
<meta
|
||||||
|
property="twitter:description"
|
||||||
|
content="愉悦查,专业大数据风险报告查询与代理平台,支持个人信用查询、小微企业风控、贷前风险背调等多场景报告应用,免费开通代理权限,助力高效识别信用与风险。"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 其他重要meta标签 -->
|
||||||
|
<meta name="theme-color" content="#3498db" />
|
||||||
|
<meta name="msapplication-TileColor" content="#3498db" />
|
||||||
|
<meta name="application-name" content="愉悦查" />
|
||||||
|
<meta name="apple-mobile-web-app-title" content="愉悦查" />
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||||
|
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
|
||||||
|
|
||||||
|
<!-- 结构化数据 -->
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "WebSite",
|
||||||
|
"name": "愉悦查",
|
||||||
|
"url": "https://www.zhinengcha.cn/",
|
||||||
|
"description": "专业大数据风险报告查询与代理平台,支持个人信用查询、小微企业风控、贷前风险背调等多场景报告应用",
|
||||||
|
"potentialAction": {
|
||||||
|
"@type": "SearchAction",
|
||||||
|
"target": "https://www.zhinengcha.cn/search?q={search_term_string}",
|
||||||
|
"query-input": "required name=search_term_string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "Organization",
|
||||||
|
"name": "愉悦查",
|
||||||
|
"url": "https://www.zhinengcha.cn/",
|
||||||
|
"description": "专业大数据风险报告查询与代理平台,支持个人和企业多场景风控应用"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
|
||||||
|
<script>
|
||||||
|
window.jWeixin = window.wx;
|
||||||
|
delete window.wx;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- 预加载关键资源 -->
|
||||||
|
<link rel="preconnect" href="https://www.zhinengcha.cn" />
|
||||||
|
<link rel="preconnect" href="https://res.wx.qq.com" />
|
||||||
|
<link rel="dns-prefetch" href="https://www.zhinengcha.cn" />
|
||||||
|
<link rel="dns-prefetch" href="https://res.wx.qq.com" />
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* 基础样式 */
|
||||||
|
html {
|
||||||
|
font-size: 16px;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
text-size-adjust: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
min-width: 320px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 确保所有元素在缩放时保持相对位置 */
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 防止水平滚动 */
|
||||||
|
#app {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式字体大小 */
|
||||||
|
@media screen and (max-width: 480px) {
|
||||||
|
html {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 481px) and (max-width: 768px) {
|
||||||
|
html {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 加载页面样式 */
|
||||||
|
#app-loading {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #fff;
|
||||||
|
z-index: 9999;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 加载动画 */
|
||||||
|
.loading-spinner {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
border: 5px solid #ccc;
|
||||||
|
border-top: 5px solid #3498db;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: spin 1s linear infinite;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
/* 与文字的间距 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 文字样式 */
|
||||||
|
.loading-text {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="app-loading">
|
||||||
|
<div class="loading-spinner"></div>
|
||||||
|
<div class="loading-text">加载中</div>
|
||||||
|
</div>
|
||||||
|
<div id="app"></div>
|
||||||
|
|
||||||
|
<script type="module" src="/src/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
8
jsconfig.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"exclude": ["node_modules", "dist"]
|
||||||
|
}
|
||||||
42
package.json
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"name": "bdqr-webview-v2",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@vant/area-data": "^2.0.0",
|
||||||
|
"@vueuse/core": "^11.3.0",
|
||||||
|
"axios": "^1.7.7",
|
||||||
|
"crypto-js": "^4.2.0",
|
||||||
|
"echarts": "^5.5.1",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"nprogress": "^0.2.0",
|
||||||
|
"pinia": "^2.2.6",
|
||||||
|
"qrcode": "^1.5.4",
|
||||||
|
"vant": "^4.9.9",
|
||||||
|
"vue": "^3.5.12",
|
||||||
|
"vue-echarts": "^7.0.3",
|
||||||
|
"vue-router": "^4.4.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vant/auto-import-resolver": "^1.2.1",
|
||||||
|
"@vitejs/plugin-vue": "^5.1.4",
|
||||||
|
"@vitejs/plugin-vue-jsx": "^4.0.1",
|
||||||
|
"autoprefixer": "^10.4.20",
|
||||||
|
"pinyin-pro": "^3.27.0",
|
||||||
|
"postcss": "^8.4.49",
|
||||||
|
"sass-embedded": "^1.81.0",
|
||||||
|
"tailwindcss": "^3.4.15",
|
||||||
|
"terser": "^5.43.1",
|
||||||
|
"unplugin-auto-import": "^0.18.5",
|
||||||
|
"unplugin-vue-components": "^0.27.5",
|
||||||
|
"vite": "^5.4.10",
|
||||||
|
"vite-plugin-vue-devtools": "^7.5.4"
|
||||||
|
},
|
||||||
|
"packageManager": "pnpm@10.9.0+sha512.0486e394640d3c1fb3c9d43d49cf92879ff74f8516959c235308f5a8f62e2e19528a65cdc2a3058f587cde71eba3d5b56327c8c33a97e4c4051ca48a10ca2d5f"
|
||||||
|
}
|
||||||
3402
pnpm-lock.yaml
generated
Normal file
6
postcss.config.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
};
|
||||||
BIN
public/favicon.ico
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
public/image/clickCaptcha.jpg
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
public/image/help/13.jpg
Normal file
|
After Width: | Height: | Size: 224 KiB |
BIN
public/image/help/14.jpg
Normal file
|
After Width: | Height: | Size: 224 KiB |
BIN
public/image/help/15.jpg
Normal file
|
After Width: | Height: | Size: 204 KiB |
BIN
public/image/help/18.jpg
Normal file
|
After Width: | Height: | Size: 864 KiB |
BIN
public/image/help/19.jpg
Normal file
|
After Width: | Height: | Size: 619 KiB |
BIN
public/image/help/20.jpg
Normal file
|
After Width: | Height: | Size: 558 KiB |
BIN
public/image/help/21.jpg
Normal file
|
After Width: | Height: | Size: 719 KiB |
BIN
public/image/help/22.jpg
Normal file
|
After Width: | Height: | Size: 878 KiB |
BIN
public/image/help/23.jpg
Normal file
|
After Width: | Height: | Size: 929 KiB |
BIN
public/image/help/24.jpg
Normal file
|
After Width: | Height: | Size: 259 KiB |
BIN
public/image/help/25.jpg
Normal file
|
After Width: | Height: | Size: 297 KiB |
BIN
public/image/help/direct-earnings.jpg
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
BIN
public/image/help/invite-earnings.jpg
Normal file
|
After Width: | Height: | Size: 886 KiB |
BIN
public/image/help/invite-step1.jpg
Normal file
|
After Width: | Height: | Size: 224 KiB |
BIN
public/image/help/invite-step2.jpg
Normal file
|
After Width: | Height: | Size: 258 KiB |
BIN
public/image/help/invite-step3.jpg
Normal file
|
After Width: | Height: | Size: 213 KiB |
BIN
public/image/help/report-calculation.jpg
Normal file
|
After Width: | Height: | Size: 367 KiB |
BIN
public/image/help/report-cost.jpg
Normal file
|
After Width: | Height: | Size: 307 KiB |
BIN
public/image/help/report-efficiency.jpg
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
public/image/help/report-push.jpg
Normal file
|
After Width: | Height: | Size: 940 KiB |
BIN
public/image/help/report-secret-1.jpg
Normal file
|
After Width: | Height: | Size: 2.1 MiB |
BIN
public/image/help/report-secret-2.jpg
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
public/image/help/report-step1.jpg
Normal file
|
After Width: | Height: | Size: 224 KiB |
BIN
public/image/help/report-step2.jpg
Normal file
|
After Width: | Height: | Size: 194 KiB |
BIN
public/image/help/report-step3.jpg
Normal file
|
After Width: | Height: | Size: 179 KiB |
BIN
public/image/help/report-step4.jpg
Normal file
|
After Width: | Height: | Size: 194 KiB |
BIN
public/image/help/report-step5.jpg
Normal file
|
After Width: | Height: | Size: 175 KiB |
BIN
public/image/help/report-types.jpg
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
public/image/help/vip-guide.jpg
Normal file
|
After Width: | Height: | Size: 257 KiB |
BIN
public/image/poster/backgroundcheck/backgroundcheck_01.png
Normal file
|
After Width: | Height: | Size: 340 KiB |
BIN
public/image/poster/backgroundcheck/backgroundcheck_02.png
Normal file
|
After Width: | Height: | Size: 345 KiB |
BIN
public/image/poster/backgroundcheck/backgroundcheck_03.png
Normal file
|
After Width: | Height: | Size: 323 KiB |
BIN
public/image/poster/backgroundcheck/backgroundcheck_04.png
Normal file
|
After Width: | Height: | Size: 347 KiB |
BIN
public/image/poster/companyinfo/companyinfo_01.png
Normal file
|
After Width: | Height: | Size: 324 KiB |
BIN
public/image/poster/companyinfo/companyinfo_02.png
Normal file
|
After Width: | Height: | Size: 366 KiB |
BIN
public/image/poster/companyinfo/companyinfo_03.png
Normal file
|
After Width: | Height: | Size: 375 KiB |
BIN
public/image/poster/companyinfo/companyinfo_04.png
Normal file
|
After Width: | Height: | Size: 313 KiB |
|
After Width: | Height: | Size: 395 KiB |
|
After Width: | Height: | Size: 328 KiB |
|
After Width: | Height: | Size: 358 KiB |
|
After Width: | Height: | Size: 343 KiB |
BIN
public/image/poster/homeservice/homeservice_01.png
Normal file
|
After Width: | Height: | Size: 324 KiB |
BIN
public/image/poster/homeservice/homeservice_02.png
Normal file
|
After Width: | Height: | Size: 338 KiB |
BIN
public/image/poster/homeservice/homeservice_03.png
Normal file
|
After Width: | Height: | Size: 343 KiB |
BIN
public/image/poster/homeservice/homeservice_04.png
Normal file
|
After Width: | Height: | Size: 336 KiB |
BIN
public/image/poster/invitation/invitation_01.png
Normal file
|
After Width: | Height: | Size: 421 KiB |
BIN
public/image/poster/invitation/invitation_02.png
Normal file
|
After Width: | Height: | Size: 356 KiB |
BIN
public/image/poster/invitation/invitation_03.png
Normal file
|
After Width: | Height: | Size: 356 KiB |
BIN
public/image/poster/invitation/invitation_04.png
Normal file
|
After Width: | Height: | Size: 321 KiB |
BIN
public/image/poster/marriage/marriage_01.png
Normal file
|
After Width: | Height: | Size: 324 KiB |
BIN
public/image/poster/marriage/marriage_02.png
Normal file
|
After Width: | Height: | Size: 324 KiB |
BIN
public/image/poster/marriage/marriage_03.png
Normal file
|
After Width: | Height: | Size: 335 KiB |
BIN
public/image/poster/marriage/marriage_04.png
Normal file
|
After Width: | Height: | Size: 331 KiB |
BIN
public/image/poster/riskassessment/riskassessment_01.png
Normal file
|
After Width: | Height: | Size: 391 KiB |
BIN
public/image/poster/riskassessment/riskassessment_02.png
Normal file
|
After Width: | Height: | Size: 387 KiB |
BIN
public/image/poster/riskassessment/riskassessment_03.png
Normal file
|
After Width: | Height: | Size: 380 KiB |
BIN
public/image/poster/riskassessment/riskassessment_04.png
Normal file
|
After Width: | Height: | Size: 376 KiB |
BIN
public/inquire_icons/benrenbuliang.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
public/inquire_icons/dashuju.png
Normal file
|
After Width: | Height: | Size: 870 B |
BIN
public/inquire_icons/default.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
public/inquire_icons/duiwaitouzi.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
public/inquire_icons/hunlianzhuangkuang.png
Normal file
|
After Width: | Height: | Size: 838 B |
BIN
public/inquire_icons/jiedaishenqing.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
public/inquire_icons/jingyingyichang.png
Normal file
|
After Width: | Height: | Size: 852 B |
BIN
public/inquire_icons/renzhijilu.png
Normal file
|
After Width: | Height: | Size: 977 B |
BIN
public/inquire_icons/rongzilishi.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
public/inquire_icons/shenqingxingwei.png
Normal file
|
After Width: | Height: | Size: 970 B |
BIN
public/inquire_icons/shesufengxian.png
Normal file
|
After Width: | Height: | Size: 983 B |
BIN
public/inquire_icons/shourupinggu.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
public/inquire_icons/sifashesu.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
public/inquire_icons/touzijilu.png
Normal file
|
After Width: | Height: | Size: 956 B |
BIN
public/inquire_icons/weiyueshixin.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
public/inquire_icons/xiehaozhuanwang.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
public/inquire_icons/xingzhengchufa.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
public/inquire_icons/xuelixinxi.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
public/inquire_icons/zaiwangshichang.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
public/inquire_icons/zhifubiaoxian.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
public/logo.png
Normal file
|
After Width: | Height: | Size: 196 KiB |
50
public/robots.txt
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
User-agent: *
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
# 允许访问主要页面
|
||||||
|
Allow: /agent
|
||||||
|
Allow: /help
|
||||||
|
Allow: /help/guide
|
||||||
|
Allow: /example
|
||||||
|
Allow: /service
|
||||||
|
Allow: /privacyPolicy
|
||||||
|
Allow: /userAgreement
|
||||||
|
Allow: /agentManageAgreement
|
||||||
|
Allow: /agentSerivceAgreement
|
||||||
|
Allow: /authorization
|
||||||
|
|
||||||
|
# 禁止访问私有页面
|
||||||
|
Disallow: /login
|
||||||
|
Disallow: /me
|
||||||
|
Disallow: /historyQuery
|
||||||
|
Disallow: /promote
|
||||||
|
Disallow: /withdraw
|
||||||
|
Disallow: /report
|
||||||
|
Disallow: /inquire/
|
||||||
|
Disallow: /payment/
|
||||||
|
Disallow: /agent/promoteDetails
|
||||||
|
Disallow: /agent/rewardsDetails
|
||||||
|
Disallow: /agent/promote
|
||||||
|
Disallow: /agent/invitation
|
||||||
|
Disallow: /agent/agentVip
|
||||||
|
Disallow: /agent/vipApply
|
||||||
|
Disallow: /agent/vipConfig
|
||||||
|
Disallow: /agent/withdraw
|
||||||
|
Disallow: /agent/withdrawDetails
|
||||||
|
Disallow: /agent/invitationAgentApply/
|
||||||
|
Disallow: /agent/subordinateList
|
||||||
|
Disallow: /agent/subordinateDetail/
|
||||||
|
|
||||||
|
# 禁止访问API接口
|
||||||
|
Disallow: /api/
|
||||||
|
|
||||||
|
# 禁止访问静态资源目录(可选)
|
||||||
|
Disallow: /assets/
|
||||||
|
Disallow: /js/
|
||||||
|
Disallow: /css/
|
||||||
|
|
||||||
|
# 网站地图
|
||||||
|
Sitemap: https://www.zhinengcha.cn/sitemap.xml
|
||||||
|
|
||||||
|
# 爬取延迟(毫秒)
|
||||||
|
Crawl-delay: 1
|
||||||
44
public/site.webmanifest
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"name": "愉悦查|大数据风险报告查询与代理平台,支持个人和企业多场景风控应用",
|
||||||
|
"short_name": "愉悦查",
|
||||||
|
"description": "专业大数据风险报告查询与代理平台,支持个人信用查询、小微企业风控、贷前风险背调等多场景报告应用",
|
||||||
|
"start_url": "/",
|
||||||
|
"display": "standalone",
|
||||||
|
"background_color": "#ffffff",
|
||||||
|
"theme_color": "#3498db",
|
||||||
|
"orientation": "portrait-primary",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "/favicon-16x16.png",
|
||||||
|
"sizes": "16x16",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/favicon-32x32.png",
|
||||||
|
"sizes": "32x32",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/apple-touch-icon.png",
|
||||||
|
"sizes": "180x180",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/android-chrome-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/android-chrome-512x512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"categories": [
|
||||||
|
"business",
|
||||||
|
"finance",
|
||||||
|
"utilities"
|
||||||
|
],
|
||||||
|
"lang": "zh-CN",
|
||||||
|
"dir": "ltr"
|
||||||
|
}
|
||||||
69
public/sitemap.xml
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
<url>
|
||||||
|
<loc>https://www.zhinengcha.cn/</loc>
|
||||||
|
<lastmod>2025-08-01</lastmod>
|
||||||
|
<changefreq>daily</changefreq>
|
||||||
|
<priority>1.0</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://www.zhinengcha.cn/agent</loc>
|
||||||
|
<lastmod>2025-08-01</lastmod>
|
||||||
|
<changefreq>weekly</changefreq>
|
||||||
|
<priority>0.8</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://www.zhinengcha.cn/help</loc>
|
||||||
|
<lastmod>2025-08-01</lastmod>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://www.zhinengcha.cn/help/guide</loc>
|
||||||
|
<lastmod>2025-08-01</lastmod>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.6</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://www.zhinengcha.cn/example</loc>
|
||||||
|
<lastmod>2025-08-01</lastmod>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.6</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://www.zhinengcha.cn/service</loc>
|
||||||
|
<lastmod>2025-08-01</lastmod>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.5</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://www.zhinengcha.cn/privacyPolicy</loc>
|
||||||
|
<lastmod>2025-08-01</lastmod>
|
||||||
|
<changefreq>yearly</changefreq>
|
||||||
|
<priority>0.3</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://www.zhinengcha.cn/userAgreement</loc>
|
||||||
|
<lastmod>2025-08-01</lastmod>
|
||||||
|
<changefreq>yearly</changefreq>
|
||||||
|
<priority>0.3</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://www.zhinengcha.cn/agentManageAgreement</loc>
|
||||||
|
<lastmod>2025-08-01</lastmod>
|
||||||
|
<changefreq>yearly</changefreq>
|
||||||
|
<priority>0.3</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://www.zhinengcha.cn/agentSerivceAgreement</loc>
|
||||||
|
<lastmod>2025-08-01</lastmod>
|
||||||
|
<changefreq>yearly</changefreq>
|
||||||
|
<priority>0.3</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://www.zhinengcha.cn/authorization</loc>
|
||||||
|
<lastmod>2025-08-01</lastmod>
|
||||||
|
<changefreq>yearly</changefreq>
|
||||||
|
<priority>0.3</priority>
|
||||||
|
</url>
|
||||||
|
</urlset>
|
||||||
152
scripts/generate-dictionaries.js
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
const projectRoot = path.resolve(__dirname, '..');
|
||||||
|
|
||||||
|
const FILE_CONFIGS = [
|
||||||
|
{
|
||||||
|
input: path.join(projectRoot, 'IVYZ3P9M_学历信息查询(实时版)_返回字段说明.md'),
|
||||||
|
output: path.join(projectRoot, 'src', 'data', 'ivyz3p9m-dictionary.json'),
|
||||||
|
handler: parseIvyz3p9mDictionary,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: path.join(projectRoot, '多头借贷小时级_返回字段说明.md'),
|
||||||
|
output: path.join(projectRoot, 'src', 'data', 'multiLoanHourlyDictionary.json'),
|
||||||
|
handler: parseMultiLoanDictionary,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
function parseMarkdownTable(sectionContent, predicate = () => true) {
|
||||||
|
const rows = [];
|
||||||
|
|
||||||
|
sectionContent.split('\n').forEach((line) => {
|
||||||
|
if (!line.trim().startsWith('|')) return;
|
||||||
|
|
||||||
|
const cells = line
|
||||||
|
.split('|')
|
||||||
|
.slice(1, -1)
|
||||||
|
.map((cell) => cell.trim());
|
||||||
|
|
||||||
|
if (cells.length === 0) return;
|
||||||
|
if (cells.some((cell) => /^-+$/.test(cell))) return;
|
||||||
|
|
||||||
|
if (predicate(cells)) {
|
||||||
|
rows.push(cells);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseIvyz3p9mDictionary(markdown) {
|
||||||
|
const result = {
|
||||||
|
educationLevel: {},
|
||||||
|
learningForm: {},
|
||||||
|
specialties: {},
|
||||||
|
schools: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
const sections = markdown.split(/\n(?=## )/);
|
||||||
|
|
||||||
|
sections.forEach((rawSection) => {
|
||||||
|
const headerMatch = rawSection.match(/^##\s*(.+)\n/);
|
||||||
|
if (!headerMatch) return;
|
||||||
|
|
||||||
|
const title = headerMatch[1].trim();
|
||||||
|
const body = rawSection.slice(headerMatch[0].length);
|
||||||
|
|
||||||
|
const isEducation = /学历层次/.test(title);
|
||||||
|
const isLearning = /学习形式/.test(title);
|
||||||
|
const isSchool = /学校/.test(title);
|
||||||
|
const isSpecialty = /专业/.test(title);
|
||||||
|
|
||||||
|
if (!(isEducation || isLearning || isSchool || isSpecialty)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rows = parseMarkdownTable(body, (cells) => cells.length >= 2);
|
||||||
|
|
||||||
|
rows.forEach((cells) => {
|
||||||
|
const code = cells[0];
|
||||||
|
const name = cells[1];
|
||||||
|
if (!code || !name) return;
|
||||||
|
|
||||||
|
if (isEducation) {
|
||||||
|
result.educationLevel[code] = name;
|
||||||
|
} else if (isLearning) {
|
||||||
|
result.learningForm[code] = name;
|
||||||
|
} else if (isSchool) {
|
||||||
|
result.schools[code] = name;
|
||||||
|
} else if (isSpecialty) {
|
||||||
|
result.specialties[code] = name;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseMultiLoanDictionary(markdown) {
|
||||||
|
const dictionary = {};
|
||||||
|
let headerCells = [];
|
||||||
|
|
||||||
|
markdown.split('\n').forEach((line) => {
|
||||||
|
if (!line.trim().startsWith('|')) return;
|
||||||
|
|
||||||
|
const cells = line
|
||||||
|
.split('|')
|
||||||
|
.slice(1, -1)
|
||||||
|
.map((cell) => cell.trim());
|
||||||
|
|
||||||
|
if (cells.some((cell) => /^-+$/.test(cell))) return;
|
||||||
|
if (cells.length < 2) return;
|
||||||
|
|
||||||
|
if (cells.includes('标签代码')) {
|
||||||
|
headerCells = cells;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (headerCells.length === 0) return;
|
||||||
|
|
||||||
|
const data = Object.fromEntries(headerCells.map((header, index) => [header, cells[index] || '']));
|
||||||
|
const code = data['标签代码'];
|
||||||
|
if (!code) return;
|
||||||
|
|
||||||
|
dictionary[code] = {
|
||||||
|
productName: data['产品名称'] || '',
|
||||||
|
labelCategory: data['标签类别'] || '',
|
||||||
|
description: data['业务含义'] || '',
|
||||||
|
dataType: data['类型'] || '',
|
||||||
|
length: data['长度'] || '',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return dictionary;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureDirectoryExists(filePath) {
|
||||||
|
const dir = path.dirname(filePath);
|
||||||
|
fs.mkdirSync(dir, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
function run() {
|
||||||
|
FILE_CONFIGS.forEach(({ input, output, handler }) => {
|
||||||
|
if (!fs.existsSync(input)) {
|
||||||
|
console.warn(`Input file not found: ${input}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const markdown = fs.readFileSync(input, 'utf-8');
|
||||||
|
const data = handler(markdown);
|
||||||
|
|
||||||
|
ensureDirectoryExists(output);
|
||||||
|
fs.writeFileSync(output, JSON.stringify(data, null, 2), 'utf-8');
|
||||||
|
console.log(`Generated dictionary: ${path.relative(projectRoot, output)}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
run();
|
||||||
|
|
||||||
321
src/App.vue
Normal file
@@ -0,0 +1,321 @@
|
|||||||
|
<script setup>
|
||||||
|
import { RouterView, useRouter, useRoute } from "vue-router";
|
||||||
|
const { isWeChat } = useEnv();
|
||||||
|
import { useAgentStore } from "@/stores/agentStore";
|
||||||
|
import { useUserStore } from "@/stores/userStore";
|
||||||
|
import { useDialogStore } from "@/stores/dialogStore";
|
||||||
|
import { useAuthStore } from "@/stores/authStore";
|
||||||
|
import { useAppStore } from "@/stores/appStore";
|
||||||
|
import { useWeixinShare } from "@/composables/useWeixinShare";
|
||||||
|
import BindPhoneDialog from "@/components/BindPhoneDialog.vue";
|
||||||
|
import BindPhoneOnlyDialog from "@/components/BindPhoneOnlyDialog.vue";
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const route = useRoute();
|
||||||
|
const agentStore = useAgentStore();
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const dialogStore = useDialogStore();
|
||||||
|
const authStore = useAuthStore();
|
||||||
|
const appStore = useAppStore();
|
||||||
|
const { setDynamicShare } = useWeixinShare();
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
// 初始化应用配置
|
||||||
|
await appStore.fetchAppConfig();
|
||||||
|
|
||||||
|
// 恢复微信授权状态(页面刷新或回调时)
|
||||||
|
authStore.restoreFromStorage();
|
||||||
|
|
||||||
|
// 检查是否是微信授权回调
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
const code = url.searchParams.get("code");
|
||||||
|
const state = url.searchParams.get("state");
|
||||||
|
|
||||||
|
if (code && state) {
|
||||||
|
// 这是微信授权回调,处理授权结果
|
||||||
|
console.log("Handling WeChat auth callback");
|
||||||
|
await handleWeixinAuthCallback(code);
|
||||||
|
} else {
|
||||||
|
// 正常初始化:加载用户信息等
|
||||||
|
await initializeApp();
|
||||||
|
}
|
||||||
|
getWeixinAuthUrl();
|
||||||
|
|
||||||
|
// 延迟配置微信分享
|
||||||
|
setTimeout(async () => {
|
||||||
|
if (isWeChat.value && window.jWeixin) {
|
||||||
|
await setDynamicShare();
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
// 监听路由变化更新分享配置
|
||||||
|
router.afterEach(async () => {
|
||||||
|
if (isWeChat.value && window.jWeixin && !authStore.isWeixinAuthing) {
|
||||||
|
await setDynamicShare();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理微信授权回调
|
||||||
|
*/
|
||||||
|
const handleWeixinAuthCallback = async (code) => {
|
||||||
|
try {
|
||||||
|
console.log("🔄 WeChat auth callback: code=", code);
|
||||||
|
|
||||||
|
// 调用后端接口交换 token
|
||||||
|
const { data, error } = await useApiFetch("/user/wxh5Auth")
|
||||||
|
.post({ code })
|
||||||
|
.json();
|
||||||
|
|
||||||
|
console.log("📡 wxh5Auth response:", {
|
||||||
|
code: data.value?.code,
|
||||||
|
hasToken: !!data.value?.data?.accessToken,
|
||||||
|
error: error.value
|
||||||
|
});
|
||||||
|
|
||||||
|
if (data.value && !error.value && data.value.code === 200) {
|
||||||
|
// 保存 token
|
||||||
|
const token = data.value.data.accessToken;
|
||||||
|
localStorage.setItem("token", token);
|
||||||
|
localStorage.setItem("refreshAfter", data.value.data.refreshAfter);
|
||||||
|
localStorage.setItem("accessExpire", data.value.data.accessExpire);
|
||||||
|
// ⚠️ 重要:保存 token 后立即设置 tokenVersion,防止被 checkTokenVersion 清除
|
||||||
|
const tokenVersion = import.meta.env.VITE_TOKEN_VERSION || "1.1";
|
||||||
|
localStorage.setItem("tokenVersion", tokenVersion);
|
||||||
|
|
||||||
|
console.log("✅ Token saved successfully, token:", token.substring(0, 20) + "...");
|
||||||
|
console.log("✅ Token saved to localStorage, userId:", data.value.data.userId || "unknown");
|
||||||
|
console.log(`✅ TokenVersion set to ${tokenVersion}`);
|
||||||
|
|
||||||
|
// 验证 token 是否真的保存成功
|
||||||
|
const savedToken = localStorage.getItem("token");
|
||||||
|
if (savedToken === token) {
|
||||||
|
console.log("✅ Token verification: localStorage中的token与保存的token一致");
|
||||||
|
} else {
|
||||||
|
console.error("❌ Token verification failed: localStorage中的token与保存的token不一致");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除 URL 中的 code 和 state 参数
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
const params = new URLSearchParams(url.search);
|
||||||
|
params.delete("code");
|
||||||
|
params.delete("state");
|
||||||
|
const newUrl = `${url.origin}${url.pathname}${params.toString() ? "?" + params.toString() : ""}`;
|
||||||
|
window.history.replaceState({}, "", newUrl);
|
||||||
|
console.log("✅ URL cleaned, removed code and state parameters");
|
||||||
|
|
||||||
|
// 获取用户信息
|
||||||
|
console.log("👤 Fetching user info...");
|
||||||
|
try {
|
||||||
|
await userStore.fetchUserInfo();
|
||||||
|
console.log("✅ User info fetched:", {
|
||||||
|
mobile: userStore.mobile,
|
||||||
|
isLoggedIn: userStore.isLoggedIn
|
||||||
|
});
|
||||||
|
} catch (userInfoErr) {
|
||||||
|
console.error("❌ Failed to fetch user info:", userInfoErr);
|
||||||
|
// 用户信息获取失败,清除 token,跳转到登录
|
||||||
|
authStore.resetAuthState();
|
||||||
|
await router.replace("/login");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取代理信息(已登录用户都尝试获取,后端会判断是否是代理)
|
||||||
|
try {
|
||||||
|
await agentStore.fetchAgentStatus();
|
||||||
|
} catch (agentErr) {
|
||||||
|
console.warn("Warning: Failed to fetch agent status:", agentErr);
|
||||||
|
// 不中断流程,只是警告
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标记授权完成
|
||||||
|
authStore.completeWeixinAuth();
|
||||||
|
console.log("✅ WeChat auth marked as complete");
|
||||||
|
|
||||||
|
// 获取 pendingRoute 并跳转
|
||||||
|
const pendingRoute = authStore.pendingRoute
|
||||||
|
console.log("🎯 pendingRoute:", pendingRoute);
|
||||||
|
|
||||||
|
// if (pendingRoute) {
|
||||||
|
// // ⚠️ 重要:必须先跳转再清除,否则清除后 pendingRoute 为 null
|
||||||
|
// console.log("🚀 Navigating to pendingRoute:", pendingRoute);
|
||||||
|
// await router.replace(pendingRoute);
|
||||||
|
// authStore.clearPendingRoute();
|
||||||
|
// console.log("✅ Navigated to pendingRoute and cleared it");
|
||||||
|
// } else {
|
||||||
|
// // 默认跳转到首页
|
||||||
|
// console.log("📍 No pendingRoute found, navigating to home");
|
||||||
|
// await router.replace("/");
|
||||||
|
// }
|
||||||
|
} else {
|
||||||
|
console.error("❌ WeChat auth failed:", {
|
||||||
|
code: data.value?.code,
|
||||||
|
message: data.value?.msg || data.value?.message,
|
||||||
|
error: error.value
|
||||||
|
});
|
||||||
|
|
||||||
|
// 授权失败,重置状态
|
||||||
|
authStore.resetAuthState();
|
||||||
|
// 跳转到登录页
|
||||||
|
await router.replace("/login");
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("❌ Error handling WeChat auth callback:", err);
|
||||||
|
authStore.resetAuthState();
|
||||||
|
await router.replace("/login");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化应用:检查 token,加载用户信息
|
||||||
|
*/
|
||||||
|
const initializeApp = async () => {
|
||||||
|
// 检查 token 版本
|
||||||
|
checkTokenVersion();
|
||||||
|
|
||||||
|
// 尝试刷新 token
|
||||||
|
await refreshTokenIfNeeded();
|
||||||
|
|
||||||
|
// 如果有 token,加载用户信息和代理信息
|
||||||
|
const token = localStorage.getItem("token");
|
||||||
|
if (token) {
|
||||||
|
try {
|
||||||
|
await userStore.fetchUserInfo();
|
||||||
|
// 已登录用户都尝试获取代理信息,后端会判断是否是代理
|
||||||
|
await agentStore.fetchAgentStatus();
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error loading user info:", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查 token 版本,清除不兼容的旧 token
|
||||||
|
* ⚠️ 注意:只有在确实需要清除旧 token 时才清除,避免误清除新保存的 token
|
||||||
|
*/
|
||||||
|
const checkTokenVersion = () => {
|
||||||
|
const CURRENT_TOKEN_VERSION = import.meta.env.VITE_TOKEN_VERSION || "1.1";
|
||||||
|
const storedVersion = localStorage.getItem("tokenVersion");
|
||||||
|
const hasToken = !!localStorage.getItem("token");
|
||||||
|
|
||||||
|
// 如果 tokenVersion 不存在或版本不匹配
|
||||||
|
if (!storedVersion || storedVersion !== CURRENT_TOKEN_VERSION) {
|
||||||
|
// 只有在有 token 的情况下才清除(避免清除刚保存的新 token)
|
||||||
|
if (hasToken) {
|
||||||
|
console.log(`Token version mismatch: storedVersion=${storedVersion}, currentVersion=${CURRENT_TOKEN_VERSION}, clearing old auth data`);
|
||||||
|
// Token 版本不匹配,清除旧数据
|
||||||
|
localStorage.removeItem("token");
|
||||||
|
localStorage.removeItem("refreshAfter");
|
||||||
|
localStorage.removeItem("accessExpire");
|
||||||
|
localStorage.removeItem("userInfo");
|
||||||
|
localStorage.removeItem("agentInfo");
|
||||||
|
}
|
||||||
|
// 无论是否有 token,都设置新的 tokenVersion
|
||||||
|
localStorage.setItem("tokenVersion", CURRENT_TOKEN_VERSION);
|
||||||
|
} else {
|
||||||
|
console.log(`Token version check passed: storedVersion=${storedVersion}, currentVersion=${CURRENT_TOKEN_VERSION}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在需要时刷新 token
|
||||||
|
*/
|
||||||
|
const refreshTokenIfNeeded = async () => {
|
||||||
|
const token = localStorage.getItem("token");
|
||||||
|
if (!token) return;
|
||||||
|
|
||||||
|
const accessExpire = localStorage.getItem("accessExpire");
|
||||||
|
const refreshAfter = localStorage.getItem("refreshAfter");
|
||||||
|
const now = Date.now();
|
||||||
|
|
||||||
|
// 检查 token 是否已过期
|
||||||
|
if (accessExpire) {
|
||||||
|
const expireTime = parseInt(accessExpire) * 1000;
|
||||||
|
if (now > expireTime) {
|
||||||
|
console.log("Token expired");
|
||||||
|
return; // Token 已过期,不刷新,由路由守卫处理
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否需要刷新
|
||||||
|
if (refreshAfter) {
|
||||||
|
const refreshTime = parseInt(refreshAfter) * 1000;
|
||||||
|
if (now < refreshTime) {
|
||||||
|
return; // 还不需要刷新
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行 token 刷新
|
||||||
|
try {
|
||||||
|
const { data, error } = await useApiFetch("/user/getToken").post().json();
|
||||||
|
if (data.value && !error.value && data.value.code === 200) {
|
||||||
|
localStorage.setItem("token", data.value.data.accessToken);
|
||||||
|
localStorage.setItem("refreshAfter", data.value.data.refreshAfter);
|
||||||
|
localStorage.setItem("accessExpire", data.value.data.accessExpire);
|
||||||
|
console.log("Token refreshed successfully");
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error refreshing token:", err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发起微信授权 URL
|
||||||
|
* 这个逻辑已经在路由守卫中实现了
|
||||||
|
* 这里保留这个函数的备份,以防需要其他地方调用
|
||||||
|
*/
|
||||||
|
const getWeixinAuthUrl = () => {
|
||||||
|
const isAuthenticated = localStorage.getItem("token");
|
||||||
|
|
||||||
|
// 检查 token 是否过期
|
||||||
|
const accessExpire = localStorage.getItem("accessExpire");
|
||||||
|
const now = Date.now();
|
||||||
|
let isTokenExpired = false;
|
||||||
|
if (accessExpire) {
|
||||||
|
isTokenExpired = now > parseInt(accessExpire) * 1000;
|
||||||
|
}
|
||||||
|
console.log("WeChat auth check:", {
|
||||||
|
isWeChat: isWeChat.value,
|
||||||
|
isAuthenticated,
|
||||||
|
isTokenExpired
|
||||||
|
});
|
||||||
|
if (isWeChat.value && !isAuthenticated && !isTokenExpired) {
|
||||||
|
console.log("🔄 Initiating WeChat auth flow");
|
||||||
|
// 如果正在授权中或已完成授权,则阻止重复授权
|
||||||
|
console.log("Auth store state:", {
|
||||||
|
isWeixinAuthing: authStore.isWeixinAuthing,
|
||||||
|
weixinAuthComplete: authStore.weixinAuthComplete
|
||||||
|
});
|
||||||
|
if (authStore.isWeixinAuthing || authStore.weixinAuthComplete) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 保存目标路由
|
||||||
|
authStore.startWeixinAuth(route);
|
||||||
|
console.log("🔖 Saved pendingRoute for WeChat auth:", route.fullPath);
|
||||||
|
const appId = import.meta.env.VITE_WECHAT_APP_ID;
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
const params = new URLSearchParams(url.search);
|
||||||
|
params.delete("code");
|
||||||
|
params.delete("state");
|
||||||
|
const cleanUrl = `${url.origin}${url.pathname}${params.toString() ? "?" + params.toString() : ""
|
||||||
|
}`;
|
||||||
|
const redirectUri = encodeURIComponent(cleanUrl);
|
||||||
|
const weixinAuthUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirectUri}&response_type=code&scope=snsapi_base&state=snsapi_base#wechat_redirect`;
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
"🔄 Triggering WeChat auth from route guard, pendingRoute:",
|
||||||
|
route.fullPath
|
||||||
|
);
|
||||||
|
window.location.href = weixinAuthUrl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<RouterView />
|
||||||
|
<BindPhoneDialog />
|
||||||
|
<BindPhoneOnlyDialog />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
280
src/api/agent.js
Normal file
@@ -0,0 +1,280 @@
|
|||||||
|
import useApiFetch from "@/composables/useApiFetch";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 代理相关API调用统一管理
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建查询字符串的辅助函数
|
||||||
|
* @param {object} params - 查询参数对象
|
||||||
|
* @returns {string} 查询字符串
|
||||||
|
*/
|
||||||
|
function buildQueryString(params) {
|
||||||
|
const queryParams = new URLSearchParams();
|
||||||
|
Object.keys(params).forEach((key) => {
|
||||||
|
if (
|
||||||
|
params[key] !== undefined &&
|
||||||
|
params[key] !== null &&
|
||||||
|
params[key] !== ""
|
||||||
|
) {
|
||||||
|
queryParams.append(key, params[key]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const queryString = queryParams.toString();
|
||||||
|
return queryString ? `?${queryString}` : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 公开接口(无需登录) ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取推广链接数据
|
||||||
|
* @param {string} linkIdentifier - 推广链接标识
|
||||||
|
*/
|
||||||
|
export function getLinkData(linkIdentifier) {
|
||||||
|
return useApiFetch(
|
||||||
|
`/agent/link?link_identifier=${encodeURIComponent(linkIdentifier)}`
|
||||||
|
)
|
||||||
|
.get()
|
||||||
|
.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过邀请码申请成为代理(已注册用户)
|
||||||
|
* @param {object} params - 申请参数
|
||||||
|
* @param {string} params.mobile - 手机号
|
||||||
|
* @param {string} params.code - 验证码
|
||||||
|
* @param {string} params.invite_code - 邀请码(必填)
|
||||||
|
* @param {string} params.region - 区域(可选)
|
||||||
|
*/
|
||||||
|
export function applyForAgent(params) {
|
||||||
|
return useApiFetch("/agent/apply").post(params).json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过邀请码注册(同时注册用户和代理)
|
||||||
|
* @param {object} params - 注册参数
|
||||||
|
* @param {string} params.mobile - 手机号
|
||||||
|
* @param {string} params.code - 验证码
|
||||||
|
* @param {string} params.invite_code - 邀请码(必填)
|
||||||
|
* @param {string} params.region - 区域(可选)
|
||||||
|
* @param {string} params.wechat_id - 微信号(可选)
|
||||||
|
*/
|
||||||
|
export function registerByInviteCode(params) {
|
||||||
|
return useApiFetch("/agent/register/invite").post(params).json();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 需要登录的接口 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取代理信息
|
||||||
|
*/
|
||||||
|
export function getAgentInfo() {
|
||||||
|
return useApiFetch("/agent/info").get().json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取代理等级特权信息
|
||||||
|
*/
|
||||||
|
export function getLevelPrivilege() {
|
||||||
|
return useApiFetch("/agent/level/privilege").get().json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成推广链接
|
||||||
|
* @param {object} params - 生成参数
|
||||||
|
* @param {number} params.product_id - 产品ID
|
||||||
|
* @param {number} params.set_price - 设定价格
|
||||||
|
*/
|
||||||
|
export function generateLink(params) {
|
||||||
|
return useApiFetch("/agent/generating_link").post(params).json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取产品配置
|
||||||
|
*/
|
||||||
|
export function getProductConfig() {
|
||||||
|
return useApiFetch("/agent/product_config").get().json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取团队统计
|
||||||
|
*/
|
||||||
|
export function getTeamStatistics() {
|
||||||
|
return useApiFetch("/agent/team/statistics").get().json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取团队列表
|
||||||
|
* @param {object} params - 查询参数
|
||||||
|
* @param {number} params.page - 页码
|
||||||
|
* @param {number} params.page_size - 每页数量
|
||||||
|
*/
|
||||||
|
export function getTeamList(params) {
|
||||||
|
const queryString = buildQueryString(params || {});
|
||||||
|
return useApiFetch(`/agent/team/list${queryString}`).get().json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取下级列表
|
||||||
|
* @param {object} params - 查询参数
|
||||||
|
* @param {number} params.page - 页码
|
||||||
|
* @param {number} params.page_size - 每页数量
|
||||||
|
*/
|
||||||
|
export function getSubordinateList(params) {
|
||||||
|
const queryString = buildQueryString(params || {});
|
||||||
|
return useApiFetch(`/agent/subordinate/list${queryString}`).get().json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取收益信息
|
||||||
|
*/
|
||||||
|
export function getRevenueInfo() {
|
||||||
|
return useApiFetch("/agent/revenue").get().json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取转化率统计
|
||||||
|
*/
|
||||||
|
export function getConversionRate() {
|
||||||
|
return useApiFetch("/agent/conversion/rate").get().json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取佣金记录
|
||||||
|
* @param {object} params - 查询参数
|
||||||
|
* @param {number} params.page - 页码
|
||||||
|
* @param {number} params.page_size - 每页数量
|
||||||
|
*/
|
||||||
|
export function getCommissionList(params) {
|
||||||
|
const queryString = buildQueryString(params || {});
|
||||||
|
return useApiFetch(`/agent/commission/list${queryString}`).get().json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取返佣记录(推广返佣)
|
||||||
|
* @param {object} params - 查询参数
|
||||||
|
* @param {number} params.page - 页码
|
||||||
|
* @param {number} params.page_size - 每页数量
|
||||||
|
* @param {number} params.rebate_type - 返佣类型(可选):1=直接上级返佣,2=钻石上级返佣,3=黄金上级返佣
|
||||||
|
*/
|
||||||
|
export function getRebateList(params) {
|
||||||
|
const queryString = buildQueryString(params || {});
|
||||||
|
return useApiFetch(`/agent/rebate/list${queryString}`).get().json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取升级返佣记录
|
||||||
|
* @param {object} params - 查询参数
|
||||||
|
* @param {number} params.page - 页码
|
||||||
|
* @param {number} params.page_size - 每页数量
|
||||||
|
*/
|
||||||
|
export function getUpgradeRebateList(params) {
|
||||||
|
const queryString = buildQueryString(params || {});
|
||||||
|
return useApiFetch(`/agent/rebate/upgrade/list${queryString}`).get().json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取升级记录
|
||||||
|
* @param {object} params - 查询参数
|
||||||
|
* @param {number} params.page - 页码
|
||||||
|
* @param {number} params.page_size - 每页数量
|
||||||
|
*/
|
||||||
|
export function getUpgradeList(params) {
|
||||||
|
const queryString = buildQueryString(params || {});
|
||||||
|
return useApiFetch(`/agent/upgrade/list${queryString}`).get().json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 申请升级
|
||||||
|
* @param {object} params - 升级参数
|
||||||
|
* @param {number} params.to_level - 目标等级:2=黄金,3=钻石
|
||||||
|
*/
|
||||||
|
export function applyUpgrade(params) {
|
||||||
|
return useApiFetch("/agent/upgrade/apply").post(params).json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 钻石代理升级下级
|
||||||
|
* @param {object} params - 升级参数
|
||||||
|
* @param {number} params.subordinate_id - 下级代理ID
|
||||||
|
* @param {number} params.to_level - 目标等级(只能是2=黄金)
|
||||||
|
*/
|
||||||
|
export function upgradeSubordinate(params) {
|
||||||
|
return useApiFetch("/agent/upgrade/subordinate").post(params).json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取提现列表
|
||||||
|
* @param {object} params - 查询参数
|
||||||
|
* @param {number} params.page - 页码
|
||||||
|
* @param {number} params.page_size - 每页数量
|
||||||
|
*/
|
||||||
|
export function getWithdrawalList(params) {
|
||||||
|
const queryString = buildQueryString(params || {});
|
||||||
|
return useApiFetch(`/agent/withdrawal/list${queryString}`).get().json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 申请提现
|
||||||
|
* @param {object} params - 提现参数
|
||||||
|
* @param {number} params.amount - 提现金额
|
||||||
|
* @param {string} params.payee_account - 收款账户
|
||||||
|
* @param {string} params.payee_name - 收款人姓名
|
||||||
|
*/
|
||||||
|
export function applyWithdrawal(params) {
|
||||||
|
return useApiFetch("/agent/withdrawal/apply").post(params).json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实名认证
|
||||||
|
* @param {object} params - 实名认证参数
|
||||||
|
* @param {string} params.name - 姓名
|
||||||
|
* @param {string} params.id_card - 身份证号
|
||||||
|
* @param {string} params.mobile - 手机号
|
||||||
|
* @param {string} params.code - 验证码
|
||||||
|
*/
|
||||||
|
export function realNameAuth(params) {
|
||||||
|
return useApiFetch("/agent/real_name").post(params).json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成邀请码
|
||||||
|
* @param {object} params - 生成参数
|
||||||
|
* @param {number} params.count - 生成数量
|
||||||
|
* @param {number} params.expire_days - 过期天数(可选,0表示不过期)
|
||||||
|
* @param {string} params.remark - 备注(可选)
|
||||||
|
*/
|
||||||
|
export function generateInviteCode(params) {
|
||||||
|
return useApiFetch("/agent/invite_code/generate").post(params).json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取邀请码列表
|
||||||
|
* @param {object} params - 查询参数
|
||||||
|
* @param {number} params.page - 页码
|
||||||
|
* @param {number} params.page_size - 每页数量
|
||||||
|
* @param {number} params.status - 状态(可选):0=未使用,1=已使用,2=已失效
|
||||||
|
*/
|
||||||
|
export function getInviteCodeList(params) {
|
||||||
|
const queryString = buildQueryString(params || {});
|
||||||
|
return useApiFetch(`/agent/invite_code/list${queryString}`).get().json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除邀请码
|
||||||
|
* @param {object} params - 删除参数
|
||||||
|
* @param {number} params.id - 邀请码ID
|
||||||
|
*/
|
||||||
|
export function deleteInviteCode(params) {
|
||||||
|
return useApiFetch("/agent/invite_code/delete").post(params).json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取邀请链接
|
||||||
|
* @param {object} params - 请求参数
|
||||||
|
* @param {string} params.invite_code - 邀请码
|
||||||
|
*/
|
||||||
|
export function getInviteLink(params) {
|
||||||
|
const queryString = buildQueryString(params || {});
|
||||||
|
return useApiFetch(`/agent/invite_link${queryString}`).get().json();
|
||||||
|
}
|
||||||
31
src/api/user.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
import useApiFetch from "@/composables/useApiFetch";
|
||||||
|
|
||||||
|
// 获取API基础URL(与生产规则一致:VITE_API_URL)
|
||||||
|
const baseURL = import.meta.env.VITE_API_URL;
|
||||||
|
|
||||||
|
// 手机号验证码登录
|
||||||
|
export function mobileCodeLogin(params) {
|
||||||
|
return useApiFetch("/user/mobileCodeLogin").post(params).json();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统一认证
|
||||||
|
export function unifiedAuth(params) {
|
||||||
|
return useApiFetch("/user/auth").post(params).json();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绑定手机号
|
||||||
|
export function bindMobile(params) {
|
||||||
|
return useApiFetch("/user/bindMobile").post(params).json();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注销账号API
|
||||||
|
export function cancelAccount() {
|
||||||
|
return axios({
|
||||||
|
method: "post",
|
||||||
|
url: `${baseURL}/api/user/cancel`,
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
26
src/assets/base.css
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
html {
|
||||||
|
margin: auto !important;
|
||||||
|
@apply max-w-lg;
|
||||||
|
/* 确保在缩放时保持响应式 */
|
||||||
|
min-width: 320px;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
min-height: 100vh;
|
||||||
|
transition: color 0.5s, background-color 0.5s;
|
||||||
|
line-height: 1.6;
|
||||||
|
font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||||
|
Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||||
|
sans-serif;
|
||||||
|
font-size: 15px;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
202
src/assets/colors.css
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
* 统一颜色变量管理文件
|
||||||
|
* 用于规范化项目中的所有颜色使用
|
||||||
|
* 支持颜色统一管理
|
||||||
|
*/
|
||||||
|
|
||||||
|
:root {
|
||||||
|
/* ===== 主题色系 ===== */
|
||||||
|
--color-primary: #FF6A19;
|
||||||
|
--color-primary-second: #FF8A3D;
|
||||||
|
--color-primary-50: #fff5f0;
|
||||||
|
--color-primary-100: #ffebe1;
|
||||||
|
--color-primary-200: #ffd7c3;
|
||||||
|
--color-primary-300: #ffc3a5;
|
||||||
|
--color-primary-400: #ffaf87;
|
||||||
|
--color-primary-500: #FF6A19;
|
||||||
|
--color-primary-600: #cc5534;
|
||||||
|
--color-primary-700: #994028;
|
||||||
|
--color-primary-800: #662b1c;
|
||||||
|
--color-primary-900: #33150e;
|
||||||
|
|
||||||
|
/* 主题色透明度变体 */
|
||||||
|
--color-primary-light: rgba(255, 106, 25, 0.1);
|
||||||
|
--color-primary-medium: rgba(255, 106, 25, 0.15);
|
||||||
|
--color-primary-dark: rgba(255, 106, 25, 0.8);
|
||||||
|
|
||||||
|
/* ===== 语义化颜色 ===== */
|
||||||
|
--color-success: #07c160;
|
||||||
|
--color-success-50: #f0f9f0;
|
||||||
|
--color-success-100: #e1f5e1;
|
||||||
|
--color-success-200: #c3ebc3;
|
||||||
|
--color-success-300: #a5e1a5;
|
||||||
|
--color-success-400: #87d787;
|
||||||
|
--color-success-500: #07c160;
|
||||||
|
--color-success-600: #059a4c;
|
||||||
|
--color-success-700: #047338;
|
||||||
|
--color-success-800: #024c24;
|
||||||
|
--color-success-900: #012510;
|
||||||
|
--color-success-light: rgba(7, 193, 96, 0.1);
|
||||||
|
--color-success-dark: rgba(7, 193, 96, 0.8);
|
||||||
|
|
||||||
|
--color-warning: #ff976a;
|
||||||
|
--color-warning-50: #fff5f0;
|
||||||
|
--color-warning-100: #ffebe1;
|
||||||
|
--color-warning-200: #ffd7c3;
|
||||||
|
--color-warning-300: #ffc3a5;
|
||||||
|
--color-warning-400: #ffaf87;
|
||||||
|
--color-warning-500: #ff976a;
|
||||||
|
--color-warning-600: #cc7955;
|
||||||
|
--color-warning-700: #995b40;
|
||||||
|
--color-warning-800: #663d2a;
|
||||||
|
--color-warning-900: #331f15;
|
||||||
|
--color-warning-light: rgba(255, 151, 106, 0.1);
|
||||||
|
--color-warning-dark: rgba(255, 151, 106, 0.8);
|
||||||
|
|
||||||
|
--color-danger: #ee0a24;
|
||||||
|
--color-danger-light: rgba(238, 10, 36, 0.1);
|
||||||
|
--color-danger-dark: rgba(238, 10, 36, 0.8);
|
||||||
|
|
||||||
|
--color-info: #1989fa;
|
||||||
|
--color-info-light: rgba(25, 137, 250, 0.1);
|
||||||
|
--color-info-dark: rgba(25, 137, 250, 0.8);
|
||||||
|
|
||||||
|
/* ===== 中性色系 ===== */
|
||||||
|
--color-gray-50: #fafafa;
|
||||||
|
--color-gray-100: #f5f5f5;
|
||||||
|
--color-gray-200: #e5e5e5;
|
||||||
|
--color-gray-300: #d4d4d4;
|
||||||
|
--color-gray-400: #a3a3a3;
|
||||||
|
--color-gray-500: #737373;
|
||||||
|
--color-gray-600: #525252;
|
||||||
|
--color-gray-700: #404040;
|
||||||
|
--color-gray-800: #262626;
|
||||||
|
--color-gray-900: #171717;
|
||||||
|
|
||||||
|
/* ===== 文本颜色 ===== */
|
||||||
|
--color-text-primary: #323233;
|
||||||
|
--color-text-secondary: #646566;
|
||||||
|
--color-text-tertiary: #969799;
|
||||||
|
--color-text-quaternary: #c8c9cc;
|
||||||
|
--color-text-disabled: #c8c9cc;
|
||||||
|
--color-text-white: #ffffff;
|
||||||
|
|
||||||
|
/* ===== 背景颜色 ===== */
|
||||||
|
--color-bg-primary: #ffffff;
|
||||||
|
--color-bg-secondary: #fafafa;
|
||||||
|
--color-bg-tertiary: #f8f8f8;
|
||||||
|
--color-bg-quaternary: #f2f3f5;
|
||||||
|
--color-bg-overlay: rgba(0, 0, 0, 0.5);
|
||||||
|
--color-bg-mask: rgba(0, 0, 0, 0.8);
|
||||||
|
|
||||||
|
/* ===== 边框颜色 ===== */
|
||||||
|
--color-border-primary: #ebedf0;
|
||||||
|
--color-border-secondary: #f2f3f5;
|
||||||
|
--color-border-tertiary: #dcdee0;
|
||||||
|
--color-border-focus: var(--color-primary);
|
||||||
|
|
||||||
|
/* ===== 状态颜色 ===== */
|
||||||
|
--color-active: #f2f3f5;
|
||||||
|
--color-hover: rgba(0, 0, 0, 0.05);
|
||||||
|
--color-focus: var(--color-primary-light);
|
||||||
|
|
||||||
|
/* ===== 阴影颜色 ===== */
|
||||||
|
--color-shadow-light: rgba(0, 0, 0, 0.1);
|
||||||
|
--color-shadow-medium: rgba(0, 0, 0, 0.15);
|
||||||
|
--color-shadow-dark: rgba(0, 0, 0, 0.2);
|
||||||
|
|
||||||
|
/* ===== 业务特定颜色 ===== */
|
||||||
|
--color-service-personal: #FF6A19; /* 个人大数据 */
|
||||||
|
--color-service-company: #FF8A3D; /* 小微企业 */
|
||||||
|
--color-service-loan: #FFB366; /* 贷前背调 */
|
||||||
|
|
||||||
|
/* ===== 渐变色彩 ===== */
|
||||||
|
--gradient-primary: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
var(--color-primary-400),
|
||||||
|
var(--color-primary-600)
|
||||||
|
);
|
||||||
|
--gradient-success: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
var(--color-success),
|
||||||
|
var(--color-success-dark)
|
||||||
|
);
|
||||||
|
--gradient-warning: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
var(--color-warning),
|
||||||
|
var(--color-warning-dark)
|
||||||
|
);
|
||||||
|
--gradient-danger: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
var(--color-danger),
|
||||||
|
var(--color-danger-dark)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 工具类 ===== */
|
||||||
|
.text-primary {
|
||||||
|
color: var(--color-primary) !important;
|
||||||
|
}
|
||||||
|
.text-primary-second {
|
||||||
|
color: var(--color-primary-second) !important;
|
||||||
|
}
|
||||||
|
.text-success {
|
||||||
|
color: var(--color-success) !important;
|
||||||
|
}
|
||||||
|
.text-warning {
|
||||||
|
color: var(--color-warning) !important;
|
||||||
|
}
|
||||||
|
.text-danger {
|
||||||
|
color: var(--color-danger) !important;
|
||||||
|
}
|
||||||
|
.text-info {
|
||||||
|
color: var(--color-info) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-primary {
|
||||||
|
background-color: var(--color-primary) !important;
|
||||||
|
}
|
||||||
|
.bg-primary-second {
|
||||||
|
background-color: var(--color-primary-second) !important;
|
||||||
|
}
|
||||||
|
.bg-success {
|
||||||
|
background-color: var(--color-success) !important;
|
||||||
|
}
|
||||||
|
.bg-warning {
|
||||||
|
background-color: var(--color-warning) !important;
|
||||||
|
}
|
||||||
|
.bg-danger {
|
||||||
|
background-color: var(--color-danger) !important;
|
||||||
|
}
|
||||||
|
.bg-info {
|
||||||
|
background-color: var(--color-info) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-primary {
|
||||||
|
border-color: var(--color-primary) !important;
|
||||||
|
}
|
||||||
|
.border-primary-second {
|
||||||
|
border-color: var(--color-primary-second) !important;
|
||||||
|
}
|
||||||
|
.border-success {
|
||||||
|
border-color: var(--color-success) !important;
|
||||||
|
}
|
||||||
|
.border-warning {
|
||||||
|
border-color: var(--color-warning) !important;
|
||||||
|
}
|
||||||
|
.border-danger {
|
||||||
|
border-color: var(--color-danger) !important;
|
||||||
|
}
|
||||||
|
.border-info {
|
||||||
|
border-color: var(--color-info) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 响应式颜色工具类 ===== */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.text-primary-mobile {
|
||||||
|
color: var(--color-primary) !important;
|
||||||
|
}
|
||||||
|
.bg-primary-mobile {
|
||||||
|
background-color: var(--color-primary) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
src/assets/images/banner.png
Normal file
|
After Width: | Height: | Size: 49 KiB |