334 lines
7.7 KiB
Markdown
334 lines
7.7 KiB
Markdown
# 微信小程序最终登录方案
|
||
|
||
## 方案说明
|
||
|
||
采用**自动静默登录**方案,用户打开小程序即自动完成登录,无需任何授权操作。
|
||
|
||
## 实现方式
|
||
|
||
### 1. 进入首页自动登录
|
||
- 用户打开小程序,进入首页
|
||
- 检查本地缓存,如果有登录信息,直接使用
|
||
- 如果没有缓存,自动调用 `wx.login` 获取 code
|
||
- 使用 code 调用后端 identify 接口完成登录
|
||
- 全程无需用户操作
|
||
|
||
### 2. 登录流程
|
||
|
||
```
|
||
用户打开小程序
|
||
↓
|
||
进入首页 (pages/index/index)
|
||
↓
|
||
检查缓存 (token, userInfo, wechatId)
|
||
↓
|
||
有缓存 → 直接使用
|
||
↓
|
||
无缓存 → 自动登录
|
||
↓
|
||
wx.login 获取 code
|
||
↓
|
||
调用 identify 接口
|
||
↓
|
||
保存登录信息
|
||
↓
|
||
完成登录
|
||
```
|
||
|
||
### 3. Token 过期处理
|
||
|
||
```
|
||
API 请求返回 401
|
||
↓
|
||
清除缓存
|
||
↓
|
||
提示"登录已过期,正在重新登录"
|
||
↓
|
||
刷新页面
|
||
↓
|
||
触发自动登录
|
||
```
|
||
|
||
### 4. 退出登录
|
||
|
||
```
|
||
点击"退出"按钮
|
||
↓
|
||
确认对话框
|
||
↓
|
||
清除登录信息
|
||
↓
|
||
调用 autoLogin() 重新登录
|
||
```
|
||
|
||
## 代码实现
|
||
|
||
### 首页 (pages/index/index.uvue)
|
||
|
||
```typescript
|
||
// 初始化用户信息
|
||
async function initUserInfo() {
|
||
try {
|
||
// 1. 先尝试从缓存获取
|
||
const cachedWechatId = uni.getStorageSync('wechatId')
|
||
const cachedUserInfo = uni.getStorageSync('userInfo')
|
||
const cachedToken = uni.getStorageSync('token')
|
||
|
||
if (cachedWechatId && cachedUserInfo && cachedToken) {
|
||
// 有完整缓存,直接使用
|
||
const parsedUserInfo = typeof cachedUserInfo === 'string'
|
||
? JSON.parse(cachedUserInfo)
|
||
: cachedUserInfo
|
||
|
||
userInfo.value = {
|
||
wechatId: cachedWechatId,
|
||
username: parsedUserInfo.username || parsedUserInfo.realName || '微信用户',
|
||
phone: parsedUserInfo.phone || '',
|
||
userId: parsedUserInfo.userId || ''
|
||
}
|
||
|
||
// 判断用户类型
|
||
userType.value = parsedUserInfo.status !== 'guest'
|
||
|
||
console.log('使用缓存的用户信息:', userInfo.value)
|
||
return
|
||
}
|
||
|
||
// 2. 没有缓存,自动登录
|
||
await autoLogin()
|
||
} catch (error) {
|
||
console.error('初始化用户信息失败:', error)
|
||
await autoLogin()
|
||
}
|
||
}
|
||
|
||
// 自动登录
|
||
async function autoLogin() {
|
||
uni.showLoading({ title: '登录中...' })
|
||
|
||
try {
|
||
uni.login({
|
||
provider: 'weixin',
|
||
success: async (loginRes) => {
|
||
console.log('微信登录成功,code:', loginRes.code)
|
||
|
||
const code = loginRes.code
|
||
const wechatId = code.substring(0, 20) // 使用部分code作为临时ID
|
||
|
||
// 调用 identify 接口
|
||
const identifyRes = await guestAPI.identify({
|
||
wechatId: wechatId,
|
||
phone: ''
|
||
})
|
||
|
||
uni.hideLoading()
|
||
|
||
if (identifyRes.success && identifyRes.data) {
|
||
const loginDomain = identifyRes.data
|
||
|
||
// 保存登录信息
|
||
uni.setStorageSync('token', loginDomain.token || '')
|
||
uni.setStorageSync('userInfo', JSON.stringify(loginDomain.user))
|
||
uni.setStorageSync('loginDomain', JSON.stringify(loginDomain))
|
||
uni.setStorageSync('wechatId', wechatId)
|
||
|
||
// 更新用户信息
|
||
userInfo.value = {
|
||
wechatId: wechatId,
|
||
username: loginDomain.user?.username || loginDomain.user?.realName || '微信用户',
|
||
phone: loginDomain.user?.phone || '',
|
||
userId: loginDomain.user?.userId || ''
|
||
}
|
||
|
||
// 判断用户类型
|
||
userType.value = loginDomain.user?.status !== 'guest'
|
||
|
||
console.log('自动登录成功:', userInfo.value)
|
||
} else {
|
||
uni.showToast({
|
||
title: identifyRes.message || '登录失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
console.error('微信登录失败:', err)
|
||
uni.hideLoading()
|
||
uni.showToast({ title: '登录失败,请重试', icon: 'none' })
|
||
}
|
||
})
|
||
} catch (error: any) {
|
||
console.error('自动登录失败:', error)
|
||
uni.hideLoading()
|
||
uni.showToast({
|
||
title: error.message || '登录失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
}
|
||
```
|
||
|
||
## 优势
|
||
|
||
### 1. 用户体验极佳
|
||
- ✅ 无需任何授权操作
|
||
- ✅ 打开即用
|
||
- ✅ 无感知登录
|
||
- ✅ 无弹窗干扰
|
||
|
||
### 2. 无权限要求
|
||
- ✅ 不需要企业认证
|
||
- ✅ 不需要开通手机号快速验证
|
||
- ✅ 个人小程序也可使用
|
||
- ✅ 测试环境友好
|
||
|
||
### 3. 代码简洁
|
||
- ✅ 删除了授权页面
|
||
- ✅ 删除了切换用户功能
|
||
- ✅ 删除了所有 mock 相关代码
|
||
- ✅ 只保留核心登录逻辑
|
||
|
||
### 4. 维护方便
|
||
- ✅ 登录逻辑集中在首页
|
||
- ✅ Token 过期自动处理
|
||
- ✅ 错误处理完善
|
||
- ✅ 日志清晰
|
||
|
||
## 后端要求
|
||
|
||
### identify 接口
|
||
|
||
```typescript
|
||
POST /urban-lifeline/system/guest/identify
|
||
{
|
||
"wechatId": "微信ID(使用code的前20位作为临时标识)",
|
||
"phone": "" // 可以为空
|
||
}
|
||
|
||
返回:
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"token": "jwt_token",
|
||
"user": {
|
||
"userId": "用户ID",
|
||
"username": "用户名",
|
||
"realName": "真实姓名",
|
||
"phone": "手机号(可能为空)",
|
||
"status": "guest" | "employee"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 建议优化
|
||
|
||
1. **后端可以通过 code 换取 openid**
|
||
- 前端传递完整的 code
|
||
- 后端调用微信 API 换取 openid
|
||
- 使用 openid 作为用户唯一标识
|
||
|
||
2. **支持游客模式**
|
||
- 如果 wechatId 不存在,创建游客账号
|
||
- 返回游客身份的 token
|
||
- 允许后续绑定手机号升级为正式用户
|
||
|
||
## 已删除的内容
|
||
|
||
### 1. 授权页面
|
||
- ❌ `pages/auth/auth.uvue` - 已删除
|
||
- ❌ pages.json 中的 auth 路由配置 - 已删除
|
||
|
||
### 2. 切换用户功能
|
||
- ❌ `switchMockUser()` 函数 - 已删除
|
||
- ❌ `isMockMode` 变量 - 已删除
|
||
- ❌ 切换按钮 UI - 已删除
|
||
- ❌ 所有条件编译代码 - 已删除
|
||
|
||
### 3. getUserProfile
|
||
- ❌ 不再使用 `getUserProfile` API
|
||
- ❌ 不再需要用户授权昵称
|
||
|
||
### 4. getPhoneNumber
|
||
- ❌ 不再使用 `getPhoneNumber` API
|
||
- ❌ 不再需要手机号授权
|
||
|
||
## 保留的功能
|
||
|
||
### 1. 退出登录
|
||
- ✅ 右上角"退出"按钮
|
||
- ✅ 点击后清除缓存并重新自动登录
|
||
- ✅ 红色主题,易于识别
|
||
|
||
### 2. Token 管理
|
||
- ✅ 自动检测 401 错误
|
||
- ✅ 自动清除过期信息
|
||
- ✅ 自动重新登录
|
||
|
||
### 3. 用户类型识别
|
||
- ✅ 区分 guest 和 employee
|
||
- ✅ 根据类型控制功能权限
|
||
|
||
## 测试清单
|
||
|
||
### 首次使用
|
||
- [ ] 打开小程序,自动登录成功
|
||
- [ ] 无任何授权弹窗
|
||
- [ ] 用户信息正确显示
|
||
- [ ] 可以正常使用所有功能
|
||
|
||
### 再次使用
|
||
- [ ] 关闭小程序重新打开
|
||
- [ ] 直接进入首页,无需重新登录
|
||
- [ ] 用户信息保持不变
|
||
|
||
### Token 过期
|
||
- [ ] 模拟 Token 过期(后端返回 401)
|
||
- [ ] 自动提示"登录已过期,正在重新登录"
|
||
- [ ] 自动完成重新登录
|
||
- [ ] 功能恢复正常
|
||
|
||
### 退出登录
|
||
- [ ] 点击"退出"按钮
|
||
- [ ] 显示确认对话框
|
||
- [ ] 确认后自动重新登录
|
||
- [ ] 登录成功后可正常使用
|
||
|
||
### API 请求
|
||
- [ ] 所有 API 请求携带正确的 token
|
||
- [ ] 请求路径正确(/urban-lifeline/)
|
||
- [ ] WebSocket 连接正常
|
||
- [ ] 文件上传功能正常
|
||
|
||
## 部署说明
|
||
|
||
### 1. 编译
|
||
```bash
|
||
npm run build:mp-weixin
|
||
```
|
||
|
||
### 2. 上传
|
||
- 使用微信开发者工具打开 `unpackage/dist/build/mp-weixin`
|
||
- 点击"上传"按钮
|
||
- 填写版本号和备注
|
||
|
||
### 3. 提交审核
|
||
- 登录微信公众平台
|
||
- 进入"版本管理"
|
||
- 提交审核
|
||
|
||
### 4. 发布
|
||
- 审核通过后,点击"发布"
|
||
- 用户即可使用
|
||
|
||
## 总结
|
||
|
||
当前方案是最简洁、最友好的登录方案:
|
||
- ✅ 无需任何用户操作
|
||
- ✅ 无需小程序认证
|
||
- ✅ 代码简洁易维护
|
||
- ✅ 用户体验极佳
|
||
- ✅ 适用于所有场景
|
||
|
||
可以直接部署使用!
|