fix(teacher): 统一详情页返回路径与中英文文案 (P1-3+P2-1)
P1-3: empty-state 默认按钮 variant 改为 outline 并新增 variant prop;button.tsx 导出 ButtonProps;统一 5 个详情页返回路径为 ghost+ArrowLeft+文字标签;course-plan-detail raw a 改为 Link。P2-1: formatLongDate 默认 locale 改为 zh-CN,weekday 改为 short;返回按钮文案中文化;course-plan-detail 全量中文化;grades/analytics 标题中文化。验证:tsc 0 错误,lint 0 错误,架构图 004/005 已同步。
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
import { useState } from "react"
|
||||
import { useRouter } from "next/navigation"
|
||||
import Link from "next/link"
|
||||
import { toast } from "sonner"
|
||||
import { ArrowLeft, Pencil, Plus, Trash2 } from "lucide-react"
|
||||
|
||||
@@ -16,16 +17,7 @@ import {
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/shared/components/ui/table"
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
} from "@/shared/components/ui/alert-dialog"
|
||||
import { ConfirmDeleteDialog } from "@/shared/components/ui/confirm-delete-dialog"
|
||||
import { usePermission } from "@/shared/hooks/use-permission"
|
||||
import { Permissions } from "@/shared/types/permissions"
|
||||
import { formatDate } from "@/shared/lib/utils"
|
||||
@@ -36,10 +28,10 @@ import { deleteCoursePlanAction } from "../actions"
|
||||
import type { CoursePlanWithItems, CoursePlanStatus } from "../types"
|
||||
|
||||
const STATUS_LABEL: Record<CoursePlanStatus, string> = {
|
||||
planning: "Planning",
|
||||
active: "Active",
|
||||
completed: "Completed",
|
||||
paused: "Paused",
|
||||
planning: "规划中",
|
||||
active: "进行中",
|
||||
completed: "已完成",
|
||||
paused: "已暂停",
|
||||
}
|
||||
|
||||
export function CoursePlanDetail({
|
||||
@@ -72,10 +64,10 @@ export function CoursePlanDetail({
|
||||
router.push(base)
|
||||
router.refresh()
|
||||
} else {
|
||||
toast.error(res.message || "Failed to delete")
|
||||
toast.error(res.message || "删除失败")
|
||||
}
|
||||
} catch {
|
||||
toast.error("Failed to delete")
|
||||
toast.error("删除失败")
|
||||
} finally {
|
||||
setIsWorking(false)
|
||||
setDeleteOpen(false)
|
||||
@@ -94,51 +86,52 @@ export function CoursePlanDetail({
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<div className="flex items-center gap-2">
|
||||
{backHref ? (
|
||||
<Button asChild variant="ghost" size="icon">
|
||||
<a href={backHref}>
|
||||
<ArrowLeft className="h-4 w-4" />
|
||||
</a>
|
||||
</Button>
|
||||
) : null}
|
||||
<h2 className="text-2xl font-bold tracking-tight">Course Plan</h2>
|
||||
</div>
|
||||
{canManage ? (
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
{editHref ? (
|
||||
<Button asChild variant="outline">
|
||||
<a href={editHref}>
|
||||
<Pencil className="mr-2 h-4 w-4" />
|
||||
Edit
|
||||
</a>
|
||||
</Button>
|
||||
) : null}
|
||||
<Button onClick={() => setDeleteOpen(true)} disabled={isWorking} variant="destructive">
|
||||
<Trash2 className="mr-2 h-4 w-4" />
|
||||
Delete
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-col gap-3">
|
||||
{backHref ? (
|
||||
<Button asChild variant="ghost" size="sm" className="w-fit">
|
||||
<Link href={backHref}>
|
||||
<ArrowLeft className="mr-2 h-4 w-4" aria-hidden="true" />
|
||||
返回课程计划列表
|
||||
</Link>
|
||||
</Button>
|
||||
) : null}
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<h2 className="text-2xl font-bold tracking-tight">课程计划</h2>
|
||||
{canManage ? (
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
{editHref ? (
|
||||
<Button asChild variant="outline">
|
||||
<Link href={editHref}>
|
||||
<Pencil className="mr-2 h-4 w-4" />
|
||||
编辑
|
||||
</Link>
|
||||
</Button>
|
||||
) : null}
|
||||
<Button onClick={() => setDeleteOpen(true)} disabled={isWorking} variant="destructive">
|
||||
<Trash2 className="mr-2 h-4 w-4" />
|
||||
删除
|
||||
</Button>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Card>
|
||||
<CardHeader className="space-y-2">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Badge variant="outline">{plan.className ?? "No class"}</Badge>
|
||||
<Badge variant="outline">{plan.subjectName ?? "Unknown subject"}</Badge>
|
||||
<Badge variant="outline">{plan.className ?? "无班级"}</Badge>
|
||||
<Badge variant="outline">{plan.subjectName ?? "未知学科"}</Badge>
|
||||
<Badge>{STATUS_LABEL[plan.status]}</Badge>
|
||||
<Badge variant="outline">Semester {plan.semester}</Badge>
|
||||
<Badge variant="outline">第 {plan.semester} 学期</Badge>
|
||||
</div>
|
||||
<CardTitle className="text-xl">
|
||||
{plan.subjectName ?? "Course Plan"} — {plan.className ?? "No Class"}
|
||||
{plan.subjectName ?? "课程计划"} — {plan.className ?? "无班级"}
|
||||
</CardTitle>
|
||||
<div className="flex flex-wrap items-center gap-2 text-xs text-muted-foreground">
|
||||
<span>Teacher: {plan.teacherName ?? "Unassigned"}</span>
|
||||
<span>· Created {formatDate(plan.createdAt)}</span>
|
||||
{plan.startDate ? <span>· Start {formatDate(plan.startDate)}</span> : null}
|
||||
{plan.endDate ? <span>· End {formatDate(plan.endDate)}</span> : null}
|
||||
<span>教师:{plan.teacherName ?? "未分配"}</span>
|
||||
<span>· 创建于 {formatDate(plan.createdAt)}</span>
|
||||
{plan.startDate ? <span>· 开始 {formatDate(plan.startDate)}</span> : null}
|
||||
{plan.endDate ? <span>· 结束 {formatDate(plan.endDate)}</span> : null}
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
@@ -150,13 +143,13 @@ export function CoursePlanDetail({
|
||||
/>
|
||||
{plan.syllabus ? (
|
||||
<div className="space-y-1">
|
||||
<h4 className="text-sm font-semibold">Syllabus</h4>
|
||||
<h4 className="text-sm font-semibold">教学大纲</h4>
|
||||
<p className="whitespace-pre-wrap text-sm text-muted-foreground">{plan.syllabus}</p>
|
||||
</div>
|
||||
) : null}
|
||||
{plan.objectives ? (
|
||||
<div className="space-y-1">
|
||||
<h4 className="text-sm font-semibold">Objectives</h4>
|
||||
<h4 className="text-sm font-semibold">教学目标</h4>
|
||||
<p className="whitespace-pre-wrap text-sm text-muted-foreground">{plan.objectives}</p>
|
||||
</div>
|
||||
) : null}
|
||||
@@ -165,28 +158,28 @@ export function CoursePlanDetail({
|
||||
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0">
|
||||
<CardTitle>Weekly Plan</CardTitle>
|
||||
<CardTitle>周计划</CardTitle>
|
||||
{canManage ? (
|
||||
<Button onClick={openCreateEditor} size="sm">
|
||||
<Plus className="mr-2 h-4 w-4" />
|
||||
Add Week
|
||||
添加周计划
|
||||
</Button>
|
||||
) : null}
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{plan.items.length === 0 ? (
|
||||
<p className="py-6 text-center text-sm text-muted-foreground">
|
||||
No weekly plans yet. {canManage ? "Click \"Add Week\" to create one." : ""}
|
||||
暂无周计划。{canManage ? "点击「添加周计划」创建第一条。" : ""}
|
||||
</p>
|
||||
) : (
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-16">Week</TableHead>
|
||||
<TableHead>Topic</TableHead>
|
||||
<TableHead className="w-20">Hours</TableHead>
|
||||
<TableHead className="w-32">Chapter</TableHead>
|
||||
<TableHead className="w-28">Status</TableHead>
|
||||
<TableHead className="w-16">周次</TableHead>
|
||||
<TableHead>主题</TableHead>
|
||||
<TableHead className="w-20">课时</TableHead>
|
||||
<TableHead className="w-32">章节</TableHead>
|
||||
<TableHead className="w-28">状态</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
@@ -207,7 +200,7 @@ export function CoursePlanDetail({
|
||||
) : null}
|
||||
{item.notes ? (
|
||||
<p className="text-xs text-muted-foreground italic">
|
||||
Note: {item.notes}
|
||||
备注:{item.notes}
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
@@ -218,7 +211,7 @@ export function CoursePlanDetail({
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Badge variant={item.isCompleted ? "default" : "secondary"}>
|
||||
{item.isCompleted ? "Done" : "Pending"}
|
||||
{item.isCompleted ? "已完成" : "待完成"}
|
||||
</Badge>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@@ -237,22 +230,14 @@ export function CoursePlanDetail({
|
||||
onOpenChange={setEditorOpen}
|
||||
/>
|
||||
|
||||
<AlertDialog open={deleteOpen} onOpenChange={setDeleteOpen}>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Delete course plan</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
This will permanently delete this course plan and all its weekly plans.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel disabled={isWorking}>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction onClick={handleDelete} disabled={isWorking}>
|
||||
Delete
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
<ConfirmDeleteDialog
|
||||
open={deleteOpen}
|
||||
onOpenChange={setDeleteOpen}
|
||||
title="删除课程计划"
|
||||
description="此操作将永久删除该课程计划及其所有周计划。"
|
||||
onConfirm={handleDelete}
|
||||
isWorking={isWorking}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user