init: AI培训与智能巡检系统
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Link, useParams } from 'react-router-dom';
|
||||
import { api } from '../api/client';
|
||||
import { useAuth } from '../lib/auth';
|
||||
import { Button } from '../components/ui';
|
||||
import { IconBack } from '../components/icons';
|
||||
import type { Thread } from '../types';
|
||||
|
||||
export function ThreadPage() {
|
||||
const { id } = useParams();
|
||||
const { user } = useAuth();
|
||||
const [thread, setThread] = useState<Thread | null>(null);
|
||||
const [body, setBody] = useState('');
|
||||
const [error, setError] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
if (id) api.thread(Number(id)).then(setThread).catch((e) => setError(String(e)));
|
||||
}, [id]);
|
||||
|
||||
const reply = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (!id) return;
|
||||
setError('');
|
||||
try {
|
||||
const updated = await api.addReply(Number(id), body);
|
||||
setThread(updated);
|
||||
setBody('');
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : '回复失败');
|
||||
}
|
||||
};
|
||||
|
||||
if (error) return <p className="error">{error}</p>;
|
||||
if (!thread) return <p className="muted">加载中…</p>;
|
||||
|
||||
const fmt = (s: string) => new Date(s + 'Z').toLocaleString('zh-CN');
|
||||
|
||||
return (
|
||||
<div className="page thread-page">
|
||||
<Link to={thread.model_id ? `/models/${thread.model_id}` : '/community'} className="back">
|
||||
<IconBack size={14} /> 返回
|
||||
</Link>
|
||||
<h1>{thread.title}</h1>
|
||||
<div className="post op">
|
||||
<div className="post-head">
|
||||
<b>{thread.author_name}</b>
|
||||
<span className="muted">{fmt(thread.created_at)}</span>
|
||||
</div>
|
||||
<p className="post-body">{thread.body}</p>
|
||||
</div>
|
||||
|
||||
<h2>{thread.reply_count} 条回复</h2>
|
||||
<div className="replies">
|
||||
{thread.replies?.map((r) => (
|
||||
<div className="post" key={r.id}>
|
||||
<div className="post-head">
|
||||
<b>{r.author_name}</b>
|
||||
<span className="muted">{fmt(r.created_at)}</span>
|
||||
</div>
|
||||
<p className="post-body">{r.body}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{user ? (
|
||||
<form className="reply-form" onSubmit={reply}>
|
||||
<textarea
|
||||
placeholder="写下你的回复…"
|
||||
value={body}
|
||||
onChange={(e) => setBody(e.target.value)}
|
||||
rows={3}
|
||||
required
|
||||
/>
|
||||
{error && <p className="error">{error}</p>}
|
||||
<Button variant="primary" type="submit">回复</Button>
|
||||
</form>
|
||||
) : (
|
||||
<p className="muted">登录后可参与讨论。</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user