81ef9317c7
密码找回(材料审核制,见 ADR 0008)
- app/pages/forgot-password.vue:两个页签——「提交申请」(企业名称 + 纳税人识别号 + 新密码 + 确认
+ 授权委托书,复用 POST /api/tender/upload,并照 HjcEnterpriseForm 做 5M 校验)与「查询进度」
(双要素查询,展示状态与时间、驳回原因)。提交后自动把条件带到查询页签。文案纪律:
「已通过」≠「已重置」。
修改密码(登录态,双因子)
- app/pages/change-password.vue:旧密码 + 短信验证码(60s 倒计时,照 register.vue)+ 新密码 +
确认;成功后清本机凭据并显示「去登录」面板。
BFF 与封装
- server/api/tender/password/{apply.post,status.get,sms.post,change.put}.ts:四条都照
register.post.ts 的透传范式(modulesApiBase + TenantId(header 与 query 都带)+ 原样返回
ApiResult,HTTP 恒 200)。前两条**匿名**(与 sms/upload 一致,不读 cookie);后两条需登录态,
从 cookie hjc_token 或 Authorization 头取 token 拼 Bearer。
- app/composables/useHjcPassword.ts:四条请求单独成一支,不塞进 useHjcAuth——找回的两条是匿名的、
不做 401 跳转;修改密码的两条经 handleAuthCode 处理登录态。
接线
- app/pages/login.vue:加「忘记密码?」入口。
- app/components/HjcUserBar.vue:已登录菜单加「修改密码」。
落点说明:新页面直接放 app/pages/*.vue——静态段路由优先于 app/pages/[slug].vue 的动态段,故不必
动 useTemplate.ts / templates/index.ts,与 login.vue、register.vue 完全同款做法,10 套模板自动可用。
验证:针对本次文件 npx eslint 0 error;pnpm run build 成功且四条新 BFF 都出现在产物里。
未验:未起 mp-java 做端到端(见 .scratch/hjc-password/issues/06)。
88 lines
3.7 KiB
TypeScript
88 lines
3.7 KiB
TypeScript
/**
|
|
* 密码找回(材料审核制)与修改密码的前端封装。
|
|
*
|
|
* 独立成一支而不是塞进 `useHjcAuth`:后者已承担登录/注册/退出,这里只放密码相关的四条请求。
|
|
*
|
|
* 两条链路的失败语义不同,注意别混:
|
|
* - **找回**(申请 / 查进度)是匿名的,后端对「企业不存在 / 信息不匹配」一律回同一句话,
|
|
* 前端拿不到区分性的原因,也不该试图区分。
|
|
* - **修改密码**的发送短信与提交都需登录态,401 要清凭据并跳登录页(交给 `handleAuthCode`)。
|
|
*/
|
|
export interface HjcPasswordApplyStatus {
|
|
status: number
|
|
statusText: string
|
|
applyTime?: string | null
|
|
auditTime?: string | null
|
|
resetTime?: string | null
|
|
rejectReason?: string | null
|
|
}
|
|
|
|
export function useHjcPassword() {
|
|
const { handleAuthCode } = useHjcAuth()
|
|
|
|
/** Nuxt 的 createError 会把后端的 statusMessage 放进 e.data,这里统一收口取文案 */
|
|
function errMessage(e: any, fallback: string) {
|
|
return e?.data?.statusMessage || e?.data?.message || e?.message || fallback
|
|
}
|
|
|
|
/** 提交找回申请(匿名)。成功时后端的 message 是统一话术,不含任何企业存在性信息 */
|
|
async function applyPasswordReset(payload: Record<string, any>) {
|
|
try {
|
|
const res: any = await $fetch('/api/tender/password/apply', { method: 'POST', body: payload })
|
|
if (res?.code === 0) {
|
|
return { ok: true, message: res?.message as string }
|
|
}
|
|
return { ok: false, message: res?.message || '提交失败' }
|
|
} catch (e: any) {
|
|
return { ok: false, message: errMessage(e, '提交失败') }
|
|
}
|
|
}
|
|
|
|
/** 查询找回进度(匿名)。data 为 null 表示没有记录 */
|
|
async function fetchApplyStatus(enterpriseName: string, creditCode: string) {
|
|
try {
|
|
const res: any = await $fetch('/api/tender/password/status', {
|
|
query: { enterpriseName, creditCode }
|
|
})
|
|
if (res?.code === 0) {
|
|
return { ok: true, data: (res.data || null) as HjcPasswordApplyStatus | null }
|
|
}
|
|
return { ok: false, data: null, message: res?.message || '查询失败' }
|
|
} catch (e: any) {
|
|
return { ok: false, data: null, message: errMessage(e, '查询失败') }
|
|
}
|
|
}
|
|
|
|
/** 发送修改密码的短信验证码(登录态)。收件号由后端从登录态取,前端不能指定 */
|
|
async function sendChangePasswordSms() {
|
|
try {
|
|
const res: any = await $fetch('/api/tender/password/sms', { method: 'POST' })
|
|
if (res?.code === 0) {
|
|
return { ok: true, message: res?.message || '验证码已发送' }
|
|
}
|
|
const auth = await handleAuthCode(res, '/change-password')
|
|
if (auth.handled) return { ok: false, message: auth.message || '请先登录' }
|
|
return { ok: false, message: res?.message || '验证码发送失败' }
|
|
} catch (e: any) {
|
|
return { ok: false, message: errMessage(e, '验证码发送失败') }
|
|
}
|
|
}
|
|
|
|
/** 提交修改密码(登录态,旧密码 + 短信验证码) */
|
|
async function changePassword(payload: Record<string, any>) {
|
|
try {
|
|
const res: any = await $fetch('/api/tender/password/change', { method: 'PUT', body: payload })
|
|
if (res?.code === 0) {
|
|
return { ok: true, message: res?.message || '密码修改成功' }
|
|
}
|
|
const auth = await handleAuthCode(res, '/change-password')
|
|
if (auth.handled) return { ok: false, message: auth.message || '请先登录' }
|
|
return { ok: false, message: res?.message || '修改密码失败' }
|
|
} catch (e: any) {
|
|
return { ok: false, message: errMessage(e, '修改密码失败') }
|
|
}
|
|
}
|
|
|
|
return { applyPasswordReset, fetchApplyStatus, sendChangePasswordSms, changePassword }
|
|
}
|