新增后台接口
Change-Id: Ibd8183079a77aad05b2c81658c2d6fe9b648e042
diff --git a/front/src/AppealPage.js b/front/src/AppealPage.js
index a0314c4..dfbe307 100644
--- a/front/src/AppealPage.js
+++ b/front/src/AppealPage.js
@@ -1,50 +1,68 @@
-import React, { useState } from "react";
+import React, { useState, useEffect } from "react";
+import { API_BASE_URL } from "./config";
-// 示例申诉数据
-const appeals = [
- {
- appeal_id: "a001",
- user_id: "u001",
- content: "我没有作弊,请审核我的账号。",
- file_url: "http://sse.bjtu.edu.cn/media/attachments/2024/10/20241012160658.pdf",
- status: 0,
- },
- {
- appeal_id: "a002",
- user_id: "u002",
- content: "误封申诉,详见附件。",
- file_url: "http://sse.bjtu.edu.cn/media/attachments/2024/10/20241012160658.pdf",
- status: 1,
- },
-];
-
-// 简单PDF预览组件
-function FileViewer({ url }) {
- if (!url) return <div>无附件</div>;
- if (url.endsWith(".pdf")) {
- return (
- <iframe
- src={url}
- title="PDF预览"
- width="100%"
- height="400px"
- style={{ border: "1px solid #ccc", borderRadius: 8 }}
- />
- );
- }
- // 这里只做PDF示例,实际可扩展为DOC等
- return <a href={url} target="_blank" rel="noopener noreferrer">下载附件</a>;
-}
-
+// State for appeals fetched from backend
export default function AppealPage() {
- const [selectedId, setSelectedId] = useState(appeals[0].appeal_id);
- const selectedAppeal = appeals.find(a => a.appeal_id === selectedId);
+ const [appeals, setAppeals] = useState([]);
+ const [selectedId, setSelectedId] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
- const handleApprove = () => {
- alert("已通过申诉(示例,无实际状态变更)");
+ // Helper to load appeals
+ const fetchAppeals = async () => {
+ setLoading(true);
+ try {
+ const res = await fetch(`${API_BASE_URL}/api/appeals`);
+ if (!res.ok) throw new Error(`请求失败,状态码 ${res.status}`);
+ const data = await res.json();
+ // console.log("Fetched appeals:", data);
+ setAppeals(data);
+ if (data.length > 0) setSelectedId(data[0].appealid);
+ setError(null);
+ } catch (err) {
+ setError(err.message);
+ } finally {
+ setLoading(false);
+ }
};
- const handleReject = () => {
- alert("已拒绝申诉(示例,无实际状态变更)");
+
+ useEffect(() => {
+ fetchAppeals();
+ }, []);
+
+ if (loading) return <div>加载中...</div>;
+ if (error) return <div>加载失败:{error}</div>;
+ const selectedAppeal = appeals.find(a => a.appealid === selectedId) || {};
+
+ // Approve selected appeal and refresh
+ const handleApprove = async () => {
+ try {
+ const res = await fetch(`${API_BASE_URL}/api/appeals-approve`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ appealid: selectedAppeal.appealid })
+ });
+ if (!res.ok) throw new Error(`请求失败,状态码 ${res.status}`);
+ alert("已通过申诉");
+ await fetchAppeals();
+ } catch (err) {
+ alert(`操作失败:${err.message}`);
+ }
+ };
+ // Reject selected appeal and refresh
+ const handleReject = async () => {
+ try {
+ const res = await fetch(`${API_BASE_URL}/api/appeals-reject`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ appealid: selectedAppeal.appealid })
+ });
+ if (!res.ok) throw new Error(`请求失败,状态码 ${res.status}`);
+ alert("已拒绝申诉");
+ await fetchAppeals();
+ } catch (err) {
+ alert(`操作失败:${err.message}`);
+ }
};
return (
@@ -55,28 +73,28 @@
<div style={{ display: "flex", flexDirection: "column", gap: 12, marginTop: 18 }}>
{appeals.map(a => (
<div
- key={a.appeal_id}
- onClick={() => setSelectedId(a.appeal_id)}
+ key={a.appealid}
+ onClick={() => setSelectedId(a.appealid)}
style={{
margin: "0 12px",
padding: "16px 10px",
borderRadius: 8,
- background: selectedId === a.appeal_id ? "#e3f2fd" : "#fff",
- border: `2px solid ${a.status === 1 ? "#43a047" : "#e53935"}`,
- color: a.status === 1 ? "#43a047" : "#e53935",
+ background: selectedId === a.appealid ? "#e3f2fd" : "#fff",
+ border: `2px solid ${a.status === 1 || a.status === 2 ? "#43a047" : "#e53935"}`,
+ color: a.status === 1 || a.status === 2 ? "#43a047" : "#e53935",
fontWeight: 600,
cursor: "pointer",
- boxShadow: selectedId === a.appeal_id ? "0 2px 8px #b2d8ea" : "none",
+ boxShadow: selectedId === a.appealid ? "0 2px 8px #b2d8ea" : "none",
transition: "all 0.2s"
}}
>
- {a.appeal_id}
+ {a.user.username}
<span style={{
float: "right",
fontSize: 12,
- color: a.status === 1 ? "#43a047" : "#e53935"
+ color: a.status === 1 || a.status === 2 ? "#43a047" : "#e53935"
}}>
- {a.status === 1 ? "已审核" : "未审核"}
+ {a.status === 1 || a.status === 2 ? "已审核" : "未审核"}
</span>
</div>
))}
@@ -87,17 +105,17 @@
<h2 style={{ marginBottom: 24, color: "#1976d2" }}>申诉详情</h2>
<div style={{ background: "#fff", borderRadius: 12, padding: 32, boxShadow: "0 2px 8px #e0e7ff", marginBottom: 32 }}>
<div style={{ marginBottom: 18 }}>
- <b>申诉ID:</b>{selectedAppeal.appeal_id}
+ <b>申诉ID:</b>{selectedAppeal.appealid}
</div>
<div style={{ marginBottom: 18 }}>
- <b>用户ID:</b>{selectedAppeal.user_id}
+ <b>用户ID:</b>{selectedAppeal.user.userid}
</div>
<div style={{ marginBottom: 18 }}>
<b>申诉内容:</b>{selectedAppeal.content}
</div>
<div style={{ marginBottom: 18 }}>
<b>申诉文件:</b>
- <FileViewer url={selectedAppeal.file_url} />
+ <FileViewer url={selectedAppeal.fileURL} />
</div>
</div>
{/* 审核按钮 */}
@@ -138,4 +156,22 @@
</div>
</div>
);
+}
+
+// 简单PDF预览组件
+function FileViewer({ url }) {
+ if (!url) return <div>无附件</div>;
+ if (url.endsWith(".pdf")) {
+ return (
+ <iframe
+ src={url}
+ title="PDF预览"
+ width="100%"
+ height="400px"
+ style={{ border: "1px solid #ccc", borderRadius: 8 }}
+ />
+ );
+ }
+ // 这里只做PDF示例,实际可扩展为DOC等
+ return <a href={url} target="_blank" rel="noopener noreferrer">下载附件</a>;
}
\ No newline at end of file