blob: 1a9f79bff30291cde3e325040bd249d6c2427cd0 [file] [log] [blame]
223011339e292152025-06-08 00:34:37 +08001import React, { useState, useEffect } from "react";
2import { API_BASE_URL } from "./config";
whtb1e79592025-06-07 16:03:09 +08003
4// 简单PDF预览组件
5function FileViewer({ url }) {
6 if (!url) return <div>无附件</div>;
7 if (url.endsWith(".pdf")) {
8 return (
9 <iframe
10 src={url}
11 title="PDF预览"
12 width="100%"
13 height="400px"
14 style={{ border: "1px solid #ccc", borderRadius: 8 }}
15 />
16 );
17 }
18 // 这里只做PDF示例,实际可扩展为DOC等
19 return <a href={url} target="_blank" rel="noopener noreferrer">下载附件</a>;
20}
21
22export default function MigrationPage() {
223011339e292152025-06-08 00:34:37 +080023 const [migrations, setMigrations] = useState([]);
24 const [selectedId, setSelectedId] = useState(null);
25 const [loading, setLoading] = useState(true);
26 const [error, setError] = useState(null);
whtb1e79592025-06-07 16:03:09 +080027
223011339e292152025-06-08 00:34:37 +080028 // Helper to load migrations list
29 const fetchMigrations = async () => {
30 setLoading(true);
31 try {
32 const res = await fetch(`${API_BASE_URL}/api/migrations`);
33 if (!res.ok) throw new Error(`请求失败,状态码 ${res.status}`);
34 const data = await res.json();
wht2bf8f802025-06-08 15:52:18 +080035 console.log("Fetched migrations:", data);
223011339e292152025-06-08 00:34:37 +080036 const formatted = data.map(item => ({
37 migration_id: item.profileurl,
38 user_id: item.user.userid,
39 application_url: item.applicationurl,
40 pending_magic: Number(item.magictogive),
41 granted_magic: Number(item.magicgived),
42 pending_uploaded: Number(item.uploadtogive),
43 granted_uploaded: Number(item.uploadgived),
44 approved: item.exampass ? 1 : 0
45 }));
46 setMigrations(formatted);
47 if (formatted.length > 0) setSelectedId(formatted[0].migration_id);
48 setError(null);
49 } catch (err) {
50 setError(err.message);
51 } finally {
52 setLoading(false);
53 }
whtb1e79592025-06-07 16:03:09 +080054 };
223011339e292152025-06-08 00:34:37 +080055
56 useEffect(() => {
57 fetchMigrations();
58 }, []);
59
60 if (loading) return <div>加载中...</div>;
61 if (error) return <div>加载失败:{error}</div>;
62
63 const selectedMigration = migrations.find(m => m.migration_id === selectedId) || {};
64
65 // Approve selected migration and refresh
66 const handleApprove = async () => {
67 try {
68 const res = await fetch(`${API_BASE_URL}/api/migrations-approve`, {
69 method: "POST",
70 headers: { "Content-Type": "application/json" },
71 body: JSON.stringify({ migration_id: selectedMigration.migration_id })
72 });
73 if (!res.ok) throw new Error(`请求失败,状态码 ${res.status}`);
74 alert("已通过迁移");
75 await fetchMigrations();
76 } catch (err) {
77 alert(`操作失败:${err.message}`);
78 }
79 };
80 // Reject selected migration and refresh
81 const handleReject = async () => {
82 try {
83 const res = await fetch(`${API_BASE_URL}/api/migrations-reject`, {
84 method: "POST",
85 headers: { "Content-Type": "application/json" },
86 body: JSON.stringify({ migration_id: selectedMigration.migration_id })
87 });
88 if (!res.ok) throw new Error(`请求失败,状态码 ${res.status}`);
89 alert("已拒绝迁移");
90 await fetchMigrations();
91 } catch (err) {
92 alert(`操作失败:${err.message}`);
93 }
whtb1e79592025-06-07 16:03:09 +080094 };
95
96 return (
97 <div style={{ display: "flex", minHeight: "100vh", background: "#f7faff" }}>
98 {/* 侧栏 */}
99 <div style={{ width: 180, background: "#fff", borderRight: "1px solid #e0e7ff", padding: 0 }}>
100 <h3 style={{ textAlign: "center", padding: "18px 0 0 0", color: "#1976d2" }}>迁移列表</h3>
101 <div style={{ display: "flex", flexDirection: "column", gap: 12, marginTop: 18 }}>
102 {migrations.map(m => (
103 <div
104 key={m.migration_id}
105 onClick={() => setSelectedId(m.migration_id)}
106 style={{
107 margin: "0 12px",
108 padding: "16px 10px",
109 borderRadius: 8,
110 background: selectedId === m.migration_id ? "#e3f2fd" : "#fff",
111 border: `2px solid ${m.approved === 1 ? "#43a047" : "#e53935"}`,
112 color: m.approved === 1 ? "#43a047" : "#e53935",
113 fontWeight: 600,
114 cursor: "pointer",
115 boxShadow: selectedId === m.migration_id ? "0 2px 8px #b2d8ea" : "none",
116 transition: "all 0.2s"
117 }}
118 >
119 {m.migration_id}
120 <span style={{
121 float: "right",
122 fontSize: 12,
123 color: m.approved === 1 ? "#43a047" : "#e53935"
124 }}>
125 {m.approved === 1 ? "已审核" : "未审核"}
126 </span>
127 </div>
128 ))}
129 </div>
130 </div>
131 {/* 迁移详情 */}
132 <div style={{ flex: 1, padding: "40px 48px" }}>
133 <h2 style={{ marginBottom: 24, color: "#1976d2" }}>迁移详情</h2>
134 <div style={{ background: "#fff", borderRadius: 12, padding: 32, boxShadow: "0 2px 8px #e0e7ff", marginBottom: 32 }}>
135 <div style={{ marginBottom: 18 }}>
136 <b>迁移ID:</b>{selectedMigration.migration_id}
137 </div>
138 <div style={{ marginBottom: 18 }}>
139 <b>用户ID:</b>{selectedMigration.user_id}
140 </div>
141 <div style={{ marginBottom: 18 }}>
142 <b>申请文件:</b>
143 <FileViewer url={selectedMigration.application_url} />
144 </div>
145 <div style={{ marginBottom: 18 }}>
146 <b>待迁移魔法值:</b>{selectedMigration.pending_magic},
147 <b>已迁移魔法值:</b>{selectedMigration.granted_magic}
148 </div>
149 <div style={{ marginBottom: 18 }}>
150 <b>待迁移上传量:</b>{selectedMigration.pending_uploaded},
151 <b>已迁移上传量:</b>{selectedMigration.granted_uploaded}
152 </div>
153 </div>
154 {/* 审核按钮 */}
155 <div style={{ display: "flex", gap: 32, justifyContent: "center" }}>
156 <button
157 style={{
158 background: selectedMigration.approved === 1 ? "#bdbdbd" : "#43a047",
159 color: "#fff",
160 border: "none",
161 borderRadius: 8,
162 padding: "10px 38px",
163 fontWeight: 600,
164 fontSize: 18,
165 cursor: selectedMigration.approved === 1 ? "not-allowed" : "pointer"
166 }}
167 disabled={selectedMigration.approved === 1}
168 onClick={handleApprove}
169 >
170 通过
171 </button>
172 <button
173 style={{
174 background: selectedMigration.approved === 1 ? "#bdbdbd" : "#e53935",
175 color: "#fff",
176 border: "none",
177 borderRadius: 8,
178 padding: "10px 38px",
179 fontWeight: 600,
180 fontSize: 18,
181 cursor: selectedMigration.approved === 1 ? "not-allowed" : "pointer"
182 }}
183 disabled={selectedMigration.approved === 1}
184 onClick={handleReject}
185 >
186 不通过
187 </button>
188 </div>
189 </div>
190 </div>
191 );
192}