Add assignment regrade update flow

这个提交包含在:
cryptocommuniums-afk
2026-02-01 11:42:48 +08:00
父节点 7a7e0a0d7f
当前提交 5a1a9a82ca
修改 4 个文件,包含 244 行新增8 行删除

查看文件

@@ -40,6 +40,7 @@ export default function HomePage() {
const [assignments, setAssignments] = useState<AssignmentSummary[]>([]);
const [selectedId, setSelectedId] = useState<number | null>(null);
const [selected, setSelected] = useState<AssignmentDetail | null>(null);
const [editingId, setEditingId] = useState<number | null>(null);
const [title, setTitle] = useState("");
const [images, setImages] = useState<ImageItem[]>([]);
@@ -255,6 +256,23 @@ export default function HomePage() {
);
};
const beginEdit = async (item: AssignmentSummary) => {
setError("");
clearImages();
setTitle(item.title);
setEditingId(item.id);
setSelectedId(item.id);
setInfo("已进入重新修改模式,请上传新的作业图片。");
await loadAssignmentDetail(item.id);
};
const cancelEdit = () => {
setEditingId(null);
setTitle("");
clearImages();
setInfo("");
};
const startCamera = async () => {
setError("");
try {
@@ -308,6 +326,7 @@ export default function HomePage() {
setIsSubmitting(true);
setInfo("正在提交图片并调用 LLM 批改,请稍候...");
try {
const isEditing = editingId !== null;
const formData = new FormData();
formData.append("username", savedUser);
if (title.trim()) {
@@ -319,8 +338,11 @@ export default function HomePage() {
formData.append("images", blob, name);
});
const res = await fetch(`${apiBase}/assignments`, {
method: "POST",
const endpoint = isEditing
? `${apiBase}/assignments/${editingId}`
: `${apiBase}/assignments`;
const res = await fetch(endpoint, {
method: isEditing ? "PUT" : "POST",
body: formData,
});
if (!res.ok) {
@@ -328,12 +350,19 @@ export default function HomePage() {
throw new Error(payload.error || "提交失败");
}
const created = (await res.json()) as AssignmentDetail;
setAssignments((prev) => [created, ...prev]);
if (isEditing) {
setAssignments((prev) =>
prev.map((item) => (item.id === created.id ? { ...item, ...created } : item))
);
} else {
setAssignments((prev) => [created, ...prev]);
}
setSelectedId(created.id);
setSelected(created);
setTitle("");
clearImages();
setInfo("批改完成,可在右侧查看结果。");
setEditingId(null);
setInfo(isEditing ? "修改完成,已重新批改。" : "批改完成,可在右侧查看结果。");
} catch (err) {
setError(err instanceof Error ? err.message : "提交失败");
} finally {
@@ -354,6 +383,9 @@ export default function HomePage() {
setSelectedId(null);
setSelected(null);
}
if (editingId === id) {
cancelEdit();
}
} catch (err) {
setError(err instanceof Error ? err.message : "删除失败");
}
@@ -414,6 +446,18 @@ export default function HomePage() {
<span className="tag">IMAGE + LLM</span>
</header>
<div className="upload-area">
{editingId && (
<div className="edit-banner">
<div>
<strong></strong>
{selected?.title || title || `作业 #${editingId}`}
<div className="muted"></div>
</div>
<button className="button ghost" onClick={cancelEdit}>
</button>
</div>
)}
<label className="muted"></label>
<input
className="input"
@@ -486,7 +530,7 @@ export default function HomePage() {
onClick={handleSubmit}
disabled={isSubmitting}
>
{isSubmitting ? "批改中..." : "提交批改"}
{isSubmitting ? "批改中..." : editingId ? "重新提交批改" : "提交批改"}
</button>
{error && <div className="feedback">{error}</div>}
@@ -530,6 +574,15 @@ export default function HomePage() {
{imageCountFor(item) > 1 ? ` (${imageCountFor(item)}张)` : ""}
</a>
)}
<button
className="button secondary"
onClick={(event) => {
event.stopPropagation();
void beginEdit(item);
}}
>
</button>
<button
className="button ghost"
onClick={(event) => {