feat(passport): 新增忘记密码功能及相关接口

- 新增忘记密码页面,支持邮箱找回和手机找回两种方式,包含验证码倒计时
- 添加密码强度和一致性校验,确保新密码安全性
- 开启对应路由 /forget,恢复已注释的忘记密码入口
- 新增发送短信验证码和邮箱验证码接口,适配未登录场景
- 新增重置密码接口,支持手机短信码及邮箱验证码方式
- 请求拦截器支持 X-Tenant-Skip 头,跳过租户信息注入,避免跨租户串扰
- 国际化新增忘记密码相关英文和中文文案
- 页面样式与登录页视觉风格一致,跨屏幕响应式布局优化
This commit is contained in:
2026-07-24 22:07:53 +08:00
parent 0bfd5e667b
commit d6b56d99ce
9 changed files with 661 additions and 8 deletions

View File

@@ -1,7 +1,7 @@
import request from '@/utils/request';
import type { ApiResult } from '@/api';
import type { User } from '@/api/system/user/model';
import type { UpdatePasswordParam, NoticeResult } from './model';
import type { UpdatePasswordParam, ResetPasswordParam, NoticeResult } from './model';
import { SERVER_API_URL } from '@/config/setting';
import { Company } from '@/api/system/company/model';
import { CmsWebsite } from '@/api/cms/cmsWebsite/model';
@@ -108,6 +108,24 @@ export async function updatePassword(
return Promise.reject(new Error(res.data.message));
}
/**
* 找回/重置密码(未登录场景,登录页"忘记密码"入口)
* 后端对应 POST /resetPassword支持手机或邮箱两种方式
*/
export async function resetPassword(
data: ResetPasswordParam
): Promise<string> {
const res = await request.post<ApiResult<unknown>>(
SERVER_API_URL + '/resetPassword',
data,
{ headers: { 'X-Tenant-Skip': '1' } }
);
if (res.data.code === 0) {
return res.data.message ?? '密码重置成功';
}
return Promise.reject(new Error(res.data.message));
}
/**
* 创建完整网站并初始化
*/

View File

@@ -24,6 +24,23 @@ export interface UpdatePasswordParam {
oldPassword: string;
}
/**
* 找回/重置密码参数
* 手机找回时传 phone + smsCode邮箱找回时传 email + emailCode
*/
export interface ResetPasswordParam {
/** 手机找回时必填 */
phone?: string;
smsCode?: string;
/** 邮箱找回时必填 */
email?: string;
emailCode?: string;
/** 新密码 */
newPassword: string;
/** 确认新密码 */
confirmPassword: string;
}
/**
* 通知数据格式
*/

View File

@@ -139,6 +139,46 @@ export async function sendSmsCaptcha(data: LoginParam) {
return Promise.reject(new Error(res.data.message));
}
/**
* 发送短信验证码(后台管理员,跨租户:只要该手机号是超管或管理员即发送)
* 后端对应 POST /sendSmsCaptchaByAdmin参数为 { phone }
* @param options.skipTenant 为 true 时不携带 tenantId 请求头(登录前无法确定租户时使用)
*/
export async function sendSmsCaptchaByAdmin(
data: LoginParam,
options?: { skipTenant?: boolean }
) {
const res = await request.post<ApiResult<SmsCaptchaResult>>(
SERVER_API_URL + '/sendSmsCaptchaByAdmin',
data,
options?.skipTenant ? { headers: { 'X-Tenant-Skip': '1' } } : undefined
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 发送邮箱验证码(找回密码等登录前场景使用)
* 后端对应 POST /sendEmailCaptcha参数为 { email }
* @param options.skipTenant 为 true 时不携带 tenantId 请求头(登录前无法确定租户时使用)
*/
export async function sendEmailCaptcha(
data: LoginParam,
options?: { skipTenant?: boolean }
) {
const res = await request.post<ApiResult<unknown>>(
SERVER_API_URL + '/sendEmailCaptcha',
data,
options?.skipTenant ? { headers: { 'X-Tenant-Skip': '1' } } : undefined
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 登录
*/