feat: 增加了任务列表
This commit is contained in:
parent
0414f0b654
commit
9b7f68b86f
|
|
@ -1,12 +1,14 @@
|
|||
import { ConfirmDialog } from '@/components/block/confirm-dialog';
|
||||
import { Sidebar, SidebarContent, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider } from '@/components/ui/sidebar';
|
||||
import { Home, Users } from 'lucide-react';
|
||||
import { Home, List, Users } from 'lucide-react';
|
||||
import { Link, Route, Routes, useLocation } from 'react-router-dom';
|
||||
import ModelPage from './pages/ModelPage';
|
||||
import TryOnPage from './pages/TryOnPage';
|
||||
import TasksPage from './pages/TasksPage';
|
||||
|
||||
const menu = [
|
||||
{ path: '/', label: '首页', icon: <Home className='mr-2' /> },
|
||||
{ path: '/tasks', label: '任务列表', icon: <List className='mr-2' /> },
|
||||
{ path: '/models', label: '模特维护', icon: <Users className='mr-2' /> },
|
||||
];
|
||||
|
||||
|
|
@ -36,6 +38,7 @@ function App() {
|
|||
<Routes>
|
||||
<Route path='/' element={<TryOnPage />} />
|
||||
<Route path='/models' element={<ModelPage />} />
|
||||
<Route path='/tasks' element={<TasksPage />} />
|
||||
</Routes>
|
||||
</main>
|
||||
<ConfirmDialog />
|
||||
|
|
|
|||
|
|
@ -227,13 +227,13 @@ export class DefaultService {
|
|||
* @returns PaginationResponse Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static getImageDataListApiImageDataListGet({
|
||||
public static getImageDataListApiImageDataListPost({
|
||||
requestBody,
|
||||
}: {
|
||||
requestBody: VideoDataPaginationRequest,
|
||||
}): CancelablePromise<PaginationResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'GET',
|
||||
method: 'POST',
|
||||
url: '/api/image/data/list',
|
||||
body: requestBody,
|
||||
mediaType: 'application/json',
|
||||
|
|
|
|||
|
|
@ -75,75 +75,24 @@ const ModelPage: React.FC = () => {
|
|||
<h1 className='text-2xl font-bold'>模特维护</h1>
|
||||
<Button onClick={handleAdd}>新建模特</Button>
|
||||
</div>
|
||||
<div className='grid grid-cols-1 sm:grid-cols-3 lg:grid-cols-4 gap-6'>
|
||||
<div className='grid gap-6 grid-cols-[repeat(auto-fit,minmax(500px,500px))]'>
|
||||
{models.map(item => (
|
||||
<div
|
||||
key={item.id}
|
||||
className='
|
||||
relative
|
||||
rounded-2xl
|
||||
bg-gradient-to-br from-white/80 via-zinc-100/60 to-blue-50/60
|
||||
dark:from-zinc-900/80 dark:via-zinc-800/60 dark:to-blue-950/60
|
||||
shadow-xl
|
||||
border border-zinc-200 dark:border-zinc-800
|
||||
backdrop-blur-md
|
||||
p-5 flex gap-4
|
||||
transition-transform hover:-translate-y-1 hover:shadow-2xl
|
||||
group
|
||||
'
|
||||
>
|
||||
<div className='relative'>
|
||||
<img
|
||||
src={item.cover_url}
|
||||
alt='cover'
|
||||
className='
|
||||
w-[120px] aspect-[9/16] object-cover rounded-xl
|
||||
shadow-md
|
||||
transition-transform group-hover:scale-105
|
||||
'
|
||||
/>
|
||||
<span className='absolute top-2 left-2 bg-blue-500/80 text-white text-xs px-2 py-0.5 rounded-full shadow'>
|
||||
{item.status === 1 ? '启用' : '禁用'}
|
||||
</span>
|
||||
</div>
|
||||
<div key={item.id} className='w-[500px] bg-white dark:bg-zinc-900 rounded-lg shadow p-4 flex gap-3'>
|
||||
<img src={item.cover_url} alt='cover' className='w-[200px] object-cover rounded aspect-[9/16]' />
|
||||
<div className='flex-1 flex flex-col gap-2'>
|
||||
<div className='flex-1 flex flex-col gap-1'>
|
||||
<div className='text-xs text-zinc-400'>ID: {item.id}</div>
|
||||
<div className='text-sm font-medium text-zinc-700 dark:text-zinc-200 truncate'>
|
||||
标签:
|
||||
{Object.values(item.tag).map((t, i) => (
|
||||
<span
|
||||
key={i}
|
||||
className='inline-block bg-blue-100 dark:bg-blue-900/40 text-blue-600 dark:text-blue-300 rounded px-2 py-0.5 mx-1 text-xs'
|
||||
>
|
||||
{t}
|
||||
</span>
|
||||
))}
|
||||
<div className='text-sm text-muted-foreground'>ID: {item.id}</div>
|
||||
<div className='text-sm truncate'>标签: {Object.values(item.tag).join('_')}</div>
|
||||
<div className='text-sm'>
|
||||
状态: <span className={item.status === 1 ? 'text-green-600' : 'text-red-500'}>{item.status === 1 ? '启用' : '禁用'}</span>
|
||||
</div>
|
||||
<div className='text-xs text-zinc-400'>创建时间: {item.create_time}</div>
|
||||
<div className='text-xs text-muted-foreground'>创建时间: {item.create_time}</div>
|
||||
</div>
|
||||
<div className='mt-4 flex gap-2'>
|
||||
<Button
|
||||
variant='outline'
|
||||
onClick={() => handleEdit(item)}
|
||||
className='
|
||||
flex-1 rounded-lg border-blue-400
|
||||
hover:border-blue-600 hover:bg-blue-50
|
||||
transition-all
|
||||
'
|
||||
>
|
||||
<div className='mt-4 flex flex-col gap-2'>
|
||||
<Button variant='outline' onClick={() => handleEdit(item)} className='flex-1'>
|
||||
编辑
|
||||
</Button>
|
||||
<Button
|
||||
variant='destructive'
|
||||
onClick={() => handleDelete(item.id)}
|
||||
className='
|
||||
flex-1 rounded-lg border-pink-400
|
||||
hover:border-pink-600 hover:bg-pink-50
|
||||
transition-all
|
||||
'
|
||||
disabled={item.status === 1}
|
||||
>
|
||||
<Button variant='destructive' onClick={() => handleDelete(item.id)} className='flex-1' disabled={item.status === 1}>
|
||||
删除
|
||||
</Button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,106 @@
|
|||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { useApi } from '@/hooks/useApi';
|
||||
import { api } from '@/lib/api';
|
||||
import type { VideoDataPaginationRequest } from '@/api/models/VideoDataPaginationRequest';
|
||||
import type { PaginationResponse } from '@/api/models/PaginationResponse';
|
||||
import { Table, TableHeader, TableBody, TableHead, TableRow, TableCell } from '@/components/ui/table';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Skeleton } from '@/components/ui/skeleton';
|
||||
import { Dialog, DialogContent } from '@/components/ui/dialog';
|
||||
|
||||
const PAGE_SIZE = 10;
|
||||
|
||||
const TasksPage: React.FC = () => {
|
||||
const [page, setPage] = useState(1);
|
||||
const [previewImg, setPreviewImg] = useState<string | null>(null);
|
||||
const [dialogOpen, setDialogOpen] = useState(false);
|
||||
|
||||
const r = useCallback(async (params: VideoDataPaginationRequest) => {
|
||||
const res = await api.DefaultService.getImageDataListApiImageDataListPost({ requestBody: params });
|
||||
return res;
|
||||
}, []);
|
||||
|
||||
const { data, loading, error, execute } = useApi<PaginationResponse>(r, null);
|
||||
|
||||
useEffect(() => {
|
||||
execute({ page, page_size: PAGE_SIZE });
|
||||
}, [page, execute]);
|
||||
|
||||
const handlePrev = () => setPage(p => Math.max(1, p - 1));
|
||||
const handleNext = () => setPage(p => p + 1);
|
||||
|
||||
return (
|
||||
<div className='p-6'>
|
||||
{/* 图片预览 Dialog */}
|
||||
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
|
||||
<DialogContent style={{ maxHeight: '80vh' }} className='flex items-center justify-center' showCloseButton={false}>
|
||||
{previewImg && <img src={previewImg} alt='预览图片' className='object-contain rounded shadow-lg max-h-[calc(80vh-100px)]' />}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
<h2 className='text-xl font-bold mb-4'>任务列表</h2>
|
||||
{loading ? (
|
||||
<Skeleton className='h-40 w-full mb-4' />
|
||||
) : error ? (
|
||||
<div className='text-red-500 mb-4'>{error}</div>
|
||||
) : (
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>图片</TableHead>
|
||||
<TableHead>ID</TableHead>
|
||||
<TableHead>任务ID</TableHead>
|
||||
<TableHead>图片状态</TableHead>
|
||||
<TableHead>视频状态</TableHead>
|
||||
<TableHead>创建时间</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{data?.data?.length ? (
|
||||
data.data.map(item => (
|
||||
<TableRow key={item.id}>
|
||||
<TableCell>
|
||||
{item.img_url ? (
|
||||
<img
|
||||
src={item.img_url}
|
||||
alt='img'
|
||||
className='w-16 h-16 object-cover rounded cursor-pointer transition hover:scale-105'
|
||||
onClick={() => {
|
||||
setPreviewImg(item.img_url!);
|
||||
setDialogOpen(true);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<span className='text-gray-400'>无</span>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell>{item.id}</TableCell>
|
||||
<TableCell>{item.task_id}</TableCell>
|
||||
<TableCell>{item.img_status || '-'}</TableCell>
|
||||
<TableCell>{item.video_status || '-'}</TableCell>
|
||||
<TableCell>{item.create_time || '-'}</TableCell>
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={6} className='text-center text-gray-400'>
|
||||
暂无数据
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
)}
|
||||
<div className='flex justify-between items-center mt-4'>
|
||||
<Button variant='outline' onClick={handlePrev} disabled={page === 1 || loading}>
|
||||
上一页
|
||||
</Button>
|
||||
<span>第 {page} 页</span>
|
||||
<Button variant='outline' onClick={handleNext} disabled={loading || (data?.data && data.data.length < PAGE_SIZE)}>
|
||||
下一页
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TasksPage;
|
||||
Loading…
Reference in New Issue