初始提交:全国记者站管理系统

This commit is contained in:
selfrelease
2026-08-01 23:09:49 +08:00
commit 45fbba0308
96 changed files with 21514 additions and 0 deletions
+96
View File
@@ -0,0 +1,96 @@
import { useState } from 'react'
import { ShieldCheck, LogIn, Loader2 } from 'lucide-react'
import { useRole } from '../../context'
import { api } from '../../api'
/**
* 登录页面 — 支持工号/姓名登录,演示模式可切换角色
*/
export function LoginPage() {
const { login, setRole } = useRole()
const [code, setCode] = useState('')
const [loading, setLoading] = useState(false)
const [error, setError] = useState('')
const handleLogin = async (e: React.FormEvent) => {
e.preventDefault()
if (!code.trim()) { setError('请输入工号或姓名'); return }
setLoading(true)
setError('')
try {
const res = await api.auth.login(code.trim())
login(res.token, res.role, res.name, res.station)
} catch (err) {
setError(err instanceof Error ? err.message : '登录失败')
} finally {
setLoading(false)
}
}
const handleDemo = (role: 'headquarters' | 'station' | 'reporter') => {
const demoNames: Record<typeof role, { name: string; station: string | null }> = {
headquarters: { name: '林致远', station: null },
station: { name: '苏明远', station: '北京记者站' },
reporter: { name: '林晓', station: '北京记者站' },
}
const demo = demoNames[role]
localStorage.setItem('auth_role', role)
localStorage.setItem('auth_name', demo.name)
localStorage.setItem('auth_station', String(demo.station))
setRole(role)
}
return (
<div className="login-page">
<div className="login-card">
<div className="login-header">
<div className="login-logo">
<ShieldCheck size={32} />
</div>
<h1></h1>
<p></p>
</div>
<form onSubmit={handleLogin} className="login-form">
<div className="form-field">
<label htmlFor="code"> / </label>
<input
id="code"
type="text"
value={code}
onChange={e => setCode(e.target.value)}
placeholder="如:PERSON_001 或 林晓"
disabled={loading}
autoFocus
/>
</div>
{error && <div className="login-error">{error}</div>}
<button type="submit" className="login-btn" disabled={loading}>
{loading ? <Loader2 size={18} className="spin" /> : <LogIn size={18} />}
<span>{loading ? '登录中...' : '登 录'}</span>
</button>
</form>
<div className="login-divider">
<span>使</span>
</div>
<div className="demo-buttons">
<button onClick={() => handleDemo('reporter')} className="demo-btn">
</button>
<button onClick={() => handleDemo('station')} className="demo-btn">
</button>
<button onClick={() => handleDemo('headquarters')} className="demo-btn">
</button>
</div>
<div className="login-hint">
<p>PERSON_001PERSON_006PERSON_007</p>
</div>
</div>
</div>
)
}