Files
accounts-manager-web/components/accounts-manager.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

181 lines
5.7 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 { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Account } from '@/lib/types';
import { useAccounts } from '@/lib/hooks/use-accounts';
// 组件导入
import { StatsCards } from './accounts/stats-cards';
import { AccountFilters } from './accounts/account-filters';
import { BatchOperations } from './accounts/batch-operations';
import { AccountUpload } from './accounts/account-upload';
import { AccountTable } from './accounts/account-table';
import { AccountDetails } from './accounts/account-details';
export function AccountsManager() {
const {
accounts,
stats,
loading,
selectedIds,
pagination,
filters,
fetchAccounts,
fetchStats,
handleFilterChange,
handlePageChange,
handlePageSizeChange,
handleSelectAll,
handleSelectOne,
handleBatchDelete,
handleBatchUpdate,
handleUploadAccounts,
setSelectedIds
} = useAccounts();
// 账户详情状态
const [detailsDialog, setDetailsDialog] = useState(false);
const [detailsMode, setDetailsMode] = useState<'view' | 'edit'>('view');
const [selectedAccount, setSelectedAccount] = useState<Account | null>(null);
// 处理查看详情
const handleViewAccount = (account: Account) => {
setSelectedAccount(account);
setDetailsMode('view');
setDetailsDialog(true);
};
// 处理编辑账户
const handleEditAccount = (account: Account) => {
setSelectedAccount(account);
setDetailsMode('edit');
setDetailsDialog(true);
};
// 处理删除单个账户
const handleDeleteAccount = async (account: Account) => {
if (!confirm('确认删除此账户?')) return;
try {
// 设置选中的账户ID
setSelectedIds([account.id]);
// 执行删除
await handleBatchDelete();
} catch (error) {
console.error('Failed to delete account:', error);
}
};
// 处理保存编辑
const handleSaveAccount = async (account: Account) => {
try {
console.log('开始保存账户:', account);
// 构建payload将null/undefined转换为空字符串
const payload: Partial<Pick<Account, 'status' | 'ownerId' | 'notes' | 'platform'>> = {};
if (account.status !== null && account.status !== undefined) {
payload.status = account.status;
}
if (account.ownerId !== null && account.ownerId !== undefined) {
payload.ownerId = account.ownerId;
}
if (account.notes !== null && account.notes !== undefined) {
payload.notes = account.notes || ''; // 将null转换为空字符串
}
if (account.platform !== null && account.platform !== undefined) {
payload.platform = account.platform;
}
console.log('更新payload:', payload);
console.log('账户ID:', account.id);
if (Object.keys(payload).length === 0) {
console.log('没有有效的字段需要更新');
return;
}
// 直接传递账户ID数组避免状态竞态条件
await handleBatchUpdate(payload, [account.id]);
console.log('账户保存完成');
} catch (error) {
console.error('Failed to save account:', error);
}
};
return (
<div className="flex flex-col">
<div className="container mx-auto p-6 flex flex-col">
{/* 页面标题 */}
<div className="flex justify-between items-center mb-6">
<div>
<h1 className="text-3xl font-bold tracking-tight"></h1>
<p className="text-muted-foreground"></p>
</div>
<AccountUpload onUpload={handleUploadAccounts} stats={stats} />
</div>
{/* 统计卡片 */}
<div className="mb-6">
<StatsCards stats={stats} loading={loading} />
</div>
{/* 账户管理区域 */}
<Card className="flex flex-col">
<CardHeader className="pb-4">
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent className="flex flex-col space-y-4">
{/* 筛选条件 */}
<AccountFilters
filters={filters}
stats={stats}
onFilterChange={handleFilterChange}
/>
{/* 批量操作 */}
<BatchOperations
selectedCount={selectedIds.length}
selectedAccounts={accounts.filter(account => selectedIds.includes(account.id))}
stats={stats}
onBatchUpdate={handleBatchUpdate}
onBatchDelete={handleBatchDelete}
/>
{/* 账户表格 - 移除高度限制 */}
<div className="">
<AccountTable
accounts={accounts}
loading={loading}
selectedIds={selectedIds}
pagination={pagination}
onSelectAll={handleSelectAll}
onSelectOne={handleSelectOne}
onPageChange={handlePageChange}
onPageSizeChange={handlePageSizeChange}
onRefresh={fetchAccounts}
onView={handleViewAccount}
onEdit={handleEditAccount}
onDelete={handleDeleteAccount}
/>
</div>
</CardContent>
</Card>
</div>
{/* 账户详情对话框 */}
<AccountDetails
account={selectedAccount}
open={detailsDialog}
mode={detailsMode}
stats={stats}
onOpenChange={setDetailsDialog}
onSave={handleSaveAccount}
onDelete={handleDeleteAccount}
/>
</div>
);
}