Browse Source

✨ feat:init

zbb 2 hours ago
parent
commit
9b8d7c7892

+ 1 - 1
App.vue

@@ -35,4 +35,4 @@
 		color: #333;
 		padding: 10px;
 	}
-</style>
+</style>

+ 9 - 4
api/index.js

@@ -6,15 +6,20 @@ import request from './request.js'
 // 用户相关接口
 export const userApi = {
 	// 发送验证码
-	sendCode: (data) => request.post('/api/auth/send-code', data),
-	
+	sendCode: (data) => request.post('/oa/code/sendCode', data, headers: {
+		isToken: false,
+	}, ),
+	codeLogin: (data) => request.post('/codeLogin', data, headers: {
+		isToken: false
+	}, ),
+
 	// 手机号登录
 	login: (data) => request.post('/api/auth/login', data),
-	
+
 	// 获取用户信息
 	getUserInfo: () => request.get('/api/user/info')
 }
 
 export default {
 	user: userApi
-}
+}

+ 33 - 0
api/login.js

@@ -0,0 +1,33 @@
+import http from "/utils/request.js";
+// 获取验证码
+let sendCode = (data) => http.post('/oa/code/sendCode', data);
+// 验证码登录
+let codeLogin = (data) => http.post('/codeLogin', data);
+// 微信一键登录
+let wxgetLogin = (data) => http.post('/xcxLogin', data);
+// 退出登录
+let logout = (data) => http.post('/logout', data);
+// 获取用户信息
+let getUserInfo = (data) => http.get('/home/user/enter/userInfo', data);
+// 一键登录获取code
+let wxLogin = () => {
+  return new Promise((resolve, reject) => {
+    uni.login({
+      success(res) {
+        uni.setStorageSync('code', res.code)
+        resolve(res.code)
+      },
+      fail() {
+        reject(new Error('获取微信登录码失败'))
+      }
+    })
+  })
+};
+export {
+  sendCode,
+  codeLogin,
+  wxgetLogin,
+  logout,
+  getUserInfo,
+  wxLogin
+};

+ 0 - 31
api/user.js

@@ -1,31 +0,0 @@
-/**
- * 用户相关接口
- */
-import request from './request.js'
-
-/**
- * 发送验证码
- */
-export const sendCode = (data) => {
-	return request.post('/api/auth/send-code', data)
-}
-
-/**
- * 手机号登录
- */
-export const login = (data) => {
-	return request.post('/api/auth/login', data)
-}
-
-/**
- * 获取用户信息
- */
-export const getUserInfo = () => {
-	return request.get('/api/user/info')
-}
-
-export default {
-	sendCode,
-	login,
-	getUserInfo
-}

+ 28 - 38
config/README.md

@@ -37,36 +37,42 @@ const CURRENT_ENV = 'development'
 
 ## 使用方式
 
-### 在 request 中使用(已自动集成
+### 方式一:在 Vue 组件中使用(推荐
 
-```javascript
-import request from '@/utils/request.js'
-// 会自动使用对应环境的 baseUrl
-await request.post('/api/auth/login', data)
+```vue
+<script setup>
+import config from '@/config/index.js'
+
+// 直接访问配置
+console.log('API 地址:', config.baseUrl)
+console.log('应用名称:', config.appName)
+console.log('AppID:', config.appId)
+</script>
 ```
 
-### 在组件中获取配置
+### 方式二:在 JS 文件中使用
 
 ```javascript
-import { getCurrentConfig } from '@/config/index.js'
+import config from '@/config/index.js'
 
-const config = await getCurrentConfig()
-console.log('当前环境:', config.env)
-console.log('API 地址:', config.baseUrl)
-console.log('应用名称:', config.appName)
-console.log('AppID:', config.appId)
+console.log(config.baseUrl)
+console.log(config.appName)
 ```
 
-### 在 JS 文件中获取配置
+### 方式三:在 request 中使用(已自动集成)
 
 ```javascript
-import { getCurrentConfig, CURRENT_ENV } from '@/config/index.js'
+import request from '@/utils/request.js'
+// 会自动使用对应环境的 baseUrl
+await request.post('/api/auth/login', data)
+```
 
-// 获取当前环境标识
-console.log('当前环境:', CURRENT_ENV)
+### 方式四:获取特定环境变量
 
-// 获取完整配置
-const config = await getCurrentConfig()
+```javascript
+import { CURRENT_ENV } from '@/config/index.js'
+
+console.log('当前环境:', CURRENT_ENV)
 ```
 
 ## 修改配置
@@ -86,24 +92,8 @@ export default {
 }
 ```
 
-## 添加新环境
-
-1. 创建新文件 `config/env.<name>.js`
-2. 在 `config/index.js` 的 `envConfigMap` 中添加映射
-3. 修改 `CURRENT_ENV` 为新环境名
+## 注意事项
 
-示例:
-
-```javascript
-// config/env.staging.js
-export default {
-	env: 'staging',
-	baseUrl: 'https://staging-api.example.com',
-	timeout: 10000,
-	appName: '布尔销销乐',
-	appVersion: '1.0.0',
-	appId: 'wx6124d881774fb80a',
-	debug: true,
-	enableLog: true
-}
-```
+1. **小程序限制**:微信小程序不支持动态 `import()`,使用同步导入
+2. **切换环境后**:需要重新编译/运行项目才能生效
+3. **默认配置**:如果 `CURRENT_ENV` 配置错误,会自动使用开发环境配置

+ 5 - 3
config/env.development.js

@@ -5,8 +5,10 @@ export default {
 	// 环境标识
 	env: 'development',
 	
-	// API 配置
-	baseUrl: 'https://dev-api.example.com',
+	// 测试
+	baseUrl: 'http://192.168.0.170:8102',
+	// 本地
+	baseUrl: 'http://192.168.0.59:8102',
 	timeout: 10000,
 	
 	// 应用信息
@@ -14,7 +16,7 @@ export default {
 	appVersion: '1.0.0',
 	
 	// 微信小程序配置
-	appId: 'wx6124d881774fb80a',
+	appId: 'wx58740a080a90e5f2',
 	
 	// 调试配置
 	debug: true,

+ 1 - 1
config/env.production.js

@@ -14,7 +14,7 @@ export default {
 	appVersion: '1.0.0',
 	
 	// 微信小程序配置
-	appId: 'wx6124d881774fb80a',
+	appId: 'wx58740a080a90e5f2',
 	
 	// 调试配置
 	debug: false,

+ 15 - 29
config/index.js

@@ -6,40 +6,26 @@
 // 手动修改此处切换环境:development | test | production
 const CURRENT_ENV = 'development'
 
+// 同步导入所有环境配置
+import developmentConfig from './env.development.js'
+import productionConfig from './env.production.js'
+
 // 环境配置映射
 const envConfigMap = {
-	development: () => import('./env.development.js'),
-	production: () => import('./env.production.js')
+	development: developmentConfig,
+	production: productionConfig
 }
 
 // 获取当前环境配置
-const getCurrentConfig = async () => {
-	const configLoader = envConfigMap[CURRENT_ENV] || envConfigMap.development
-	try {
-		const config = await configLoader()
-		return config.default
-	} catch (error) {
-		console.error('加载环境配置失败:', error)
-		// 返回默认配置
-		return {
-			env: 'development',
-			baseUrl: 'https://dev-api.example.com',
-			timeout: 10000,
-			appName: '布尔销销乐',
-			appVersion: '1.0.0',
-			appId: 'wx6124d881774fb80a',
-			debug: true,
-			enableLog: true
-		}
-	}
+const getCurrentConfig = () => {
+	return envConfigMap[CURRENT_ENV] || developmentConfig
 }
 
-// 同步获取配置(用于初始化)
-const getSyncConfig = () => {
-	const configLoader = envConfigMap[CURRENT_ENV] || envConfigMap.development
-	// 注意:这里是同步导入,实际使用时建议用异步
-	return configLoader().then(m => m.default)
-}
+// 导出当前配置
+const config = getCurrentConfig()
+
+console.log('当前环境:', config.env, '| API 地址:', config.baseUrl)
 
-export { CURRENT_ENV, getCurrentConfig, getSyncConfig }
-export default getCurrentConfig
+export { CURRENT_ENV }
+export default config
+export { getCurrentConfig }

+ 27 - 26
manifest.json

@@ -50,7 +50,7 @@
     /* 快应用特有相关 */
     "mp-weixin" : {
         /* 小程序特有相关 */
-        "appid" : "wx6124d881774fb80a",
+        "appid" : "wx58740a080a90e5f2",
         "setting" : {
             "urlCheck" : false,
             "es6" : true,
@@ -64,31 +64,32 @@
             "selectedColor" : "#667eea",
             "backgroundColor" : "#ffffff",
             "borderStyle" : "black",
-            "list" : [{
-				"pagePath": "pages/index/index",
-				"text": "首页",
-				"iconPath": "static/tabbar/tabbar-home.png",
-				"selectedIconPath": "static/tabbar/tabbar-home-active.png"
-			},
-			{
-				"pagePath": "pages/todos/index",
-				"text": "待办",
-				"iconPath": "static/tabbar/tabbar-todo.png",
-				"selectedIconPath": "static/tabbar/tabbar-todo-active.png"
-			},
-			{
-				"pagePath": "pages/message/index",
-				"text": "消息",
-				"iconPath": "static/tabbar/tabbar-message.png",
-				"selectedIconPath": "static/tabbar/tabbar-message-active.png"
-			},
-			{
-				"pagePath": "pages/mine/index",
-				"text": "我的",
-				"iconPath": "static/tabbar/tabbar-mine.png",
-				"selectedIconPath": "static/tabbar/tabbar-mine-active.png"
-			}
-		]
+            "list" : [
+                {
+                    "pagePath" : "pages/index/index",
+                    "text" : "首页",
+                    "iconPath" : "static/tabbar/tabbar-home.png",
+                    "selectedIconPath" : "static/tabbar/tabbar-home-active.png"
+                },
+                {
+                    "pagePath" : "pages/todos/index",
+                    "text" : "待办",
+                    "iconPath" : "static/tabbar/tabbar-todo.png",
+                    "selectedIconPath" : "static/tabbar/tabbar-todo-active.png"
+                },
+                {
+                    "pagePath" : "pages/message/index",
+                    "text" : "消息",
+                    "iconPath" : "static/tabbar/tabbar-message.png",
+                    "selectedIconPath" : "static/tabbar/tabbar-message-active.png"
+                },
+                {
+                    "pagePath" : "pages/mine/index",
+                    "text" : "我的",
+                    "iconPath" : "static/tabbar/tabbar-mine.png",
+                    "selectedIconPath" : "static/tabbar/tabbar-mine-active.png"
+                }
+            ]
         }
     },
     "vueVersion" : "3"

+ 52 - 18
pages/index/index.vue

@@ -1,15 +1,18 @@
 <template>
 	<view class="index-container">
 		<!-- 顶部背景 -->
-		<view class="top-bg"></view>
+		<image class="top-bg" src="/static/image/home/top-bg.png"  />
 		<NavBar title="" color="#020202" :fixed="true" :bg="'transparent'">
 			<template #left>
-				<view class="left-title">布尔销销乐</view>
+				<view class="left-title">{{appName}}</view>
 			</template>
 		</NavBar>
 		<view class="page-warp">
 			<view class="page-top">
 				<view class="user-card">
+					<!-- 背景图 -->
+					<image class="user-card-bg" src="/static/image/home/usecard-bg.png"  />
+
 					<!-- 左上:姓名 + 职位 -->
 					<view class="user-header">
 						<view class="name-row">
@@ -21,8 +24,8 @@
 
 					<!-- 右上:头像 -->
 					<view class="avatar-wrapper">
-						<image class="avatar" src="/static/image/public/avatar-default.png" mode="aspectFill" />
-						<image class="badge-icon" src="/static/image/public/badge-icon.png" mode="aspectFill" />
+						<image class="avatar" src="/static/image/public/avatar-default.png"  />
+						<image class="badge-icon" src="/static/image/public/badge-icon.png"  />
 					</view>
 
 					<!-- 左下:联系方式 -->
@@ -240,15 +243,32 @@
 <script setup>
 	import NavBar from '@/components/nav-bar/index.vue'
 	import CardPreview from './components/card-preview.vue'
-	import { ref, onMounted, computed } from 'vue'
-	import { useUserStore } from '@/store/modules/user.js'
-	import { storeToRefs } from 'pinia'
-
+	import {
+		ref,
+		onMounted,
+		computed
+	} from 'vue'
+	import {
+		useUserStore
+	} from '@/store/modules/user.js'
+	import {
+		storeToRefs
+	} from 'pinia'
+	import {
+		getCurrentConfig
+	} from '@/config/index.js'
 	// 使用 Pinia 管理用户状态
 	const userStore = useUserStore()
-	const { userInfo, isLoggedIn } = storeToRefs(userStore)
+	const {
+		userInfo,
+		isLoggedIn
+	} = storeToRefs(userStore)
+
+	let appName = ref('')
 
-	onMounted(() => {
+	onMounted(async() => {
+		const config = await getCurrentConfig()
+		appName.value = config.appName
 		// 从 store 中获取用户信息(已自动从 localStorage 加载)
 		console.log('用户登录状态:', isLoggedIn.value)
 		console.log('用户信息:', userInfo.value)
@@ -324,11 +344,10 @@
 	.top-bg {
 		width: 750rpx;
 		height: 634rpx;
-		background: url('/static/image/home/top-bg.png') no-repeat;
-		background-size: 100% 100%;
 		position: fixed;
 		top: 0;
 		left: 0;
+		z-index: 1;
 	}
 
 	.page-warp {
@@ -344,11 +363,24 @@
 		.user-card {
 			width: 100%;
 			height: 414rpx;
-			background: url('/static/image/home/usecard-bg.png') no-repeat;
-			background-size: 100% 100%;
 			padding: 80rpx 40rpx 32rpx;
 			position: relative;
 
+			.user-card-bg {
+				position: absolute;
+				top: 0;
+				left: 0;
+				width: 100%;
+				height: 100%;
+				z-index: 0;
+			}
+
+			view,
+			text {
+				position: relative;
+				z-index: 1;
+			}
+
 			.user-header {
 				.name-row {
 					display: flex;
@@ -388,22 +420,24 @@
 				width: 140rpx;
 				height: 140rpx;
 				border-radius: 50%;
-				box-shadow: 0rpx 0rpx 4rpx 0rpx rgba(21,93,252,0.20);
+				box-shadow: 0rpx 0rpx 4rpx 0rpx rgba(21, 93, 252, 0.20);
 
 				.avatar {
 					width: 100%;
 					height: 100%;
 				}
-				.badge-icon{
+
+				.badge-icon {
 					width: 64rpx;
 					height: 64rpx;
 					position: absolute;
-					bottom:0;
-					right:0;
+					bottom: 0;
+					right: 0;
 					transform: translate(50% 50%);
 					z-index: 1;
 				}
 			}
+
 			.user-contact {
 				margin-top: 32rpx;
 

+ 170 - 184
pages/login/login.vue

@@ -52,10 +52,18 @@
 
 			<!-- 微信一键登录 -->
 			<view class="wechat-login-wrapper">
+				<!-- #ifdef MP-WEIXIN -->
+				<button class="wechat-login-btn" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">
+					<image class="wechat-icon-img" src="/static/image/public/wechat-icon.png" mode="aspectFit" />
+					<text class="wechat-text">微信一键登录</text>
+				</button>
+				<!-- #endif -->
+				<!-- #ifndef MP-WEIXIN -->
 				<button class="wechat-login-btn" @click="wechatLogin">
 					<text class="wechat-icon"></text>
 					<text class="wechat-text">微信一键登录</text>
 				</button>
+				<!-- #endif -->
 			</view>
 		</view>
 
@@ -69,89 +77,7 @@
 				</view>
 				<scroll-view scroll-y class="popup-body">
 					<view class="agreement-content">
-						<text class="agreement-title">用户协议</text>
-						<text class="update-time">最后更新时间:2026 年 4 月 24 日</text>
-
-						<view class="section">
-							<text class="section-title">一、协议的接受与修改</text>
-							<text class="section-content">
-								1.1 欢迎您使用布尔销销乐服务。请您仔细阅读本用户协议,以确保您了解我们的产品或服务,以及本协议规定的双方的权利和义务。\n
-								1.2 当您使用本服务时,即表示您已阅读、理解并同意接受本协议的所有条款。如果您不同意本协议的任何条款,请立即停止使用本服务。\n
-								1.3 我们有权根据需要不时修改本协议条款,修改后的协议一旦公布即有效代替原来的协议。您可随时查阅最新协议。
-							</text>
-						</view>
-
-						<view class="section">
-							<text class="section-title">二、服务内容</text>
-							<text class="section-content">
-								2.1 布尔销销乐是一款面向企业的客户关系管理工具,提供客户管理、销售跟进、数据分析等功能。\n
-								2.2 我们有权对服务内容进行变更、中断或终止,变更、中断或终止服务前将尽可能提前通知用户。
-							</text>
-						</view>
-
-						<view class="section">
-							<text class="section-title">三、用户账号</text>
-							<text class="section-content">
-								3.1 您需要通过手机号验证码登录或微信授权登录方式使用本服务。\n
-								3.2 您应保证提供的信息真实、准确、完整。\n
-								3.3 您应妥善保管您的账号信息,因您保管不善导致账号被盗、密码失密或遭受其他损失的,您应自行承担相应责任。
-							</text>
-						</view>
-
-						<view class="section">
-							<text class="section-title">四、用户行为规范</text>
-							<text class="section-content">
-								4.1 您在使用本服务时,应遵守国家法律法规,不得利用本服务从事任何违法违规活动。\n
-								4.2 您不得利用本服务制作、复制、发布、传播含有下列内容的信息:\n
-								(1) 反对宪法所确定的基本原则的;\n
-								(2) 危害国家安全、泄露国家秘密的;\n
-								(3) 损害国家荣誉和利益的;\n
-								(4) 煽动民族仇恨、民族歧视的;\n
-								(5) 破坏国家宗教政策,宣扬邪教和封建迷信的;\n
-								(6) 散布谣言、淫秽色情、赌博、暴力、凶杀、恐怖或者教唆犯罪的。
-							</text>
-						</view>
-
-						<view class="section">
-							<text class="section-title">五、知识产权</text>
-							<text class="section-content">
-								5.1 本服务包含的所有内容(包括但不限于文字、图片、音频、视频、软件、程序、代码、界面设计等)的知识产权均归我们所有。\n
-								5.2 未经我们书面许可,您不得以任何形式复制、传播、展示、修改本服务的内容。
-							</text>
-						</view>
-
-						<view class="section">
-							<text class="section-title">六、免责声明</text>
-							<text class="section-content">
-								6.1 因不可抗力(如自然灾害、政府行为、社会异常事件等)导致服务中断或数据丢失,我们不承担责任。\n
-								6.2 因网络状况、通讯线路、黑客攻击、计算机病毒、政府管制等任何非我们原因导致的服务中断或数据丢失,我们不承担责任。
-							</text>
-						</view>
-
-						<view class="section">
-							<text class="section-title">七、协议终止</text>
-							<text class="section-content">
-								7.1 您有权随时停止使用本服务并注销账号。\n
-								7.2 如您违反本协议,我们有权终止向您提供服务,并保留追究法律责任的权利。
-							</text>
-						</view>
-
-						<view class="section">
-							<text class="section-title">八、法律适用与争议解决</text>
-							<text class="section-content">
-								8.1 本协议的成立、生效、履行、解释及争议解决均适用中华人民共和国法律。\n
-								8.2 如双方就本协议内容或其执行发生任何争议,应友好协商解决;协商不成的,任何一方均可向我们所在地有管辖权的人民法院提起诉讼。
-							</text>
-						</view>
-
-						<view class="section">
-							<text class="section-title">九、联系我们</text>
-							<text class="section-content">
-								如您对本协议有任何疑问,请通过以下方式联系我们:\n
-								客服电话:400-XXX-XXXX\n
-								客服邮箱:support@example.com
-							</text>
-						</view>
+						<yonghuxieyi/>
 					</view>
 				</scroll-view>
 				<view class="popup-footer">
@@ -170,73 +96,8 @@
 				</view>
 				<scroll-view scroll-y class="popup-body">
 					<view class="agreement-content">
-						<text class="agreement-title">隐私政策</text>
-						<text class="update-time">最后更新时间:2026 年 4 月 24 日</text>
-
-						<view class="section">
-							<text class="section-title">一、我们如何收集和使用您的个人信息</text>
-							<text class="section-content">
-								1.1 为了向您提供服务,我们可能会收集以下信息:\n
-								(1) 手机号码:用于账号注册和登录验证;\n
-								(2) 微信昵称、头像:用于完善您的个人资料(仅在微信授权登录时收集);\n
-								(3) 设备信息:用于保障服务安全和优化用户体验。\n
-								1.2 我们收集的信息仅用于提供服务、改进产品质量和保障账号安全,不会用于其他用途。
-							</text>
-						</view>
-
-						<view class="section">
-							<text class="section-title">二、我们如何共享、转让、公开披露您的个人信息</text>
-							<text class="section-content">
-								2.1 我们不会与任何公司、组织和个人共享您的个人信息,但以下情况除外:\n
-								(1) 事先获得您的明确同意;\n
-								(2) 根据法律法规或政府主管部门的强制性要求。\n
-								2.2 我们不会转让您的个人信息给任何第三方。\n
-								2.3 我们不会公开披露您的个人信息,除非获得您的明确同意或基于法律规定。
-							</text>
-						</view>
-
-						<view class="section">
-							<text class="section-title">三、我们如何保护您的个人信息</text>
-							<text class="section-content">
-								3.1 我们已使用符合业界标准的安全防护措施保护您的个人信息。\n
-								3.2 我们采取数据加密、访问控制等技术措施防止数据遭到未经授权的访问、使用、修改或泄露。\n
-								3.3 我们仅允许有必要知晓这些信息的员工访问您的个人信息,并为此设置了严格的访问权限控制。
-							</text>
-						</view>
-
-						<view class="section">
-							<text class="section-title">四、您的权利</text>
-							<text class="section-content">
-								4.1 您有权访问、更正、删除您的个人信息。\n
-								4.2 您有权改变您授权同意的范围或撤回您的授权。\n
-								4.3 您有权注销您的账号。
-							</text>
-						</view>
-
-						<view class="section">
-							<text class="section-title">五、我们如何处理未成年人的个人信息</text>
-							<text class="section-content">
-								5.1 我们非常重视对未成年人个人信息的保护。\n
-								5.2 若您是 18 周岁以下的未成年人,在使用本服务前,应事先取得您家长或法定监护人的书面同意。
-							</text>
-						</view>
-
-						<view class="section">
-							<text class="section-title">六、隐私政策的更新</text>
-							<text class="section-content">
-								6.1 我们可能会适时对本隐私政策进行修订。\n
-								6.2 当本政策的条款发生变更时,我们会在版本更新时以适当的方式向您提示变更后的内容。
-							</text>
-						</view>
-
-						<view class="section">
-							<text class="section-title">七、联系我们</text>
-							<text class="section-content">
-								如您对本隐私政策有任何疑问,请通过以下方式联系我们:\n
-								客服电话:400-XXX-XXXX\n
-								客服邮箱:support@example.com
-							</text>
-						</view>
+						
+						<yonghuzhengce/>
 					</view>
 				</scroll-view>
 				<view class="popup-footer">
@@ -248,6 +109,9 @@
 </template>
 
 <script setup>
+	import  yonghuxieyi from "./yonghuxieyi.vue"
+	import  yonghuzhengce from "./yonghuzhengce.vue"
+	
 	import {
 		getCurrentConfig
 	} from '@/config/index.js'
@@ -256,17 +120,18 @@
 		onMounted
 	} from 'vue'
 	import {
-		login,
-		sendCode
-	} from '@/api/user.js'
+		sendCode,
+		codeLogin,
+		wxgetLogin,
+		getUserInfo,
+		wxLogin
+	} from '@/api/login.js'
 	import {
-		saveUserInfo
+		saveUserInfo,
+		getToken
 	} from '@/utils/userCache.js'
-
-
-
 	let appName = ref('')
-
+	let version = ref('')
 	onMounted(async () => {
 		const config = await getCurrentConfig()
 		appName.value = config.appName
@@ -295,9 +160,18 @@
 			})
 			return
 		}
-
 		try {
-			const res = await login(phoneNumber.value)
+			const res = await sendCode({
+				phone: phoneNumber.value,
+				type: 3
+			})
+			if (res.code != 200) {
+				uni.showToast({
+					title: res.msg,
+					icon: 'error'
+				})
+				return
+			}
 			console.log('验证码发送成功:', res)
 
 			// 开始倒计时
@@ -330,7 +204,7 @@
 			return
 		}
 
-		if (!verifyCode.value || verifyCode.value.length !== 6) {
+		if (!verifyCode.value) {
 			uni.showToast({
 				title: '请输入验证码',
 				icon: 'none'
@@ -339,24 +213,54 @@
 		}
 
 		isLoading.value = true
-
 		try {
-			const res = await sendCode(phoneNumber.value, verifyCode.value)
-			console.log('登录成功:', res)
-
-			// 保存用户信息和 token
-			const {
-				userInfo,
-				token
-			} = res.data || res
+			// 第一步:调用登录接口获取 token
+			const res = await codeLogin({phonenumber:phoneNumber.value, smsCode:verifyCode.value})
+			console.log('登录接口返回:', res)
+			
+			if (res.code != 200) {
+				uni.showToast({
+					title: res.msg || '登录失败',
+					icon: 'none'
+				})
+				isLoading.value = false
+				return
+			}
+			
+			// 获取 token
+			const { token } = res.data || res
+			
+			if (!token) {
+				uni.showToast({
+					title: '未获取到 token',
+					icon: 'none'
+				})
+				isLoading.value = false
+				return
+			}
+			
+			// 第二步:调用 getUserInfo 获取用户信息
+			const userInfoRes = await getUserInfo({})
+			console.log('用户信息接口返回:', userInfoRes)
+			
+			if (userInfoRes.code != 200) {
+				uni.showToast({
+					title: userInfoRes.msg || '获取用户信息失败',
+					icon: 'none'
+				})
+				isLoading.value = false
+				return
+			}
+			
+			// 第三步:保存用户信息和 token
+			const userInfo = userInfoRes.data || userInfoRes
 			const saveSuccess = saveUserInfo(userInfo, token)
-
+			
 			if (saveSuccess) {
 				uni.showToast({
 					title: '登录成功',
 					icon: 'success'
 				})
-
 				// 延迟跳转
 				setTimeout(() => {
 					uni.reLaunch({
@@ -371,30 +275,106 @@
 			}
 		} catch (error) {
 			console.error('登录失败:', error)
+			uni.showToast({
+				title: '登录失败,请重试',
+				icon: 'none'
+			})
 		} finally {
 			isLoading.value = false
 		}
 	}
 
-	// 微信登录
-	const wechatLogin = () => {
+	// 微信登录 - 获取手机号
+	const getPhoneNumber = async (e) => {
 		// #ifdef MP-WEIXIN
-		uni.getUserProfile({
-			desc: '用于完善用户资料',
-			success: (res) => {
-				console.log('微信授权成功:', res.userInfo)
-				// TODO: 调用微信登录接口
+		if (e.detail.errMsg !== 'getPhoneNumber:ok') {
+			uni.showToast({
+				title: '您取消了授权',
+				icon: 'none'
+			})
+			return
+		}
+
+		try {
+			// 先获取微信登录 code
+			const code = await wxLogin()
+			
+			// 调用 wxgetLogin 接口,传入 code 和手机号信息
+			console.log(e,"eeeeeeee");
+			const res = await wxgetLogin({
+				wxCode: code,
+				phoneCode: e.detail.code,
+				iv: e.detail.iv,
+				type: 1
+			})
+			
+			if (res.code != 200) {
+				uni.showToast({
+					title: res.msg || '登录失败',
+					icon: 'none'
+				})
+				return
+			}
+			
+			console.log('微信登录成功:', res)
+			
+			// 获取 token
+			const { token } = res.data || res
+			
+			if (!token) {
+				uni.showToast({
+					title: '未获取到 token',
+					icon: 'none'
+				})
+				return
+			}
+			
+			// 第二步:调用 getUserInfo 获取用户信息
+			const userInfoRes = await getUserInfo({})
+			console.log('用户信息接口返回:', userInfoRes)
+			
+			if (userInfoRes.code != 200) {
 				uni.showToast({
-					title: '微信授权成功',
+					title: userInfoRes.msg || '获取用户信息失败',
+					icon: 'none'
+				})
+				return
+			}
+			
+			// 第三步:保存用户信息和 token
+			const userInfo = userInfoRes.data || userInfoRes
+			const saveSuccess = saveUserInfo(userInfo, token)
+			
+			if (saveSuccess) {
+				uni.showToast({
+					title: '登录成功',
 					icon: 'success'
 				})
-			},
-			fail: (err) => {
-				console.log('微信授权失败:', err)
+				
+				// 延迟跳转到首页
+				setTimeout(() => {
+					uni.reLaunch({
+						url: '/pages/index/index'
+					})
+				}, .800)
+			} else {
+				uni.showToast({
+					title: '保存登录信息失败',
+					icon: 'none'
+				})
 			}
-		})
+		} catch (error) {
+			console.error('微信登录失败:', error)
+			uni.showToast({
+				title: '登录失败,请重试',
+				icon: 'none'
+			})
+		}
 		// #endif
+	}
 
+	// 微信登录(非小程序环境备用)
+	const wechatLogin = async () => {
 		// #ifndef MP-WEIXIN
 		uni.showToast({
 			title: '请在微信小程序中使用',
@@ -595,6 +575,12 @@
 					border: none;
 				}
 
+				.wechat-icon-img {
+					width: 40rpx;
+					height: 40rpx;
+					margin-right: 12rpx;
+				}
+
 				.wechat-icon {
 					margin-right: 12rpx;
 					font-size: 36rpx;

+ 291 - 0
pages/login/yonghuxieyi.vue

@@ -0,0 +1,291 @@
+<template>
+	<view class="agreement-container">
+		
+		<!-- 内容区域 -->
+		<scroll-view scroll-y class="content-scroll">
+			<view class="content-wrapper">
+				<view class="intro-text">
+					欢迎您使用布尔销销乐 CRM 小程序(以下简称"本小程序")。本协议是您(以下简称"用户",包括个人用户及企业用户)与本小程序运营方(以下简称"运营方")之间就使用本小程序所订立的具有法律约束力的协议。请您在注册、登录或使用本小程序前,仔细阅读并充分理解本协议全部条款,特别是免除或限制运营方责任的条款、用户权利义务条款及争议解决条款。您一旦点击"同意"、完成注册登录或使用本小程序服务,即视为您已阅读、理解并完全同意本协议的全部内容,自愿接受本协议约束。若您不同意本协议任何条款,请勿使用本小程序。
+				</view>
+				
+				<view class="section">
+					<text class="section-title">一、服务说明</text>
+					<view class="section-content">
+						<view class="paragraph">1. 本小程序是由运营方开发并运营的客户关系管理工具,核心服务包括但不限于客户信息录入与管理、跟进记录留存、客户标签分类、数据统计分析、任务提醒、团队协作等(具体服务内容以小程序实际功能为准),旨在帮助用户高效管理客户关系、提升工作效率。</view>
+						<view class="paragraph">2. 运营方有权根据业务发展、技术升级、法律法规要求等,对本小程序的服务内容、功能模块、操作流程等进行修改、升级、暂停或终止,并将通过小程序公告、站内信、短信等合理方式提前通知用户,用户应及时关注相关通知。</view>
+						<view class="paragraph">3. 本小程序的使用需依赖稳定的网络环境(移动网络或无线网络),用户应自行承担网络服务费用及因网络问题导致的服务使用异常、数据传输延迟等风险。</view>
+						<view class="paragraph">4. 用户使用本小程序时,应遵守微信小程序平台、支付宝小程序平台等第三方载体的相关规则,若因用户违反第三方平台规则导致本小程序无法正常使用,运营方不承担责任。</view>
+					</view>
+				</view>
+				
+				<view class="section">
+					<text class="section-title">二、用户注册与账号管理</text>
+					<view class="section-content">
+						<text class="subsection-title">(一)注册资格</text>
+						<view class="paragraph">1. 个人用户需为具备完全民事行为能力的自然人,企业用户需为依法注册成立、具备合法经营资质的法人或其他组织。</view>
+						<view class="paragraph">2. 未成年人若需使用本小程序,必须在法定监护人的陪同下阅读本协议,并取得法定监护人的书面或口头同意,且法定监护人应承担相应的监护责任。运营方有权要求未成年人用户提供监护人身份信息进行验证,若无法提供或验证失败,运营方有权拒绝提供服务或终止账号使用。</view>
+						<view class="paragraph">3. 用户需保证注册时提供的信息(包括但不限于姓名、手机号码、企业名称、营业执照等)真实、准确、完整、有效,不得提供虚假信息或冒用他人身份信息注册账号。若信息发生变更,用户应及时更新,否则因此产生的一切后果由用户自行承担。</view>
+						
+						<text class="subsection-title">(二)账号管理</text>
+						<view class="paragraph">1. 用户完成注册后,将获得本小程序的专属账号及密码(或通过第三方账号快捷登录),账号及密码由用户自行保管,用户对账号的所有操作(包括但不限于录入客户信息、发送指令、修改设置等)承担全部责任。</view>
+						<view class="paragraph">2. 用户不得将账号、密码转让、出租、出借、共享给第三方,若因用户自身保管不善导致账号泄露、被盗用,或因第三方使用账号产生的任何损失,由用户自行承担,运营方不承担赔偿责任。</view>
+						<view class="paragraph">3. 若用户发现账号异常(如被盗用、被非法操作),应立即通知运营方,并配合运营方进行核查、处理,运营方有权根据实际情况采取冻结账号、重置密码等措施,但不承担因账号异常导致的用户损失。</view>
+						<view class="paragraph">4. 用户可根据自身需求,通过小程序"设置 - 账号管理"路径申请注销账号。账号注销后,该账号下的所有数据(包括客户信息、跟进记录、统计数据等)将按本协议及隐私政策的规定进行处理,注销后无法恢复,请用户谨慎操作。</view>
+					</view>
+				</view>
+				
+				<view class="section">
+					<text class="section-title">三、用户权利与义务</text>
+					<view class="section-content">
+						<text class="subsection-title">(一)用户权利</text>
+						<view class="paragraph">1. 有权按照本协议约定,正常使用本小程序提供的各项合法服务,对小程序的功能优化、服务改进提出建议。</view>
+						<view class="paragraph">2. 有权查询、修改、删除本人账号下的个人信息及客户信息(法律法规另有规定或本协议另有约定的除外),有权要求运营方对相关数据进行解释。</view>
+						<view class="paragraph">3. 有权拒绝运营方的不合理要求(如强制收集非必要信息、强制绑定第三方服务等),有权在不同意本协议修改内容时,停止使用本小程序并注销账号。</view>
+						
+						<text class="subsection-title">(二)用户义务</text>
+						<view class="paragraph">1. 严格遵守《中华人民共和国网络安全法》《中华人民共和国个人信息保护法》《数据安全法》等相关法律法规及本协议约定,不得利用本小程序从事任何违法违规活动。</view>
+						<view class="paragraph">2. 不得利用本小程序收集、存储、传输、泄露他人隐私信息(包括但不限于客户的姓名、手机号码、身份证号、住址、商业秘密等),不得侵犯他人的肖像权、名誉权、隐私权、知识产权等合法权益。</view>
+						<view class="paragraph">3. 录入、上传的客户信息及相关内容(如跟进记录、备注等)需真实、合法、有效,不得录入虚假信息、违法信息、低俗信息或与本小程序服务无关的内容,若因用户录入内容不当导致的纠纷、损失,由用户自行承担。</view>
+						<view class="paragraph">4. 不得对本小程序进行逆向工程、反向编译、破解、篡改,不得利用脚本、插件等工具恶意刷量、干扰小程序正常运行,不得攻击、破坏小程序的服务器及数据系统。</view>
+						<view class="paragraph">5. 配合运营方的合规检查、安全核查,及时提供必要的证明材料(如企业资质、身份信息等),若拒绝配合或提供虚假材料,运营方有权暂停或终止服务。</view>
+						<view class="paragraph">6. 自行承担因使用本小程序产生的一切费用(包括但不限于网络费、设备费、服务费等)及相关风险,如因用户自身操作失误、设备故障等导致的数据丢失、服务无法使用,运营方不承担责任。</view>
+					</view>
+				</view>
+				
+				<view class="section">
+					<text class="section-title">四、运营方权利与义务</text>
+					<view class="section-content">
+						<text class="subsection-title">(一)运营方权利</text>
+						<view class="paragraph">1. 有权按照本协议约定,提供本小程序服务,对用户的使用行为进行监督、管理,对违反本协议及相关规定的用户,有权采取警告、限制功能、冻结账号、终止服务等措施,情节严重的,将依法追究法律责任。</view>
+						<view class="paragraph">2. 有权根据业务需要,修改、升级本小程序的服务内容及功能,有权制定、修改本小程序的使用规则、隐私政策等相关文件,修改后将通过合理方式通知用户,用户继续使用服务即视为同意修改后的内容。</view>
+						<view class="paragraph">3. 有权在符合法律法规及本协议约定的前提下,收集、存储、使用、处理用户及客户的相关数据(具体以隐私政策为准),用于优化服务、提升用户体验、保障服务安全。</view>
+						<view class="paragraph">4. 有权根据用户的使用情况,对用户账号进行分级管理,不同等级的账号享有不同的服务权限,运营方有权调整账号等级及对应权限。</view>
+						
+						<text class="subsection-title">(二)运营方义务</text>
+						<view class="paragraph">1. 按照本协议约定,提供稳定、安全的小程序服务,尽力保障小程序的正常运行,减少服务中断、数据丢失等情况的发生。</view>
+						<view class="paragraph">2. 严格遵守个人信息保护相关法律法规,建立健全数据安全管理制度,采取加密、备份等技术措施,保护用户及客户的信息安全,不得擅自泄露、出售、出租用户及客户的信息(法律法规另有规定或用户书面同意的除外)。</view>
+						<view class="paragraph">3. 及时响应用户的咨询、投诉及建议,建立有效的客服渠道,对用户反映的问题进行核查、处理,并在合理期限内反馈结果。</view>
+						<view class="paragraph">4. 向用户明确告知本小程序的服务范围、功能限制、收费标准(如有)等信息,不得隐瞒或误导用户。</view>
+						<view class="paragraph">5. 按照相关法律法规要求,对用户数据进行留存、备份,在用户账号注销后,按照隐私政策的规定处理相关数据,不得随意泄露或滥用。</view>
+					</view>
+				</view>
+				
+				<view class="section">
+					<text class="section-title">五、数据安全与隐私保护</text>
+					<view class="section-content">
+						<view class="paragraph">1. 运营方重视用户及客户的数据安全与隐私保护,将严格按照《中华人民共和国个人信息保护法》等相关法律法规及本小程序隐私政策的规定,处理用户及客户的信息,采取合理的安全措施(如加密存储、访问权限控制、定期安全检测等),防止信息泄露、篡改、丢失。</view>
+						<view class="paragraph">2. 用户确认,其录入、上传至本小程序的客户信息及相关内容,均已获得客户的合法授权,用户对该等信息享有合法的处理权,若因用户未获得授权导致的纠纷、损失,由用户自行承担,与运营方无关。</view>
+						<view class="paragraph">3. 运营方不得向任何第三方泄露、出售、出租用户及客户的信息,除非符合以下情形:(1)法律法规另有规定;(2)用户书面同意;(3)为保障小程序正常运行、维护用户合法权益,或配合司法机关、行政机关的调查取证工作。</view>
+						<view class="paragraph">4. 用户应自行妥善保管客户信息,不得通过本小程序泄露、传播客户隐私,若因用户自身操作导致客户信息泄露,产生的一切责任由用户自行承担。</view>
+						<view class="paragraph">5. 若发生数据泄露、篡改等安全事件,运营方将及时采取补救措施,并按照相关法律法规要求,通知用户及相关监管部门。</view>
+					</view>
+				</view>
+				
+				<view class="section">
+					<text class="section-title">六、服务的变更、暂停与终止</text>
+					<view class="section-content">
+						<view class="paragraph">1. 运营方有权根据业务发展、技术升级、法律法规变化等情况,变更本小程序的服务内容、功能模块,或暂停、终止部分或全部服务,变更、暂停或终止前,将通过小程序公告、站内信等方式提前通知用户,用户可选择继续使用或停止使用服务,若用户继续使用,视为同意相关变更;若用户不同意,可注销账号。</view>
+						<view class="paragraph">2. 若用户出现以下情形,运营方有权立即暂停或终止对用户的全部服务,且不承担任何赔偿责任:(1)违反本协议约定,从事违法违规活动;(2)提供虚假注册信息,冒用他人身份信息;(3)转让、出租、出借账号;(4)恶意攻击、破坏小程序系统;(5)长期不使用账号(超过 180 天);(6)违反第三方平台规则,导致小程序无法正常为其提供服务;(7)法律法规规定的其他情形。</view>
+						<view class="paragraph">3. 服务终止后,运营方将停止向用户提供任何服务,用户账号下的相关数据将按照本协议及隐私政策的规定进行处理,运营方不承担数据恢复、赔偿等责任,用户应自行备份相关数据。</view>
+					</view>
+				</view>
+				
+				<view class="section">
+					<text class="section-title">七、知识产权</text>
+					<view class="section-content">
+						<view class="paragraph">1. 本小程序的全部知识产权(包括但不限于软件著作权、商标权、专利权、外观设计权、文字作品著作权等)均归运营方所有,或由运营方依法获得授权使用。</view>
+						<view class="paragraph">2. 用户在使用本小程序过程中,不得擅自复制、传播、修改、转让本小程序的任何内容(包括但不限于代码、界面设计、图标、文字、logo 等),不得侵犯运营方的知识产权。</view>
+						<view class="paragraph">3. 用户录入、上传至本小程序的内容(如客户信息、跟进记录等),其知识产权归用户所有,但用户授予运营方在提供服务过程中,合理使用该等内容的权利(包括但不限于存储、展示、统计、优化等),服务终止后,该授权自动终止,运营方不得再使用该等内容(法律法规另有规定的除外)。</view>
+					</view>
+				</view>
+				
+				<view class="section">
+					<text class="section-title">八、免责声明</text>
+					<view class="section-content">
+						<view class="paragraph">1. 因不可抗力(包括但不限于地震、洪水、台风、战争、政策调整、网络中断、服务器故障等)导致本小程序服务中断、数据丢失,或用户无法正常使用服务,运营方不承担任何责任,用户自行承担相关损失。</view>
+						<view class="paragraph">2. 因用户自身操作失误、设备故障、网络问题、第三方软件干扰等原因,导致数据丢失、服务无法使用,或产生其他损失,运营方不承担责任。</view>
+						<view class="paragraph">3. 本小程序仅提供客户关系管理工具服务,用户利用本小程序从事的任何商业活动、交易行为,其风险由用户自行承担,运营方不参与、不担保,也不承担任何连带责任。</view>
+						<view class="paragraph">4. 本小程序可能包含第三方链接或服务,该等链接或服务由第三方提供,运营方不对第三方服务的真实性、合法性、安全性负责,用户使用第三方服务产生的损失,由用户自行承担。</view>
+						<view class="paragraph">5. 运营方已采取合理措施保障小程序的安全,但不保证小程序完全无漏洞、无风险,若因网络攻击、病毒入侵等原因导致用户损失,运营方不承担赔偿责任,但若因运营方故意或重大过失导致的除外。</view>
+						<view class="paragraph">6. 因用户违反本协议约定,导致自身或第三方遭受损失,由用户自行承担全部责任,若给运营方造成损失,用户应依法予以赔偿。</view>
+					</view>
+				</view>
+				
+				<view class="section">
+					<text class="section-title">九、违约责任</text>
+					<view class="section-content">
+						<view class="paragraph">1. 任何一方违反本协议约定,均应承担违约责任,向守约方赔偿因此造成的全部损失(包括但不限于直接损失、间接损失、律师费、诉讼费等)。</view>
+						<view class="paragraph">2. 若用户违反本协议约定,运营方有权采取警告、限制功能、冻结账号、终止服务等措施,同时用户应赔偿运营方因此遭受的损失;若用户的违法违规行为涉嫌犯罪,运营方将依法向司法机关举报。</view>
+						<view class="paragraph">3. 若运营方违反本协议约定,未履行数据安全保护义务,导致用户信息泄露、丢失,或未按约定提供服务,应向用户赔偿因此造成的直接损失。</view>
+					</view>
+				</view>
+				
+				<view class="section">
+					<text class="section-title">十、协议的修改与生效</text>
+					<view class="section-content">
+						<view class="paragraph">1. 运营方有权根据法律法规变化、业务发展需要,修改本协议内容,修改后将通过小程序公告、站内信等方式通知用户,修改后的协议自通知发布之日起生效,用户继续使用本小程序服务,即视为同意修改后的协议;若用户不同意修改后的协议,可停止使用服务并注销账号。</view>
+						<view class="paragraph">2. 本协议自用户点击"同意"、完成注册登录或首次使用本小程序服务之日起生效,有效期至用户注销账号或本小程序终止服务之日止。</view>
+						<view class="paragraph">3. 本协议未尽事宜,按照相关法律法规及运营方制定的隐私政策、使用规则等相关文件执行;若本协议与相关法律法规相抵触,以法律法规为准。</view>
+					</view>
+				</view>
+				
+				<view class="section">
+					<text class="section-title">十一、争议解决</text>
+					<view class="section-content">
+						<view class="paragraph">1. 本协议的订立、履行、解释及争议解决,均适用中华人民共和国法律(不包括冲突法规则)。</view>
+						<view class="paragraph">2. 双方因履行本协议产生的任何争议,应首先通过友好协商的方式解决;协商不成的,任何一方均有权向运营方所在地有管辖权的人民法院提起诉讼。</view>
+					</view>
+				</view>
+				
+				<view class="section">
+					<text class="section-title">十二、其他条款</text>
+					<view class="section-content">
+						<view class="paragraph">1. 本协议构成双方就使用本小程序服务所达成的完整协议,取代双方此前就相关事宜达成的任何口头或书面协议、承诺。</view>
+						<view class="paragraph">2. 若本协议的任何条款被认定为无效或不可执行,不影响其他条款的效力,其他条款仍然有效,双方应按照有效条款履行义务。</view>
+					</view>
+				</view>
+				
+				<!-- 底部占位 -->
+				<view class="bottom-spacer"></view>
+			</view>
+		</scroll-view>
+	</view>
+</template>
+
+<script setup>
+	import StatusBarPlaceholder from '@/components/status-bar-placeholder/index.vue'
+	
+	const goBack = () => {
+		uni.navigateBack()
+	}
+</script>
+
+<style lang="scss" scoped>
+	.agreement-container {
+		background: #f5f6f8;
+	}
+	
+	// 导航栏
+	.nav-bar {
+		background: #ffffff;
+		position: sticky;
+		top: 0;
+		z-index: 100;
+		box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
+		
+		.nav-content {
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			height: 88rpx;
+			padding: 0 32rpx;
+			
+			.nav-back {
+				width: 60rpx;
+				height: 60rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+			}
+			
+			.nav-title {
+				font-size: 32rpx;
+				font-weight: 600;
+				color: #333333;
+			}
+			
+			.nav-placeholder {
+				width: 60rpx;
+			}
+		}
+	}
+	
+	// 标题区域
+	.header-section {
+		background: linear-gradient(135deg, #4A90E2 0%, #6FB3F2 100%);
+		padding: 60rpx 40rpx 80rpx;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		
+		.main-title {
+			font-size: 40rpx;
+			font-weight: 600;
+			color: #ffffff;
+			text-align: center;
+			margin-bottom: 16rpx;
+			text-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
+		}
+		
+		.sub-title {
+			font-size: 32rpx;
+			font-weight: 500;
+			color: rgba(255, 255, 255, 0.9);
+			text-align: center;
+		}
+	}
+	
+	// 内容滚动区域
+	.content-scroll {
+		margin-top: -40rpx;
+		border-radius: 40rpx 40rpx 0 0;
+		background: #f5f6f8;
+		
+		.content-wrapper {
+			background: #ffffff;
+			padding: 48rpx 40rpx;
+			min-height: 100%;
+		}
+	}
+	
+	// 介绍文字
+	.intro-text {
+		font-size: 28rpx;
+		color: #666666;
+		line-height: 1.8;
+		margin-bottom: 40rpx;
+		padding: 32rpx;
+		background: linear-gradient(135deg, rgba(74, 144, 226, 0.05) 0%, rgba(111, 179, 242, 0.05) 100%);
+		border-radius: 16rpx;
+		border-left: 6rpx solid #4A90E2;
+	}
+	
+	// 章节
+	.section {
+		margin-bottom: 40rpx;
+		
+		.section-title {
+			display: block;
+			font-size: 30rpx;
+			font-weight: 600;
+			color: #333333;
+			margin-bottom: 24rpx;
+			padding-left: 16rpx;
+			border-left: 6rpx solid #4A90E2;
+		}
+		
+		.subsection-title {
+			display: block;
+			font-size: 28rpx;
+			font-weight: 600;
+			color: #4A90E2;
+			margin: 24rpx 0 16rpx;
+		}
+		
+		.section-content {
+			.paragraph {
+				font-size: 28rpx;
+				color: #666666;
+				line-height: 1.8;
+				margin-bottom: 16rpx;
+				text-align: justify;
+				text-indent: 2em;
+			}
+		}
+	}
+	
+	// 底部占位
+	.bottom-spacer {
+		height: 40rpx;
+	}
+</style>

+ 280 - 0
pages/login/yonghuzhengce.vue

@@ -0,0 +1,280 @@
+<template>
+	<view class="agreement-container">
+		<!-- 内容区域 -->
+		<scroll-view scroll-y class="content-scroll">
+			<view class="content-wrapper">
+				<view class="intro-text">
+					欢迎您使用布尔销销乐 CRM 小程序(以下简称"本小程序")。本隐私政策(以下简称"本政策")旨在向您清晰、准确地说明运营方(以下简称"我们")如何收集、使用、存储、保护您的个人信息及客户相关信息,以及您享有的相关权利。请您在注册、登录或使用本小程序前,仔细阅读并充分理解本政策全部内容,特别是涉及信息收集范围、使用目的、第三方共享等关键条款。您一旦点击"同意"、完成注册登录或使用本小程序服务,即视为您已阅读、理解并完全同意本政策的全部内容,自愿接受本政策约束。若您不同意本政策任何条款,请勿使用本小程序。
+				</view>
+				
+				<view class="section">
+					<text class="section-title">一、隐私政策的适用范围</text>
+					<view class="section-content">
+						<view class="paragraph">1. 本政策适用于本小程序提供的所有服务,包括但不限于用户注册、账号管理、客户信息录入与管理、跟进记录留存、数据统计分析、团队协作等核心服务。</view>
+						<view class="paragraph">2. 本政策不适用于以下场景:(1)第三方通过本小程序提供的链接或服务(如第三方支付、第三方协作工具等),该等第三方服务的隐私政策由第三方自行制定,我们不承担相关责任;(2)用户通过本小程序录入、上传的客户信息,该等信息的收集、使用、保护由用户自行负责,我们仅提供存储、展示等技术支持,相关责任由用户承担。</view>
+						<view class="paragraph">3. 为规范个人信息处理行为,保障您的个人信息安全,我们严格遵循《中华人民共和国个人信息保护法》《中华人民共和国网络安全法》《数据安全法》等相关法律法规,杜绝违法违规收集、使用、泄露个人信息的行为,同时避免出现未明示同意即收集信息、未提供撤回同意途径等违规情形。</view>
+					</view>
+				</view>
+				
+				<view class="section">
+					<text class="section-title">二、信息的收集与使用</text>
+					<view class="section-content">
+						<text class="subsection-title">(一)收集的信息类型及目的</text>
+						<view class="paragraph">我们遵循"合法、正当、必要、诚信"的原则,仅收集为提供本小程序服务所必需的信息,不收集与服务无关的信息,不超范围收集信息,具体如下:</view>
+						
+						<view class="paragraph">1. 用户注册及账号管理相关信息</view>
+						<view class="paragraph" style="margin-left: 20rpx;">(1)个人用户:注册时需提供手机号码(用于接收验证码、登录验证)、姓名(用于身份识别),若通过第三方账号(如微信、支付宝)快捷登录,我们将获取您第三方账号的昵称、头像等公开信息(仅用于账号绑定及身份展示,不获取其他隐私信息)。该等信息用于完成账号注册、登录验证、密码重置、账号安全保障等,确保账号使用的安全性和合规性。</view>
+						<view class="paragraph" style="margin-left: 20rpx;">(2)企业用户:注册时需提供企业名称、统一社会信用代码、营业执照复印件、联系人姓名及手机号码。该等信息用于核实企业合法经营资质、完成账号注册及企业认证,保障企业用户服务的合规性,同时便于我们提供针对性的团队协作、客户管理等服务。</view>
+						
+						<view class="paragraph">2. 小程序使用过程中收集的信息</view>
+						<view class="paragraph" style="margin-left: 20rpx;">(1)设备及网络信息:当您使用本小程序时,我们将自动收集您的设备型号、操作系统版本、IP 地址、网络类型(移动网络/无线网络)、设备唯一标识符(用于区分不同设备,保障账号安全)等信息。该等信息用于优化小程序运行性能、排查使用故障、保障服务稳定性,避免因设备或网络问题导致的服务异常。</view>
+						<view class="paragraph" style="margin-left: 20rpx;">(2)使用行为信息:我们将收集您使用本小程序的相关行为数据,包括但不限于登录时间、操作记录(如客户信息录入、跟进记录编辑、标签分类、数据查询等)、服务使用频率、功能偏好等。该等信息用于分析用户使用习惯、优化服务流程、提升服务质量,为您提供更贴合需求的客户管理功能。</view>
+						<view class="paragraph" style="margin-left: 20rpx;">(3)客户相关信息:由您自行录入、上传至本小程序的客户信息,包括但不限于客户姓名、手机号码、邮箱、地址、跟进记录、需求偏好、交易记录等。该等信息由您自主控制,我们仅提供存储、展示、统计、提醒等技术支持,用于帮助您高效管理客户关系,具体使用范围由您自行决定,我们不主动使用该等信息用于其他目的。</view>
+						
+						<view class="paragraph">3. 其他必要信息:根据法律法规要求、服务优化需要或您的主动请求,我们可能收集您的其他相关信息(如客服咨询时提供的问题描述、反馈意见等),该等信息仅用于解决您的问题、优化服务,不用于其他用途。</view>
+						
+						<view class="paragraph">4. 权限调用说明:若您需要使用本小程序的特定功能(如上传客户资料文件、拍摄客户相关照片),我们将向您申请调用设备的相册、摄像头权限,该等权限仅在您主动授权后启用,您可随时在设备设置中关闭权限,关闭后相关功能将无法正常使用,但不影响其他核心服务的使用,我们不会在未获得您授权的情况下擅自调用相关权限。</view>
+						
+						<text class="subsection-title">(二)信息收集方式</text>
+						<view class="paragraph">1. 主动提供:您在注册、登录、使用本小程序过程中,主动填写、录入、上传的信息(如注册信息、客户信息、反馈意见等)。</view>
+						<view class="paragraph">2. 自动收集:当您使用本小程序时,通过小程序后台系统自动收集的设备信息、网络信息、使用行为信息(该等信息均为匿名化或去标识化处理后的数据,不直接关联您的个人身份)。</view>
+						<view class="paragraph">3. 第三方获取:若您通过第三方账号快捷登录,我们将从第三方平台获取您的公开信息(仅获取昵称、头像等非隐私信息),该等信息的获取已获得第三方平台及您的授权,具体以第三方平台的隐私政策为准。</view>
+						<view class="paragraph">4. 特别说明:我们不会通过强制弹窗、默认勾选等非明示方式征求您的同意,所有信息收集均以您明确同意为前提,隐私政策将以显著方式展示,便于您随时查阅。</view>
+						
+						<text class="subsection-title">(三)信息使用限制</text>
+						<view class="paragraph">1. 我们仅在本政策约定的使用范围内使用收集的信息,不得超出服务目的使用信息;若因服务升级、功能优化需要,需扩大信息使用范围,我们将提前通过小程序公告、站内信等方式通知您,获得您的同意后再使用。</view>
+						<view class="paragraph">2. 我们不会将您的个人信息及客户信息用于与本小程序服务无关的用途,不会用于非法营销、广告推送等活动;若需进行服务相关的营销推送,我们将提前获得您的单独同意,您可随时取消订阅。</view>
+						<view class="paragraph">3. 我们不会通过自动化决策方式向您进行信息推送、商业营销,若确有需要,将同时提供不针对您个人特征的选项及便捷的拒绝方式。</view>
+					</view>
+				</view>
+				
+				<view class="section">
+					<text class="section-title">三、信息的存储与保护</text>
+					<view class="section-content">
+						<text class="subsection-title">(一)信息存储</text>
+						<view class="paragraph">1. 存储地点:我们将您的个人信息及客户信息存储在中华人民共和国境内的服务器上,不跨境存储;若因业务需要需跨境存储,我们将提前获得您的同意,并按照相关法律法规要求办理跨境数据传输手续,确保信息安全。</view>
+						<view class="paragraph">2. 存储期限:我们将按照"最小必要、最短期限"的原则存储信息,具体存储期限如下:(1)用户个人信息:自您注册账号之日起,至您注销账号后 180 天(用于处理账号注销后的遗留问题、纠纷排查等);(2)客户相关信息:由您自主控制存储期限,您可随时删除,若您未主动删除,将与您的账号绑定,账号注销后按本政策约定处理;(3)设备及使用行为信息:存储期限不超过 1 年(用于服务优化、故障排查,到期后将进行匿名化处理)。</view>
+						<view class="paragraph">3. 存储方式:我们采用加密存储、访问权限控制、定期备份等技术措施,对信息进行安全存储,防止信息泄露、篡改、丢失。</view>
+						
+						<text class="subsection-title">(二)信息保护措施</text>
+						<view class="paragraph">1. 技术保护:我们建立了完善的数据安全管理制度,采用 SSL 加密传输、AES 加密存储、防火墙防护、入侵检测等技术,保障信息在传输、存储过程中的安全;定期对服务器、系统进行安全检测、漏洞修复,防范网络攻击、病毒入侵等安全风险。</view>
+						<view class="paragraph">2. 管理保护:我们对接触用户信息的员工进行严格的权限管理,仅授权必要岗位员工接触相关信息,签订保密协议,定期进行隐私保护培训,明确保密责任;建立信息访问日志,对信息访问、操作进行记录,便于追溯核查。</view>
+						<view class="paragraph">3. 应急处理:若发生信息泄露、篡改、丢失等安全事件,我们将立即启动应急响应机制,采取补救措施(如封锁漏洞、删除泄露信息、通知相关用户等),并按照相关法律法规要求,及时向监管部门报告,同时告知您事件相关情况及处理进展。</view>
+						<view class="paragraph">4. 合规保障:我们严格遵守相关法律法规,不泄露、出售、出租您的个人信息及客户信息,杜绝违法违规处理信息的行为,定期开展隐私保护合规自查,确保信息处理行为合法合规。</view>
+					</view>
+				</view>
+				
+				<view class="section">
+					<text class="section-title">四、信息的共享、转让与公开披露</text>
+					<view class="section-content">
+						<view class="paragraph">我们严格保护您的信息安全,不会随意共享、转让、公开披露您的个人信息及客户信息,仅在以下合法情形下进行,且均会采取必要措施保障信息安全:</view>
+						<view class="paragraph">1. 经您书面同意:在获得您明确的书面同意后,我们可将相关信息共享给第三方(如您授权的团队成员、合作服务商等),共享范围仅限于您同意的内容。</view>
+						<view class="paragraph">2. 法律法规要求:根据司法机关、行政机关的合法要求(如法院传票、行政调查通知等),我们将依法提供相关信息,配合调查取证工作,不承担相关责任。</view>
+						<view class="paragraph">3. 服务合作需要:为保障本小程序服务的正常运行,我们可能将部分信息(如设备信息、使用行为信息,均已匿名化、去标识化处理,不关联个人身份)共享给合作的技术服务商(如服务器提供商、数据安全服务商等),该等服务商仅用于提供技术支持,不得将信息用于其他用途,且需与我们签订保密协议,承担保密责任。</view>
+						<view class="paragraph">4. 特别说明:我们不会向其他个人信息处理者提供您的个人信息,若确有必要,将向您明确告知接收方的名称、联系方式、处理目的、处理方式和个人信息的种类,并取得您的单独同意,同时对接收方的信息处理行为进行监督,确保信息安全;我们不会将您的个人信息进行匿名化处理前向第三方提供。</view>
+						<view class="paragraph">5. 转让与合并:若我们发生合并、分立、收购、资产转让等变更,相关信息将由变更后的主体承接,我们将提前通过小程序公告、站内信等方式通知您,确保信息的连续性和安全性,变更后的主体将继续履行本政策约定的信息保护义务。</view>
+						<view class="paragraph">6. 公开披露:我们不会主动公开披露您的个人信息及客户信息,除非获得您的书面同意,或根据法律法规要求必须公开披露,公开披露时将采取去标识化处理,避免泄露您的身份信息。</view>
+					</view>
+				</view>
+				
+				<view class="section">
+					<text class="section-title">五、用户的信息权利</text>
+					<view class="section-content">
+						<view class="paragraph">根据相关法律法规规定,您对自己的个人信息及录入的客户信息享有查询、修改、删除、撤回同意、注销账号等权利,我们将为您提供便捷的行使权利的渠道,具体操作方式如下:</view>
+						<view class="paragraph">1. 查询权:您可通过小程序"我的 - 个人中心"查询您的个人信息(如注册信息、账号绑定信息等),通过"客户管理"模块查询您录入的客户信息及相关操作记录。</view>
+						<view class="paragraph">2. 修改权:您可通过小程序"我的 - 个人中心 - 编辑资料"修改您的个人信息(如姓名、手机号码等),通过"客户管理"模块修改您录入的客户信息,修改后即时生效,我们将同步更新相关存储信息。</view>
+						<view class="paragraph">3. 删除权:您可通过小程序"客户管理"模块删除您录入的客户信息,通过"我的 - 个人中心 - 账号管理"申请删除部分个人信息(如第三方账号绑定信息);若您需删除全部个人信息,可申请注销账号,账号注销后,相关个人信息及客户信息将按本政策约定处理。</view>
+						<view class="paragraph">4. 撤回同意权:您可随时撤回对信息收集、使用、共享的同意,具体方式如下:(1)撤回设备权限授权:通过您的设备设置,关闭相册、摄像头等权限,撤回对该类信息收集的同意;(2)撤回信息使用同意:通过小程序"我的 - 设置 - 隐私设置",撤回对相关信息使用的同意;(3)撤回共享同意:联系客服,申请撤回对第三方共享信息的同意。撤回同意后,我们将停止相关信息的收集、使用、共享,但不影响撤回前已完成的信息处理行为的合法性,也不影响我们基于法律法规要求或其他合法事由处理信息。我们将为您提供便捷的撤回同意方式,不设置不必要或不合理条件。</view>
+						<view class="paragraph">5. 账号注销权:您可通过小程序"我的 - 设置 - 账号管理 - 注销账号"申请注销账号,注销前请您备份好相关客户信息及个人数据(注销后无法恢复)。账号注销后,我们将在 180 天内删除您的全部个人信息(用于处理遗留问题的信息除外),客户信息将由您自行负责备份或删除,我们将不再存储、使用该等信息。</view>
+						<view class="paragraph">6. 投诉与咨询权:若您对信息处理行为有疑问、异议,或认为您的信息权利受到侵害,可通过本政策约定的客服渠道联系我们,我们将在 15 个工作日内进行核查、处理,并向您反馈结果。我们已建立便捷的用户权利申请受理和处理机制,及时响应您的相关请求。</view>
+					</view>
+				</view>
+				
+				<view class="section">
+					<text class="section-title">六、未成年人信息保护</text>
+					<view class="section-content">
+						<view class="paragraph">1. 本小程序主要面向具备完全民事行为能力的个人用户及企业用户,不主动向未成年人提供服务;若未成年人在法定监护人的陪同下使用本小程序,必须取得法定监护人的书面或口头同意,法定监护人应承担相应的监护责任。</view>
+						<view class="paragraph">2. 若法定监护人发现未成年人擅自使用本小程序并收集了其个人信息,可联系我们申请删除相关信息、注销账号,我们将在核实身份后,及时采取相应措施,保障未成年人的信息安全。</view>
+						<view class="paragraph">3. 我们不会向未成年人收集、存储、使用超出服务必要的个人信息,不会泄露未成年人的个人信息,切实保障未成年人的隐私权益。</view>
+					</view>
+				</view>
+				
+				<view class="section">
+					<text class="section-title">七、隐私政策的修改与通知</text>
+					<view class="section-content">
+						<view class="paragraph">1. 我们有权根据法律法规变化、业务发展需要、技术升级等情况,修改本隐私政策内容,修改后的政策将更有利于保护您的信息安全。</view>
+						<view class="paragraph">2. 隐私政策修改后,我们将通过小程序公告、站内信、弹窗等显著方式提前通知您,修改后的政策自通知发布之日起生效;若您继续使用本小程序服务,即视为您已阅读、理解并同意修改后的隐私政策;若您不同意修改后的政策,可停止使用服务并注销账号。</view>
+						<view class="paragraph">3. 我们将在小程序内显著位置设置隐私政策查阅入口,您可随时查阅本政策的最新版本,了解信息处理的相关情况,确保您的知情权。</view>
+					</view>
+				</view>
+				
+				<view class="section">
+					<text class="section-title">八、免责条款</text>
+					<view class="section-content">
+						<view class="paragraph">1. 因不可抗力(包括但不限于地震、洪水、台风、战争、网络中断、服务器故障、病毒入侵等)导致信息泄露、篡改、丢失,或无法正常行使信息权利,我们不承担任何责任,您自行承担相关损失。</view>
+						<view class="paragraph">2. 因您自身操作失误、设备故障、网络问题、第三方软件干扰,或您将账号密码泄露给第三方,导致信息泄露、丢失或被非法操作,我们不承担责任,相关责任由您自行承担。</view>
+						<view class="paragraph">3. 您录入、上传的客户信息,若未获得客户的合法授权,导致的纠纷、损失,由您自行承担,与我们无关;若因您自身操作导致客户信息泄露,产生的一切责任由您自行承担。</view>
+						<view class="paragraph">4. 第三方服务相关的信息安全责任:本小程序可能包含第三方链接或服务,该等第三方服务的信息收集、使用由第三方自行负责,我们不承担相关责任,您使用第三方服务前,应仔细阅读第三方的隐私政策。</view>
+						<view class="paragraph">5. 我们已采取合理、必要的措施保障信息安全,但不保证信息完全无漏洞、无风险,若因网络攻击、黑客入侵等不可抗力之外的原因导致信息泄露,且我们无故意或重大过失,我们不承担赔偿责任。</view>
+					</view>
+				</view>
+				
+				<view class="section">
+					<text class="section-title">九、争议解决</text>
+					<view class="section-content">
+						<view class="paragraph">1. 本隐私政策的订立、履行、解释及争议解决,均适用中华人民共和国法律(不包括冲突法规则)。</view>
+						<view class="paragraph">2. 双方因履行本隐私政策产生的任何争议,应首先通过友好协商的方式解决;协商不成的,任何一方均有权向运营方所在地有管辖权的人民法院提起诉讼。</view>
+					</view>
+				</view>
+				
+				<view class="section">
+					<text class="section-title">十、其他条款</text>
+					<view class="section-content">
+						<view class="paragraph">1. 本隐私政策的最终解释权归本小程序运营方所有。</view>
+					</view>
+				</view>
+				
+				<!-- 底部占位 -->
+				<view class="bottom-spacer"></view>
+			</view>
+		</scroll-view>
+	</view>
+</template>
+
+<script setup>
+	import StatusBarPlaceholder from '@/components/status-bar-placeholder/index.vue'
+	
+	const goBack = () => {
+		uni.navigateBack()
+	}
+</script>
+
+<style lang="scss" scoped>
+	.agreement-container {
+		background: #f5f6f8;
+	}
+	
+	// 导航栏
+	.nav-bar {
+		background: #ffffff;
+		position: sticky;
+		top: 0;
+		z-index: 100;
+		box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
+		
+		.nav-content {
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			height: 88rpx;
+			padding: 0 32rpx;
+			
+			.nav-back {
+				width: 60rpx;
+				height: 60rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+			}
+			
+			.nav-title {
+				font-size: 32rpx;
+				font-weight: 600;
+				color: #333333;
+			}
+			
+			.nav-placeholder {
+				width: 60rpx;
+			}
+		}
+	}
+	
+	// 标题区域
+	.header-section {
+		background: linear-gradient(135deg, #4A90E2 0%, #6FB3F2 100%);
+		padding: 60rpx 40rpx 80rpx;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		
+		.main-title {
+			font-size: 40rpx;
+			font-weight: 600;
+			color: #ffffff;
+			text-align: center;
+			margin-bottom: 16rpx;
+			text-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
+		}
+		
+		.sub-title {
+			font-size: 32rpx;
+			font-weight: 500;
+			color: rgba(255, 255, 255, 0.9);
+			text-align: center;
+		}
+	}
+	
+	// 内容滚动区域
+	.content-scroll {
+		margin-top: -40rpx;
+		border-radius: 40rpx 40rpx 0 0;
+		background: #f5f6f8;
+		
+		.content-wrapper {
+			background: #ffffff;
+			padding: 48rpx 40rpx;
+			min-height: 100%;
+		}
+	}
+	
+	// 介绍文字
+	.intro-text {
+		font-size: 28rpx;
+		color: #666666;
+		line-height: 1.8;
+		margin-bottom: 40rpx;
+		padding: 32rpx;
+		background: linear-gradient(135deg, rgba(74, 144, 226, 0.05) 0%, rgba(111, 179, 242, 0.05) 100%);
+		border-radius: 16rpx;
+		border-left: 6rpx solid #4A90E2;
+	}
+	
+	// 章节
+	.section {
+		margin-bottom: 40rpx;
+		
+		.section-title {
+			display: block;
+			font-size: 30rpx;
+			font-weight: 600;
+			color: #333333;
+			margin-bottom: 24rpx;
+			padding-left: 16rpx;
+			border-left: 6rpx solid #4A90E2;
+		}
+		
+		.subsection-title {
+			display: block;
+			font-size: 28rpx;
+			font-weight: 600;
+			color: #4A90E2;
+			margin: 24rpx 0 16rpx;
+		}
+		
+		.section-content {
+			.paragraph {
+				font-size: 28rpx;
+				color: #666666;
+				line-height: 1.8;
+				margin-bottom: 16rpx;
+				text-align: justify;
+				text-indent: 2em;
+			}
+		}
+	}
+	
+	// 底部占位
+	.bottom-spacer {
+		height: 40rpx;
+	}
+</style>

+ 178 - 39
pages/mine/index.vue

@@ -1,8 +1,13 @@
 <template>
 	<view class="mine-container">
 	
+		<!-- 顶部用户信�区域 -->
 		<view class="user-header">
-			<StatusBarPlaceholder></StatusBarPlaceholder> 
+			<StatusBarPlaceholder></StatusBarPlaceholder>
+			
+			<!-- 背景装饰 -->
+			<view class="header-bg-decoration"></view>
+			
 			<view class="header-content">
 				<view class="user-info">
 					<view class="avatar-wrapper">
@@ -10,22 +15,24 @@
 					</view>
 					<view class="user-details">
 						<view class="name-row">
-							<text class="user-name">Àƽ</text>
-							<text class="user-role">123dasfjsal </text>
+							<text class="user-name">赵建平</text>
+							<text class="user-role">销售��</text>
 						</view>
-						<text class="company-name">浙江舒å�šç‰¹ç½‘ç»œç§‘æŠæœ‰é™�å…¬å�¸</text>
+						<text class="company-name">浙江舒�特网络科有�公�</text>
 					</view>
 				</view>
-				<view class="qr-btn">
-					<uni-icons type="qrcode" size="24" color="#ffffff"></uni-icons>
+				<view class="qr-btn" @click="showCard">
+					<uni-icons type="qrcode" size="28" color="#ffffff"></uni-icons>
 					<text class="qr-text">我的�片</text>
 				</view>
 			</view>
 		</view>
 
-		<!-- 线索数� -->
+		<!-- 线索数��片 -->
 		<view class="data-card">
-			<view class="card-title">线索数�</view>
+			<view class="card-header">
+				<text class="card-title">线索数�</text>
+			</view>
 			<view class="data-row">
 				<view class="data-item">
 					<text class="data-value">1,266</text>
@@ -42,9 +49,12 @@
 			</view>
 		</view>
 
-		<!-- 客户数� -->
+		<!-- 客户数��片 -->
 		<view class="data-card">
-			<view class="card-title">客户数�</view>
+			<view class="card-header">
+				<text class="card-title">客户数�</text>
+				<uni-icons type="eye" size="20" color="#999999"></uni-icons>
+			</view>
 			<view class="data-row">
 				<view class="data-item">
 					<text class="data-value">1,088</text>
@@ -61,9 +71,12 @@
 			</view>
 		</view>
 
-		<!-- 商机数� -->
+		<!-- 商机数��片 -->
 		<view class="data-card">
-			<view class="card-title">商机数�</view>
+			<view class="card-header">
+				<text class="card-title">商机数�</text>
+				<uni-icons type="eye" size="20" color="#999999"></uni-icons>
+			</view>
 			<view class="data-row">
 				<view class="data-item">
 					<text class="data-value">1,366</text>
@@ -83,22 +96,36 @@
 		<!-- 功能�� -->
 		<view class="menu-card">
 			<view class="menu-item" @click="navigateTo('guide')">
-				<uni-icons type="help" size="20" color="#667eea"></uni-icons>
+				<view class="menu-icon-wrapper">
+					<uni-icons type="help" size="22" color="#667eea"></uni-icons>
+				</view>
 				<text class="menu-text">使用指�</text>
 				<uni-icons type="right" size="16" color="#cccccc"></uni-icons>
 			</view>
 			<view class="menu-divider"></view>
 			<view class="menu-item" @click="navigateTo('service')">
-				<uni-icons type="paperclip" size="20" color="#667eea"></uni-icons>
+				<view class="menu-icon-wrapper">
+					<uni-icons type="paperclip" size="22" color="#667eea"></uni-icons>
+				</view>
 				<text class="menu-text">�系客�</text>
 				<uni-icons type="right" size="16" color="#cccccc"></uni-icons>
 			</view>
 			<view class="menu-divider"></view>
 			<view class="menu-item" @click="navigateTo('about')">
-				<uni-icons type="gear" size="20" color="#667eea"></uni-icons>
+				<view class="menu-icon-wrapper">
+					<uni-icons type="gear" size="22" color="#667eea"></uni-icons>
+				</view>
 				<text class="menu-text">关于我们</text>
 				<uni-icons type="right" size="16" color="#cccccc"></uni-icons>
 			</view>
+			<view class="menu-divider"></view>
+			<view class="menu-item logout-item" @click="handleLogout">
+				<view class="menu-icon-wrapper">
+					<uni-icons type="closeempty" size="22" color="#ff4d4f"></uni-icons>
+				</view>
+				<text class="menu-text logout-text">退出登录</text>
+				<uni-icons type="right" size="16" color="#cccccc"></uni-icons>
+			</view>
 		</view>
 	</view>
 </template>
@@ -106,13 +133,60 @@
 <script setup>
 import { ref ,onMounted} from 'vue'
 import  StatusBarPlaceholder from "@/components/status-bar-placeholder/index.vue"
+import { logout } from '@/api/login.js'
 
 const navigateTo = (page) => {
 	uni.showToast({
-		title: `功能å¼å�‘中ï¼{page}`,
+		title: ``,
 		icon: 'none'
 	})
 }
+
+// 显示�片
+const showCard = () => {
+	uni.showToast({
+		title: '我的�片',
+		icon: 'none'
+	})
+}
+
+// ��出登��const handleLogout = () => {
+	uni.showModal({
+		title: '�示',
+		content:'缺人�退出登录�?',
+		success: async (res) => {
+			if (res.confirm) {
+				try {
+					// 调用��出登录接��					await logout({})
+					
+					// 清除本地存储
+					uni.removeStorageSync('token')
+					uni.removeStorageSync('userInfo')
+					uni.removeStorageSync('code')
+					
+					// �示�功
+					uni.showToast({
+						title: '�作�功',
+						icon: 'success'
+					})
+					
+					// 延迟跳转到登录页
+					setTimeout(() => {
+						uni.reLaunch({
+							url: '/pages/login/login'
+						})
+					}, 1500)
+				} catch (error) {
+					console.error('退出登录失败', error)
+					uni.showToast({
+						title: '退出登录失败,请�试',
+						icon: 'none'
+					})
+				}
+			}
+		}
+	})
+}
 </script>
 
 <style lang="scss" scoped>
@@ -121,32 +195,50 @@ const navigateTo = (page) => {
 	background: #f5f6f8;
 }
 
-// 顶部用户信��片
+// 顶部用户信�区域
 .user-header {
-	background: linear-gradient(180deg, #5B86F5 0%, #36D1DC 100%);
-	padding: 40rpx;
+	background: linear-gradient(135deg, #4A90E2 0%, #6FB3F2 50%, #87CEEB 100%);
+	padding: 0 40rpx 160rpx;
 	padding-top: calc(var(--status-bar-height) + 20rpx);
 	position: relative;
+	overflow: hidden;
+	
+	// 背景光晕装饰
+	.header-bg-decoration {
+		position: absolute;
+		top: -100rpx;
+		right: -100rpx;
+		width: 400rpx;
+		height: 400rpx;
+		background: radial-gradient(circle, rgba(255,255,255,0.15) 0%, transparent 70%);
+		border-radius: 50%;
+	}
 	
 	.header-content {
 		position: relative;
 		z-index: 2;
+		display: flex;
+		justify-content: space-between;
+		align-items: flex-start;
 	}
 	
 	.user-info {
 		display: flex;
 		align-items: center;
-		margin-bottom: 32rpx;
+		flex: 1;
 		
 		.avatar-wrapper {
 			flex-shrink: 0;
 			margin-right: 24rpx;
+			position: relative;
 			
 			.avatar {
-				width: 120rpx;
-				height: 120rpx;
+				width: 128rpx;
+				height: 128rpx;
 				border-radius: 50%;
-				border: 4rpx solid rgba(255, 255, 255, 0.3);
+				border: 4rpx solid rgba(255, 255, 255, 0.4);
+				box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.15);
+				background: #ffffff;
 			}
 		}
 		
@@ -162,39 +254,46 @@ const navigateTo = (page) => {
 					font-size: 36rpx;
 					font-weight: 600;
 					color: #ffffff;
+					text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
 				}
 				
 				.user-role {
 					font-size: 22rpx;
-					color: rgba(255, 255, 255, 0.9);
-					background: rgba(255, 255, 255, 0.2);
-					padding: 4rpx 12rpx;
+					color: #ffffff;
+					background: rgba(255, 255, 255, 0.25);
+					padding: 4rpx 16rpx;
 					border-radius: 20rpx;
-					margin-left: 12rpx;
+					margin-left: 16rpx;
+					font-weight: 500;
 				}
 			}
 			
 			.company-name {
 				font-size: 24rpx;
-				color: rgba(255, 255, 255, 0.8);
+				color: rgba(255, 255, 255, 0.85);
 				display: block;
+				text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
 			}
 		}
 	}
 	
 	.qr-btn {
 		display: flex;
+		flex-direction: column;
 		align-items: center;
 		justify-content: center;
 		background: rgba(255, 255, 255, 0.2);
-		padding: 12rpx 24rpx;
+		padding: 16rpx 20rpx;
 		border-radius: 24rpx;
-		align-self: flex-start;
+		backdrop-filter: blur(10rpx);
+		border: 1rpx solid rgba(255, 255, 255, 0.3);
+		box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
 		
 		.qr-text {
-			font-size: 22rpx;
+			font-size: 20rpx;
 			color: #ffffff;
-			margin-left: 8rpx;
+			margin-top: 4rpx;
+			text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
 		}
 	}
 }
@@ -202,15 +301,22 @@ const navigateTo = (page) => {
 // 数��片
 .data-card {
 	background: #ffffff;
-	margin: 20rpx;
+	margin: 20rpx 40rpx;
 	padding: 32rpx;
 	border-radius: 24rpx;
 	box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06);
 	
+	.card-header {
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		margin-bottom: 24rpx;
+	}
+	
 	.card-title {
 		font-size: 28rpx;
-		color: #666666;
-		margin-bottom: 24rpx;
+		font-weight: 600;
+		color: #333333;
 	}
 	
 	.data-row {
@@ -222,12 +328,14 @@ const navigateTo = (page) => {
 			flex-direction: column;
 			align-items: center;
 			flex: 1;
+			position: relative;
 			
 			.data-value {
 				font-size: 40rpx;
 				font-weight: 600;
 				color: #333333;
 				margin-bottom: 12rpx;
+				font-family: DIN, 'DIN Alternate', sans-serif;
 			}
 			
 			.data-label {
@@ -239,8 +347,15 @@ const navigateTo = (page) => {
 				color: #ff6b35;
 			}
 			
-			&:not(:last-child) {
-				border-right: 1rpx solid #f0f0f0;
+			&:not(:last-child)::after {
+				content: '';
+				position: absolute;
+				right: 0;
+				top: 50%;
+				transform: translateY(-50%);
+				width: 1rpx;
+				height: 60rpx;
+				background: #f0f0f0;
 			}
 		}
 	}
@@ -249,7 +364,7 @@ const navigateTo = (page) => {
 // 功能��
 .menu-card {
 	background: #ffffff;
-	margin: 20rpx;
+	margin: 20rpx 40rpx;
 	padding: 0 32rpx;
 	border-radius: 24rpx;
 	box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06);
@@ -259,11 +374,21 @@ const navigateTo = (page) => {
 		align-items: center;
 		padding: 32rpx 0;
 		
+		.menu-icon-wrapper {
+			width: 60rpx;
+			height: 60rpx;
+			border-radius: 16rpx;
+			background: rgba(102, 126, 234, 0.08);
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			margin-right: 20rpx;
+		}
+		
 		.menu-text {
 			flex: 1;
 			font-size: 28rpx;
 			color: #333333;
-			margin-left: 20rpx;
 		}
 	}
 	
@@ -271,5 +396,19 @@ const navigateTo = (page) => {
 		height: 1rpx;
 		background: #f0f0f0;
 	}
+	
+	// ��出登录样��	.logout-item {
+		.menu-icon-wrapper {
+			background: rgba(255, 77, 79, 0.08);
+		}
+		
+		.menu-text {
+			color: #ff4d4f;
+			
+			&.logout-text {
+				color: #ff4d4f;
+			}
+		}
+	}
 }
 </style>

+ 208 - 69
pages/splash/splash.vue

@@ -1,20 +1,29 @@
 <template>
 	<view class="splash-container">
+		<!-- 背景装饰 -->
+		<view class="splash-bg-1"></view>
+		<view class="splash-bg-2"></view>
+		
 		<!-- Logo 区域 -->
 		<view class="logo-section">
-			<image class="logo-icon" src="/static/image/public/logo.png" mode="aspectFill"></image>
+			<view class="logo-wrapper">
+				<view class="logo-glow"></view>
+				<image class="logo-icon" src="/static/image/public/logo.png" mode="aspectFit"></image>
+			</view>
 			<text class="app-name">{{appName}}</text>
 			<text class="app-slogan">您的客户关系管理助手</text>
 		</view>
 
 		<!-- 加载动画 -->
 		<view class="loading-section">
-			<view class="loading-dots">
-				<view class="dot dot1"></view>
-				<view class="dot dot2"></view>
-				<view class="dot dot3"></view>
-			</view>
-			<text class="loading-text">{{ loadingText }}</text>
+			<text class="loading-text">
+				正在加载
+				<view class="loading-dots">
+					<view class="dot dot1"></view>
+					<view class="dot dot2"></view>
+					<view class="dot dot3"></view>
+				</view>
+			</text>
 		</view>
 
 		<!-- 版本信息 -->
@@ -33,8 +42,14 @@
 		onMounted
 	} from 'vue'
 	import {
-		isLogin
+		isLogin,
+		getToken,
+		saveUserInfo,
+		clearUserInfo
 	} from '@/utils/userCache.js'
+	import {
+		getUserInfo as fetchUserInfo
+	} from '@/api/login.js'
 	import {
 		getCurrentConfig
 	} from '@/config/index.js'
@@ -44,6 +59,7 @@
 	// 页面加载
 	onMounted(async () => {
 		const config = await getCurrentConfig()
+		console.log(config,"configconfigconfigconfig");
 		appName.value = config.appName
 		version.value = config.appVersion
 		initApp()
@@ -55,30 +71,52 @@
 	const initApp = async () => {
 		try {
 			// 模拟加载延迟(提升用户体验)
-			// await sleep(500)
+			await sleep(500)
 
 			loadingText.value = '检查登录状态...'
 
-			// 检查登录状态
-			// const loggedIn = isLogin() 
-
-			// 再延迟一点,让动画更流畅
-			// await sleep(800)
-
-			if (true) {
+			// 获取本地 token
+			const token = getToken()
+			
+			// 如果没有 token,直接跳转登录页
+			if (!token) {
+				console.log('未登录,token 不存在')
+				await sleep(800)
+				uni.reLaunch({
+					url: '/pages/index/index'
+				})
+				return
+			}
+			
+			// 调用 getUserInfo 接口验证 token
+			const res = await fetchUserInfo({})
+			
+			if (res.code === 200) {
+				// token 有效,更新用户信息
+				const userInfo = res.data || res
+				saveUserInfo(userInfo, token)
+				console.log('登录态有效,用户信息已更新')
+				// 延迟跳转,让动画更流畅
+				await sleep(500)
 				// 已登录,跳转首页
 				uni.reLaunch({
 					url: '/pages/index/index'
 				})
 			} else {
-				// 未登录,跳转登录页
+				// token 失效,清除本地存储
+				console.log('登录凭证失效,需要重新登录')
+				clearUserInfo()
+				await sleep(800)
+				// 跳转登录页
 				uni.reLaunch({
 					url: '/pages/login/login'
 				})
 			}
 		} catch (error) {
-			console.error('初始化失败:', error)
-
+			console.error('验证登录态失败:', error)
+			// 接口调用失败,也视为 token 失效
+			clearUserInfo()
+			
 			// 出错时跳转到登录页
 			uni.reLaunch({
 				url: '/pages/login/login'
@@ -98,12 +136,36 @@
 <style lang="scss" scoped>
 	.splash-container {
 		min-height: 100vh;
-		background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
+		background: linear-gradient(135deg, #4A90E2 0%, #6FB3F2 50%, #87CEEB 100%);
+		position: relative;
+		overflow: hidden;
 		display: flex;
 		flex-direction: column;
 		align-items: center;
 		justify-content: center;
 		padding: 0 40rpx;
+		
+		.splash-bg-1 {
+			position: absolute;
+			top: -20%;
+			left: -10%;
+			width: 60%;
+			height: 60%;
+			background: radial-gradient(circle, rgba(255,255,255,0.15) 0%, transparent 70%);
+			border-radius: 50%;
+			animation: floatBg1 8s ease-in-out infinite;
+		}
+		
+		.splash-bg-2 {
+			position: absolute;
+			bottom: -20%;
+			right: -10%;
+			width: 70%;
+			height: 70%;
+			background: radial-gradient(circle, rgba(255,255,255,0.12) 0%, transparent 70%);
+			border-radius: 50%;
+			animation: floatBg2 10s ease-in-out infinite;
+		}
 	}
 
 	// Logo 区域
@@ -112,29 +174,60 @@
 		flex-direction: column;
 		align-items: center;
 		margin-bottom: 120rpx;
-
-		.logo-icon {
-			width: 200rpx;
-			height: 200rpx;
-			border-radius: 40rpx;
+		position: relative;
+		z-index: 10;
+		
+		.logo-wrapper {
+			position: relative;
+			width: 240rpx;
+			height: 240rpx;
 			display: flex;
 			align-items: center;
 			justify-content: center;
-			animation: logoFloat 2s ease-in-out infinite;
+			
+			.logo-glow {
+				position: absolute;
+				top: 50%;
+				left: 50%;
+				transform: translate(-50%, -50%);
+				width: 280rpx;
+				height: 280rpx;
+				background: radial-gradient(circle, rgba(255,255,255,0.3) 0%, transparent 70%);
+				border-radius: 50%;
+				animation: logoGlow 3s ease-in-out infinite;
+			}
+			
+			.logo-icon {
+				width: 200rpx;
+				height: 200rpx;
+				border-radius: 44rpx;
+				background: rgba(255, 255, 255, 0.95);
+				box-shadow: 0 20rpx 60rpx rgba(0, 0, 0, 0.15),
+							0 0 40rpx rgba(255, 255, 255, 0.3);
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				animation: logoFloat 3s ease-in-out infinite;
+				position: relative;
+				z-index: 2;
+			}
 		}
 
 		.app-name {
 			font-size: 48rpx;
 			font-weight: 600;
 			color: #ffffff;
-			margin-top: 40rpx;
-			letter-spacing: 2rpx;
+			margin-top: 48rpx;
+			letter-spacing: 3rpx;
+			text-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.15);
 		}
 
 		.app-slogan {
 			font-size: 26rpx;
-			color: rgba(255, 255, 255, 0.8);
-			margin-top: 16rpx;
+			color: rgba(255, 255, 255, 0.85);
+			margin-top: 20rpx;
+			letter-spacing: 1rpx;
+			text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
 		}
 	}
 
@@ -143,38 +236,52 @@
 		display: flex;
 		flex-direction: column;
 		align-items: center;
+		position: relative;
+		z-index: 10;
 
-		.loading-dots {
+		.loading-text {
+			font-size: 28rpx;
+			color: rgba(255, 255, 255, 0.95);
+			letter-spacing: 2rpx;
+			text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
 			display: flex;
-			justify-content: center;
 			align-items: center;
-			margin-bottom: 24rpx;
-
-			.dot {
-				width: 20rpx;
+			justify-content: center;
+			background: rgba(255, 255, 255, 0.15);
+			padding: 20rpx 40rpx;
+			border-radius: 40rpx;
+			backdrop-filter: blur(10rpx);
+			box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.1);
+			
+			.loading-dots {
+				display: flex;
+				justify-content: center;
+				align-items: center;
+				margin-left: 8rpx;
 				height: 20rpx;
-				border-radius: 50%;
-				background-color: #ffffff;
-				margin: 0 8rpx;
-				opacity: 0.3;
-			}
 
-			.dot1 {
-				animation: loadingDot 1.4s ease-in-out infinite;
-			}
+				.dot {
+					width: 12rpx;
+					height: 12rpx;
+					border-radius: 50%;
+					background-color: #ffffff;
+					margin: 0 4rpx;
+					opacity: 0.4;
+					box-shadow: 0 0 15rpx rgba(255, 255, 255, 0.5);
+				}
 
-			.dot2 {
-				animation: loadingDot 1.4s ease-in-out 0.2s infinite;
-			}
+				.dot1 {
+					animation: loadingDot 1.4s ease-in-out infinite;
+				}
 
-			.dot3 {
-				animation: loadingDot 1.4s ease-in-out 0.4s infinite;
-			}
-		}
+				.dot2 {
+					animation: loadingDot 1.4s ease-in-out 0.2s infinite;
+				}
 
-		.loading-text {
-			font-size: 26rpx;
-			color: rgba(255, 255, 255, 0.9);
+				.dot3 {
+					animation: loadingDot 1.4s ease-in-out 0.4s infinite;
+				}
+			}
 		}
 	}
 
@@ -186,38 +293,70 @@
 		flex-direction: column;
 		align-items: center;
 		justify-content: center;
+		z-index: 10;
+		background: rgba(255, 255, 255, 0.1);
+		padding: 20rpx 40rpx;
+		border-radius: 32rpx;
+		backdrop-filter: blur(10rpx);
+		box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.1);
+		border: 1rpx solid rgba(255, 255, 255, 0.2);
 
 		.version-text {
 			font-size: 22rpx;
-			color: rgba(255, 255, 255, 0.6);
+			color: rgba(255, 255, 255, 0.7);
+			text-align: center;
+			line-height: 1.6;
+			text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
 		}
 	}
 
 	// 动画
 	@keyframes logoFloat {
-
-		0%,
-		100% {
-			transform: translateY(0);
+		0%, 100% {
+			transform: translateY(0) scale(1);
+		}
+		50% {
+			transform: translateY(-15rpx) scale(1.02);
+		}
+	}
+	
+	@keyframes logoGlow {
+		0%, 100% {
+			opacity: 0.5;
+			transform: translate(-50%, -50%) scale(1);
 		}
-
 		50% {
-			transform: translateY(-20rpx);
+			opacity: 0.8;
+			transform: translate(-50%, -50%) scale(1.1);
 		}
 	}
 
 	@keyframes loadingDot {
-
-		0%,
-		80%,
-		100% {
-			transform: scale(0.6);
-			opacity: 0.3;
+		0%, 80%, 100% {
+			transform: scale(0.8);
+			opacity: 0.4;
 		}
-
 		40% {
-			transform: scale(1);
+			transform: scale(1.2);
 			opacity: 1;
 		}
 	}
+	
+	@keyframes floatBg1 {
+		0%, 100% {
+			transform: translate(0, 0) scale(1);
+		}
+		50% {
+			transform: translate(30rpx, -30rpx) scale(1.05);
+		}
+	}
+	
+	@keyframes floatBg2 {
+		0%, 100% {
+			transform: translate(0, 0) scale(1);
+		}
+		50% {
+			transform: translate(-30rpx, 30rpx) scale(1.08);
+		}
+	}
 </style>

BIN
static/image/public/card-qr.png


BIN
static/image/public/card-save.png


BIN
static/image/public/card-sharing.png


BIN
static/image/public/qr-icon.png


BIN
static/image/public/wechat-icon.png


+ 51 - 106
utils/request.js

@@ -2,117 +2,62 @@
  * 请求封装
  * 根据环境自动切换 API 地址
  */
-import { getCurrentConfig, CURRENT_ENV } from '@/config/index.js'
-
-// 缓存配置
-let configCache = null
-
-// 初始化配置
-const initConfig = async () => {
-	if (!configCache) {
-		configCache = await getCurrentConfig()
-		console.log('当前环境:', configCache.env, '| API 地址:', configCache.baseUrl)
+import config from '@/config/index.js'
+
+const {
+	baseUrl,
+	timeout,
+	debug,
+	env
+} = config
+
+const noTokenUrls = [
+	'/oa/code/sendCode', // 获取验证码
+	'/codeLogin', // 登录接口
+	'/xcxLogin' // 一键登录
+];
+// 核心请求方法
+const request = (url, method = 'GET', data = {}) => {
+	// 1. 检查当前接口是否需要token
+	const needToken = !noTokenUrls.some(path => url.startsWith(path));
+	// 2. 获取本地存储的token
+	const token = uni.getStorageSync('token') || '';
+
+	const fullUrl = baseUrl + url;
+	// 构建请求头(有token则自动携带)
+	const header = {
+		'Content-Type': 'application/json;charset=UTF-8'
+	};
+	if (needToken && token) {
+		header["Authorization"] = "Bearer " + token
+		// Bearer
 	}
-	return configCache
-}
-
-// 预加载配置
-initConfig()
-
-/**
- * 统一请求方法
- */
-export const request = async (options) => {
-	// 确保配置已加载
-	const config = await initConfig()
-	const { baseUrl, timeout, debug } = config
-	
 	return new Promise((resolve, reject) => {
-		// 获取 token
-		const token = uni.getStorageSync('token') || ''
-		
-		if (debug) {
-			console.log('Request:', options.method || 'GET', options.url, options.data)
-		}
-		
 		uni.request({
-			url: baseUrl + options.url,
-			method: options.method || 'GET',
-			data: options.data || {},
-			header: {
-				'Content-Type': 'application/json',
-				'Authorization': token ? `Bearer ${token}` : ''
-			},
-			timeout: timeout,
+			url: fullUrl,
+			method: method.toUpperCase(), // 统一转大写避免错误
+			data: data, // POST 参数放请求体
+			header: header,
+			timeout: 10000,
 			success: (res) => {
-				const { statusCode, data } = res
-				
-				if (debug) {
-					console.log('Response:', statusCode, data)
-				}
-				
-				// HTTP 状态码判断
-				if (statusCode === 200) {
-					// 业务状态码判断
-					if (data.code === 0 || data.code === 200 || data.success) {
-						resolve(data)
-					} else {
-						// 业务错误
-						uni.showToast({
-							title: data.message || data.msg || '请求失败',
-							icon: 'none',
-							duration: 2000
-						})
-						reject(data)
-					}
-				} else if (statusCode === 401) {
-					// 未授权,清除缓存并跳转登录页
-					uni.removeStorageSync('userInfo')
-					uni.removeStorageSync('token')
-					uni.reLaunch({
-						url: '/pages/login/login'
-					})
-					reject({ message: '未授权,请重新登录' })
-				} else {
-					// 其他错误
-					uni.showToast({
-						title: '网络请求失败',
-						icon: 'none',
-						duration: 2000
-					})
-					reject(res)
-				}
+				resolve(res.data);
 			},
 			fail: (err) => {
-				console.error('Request fail:', err)
+				// 统一错误提示
 				uni.showToast({
-					title: '网络连接失败',
-					icon: 'none',
-					duration: 2000
-				})
-				reject(err)
+					title: err.errMsg || '请求失败',
+					icon: 'none'
+				});
+				reject(err);
 			}
-		})
-	})
-}
-
-/**
- * 快捷请求方法
- */
-export const get = (url, data) => {
-	return request({ url, method: 'GET', data })
-}
-
-export const post = (url, data) => {
-	return request({ url, method: 'POST', data })
-}
-
-export const put = (url, data) => {
-	return request({ url, method: 'PUT', data })
-}
-
-export const del = (url, data) => {
-	return request({ url, method: 'DELETE', data })
-}
-
-export default request
+		});
+	});
+};
+
+// 导出方法
+export default {
+	// GET 请求
+	get: (url, data = {}) => request(url, 'GET', data),
+	// POST 请求
+	post: (url, data = {}) => request(url, 'POST', data)
+};

+ 2 - 3
utils/userCache.js

@@ -6,7 +6,7 @@ const USER_INFO_KEY = 'userInfo'
 const TOKEN_KEY = 'token'
 
 /**
- * 保存用户信息
+ * 保存用户信息和 token
  * @param {object} userInfo - 用户信息对象
  * @param {string} token - 登录 token
  */
@@ -56,9 +56,8 @@ export const getToken = () => {
  * @returns {boolean} 是否已登录
  */
 export const isLogin = () => {
-	const userInfo = getUserInfo()
 	const token = getToken()
-	return !!(userInfo && token)
+	return !!token
 }
 
 /**