- 登录弹窗与系统改密统一用 @stash/ui 的 PasswordInput(改密页补上显隐切换) - 删除分类不再用 window.confirm,改用 Modal + 危险按钮(组件库推荐的组合) - 删除页面私有的 PasswordInput 组件与 .password-field 样式
118 lines
3.3 KiB
TypeScript
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>
|
|
)
|
|
}
|