83 lines
2.7 KiB
TypeScript
83 lines
2.7 KiB
TypeScript
|
|
import React, { useState } from 'react'
|
||
|
|
import { Card, Table, Tag, Space, Input, Select, Typography } from 'antd'
|
||
|
|
import { SearchOutlined } from '@ant-design/icons'
|
||
|
|
import { useQuery } from '@tanstack/react-query'
|
||
|
|
import api from '@/lib/api'
|
||
|
|
|
||
|
|
const { Title } = Typography
|
||
|
|
|
||
|
|
const statusColors: Record<string, string> = {
|
||
|
|
active: 'blue', suspended: 'orange', completed: 'green',
|
||
|
|
}
|
||
|
|
|
||
|
|
export default function ReviewAdmin() {
|
||
|
|
const [search, setSearch] = useState('')
|
||
|
|
const [statusFilter, setStatusFilter] = useState<string>()
|
||
|
|
|
||
|
|
const { data, isLoading } = useQuery({
|
||
|
|
queryKey: ['admin', 'reviews', search, statusFilter],
|
||
|
|
queryFn: () => api.get('/admin-api/reviews', { params: { search, status: statusFilter } }).then(r => r.data?.data ?? { items: [], total: 0 }),
|
||
|
|
refetchInterval: 30_000,
|
||
|
|
})
|
||
|
|
|
||
|
|
const columns = [
|
||
|
|
{ title: 'ID', dataIndex: 'id', width: 100, ellipsis: true },
|
||
|
|
{ title: '用户', dataIndex: 'userId', width: 100, ellipsis: true },
|
||
|
|
{ title: '正面', dataIndex: 'frontText', width: 200, ellipsis: true },
|
||
|
|
{ title: '难度', dataIndex: 'difficulty', width: 80 },
|
||
|
|
{
|
||
|
|
title: '状态', dataIndex: 'status', width: 80,
|
||
|
|
render: (s: string) => <Tag color={statusColors[s] || 'default'}>{s}</Tag>,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
title: '调度', dataIndex: 'scheduleState', width: 80,
|
||
|
|
render: (s: string) => s || '-',
|
||
|
|
},
|
||
|
|
{ title: '间隔(天)', dataIndex: 'intervalDays', width: 80 },
|
||
|
|
{ title: '复习次数', dataIndex: 'repetitionCount', width: 80 },
|
||
|
|
{ title: '失误次数', dataIndex: 'lapseCount', width: 80 },
|
||
|
|
{
|
||
|
|
title: '下次复习', dataIndex: 'nextReviewAt', width: 120,
|
||
|
|
render: (d: string) => d ? new Date(d).toLocaleDateString() : '-',
|
||
|
|
},
|
||
|
|
]
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div>
|
||
|
|
<Title level={4}>复习数据管理</Title>
|
||
|
|
<Space style={{ marginBottom: 16 }}>
|
||
|
|
<Input
|
||
|
|
placeholder="搜索卡片内容"
|
||
|
|
prefix={<SearchOutlined />}
|
||
|
|
value={search}
|
||
|
|
onChange={e => setSearch(e.target.value)}
|
||
|
|
style={{ width: 240 }}
|
||
|
|
allowClear
|
||
|
|
/>
|
||
|
|
<Select
|
||
|
|
placeholder="状态筛选"
|
||
|
|
value={statusFilter}
|
||
|
|
onChange={setStatusFilter}
|
||
|
|
allowClear
|
||
|
|
style={{ width: 120 }}
|
||
|
|
options={[
|
||
|
|
{ label: '全部', value: undefined },
|
||
|
|
{ label: 'Active', value: 'active' },
|
||
|
|
{ label: 'Suspended', value: 'suspended' },
|
||
|
|
{ label: 'Completed', value: 'completed' },
|
||
|
|
]}
|
||
|
|
/>
|
||
|
|
</Space>
|
||
|
|
<Table
|
||
|
|
dataSource={data?.items || []}
|
||
|
|
columns={columns}
|
||
|
|
rowKey="id"
|
||
|
|
loading={isLoading}
|
||
|
|
pagination={{ total: data?.total || 0 }}
|
||
|
|
size="small"
|
||
|
|
scroll={{ x: 1100 }}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|