From 66d8acc9a958d8ed4aaea7928a528f864c32c1c8 Mon Sep 17 00:00:00 2001 From: dzq Date: Fri, 7 Nov 2025 10:42:14 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=B7=BB=E5=8A=A0=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E3=80=81=E4=BC=81=E4=B8=9A=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E4=B8=8EFake=E7=99=BB=E5=BD=95=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E8=AF=A6=E7=BB=86=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增登录流程详细文档,包含三种登录方式的完整流程、参数说明、返回信息及实现逻辑。文档涵盖核心代码实现、API接口详情、状态管理、错误处理与最佳实践等内容,为开发人员提供全面的参考指南。 --- doc/登录流程详细文档.md | 951 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 951 insertions(+) create mode 100644 doc/登录流程详细文档.md diff --git a/doc/登录流程详细文档.md b/doc/登录流程详细文档.md new file mode 100644 index 0000000..97541da --- /dev/null +++ b/doc/登录流程详细文档.md @@ -0,0 +1,951 @@ +# 微信登录、企业微信登录与Fake登录流程详细文档 + +## 文档概述 + +本文档详细描述了智柜宝系统中三种登录方式的完整流程、参数说明、返回信息及实现逻辑。 + +## 一、微信登录(普通微信公众号登录) + +### 1.1 登录流程图 + +``` +用户访问应用 + ↓ +检查微信环境(micromessenger) + ↓ +跳转微信授权页面 + ↓ +用户授权 + ↓ +微信回调携带 code 和 state + ↓ +调用 getOpenIdApi 换取 openid + ↓ +调用 getBalanceApi 获取余额 + ↓ +完成认证 +``` + +### 1.2 核心实现 + +#### 前端回调处理(`src/main.ts` 或页面组件) + +```typescript +onMounted(() => { + const urlParams = new URLSearchParams(window.location.search); + const code = urlParams.get('code'); + const state = urlParams.get('state'); + + if (code) { + wxStore.handleWxCallback({ code, state }); + } +}); +``` + +#### Store 处理逻辑(`src/pinia/stores/wx.ts:81-147`) + +```typescript +const handleWxCallback = async (params: { corpid?: string; code?: string; state?: string; }) => { + isHandleWxCallbackComplete.value = false; + + if (params.code) { + code.value = params.code; + state.value = params.state || state.value; + corpid.value = params.corpid || corpid.value; + corpidLogin.value = !!corpid.value; + + try { + // 微信公众号登录(无 corpid) + if (!corpid.value) { + const res = await getOpenIdApi({ code: params.code }); + if (res && res.code == 0) { + openid.value = res.data; + } + + // 获取余额信息 + if (openid.value) { + corpid.value = "wpZ1ZrEgAA2QTxIRcB4cMtY7hQbTcPAw"; // 默认企业ID + const balanceRes = await getBalanceApi(corpid.value, openid.value); + if (balanceRes && balanceRes.code == 0) { + balance.value = balanceRes.data.balance; + useBalance.value = balanceRes.data.useBalance; + balanceLimit.value = balanceRes.data.balanceLimit; + userid.value = balanceRes.data.userid; + if (!ab98User.value && balanceRes.data.ab98User) { + setAb98User(balanceRes.data.ab98User); + } + } + } + } + } catch (err) { + console.error('获取 openid 失败:', err); + } finally { + isHandleWxCallbackComplete.value = true; + } + } else { + isHandleWxCallbackComplete.value = true; + } +}; +``` + +### 1.3 API 接口详情 + +#### 获取 OpenID + +**接口地址**: `GET /api/v1/payment/getOpenId` + +**请求参数**: +```typescript +interface GetOpenIdRequestParams { + code: string; // 微信授权后返回的授权码 +} +``` + +**返回数据**: +```typescript +interface ApiResponseData { + code: number; // 状态码:0 表示成功 + msg: string; // 消息 + data: string; // openid 字符串 +} +``` + +**示例响应**: +```json +{ + "code": 0, + "msg": "success", + "data": "oMRxw6Eum0DB1IjI_pEX_yrawBHw" +} +``` + +#### 获取余额 + +**接口地址**: `GET /api/v1/payment/getBalance` + +**请求参数**: +```typescript +{ + corpid: string; // 企业ID + openid: string; // 微信用户唯一标识 +} +``` + +**返回数据**: +```typescript +interface GetBalanceResponse { + userid: string; // 系统用户ID + corpid: string; // 企业ID + balance: number; // 剩余借呗 + useBalance: number; // 已用借呗 + balanceLimit: number; // 借呗总额 + ab98User: ab98UserDTO; // 汇邦云用户信息 +} +``` + +**示例响应**: +```json +{ + "code": 0, + "msg": "success", + "data": { + "userid": "woZ1ZrEgAAV9AEdRt1MGQxSg-KDJrDlA", + "corpid": "wpZ1ZrEgAA2QTxIRcB4cMtY7hQbTcPAw", + "balance": 5000, + "useBalance": 2000, + "balanceLimit": 7000, + "ab98User": { + "userid": "123456", + "name": "张三", + "tel": "13800138000", + "sex": "男", + "faceImg": "https://example.com/avatar.jpg", + "registered": true, + "ab98Balance": 10000 + } + } +} +``` + +### 1.4 微信授权 URL 生成 + +```typescript +const generateWxAuthUrl = () => { + const appId = import.meta.env.VITE_WX_APP_ID; + const redirectUri = encodeURIComponent(window.location.origin + '/callback'); + const scope = 'snsapi_userinfo'; // 或 snsapi_base + const state = Math.random().toString(36).substring(2, 15); + + return `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirectUri}&response_type=code&scope=${scope}&state=${state}#wechat_redirect`; +}; +``` + +**参数说明**: +- `appid`: 微信公众号的 AppID +- `redirect_uri`: 授权后回调的网址(需 URL 编码) +- `scope`: 授权范围 + - `snsapi_base`: 静默授权,只能获取 openid + - `snsapi_userinfo`: 需用户授权,可获取用户信息 +- `state`: 自定义参数,用于防止 CSRF 攻击 + +--- + +## 二、企业微信登录 + +### 2.1 登录流程图 + +``` +用户访问应用 + ↓ +检测 URL 中的 corpid 参数 + ↓ +跳转企业微信授权页面 + ↓ +用户授权 + ↓ +企业微信回调携带 corpid、code、state + ↓ +调用 qyLogin 验证并获取用户信息 + ↓ +调用 getBalanceByQyUserid 获取余额 + ↓ +关联 AB98 用户系统 + ↓ +完成认证 +``` + +### 2.2 核心实现 + +#### 路由守卫处理(`src/router/guard.ts:22-31`) + +```typescript +// 企业微信登录参数检测 +const urlParams = new URLSearchParams(window.location.search); +const corpid = urlParams.get('corpid') || undefined; +if (corpid) { + return true; +} +const isAdmin = urlParams.get('isAdmin') || undefined; +if (isAdmin) { + return true; +} +``` + +#### Store 处理逻辑(`src/pinia/stores/wx.ts:93-109`) + +```typescript +if (!corpid.value) { + // 微信公众号登录 + const res = await getOpenIdApi({ code: params.code }); + if (res && res.code == 0) { + openid.value = res.data; + } +} else { + // 企业微信登录 + const res = await qyLogin({ + corpid: corpid.value, + code: params.code, + state: params.state + }); + + if (res && res.code == 0) { + userid.value = res.data.userid; // 系统用户ID + openid.value = res.data.openid; // 微信 openid + isCabinetAdmin.value = res.data.isCabinetAdmin === 1; // 是否为柜子管理员 + name.value = res.data.name; // 用户姓名 + qyUserId.value = res.data.qyUserId; // 企业微信用户ID + setAb98User(res.data.ab98User); // 设置 AB98 用户信息 + } +} +``` + +#### 余额获取(`src/pinia/stores/wx.ts:66-79`) + +```typescript +const refreshBalance = async () => { + if (corpid.value && userid.value) { + const res = await getBalanceByQyUserid(corpid.value, userid.value); + if (res && res.code == 0) { + balance.value = res.data.balance; + useBalance.value = res.data.useBalance; + balanceLimit.value = res.data.balanceLimit; + + if (res.data.ab98User) { + setAb98User(res.data.ab98User); + } + } + } +}; +``` + +### 2.3 API 接口详情 + +#### 企业微信登录 + +**接口地址**: `GET /api/v1/payment/login/qy` + +**请求参数**: +```typescript +interface QyLoginRequestParams { + corpid: string; // 企业ID + code: string; // 企业微信授权后返回的授权码 + state?: string; // 状态参数(防CSRF) +} +``` + +**返回数据**: +```typescript +interface QyLoginDTO { + userid: string; // 系统用户ID + openid: string; // 微信 openid + isCabinetAdmin: number; // 是否为柜子管理员(1是 0否) + qyUserId: number; // 企业微信用户ID + name: string; // 用户姓名 + ab98User: ab98UserDTO; // 汇邦云用户信息 +} +``` + +**示例响应**: +```json +{ + "code": 0, + "msg": "success", + "data": { + "userid": "woZ1ZrEgAAV9AEdRt1MGQxSg-KDJrDlA", + "openid": "oMRxw6Eum0DB1IjI_pEX_yrawBHw", + "isCabinetAdmin": 1, + "qyUserId": 10001, + "name": "张三", + "ab98User": { + "userid": "123456", + "name": "张三", + "tel": "13800138000", + "sex": "男", + "faceImg": "https://example.com/avatar.jpg", + "registered": true, + "ab98Balance": 10000 + } + } +} +``` + +#### 根据企业微信用户ID获取余额 + +**接口地址**: `GET /api/v1/payment/getBalanceByQyUserid` + +**请求参数**: +```typescript +{ + corpid: string; // 企业ID + userid: string; // 系统用户ID +} +``` + +**返回数据**: 同 `GetBalanceResponse` 结构 + +### 2.4 企业微信授权 URL 生成 + +```typescript +const generateQyWxAuthUrl = () => { + const corpid = import.meta.env.VITE_WX_CORP_ID; + const redirectUri = encodeURIComponent(window.location.origin + '/callback'); + const scope = 'snsapi_base'; // 企业微信通常使用 base + const state = Math.random().toString(36).substring(2, 15); + + return `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${corpid}&redirect_uri=${redirectUri}&response_type=code&scope=${scope}&state=${state}#wechat_redirect`; +}; +``` + +--- + +## 三、Fake登录(模拟企业微信登录) + +### 3.1 应用场景 + +Fake登录用于开发测试环境,模拟企业微信登录流程,无需真实的企业微信授权,直接使用预设的测试账号信息。 + +### 3.2 登录流程图 + +``` +触发 fake 登录 + ↓ +设置 fake 登录状态 + ↓ +设置默认企业ID + ↓ +设置默认用户ID + ↓ +调用 fakeQyLoginApi + ↓ +获取模拟用户信息 + ↓ +完成认证 +``` + +### 3.3 核心实现(`src/pinia/stores/wx.ts:149-163`) + +```typescript +const fakeQyLogin = async () => { + isFakeQyLogin.value = true; // 标记为 fake 登录 + corpid.value = "wpZ1ZrEgAA2QTxIRcB4cMtY7hQbTcPAw"; // 默认企业ID + corpidLogin.value = true; // 标记为企业微信登录 + userid.value = "woZ1ZrEgAAV9AEdRt1MGQxSg-KDJrDlA"; // 默认用户ID + + // 调用 fake API + const res = await fakeQyLoginApi({ corpid: corpid.value, userid: userid.value }); + + if (res && res.code == 0) { + userid.value = res.data.userid; + openid.value = "oMRxw6Eum0DB1IjI_pEX_yrawBHw"; // 固定的测试 openid + isCabinetAdmin.value = res.data.isCabinetAdmin === 1; + name.value = res.data.name; + qyUserId.value = res.data.qyUserId; + setAb98User(res.data.ab98User); + } +}; +``` + +### 3.4 API 接口详情 + +**接口地址**: `GET /api/v1/payment/login/qy/fake` + +**请求参数**: +```typescript +{ + corpid: string; // 企业ID + userid: string; // 系统用户ID +} +``` + +**返回数据**: 与 `QyLoginDTO` 相同 + +**示例响应**: +```json +{ + "code": 0, + "msg": "success", + "data": { + "userid": "woZ1ZrEgAAV9AEdRt1MGQxSg-KDJrDlA", + "openid": "oMRxw6Eum0DB1IjI_pEX_yrawBHw", + "isCabinetAdmin": 1, + "qyUserId": 10001, + "name": "测试用户", + "ab98User": { + "userid": "123456", + "name": "测试用户", + "tel": "13800138000", + "sex": "男", + "faceImg": "https://example.com/test-avatar.jpg", + "registered": true, + "ab98Balance": 10000 + } + } +} +``` + +### 3.5 调用方式 + +#### 在页面中调用 + +```typescript +import { useWxStore } from '@/pinia/stores/wx'; + +const wxStore = useWxStore(); + +// 触发 fake 登录 +const handleFakeLogin = () => { + wxStore.fakeQyLogin(); +}; +``` + +#### 在组件模板中调用 + +```vue + +``` + +--- + +## 四、状态管理(Pinia Store) + +### 4.1 WxStore 状态定义(`src/pinia/stores/wx.ts:7-38`) + +```typescript +export const useWxStore = defineStore("wx", () => { + // 授权信息 + const code = ref(""); // 微信授权 code + const state = ref(""); // 防CSRF的state参数 + + // 用户标识 + const openid = ref(""); // 微信用户唯一标识 + const userid = ref(""); // 系统用户ID + const qyUserId = ref(0); // 企业微信用户ID + + // 企业信息 + const corpid = ref(""); // 企业ID + const corpidLogin = ref(false);// 是否企业微信登录 + + // 用户信息 + const isCabinetAdmin = ref(false); // 是否是柜子管理员 + const name = ref(""); // 企业微信用户姓名 + const ab98User = ref(null); // 汇邦云用户信息 + + // 余额信息 + const balance = ref(0); // 剩余借呗 + const useBalance = ref(0); // 已用借呗 + const balanceLimit = ref(0); // 借呗总额 + + // 登录状态 + const isFakeQyLogin = ref(false); // 是否fake登录 + const isHandleWxCallbackComplete = ref(false); // 回调处理是否完成 +}); +``` + +### 4.2 AB98用户Store(`src/pinia/stores/ab98-user.ts`) + +```typescript +export const useAb98UserStore = defineStore("ab98User", () => { + // 用户基本信息 + const face_img = ref(''); // 用户头像 + const sex = ref(''); // 性别 + const name = ref(''); // 姓名 + const userid = ref(""); // 用户ID + const registered = ref(false); // 是否已注册 + const tel = ref(""); // 手机号 + const token = ref(""); // 认证令牌 + + // 登录状态 + const isLogin = ref(false); + const tokenLogin = ref(""); + const loginCode = '1'; // 默认验证码 +}); +``` + +### 4.3 核心方法 + +#### 设置 AB98 用户信息 + +```typescript +const setAb98User = (user: ab98UserDTO) => { + ab98User.value = user; + const ab98UserStore = useAb98UserStore(); + ab98UserStore.setUserInfo({ + face_img: ab98User.value.faceImg || "", + success: true, + sex: ab98User.value.sex || "", + name: ab98User.value.name || "", + userid: ab98User.value.userid || "", + registered: true, + tel: ab98User.value.tel || "", + }); +}; +``` + +#### 等待回调完成 + +```typescript +const waitForHandleWxCallbackComplete = async (timeout = 30000): Promise => { + const startTime = Date.now(); + while (!isHandleWxCallbackComplete.value) { + if (Date.now() - startTime > timeout) { + console.warn('等待 handleWxCallback 完成超时'); + return false; + } + await new Promise(resolve => setTimeout(resolve, 100)); + } + return true; +}; +``` + +--- + +## 五、数据类型定义 + +### 5.1 ab98UserDTO + +```typescript +interface ab98UserDTO { + /** 主键ID */ + ab98UserId?: number; + /** openid */ + openid?: string; + /** 汇邦云用户唯一ID */ + userid?: string; + /** 真实姓名 */ + name?: string; + /** 手机号码 */ + tel?: string; + /** 身份证号码 */ + idnum?: string; + /** 性别(男 女) */ + sex?: string; + /** 人脸照片地址 */ + faceImg?: string; + /** 身份证正面地址 */ + idcardFront?: string; + /** 身份证背面地址 */ + idcardBack?: string; + /** 身份证登记地址 */ + address?: string; + /** 是否已注册(0未注册 1已注册) */ + registered?: boolean; + /** 借呗余额 单位分 */ + ab98Balance?: number; +} +``` + +### 5.2 通用响应类型 + +```typescript +interface ApiResponseData { + code: number; // 状态码:0表示成功,其他值表示失败 + msg: string; // 消息 + data: T; // 数据 +} + +interface ApiResponseMsgData { + code: number; // 状态码 + msg: string; // 消息 + data: T; // 数据 +} +``` + +--- + +## 六、环境配置 + +### 6.1 环境变量 + +#### 开发环境(`.env.development`) + +```env +# 微信公众号配置 +VITE_WX_APP_ID=your_dev_app_id +VITE_WX_CORP_ID=your_dev_corp_id + +# API 基础地址 +VITE_BASE_URL=https://apifoxmock.com/m1/2930465-2145633-default +``` + +#### 生产环境(`.env.production`) + +```env +# 微信公众号配置 +VITE_WX_APP_ID=your_prod_app_id +VITE_WX_CORP_ID=your_prod_corp_id + +# API 基础地址 +VITE_BASE_URL=https://api.example.com +``` + +### 6.2 微信环境检测(`src/common/utils/wx.ts`) + +```typescript +function checkInWeChat(targetUrl: string) { + const ua = navigator.userAgent.toLowerCase(); + if (!ua.includes('micromessenger')) { + // 不在微信内,提示用户在微信中打开 + const weChatUrl = `weixin://dl/business/?t=${encodeURIComponent(targetUrl)}`; + window.location.href = weChatUrl; + + setTimeout(() => { + if (document.hidden) return; + alert("未检测到微信,请手动打开微信并访问链接。"); + }, 2000); + } else { + console.log("已在微信内,无需跳转"); + } +} +``` + +--- + +## 七、路由守卫与权限控制 + +### 7.1 登录检查(`src/router/guard.ts`) + +```typescript +router.beforeEach((to, _from) => { + // 检测企业微信登录参数 + const urlParams = new URLSearchParams(window.location.search); + const corpid = urlParams.get('corpid') || undefined; + if (corpid) return true; + + const isAdmin = urlParams.get('isAdmin') || undefined; + if (isAdmin) return true; + + // 检查 AB98 用户登录状态 + const ab98UserStore = useAb98UserStore(); + if (!ab98UserStore.isLogin) { + if (isWhiteList(to)) return true; // 白名单页面直接访问 + return "/ab98"; // 重定向到登录页 + } + + return true; +}); +``` + +### 7.2 等待认证完成 + +在页面组件中使用: + +```vue + + + +``` + +--- + +## 八、错误处理与调试 + +### 8.1 常见错误 + +#### 1. 微信认证失败 + +**可能原因**: +- 回调域名未在微信公众平台配置 +- AppID 或 Secret 错误 +- 网络问题导致 API 调用失败 + +**解决方案**: +```typescript +const retryWxAuth = async (maxRetries = 3) => { + for (let i = 0; i < maxRetries; i++) { + try { + await wxStore.handleWxCallback(params); + if (wxStore.isHandleWxCallbackComplete) break; + } catch (error) { + console.error(`微信认证重试 ${i + 1} 失败:`, error); + if (i === maxRetries - 1) throw error; + await new Promise(resolve => setTimeout(resolve, 1000)); + } + } +}; +``` + +#### 2. OpenID 获取失败 + +**调试方法**: +```typescript +const debugWxAuth = async () => { + console.log('当前 URL 参数:', window.location.search); + + const urlParams = new URLSearchParams(window.location.search); + const code = urlParams.get('code'); + + if (!code) { + console.error('未获取到微信 code'); + return; + } + + console.log('获取到 code:', code); + + try { + const response = await getOpenIdApi({ code }); + console.log('OpenID 响应:', response); + } catch (error) { + console.error('获取 OpenID 失败:', error); + } +}; +``` + +### 8.2 日志输出 + +在关键位置添加日志: + +```typescript +const handleWxCallback = async (params: any) => { + console.log('=== 微信回调开始 ==='); + console.log('参数:', params); + console.log('corpid:', corpid.value); + console.log('corpidLogin:', corpidLogin.value); + + // ... 处理逻辑 + + console.log('=== 微信回调完成 ==='); +}; +``` + +--- + +## 九、最佳实践 + +### 9.1 安全性 + +1. **CSRF 防护** + - 使用 `state` 参数防止 CSRF 攻击 + - 生成随机字符串作为 `state` 值 + +2. **Token 加密** + ```typescript + const encryptToken = (token: string) => { + return btoa(encodeURIComponent(token)); + }; + ``` + +3. **敏感信息存储** + - 避免在 localStorage 中存储敏感信息 + - 使用加密后存储 + +### 9.2 性能优化 + +1. **减少 API 调用** + ```typescript + const cachedUserInfo = ref(null); + + const getUserInfo = async (forceRefresh = false) => { + if (cachedUserInfo.value && !forceRefresh) { + return cachedUserInfo.value; + } + const userInfo = await fetchUserInfo(); + cachedUserInfo.value = userInfo; + return userInfo; + }; + ``` + +2. **并行请求** + ```typescript + const loadUserData = async () => { + const [userInfo, balanceInfo] = await Promise.all([ + getUserInfo(), + getBalanceInfo() + ]); + return { userInfo, balanceInfo }; + }; + ``` + +### 9.3 用户体验 + +1. **加载状态提示** + ```vue + + ``` + +2. **错误提示** + ```typescript + const handleError = (error: any) => { + Toast.fail(error.message || '操作失败'); + }; + ``` + +--- + +## 十、测试 + +### 10.1 单元测试 + +```typescript +// tests/stores/wx.test.ts +import { describe, it, expect } from "vitest"; +import { setActivePinia, createPinia } from "pinia"; +import { useWxStore } from "@/pinia/stores/wx"; + +describe("Wx Store", () => { + beforeEach(() => { + setActivePinia(createPinia()); + }); + + it("应该处理微信回调", async () => { + const wxStore = useWxStore(); + await wxStore.handleWxCallback({ + code: "test_code", + state: "test_state" + }); + expect(wxStore.code).toBe("test_code"); + expect(wxStore.state).toBe("test_state"); + }); + + it("应该进行 fake 登录", async () => { + const wxStore = useWxStore(); + await wxStore.fakeQyLogin(); + expect(wxStore.isFakeQyLogin).toBe(true); + }); +}); +``` + +### 10.2 集成测试 + +```typescript +// tests/integration/login.test.ts +describe("登录流程集成测试", () => { + it("应该完成完整的微信认证流程", async () => { + // 1. 模拟微信回调 + const params = { code: "test_code", state: "test_state" }; + + // 2. 处理回调 + await wxStore.handleWxCallback(params); + + // 3. 验证状态更新 + expect(wxStore.isHandleWxCallbackComplete).toBe(true); + + // 4. 检查用户信息 + expect(wxStore.openid).toBeTruthy(); + }); +}); +``` + +--- + +## 十一、总结 + +### 11.1 三种登录方式对比 + +| 特性 | 微信登录 | 企业微信登录 | Fake登录 | +|------|----------|--------------|----------| +| 触发方式 | 微信授权回调 | 企业微信授权回调 | 手动调用 | +| 依赖 | 微信公众号 | 企业微信 | 无 | +| 适用环境 | 生产/测试 | 生产/测试 | 仅测试 | +| 获取openid | ✓ | ✓ | ✓(模拟) | +| 获取用户信息 | ✓ | ✓ | ✓(模拟) | +| 获取余额 | ✓ | ✓ | ✓(模拟) | +| 管理员权限 | 根据后端返回 | 根据后端返回 | 根据后端返回 | + +### 11.2 关键要点 + +1. **微信登录**:使用 `snsapi_userinfo` 或 `snsapi_base` 授权,通过 `code` 获取 `openid` +2. **企业微信登录**:需要 `corpid` 参数,通过 `code` 获取企业微信用户信息 +3. **Fake登录**:仅用于测试环境,直接使用预设的测试账号 +4. **状态管理**:使用 Pinia 管理登录状态和用户信息 +5. **余额系统**:通过 `balance`、`useBalance`、`balanceLimit` 管理借呗额度 +6. **AB98集成**:三种登录方式最终都会关联到汇邦云用户系统 + +### 11.3 开发注意事项 + +1. 确保在微信/企业微信环境下测试 +2. 正确配置回调域名 +3. 使用 `state` 参数防止 CSRF 攻击 +4. 合理处理 API 调用错误 +5. 在测试环境使用 Fake 登录提高效率 +6. 遵循状态管理最佳实践 + +--- + +**文档版本**: v1.0 +**最后更新**: 2025-11-07 +**维护者**: 智柜宝开发团队