Files
stash/stash-web/src/components/auth/LoginDialog.tsx
T
CNWei fe9d1b2659 refactor(admin): 接入 PasswordInput,删除分类改用 Modal 确认
- 登录弹窗与系统改密统一用 @stash/ui 的 PasswordInput(改密页补上显隐切换)
- 删除分类不再用 window.confirm,改用 Modal + 危险按钮(组件库推荐的组合)
- 删除页面私有的 PasswordInput 组件与 .password-field 样式
2026-10-29 20:46:11 +08:00

118 lines
3.3 KiB
TypeScript

import { Button, FormField, Icon, Modal, Notice, PasswordInput, Space, Text } from '@stash/ui'
import { useEffect, useState } from 'react'
import { login, setup, type SessionState } from '../../auth'
/**
* 登录弹窗:首次使用显示「设置密码 + 确认」,之后只显示密码。
*
* 成功后由父组件刷新会话状态;弹窗本身不跳转页面。
*/
type LoginDialogProps = {
open: boolean
hasAdmin: boolean
onClose: () => void
onSuccess: (session: SessionState) => void
}
export function LoginDialog({ open, hasAdmin, onClose, onSuccess }: LoginDialogProps) {
const [password, setPassword] = useState('')
const [confirm, setConfirm] = useState('')
const [error, setError] = useState('')
const [busy, setBusy] = useState(false)
// 每次打开重置,避免上次的错误/输入残留
useEffect(() => {
if (!open) return
setPassword('')
setConfirm('')
setError('')
setBusy(false)
}, [open])
const isSetup = !hasAdmin
const submit = async () => {
setError('')
if (isSetup && password !== confirm) {
setError('两次输入的密码不一致')
return
}
setBusy(true)
const result = isSetup ? await setup(password) : await login(password)
setBusy(false)
if (!result.ok) {
setError(result.error)
return
}
onSuccess({
authenticated: true,
has_admin: true,
username: 'admin',
})
}
return (
<Modal
open={open}
onClose={onClose}
title={isSetup ? '设置管理员密码' : '登录'}
footer={
<Space gap="sm" justify="end">
<Button variant="secondary" onClick={onClose}>
取消
</Button>
<Button loading={busy} icon={<Icon name="lock_line" />} onClick={submit}>
{isSetup ? '设置并登录' : '登录'}
</Button>
</Space>
}
>
<Space direction="column" gap="md" align="stretch">
<Text size="sm" tone="muted">
{isSetup
? '首次使用:设置一个至少 8 位的密码,之后用它登录编辑。'
: '登录后可以编辑页头滚动信息、侧栏顺序与显示。'}
</Text>
{error !== '' && (
<Notice tone="error" title="操作失败">
{error}
</Notice>
)}
<FormField label="密码" htmlFor="login-password" required>
<PasswordInput
id="login-password"
placeholder="输入密码"
autoComplete={isSetup ? 'new-password' : 'current-password'}
value={password}
autoFocus
onChange={(event) => setPassword(event.target.value)}
onKeyDown={(event) => {
if (event.key === 'Enter') void submit()
}}
/>
</FormField>
{isSetup && (
<FormField label="确认密码" htmlFor="login-confirm" required>
<PasswordInput
id="login-confirm"
placeholder="再输入一次"
autoComplete="new-password"
value={confirm}
onChange={(event) => setConfirm(event.target.value)}
onKeyDown={(event) => {
if (event.key === 'Enter') void submit()
}}
/>
</FormField>
)}
</Space>
</Modal>
)
}