feat(backend): Phase 0 项目骨架完成 — 后端/前端/数据库/Docker
- 后端:FastAPI + SQLAlchemy + Alembic,7 张核心表迁移成功 - 前端:Next.js 16 + TailwindCSS 4 + 三端布局(投资人/创始人/Admin) - 数据库:PostgreSQL 16,7 张核心实体表(tenants/users/companies/monthly_reports/health_scores/risk_events/audit_logs) - Docker:docker-compose.yml + 前后端 Dockerfile - 测试:健康检查 4 个测试全部 GREEN - 文档:README/run.md/AGENTS.md/docs 体系完整
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
/** 空状态占位组件。 */
|
||||
|
||||
import { Inbox } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
/**
|
||||
* 空状态占位。
|
||||
* @param title - 标题
|
||||
* @param description - 描述
|
||||
* @param className - 额外类名
|
||||
*/
|
||||
export function EmptyState({
|
||||
title = "暂无数据",
|
||||
description,
|
||||
className,
|
||||
}: {
|
||||
title?: string;
|
||||
description?: string;
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<div className={cn("flex flex-col items-center justify-center py-12 text-center", className)}>
|
||||
<Inbox className="mb-3 text-muted-foreground" size={40} aria-hidden="true" />
|
||||
<p className="text-sm font-medium text-foreground">{title}</p>
|
||||
{description && <p className="mt-1 text-xs text-muted-foreground">{description}</p>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/** 健康度评分徽章组件。 */
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
/**
|
||||
* 健康度评分徽章。
|
||||
* @param score - 分数(0-100)
|
||||
* @param label - 标签文字
|
||||
*/
|
||||
export function HealthScoreBadge({ score, label }: { score: number; label?: string }) {
|
||||
const level = score >= 80 ? "good" : score >= 60 ? "fair" : "poor";
|
||||
const colors = {
|
||||
good: "bg-[var(--success)]/10 text-[var(--success)] border-[var(--success)]/30",
|
||||
fair: "bg-[var(--warning)]/10 text-[var(--warning)] border-[var(--warning)]/30",
|
||||
poor: "bg-[var(--destructive)]/10 text-[var(--destructive)] border-[var(--destructive)]/30",
|
||||
};
|
||||
|
||||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"inline-flex items-center rounded-md border px-2 py-0.5 text-xs font-medium",
|
||||
colors[level],
|
||||
)}
|
||||
>
|
||||
{label && <span className="mr-1">{label}</span>}
|
||||
{score}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/** 加载中旋转图标组件。 */
|
||||
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
/**
|
||||
* 加载中旋转图标。
|
||||
* @param className - 额外类名
|
||||
* @param size - 图标尺寸(像素)
|
||||
*/
|
||||
export function LoadingSpinner({ className, size = 24 }: { className?: string; size?: number }) {
|
||||
return (
|
||||
<div className={cn("flex items-center justify-center", className)} role="status">
|
||||
<Loader2 className="animate-spin text-muted-foreground" size={size} aria-label="加载中" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user