feat(#558): 微信登录前端 - 授权按钮、回调页、绑定弹窗 #672

Merged
auto-approve-bot merged 2 commits from feat/558-wechat-login-frontend into develop 2026-07-21 10:47:31 +08:00
Owner

变更内容

1. API 层 (src/api/auth.ts)

  • getWechatAuthUrl() — 获取微信授权链接
  • wechatCallback(code, state) — 微信回调登录
  • sendVerificationCode() — 发送验证码(邮箱/手机)
  • bindContact() — 绑定联系方式

2. 登录页改造 (src/pages/auth/Login.tsx)

  • 微信登录按钮从占位改为真实调用
  • 点击后获取授权 URL 并跳转

3. 微信回调页 (src/pages/auth/WechatCallback.tsx)

  • 读取 URL 中的 code 和 state
  • 调用回调接口完成登录
  • 未绑定用户显示绑定弹窗

4. 绑定联系方式弹窗 (src/components/auth/BindContactModal.tsx)

  • 邮箱/手机 Tab 切换
  • 发送验证码(60s 倒计时)
  • 验证码校验 + 绑定提交

5. 路由 (src/router/index.tsx)

  • 新增 /auth/wechat/callback 路由

依赖后端

  • PR #670 微信登录后端接口
## 变更内容 ### 1. API 层 (`src/api/auth.ts`) - `getWechatAuthUrl()` — 获取微信授权链接 - `wechatCallback(code, state)` — 微信回调登录 - `sendVerificationCode()` — 发送验证码(邮箱/手机) - `bindContact()` — 绑定联系方式 ### 2. 登录页改造 (`src/pages/auth/Login.tsx`) - 微信登录按钮从占位改为真实调用 - 点击后获取授权 URL 并跳转 ### 3. 微信回调页 (`src/pages/auth/WechatCallback.tsx`) - 读取 URL 中的 code 和 state - 调用回调接口完成登录 - 未绑定用户显示绑定弹窗 ### 4. 绑定联系方式弹窗 (`src/components/auth/BindContactModal.tsx`) - 邮箱/手机 Tab 切换 - 发送验证码(60s 倒计时) - 验证码校验 + 绑定提交 ### 5. 路由 (`src/router/index.tsx`) - 新增 `/auth/wechat/callback` 路由 ## 依赖后端 - PR #670 微信登录后端接口
xiaoxia added 2 commits 2026-07-21 10:44:34 +08:00
- 登录页微信按钮:调 /auth/wechat/url 获取授权链接并跳转
- 微信回调页 /auth/wechat/callback:处理 code+state,完成登录
- 绑定联系方式弹窗:邮箱/手机 Tab 切换,验证码倒计时
- API 层新增微信登录、发送验证码、绑定联系方式接口
- 路由新增 /auth/wechat/callback
fix: restore file permissions
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 27s
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m26s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 1m42s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 1m49s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 2m57s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 2m34s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 32s
AI Code Review / AI Code Review (pull_request) Successful in 7m22s
8aed9bd11d

🚀 预览环境已部署

项目 详情
PR号 #672
预览链接 https://pr-672.preview.xiaoxiajianji.com
API环境 staging

💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。

🔄 每次提交新代码后预览环境会自动更新。

🗑️ PR 关闭或合并后,预览环境会自动清理。

🚀 **预览环境已部署** | 项目 | 详情 | |------|------| | PR号 | #672 | | 预览链接 | [https://pr-672.preview.xiaoxiajianji.com](https://pr-672.preview.xiaoxiajianji.com) | | API环境 | staging | > 💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。 > > 🔄 每次提交新代码后预览环境会自动更新。 > > 🗑️ PR 关闭或合并后,预览环境会自动清理。
auto-approve-bot approved these changes 2026-07-21 10:46:24 +08:00
auto-approve-bot left a comment
Collaborator

CI全绿,自动审批通过。

CI全绿,自动审批通过。
auto-approve-bot approved these changes 2026-07-21 10:46:24 +08:00
auto-approve-bot left a comment
Collaborator

CI全绿,自动审批通过。

CI全绿,自动审批通过。
auto-approve-bot merged commit 9a1eb14fbb into develop 2026-07-21 10:47:31 +08:00
auto-approve-bot deleted branch feat/558-wechat-login-frontend 2026-07-21 10:47:31 +08:00

🗑️ 预览环境已清理

PR #672 已关闭或合并,对应的预览环境已被清理。

如有需要,可以重新打开 PR 来重新生成预览环境。

🗑️ **预览环境已清理** PR #672 已关闭或合并,对应的预览环境已被清理。 > 如有需要,可以重新打开 PR 来重新生成预览环境。
Collaborator

代码审查结果 - PR #672

⚠️ 问题(3个需要修改)

  1. apps/web/src/components/auth/BindContactModal.tsx 第28-36行:倒计时逻辑存在严重内存泄漏和逻辑错误。

    • 原因useEffect 依赖 [countdown]。每次 countdown 减 1 时,Effect 都会重新执行。由于 countdown > 0 始终为真,代码会不断创建新的 setInterval 而不清理旧的,导致倒计时速度呈指数级加快,严重时会导致页面卡顿。
    • 后果:功能异常、性能下降、内存泄漏。
    • 修改建议:应使用 useRef 保存 timer ID,并在 Effect 开始时先清理之前的 timer,或者仅在 countdown 变为 60 时启动定时器。
  2. apps/web/src/pages/auth/WechatCallback.tsx 第28行useEffect 依赖项包含 searchParams 可能导致逻辑重复执行。

    • 原因:React Router 的 useSearchParams 返回的对象在每次渲染时可能被视为新的引用。将其直接放入依赖数组会导致回调逻辑在每次渲染时被触发,可能引发重复的 API 请求。
    • 后果:重复请求后端接口,浪费资源或导致状态冲突。
    • 修改建议:提取 codestate 变量,将这两个具体值作为依赖项,或者使用 searchParams.toString()
  3. apps/web/src/pages/auth/WechatCallback.tsx 第30-33行:缺少 OAuth state 参数的校验与清理。

    • 原因Login.tsx 中将 state 存入了 localStorage,但在回调页 WechatCallback.tsx 中,仅从 URL 获取了 state 并直接传给后端,未与本地存储的 state 进行比对验证,也未在流程结束后清理 localStorage
    • 后果:虽然通常由后端校验,但前端缺少二次校验降低了安全性;残留的 wechat_state 可能影响后续登录流程。
    • 修改建议:在调用 API 前比对 searchParams.get("state")localStorage.getItem("wechat_state"),不一致则报错;流程结束后清除 localStorage。

💡 建议(2个可选)

  1. apps/web/src/components/auth/BindContactModal.tsx 第98-177行:同一个 form 实例被用于两个独立的 <Form> 组件(邮箱和手机 Tab)。

    • 建议:虽然 Ant Design 允许,但在 Tab 切换场景下共用同一个实例容易造成字段状态残留或验证逻辑混乱。建议为每个 Tab 使用独立的 FormInstance,或者在 Tab 切换时手动重置字段。
  2. apps/web/src/pages/auth/WechatCallback.tsx 第78-81行:用户取消绑定时的状态清理。

    • 建议:在 handleBindCancel 中,用户点击取消返回登录页。此时 access_token 已经存入 localStorage(第57行),但用户并未完成绑定。建议在跳转回登录页时清除本次登录产生的 Token,避免出现“已登录但未绑定”的中间态导致后续逻辑冲突。

格式检查通过 | 逻辑审查需修改 | ⚠️ 建议关注性能


🤖 由 AI 代码审查机器人自动生成 | 2026-07-21 10:51:52 | 模型:

## 代码审查结果 - PR #672 ### ⚠️ 问题(3个需要修改) 1. **apps/web/src/components/auth/BindContactModal.tsx 第28-36行**:倒计时逻辑存在严重内存泄漏和逻辑错误。 - **原因**:`useEffect` 依赖 `[countdown]`。每次 `countdown` 减 1 时,Effect 都会重新执行。由于 `countdown > 0` 始终为真,代码会不断创建新的 `setInterval` 而不清理旧的,导致倒计时速度呈指数级加快,严重时会导致页面卡顿。 - **后果**:功能异常、性能下降、内存泄漏。 - **修改建议**:应使用 `useRef` 保存 timer ID,并在 Effect 开始时先清理之前的 timer,或者仅在 `countdown` 变为 60 时启动定时器。 2. **apps/web/src/pages/auth/WechatCallback.tsx 第28行**:`useEffect` 依赖项包含 `searchParams` 可能导致逻辑重复执行。 - **原因**:React Router 的 `useSearchParams` 返回的对象在每次渲染时可能被视为新的引用。将其直接放入依赖数组会导致回调逻辑在每次渲染时被触发,可能引发重复的 API 请求。 - **后果**:重复请求后端接口,浪费资源或导致状态冲突。 - **修改建议**:提取 `code` 和 `state` 变量,将这两个具体值作为依赖项,或者使用 `searchParams.toString()`。 3. **apps/web/src/pages/auth/WechatCallback.tsx 第30-33行**:缺少 OAuth `state` 参数的校验与清理。 - **原因**:`Login.tsx` 中将 `state` 存入了 `localStorage`,但在回调页 `WechatCallback.tsx` 中,仅从 URL 获取了 `state` 并直接传给后端,未与本地存储的 `state` 进行比对验证,也未在流程结束后清理 `localStorage`。 - **后果**:虽然通常由后端校验,但前端缺少二次校验降低了安全性;残留的 `wechat_state` 可能影响后续登录流程。 - **修改建议**:在调用 API 前比对 `searchParams.get("state")` 与 `localStorage.getItem("wechat_state")`,不一致则报错;流程结束后清除 localStorage。 ### 💡 建议(2个可选) 1. **apps/web/src/components/auth/BindContactModal.tsx 第98-177行**:同一个 `form` 实例被用于两个独立的 `<Form>` 组件(邮箱和手机 Tab)。 - **建议**:虽然 Ant Design 允许,但在 Tab 切换场景下共用同一个实例容易造成字段状态残留或验证逻辑混乱。建议为每个 Tab 使用独立的 `FormInstance`,或者在 Tab 切换时手动重置字段。 2. **apps/web/src/pages/auth/WechatCallback.tsx 第78-81行**:用户取消绑定时的状态清理。 - **建议**:在 `handleBindCancel` 中,用户点击取消返回登录页。此时 `access_token` 已经存入 localStorage(第57行),但用户并未完成绑定。建议在跳转回登录页时清除本次登录产生的 Token,避免出现“已登录但未绑定”的中间态导致后续逻辑冲突。 --- ✅ 格式检查通过 | ❌ 逻辑审查需修改 | ⚠️ 建议关注性能 --- <sub>🤖 由 AI 代码审查机器人自动生成 | 2026-07-21 10:51:52 | 模型: </sub> <!-- AI_CODE_REVIEW_AUTO_COMMENT -->
Sign in to join this conversation.