218 lines
6.7 KiB
TypeScript
218 lines
6.7 KiB
TypeScript
// import React from 'react';
|
|
import { type MetaFunction } from "@remix-run/node";
|
|
import { useLoaderData } from "@remix-run/react";
|
|
import { Card } from "~/components/ui/Card";
|
|
import { Button } from "~/components/ui/Button";
|
|
import { StatusBadge, links as statusBadgeLinks } from "~/components/ui/StatusBadge";
|
|
import { FileTag, links as fileTagLinks } from "~/components/ui/FileTag";
|
|
// import { FileTypeTag, links as fileTypeTagLinks } from "~/components/ui/FileTypeTag";
|
|
import { Tag } from "~/components/ui/Tag";
|
|
import homeStyles from "~/styles/pages/home.css?url";
|
|
import { getDocuments, type DocumentUI } from "~/api/files/documents";
|
|
export const links = () => [
|
|
{ rel: "stylesheet", href: homeStyles },
|
|
...statusBadgeLinks(),
|
|
...fileTagLinks()
|
|
];
|
|
|
|
export const meta: MetaFunction = () => {
|
|
return [
|
|
{ title: "中国烟草AI合同及卷宗审核系统 - 首页" },
|
|
{ name: "description", content: "AI审核系统首页" }
|
|
];
|
|
};
|
|
|
|
// API 响应的类型定义
|
|
interface StatsData {
|
|
totalFiles: number;
|
|
reviewedFiles: number;
|
|
pendingFiles: number;
|
|
passRate: number;
|
|
}
|
|
|
|
|
|
// interface LoaderData {
|
|
// stats: StatsData;
|
|
// recentFiles: RecentFile[];
|
|
// }
|
|
|
|
|
|
// 模拟数据,实际项目中应该从API获取
|
|
export async function loader() {
|
|
try {
|
|
const documentSearchParams = {
|
|
page: 1,
|
|
pageSize: 10,
|
|
order: 'updated_at.desc'
|
|
};
|
|
|
|
// 获取最近文档数据
|
|
const responseDocuments = await getDocuments(documentSearchParams);
|
|
if (responseDocuments.error) {
|
|
console.error('获取最近文档数据失败', responseDocuments.error);
|
|
return Response.json({ error: responseDocuments.error }, { status: responseDocuments.status || 500 });
|
|
}
|
|
const recentFiles = responseDocuments.data?.documents || [];
|
|
console.log("recentFiles-------",recentFiles);
|
|
|
|
|
|
// 模拟数据
|
|
const stats = {
|
|
totalFiles: 156,
|
|
reviewedFiles: 124,
|
|
pendingFiles: 32,
|
|
passRate: 92.5
|
|
} as StatsData;
|
|
|
|
|
|
|
|
return Response.json({ stats, recentFiles });
|
|
} catch (error) {
|
|
// 错误处理
|
|
console.error('Failed to fetch dashboard data:', error);
|
|
return Response.json(
|
|
{ error: '获取数据失败,请稍后重试' },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|
|
|
|
export default function Index() {
|
|
const { stats, recentFiles } = useLoaderData<typeof loader>();
|
|
|
|
return (
|
|
<div className="dashboard-container">
|
|
{/* 页面标识 */}
|
|
|
|
{/* 统计卡片区域 */}
|
|
<Card title="统计信息" icon="ri-bar-chart-line" className="mt-6 transition-all duration-200 hover:shadow-[0_4px_15px_rgba(0,0,0,0.1)]">
|
|
<div className="stat-grid ">
|
|
<StatCard
|
|
title="总文件数"
|
|
value={stats.totalFiles}
|
|
icon="ri-file-list-3-line"
|
|
/>
|
|
<StatCard
|
|
title="已审核"
|
|
value={stats.reviewedFiles}
|
|
icon="ri-check-double-line"
|
|
trend={{ value: 5.2, isUp: true }}
|
|
/>
|
|
<StatCard
|
|
title="待审核"
|
|
value={stats.pendingFiles}
|
|
icon="ri-time-line"
|
|
trend={{ value: 2.1, isUp: false }}
|
|
/>
|
|
<StatCard
|
|
title="通过率"
|
|
value={`${stats.passRate}%`}
|
|
icon="ri-pie-chart-line"
|
|
trend={{ value: 1.5, isUp: true }}
|
|
/>
|
|
</div>
|
|
</Card>
|
|
|
|
{/* 快捷访问区域 */}
|
|
<Card title="快捷访问" icon="ri-speed-line" className="mt-6 transition-all duration-200 hover:shadow-[0_4px_15px_rgba(0,0,0,0.1)]">
|
|
<div className="shortcut-grid">
|
|
<ShortcutItem icon="ri-upload-cloud-line" label="上传文件" to="/files/upload" />
|
|
<ShortcutItem icon="ri-file-list-3-line" label="文件列表" to="/documents" />
|
|
<ShortcutItem icon="ri-list-check-2" label="评查点管理" to="/rules" />
|
|
<ShortcutItem icon="ri-folder-open-line" label="评查点分组" to="/rule-groups" />
|
|
<ShortcutItem icon="ri-file-chart-line" label="评查详情" to="/reviews" />
|
|
<ShortcutItem icon="ri-file-list-line" label="文档类型" to="/document-types" />
|
|
{/* <ShortcutItem icon="ri-settings-3-line" label="系统设置" to="/settings" /> */}
|
|
<ShortcutItem icon="ri-chat-1-line" label="提示词管理" to="/prompts" />
|
|
</div>
|
|
</Card>
|
|
|
|
{/* 最近文档区域 */}
|
|
<Card
|
|
title="最近文档"
|
|
icon="ri-file-list-3-line"
|
|
extra={<Button to="/documents" size="small">查看全部</Button>}
|
|
className="mt-6"
|
|
>
|
|
<div className="doc-list">
|
|
{recentFiles.map((file: DocumentUI) => (
|
|
<div key={file.id} className="doc-item">
|
|
<div className="doc-info">
|
|
<FileTag
|
|
extension={file.name.endsWith('.pdf') ? 'pdf' : 'docx'}
|
|
showIcon={true}
|
|
showText={false}
|
|
showBackground={false}
|
|
size="lg"
|
|
className="mr-2"
|
|
/>
|
|
<div>
|
|
<div className="doc-name">{file.name}</div>
|
|
<div className="doc-meta">
|
|
<Tag size="sm" className="mr-2">
|
|
{file.typeName}
|
|
</Tag>
|
|
<span className="text-gray-500">·</span>
|
|
<span className="ml-2 text-gray-500">{file.updatedAt}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="doc-status">
|
|
<StatusBadge status={file.fileStatus} />
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</Card>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// 统计卡片组件
|
|
interface StatCardProps {
|
|
title: string;
|
|
value: number | string;
|
|
icon: string;
|
|
trend?: {
|
|
value: number;
|
|
isUp: boolean;
|
|
};
|
|
}
|
|
|
|
function StatCard({ title, value, icon, trend }: StatCardProps) {
|
|
return (
|
|
<div className="stat-card">
|
|
<div className="stat-title">{title}</div>
|
|
<div className="stat-value">{value}</div>
|
|
{trend && (
|
|
<div className={`stat-trend ${trend.isUp ? 'trend-up' : 'trend-down'}`}>
|
|
<i className={`mr-1 ${trend.isUp ? 'ri-arrow-up-s-line' : 'ri-arrow-down-s-line'}`}></i>
|
|
<span>{trend.value}%</span>
|
|
<span className="ml-1 text-gray-500">较上月</span>
|
|
</div>
|
|
)}
|
|
<i className={`${icon} stat-icon`}></i>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// 快捷方式组件
|
|
interface ShortcutItemProps {
|
|
icon: string;
|
|
label: string;
|
|
to: string;
|
|
}
|
|
|
|
function ShortcutItem({ icon, label, to }: ShortcutItemProps) {
|
|
return (
|
|
<Button
|
|
to={to}
|
|
type="default"
|
|
className="shortcut-item"
|
|
>
|
|
<i className={`${icon} shortcut-icon text-2xl`}></i>
|
|
<span className="shortcut-label">{label}</span>
|
|
</Button>
|
|
);
|
|
}
|