feat: 完成 P1 全部功能 + 修复 proxy 导出 + 切换 MySQL 端口至 14013
## P1 功能(20 项) - 站内消息系统、家长仪表盘、学生考勤管理 - Excel 导入导出、用户批量导入、成绩导出 - 排课规则+自动排课+课表调整 - 成绩趋势+对比分析、密码安全策略、速率限制 - 数据变更日志、文件预览+存储策略、全文检索 - 依赖审计集成 CI、数据库定时备份、E2E 测试完善 - 通知偏好管理 ## 基础设施修复 - src/proxy.ts: 将 middleware 导出重命名为 proxy(Next.js 16 要求) - .env: MySQL 端口从 13002 切换至 14013 - scripts/create-db.ts: 新增数据库初始化脚本 ## 架构文档同步 - 004_architecture_impact_map.md 和 005_architecture_data.json 完整记录所有新增表、模块、路由、权限、依赖关系
This commit is contained in:
94
src/modules/scheduling/components/auto-schedule-result.tsx
Normal file
94
src/modules/scheduling/components/auto-schedule-result.tsx
Normal file
@@ -0,0 +1,94 @@
|
||||
"use client"
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/shared/components/ui/card"
|
||||
import { Badge } from "@/shared/components/ui/badge"
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/shared/components/ui/table"
|
||||
import { AlertTriangle, CheckCircle2 } from "lucide-react"
|
||||
|
||||
import type { AutoScheduleResult } from "../types"
|
||||
|
||||
const WEEKDAY_LABELS = ["", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
|
||||
|
||||
export function AutoScheduleResultView({ result }: { result: AutoScheduleResult }) {
|
||||
const sortedSchedules = [...result.schedules].sort(
|
||||
(a, b) => a.weekday - b.weekday || a.startTime.localeCompare(b.startTime)
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center justify-between">
|
||||
<span>Generated Schedule</span>
|
||||
<div className="flex items-center gap-2 text-sm font-normal">
|
||||
<Badge variant="secondary">{result.scheduledCount} sessions</Badge>
|
||||
<Badge variant={result.conflictCount > 0 ? "destructive" : "default"}>
|
||||
{result.conflictCount} conflicts
|
||||
</Badge>
|
||||
</div>
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{sortedSchedules.length === 0 ? (
|
||||
<p className="text-muted-foreground text-sm">No sessions generated.</p>
|
||||
) : (
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Day</TableHead>
|
||||
<TableHead>Start</TableHead>
|
||||
<TableHead>End</TableHead>
|
||||
<TableHead>Course</TableHead>
|
||||
<TableHead>Location</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{sortedSchedules.map((s, idx) => (
|
||||
<TableRow key={`${s.weekday}-${s.startTime}-${idx}`}>
|
||||
<TableCell>{WEEKDAY_LABELS[s.weekday] ?? `Day ${s.weekday}`}</TableCell>
|
||||
<TableCell>{s.startTime}</TableCell>
|
||||
<TableCell>{s.endTime}</TableCell>
|
||||
<TableCell className="font-medium">{s.course}</TableCell>
|
||||
<TableCell>{s.location ?? "-"}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{result.conflicts.length > 0 && (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<AlertTriangle className="text-destructive h-5 w-5" />
|
||||
<span>Conflicts & Warnings</span>
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm">
|
||||
{result.conflicts.map((c, idx) => (
|
||||
<li key={idx} className="text-muted-foreground">
|
||||
<Badge variant="outline" className="mr-2">
|
||||
{c.type}
|
||||
</Badge>
|
||||
{c.description}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{result.conflicts.length === 0 && result.scheduledCount > 0 && (
|
||||
<Card>
|
||||
<CardContent className="flex items-center gap-2 py-4 text-sm">
|
||||
<CheckCircle2 className="text-primary h-5 w-5" />
|
||||
<span>No conflicts detected. The schedule is ready to apply.</span>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user