refactor: 统一分页组件和UI优化

- 使用公共Pagination组件统一各页面的分页逻辑
- 优化exceptions页面异常列表展示
- 简化settings/rules页面规则管理
- 后端tasks.py增加分页参数支持
This commit is contained in:
freedakgmail
2026-07-07 13:53:54 +08:00
parent b93929eb1a
commit feebbb10ac
6 changed files with 101 additions and 92 deletions
+45 -43
View File
@@ -457,46 +457,40 @@ function ExceptionsContent() {
</TableCell>
</TableRow>
) : (
exceptions.map((exception, index) => (
<motion.div
key={exception.id}
initial={{ opacity: 0, y: 4 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.2, delay: index * 0.02 }}
>
<TableRow className="group">
<TableCell>
<Badge className={statusConfig[exception.status]?.color || "bg-gray-100 text-gray-700"}>
{statusConfig[exception.status]?.label || exception.status}
exceptions.map((exception) => (
<TableRow key={exception.id} className="group">
<TableCell>
<Badge className={statusConfig[exception.status]?.color || "bg-gray-100 text-gray-700"}>
{statusConfig[exception.status]?.label || exception.status}
</Badge>
</TableCell>
<TableCell>
<div>
<div className="font-medium">{exception.employee_name}</div>
<div className="text-xs text-muted-foreground">{exception.employee_id}</div>
</div>
</TableCell>
<TableCell>
<Badge variant="outline" className="font-normal">
{typeLabels[exception.exception_type] || typeLabels[exception.exception_type.toLowerCase()] || typeLabels[exception.exception_type.toUpperCase()] || exception.exception_type}
</Badge>
</TableCell>
<TableCell>
<div className="flex items-center gap-2">
<div className={`w-2 h-2 rounded-full ${severityConfig[exception.severity]?.icon || "bg-gray-500"}`} />
<Badge className={severityConfig[exception.severity]?.color || "bg-gray-100 text-gray-700"}>
{severityConfig[exception.severity]?.label || exception.severity}
</Badge>
</TableCell>
<TableCell>
<div>
<div className="font-medium">{exception.employee_name}</div>
<div className="text-xs text-muted-foreground">{exception.employee_id}</div>
</div>
</TableCell>
<TableCell>
<Badge variant="outline" className="font-normal">
{typeLabels[exception.exception_type] || typeLabels[exception.exception_type.toLowerCase()] || typeLabels[exception.exception_type.toUpperCase()] || exception.exception_type}
</Badge>
</TableCell>
<TableCell>
<div className="flex items-center gap-2">
<div className={`w-2 h-2 rounded-full ${severityConfig[exception.severity]?.icon || "bg-gray-500"}`} />
<Badge className={severityConfig[exception.severity]?.color || "bg-gray-100 text-gray-700"}>
{severityConfig[exception.severity]?.label || exception.severity}
</Badge>
</div>
</TableCell>
<TableCell className="max-w-[200px]">
<span className="truncate block">{exception.description}</span>
</TableCell>
<TableCell className="text-right">
{exception.difference_amount != null && (
<span className={exception.difference_amount > 0 ? "text-red-600" : "text-emerald-600"}>
{exception.difference_amount > 0 ? "+" : ""}
{exception.difference_amount.toFixed(2)}
</div>
</TableCell>
<TableCell className="max-w-[200px]">
<span className="truncate block">{exception.description}</span>
</TableCell>
<TableCell className="text-right">
{exception.difference_amount != null && (
<span className={exception.difference_amount > 0 ? "text-red-600" : "text-emerald-600"}>
{exception.difference_amount > 0 ? "+" : ""}
{exception.difference_amount.toFixed(2)}
</span>
)}
</TableCell>
@@ -518,9 +512,8 @@ function ExceptionsContent() {
</div>
</TableCell>
</TableRow>
</motion.div>
))
)}
))
)}
</TableBody>
</Table>
</CardContent>
@@ -608,7 +601,16 @@ function ExceptionsContent() {
<div>
<p className="text-caption text-muted-foreground mb-1"></p>
<pre className="text-xs bg-muted p-3 rounded-lg overflow-auto">
{JSON.stringify(JSON.parse(selectedException.detail), null, 2)}
{(() => {
try {
const detail = typeof selectedException.detail === 'string'
? JSON.parse(selectedException.detail)
: selectedException.detail;
return JSON.stringify(detail, null, 2);
} catch {
return String(selectedException.detail);
}
})()}
</pre>
</div>
)}