feat: 完善日报系统功能
新增功能: 1. ✅ 启用/禁用切换按钮 - 配置列表显示启用/禁用状态 - 点击按钮切换配置状态,不再直接删除 2. ✅ 独立删除按钮 - 删除前弹出确认提示 - 确认后才真正删除配置 3. ✅ 配置排序功能 - 添加sort_order字段支持排序 - 上移/下移按钮调整配置顺序 - 按sort_order升序排列 4. ✅ 定时任务验证 - 已有每天8:01自动生成日报的cron任务 - server.ts已正确集成定时任务 - 定时任务会为所有启用的配置生成日报 5. ✅ 批量下载功能 - 历史记录添加复选框选择 - 全选/取消全选功能 - 批量下载按钮一次性下载多个日报 数据库表更新: - t_daily_report_config新增sort_order字段 - 历史记录查询包含is_active状态显示 - 配置表建表语句支持排序字段 前端更新: - 配置列表显示状态列 - 操作按钮分为启用/禁用、删除、上移、下移 - 历史记录添加批量选择和下载功能 代码静态检查通过,所有功能可用 Coze-Commit-Type: user Coze-User-ID: 3722323274763196 Coze-Conversation-ID: 9894087
This commit is contained in:
@@ -1,14 +1,14 @@
|
|||||||
import { NextRequest, NextResponse } from 'next/server';
|
import { NextRequest, NextResponse } from 'next/server';
|
||||||
import pool from '@/lib/db';
|
import pool from '@/lib/db';
|
||||||
|
|
||||||
// PUT - 更新配置
|
// PUT - 更新配置(包括排序)
|
||||||
export async function PUT(
|
export async function PUT(
|
||||||
request: NextRequest,
|
request: NextRequest,
|
||||||
{ params }: { params: Promise<{ id: string }> }
|
{ params }: { params: Promise<{ id: string }> }
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const body = await request.json();
|
const body = await request.json();
|
||||||
const { config_name, split_type, selected_fields, is_active } = body;
|
const { config_name, split_type, selected_fields, is_active, sort_order } = body;
|
||||||
const { id: configId } = await params;
|
const { id: configId } = await params;
|
||||||
|
|
||||||
// 构建更新字段
|
// 构建更新字段
|
||||||
@@ -35,6 +35,11 @@ export async function PUT(
|
|||||||
updateValues.push(is_active);
|
updateValues.push(is_active);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sort_order !== undefined) {
|
||||||
|
updateFields.push('sort_order = ?');
|
||||||
|
updateValues.push(sort_order);
|
||||||
|
}
|
||||||
|
|
||||||
if (updateFields.length === 0) {
|
if (updateFields.length === 0) {
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
success: false,
|
success: false,
|
||||||
@@ -62,7 +67,7 @@ export async function PUT(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DELETE - 删除配置(设置为禁用)
|
// DELETE - 真正删除配置
|
||||||
export async function DELETE(
|
export async function DELETE(
|
||||||
request: NextRequest,
|
request: NextRequest,
|
||||||
{ params }: { params: Promise<{ id: string }> }
|
{ params }: { params: Promise<{ id: string }> }
|
||||||
@@ -71,18 +76,18 @@ export async function DELETE(
|
|||||||
const { id: configId } = await params;
|
const { id: configId } = await params;
|
||||||
|
|
||||||
await pool.execute(
|
await pool.execute(
|
||||||
'UPDATE t_daily_report_config SET is_active = 0 WHERE id = ?',
|
'DELETE FROM t_daily_report_config WHERE id = ?',
|
||||||
[configId]
|
[configId]
|
||||||
);
|
);
|
||||||
|
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
success: true,
|
success: true,
|
||||||
message: '配置已禁用'
|
message: '配置已删除'
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
success: false,
|
success: false,
|
||||||
message: '禁用配置失败',
|
message: '删除配置失败',
|
||||||
error: error instanceof Error ? error.message : '未知错误'
|
error: error instanceof Error ? error.message : '未知错误'
|
||||||
}, { status: 500 });
|
}, { status: 500 });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export async function GET() {
|
|||||||
try {
|
try {
|
||||||
const connection = await pool.getConnection();
|
const connection = await pool.getConnection();
|
||||||
const [configRows] = await connection.query<any[]>(
|
const [configRows] = await connection.query<any[]>(
|
||||||
'SELECT * FROM t_daily_report_config WHERE is_active = 1 ORDER BY create_time DESC'
|
'SELECT * FROM t_daily_report_config ORDER BY sort_order ASC, create_time DESC'
|
||||||
);
|
);
|
||||||
configs = configRows || [];
|
configs = configRows || [];
|
||||||
connection.release();
|
connection.release();
|
||||||
@@ -82,7 +82,8 @@ export async function POST(request: NextRequest) {
|
|||||||
sum_fields VARCHAR(3000) NULL COMMENT '求和字段列表',
|
sum_fields VARCHAR(3000) NULL COMMENT '求和字段列表',
|
||||||
create_time DATETIME NULL COMMENT '创建时间',
|
create_time DATETIME NULL COMMENT '创建时间',
|
||||||
update_time DATETIME NULL COMMENT '更新时间',
|
update_time DATETIME NULL COMMENT '更新时间',
|
||||||
is_active TINYINT NULL COMMENT '是否启用'
|
is_active TINYINT NULL COMMENT '是否启用',
|
||||||
|
sort_order INT NULL COMMENT '排序顺序'
|
||||||
)
|
)
|
||||||
UNIQUE KEY(id)
|
UNIQUE KEY(id)
|
||||||
DISTRIBUTED BY HASH(id) BUCKETS 1
|
DISTRIBUTED BY HASH(id) BUCKETS 1
|
||||||
@@ -105,8 +106,8 @@ export async function POST(request: NextRequest) {
|
|||||||
// 插入配置
|
// 插入配置
|
||||||
await connection.query(
|
await connection.query(
|
||||||
`INSERT INTO t_daily_report_config
|
`INSERT INTO t_daily_report_config
|
||||||
(id, config_name, split_type, split_value, split_name, selected_fields, sum_fields, create_time, update_time, is_active)
|
(id, config_name, split_type, split_value, split_name, selected_fields, sum_fields, create_time, update_time, is_active, sort_order)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 1)`,
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 999)`,
|
||||||
[
|
[
|
||||||
id,
|
id,
|
||||||
config_name,
|
config_name,
|
||||||
|
|||||||
52
src/app/api/download/batch/route.ts
Normal file
52
src/app/api/download/batch/route.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import { NextRequest, NextResponse } from 'next/server';
|
||||||
|
import pool from '@/lib/db';
|
||||||
|
|
||||||
|
// 批量下载日报
|
||||||
|
export async function POST(request: NextRequest) {
|
||||||
|
try {
|
||||||
|
const body = await request.json();
|
||||||
|
const { ids } = body; // 历史记录ID数组
|
||||||
|
|
||||||
|
if (!ids || !Array.isArray(ids) || ids.length === 0) {
|
||||||
|
return NextResponse.json({
|
||||||
|
success: false,
|
||||||
|
message: '请选择要下载的日报'
|
||||||
|
}, { status: 400 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取所有选中的历史记录
|
||||||
|
const [historyRecords] = await pool.execute<any[]>(
|
||||||
|
`SELECT id, file_path, split_name, report_date
|
||||||
|
FROM t_daily_report_history
|
||||||
|
WHERE id IN (${ids.map(() => '?').join(',')})
|
||||||
|
AND status = 1`,
|
||||||
|
ids
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!Array.isArray(historyRecords) || historyRecords.length === 0) {
|
||||||
|
return NextResponse.json({
|
||||||
|
success: false,
|
||||||
|
message: '未找到有效的日报记录'
|
||||||
|
}, { status: 404 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回文件路径列表,前端可以批量下载
|
||||||
|
const files = historyRecords.map(record => ({
|
||||||
|
id: record.id,
|
||||||
|
fileName: `${record.split_name || '日报'}_${record.report_date}.xlsx`,
|
||||||
|
filePath: record.file_path
|
||||||
|
}));
|
||||||
|
|
||||||
|
return NextResponse.json({
|
||||||
|
success: true,
|
||||||
|
files: files,
|
||||||
|
count: files.length
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
return NextResponse.json({
|
||||||
|
success: false,
|
||||||
|
message: '批量下载失败',
|
||||||
|
error: error instanceof Error ? error.message : '未知错误'
|
||||||
|
}, { status: 500 });
|
||||||
|
}
|
||||||
|
}
|
||||||
288
src/app/page.tsx
288
src/app/page.tsx
@@ -41,6 +41,9 @@ export default function Home() {
|
|||||||
const [historyPage, setHistoryPage] = useState(1);
|
const [historyPage, setHistoryPage] = useState(1);
|
||||||
const [historyTotal, setHistoryTotal] = useState(0);
|
const [historyTotal, setHistoryTotal] = useState(0);
|
||||||
|
|
||||||
|
// 批量下载
|
||||||
|
const [selectedHistoryIds, setSelectedHistoryIds] = useState<string[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadData();
|
loadData();
|
||||||
}, []);
|
}, []);
|
||||||
@@ -174,6 +177,69 @@ export default function Home() {
|
|||||||
setLoading(false);
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleBatchDownload = async () => {
|
||||||
|
if (selectedHistoryIds.length === 0) {
|
||||||
|
toast({
|
||||||
|
title: '错误',
|
||||||
|
description: '请选择要下载的日报',
|
||||||
|
variant: 'destructive'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
const res = await fetch('/api/download/batch', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ ids: selectedHistoryIds })
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
if (data.success && data.files) {
|
||||||
|
// 批量下载文件
|
||||||
|
data.files.forEach((file: { fileName: string; filePath: string }) => {
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = file.filePath;
|
||||||
|
link.download = file.fileName;
|
||||||
|
link.target = '_blank';
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
});
|
||||||
|
|
||||||
|
toast({
|
||||||
|
title: '成功',
|
||||||
|
description: `已开始下载 ${data.count} 个日报文件`
|
||||||
|
});
|
||||||
|
setSelectedHistoryIds([]);
|
||||||
|
} else {
|
||||||
|
toast({
|
||||||
|
title: '错误',
|
||||||
|
description: data.message,
|
||||||
|
variant: 'destructive'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
toast({
|
||||||
|
title: '错误',
|
||||||
|
description: '批量下载失败',
|
||||||
|
variant: 'destructive'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectHistory = (id: string, checked: boolean) => {
|
||||||
|
if (checked) {
|
||||||
|
setSelectedHistoryIds([...selectedHistoryIds, id]);
|
||||||
|
} else {
|
||||||
|
setSelectedHistoryIds(selectedHistoryIds.filter(hId => hId !== id));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleGenerateReport = async () => {
|
const handleGenerateReport = async () => {
|
||||||
if (!reportSplitValue || reportSelectedFields.length === 0) {
|
if (!reportSplitValue || reportSelectedFields.length === 0) {
|
||||||
toast({
|
toast({
|
||||||
@@ -224,6 +290,9 @@ export default function Home() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteConfig = async (id: string) => {
|
const handleDeleteConfig = async (id: string) => {
|
||||||
|
if (!confirm('确定要删除这个配置吗?删除后无法恢复!')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`/api/config/${id}`, {
|
const res = await fetch(`/api/config/${id}`, {
|
||||||
@@ -234,7 +303,7 @@ export default function Home() {
|
|||||||
if (data.success) {
|
if (data.success) {
|
||||||
toast({
|
toast({
|
||||||
title: '成功',
|
title: '成功',
|
||||||
description: '配置已禁用'
|
description: '配置已删除'
|
||||||
});
|
});
|
||||||
loadData();
|
loadData();
|
||||||
} else {
|
} else {
|
||||||
@@ -247,7 +316,130 @@ export default function Home() {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast({
|
toast({
|
||||||
title: '错误',
|
title: '错误',
|
||||||
description: '禁用配置失败',
|
description: '删除配置失败',
|
||||||
|
variant: 'destructive'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleToggleActive = async (id: string, isActive: number) => {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
const res = await fetch(`/api/config/${id}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ is_active: isActive })
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
if (data.success) {
|
||||||
|
toast({
|
||||||
|
title: '成功',
|
||||||
|
description: isActive === 1 ? '配置已启用' : '配置已禁用'
|
||||||
|
});
|
||||||
|
loadData();
|
||||||
|
} else {
|
||||||
|
toast({
|
||||||
|
title: '错误',
|
||||||
|
description: data.message,
|
||||||
|
variant: 'destructive'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
toast({
|
||||||
|
title: '错误',
|
||||||
|
description: '更新配置状态失败',
|
||||||
|
variant: 'destructive'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMoveUp = async (id: string) => {
|
||||||
|
const currentIndex = configs.findIndex(c => c.id === id);
|
||||||
|
if (currentIndex <= 0) return; // 已经是第一个
|
||||||
|
|
||||||
|
const currentConfig = configs[currentIndex];
|
||||||
|
const prevConfig = configs[currentIndex - 1];
|
||||||
|
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
// 交换排序顺序
|
||||||
|
const currentOrder = currentConfig.sort_order || 999;
|
||||||
|
const prevOrder = prevConfig.sort_order || 999;
|
||||||
|
|
||||||
|
await fetch(`/api/config/${id}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ sort_order: prevOrder - 1 })
|
||||||
|
});
|
||||||
|
|
||||||
|
await fetch(`/api/config/${prevConfig.id}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ sort_order: currentOrder })
|
||||||
|
});
|
||||||
|
|
||||||
|
toast({
|
||||||
|
title: '成功',
|
||||||
|
description: '配置已上移'
|
||||||
|
});
|
||||||
|
loadData();
|
||||||
|
} catch (error) {
|
||||||
|
toast({
|
||||||
|
title: '错误',
|
||||||
|
description: '移动配置失败',
|
||||||
|
variant: 'destructive'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMoveDown = async (id: string) => {
|
||||||
|
const currentIndex = configs.findIndex(c => c.id === id);
|
||||||
|
if (currentIndex >= configs.length - 1) return; // 已经是最后一个
|
||||||
|
|
||||||
|
const currentConfig = configs[currentIndex];
|
||||||
|
const nextConfig = configs[currentIndex + 1];
|
||||||
|
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
// 交换排序顺序
|
||||||
|
const currentOrder = currentConfig.sort_order || 999;
|
||||||
|
const nextOrder = nextConfig.sort_order || 999;
|
||||||
|
|
||||||
|
await fetch(`/api/config/${id}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ sort_order: nextOrder + 1 })
|
||||||
|
});
|
||||||
|
|
||||||
|
await fetch(`/api/config/${nextConfig.id}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ sort_order: currentOrder })
|
||||||
|
});
|
||||||
|
|
||||||
|
toast({
|
||||||
|
title: '成功',
|
||||||
|
description: '配置已下移'
|
||||||
|
});
|
||||||
|
loadData();
|
||||||
|
} catch (error) {
|
||||||
|
toast({
|
||||||
|
title: '错误',
|
||||||
|
description: '移动配置失败',
|
||||||
variant: 'destructive'
|
variant: 'destructive'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -446,6 +638,7 @@ export default function Home() {
|
|||||||
<TableHead>企业/用户</TableHead>
|
<TableHead>企业/用户</TableHead>
|
||||||
<TableHead>字段数</TableHead>
|
<TableHead>字段数</TableHead>
|
||||||
<TableHead>求和字段</TableHead>
|
<TableHead>求和字段</TableHead>
|
||||||
|
<TableHead>状态</TableHead>
|
||||||
<TableHead>操作</TableHead>
|
<TableHead>操作</TableHead>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
@@ -466,14 +659,56 @@ export default function Home() {
|
|||||||
{config.sum_fields ? JSON.parse(config.sum_fields).length : 0} 个
|
{config.sum_fields ? JSON.parse(config.sum_fields).length : 0} 个
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<Button
|
<Badge variant={config.is_active === 1 ? 'default' : 'secondary'}>
|
||||||
variant="destructive"
|
{config.is_active === 1 ? '启用' : '禁用'}
|
||||||
size="sm"
|
</Badge>
|
||||||
onClick={() => handleDeleteConfig(config.id)}
|
</TableCell>
|
||||||
disabled={loading}
|
<TableCell>
|
||||||
>
|
<div className="flex gap-2">
|
||||||
禁用
|
{config.is_active === 1 ? (
|
||||||
</Button>
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => handleToggleActive(config.id, 0)}
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
禁用
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
variant="default"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => handleToggleActive(config.id, 1)}
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
启用
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
variant="destructive"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => handleDeleteConfig(config.id)}
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => handleMoveUp(config.id)}
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
↑
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => handleMoveDown(config.id)}
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
↓
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}
|
))}
|
||||||
@@ -612,13 +847,36 @@ export default function Home() {
|
|||||||
<TabsContent value="history">
|
<TabsContent value="history">
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>日报历史记录</CardTitle>
|
<div className="flex justify-between items-center">
|
||||||
<CardDescription>查看已生成的日报历史</CardDescription>
|
<div>
|
||||||
|
<CardTitle>日报历史记录</CardTitle>
|
||||||
|
<CardDescription>查看已生成的日报历史</CardDescription>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
variant="default"
|
||||||
|
onClick={handleBatchDownload}
|
||||||
|
disabled={selectedHistoryIds.length === 0 || loading}
|
||||||
|
>
|
||||||
|
批量下载 ({selectedHistoryIds.length})
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<Table>
|
<Table>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
|
<TableHead className="w-12">
|
||||||
|
<Checkbox
|
||||||
|
checked={selectedHistoryIds.length === history.length && history.length > 0}
|
||||||
|
onCheckedChange={(checked) => {
|
||||||
|
if (checked) {
|
||||||
|
setSelectedHistoryIds(history.map(h => h.id));
|
||||||
|
} else {
|
||||||
|
setSelectedHistoryIds([]);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</TableHead>
|
||||||
<TableHead>报表日期</TableHead>
|
<TableHead>报表日期</TableHead>
|
||||||
<TableHead>拆分方式</TableHead>
|
<TableHead>拆分方式</TableHead>
|
||||||
<TableHead>企业/用户</TableHead>
|
<TableHead>企业/用户</TableHead>
|
||||||
@@ -633,6 +891,12 @@ export default function Home() {
|
|||||||
<TableBody>
|
<TableBody>
|
||||||
{history.map((record) => (
|
{history.map((record) => (
|
||||||
<TableRow key={record.id}>
|
<TableRow key={record.id}>
|
||||||
|
<TableCell>
|
||||||
|
<Checkbox
|
||||||
|
checked={selectedHistoryIds.includes(record.id)}
|
||||||
|
onCheckedChange={(checked) => handleSelectHistory(record.id, checked as boolean)}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
<TableCell>{record.report_date}</TableCell>
|
<TableCell>{record.report_date}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<Badge variant={record.split_type === 'company_id' ? 'default' : 'secondary'}>
|
<Badge variant={record.split_type === 'company_id' ? 'default' : 'secondary'}>
|
||||||
|
|||||||
Reference in New Issue
Block a user