Files
accounts-manager-web/components/accounts/batch-operations.tsx
Your Name 0b95ca36f1 Initial project setup with Next.js accounts manager
- Set up Next.js project structure
- Added UI components and styling
- Configured package dependencies
- Added feature documentation

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-23 01:40:14 +08:00

200 lines
6.7 KiB
TypeScript

"use client";
import { useState } from 'react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Edit3, Trash2 } from 'lucide-react';
import { Account, StatsOverview } from '@/lib/types';
import { toast } from 'sonner';
import { PlatformSelector, OwnerSelector, StatusSelector } from '@/components/shared';
interface BatchOperationsProps {
selectedCount: number;
selectedAccounts: Account[];
stats: StatsOverview | null;
onBatchUpdate: (payload: Partial<Pick<Account, 'status' | 'ownerId' | 'notes' | 'platform'>>) => Promise<void>;
onBatchDelete: () => Promise<void>;
}
export function BatchOperations({ selectedCount, selectedAccounts, stats, onBatchUpdate, onBatchDelete }: BatchOperationsProps) {
const [updateDialog, setUpdateDialog] = useState(false);
const [updateData, setUpdateData] = useState({
status: '',
platform: '',
ownerId: '',
notes: ''
});
const [loading, setLoading] = useState(false);
// 计算选中账户的统计信息
const getSelectedStats = () => {
const platforms = new Set(selectedAccounts.map(account => account.platform));
const owners = new Set(selectedAccounts.map(account => account.ownerId));
return {
platformCount: platforms.size,
ownerCount: owners.size,
platforms: Array.from(platforms).slice(0, 3), // 只显示前3个
owners: Array.from(owners).slice(0, 3) // 只显示前3个
};
};
const selectedStats = getSelectedStats();
const handleBatchUpdate = async () => {
const payload: Partial<Pick<Account, 'status' | 'ownerId' | 'notes' | 'platform'>> = {};
if (updateData.status) payload.status = updateData.status;
if (updateData.platform) payload.platform = updateData.platform;
if (updateData.ownerId) payload.ownerId = updateData.ownerId;
if (updateData.notes) payload.notes = updateData.notes;
if (Object.keys(payload).length === 0) {
toast.warning('请至少选择一个字段进行更新');
return;
}
setLoading(true);
try {
await onBatchUpdate(payload);
setUpdateDialog(false);
setUpdateData({ status: '', platform: '', ownerId: '', notes: '' });
} finally {
setLoading(false);
}
};
const handleBatchDelete = async () => {
setLoading(true);
try {
await onBatchDelete();
} finally {
setLoading(false);
}
};
if (selectedCount === 0) {
return null;
}
return (
<>
<div className="flex items-center space-x-2 p-3 bg-muted rounded-lg">
<div className="flex-1">
<div className="flex items-center space-x-4">
<span className="text-sm font-medium"> {selectedCount} </span>
<div className="flex items-center space-x-3 text-xs text-muted-foreground">
<span>
{selectedStats.ownerCount}
{selectedStats.ownerCount > 0 && (
<span className="ml-1">
({selectedStats.owners.join(', ')}
{selectedStats.ownerCount > 3 && `${selectedStats.ownerCount}`})
</span>
)}
</span>
<span></span>
<span>
{selectedStats.platformCount}
{selectedStats.platformCount > 0 && (
<span className="ml-1">
({selectedStats.platforms.join(', ')}
{selectedStats.platformCount > 3 && `${selectedStats.platformCount}`})
</span>
)}
</span>
</div>
</div>
</div>
<Button
variant="outline"
size="sm"
onClick={() => setUpdateDialog(true)}
disabled={loading}
>
<Edit3 className="h-4 w-4 mr-1" />
</Button>
<Button
variant="destructive"
size="sm"
onClick={handleBatchDelete}
disabled={loading}
>
<Trash2 className="h-4 w-4 mr-1" />
</Button>
</div>
<Dialog open={updateDialog} onOpenChange={setUpdateDialog}>
<DialogContent>
<DialogHeader>
<DialogTitle></DialogTitle>
<DialogDescription>
{selectedCount}
</DialogDescription>
</DialogHeader>
<div className="grid grid-cols-1 gap-6">
<div className="space-y-3">
<label className="text-sm font-medium"></label>
<PlatformSelector
value={updateData.platform}
onValueChange={(value) => setUpdateData({...updateData, platform: value})}
stats={stats}
showNoneOption={true}
placeholder="选择新平台(可选)"
/>
</div>
<div className="space-y-3">
<label className="text-sm font-medium"></label>
<StatusSelector
value={updateData.status}
onValueChange={(value) => setUpdateData({...updateData, status: value})}
stats={stats}
showNoneOption={true}
placeholder="选择新状态(可选)"
/>
</div>
<div className="space-y-3">
<label className="text-sm font-medium">ID</label>
<OwnerSelector
value={updateData.ownerId}
onValueChange={(value) => setUpdateData({...updateData, ownerId: value})}
stats={stats}
showNoneOption={true}
placeholder="选择所有者(可选)"
/>
</div>
<div className="space-y-3">
<label className="text-sm font-medium"></label>
<Input
placeholder="输入新的备注(可选)"
value={updateData.notes}
onChange={(e) => setUpdateData({...updateData, notes: e.target.value})}
/>
</div>
</div>
<DialogFooter>
<Button
variant="outline"
onClick={() => setUpdateDialog(false)}
disabled={loading}
>
</Button>
<Button
onClick={handleBatchUpdate}
disabled={loading}
>
{loading ? '更新中...' : '确认更新'}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</>
);
}