Add assignment regrade update flow
这个提交包含在:
@@ -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) => {
|
||||
|
||||
在新工单中引用
屏蔽一个用户