feat(passport): 增加多租户手机号登录支持并修复邮箱验证码校验
- 修复邮箱登录验证码未校验问题,恢复输入错误提示及刷新验证码逻辑 - 新增多租户选项登录流程,支持单租户直接登录及多租户选择弹窗 - 扩展登录接口及模型,新增 TenantOption 类型和 LoginOutcome 联合结果类型 - 新增 loginBySelectTenant 二次登录接口及对应组件逻辑 - 统一保存登录态,包括 token、租户ID和用户ID到本地存储 - 调整前端短信登录逻辑,根据返回状态决定流程,支持多租户弹窗选择 - 确保新增代码无类型错误并通过构建验证
This commit is contained in:
@@ -9,6 +9,30 @@ import type {
|
||||
} from './model';
|
||||
import { User } from '@/api/system/user/model';
|
||||
import { SERVER_API_URL } from '@/config/setting';
|
||||
import type { LoginOutcome, TenantOption } from './model';
|
||||
|
||||
/**
|
||||
* 登录态落地:把后端返回的 access_token / 租户 / 用户 持久化到本地
|
||||
*/
|
||||
function saveLoginState(result: LoginResult | undefined, remember?: boolean) {
|
||||
if (!result) return;
|
||||
if (result.access_token) {
|
||||
setToken(result.access_token, remember);
|
||||
}
|
||||
const user = result.user;
|
||||
if (user) {
|
||||
if (user.tenantId != null) {
|
||||
try {
|
||||
localStorage.setItem('TenantId', String(user.tenantId));
|
||||
} catch { /* ignore */ }
|
||||
}
|
||||
if (user.userId != null) {
|
||||
try {
|
||||
localStorage.setItem('UserId', String(user.userId));
|
||||
} catch { /* ignore */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录
|
||||
@@ -106,23 +130,58 @@ export async function loginBySms(data: LoginParam) {
|
||||
|
||||
/**
|
||||
* 超管手机号短信登录
|
||||
* 后端对应 POST /loginBySuperAdminSms,参数为 { phone, code, tenantId }
|
||||
* - 单租户:直接返回 ok
|
||||
* - 多租户:返回 selectTenant,前端需调用 loginBySelectTenant 二次登录
|
||||
*/
|
||||
export async function loginBySuperAdminSms(data: LoginParam) {
|
||||
export async function loginBySuperAdminSms(
|
||||
data: LoginParam
|
||||
): Promise<LoginOutcome> {
|
||||
const res = await request.post<ApiResult<LoginResult>>(
|
||||
SERVER_API_URL + '/loginBySuperAdminSms',
|
||||
data
|
||||
{ phone: data.phone, code: data.smsCode, smsCode: data.smsCode, tenantId: data.tenantId }
|
||||
);
|
||||
if (res.data.code === 0) {
|
||||
setToken(res.data.data?.access_token, data.remember);
|
||||
if (res.data.data?.user) {
|
||||
const user = res.data.data?.user;
|
||||
localStorage.setItem('TenantId', String(user.tenantId));
|
||||
localStorage.setItem('UserId', String(user.userId));
|
||||
}
|
||||
|
||||
return res.data.message;
|
||||
if (res.data.code !== 0) {
|
||||
return Promise.reject(new Error(res.data.message));
|
||||
}
|
||||
return Promise.reject(new Error(res.data.message));
|
||||
const result = res.data.data;
|
||||
if (result?.tenants && result.tenants.length > 0) {
|
||||
return {
|
||||
status: 'selectTenant',
|
||||
tenants: result.tenants as TenantOption[],
|
||||
message: res.data.message || '请选择要登录的租户'
|
||||
};
|
||||
}
|
||||
if (result?.user) {
|
||||
saveLoginState(result, data.remember);
|
||||
return { status: 'ok', user: result.user, message: res.data.message || '登录成功' };
|
||||
}
|
||||
return Promise.reject(new Error(res.data.message || '登录失败'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择租户后登录(多租户短信登录专用二次登录接口)
|
||||
* 后端对应 POST /loginBySelectTenant,参数为 { phone, code, tenantId }
|
||||
*/
|
||||
export async function loginBySelectTenant(data: {
|
||||
phone: string;
|
||||
code: string;
|
||||
tenantId: number;
|
||||
remember?: boolean;
|
||||
}): Promise<LoginOutcome> {
|
||||
const res = await request.post<ApiResult<LoginResult>>(
|
||||
SERVER_API_URL + '/loginBySelectTenant',
|
||||
{ phone: data.phone, code: data.code, smsCode: data.code, tenantId: data.tenantId }
|
||||
);
|
||||
if (res.data.code !== 0) {
|
||||
return Promise.reject(new Error(res.data.message));
|
||||
}
|
||||
const result = res.data.data;
|
||||
if (result?.user) {
|
||||
saveLoginState(result, data.remember);
|
||||
return { status: 'ok', user: result.user, message: res.data.message || '登录成功' };
|
||||
}
|
||||
return Promise.reject(new Error(res.data.message || '登录失败'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,6 +19,8 @@ export interface LoginParam {
|
||||
phone?: string;
|
||||
// 短信验证码
|
||||
code?: string;
|
||||
// 短信验证码(别名,与后端 LoginParam.code 对应)
|
||||
smsCode?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -29,8 +31,30 @@ export interface LoginResult {
|
||||
access_token?: string;
|
||||
// 用户信息
|
||||
user?: User;
|
||||
// 多租户场景下返回,此时 access_token / user 为 null
|
||||
tenants?: TenantOption[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 多租户登录时后端返回的租户选项
|
||||
*/
|
||||
export interface TenantOption {
|
||||
tenantId?: number;
|
||||
tenantName?: string;
|
||||
userId?: number;
|
||||
username?: string;
|
||||
nickname?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录接口统一返回结果
|
||||
* - ok:单租户直接登录成功
|
||||
* - selectTenant:多租户,需要前端弹出选择租户列表
|
||||
*/
|
||||
export type LoginOutcome =
|
||||
| { status: 'ok'; user: NonNullable<LoginResult['user']>; message: string }
|
||||
| { status: 'selectTenant'; tenants: TenantOption[]; message: string };
|
||||
|
||||
/**
|
||||
* 图形验证码返回结果
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user