feat: initial frontend - React + TypeScript + Vite

- Login page with JWT auth
- Dashboard with stats and charts
- Issues list with pagination, filtering
- Issue detail with comments, status transitions
- Create issue form
- Dark theme UI
- Docker (nginx) with API proxy to backend
- Sidebar navigation
This commit is contained in:
Zhi
2026-02-27 09:47:19 +00:00
parent 32557f1de2
commit 853594f447
20 changed files with 831 additions and 0 deletions

54
src/pages/LoginPage.tsx Normal file
View File

@@ -0,0 +1,54 @@
import React, { useState } from 'react'
interface Props {
onLogin: (username: string, password: string) => Promise<void>
}
export default function LoginPage({ onLogin }: Props) {
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
const [error, setError] = useState('')
const [loading, setLoading] = useState(false)
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setError('')
setLoading(true)
try {
await onLogin(username, password)
} catch {
setError('登录失败,请检查用户名和密码')
} finally {
setLoading(false)
}
}
return (
<div className="login-page">
<div className="login-card">
<h1> HarborForge</h1>
<p className="subtitle">Agent/</p>
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="用户名"
value={username}
onChange={(e) => setUsername(e.target.value)}
required
/>
<input
type="password"
placeholder="密码"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
{error && <p className="error">{error}</p>}
<button type="submit" disabled={loading}>
{loading ? '登录中...' : '登录'}
</button>
</form>
</div>
</div>
)
}