Files
users/components/dialogs/batch-recalculate-dialog.tsx
v0 b17b488f8e refactor: restructure navigation and module layout
Reorganize navigation and module structure based on new requirements.

Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
2026-01-31 04:32:36 +00:00

171 lines
6.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client"
import { useState } from "react"
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"
import { Label } from "@/components/ui/label"
import { Checkbox } from "@/components/ui/checkbox"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Progress } from "@/components/ui/progress"
import { RefreshCw, Database, Clock, AlertTriangle } from "lucide-react"
interface BatchRecalculateDialogProps {
open: boolean
onOpenChange: (open: boolean) => void
}
const DATA_SOURCES = [
{ id: "1", name: "存客宝-用户主库", records: 128956342 },
{ id: "2", name: "触客宝-行为数据", records: 89234567 },
{ id: "3", name: "数智员工-账号API", records: 45678901 },
]
const AI_RULES = [
{ id: 1, name: "用户数据智能清洗", selected: true },
{ id: 2, name: "交易流水异常检测", selected: true },
{ id: 3, name: "聊天记录语义清洗", selected: false },
]
export function BatchRecalculateDialog({ open, onOpenChange }: BatchRecalculateDialogProps) {
const [isProcessing, setIsProcessing] = useState(false)
const [progress, setProgress] = useState(0)
const [selectedRules, setSelectedRules] = useState(AI_RULES.filter((r) => r.selected).map((r) => r.id))
const [scope, setScope] = useState("incremental")
const handleStart = () => {
setIsProcessing(true)
setProgress(0)
const interval = setInterval(() => {
setProgress((prev) => {
if (prev >= 100) {
clearInterval(interval)
setIsProcessing(false)
return 100
}
return prev + 10
})
}, 500)
}
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-lg">
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<RefreshCw className="w-5 h-5" />
</DialogTitle>
<DialogDescription>AI清洗规则</DialogDescription>
</DialogHeader>
{isProcessing ? (
<div className="space-y-4 py-4">
<div className="flex items-center justify-center">
<RefreshCw className="w-12 h-12 text-violet-500 animate-spin" />
</div>
<div className="text-center">
<p className="font-medium text-slate-800">...</p>
<p className="text-sm text-slate-500 mt-1"> {progress}%</p>
</div>
<Progress value={progress} className="h-2" />
<div className="text-center text-sm text-slate-500">
: {Math.ceil(((100 - progress) / 10) * 0.5)}
</div>
</div>
) : (
<div className="space-y-4">
<div className="space-y-2">
<Label>AI清洗规则</Label>
<div className="space-y-2">
{AI_RULES.map((rule) => (
<div key={rule.id} className="flex items-center gap-3 p-3 bg-slate-50 rounded-lg">
<Checkbox
checked={selectedRules.includes(rule.id)}
onCheckedChange={(checked) => {
if (checked) {
setSelectedRules([...selectedRules, rule.id])
} else {
setSelectedRules(selectedRules.filter((id) => id !== rule.id))
}
}}
/>
<span className="text-sm font-medium">{rule.name}</span>
</div>
))}
</div>
</div>
<div className="space-y-2">
<Label></Label>
<Select value={scope} onValueChange={setScope}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="incremental">/</SelectItem>
<SelectItem value="full"></SelectItem>
<SelectItem value="failed"></SelectItem>
</SelectContent>
</Select>
</div>
<div className="p-4 bg-amber-50 rounded-lg border border-amber-200">
<div className="flex items-start gap-2">
<AlertTriangle className="w-5 h-5 text-amber-600 mt-0.5" />
<div>
<p className="font-medium text-amber-800"></p>
<p className="text-sm text-amber-700 mt-1">
{scope === "full"
? "全量重算将处理所有历史数据,预计耗时较长,请确认后执行。"
: "增量重算仅处理新增或变更的数据,速度较快。"}
</p>
</div>
</div>
</div>
<div className="grid grid-cols-2 gap-4 text-sm">
<div className="p-3 bg-slate-50 rounded-lg">
<div className="flex items-center gap-2 text-slate-500 mb-1">
<Database className="w-4 h-4" />
</div>
<p className="font-bold text-slate-800">
{scope === "full" ? "128.9M" : scope === "failed" ? "3.4K" : "15.6K"}
</p>
</div>
<div className="p-3 bg-slate-50 rounded-lg">
<div className="flex items-center gap-2 text-slate-500 mb-1">
<Clock className="w-4 h-4" />
</div>
<p className="font-bold text-slate-800">
{scope === "full" ? "约 2 小时" : scope === "failed" ? "约 5 分钟" : "约 15 分钟"}
</p>
</div>
</div>
</div>
)}
<DialogFooter>
<Button variant="outline" onClick={() => onOpenChange(false)} disabled={isProcessing}>
{isProcessing ? "后台运行" : "取消"}
</Button>
{!isProcessing && (
<Button onClick={handleStart} disabled={selectedRules.length === 0}>
<RefreshCw className="w-4 h-4 mr-2" />
</Button>
)}
</DialogFooter>
</DialogContent>
</Dialog>
)
}