|
|
@@ -1,6 +1,6 @@
|
|
|
import React, { useState } from 'react';
|
|
|
import { useQuery, useMutation } from '@tanstack/react-query';
|
|
|
-import { Plus, Edit, Trash2, Search } from 'lucide-react';
|
|
|
+import { Plus, Edit, Trash2, Search, Ban, Check } from 'lucide-react';
|
|
|
import { format } from 'date-fns';
|
|
|
import { Input } from '@d8d/shared-ui-components/components/ui/input';
|
|
|
import { Button } from '@d8d/shared-ui-components/components/ui/button';
|
|
|
@@ -25,12 +25,32 @@ interface PlatformSearchParams {
|
|
|
|
|
|
import type { PlatformResponse } from '../api/types';
|
|
|
|
|
|
+// 平台状态枚举
|
|
|
+enum PlatformStatus {
|
|
|
+ ENABLED = 1,
|
|
|
+ DISABLED = 0
|
|
|
+}
|
|
|
+
|
|
|
+// 状态文本映射
|
|
|
+const statusTextMap: Record<number, string> = {
|
|
|
+ [PlatformStatus.ENABLED]: '正常',
|
|
|
+ [PlatformStatus.DISABLED]: '禁用'
|
|
|
+};
|
|
|
+
|
|
|
+// 状态样式映射
|
|
|
+const statusClassMap: Record<number, string> = {
|
|
|
+ [PlatformStatus.ENABLED]: 'text-green-600',
|
|
|
+ [PlatformStatus.DISABLED]: 'text-gray-400'
|
|
|
+};
|
|
|
+
|
|
|
const PlatformManagement: React.FC = () => {
|
|
|
const [searchParams, setSearchParams] = useState<PlatformSearchParams>({ page: 1, limit: 10, search: '' });
|
|
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
|
const [isCreateForm, setIsCreateForm] = useState(true);
|
|
|
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
|
|
const [platformToDelete, setPlatformToDelete] = useState<number | null>(null);
|
|
|
+ const [toggleDialogOpen, setToggleDialogOpen] = useState(false);
|
|
|
+ const [platformToToggle, setPlatformToToggle] = useState<{ id: number; status: number; name: string } | null>(null);
|
|
|
|
|
|
// 表单实例
|
|
|
const createForm = useForm<CreatePlatformRequest>({
|
|
|
@@ -54,8 +74,8 @@ const PlatformManagement: React.FC = () => {
|
|
|
queryFn: async () => {
|
|
|
const res = await platformClientManager.get().getAllPlatforms.$get({
|
|
|
query: {
|
|
|
- skip: (searchParams.page - 1) * searchParams.limit,
|
|
|
- take: searchParams.limit
|
|
|
+ page: searchParams.page,
|
|
|
+ limit: searchParams.limit
|
|
|
}
|
|
|
});
|
|
|
if (res.status !== 200) throw new Error('获取平台列表失败');
|
|
|
@@ -124,6 +144,24 @@ const PlatformManagement: React.FC = () => {
|
|
|
}
|
|
|
});
|
|
|
|
|
|
+ // 切换平台状态
|
|
|
+ const toggleStatusMutation = useMutation({
|
|
|
+ mutationFn: async (data: { id: number; status: '0' | '1' }) => {
|
|
|
+ const res = await platformClientManager.get().togglePlatformStatus.$post({ json: data });
|
|
|
+ if (res.status !== 200) throw new Error('操作失败');
|
|
|
+ return await res.json();
|
|
|
+ },
|
|
|
+ onSuccess: () => {
|
|
|
+ toast.success('平台状态已更新');
|
|
|
+ setToggleDialogOpen(false);
|
|
|
+ setPlatformToToggle(null);
|
|
|
+ refetch();
|
|
|
+ },
|
|
|
+ onError: (error) => {
|
|
|
+ toast.error(error instanceof Error ? error.message : '操作失败');
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
// 处理搜索
|
|
|
const handleSearch = (e: React.FormEvent) => {
|
|
|
e.preventDefault();
|
|
|
@@ -132,9 +170,9 @@ const PlatformManagement: React.FC = () => {
|
|
|
const searchQuery = async () => {
|
|
|
const res = await platformClientManager.get().searchPlatforms.$get({
|
|
|
query: {
|
|
|
- name: searchParams.search,
|
|
|
- skip: 0,
|
|
|
- take: searchParams.limit
|
|
|
+ search: searchParams.search,
|
|
|
+ page: 1,
|
|
|
+ limit: searchParams.limit
|
|
|
}
|
|
|
});
|
|
|
if (res.status !== 200) throw new Error('搜索平台失败');
|
|
|
@@ -186,22 +224,35 @@ const PlatformManagement: React.FC = () => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+ // 处理切换状态
|
|
|
+ const handleToggleStatus = (platform: PlatformResponse) => {
|
|
|
+ setPlatformToToggle({
|
|
|
+ id: platform.id,
|
|
|
+ status: platform.status ?? PlatformStatus.ENABLED,
|
|
|
+ name: platform.platformName || ''
|
|
|
+ });
|
|
|
+ setToggleDialogOpen(true);
|
|
|
+ };
|
|
|
+
|
|
|
+ // 确认切换状态
|
|
|
+ const confirmToggleStatus = () => {
|
|
|
+ if (platformToToggle) {
|
|
|
+ const newStatus = platformToToggle.status === PlatformStatus.ENABLED ? '0' : '1';
|
|
|
+ toggleStatusMutation.mutate({
|
|
|
+ id: platformToToggle.id,
|
|
|
+ status: newStatus
|
|
|
+ });
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
// 处理创建表单提交
|
|
|
const handleCreateSubmit = async (data: CreatePlatformRequest) => {
|
|
|
- try {
|
|
|
- await createMutation.mutateAsync(data);
|
|
|
- } catch (error) {
|
|
|
- throw error;
|
|
|
- }
|
|
|
+ await createMutation.mutateAsync(data);
|
|
|
};
|
|
|
|
|
|
// 处理编辑表单提交
|
|
|
const handleUpdateSubmit = async (data: UpdatePlatformRequest) => {
|
|
|
- try {
|
|
|
- await updateMutation.mutateAsync(data);
|
|
|
- } catch (error) {
|
|
|
- throw error;
|
|
|
- }
|
|
|
+ await updateMutation.mutateAsync(data);
|
|
|
};
|
|
|
|
|
|
// 日期格式化函数
|
|
|
@@ -211,7 +262,7 @@ const PlatformManagement: React.FC = () => {
|
|
|
const date = new Date(dateString);
|
|
|
if (isNaN(date.getTime())) return dateString;
|
|
|
return format(date, 'yyyy-MM-dd HH:mm');
|
|
|
- } catch (error) {
|
|
|
+ } catch (_error) {
|
|
|
return dateString;
|
|
|
}
|
|
|
};
|
|
|
@@ -257,6 +308,7 @@ const PlatformManagement: React.FC = () => {
|
|
|
<TableRow>
|
|
|
<TableHead>平台ID</TableHead>
|
|
|
<TableHead>平台名称</TableHead>
|
|
|
+ <TableHead>状态</TableHead>
|
|
|
<TableHead>联系人</TableHead>
|
|
|
<TableHead>联系电话</TableHead>
|
|
|
<TableHead>联系邮箱</TableHead>
|
|
|
@@ -270,6 +322,7 @@ const PlatformManagement: React.FC = () => {
|
|
|
<TableRow key={index}>
|
|
|
<TableCell><Skeleton className="h-4 w-8" /></TableCell>
|
|
|
<TableCell><Skeleton className="h-4 w-32" /></TableCell>
|
|
|
+ <TableCell><Skeleton className="h-4 w-12" /></TableCell>
|
|
|
<TableCell><Skeleton className="h-4 w-20" /></TableCell>
|
|
|
<TableCell><Skeleton className="h-4 w-24" /></TableCell>
|
|
|
<TableCell><Skeleton className="h-4 w-32" /></TableCell>
|
|
|
@@ -278,44 +331,68 @@ const PlatformManagement: React.FC = () => {
|
|
|
<div className="flex justify-end gap-2">
|
|
|
<Skeleton className="h-8 w-8 rounded" />
|
|
|
<Skeleton className="h-8 w-8 rounded" />
|
|
|
+ <Skeleton className="h-8 w-8 rounded" />
|
|
|
</div>
|
|
|
</TableCell>
|
|
|
</TableRow>
|
|
|
))
|
|
|
) : data?.data && data.data.length > 0 ? (
|
|
|
- data.data.map((platform: PlatformResponse) => (
|
|
|
- <TableRow key={platform.id}>
|
|
|
- <TableCell>{platform.id}</TableCell>
|
|
|
- <TableCell>{platform.platformName || '-'}</TableCell>
|
|
|
- <TableCell>{platform.contactPerson || '-'}</TableCell>
|
|
|
- <TableCell>{platform.contactPhone || '-'}</TableCell>
|
|
|
- <TableCell>{platform.contactEmail || '-'}</TableCell>
|
|
|
- <TableCell>{formatDate(platform.createTime)}</TableCell>
|
|
|
- <TableCell className="text-right">
|
|
|
- <div className="flex justify-end gap-2">
|
|
|
- <Button
|
|
|
- variant="ghost"
|
|
|
- size="icon"
|
|
|
- onClick={() => handleEditPlatform(platform)}
|
|
|
- data-testid={`edit-button-${platform.id}`}
|
|
|
- >
|
|
|
- <Edit className="h-4 w-4" />
|
|
|
- </Button>
|
|
|
- <Button
|
|
|
- variant="ghost"
|
|
|
- size="icon"
|
|
|
- onClick={() => handleDeletePlatform(platform.id)}
|
|
|
- data-testid={`delete-button-${platform.id}`}
|
|
|
- >
|
|
|
- <Trash2 className="h-4 w-4" />
|
|
|
- </Button>
|
|
|
- </div>
|
|
|
- </TableCell>
|
|
|
- </TableRow>
|
|
|
- ))
|
|
|
+ data.data.map((platform: PlatformResponse) => {
|
|
|
+ const status = platform.status ?? PlatformStatus.ENABLED;
|
|
|
+ return (
|
|
|
+ <TableRow key={platform.id}>
|
|
|
+ <TableCell>{platform.id}</TableCell>
|
|
|
+ <TableCell>{platform.platformName || '-'}</TableCell>
|
|
|
+ <TableCell>
|
|
|
+ <span className={statusClassMap[status]}>
|
|
|
+ {statusTextMap[status]}
|
|
|
+ </span>
|
|
|
+ </TableCell>
|
|
|
+ <TableCell>{platform.contactPerson || '-'}</TableCell>
|
|
|
+ <TableCell>{platform.contactPhone || '-'}</TableCell>
|
|
|
+ <TableCell>{platform.contactEmail || '-'}</TableCell>
|
|
|
+ <TableCell>{formatDate(platform.createTime)}</TableCell>
|
|
|
+ <TableCell className="text-right">
|
|
|
+ <div className="flex justify-end gap-2">
|
|
|
+ <Button
|
|
|
+ variant="ghost"
|
|
|
+ size="icon"
|
|
|
+ onClick={() => handleEditPlatform(platform)}
|
|
|
+ data-testid={`edit-button-${platform.id}`}
|
|
|
+ >
|
|
|
+ <Edit className="h-4 w-4" />
|
|
|
+ </Button>
|
|
|
+ {/* 禁用/启用按钮 */}
|
|
|
+ <Button
|
|
|
+ variant="ghost"
|
|
|
+ size="icon"
|
|
|
+ onClick={() => handleToggleStatus(platform)}
|
|
|
+ data-testid={`toggle-button-${platform.id}`}
|
|
|
+ title={status === PlatformStatus.ENABLED ? '禁用平台' : '启用平台'}
|
|
|
+ >
|
|
|
+ {status === PlatformStatus.ENABLED ? (
|
|
|
+ <Ban className="h-4 w-4" />
|
|
|
+ ) : (
|
|
|
+ <Check className="h-4 w-4" />
|
|
|
+ )}
|
|
|
+ </Button>
|
|
|
+ <Button
|
|
|
+ variant="ghost"
|
|
|
+ size="icon"
|
|
|
+ onClick={() => handleDeletePlatform(platform.id)}
|
|
|
+ data-testid={`delete-button-${platform.id}`}
|
|
|
+ title="删除平台"
|
|
|
+ >
|
|
|
+ <Trash2 className="h-4 w-4" />
|
|
|
+ </Button>
|
|
|
+ </div>
|
|
|
+ </TableCell>
|
|
|
+ </TableRow>
|
|
|
+ );
|
|
|
+ })
|
|
|
) : (
|
|
|
<TableRow>
|
|
|
- <TableCell colSpan={7} className="text-center py-8">
|
|
|
+ <TableCell colSpan={8} className="text-center py-8">
|
|
|
<p className="text-muted-foreground">暂无平台数据</p>
|
|
|
</TableCell>
|
|
|
</TableRow>
|
|
|
@@ -512,7 +589,7 @@ const PlatformManagement: React.FC = () => {
|
|
|
<DialogHeader>
|
|
|
<DialogTitle>确认删除</DialogTitle>
|
|
|
<DialogDescription>
|
|
|
- 确定要删除这个平台吗?此操作无法撤销。
|
|
|
+ 确定要删除这个平台吗?此操作将永久删除该平台,无法撤销。
|
|
|
</DialogDescription>
|
|
|
</DialogHeader>
|
|
|
<DialogFooter>
|
|
|
@@ -530,8 +607,38 @@ const PlatformManagement: React.FC = () => {
|
|
|
</DialogFooter>
|
|
|
</DialogContent>
|
|
|
</Dialog>
|
|
|
+
|
|
|
+ {/* 切换状态确认对话框 */}
|
|
|
+ <Dialog open={toggleDialogOpen} onOpenChange={setToggleDialogOpen}>
|
|
|
+ <DialogContent>
|
|
|
+ <DialogHeader>
|
|
|
+ <DialogTitle>
|
|
|
+ {platformToToggle?.status === PlatformStatus.ENABLED ? '确认禁用' : '确认启用'}
|
|
|
+ </DialogTitle>
|
|
|
+ <DialogDescription>
|
|
|
+ {platformToToggle?.status === PlatformStatus.ENABLED
|
|
|
+ ? `确定要禁用平台"${platformToToggle?.name}"吗?禁用后该平台将不可用。`
|
|
|
+ : `确定要启用平台"${platformToToggle?.name}"吗?`
|
|
|
+ }
|
|
|
+ </DialogDescription>
|
|
|
+ </DialogHeader>
|
|
|
+ <DialogFooter>
|
|
|
+ <Button variant="outline" onClick={() => setToggleDialogOpen(false)}>
|
|
|
+ 取消
|
|
|
+ </Button>
|
|
|
+ <Button
|
|
|
+ variant={platformToToggle?.status === PlatformStatus.ENABLED ? 'destructive' : 'default'}
|
|
|
+ onClick={confirmToggleStatus}
|
|
|
+ disabled={toggleStatusMutation.isPending}
|
|
|
+ data-testid="confirm-toggle-button"
|
|
|
+ >
|
|
|
+ {toggleStatusMutation.isPending ? '处理中...' : platformToToggle?.status === PlatformStatus.ENABLED ? '禁用' : '启用'}
|
|
|
+ </Button>
|
|
|
+ </DialogFooter>
|
|
|
+ </DialogContent>
|
|
|
+ </Dialog>
|
|
|
</div>
|
|
|
);
|
|
|
};
|
|
|
|
|
|
-export default PlatformManagement;
|
|
|
+export default PlatformManagement;
|