Files
accounts-manager-web/lib/hooks/use-accounts.ts
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

265 lines
7.4 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.

import { useState, useEffect } from 'react';
import {
Account,
ListAccountsBody,
ListAccountsResponse,
StatsOverview,
BusinessCode,
BatchUpdateBody,
BatchDeleteBody,
ScriptUploadItem
} from '@/lib/types';
import { apiClient } from '@/lib/api';
import { toast } from 'sonner';
export interface UseAccountsReturn {
// 数据状态
accounts: Account[];
stats: StatsOverview | null;
loading: boolean;
selectedIds: number[];
// 分页和筛选
pagination: {
page: number;
pageSize: number;
total: number;
totalPages: number;
};
filters: {
platform: string;
status: string[];
ownerId: string;
search: string;
};
sort: {
field: keyof Account;
order: 'asc' | 'desc';
};
// 操作方法
fetchAccounts: () => Promise<void>;
fetchStats: () => Promise<void>;
handleFilterChange: (key: string, value: any) => void;
handlePageChange: (page: number) => void;
handlePageSizeChange: (pageSize: number) => void;
handleSortChange: (field: keyof Account, order: 'asc' | 'desc') => void;
handleSelectAll: (checked: boolean) => void;
handleSelectOne: (id: number, checked: boolean) => void;
handleBatchDelete: () => Promise<void>;
handleBatchUpdate: (payload: Partial<Pick<Account, 'status' | 'ownerId' | 'notes' | 'platform'>>) => Promise<void>;
handleUploadAccounts: (accounts: ScriptUploadItem[], ownerId: string) => Promise<void>;
setSelectedIds: (ids: number[]) => void;
}
export function useAccounts(): UseAccountsReturn {
const [accounts, setAccounts] = useState<Account[]>([]);
const [stats, setStats] = useState<StatsOverview | null>(null);
const [loading, setLoading] = useState(false);
const [selectedIds, setSelectedIds] = useState<number[]>([]);
const [pagination, setPagination] = useState({
page: 1,
pageSize: 20,
total: 0,
totalPages: 0
});
const [filters, setFilters] = useState({
platform: '',
status: [] as string[],
ownerId: '',
search: ''
});
const [sort, setSort] = useState({
field: 'id' as keyof Account,
order: 'desc' as 'asc' | 'desc'
});
// 获取统计数据
const fetchStats = async () => {
try {
const response = await apiClient.getStatsOverview();
if (response.code === BusinessCode.Success && response.data) {
setStats(response.data);
}
} catch (error) {
console.error('Failed to fetch stats:', error);
toast.error('获取统计数据失败');
}
};
// 获取账户列表
const fetchAccounts = async () => {
setLoading(true);
try {
const body: ListAccountsBody = {
filters,
pagination: {
page: pagination.page,
pageSize: pagination.pageSize
},
sort
};
const response = await apiClient.getAccountsList(body);
if (response.code === BusinessCode.Success && response.data) {
setAccounts(response.data.list);
setPagination(prev => ({
...prev,
total: response.data.pagination.total,
totalPages: response.data.pagination.totalPages
}));
}
} catch (error) {
console.error('Failed to fetch accounts:', error);
toast.error('获取账户列表失败');
} finally {
setLoading(false);
}
};
// 处理筛选变化
const handleFilterChange = (key: string, value: any) => {
setFilters({ ...filters, [key]: value });
setPagination({ ...pagination, page: 1 });
};
// 处理分页
const handlePageChange = (page: number) => {
setPagination({ ...pagination, page });
};
// 处理每页大小变化
const handlePageSizeChange = (pageSize: number) => {
setPagination({ ...pagination, pageSize, page: 1 });
};
// 处理排序
const handleSortChange = (field: keyof Account, order: 'asc' | 'desc') => {
setSort({ field, order });
};
// 处理全选
const handleSelectAll = (checked: boolean) => {
if (checked) {
setSelectedIds(accounts.map(account => account.id));
} else {
setSelectedIds([]);
}
};
// 处理单选
const handleSelectOne = (id: number, checked: boolean) => {
if (checked) {
setSelectedIds([...selectedIds, id]);
} else {
setSelectedIds(selectedIds.filter(selectedId => selectedId !== id));
}
};
// 批量删除
const handleBatchDelete = async () => {
if (selectedIds.length === 0) return;
if (!confirm(`确认删除 ${selectedIds.length} 个账户?`)) return;
try {
const response = await apiClient.batchDeleteAccounts({ ids: selectedIds });
if (response.code === BusinessCode.Success) {
setSelectedIds([]);
await fetchAccounts();
await fetchStats();
toast.success(`成功删除 ${response.data?.deletedCount || 0} 个账户`);
}
} catch (error) {
console.error('Failed to delete accounts:', error);
toast.error('删除失败,请检查网络连接后重试');
}
};
// 批量更新
const handleBatchUpdate = async (payload: Partial<Pick<Account, 'status' | 'ownerId' | 'notes' | 'platform'>>, targetIds?: number[]) => {
const idsToUpdate = targetIds || selectedIds;
console.log('handleBatchUpdate 被调用, idsToUpdate:', idsToUpdate);
console.log('payload:', payload);
if (idsToUpdate.length === 0) {
console.log('idsToUpdate为空直接返回');
return;
}
if (Object.keys(payload).length === 0) {
toast.warning('请至少选择一个字段进行更新');
return;
}
try {
console.log('发送批量更新请求...');
const response = await apiClient.batchUpdateAccounts({ ids: idsToUpdate, payload });
console.log('批量更新响应:', response);
if (response.code === BusinessCode.Success) {
if (!targetIds) {
// 只有在没有指定目标ID时才清空选中状态批量操作时
setSelectedIds([]);
}
await fetchAccounts();
await fetchStats();
toast.success(`成功更新 ${response.data?.updatedCount || 0} 个账户`);
}
} catch (error) {
console.error('Failed to update accounts:', error);
toast.error('更新失败,请检查网络连接后重试');
}
};
// 上传账户
const handleUploadAccounts = async (uploadAccounts: ScriptUploadItem[], ownerId: string) => {
try {
const response = await apiClient.uploadAccounts(uploadAccounts, ownerId);
if (response.code === BusinessCode.Success) {
await fetchAccounts();
await fetchStats();
toast.success(`成功处理 ${response.data?.processedCount || 0} 个账户 (${response.data?.createdCount || 0} 个新建, ${response.data?.updatedCount || 0} 个更新)`);
return;
}
} catch (error) {
console.error('Failed to upload accounts:', error);
toast.error('上传失败,请检查网络连接后重试');
}
};
// 初始化数据
useEffect(() => {
fetchAccounts();
}, [filters, pagination.page, pagination.pageSize, sort]);
// 只在开始时获取统计数据
useEffect(() => {
fetchStats();
}, []);
return {
accounts,
stats,
loading,
selectedIds,
pagination,
filters,
sort,
fetchAccounts,
fetchStats,
handleFilterChange,
handlePageChange,
handlePageSizeChange,
handleSortChange,
handleSelectAll,
handleSelectOne,
handleBatchDelete,
handleBatchUpdate,
handleUploadAccounts,
setSelectedIds
};
}