feature:增加数据配比功能 (#52)

* refactor: 修改调整数据归集实现,删除无用代码,优化代码结构

* feature: 每天凌晨00:00扫描所有数据集,检查数据集是否超过了预设的保留天数,超出保留天数的数据集调用删除接口进行删除

* fix: 修改删除数据集文件的逻辑,上传到数据集中的文件会同时删除数据库中的记录和文件系统中的文件,归集过来的文件仅删除数据库中的记录

* fix: 增加参数校验和接口定义,删除不使用的接口

* fix: 数据集统计数据默认为0

* feature: 数据集状态增加流转,创建时为草稿状态,上传文件或者归集文件后修改为活动状态

* refactor: 修改分页查询归集任务的代码

* fix: 更新后重新执行;归集任务执行增加事务控制

* feature: 创建归集任务时能够同步创建数据集,更新归集任务时能更新到指定数据集

* fix: 创建归集任务不需要创建数据集时不应该报错

* fix: 修复删除文件时数据集的统计数据不变动

* feature: 查询数据集详情时能够获取到文件标签分布

* fix: tags为空时不进行分析

* fix: 状态修改为ACTIVE

* fix: 修改解析tag的方法

* feature: 实现创建、分页查询、删除配比任务

* feature: 实现创建、分页查询、删除配比任务的前端交互

* fix: 修复进度计算异常导致的页面报错
This commit is contained in:
hefanli
2025-11-03 10:17:39 +08:00
committed by GitHub
parent 07edf16044
commit 08bd4eca5c
32 changed files with 1894 additions and 1028 deletions

View File

@@ -0,0 +1,132 @@
import React from "react";
import { Badge, Card, Input, Progress } from "antd";
import { BarChart3 } from "lucide-react";
import type { Dataset } from "@/pages/DataManagement/dataset.model.ts";
interface RatioConfigItem {
id: string;
name: string;
type: "dataset" | "label";
quantity: number;
percentage: number;
source: string;
}
interface RatioConfigProps {
ratioType: "dataset" | "label";
selectedDatasets: string[];
datasets: Dataset[];
ratioConfigs: RatioConfigItem[];
totalTargetCount: number;
distributions: Record<string, Record<string, number>>;
onUpdateDatasetQuantity: (datasetId: string, quantity: number) => void;
onUpdateLabelQuantity: (datasetId: string, label: string, quantity: number) => void;
}
const RatioConfig: React.FC<RatioConfigProps> = ({
ratioType,
selectedDatasets,
datasets,
ratioConfigs,
totalTargetCount,
distributions,
onUpdateDatasetQuantity,
onUpdateLabelQuantity,
}) => {
const totalConfigured = ratioConfigs.reduce((sum, c) => sum + (c.quantity || 0), 0);
return (
<div className="mb-4">
<div className="flex items-center justify-between">
<span className="text-sm font-medium"></span>
<span className="text-xs text-gray-500">
: {totalConfigured} / {totalTargetCount}
</span>
</div>
{selectedDatasets.length === 0 ? (
<div className="text-center py-8 text-gray-500">
<BarChart3 className="w-12 h-12 mx-auto mb-2 text-gray-300" />
<p className="text-sm"></p>
</div>
) : (
<div style={{ maxHeight: 500, overflowY: "auto" }}>
{selectedDatasets.map((datasetId) => {
const dataset = datasets.find((d) => String(d.id) === datasetId);
const config = ratioConfigs.find((c) => c.source === datasetId);
const currentQuantity = config?.quantity || 0;
if (!dataset) return null;
return (
<Card key={datasetId} size="small" className="mb-2">
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-2">
<span className="font-medium text-sm">{dataset.name}</span>
<Badge color="gray">{dataset.fileCount}</Badge>
</div>
<div className="text-xs text-gray-500">{config?.percentage || 0}%</div>
</div>
{ratioType === "dataset" ? (
<div>
<div className="flex items-center gap-2 mb-2">
<span className="text-xs">:</span>
<Input
type="number"
value={currentQuantity}
onChange={(e) => onUpdateDatasetQuantity(datasetId, Number(e.target.value))}
style={{ width: 80 }}
min={0}
max={Math.min(dataset.fileCount || 0, totalTargetCount)}
/>
<span className="text-xs text-gray-500"></span>
</div>
<Progress
percent={Math.round((currentQuantity / totalTargetCount) * 100)}
size="small"
/>
</div>
) : (
<div>
{!distributions[String(dataset.id)] ? (
<div className="text-xs text-gray-400">...</div>
) : Object.entries(distributions[String(dataset.id)]).length === 0 ? (
<div className="text-xs text-gray-400"></div>
) : (
<div className="flex flex-col gap-2">
{Object.entries(distributions[String(dataset.id)]).map(([label, count]) => {
const sourceKey = `${datasetId}_${label}`;
const labelConfig = ratioConfigs.find((c) => c.source === sourceKey);
const labelQuantity = labelConfig?.quantity || 0;
return (
<div key={label} className="flex items-center justify-between gap-2">
<div className="flex items-center gap-2">
<Badge color="gray">{label}</Badge>
<span className="text-xs text-gray-500">{count}</span>
</div>
<div className="flex items-center gap-2">
<span className="text-xs">:</span>
<Input
type="number"
value={labelQuantity}
onChange={(e) => onUpdateLabelQuantity(datasetId, label, Number(e.target.value))}
style={{ width: 80 }}
min={0}
max={Math.min(Number(count) || 0, totalTargetCount)}
/>
<span className="text-xs text-gray-500"></span>
</div>
</div>
);
})}
</div>
)}
</div>
)}
</Card>
);
})}
</div>
)}
</div>
);
};
export default RatioConfig;