Spaces:
Sleeping
Sleeping
Upload 44 files
Browse files- index.html +6 -8
- package.json +2 -1
- pages/ScoreList.tsx +14 -6
- pages/StudentList.tsx +12 -7
index.html
CHANGED
|
@@ -4,9 +4,6 @@
|
|
| 4 |
<meta charset="utf-8" />
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
| 6 |
<title>智慧校园管理系统</title>
|
| 7 |
-
<!-- 移除 Tailwind Play CDN (严重拖慢速度) -->
|
| 8 |
-
<!-- 优化 XLSX 加载:使用 defer 不阻塞渲染 -->
|
| 9 |
-
<script defer src="https://cdn.sheetjs.com/xlsx-0.20.1/package/dist/xlsx.full.min.js"></script>
|
| 10 |
<style>
|
| 11 |
/* Critical CSS for immediate loading state */
|
| 12 |
body { margin: 0; background-color: #f9fafb; font-family: sans-serif; }
|
|
@@ -26,14 +23,15 @@
|
|
| 26 |
<script type="importmap">
|
| 27 |
{
|
| 28 |
"imports": {
|
| 29 |
-
"
|
| 30 |
-
"@vitejs/plugin-react": "https://aistudiocdn.com/@vitejs/plugin-react@^5.1.1",
|
| 31 |
-
"vite": "https://aistudiocdn.com/vite@^7.2.6",
|
| 32 |
"react-dom/": "https://aistudiocdn.com/react-dom@^19.2.0/",
|
| 33 |
"react/": "https://aistudiocdn.com/react@^19.2.0/",
|
| 34 |
-
"react": "https://aistudiocdn.com/react@^
|
| 35 |
"recharts": "https://aistudiocdn.com/recharts@^3.5.1",
|
| 36 |
-
"
|
|
|
|
|
|
|
|
|
|
| 37 |
}
|
| 38 |
}
|
| 39 |
</script>
|
|
|
|
| 4 |
<meta charset="utf-8" />
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
| 6 |
<title>智慧校园管理系统</title>
|
|
|
|
|
|
|
|
|
|
| 7 |
<style>
|
| 8 |
/* Critical CSS for immediate loading state */
|
| 9 |
body { margin: 0; background-color: #f9fafb; font-family: sans-serif; }
|
|
|
|
| 23 |
<script type="importmap">
|
| 24 |
{
|
| 25 |
"imports": {
|
| 26 |
+
"react": "https://aistudiocdn.com/react@^19.2.0",
|
|
|
|
|
|
|
| 27 |
"react-dom/": "https://aistudiocdn.com/react-dom@^19.2.0/",
|
| 28 |
"react/": "https://aistudiocdn.com/react@^19.2.0/",
|
| 29 |
+
"lucide-react": "https://aistudiocdn.com/lucide-react@^0.555.0",
|
| 30 |
"recharts": "https://aistudiocdn.com/recharts@^3.5.1",
|
| 31 |
+
"vite": "https://aistudiocdn.com/vite@^7.2.6",
|
| 32 |
+
"@vitejs/plugin-react": "https://aistudiocdn.com/@vitejs/plugin-react@^5.1.1",
|
| 33 |
+
"react-dom": "https://aistudiocdn.com/react-dom@^19.2.0",
|
| 34 |
+
"xlsx": "https://aistudiocdn.com/xlsx@^0.18.5"
|
| 35 |
}
|
| 36 |
}
|
| 37 |
</script>
|
package.json
CHANGED
|
@@ -17,7 +17,8 @@
|
|
| 17 |
"react-dom": "^18.2.0",
|
| 18 |
"lucide-react": "^0.294.0",
|
| 19 |
"recharts": "^2.10.3",
|
| 20 |
-
"compression": "^1.7.4"
|
|
|
|
| 21 |
},
|
| 22 |
"devDependencies": {
|
| 23 |
"@types/react": "^18.2.43",
|
|
|
|
| 17 |
"react-dom": "^18.2.0",
|
| 18 |
"lucide-react": "^0.294.0",
|
| 19 |
"recharts": "^2.10.3",
|
| 20 |
+
"compression": "^1.7.4",
|
| 21 |
+
"xlsx": "^0.18.5"
|
| 22 |
},
|
| 23 |
"devDependencies": {
|
| 24 |
"@types/react": "^18.2.43",
|
pages/ScoreList.tsx
CHANGED
|
@@ -147,16 +147,24 @@ export const ScoreList: React.FC = () => {
|
|
| 147 |
|
| 148 |
const handleExcelImport = async () => {
|
| 149 |
if (!importFile) return alert('请选择文件');
|
| 150 |
-
// @ts-ignore
|
| 151 |
-
if (!window.XLSX) return alert('Excel 组件未加载');
|
| 152 |
setSubmitting(true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 153 |
const reader = new FileReader();
|
| 154 |
reader.onload = async (e) => {
|
| 155 |
try {
|
| 156 |
-
|
| 157 |
-
const workbook =
|
| 158 |
-
|
| 159 |
-
const jsonData =
|
|
|
|
| 160 |
const headers = Object.keys(jsonData[0] || {}).map(h => h.trim());
|
| 161 |
const matchedSubjects = subjects.filter(s => headers.includes(s.name));
|
| 162 |
if (matchedSubjects.length === 0) { alert('未找到学科'); setSubmitting(false); return; }
|
|
|
|
| 147 |
|
| 148 |
const handleExcelImport = async () => {
|
| 149 |
if (!importFile) return alert('请选择文件');
|
|
|
|
|
|
|
| 150 |
setSubmitting(true);
|
| 151 |
+
|
| 152 |
+
let XLSX: any;
|
| 153 |
+
try {
|
| 154 |
+
XLSX = await import('xlsx');
|
| 155 |
+
} catch (e) {
|
| 156 |
+
setSubmitting(false);
|
| 157 |
+
return alert('加载 Excel 解析组件失败,请检查网络');
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
const reader = new FileReader();
|
| 161 |
reader.onload = async (e) => {
|
| 162 |
try {
|
| 163 |
+
const data = e.target?.result;
|
| 164 |
+
const workbook = XLSX.read(data, { type: 'array' });
|
| 165 |
+
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
|
| 166 |
+
const jsonData = XLSX.utils.sheet_to_json(worksheet);
|
| 167 |
+
|
| 168 |
const headers = Object.keys(jsonData[0] || {}).map(h => h.trim());
|
| 169 |
const matchedSubjects = subjects.filter(s => headers.includes(s.name));
|
| 170 |
if (matchedSubjects.length === 0) { alert('未找到学科'); setSubmitting(false); return; }
|
pages/StudentList.tsx
CHANGED
|
@@ -180,21 +180,26 @@ export const StudentList: React.FC = () => {
|
|
| 180 |
|
| 181 |
const handleExcelImport = async () => {
|
| 182 |
if (!importFile) return alert('请选择文件');
|
| 183 |
-
|
| 184 |
-
if (!window.XLSX) return alert('Excel 解析组件未加载,请刷新页面重试');
|
| 185 |
-
|
| 186 |
setSubmitting(true);
|
| 187 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 188 |
const reader = new FileReader();
|
| 189 |
reader.onload = async (e) => {
|
| 190 |
try {
|
| 191 |
const data = e.target?.result;
|
| 192 |
-
|
| 193 |
-
const workbook = window.XLSX.read(data, { type: 'array' });
|
| 194 |
const firstSheetName = workbook.SheetNames[0];
|
| 195 |
const worksheet = workbook.Sheets[firstSheetName];
|
| 196 |
-
|
| 197 |
-
const rawRows: any[][] = window.XLSX.utils.sheet_to_json(worksheet, { header: 1 });
|
| 198 |
|
| 199 |
if (rawRows.length < 1) return alert('文件为空');
|
| 200 |
|
|
|
|
| 180 |
|
| 181 |
const handleExcelImport = async () => {
|
| 182 |
if (!importFile) return alert('请选择文件');
|
| 183 |
+
|
|
|
|
|
|
|
| 184 |
setSubmitting(true);
|
| 185 |
|
| 186 |
+
// Dynamic import to avoid loading XLSX on initial page load
|
| 187 |
+
let XLSX: any;
|
| 188 |
+
try {
|
| 189 |
+
XLSX = await import('xlsx');
|
| 190 |
+
} catch (e) {
|
| 191 |
+
setSubmitting(false);
|
| 192 |
+
return alert('加载 Excel 解析组件失败,请检查网络');
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
const reader = new FileReader();
|
| 196 |
reader.onload = async (e) => {
|
| 197 |
try {
|
| 198 |
const data = e.target?.result;
|
| 199 |
+
const workbook = XLSX.read(data, { type: 'array' });
|
|
|
|
| 200 |
const firstSheetName = workbook.SheetNames[0];
|
| 201 |
const worksheet = workbook.Sheets[firstSheetName];
|
| 202 |
+
const rawRows: any[][] = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
|
|
|
|
| 203 |
|
| 204 |
if (rawRows.length < 1) return alert('文件为空');
|
| 205 |
|