Files
hfb_jysh/frontend/src/features/admin/AdminChangePasswordPage.tsx
T

138 lines
5.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useState } from 'react'
import { Alert, App, Button, Form, Input, Typography } from 'antd'
import { LockOutlined } from '@ant-design/icons'
import { Navigate, useNavigate } from 'react-router-dom'
import { BrandLogo } from '@/components/BrandLogo'
import { getAdminBasePath, getAdminLoginPath } from '@/shared/api/adminClient'
import { useAdminSessionStore } from '@/stores/adminSession'
interface ChangePasswordForm {
old_password: string
new_password: string
confirm_password: string
}
export function AdminChangePasswordPage() {
const { message } = App.useApp()
const navigate = useNavigate()
const admin = useAdminSessionStore(state => state.admin)
const logout = useAdminSessionStore(state => state.logout)
const changePassword = useAdminSessionStore(state => state.changePassword)
const [submitting, setSubmitting] = useState(false)
const [error, setError] = useState('')
const basePath = getAdminBasePath()
if (!admin) return <Navigate to={getAdminLoginPath()} replace />
if (!admin.password_must_change) return <Navigate to={basePath} replace />
const onFinish = async (values: ChangePasswordForm) => {
setSubmitting(true)
setError('')
try {
await changePassword(values.old_password, values.new_password)
message.success('初始密码已更新')
navigate(basePath, { replace: true })
} catch (err) {
setError(err instanceof Error ? err.message : '密码没有更新,请检查原密码')
} finally {
setSubmitting(false)
}
}
return (
<main className="admin-login-page">
<section className="admin-login-brand">
<div className="admin-login-brand__inner">
<BrandLogo height={56} variant="dark" />
<div className="admin-login-brand__eyebrow">FIRST RUN · SECURITY</div>
<Typography.Title className="brand-title admin-login-brand__title">
先把钥匙
<br />
换掉。
</Typography.Title>
<Typography.Paragraph className="admin-login-brand__copy">
初始密码只用于第一次进入。修改完成后,这个后台会话才能打开订单、财务和分销操作。
</Typography.Paragraph>
</div>
</section>
<section className="admin-login-form-panel">
<div className="admin-login-card">
<div className="admin-login-card__head">
<BrandLogo height={34} />
<Typography.Title level={2} className="brand-title">
修改初始密码
</Typography.Title>
<Typography.Text type="secondary">
当前账号:{admin.nickname || admin.username}({admin.username})
</Typography.Text>
</div>
{error ? <Alert type="error" showIcon message={error} className="login-alert" /> : null}
<Form<ChangePasswordForm>
layout="vertical"
size="large"
requiredMark={false}
onFinish={onFinish}
>
<Form.Item
label="原密码"
name="old_password"
rules={[{ required: true, message: '请输入原密码' }]}
>
<Input.Password prefix={<LockOutlined />} placeholder="请输入原密码" />
</Form.Item>
<Form.Item
label="新密码"
name="new_password"
rules={[
{ required: true, message: '请输入新密码' },
{ min: 8, max: 20, message: '密码长度需为 8–20 位' },
]}
>
<Input.Password prefix={<LockOutlined />} placeholder="8–20 位新密码" />
</Form.Item>
<Form.Item
label="确认新密码"
name="confirm_password"
dependencies={['new_password']}
rules={[
{ required: true, message: '请再次输入新密码' },
({ getFieldValue }) => ({
validator(_, value) {
if (!value || getFieldValue('new_password') === value) {
return Promise.resolve()
}
return Promise.reject(new Error('两次输入的新密码不一致'))
},
}),
]}
>
<Input.Password prefix={<LockOutlined />} placeholder="再次输入新密码" />
</Form.Item>
<Button type="primary" htmlType="submit" block loading={submitting}>
更新密码并进入后台
</Button>
</Form>
<div className="admin-login-card__foot">
<span>改密后旧会话会按后端规则刷新</span>
<Button
type="link"
onClick={async () => {
await logout()
navigate(getAdminLoginPath(), { replace: true })
}}
>
退出登录
</Button>
</div>
</div>
</section>
</main>
)
}