This commit is contained in:
parent
913c2ba036
commit
dba965344a
112
App.vue
112
App.vue
|
|
@ -1,6 +1,5 @@
|
|||
<script>
|
||||
import WechatAuth from '@/utils/wechat-auth.js'
|
||||
import { getUserInfo } from '@/http/api/profile.js'
|
||||
import { wxLogin } from '@/http/api/auth.js'
|
||||
|
||||
export default {
|
||||
onLaunch: function() {
|
||||
|
|
@ -16,41 +15,96 @@
|
|||
methods: {
|
||||
// 应用初始化
|
||||
async initApp() {
|
||||
console.log('应用初始化开始')
|
||||
await this.checkAutoLogin()
|
||||
},
|
||||
|
||||
// 等待HTTP配置初始化
|
||||
async waitForHttpInit() {
|
||||
// 等待uni.$u.http可用
|
||||
let retryCount = 0
|
||||
const maxRetries = 10
|
||||
|
||||
while (!uni.$u || !uni.$u.http) {
|
||||
if (retryCount >= maxRetries) {
|
||||
throw new Error('HTTP配置初始化超时')
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, 100))
|
||||
retryCount++
|
||||
}
|
||||
|
||||
console.log('HTTP配置初始化完成')
|
||||
},
|
||||
|
||||
// 检查自动登录
|
||||
async checkAutoLogin() {
|
||||
try {
|
||||
await this.checkLoginStatus()
|
||||
// 检查本地是否有有效token
|
||||
const token = uni.getStorageSync('token')
|
||||
if (token) {
|
||||
return
|
||||
}
|
||||
|
||||
// 等待HTTP配置初始化完成
|
||||
await this.waitForHttpInit()
|
||||
|
||||
// 获取微信登录code
|
||||
const loginRes = await new Promise((resolve, reject) => {
|
||||
uni.login({
|
||||
success: resolve,
|
||||
fail: reject
|
||||
})
|
||||
})
|
||||
|
||||
if (loginRes.code) {
|
||||
// 调用后端登录接口
|
||||
const result = await uni.$u.http.post('/wechat/user/mini/login', {
|
||||
code: loginRes.code
|
||||
}, {
|
||||
custom: {
|
||||
loading: false,
|
||||
toast: false,
|
||||
auth: false
|
||||
}
|
||||
})
|
||||
|
||||
if (result && result.token) {
|
||||
// 用户已授权过手机号,保存登录信息
|
||||
this.saveLoginData(result)
|
||||
} else {
|
||||
// 用户未授权手机号,保存微信登录code供后续使用
|
||||
this.saveWxCode(loginRes.code)
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// 静默处理初始化错误
|
||||
// 静默处理错误,不影响应用正常启动
|
||||
console.error('自动登录失败:', error)
|
||||
}
|
||||
},
|
||||
|
||||
// 检查登录状态
|
||||
async checkLoginStatus() {
|
||||
const token = WechatAuth.getToken()
|
||||
|
||||
if (!token) {
|
||||
return
|
||||
// 保存登录数据
|
||||
saveLoginData(result) {
|
||||
uni.setStorageSync('token', result.token)
|
||||
if (result.refreshToken) {
|
||||
uni.setStorageSync('refreshToken', result.refreshToken)
|
||||
}
|
||||
if (result.userInfo) {
|
||||
uni.setStorageSync('wxUserInfo', result.userInfo)
|
||||
uni.setStorageSync('userInfo', result.userInfo)
|
||||
}
|
||||
|
||||
try {
|
||||
// 验证token有效性
|
||||
const userInfo = await getUserInfo({
|
||||
custom: {
|
||||
loading: false,
|
||||
toast: false
|
||||
}
|
||||
})
|
||||
// 设置登录状态
|
||||
const loginStep = result.userInfo && result.userInfo.profileCompleted
|
||||
? 'profile_completed'
|
||||
: 'phone_authed'
|
||||
uni.setStorageSync('loginStep', loginStep)
|
||||
},
|
||||
|
||||
// 更新本地用户信息
|
||||
if (userInfo) {
|
||||
WechatAuth.saveLoginInfo(token, WechatAuth.getRefreshToken(), userInfo)
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
// token无效,清除登录信息
|
||||
if (error.code === 401 || error.statusCode === 401) {
|
||||
WechatAuth.clearLoginInfo()
|
||||
}
|
||||
}
|
||||
// 保存微信code
|
||||
saveWxCode(code) {
|
||||
uni.setStorageSync('wxLoginCode', code)
|
||||
uni.setStorageSync('loginDate', new Date().toISOString())
|
||||
uni.setStorageSync('loginStep', 'wx_logged')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -202,30 +202,28 @@ export const userLogin = (loginData, config = {}) => {
|
|||
* })
|
||||
*/
|
||||
export const wxLogin = (wxData, config = {}) => {
|
||||
return executeAuthRequest('/auth/wx-login', wxData, 'PUBLIC_AUTH', AUTH_LOADING_TEXTS.WX_LOGIN, config)
|
||||
return executeAuthRequest('/wechat/user/mini/login', wxData, 'PUBLIC_AUTH', AUTH_LOADING_TEXTS.WX_LOGIN, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信手机号授权登录
|
||||
* @description 使用微信手机号授权进行登录认证,适用于小程序环境
|
||||
* 更新用户手机号
|
||||
* @description 通过微信手机号授权更新已登录用户的手机号,需要用户已登录
|
||||
* @param {PhoneAuthData} phoneData 手机号授权数据对象
|
||||
* @param {string} phoneData.code 微信登录凭证code
|
||||
* @param {string} phoneData.encryptedData 加密的手机号数据
|
||||
* @param {string} phoneData.iv 初始向量
|
||||
* @param {Object} [config={}] 自定义请求配置
|
||||
* @returns {Promise<AuthResult>} 返回认证结果,包含token和用户信息
|
||||
* @returns {Promise<string>} 返回解密后的手机号
|
||||
* @example
|
||||
* // 微信手机号登录
|
||||
* const result = await wxPhoneLogin({
|
||||
* code: 'wx_code_123',
|
||||
* // 更新用户手机号
|
||||
* const phoneNumber = await updatePhoneNumber({
|
||||
* encryptedData: 'encrypted_phone_data',
|
||||
* iv: 'initial_vector'
|
||||
* })
|
||||
*
|
||||
* @since 2.0.0 新增的登录流程重构功能
|
||||
* @since 2.0.0 重构为手机号更新功能
|
||||
*/
|
||||
export const wxPhoneLogin = (phoneData, config = {}) => {
|
||||
return executeAuthRequest('/auth/wx-phone-login', phoneData, 'PUBLIC_AUTH', AUTH_LOADING_TEXTS.PHONE_VERIFY, config)
|
||||
export const updatePhoneNumber = (phoneData, config = {}) => {
|
||||
return executeAuthRequest('/user/wechat/mini/phone-update', phoneData, 'AUTHENTICATED_SESSION', AUTH_LOADING_TEXTS.PHONE_VERIFY, config)
|
||||
}
|
||||
|
||||
// ==================== 用户注册相关API ====================
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
const ENV_CONFIG = {
|
||||
// 开发环境
|
||||
development: {
|
||||
baseURL: 'https://dev-api.pet-ai.com',
|
||||
baseURL: 'http://localhost:8888',
|
||||
timeout: 30000
|
||||
},
|
||||
// 测试环境
|
||||
|
|
@ -57,32 +57,7 @@ export const HTTP_CONFIG = {
|
|||
*/
|
||||
export const NO_AUTH_APIS = [
|
||||
// 用户认证相关
|
||||
'/auth/login',
|
||||
'/auth/register',
|
||||
'/auth/wx-login',
|
||||
'/auth/wx-phone-login', // 微信手机号登录
|
||||
'/auth/refresh',
|
||||
'/auth/reset-password', // 重置密码
|
||||
|
||||
// 短信验证相关
|
||||
'/sms/send', // 发送短信验证码
|
||||
'/sms/verify', // 验证短信验证码
|
||||
|
||||
// 公开浏览的接口
|
||||
'/ai/knowledge', // AI知识库
|
||||
'/adoption/pets', // 浏览待领养宠物
|
||||
'/adoption/pets/search', // 搜索宠物
|
||||
'/adoption/pets/filter', // 筛选宠物
|
||||
'/adoption/organizations', // 领养机构列表
|
||||
'/reviews', // 查看评价
|
||||
'/reviews/*', // 查看特定对象的评价
|
||||
|
||||
// 系统相关
|
||||
'/system/config', // 系统配置
|
||||
'/system/version', // 版本信息
|
||||
'/system/check-update', // 检查更新
|
||||
'/common/regions', // 地区数据
|
||||
'/common/upload-config' // 上传配置
|
||||
'/wechat/user/mini/login', // 微信小程序登录
|
||||
]
|
||||
|
||||
/**
|
||||
|
|
@ -90,30 +65,7 @@ export const NO_AUTH_APIS = [
|
|||
* 这些接口在调用时如果未登录会自动跳转到登录页面
|
||||
*/
|
||||
export const AUTH_REQUIRED_APIS = [
|
||||
// 用户个人信息相关
|
||||
'/profile/info', // 获取用户信息
|
||||
'/profile/update', // 更新用户信息
|
||||
'/profile/avatar', // 更新头像
|
||||
'/profile/stats', // 用户统计信息
|
||||
|
||||
// 宠物管理相关
|
||||
'/pets/create', // 创建宠物
|
||||
'/pets/update', // 更新宠物信息
|
||||
'/pets/delete', // 删除宠物
|
||||
'/pets/my', // 我的宠物列表
|
||||
|
||||
// 领养相关
|
||||
'/adoption/apply', // 申请领养
|
||||
'/adoption/my-applications', // 我的申请
|
||||
'/adoption/my-pets', // 我发布的宠物
|
||||
|
||||
// 收藏和关注
|
||||
'/favorites/*', // 收藏相关
|
||||
'/follows/*', // 关注相关
|
||||
|
||||
// 消息和通知
|
||||
'/messages/*', // 消息相关
|
||||
'/notifications/*' // 通知相关
|
||||
]
|
||||
|
||||
/**
|
||||
|
|
@ -142,6 +94,31 @@ export function checkApiAuth(url) {
|
|||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查接口是否需要强制登录
|
||||
* @param {String} url 接口URL
|
||||
* @returns {Boolean} 是否需要强制登录
|
||||
*/
|
||||
export function checkAuthRequiredApi(url) {
|
||||
// 移除查询参数,只保留路径
|
||||
const path = url.split('?')[0]
|
||||
|
||||
// 检查是否在需要强制登录的列表中
|
||||
for (const authApi of AUTH_REQUIRED_APIS) {
|
||||
// 支持通配符匹配
|
||||
if (authApi.includes('*')) {
|
||||
const regex = new RegExp('^' + authApi.replace(/\*/g, '.*') + '$')
|
||||
if (regex.test(path)) {
|
||||
return true
|
||||
}
|
||||
} else if (path === authApi || path.startsWith(authApi + '/')) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加不需要鉴权的接口
|
||||
* @param {String|Array} apis 接口路径或接口路径数组
|
||||
|
|
|
|||
|
|
@ -1,7 +1,109 @@
|
|||
// HTTP请求配置和拦截器
|
||||
// 基于uView-next的luch-request库实现
|
||||
|
||||
import { HTTP_CONFIG, checkApiAuth } from './config.js'
|
||||
import { HTTP_CONFIG, checkApiAuth, AUTH_REQUIRED_APIS } from './config.js'
|
||||
|
||||
/**
|
||||
* 清理认证数据
|
||||
*/
|
||||
function clearAuthData() {
|
||||
uni.removeStorageSync(HTTP_CONFIG.storageKeys.token)
|
||||
uni.removeStorageSync(HTTP_CONFIG.storageKeys.refreshToken)
|
||||
uni.removeStorageSync(HTTP_CONFIG.storageKeys.userInfo)
|
||||
uni.removeStorageSync('loginStep')
|
||||
uni.removeStorageSync('wxLoginCode')
|
||||
uni.removeStorageSync('wxUserInfo')
|
||||
uni.removeStorageSync('loginDate')
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查接口是否需要强制登录
|
||||
* @param {String} url 接口URL
|
||||
* @returns {Boolean} 是否需要强制登录
|
||||
*/
|
||||
function checkAuthRequiredApi(url) {
|
||||
// 移除查询参数,只保留路径
|
||||
const path = url.split('?')[0]
|
||||
|
||||
// 检查是否在需要强制登录的列表中
|
||||
for (const authApi of AUTH_REQUIRED_APIS) {
|
||||
// 支持通配符匹配
|
||||
if (authApi.includes('*')) {
|
||||
const regex = new RegExp('^' + authApi.replace(/\*/g, '.*') + '$')
|
||||
if (regex.test(path)) {
|
||||
return true
|
||||
}
|
||||
} else if (path === authApi || path.startsWith(authApi + '/')) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否已完成登录
|
||||
* @returns {Boolean} 是否已完成登录
|
||||
*/
|
||||
function isUserLoggedIn() {
|
||||
const token = uni.getStorageSync(HTTP_CONFIG.storageKeys.token)
|
||||
const loginStep = uni.getStorageSync('loginStep')
|
||||
|
||||
// 检查是否有有效的token和完成的登录流程
|
||||
return !!(token && (loginStep === 'profile_completed' || loginStep === 'phone_authed'))
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试自动登录
|
||||
* @returns {Promise<Boolean>} 是否登录成功
|
||||
*/
|
||||
async function tryAutoLogin() {
|
||||
try {
|
||||
return await autoLogin()
|
||||
} catch (error) {
|
||||
console.error('自动登录失败:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理需要鉴权的情况
|
||||
*/
|
||||
function handleAuthRequired() {
|
||||
const loginStep = uni.getStorageSync('loginStep')
|
||||
|
||||
// 根据当前登录状态决定跳转页面
|
||||
let targetPage = '/pages/login/login'
|
||||
let toastMessage = '请先登录'
|
||||
|
||||
switch (loginStep) {
|
||||
case 'wx_logged':
|
||||
targetPage = '/pages/auth/phone-auth'
|
||||
toastMessage = '请完成手机号授权'
|
||||
break
|
||||
case 'phone_authed':
|
||||
case 'phone_skipped':
|
||||
targetPage = '/pages/profile/user-info?mode=setup'
|
||||
toastMessage = '请完善个人信息'
|
||||
break
|
||||
default:
|
||||
targetPage = '/pages/login/login'
|
||||
toastMessage = '请先登录'
|
||||
}
|
||||
|
||||
// 显示提示并跳转
|
||||
uni.showToast({
|
||||
title: toastMessage,
|
||||
icon: 'none',
|
||||
duration: 1500
|
||||
})
|
||||
|
||||
setTimeout(() => {
|
||||
uni.navigateTo({ url: targetPage }).catch(() => {
|
||||
uni.reLaunch({ url: targetPage })
|
||||
})
|
||||
}, 1500)
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化HTTP配置
|
||||
|
|
@ -24,20 +126,34 @@ export default (vm) => {
|
|||
config.data = config.data || {}
|
||||
config.custom = config.custom || {}
|
||||
|
||||
|
||||
|
||||
// 自动检查接口是否需要鉴权(如果没有明确指定)
|
||||
if (config.custom.auth === undefined) {
|
||||
config.custom.auth = checkApiAuth(config.url)
|
||||
}
|
||||
|
||||
// 根据custom参数中配置的是否需要token,添加对应的请求头
|
||||
if (config.custom.auth) {
|
||||
// 从本地存储获取token
|
||||
// 检查是否为需要强制登录的接口
|
||||
const isAuthRequiredApi = checkAuthRequiredApi(config.url)
|
||||
|
||||
// 如果是需要强制登录的接口,检查登录状态
|
||||
if (isAuthRequiredApi) {
|
||||
if (!isUserLoggedIn()) {
|
||||
console.log('访问需要鉴权的接口但未完成登录,跳转到登录流程:', config.url)
|
||||
handleAuthRequired()
|
||||
return Promise.reject({
|
||||
message: '需要登录',
|
||||
code: 'AUTH_REQUIRED',
|
||||
url: config.url
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 添加Authorization请求头
|
||||
if (config.custom.auth !== false) {
|
||||
const token = uni.getStorageSync(HTTP_CONFIG.storageKeys.token)
|
||||
if (token) {
|
||||
config.header.Authorization = `Bearer ${token}`
|
||||
} else {
|
||||
// 如果需要token但没有token,可以跳转到登录页
|
||||
console.warn('需要token但未找到,请先登录')
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -52,6 +168,11 @@ export default (vm) => {
|
|||
return config
|
||||
}, config => {
|
||||
// 请求错误处理
|
||||
// 如果是AUTH_REQUIRED错误,不显示loading
|
||||
if (config.code === 'AUTH_REQUIRED') {
|
||||
// 不显示loading,因为会跳转页面
|
||||
return Promise.reject(config)
|
||||
}
|
||||
return Promise.reject(config)
|
||||
})
|
||||
|
||||
|
|
@ -76,13 +197,9 @@ export default (vm) => {
|
|||
|
||||
// 特殊状态码处理
|
||||
if (data.code === 401) {
|
||||
// token过期,清除本地token并跳转到登录页
|
||||
uni.removeStorageSync(HTTP_CONFIG.storageKeys.token)
|
||||
uni.removeStorageSync(HTTP_CONFIG.storageKeys.refreshToken)
|
||||
uni.removeStorageSync(HTTP_CONFIG.storageKeys.userInfo)
|
||||
uni.reLaunch({
|
||||
url: HTTP_CONFIG.loginPage
|
||||
})
|
||||
// token过期,清除本地认证信息并跳转到登录流程
|
||||
clearAuthData()
|
||||
handleAuthRequired()
|
||||
return Promise.reject(data)
|
||||
}
|
||||
|
||||
|
|
@ -116,14 +233,8 @@ export default (vm) => {
|
|||
break
|
||||
case 401:
|
||||
errorMessage = '未授权,请重新登录'
|
||||
// 清除本地认证信息
|
||||
uni.removeStorageSync(HTTP_CONFIG.storageKeys.token)
|
||||
uni.removeStorageSync(HTTP_CONFIG.storageKeys.refreshToken)
|
||||
uni.removeStorageSync(HTTP_CONFIG.storageKeys.userInfo)
|
||||
// 跳转到登录页
|
||||
uni.reLaunch({
|
||||
url: HTTP_CONFIG.loginPage
|
||||
})
|
||||
clearAuthData()
|
||||
handleAuthRequired()
|
||||
break
|
||||
case 403:
|
||||
errorMessage = '拒绝访问'
|
||||
|
|
|
|||
|
|
@ -1,163 +0,0 @@
|
|||
# Pages 目录优化报告
|
||||
|
||||
## 优化概览
|
||||
|
||||
本次优化对 `pages` 目录下的页面组件进行了全面的代码质量、性能和可维护性优化。
|
||||
|
||||
## 1. Auth 模块优化 ✅
|
||||
|
||||
### pages/auth/phone-auth.vue
|
||||
**优化内容:**
|
||||
- ✅ **错误处理优化**:提取了 `handleError` 方法,统一处理各种错误类型
|
||||
- ✅ **代码结构优化**:简化了错误处理逻辑,减少重复代码
|
||||
- ✅ **用户体验提升**:改进了错误提示信息的准确性和友好性
|
||||
|
||||
**优化前后对比:**
|
||||
```javascript
|
||||
// 优化前:重复的错误处理逻辑
|
||||
} catch (error) {
|
||||
// 30+ 行重复的错误处理代码
|
||||
}
|
||||
|
||||
// 优化后:统一的错误处理方法
|
||||
} catch (error) {
|
||||
handleError(error)
|
||||
}
|
||||
```
|
||||
|
||||
## 2. Profile 模块优化 ✅
|
||||
|
||||
### pages/profile/profile.vue
|
||||
**优化内容:**
|
||||
- ✅ **数据结构优化**:清理了多余的空行,优化了响应式数据的组织
|
||||
- ✅ **方法重构**:提取了 `resetStatsToDefault` 方法,避免重复的数据重置逻辑
|
||||
- ✅ **导航优化**:改进了 `navigateTo` 方法,添加了更好的错误处理和自定义选项
|
||||
- ✅ **代码清理**:移除了多余的空行和注释
|
||||
|
||||
**优化前后对比:**
|
||||
```javascript
|
||||
// 优化前:重复的数据重置
|
||||
petStats.petCount = 0
|
||||
petStats.recordCount = 0
|
||||
// ... 更多重复代码
|
||||
|
||||
// 优化后:统一的重置方法
|
||||
resetStatsToDefault()
|
||||
```
|
||||
|
||||
### pages/profile/user-info.vue
|
||||
**优化内容:**
|
||||
- ✅ **选择器配置优化**:统一了选择器数据的管理
|
||||
- ✅ **事件处理简化**:移除了不必要的 `@change` 事件处理器
|
||||
- ✅ **代码清理**:删除了未使用的方法(`onNickNameChange`, `onBioChange`)
|
||||
|
||||
**优化前后对比:**
|
||||
```javascript
|
||||
// 优化前:不必要的事件处理
|
||||
<u-input v-model="userInfo.nickName" @change="onNickNameChange" />
|
||||
|
||||
// 优化后:直接使用 v-model
|
||||
<u-input v-model="userInfo.nickName" />
|
||||
```
|
||||
|
||||
## 3. Pets 模块优化 ✅
|
||||
|
||||
### pages/pets/pets.vue
|
||||
**优化内容:**
|
||||
- ✅ **配置数据提取**:将硬编码的配置数据提取到文件顶部
|
||||
- ✅ **方法重构**:创建了 `generateDefaultPets` 方法,分离了数据生成逻辑
|
||||
- ✅ **代码组织**:优化了 `getPetEmoji` 方法,使用配置映射
|
||||
|
||||
**优化前后对比:**
|
||||
```javascript
|
||||
// 优化前:硬编码的表情映射
|
||||
getPetEmoji(breed) {
|
||||
const emojiMap = {
|
||||
'橘猫': '🐱',
|
||||
// ... 更多硬编码
|
||||
}
|
||||
return emojiMap[breed] || '🐾'
|
||||
}
|
||||
|
||||
// 优化后:使用配置常量
|
||||
getPetEmoji(breed) {
|
||||
return PET_EMOJI_MAP[breed] || '🐾'
|
||||
}
|
||||
```
|
||||
|
||||
## 4. Adoption 模块优化 ✅
|
||||
|
||||
### pages/adoption/adoption.vue
|
||||
**优化内容:**
|
||||
- ✅ **数据结构优化**:重新组织了 data 中的属性,按功能分组
|
||||
- ✅ **代码清理**:清理了多余的空行和注释
|
||||
- ✅ **可读性提升**:改进了数据属性的分组和命名
|
||||
|
||||
## 5. 全局优化成果
|
||||
|
||||
### 代码质量提升
|
||||
- ✅ **减少重复代码**:提取了公共方法和配置
|
||||
- ✅ **统一错误处理**:建立了一致的错误处理模式
|
||||
- ✅ **改进代码结构**:优化了方法组织和数据结构
|
||||
|
||||
### 性能优化
|
||||
- ✅ **减少不必要的事件监听**:移除了冗余的 change 事件
|
||||
- ✅ **优化数据初始化**:改进了默认数据的生成方式
|
||||
- ✅ **提升渲染效率**:减少了不必要的响应式更新
|
||||
|
||||
### 可维护性提升
|
||||
- ✅ **配置化管理**:将硬编码数据提取为配置常量
|
||||
- ✅ **方法职责单一**:每个方法都有明确的职责
|
||||
- ✅ **代码组织清晰**:按功能模块组织代码结构
|
||||
|
||||
## 6. 保留的功能特性
|
||||
|
||||
### 登录流程功能 ✅
|
||||
- ✅ 保留了所有登录流程重构中新添加的功能
|
||||
- ✅ 保持了页面间的数据传递和状态管理
|
||||
- ✅ 确保了所有页面的路由配置正确
|
||||
|
||||
### 用户体验 ✅
|
||||
- ✅ 维护了现有的用户体验和交互逻辑
|
||||
- ✅ 保持了页面的响应式设计
|
||||
- ✅ 确保了样式的一致性
|
||||
|
||||
## 7. 优化统计
|
||||
|
||||
### 文件修改统计
|
||||
- **优化文件数量**: 5个主要文件
|
||||
- **代码行数减少**: ~150行
|
||||
- **方法提取**: 6个新的工具方法
|
||||
- **配置常量**: 3个新的配置对象
|
||||
|
||||
### 质量指标改进
|
||||
- 📊 **代码复用率**: 提升 25%
|
||||
- 🚀 **错误处理一致性**: 提升 40%
|
||||
- 🔧 **可维护性**: 提升 30%
|
||||
- 📚 **代码可读性**: 提升 35%
|
||||
|
||||
## 8. 后续建议
|
||||
|
||||
### 进一步优化方向
|
||||
1. **组件化重构**: 将重复的UI组件提取为公共组件
|
||||
2. **状态管理**: 考虑引入 Pinia 进行全局状态管理
|
||||
3. **类型安全**: 考虑引入 TypeScript 提升代码安全性
|
||||
4. **性能监控**: 添加性能监控和错误上报机制
|
||||
|
||||
### 维护建议
|
||||
1. **代码规范**: 建立统一的代码规范和 ESLint 配置
|
||||
2. **文档完善**: 为复杂的业务逻辑添加详细注释
|
||||
3. **测试覆盖**: 为关键功能添加单元测试
|
||||
4. **持续优化**: 定期进行代码审查和重构
|
||||
|
||||
## 总结
|
||||
|
||||
本次优化成功提升了 pages 目录下代码的质量、性能和可维护性,同时保持了所有现有功能的完整性。新的代码结构更加清晰、易于维护,为后续开发提供了良好的基础。
|
||||
|
||||
优化重点关注了:
|
||||
- 代码复用和模块化
|
||||
- 错误处理的统一性
|
||||
- 配置数据的管理
|
||||
- 用户体验的保持
|
||||
|
||||
所有优化都经过了仔细的测试和验证,确保不会影响现有功能的正常运行。
|
||||
|
|
@ -62,7 +62,7 @@
|
|||
|
||||
<script>
|
||||
import { ref } from 'vue'
|
||||
import { wxPhoneLogin } from '@/http/api/auth.js'
|
||||
import { updatePhoneNumber } from '@/http/api/auth.js'
|
||||
import {
|
||||
savePhoneAuthData,
|
||||
markPhoneSkipped,
|
||||
|
|
@ -173,47 +173,44 @@ export default {
|
|||
|
||||
console.log(phoneData)
|
||||
|
||||
console.log('准备调用手机号授权API:', {
|
||||
hasCode: !!phoneData.code,
|
||||
console.log('准备调用手机号更新API:', {
|
||||
hasEncryptedData: !!phoneData.encryptedData,
|
||||
hasIv: !!phoneData.iv,
|
||||
apiUrl: '/auth/wx-phone-login'
|
||||
apiUrl: '/user/wechat/mini/phone-update'
|
||||
})
|
||||
|
||||
// 调用真实API接口
|
||||
const result = await wxPhoneLogin(phoneData, {
|
||||
// 调用手机号更新API(需要用户已登录)
|
||||
const phoneNumber = await updatePhoneNumber({
|
||||
encryptedData: phoneData.encryptedData,
|
||||
iv: phoneData.iv
|
||||
}, {
|
||||
custom: {
|
||||
loading: false, // 使用页面自己的loading状态
|
||||
catch: true // 确保错误能被catch到
|
||||
}
|
||||
})
|
||||
|
||||
console.log('手机号授权API调用成功:', {
|
||||
hasToken: !!(result && result.token),
|
||||
hasUserInfo: !!(result && result.userInfo)
|
||||
})
|
||||
|
||||
// 使用状态管理工具保存手机号授权数据
|
||||
if (result && result.token) {
|
||||
savePhoneAuthData(result)
|
||||
} else {
|
||||
throw new Error('API返回数据格式错误')
|
||||
console.log('手机号更新成功:', phoneNumber)
|
||||
|
||||
// 更新本地用户信息
|
||||
const userInfo = authStore.userInfo
|
||||
if (userInfo) {
|
||||
userInfo.phone = phoneNumber
|
||||
authStore.setUserInfo(userInfo)
|
||||
}
|
||||
|
||||
|
||||
uni.showToast({
|
||||
title: '授权成功',
|
||||
title: '手机号更新成功',
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
// 跳转到个人信息设置页面
|
||||
|
||||
// 返回上一页
|
||||
setTimeout(() => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/profile/user-info?mode=setup'
|
||||
})
|
||||
uni.navigateBack()
|
||||
}, 1500)
|
||||
|
||||
} catch (error) {
|
||||
console.error('手机号授权失败:', error)
|
||||
console.error('手机号更新失败:', error)
|
||||
handleError(error)
|
||||
} finally {
|
||||
authorizing.value = false
|
||||
|
|
|
|||
|
|
@ -144,13 +144,6 @@
|
|||
import { reactive, ref, onMounted, computed } from 'vue'
|
||||
import { uploadImage } from '@/http/api/common.js'
|
||||
import { updateUserInfo } from '@/http/api/profile.js'
|
||||
import {
|
||||
getCurrentLoginStep,
|
||||
isLoginCompleted,
|
||||
checkAndResumeLogin,
|
||||
saveWxLoginData,
|
||||
clearTempLoginData
|
||||
} from '@/utils/loginState.js'
|
||||
|
||||
export default {
|
||||
name: 'ProfilePage',
|
||||
|
|
@ -189,30 +182,16 @@ export default {
|
|||
|
||||
// 方法定义
|
||||
const initPage = () => {
|
||||
checkLogin()
|
||||
loadUserInfo()
|
||||
loadUserStats()
|
||||
}
|
||||
|
||||
const checkLogin = () => {
|
||||
// 检查登录状态(仅用于显示,不强制跳转)
|
||||
console.log('Profile页面登录状态检查')
|
||||
|
||||
const currentStep = getCurrentLoginStep()
|
||||
console.log('当前登录步骤:', currentStep)
|
||||
|
||||
// 不再自动跳转,让用户自主选择是否登录
|
||||
// 登录状态会在调用需要鉴权的接口时自动处理
|
||||
|
||||
// 检查是否已完成登录
|
||||
if (isLoginCompleted()) {
|
||||
const savedUserInfo = uni.getStorageSync('userInfo')
|
||||
if (savedUserInfo) {
|
||||
userInfo.value = savedUserInfo
|
||||
calculateLoginDays()
|
||||
|
||||
// 清理临时登录数据
|
||||
clearTempLoginData()
|
||||
}
|
||||
const loadUserInfo = () => {
|
||||
// 尝试从本地存储加载用户信息
|
||||
const savedUserInfo = uni.getStorageSync('userInfo')
|
||||
if (savedUserInfo) {
|
||||
userInfo.value = savedUserInfo
|
||||
calculateLoginDays()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -289,46 +268,8 @@ export default {
|
|||
}
|
||||
|
||||
const handleUserAction = () => {
|
||||
if (userInfo.value.nickName) {
|
||||
// 已登录,跳转到个人信息设置
|
||||
navigateTo('/pages/profile/user-info')
|
||||
} else {
|
||||
// 未登录,执行登录
|
||||
wxLogin()
|
||||
}
|
||||
}
|
||||
|
||||
const wxLogin = () => {
|
||||
uni.login({
|
||||
provider: 'weixin',
|
||||
success: (res) => {
|
||||
console.log('登录成功', res)
|
||||
|
||||
// 使用状态管理工具保存微信登录数据
|
||||
saveWxLoginData(res)
|
||||
calculateLoginDays()
|
||||
|
||||
uni.showToast({
|
||||
title: '登录成功',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
})
|
||||
|
||||
// 跳转到手机号授权页面
|
||||
setTimeout(() => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/auth/phone-auth'
|
||||
})
|
||||
}, 1500)
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('登录失败', err)
|
||||
uni.showToast({
|
||||
title: '登录失败,请重试',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
// 直接跳转到个人信息设置,如果需要登录会在API调用时自动处理
|
||||
navigateTo('/pages/profile/user-info')
|
||||
}
|
||||
|
||||
// 统一的页面导航方法
|
||||
|
|
@ -427,6 +368,7 @@ export default {
|
|||
petStats,
|
||||
familyStats,
|
||||
adoptionStats,
|
||||
loadUserInfo,
|
||||
handleUserAction,
|
||||
navigateTo,
|
||||
navigateToFamily,
|
||||
|
|
|
|||
|
|
@ -231,28 +231,9 @@ export default {
|
|||
// 生命周期
|
||||
onMounted(() => {
|
||||
initPageMode()
|
||||
validateLoginState()
|
||||
loadUserInfo()
|
||||
})
|
||||
|
||||
// 验证登录状态
|
||||
const validateLoginState = () => {
|
||||
if (isSetupMode.value) {
|
||||
// 首次设置模式需要验证登录状态
|
||||
console.log('个人信息设置页面状态验证')
|
||||
|
||||
// 检查是否有有效的登录状态
|
||||
const currentStep = uni.getStorageSync(STORAGE_KEYS.LOGIN_STEP)
|
||||
if (!currentStep || currentStep === 'not_logged') {
|
||||
console.warn('无效的登录状态,返回profile页面')
|
||||
uni.reLaunch({
|
||||
url: '/pages/profile/profile'
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 方法定义
|
||||
const initPageMode = () => {
|
||||
// 获取页面参数
|
||||
|
|
@ -548,8 +529,7 @@ export default {
|
|||
// 新增的模式相关变量和方法
|
||||
isSetupMode,
|
||||
phoneSkipped,
|
||||
skipSetup,
|
||||
validateLoginState
|
||||
skipSetup
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ export const STORAGE_KEYS = {
|
|||
LOGIN_STEP: 'loginStep',
|
||||
WX_LOGIN_CODE: 'wxLoginCode',
|
||||
TOKEN: 'token',
|
||||
REFRESH_TOKEN: 'refreshToken',
|
||||
PHONE_NUMBER: 'phoneNumber',
|
||||
WX_USER_INFO: 'wxUserInfo',
|
||||
USER_INFO: 'userInfo',
|
||||
|
|
@ -97,17 +98,21 @@ export const saveWxLoginData = (loginData) => {
|
|||
* @param {Object} phoneData 手机号数据
|
||||
*/
|
||||
export const savePhoneAuthData = (phoneData) => {
|
||||
const { token, userInfo } = phoneData
|
||||
|
||||
const { token, refreshToken, userInfo } = phoneData
|
||||
|
||||
if (token) {
|
||||
uni.setStorageSync(STORAGE_KEYS.TOKEN, token)
|
||||
}
|
||||
|
||||
|
||||
if (refreshToken) {
|
||||
uni.setStorageSync(STORAGE_KEYS.REFRESH_TOKEN, refreshToken)
|
||||
}
|
||||
|
||||
if (userInfo) {
|
||||
if (userInfo.phoneNumber) {
|
||||
uni.setStorageSync(STORAGE_KEYS.PHONE_NUMBER, userInfo.phoneNumber)
|
||||
}
|
||||
|
||||
|
||||
// 保存微信用户信息供后续使用
|
||||
const wxUserInfo = {
|
||||
phoneNumber: userInfo.phoneNumber || '',
|
||||
|
|
@ -116,10 +121,17 @@ export const savePhoneAuthData = (phoneData) => {
|
|||
avatarUrl: userInfo.avatarUrl || ''
|
||||
}
|
||||
uni.setStorageSync(STORAGE_KEYS.WX_USER_INFO, wxUserInfo)
|
||||
uni.setStorageSync(STORAGE_KEYS.USER_INFO, userInfo)
|
||||
}
|
||||
|
||||
setLoginStep(LOGIN_STEPS.PHONE_AUTHED)
|
||||
console.log('保存手机号授权数据:', { token: !!token, userInfo: !!userInfo })
|
||||
|
||||
// 根据用户信息完善状态设置登录步骤
|
||||
if (userInfo && userInfo.profileCompleted) {
|
||||
setLoginStep(LOGIN_STEPS.PROFILE_COMPLETED)
|
||||
} else {
|
||||
setLoginStep(LOGIN_STEPS.PHONE_AUTHED)
|
||||
}
|
||||
|
||||
console.log('保存手机号授权数据:', { token: !!token, refreshToken: !!refreshToken, userInfo: !!userInfo })
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -151,6 +163,133 @@ export const clearTempLoginData = () => {
|
|||
console.log('清理临时登录数据')
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查并验证token有效性
|
||||
* @returns {Promise<boolean>} token是否有效
|
||||
*/
|
||||
export const validateToken = async () => {
|
||||
const token = uni.getStorageSync(STORAGE_KEYS.TOKEN)
|
||||
if (!token) {
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
// 调用一个简单的API来验证token
|
||||
const { getUserInfo } = await import('@/http/api/profile.js')
|
||||
await getUserInfo({
|
||||
custom: {
|
||||
loading: false,
|
||||
toast: false
|
||||
}
|
||||
})
|
||||
return true
|
||||
} catch (error) {
|
||||
console.log('Token验证失败:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试刷新token
|
||||
* @returns {Promise<boolean>} 是否刷新成功
|
||||
*/
|
||||
export const tryRefreshToken = async () => {
|
||||
const refreshToken = uni.getStorageSync(STORAGE_KEYS.REFRESH_TOKEN)
|
||||
if (!refreshToken) {
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
const { refreshToken: refreshTokenApi } = await import('@/http/api/auth.js')
|
||||
const result = await refreshTokenApi({
|
||||
custom: {
|
||||
loading: false,
|
||||
toast: false
|
||||
}
|
||||
})
|
||||
|
||||
if (result && result.token) {
|
||||
uni.setStorageSync(STORAGE_KEYS.TOKEN, result.token)
|
||||
if (result.refreshToken) {
|
||||
uni.setStorageSync(STORAGE_KEYS.REFRESH_TOKEN, result.refreshToken)
|
||||
}
|
||||
console.log('Token刷新成功')
|
||||
return true
|
||||
}
|
||||
return false
|
||||
} catch (error) {
|
||||
console.log('Token刷新失败:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动登录(用于用户再次进入小程序)
|
||||
* @returns {Promise<boolean>} 是否登录成功
|
||||
*/
|
||||
export const autoLogin = async () => {
|
||||
console.log('开始自动登录检查')
|
||||
|
||||
// 1. 检查token有效性
|
||||
if (await validateToken()) {
|
||||
console.log('Token有效,自动登录成功')
|
||||
return true
|
||||
}
|
||||
|
||||
// 2. 尝试刷新token
|
||||
if (await tryRefreshToken()) {
|
||||
console.log('Token刷新成功,自动登录成功')
|
||||
return true
|
||||
}
|
||||
|
||||
// 3. 尝试使用微信code重新登录(不需要手机号授权)
|
||||
try {
|
||||
const loginRes = await new Promise((resolve, reject) => {
|
||||
uni.login({
|
||||
success: resolve,
|
||||
fail: reject
|
||||
})
|
||||
})
|
||||
|
||||
if (loginRes.code) {
|
||||
const { wxLogin } = await import('@/http/api/auth.js')
|
||||
const result = await wxLogin({
|
||||
code: loginRes.code
|
||||
}, {
|
||||
custom: {
|
||||
loading: false,
|
||||
toast: false
|
||||
}
|
||||
})
|
||||
|
||||
if (result && result.token) {
|
||||
// 保存新的登录信息
|
||||
uni.setStorageSync(STORAGE_KEYS.TOKEN, result.token)
|
||||
if (result.refreshToken) {
|
||||
uni.setStorageSync(STORAGE_KEYS.REFRESH_TOKEN, result.refreshToken)
|
||||
}
|
||||
if (result.userInfo) {
|
||||
uni.setStorageSync(STORAGE_KEYS.WX_USER_INFO, result.userInfo)
|
||||
uni.setStorageSync(STORAGE_KEYS.USER_INFO, result.userInfo)
|
||||
// 如果用户已完善过信息,设置为已完成状态
|
||||
if (result.userInfo.profileCompleted) {
|
||||
setLoginStep(LOGIN_STEPS.PROFILE_COMPLETED)
|
||||
} else {
|
||||
setLoginStep(LOGIN_STEPS.PHONE_AUTHED)
|
||||
}
|
||||
}
|
||||
console.log('微信code登录成功,自动登录成功')
|
||||
return true
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('微信code登录失败:', error)
|
||||
}
|
||||
|
||||
console.log('自动登录失败,需要用户手动登录')
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 完全重置登录状态(用于登出)
|
||||
*/
|
||||
|
|
@ -158,11 +297,12 @@ export const resetLoginState = () => {
|
|||
uni.removeStorageSync(STORAGE_KEYS.LOGIN_STEP)
|
||||
uni.removeStorageSync(STORAGE_KEYS.WX_LOGIN_CODE)
|
||||
uni.removeStorageSync(STORAGE_KEYS.TOKEN)
|
||||
uni.removeStorageSync(STORAGE_KEYS.REFRESH_TOKEN)
|
||||
uni.removeStorageSync(STORAGE_KEYS.PHONE_NUMBER)
|
||||
uni.removeStorageSync(STORAGE_KEYS.WX_USER_INFO)
|
||||
uni.removeStorageSync(STORAGE_KEYS.USER_INFO)
|
||||
uni.removeStorageSync(STORAGE_KEYS.LOGIN_DATE)
|
||||
|
||||
|
||||
console.log('重置登录状态')
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue