feat: 实现设置页面 + 路由系统 + JWT认证体系 + 公告优化 + 错误类型系统
## 新增功能 ### 设置页面(Router + Modal 叠加) - HashRouter 路由系统,Electron file:// 协议兼容 - 设置页以居中 Modal 叠加首页,仅 X 按钮关闭 - 主题切换 Segmented 控件(与首页 Switch 共享 Context) - 大模型产物存储仓库路径配置(原生文件夹选择对话框) - 企业版额外:团队创作存储仓库路径 - 系统信息展示(平台/版本/版本类型/环境) - 版本更新检查(状态机:idle→checking→no-update/available→downloading→downloaded→error) ### JWT 认证体系 - 双 Token 机制:access_token + refresh_token - Axios 拦截器 401 自动刷新 + 并发请求去重队列 - 启动时 refresh_token 静默续期(自动登录) - 记住密码:Base64 编码存储,表单自动回填 - setTokenRefreshHandler 解耦模式:request.ts 不知晓 auth ### 自定义错误类型系统 - RefreshError 继承 RequestError,type = AUTH_EXPIRED - 全局拦截器捕获 RefreshError → 自动 clearToken + AUTH_REQUIRED - 任何位置 throw new RefreshError() 即可触发登录 Modal ### 公告卡片优化 - 长文本 Tooltip 悬浮预览 - 点击卡片弹出详情 Modal(全文保留换行) ### SettingsContext(类似 Vue Pinia) - 集中式设置状态管理 - localStorage 持久化:ele-heixiu-output-path / ele-heixiu-team-repo-path - useSettings() 全局消费 ## 架构变更 - App.tsx → HashRouter + AppRoutes + LoginPage 弹层 - Layout.tsx = NavBar + <Outlet /> 页面壳 - HomePage.tsx 从 App.tsx 提取 - NavBar 使用 useNavigate() 真实路由导航 - useUpdater 改为模块级单例 IPC 监听器(修复 MaxListenersExceededWarning) - electron/main.ts 新增 FILE_DIALOG IPC handler ## 依赖 - 新增 react-router-dom
This commit is contained in:
@@ -5,6 +5,14 @@
|
||||
|
||||
import { get } from '../request';
|
||||
|
||||
// ============================================================
|
||||
// AnnouncementUrlObj — 公告模块路由常量
|
||||
// ============================================================
|
||||
|
||||
const AnnouncementUrlObj = {
|
||||
list: '/api/v1/announcements',
|
||||
} as const;
|
||||
|
||||
// ---------- 类型 ----------
|
||||
|
||||
/** 公告类型枚举 */
|
||||
@@ -34,5 +42,5 @@ export type AnnouncementListResponse = Announcement[];
|
||||
* GET /api/v1/announcements
|
||||
*/
|
||||
export function fetchAnnouncements(): Promise<AnnouncementListResponse> {
|
||||
return get<AnnouncementListResponse>('/api/v1/announcements');
|
||||
return get<AnnouncementListResponse>(AnnouncementUrlObj.list);
|
||||
}
|
||||
|
||||
190
src/services/modules/auth.ts
Normal file
190
src/services/modules/auth.ts
Normal file
@@ -0,0 +1,190 @@
|
||||
import {post, get} from '../request';
|
||||
|
||||
// ============================================================
|
||||
// AuthUrlObj — 认证模块路由常量
|
||||
// 集中管理,后续接口升级 v2 等只需改此处
|
||||
// ============================================================
|
||||
|
||||
const AuthUrlObj = {
|
||||
login: '/api/v1/auth/login',
|
||||
register: '/api/v1/auth/register',
|
||||
sendSms: '/api/v1/auth/sms/send',
|
||||
refreshToken: '/api/v1/auth/refresh',
|
||||
userInfo: '/api/v1/auth/me',
|
||||
changePassword: '/api/v1/auth/change-password',
|
||||
resetPassword: '/api/v1/auth/reset-password',
|
||||
logout: '/api/v1/auth/logout',
|
||||
} as const;
|
||||
|
||||
// ============================================================
|
||||
// 认证相关 DTO 传输模型
|
||||
// ============================================================
|
||||
|
||||
/** 短信验证码请求体 */
|
||||
export interface SendSMSRequestBody {
|
||||
phone: string;
|
||||
}
|
||||
|
||||
/** 注册请求体 */
|
||||
export interface RegisterRequestBody {
|
||||
// 用户名,3~64 位,仅允许字母、数字、-、_
|
||||
username: string;
|
||||
// 密码,6~128 位
|
||||
password: string;
|
||||
// 手机号,5~32 位
|
||||
phone: string;
|
||||
// 短信验证码,4~8 位
|
||||
sms_code: string;
|
||||
// 设备标识(网卡 MAC),8~128 位
|
||||
device_id: string;
|
||||
// 设备标签/备注(可选)
|
||||
device_label: string;
|
||||
// 个人昵称(可选)
|
||||
display_name: string;
|
||||
// 邀请码(可选),填写后触发邀请佣金逻辑
|
||||
referral_code: string;
|
||||
}
|
||||
|
||||
export interface RegisterResponseBody {
|
||||
access_token: string;
|
||||
refresh_token: string;
|
||||
token_type: string;
|
||||
expires_in: 0;
|
||||
refresh_expires_in: 0;
|
||||
user_id: string;
|
||||
username: string;
|
||||
role: "user" | "admin" | "superadmin";
|
||||
email: string;
|
||||
balance_cent: 0;
|
||||
account_type: "individual" | "company" | "employee";
|
||||
display_name: string;
|
||||
company_id: string;
|
||||
real_name: string;
|
||||
phone: string;
|
||||
license_code: string;
|
||||
admin_permissions: string []
|
||||
}
|
||||
|
||||
/** 登录请求体 */
|
||||
export interface LoginRequestBody {
|
||||
username: string;
|
||||
password: string;
|
||||
device_id: string;
|
||||
user_ip: string;
|
||||
}
|
||||
|
||||
export interface LoginResponseBody {
|
||||
access_token: string;
|
||||
refresh_token: string;
|
||||
token_type: string;
|
||||
expires_in: number;
|
||||
refresh_expires_in: number;
|
||||
user_id: string;
|
||||
username: string;
|
||||
role: "user" | "admin" | "superadmin";
|
||||
email: string;
|
||||
balance_cent: number;
|
||||
account_type: "individual" | "company" | "employee";
|
||||
display_name: string;
|
||||
company_id: string;
|
||||
real_name: string;
|
||||
phone: string;
|
||||
license_code: string;
|
||||
admin_permissions: string[];
|
||||
}
|
||||
|
||||
export interface RefreshTokenRequestBody {
|
||||
refresh_token: string;
|
||||
}
|
||||
|
||||
export interface RefreshTokenResponseBody {
|
||||
access_token: string;
|
||||
refresh_token: string;
|
||||
token_type: string;
|
||||
expires_in: number;
|
||||
refresh_expires_in: number;
|
||||
}
|
||||
|
||||
export interface UserInfoBody {
|
||||
id: string;
|
||||
username: string;
|
||||
email: string;
|
||||
balance_cent: number;
|
||||
gift_balance_cent: number;
|
||||
role: "user" | "admin" | "superadmin";
|
||||
status: string;
|
||||
account_type: "individual" | "company" | "employee";
|
||||
display_name: string;
|
||||
real_name: string;
|
||||
phone: string;
|
||||
company_id: string;
|
||||
discount_rate: number;
|
||||
subscription_plan: string;
|
||||
subscription_expires_at: Date;
|
||||
seat_limit: number;
|
||||
last_login_at: Date;
|
||||
created_at: Date;
|
||||
model_package_id: number;
|
||||
vip_level_id: number;
|
||||
software_expires_at: Date;
|
||||
referral_code: string;
|
||||
admin_permissions: string[];
|
||||
}
|
||||
|
||||
export interface ChangePasswordRequestBody {
|
||||
current_password: string;
|
||||
new_password: string;
|
||||
}
|
||||
|
||||
export interface UsePhoneResetPasswordRequestBody {
|
||||
phone: string;
|
||||
sms_code: string;
|
||||
new_password: string;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// AuthAPI — 认证相关 API 静态方法类
|
||||
// 调用方式:AuthAPI.login() / AuthAPI.register() 等
|
||||
// ============================================================
|
||||
|
||||
export class AuthAPI {
|
||||
/** 登录 */
|
||||
static login(data: LoginRequestBody): Promise<LoginResponseBody> {
|
||||
return post<LoginResponseBody>(AuthUrlObj.login, data);
|
||||
}
|
||||
|
||||
/** 注册 */
|
||||
static register(data: RegisterRequestBody): Promise<RegisterResponseBody> {
|
||||
return post<RegisterResponseBody>(AuthUrlObj.register, data);
|
||||
}
|
||||
|
||||
/** 发送短信验证码 */
|
||||
static sendSms(data: SendSMSRequestBody): Promise<void> {
|
||||
return post<void>(AuthUrlObj.sendSms, data);
|
||||
}
|
||||
|
||||
/** 刷新 Token */
|
||||
static refreshToken(data: RefreshTokenRequestBody): Promise<RefreshTokenResponseBody> {
|
||||
return post<RefreshTokenResponseBody>(AuthUrlObj.refreshToken, data);
|
||||
}
|
||||
|
||||
/** 获取当前用户信息 */
|
||||
static getUserInfo(): Promise<UserInfoBody> {
|
||||
return get<UserInfoBody>(AuthUrlObj.userInfo);
|
||||
}
|
||||
|
||||
/** 修改密码(已登录) */
|
||||
static changePassword(data: ChangePasswordRequestBody): Promise<void> {
|
||||
return post<void>(AuthUrlObj.changePassword, data);
|
||||
}
|
||||
|
||||
/** 手机验证码重置密码 */
|
||||
static resetPassword(data: UsePhoneResetPasswordRequestBody): Promise<void> {
|
||||
return post<void>(AuthUrlObj.resetPassword, data);
|
||||
}
|
||||
|
||||
/** 退出登录 */
|
||||
static logout(): Promise<void> {
|
||||
return post<void>(AuthUrlObj.logout);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
// ============================================================
|
||||
// API 模块统一导出
|
||||
// 后续新增模块(如 auth、user、billing 等)在此追加
|
||||
// ============================================================
|
||||
|
||||
export {
|
||||
@@ -9,3 +8,17 @@ export {
|
||||
type AnnouncementType,
|
||||
type AnnouncementListResponse,
|
||||
} from './announcement';
|
||||
|
||||
export {
|
||||
AuthAPI,
|
||||
type SendSMSRequestBody,
|
||||
type RegisterRequestBody,
|
||||
type RegisterResponseBody,
|
||||
type LoginRequestBody,
|
||||
type LoginResponseBody,
|
||||
type RefreshTokenRequestBody,
|
||||
type RefreshTokenResponseBody,
|
||||
type UserInfoBody,
|
||||
type ChangePasswordRequestBody,
|
||||
type UsePhoneResetPasswordRequestBody,
|
||||
} from './auth';
|
||||
|
||||
Reference in New Issue
Block a user