175 lines
5.6 KiB
TypeScript
175 lines
5.6 KiB
TypeScript
'use client';
|
||
|
||
import { ProTable, ProTableActions } from '@/components/pro-table';
|
||
import { getTicket, getTicketList, updateTicketStatus } from '@/services/admin/ticket';
|
||
import { useQuery } from '@tanstack/react-query';
|
||
import { Button } from '@workspace/ui/components/button';
|
||
import { Drawer, DrawerContent, DrawerHeader, DrawerTitle } from '@workspace/ui/components/drawer';
|
||
import { ScrollArea } from '@workspace/ui/components/scroll-area';
|
||
import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button';
|
||
import { cn } from '@workspace/ui/lib/utils';
|
||
import { formatDate } from '@workspace/ui/utils';
|
||
import { useTranslations } from 'next-intl';
|
||
import NextImage from 'next/legacy/image';
|
||
import { useEffect, useRef, useState } from 'react';
|
||
import { toast } from 'sonner';
|
||
import { UserDetail } from '../user/user-detail';
|
||
|
||
export default function Page() {
|
||
const t = useTranslations('ticket');
|
||
|
||
const [ticketId, setTicketId] = useState<any>(null);
|
||
|
||
const [message, setMessage] = useState('');
|
||
|
||
const { data: ticket, refetch: refetchTicket } = useQuery({
|
||
queryKey: ['getTicket', ticketId],
|
||
queryFn: async () => {
|
||
const { data } = await getTicket({
|
||
id: ticketId,
|
||
});
|
||
return data.data as API.Ticket;
|
||
},
|
||
enabled: !!ticketId,
|
||
refetchInterval: 5000,
|
||
});
|
||
|
||
const scrollRef = useRef<HTMLDivElement | null>(null);
|
||
useEffect(() => {
|
||
setTimeout(() => {
|
||
if (scrollRef.current) {
|
||
scrollRef.current.children[1]?.scrollTo({
|
||
top: scrollRef.current.children[1].scrollHeight,
|
||
behavior: 'smooth',
|
||
});
|
||
}
|
||
}, 66);
|
||
}, [ticket?.follow?.length]);
|
||
|
||
const ref = useRef<ProTableActions>(null);
|
||
return (
|
||
<>
|
||
<ProTable<API.Ticket, { status: number }>
|
||
action={ref}
|
||
header={{
|
||
title: t('ticketList'),
|
||
}}
|
||
columns={[
|
||
{
|
||
accessorKey: 'title',
|
||
header: t('title'),
|
||
},
|
||
{
|
||
accessorKey: 'user_id',
|
||
header: t('user'),
|
||
cell: ({ row }) => <UserDetail id={row.original.user_id} />,
|
||
},
|
||
{
|
||
accessorKey: 'updated_at',
|
||
header: t('updatedAt'),
|
||
cell: ({ row }) => formatDate(row.getValue('updated_at')),
|
||
},
|
||
]}
|
||
/* params={[
|
||
{
|
||
key: 'status',
|
||
placeholder: t('status.0'),
|
||
options: [
|
||
{
|
||
label: t('close'),
|
||
value: '4',
|
||
},
|
||
],
|
||
},
|
||
]}*/
|
||
request={async (pagination, filters) => {
|
||
const { data } = await getTicketList({
|
||
...pagination,
|
||
...filters,
|
||
issue_type: 1,
|
||
});
|
||
return {
|
||
list: data.data?.list || [],
|
||
total: data.data?.total || 0,
|
||
};
|
||
}}
|
||
actions={{
|
||
render(row) {
|
||
if (row.status !== 4) {
|
||
return [
|
||
<Button key='reply' size='sm' onClick={() => setTicketId(row.id)}>
|
||
{t('check')}
|
||
</Button>,
|
||
<ConfirmButton
|
||
key='colse'
|
||
trigger={
|
||
<Button size='sm' variant='destructive'>
|
||
{t('close')}
|
||
</Button>
|
||
}
|
||
title={t('confirmClose')}
|
||
description={t('closeWarning')}
|
||
onConfirm={async () => {
|
||
await updateTicketStatus({
|
||
id: row.id,
|
||
status: 4,
|
||
});
|
||
toast.success(t('closeSuccess'));
|
||
ref.current?.refresh();
|
||
}}
|
||
cancelText={t('cancel')}
|
||
confirmText={t('confirm')}
|
||
/>,
|
||
];
|
||
}
|
||
return [
|
||
<Button key='check' size='sm' onClick={() => setTicketId(row.id)}>
|
||
{t('check')}
|
||
</Button>,
|
||
];
|
||
},
|
||
}}
|
||
/>
|
||
|
||
<Drawer
|
||
open={!!ticketId}
|
||
onOpenChange={(open) => {
|
||
if (!open) setTicketId(null);
|
||
}}
|
||
>
|
||
<DrawerContent className='container mx-auto h-screen'>
|
||
<DrawerHeader className='border-b text-left'>
|
||
<DrawerTitle>{ticket?.title}</DrawerTitle>
|
||
</DrawerHeader>
|
||
<ScrollArea className='h-full overflow-hidden' ref={scrollRef}>
|
||
<div className='flex h-full flex-col gap-4 p-4'>
|
||
<div className={cn('flex items-center gap-4', {})}>
|
||
<div className={cn('flex flex-col gap-1', {})}>
|
||
<div className={cn('bg-accent w-fit rounded-lg p-2 font-medium', {})}>
|
||
<div> 提现金额:{ticket?.title?.split('-')[1]}</div>
|
||
<div> 提现方式:{ticket?.description?.split('-')[0]}</div>
|
||
{ticket?.description?.split('-')[1]?.includes('data:image') ? (
|
||
<div>
|
||
<div>收款码:</div>
|
||
<NextImage
|
||
src={ticket?.description?.split('-')[1]!}
|
||
width={300}
|
||
height={300}
|
||
className='!size-auto object-cover'
|
||
alt='image'
|
||
/>
|
||
</div>
|
||
) : (
|
||
<div>提现地址:{ticket?.description?.split('-')[1]}</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</ScrollArea>
|
||
</DrawerContent>
|
||
</Drawer>
|
||
</>
|
||
);
|
||
}
|