feat(web): migrate account and user management to React
Add React account and user administration flows, including TOTP and SSO handling. Route /next SSO callbacks to React while preserving the existing Vue and native app behavior, and cover the routing policy with API tests.
This commit is contained in:
1 parent
f802598dab
commit
1ab9b76101
17 files changed
+1058
-60
No files matched your search
@@ -6,7 +6,7 @@
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `/login` | 登录 | 公开 | 验证码、密码、TOTP、SSO 设置、会话落盘 | building |
|
||||
| `/dashboard` | 教务总览 | 已登录用户 | `GET /api/dashboard`、角色视图、待办和学期 | building |
|
||||
| `/account` | 个人账户 | 已登录用户 | TOTP、Passkey、恢复码、SSO 绑定 | inventory |
|
||||
| `/users` | 用户与权限 | SuperAdmin | 列表、筛选、分页、创建、重置密码、角色范围 | inventory |
|
||||
| `/account` | 个人账户 | 已登录用户 | TOTP、恢复码、SSO 绑定;Passkey 浏览器仪式尚未开放 | verification |
|
||||
| `/users` | 用户与权限 | SuperAdmin | 列表、筛选、分页、创建、启停、重置密码、角色范围、Excel | verification |
|
||||
|
||||
后续从 `web/src/router/index.ts` 逐条补全。只有关键合同和各状态验收完整后,状态才能更新为 `complete`。
|
||||
+3
-2
@@ -27,7 +27,8 @@ npm.cmd run build
|
||||
- 账号密码、验证码和 TOTP 登录;
|
||||
- 权限感知的应用外壳;
|
||||
- 读取真实 `/api/dashboard` 数据的首个页面;
|
||||
- `/account` 和 `/users` 迁移占位路由,可安全返回现有 Vue 页面。
|
||||
- 完整迁移 `/account` 的身份信息、TOTP 和统一身份绑定流程;
|
||||
- 完整迁移 `/users` 的分页筛选、Excel、账号、角色、状态和密码管理流程。
|
||||
|
||||
## 迁移纪律
|
||||
|
||||
@@ -42,7 +43,7 @@ npm.cmd run build
|
||||
| 批次 | 内容 | 状态 |
|
||||
| --- | --- | --- |
|
||||
| 0 | 工程、主题、会话、登录、应用外壳 | 进行中 |
|
||||
| 1 | Dashboard、Users、Account、移动端代表页 | Dashboard 首版已接入 |
|
||||
| 1 | Dashboard、Users、Account、移动端代表页 | 前三项进入联调验收 |
|
||||
| 2 | 标准 CRUD 与基础数据模块 | 未开始 |
|
||||
| 3 | 学生、教师与审批工作台 | 未开始 |
|
||||
| 4 | 选课、排课、成绩、实验等复杂模块 | 未开始 |
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import type { AxiosRequestConfig } from 'axios'
|
||||
import http from './http'
|
||||
|
||||
function responseFileName(header: string | undefined, fallback: string) {
|
||||
if (!header) return fallback
|
||||
const encoded = header.match(/filename\*=UTF-8''([^;]+)/i)?.[1]
|
||||
if (encoded) return decodeURIComponent(encoded)
|
||||
const plain = header.match(/filename="?([^";]+)"?/i)?.[1]
|
||||
return plain || fallback
|
||||
}
|
||||
|
||||
export async function downloadApiFile(
|
||||
path: string,
|
||||
fallbackName: string,
|
||||
config?: AxiosRequestConfig,
|
||||
) {
|
||||
const response = await http.get(path, { ...config, responseType: 'blob' })
|
||||
const url = URL.createObjectURL(response.data)
|
||||
try {
|
||||
const anchor = document.createElement('a')
|
||||
anchor.href = url
|
||||
anchor.download = responseFileName(response.headers['content-disposition'], fallbackName)
|
||||
document.body.appendChild(anchor)
|
||||
anchor.click()
|
||||
anchor.remove()
|
||||
} finally {
|
||||
URL.revokeObjectURL(url)
|
||||
}
|
||||
}
|
||||
|
||||
export async function importExcel(path: string, file: File) {
|
||||
const form = new FormData()
|
||||
form.append('file', file)
|
||||
return http.post(path, form, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
timeout: 60000,
|
||||
})
|
||||
}
|
||||
Loaded 3 of 17 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user