mirror of
https://github.com/songquanpeng/one-api.git
synced 2025-09-29 22:56:39 +08:00
246 lines
7.5 KiB
JavaScript
246 lines
7.5 KiB
JavaScript
import { useState, useEffect, useCallback } from 'react';
|
||
import { showError, trims } from 'utils/common';
|
||
|
||
import Table from '@mui/material/Table';
|
||
import TableBody from '@mui/material/TableBody';
|
||
import TableContainer from '@mui/material/TableContainer';
|
||
import PerfectScrollbar from 'react-perfect-scrollbar';
|
||
import TablePagination from '@mui/material/TablePagination';
|
||
import LinearProgress from '@mui/material/LinearProgress';
|
||
import ButtonGroup from '@mui/material/ButtonGroup';
|
||
import Toolbar from '@mui/material/Toolbar';
|
||
|
||
import { Button, Card, Stack, Container, Typography, Box } from '@mui/material';
|
||
import LogTableRow from './component/TableRow';
|
||
import KeywordTableHead from 'ui-component/TableHead';
|
||
import TableToolBar from './component/TableToolBar';
|
||
import { API } from 'utils/api';
|
||
import { isAdmin } from 'utils/common';
|
||
import { ITEMS_PER_PAGE } from 'constants';
|
||
import { IconRefresh, IconSearch } from '@tabler/icons-react';
|
||
import dayjs from 'dayjs';
|
||
|
||
export default function Log() {
|
||
const originalKeyword = {
|
||
p: 0,
|
||
username: '',
|
||
token_name: '',
|
||
model_name: '',
|
||
start_timestamp: 0,
|
||
end_timestamp: dayjs().unix() + 3600,
|
||
log_type: 0,
|
||
channel: ''
|
||
};
|
||
|
||
const [page, setPage] = useState(0);
|
||
const [order, setOrder] = useState('desc');
|
||
const [orderBy, setOrderBy] = useState('created_at');
|
||
const [rowsPerPage, setRowsPerPage] = useState(ITEMS_PER_PAGE);
|
||
const [listCount, setListCount] = useState(0);
|
||
const [searching, setSearching] = useState(false);
|
||
const [toolBarValue, setToolBarValue] = useState(originalKeyword);
|
||
const [searchKeyword, setSearchKeyword] = useState(originalKeyword);
|
||
const [refreshFlag, setRefreshFlag] = useState(false);
|
||
|
||
const [logs, setLogs] = useState([]);
|
||
const userIsAdmin = isAdmin();
|
||
|
||
const handleSort = (event, id) => {
|
||
const isAsc = orderBy === id && order === 'asc';
|
||
if (id !== '') {
|
||
setOrder(isAsc ? 'desc' : 'asc');
|
||
setOrderBy(id);
|
||
}
|
||
};
|
||
|
||
const handleChangePage = (event, newPage) => {
|
||
setPage(newPage);
|
||
};
|
||
|
||
const handleChangeRowsPerPage = (event) => {
|
||
setPage(0);
|
||
setRowsPerPage(parseInt(event.target.value, 10));
|
||
};
|
||
|
||
const searchLogs = async () => {
|
||
setPage(0);
|
||
setSearchKeyword(toolBarValue);
|
||
};
|
||
|
||
const handleToolBarValue = (event) => {
|
||
setToolBarValue({ ...toolBarValue, [event.target.name]: event.target.value });
|
||
};
|
||
|
||
const fetchData = useCallback(
|
||
async (page, rowsPerPage, keyword, order, orderBy) => {
|
||
setSearching(true);
|
||
keyword = trims(keyword);
|
||
try {
|
||
if (orderBy) {
|
||
orderBy = order === 'desc' ? '-' + orderBy : orderBy;
|
||
}
|
||
const url = userIsAdmin ? '/api/log/' : '/api/log/self/';
|
||
if (!userIsAdmin) {
|
||
delete keyword.username;
|
||
delete keyword.channel;
|
||
}
|
||
|
||
const res = await API.get(url, {
|
||
params: {
|
||
page: page + 1,
|
||
size: rowsPerPage,
|
||
order: orderBy,
|
||
...keyword
|
||
}
|
||
});
|
||
const { success, message, data } = res.data;
|
||
if (success) {
|
||
setListCount(data.total_count);
|
||
setLogs(data.data);
|
||
} else {
|
||
showError(message);
|
||
}
|
||
} catch (error) {
|
||
console.error(error);
|
||
}
|
||
setSearching(false);
|
||
},
|
||
[userIsAdmin]
|
||
);
|
||
|
||
// 处理刷新
|
||
const handleRefresh = async () => {
|
||
setOrderBy('created_at');
|
||
setOrder('desc');
|
||
setToolBarValue(originalKeyword);
|
||
setSearchKeyword(originalKeyword);
|
||
setRefreshFlag(!refreshFlag);
|
||
};
|
||
|
||
useEffect(() => {
|
||
fetchData(page, rowsPerPage, searchKeyword, order, orderBy);
|
||
}, [page, rowsPerPage, searchKeyword, order, orderBy, fetchData, refreshFlag]);
|
||
|
||
return (
|
||
<>
|
||
<Stack direction="row" alignItems="center" justifyContent="space-between" mb={5}>
|
||
<Typography variant="h4">日志</Typography>
|
||
</Stack>
|
||
<Card>
|
||
<Box component="form" noValidate>
|
||
<TableToolBar filterName={toolBarValue} handleFilterName={handleToolBarValue} userIsAdmin={userIsAdmin} />
|
||
</Box>
|
||
<Toolbar
|
||
sx={{
|
||
textAlign: 'right',
|
||
height: 50,
|
||
display: 'flex',
|
||
justifyContent: 'space-between',
|
||
p: (theme) => theme.spacing(0, 1, 0, 3)
|
||
}}
|
||
>
|
||
<Container>
|
||
<ButtonGroup variant="outlined" aria-label="outlined small primary button group">
|
||
<Button onClick={handleRefresh} startIcon={<IconRefresh width={'18px'} />}>
|
||
刷新/清除搜索条件
|
||
</Button>
|
||
|
||
<Button onClick={searchLogs} startIcon={<IconSearch width={'18px'} />}>
|
||
搜索
|
||
</Button>
|
||
</ButtonGroup>
|
||
</Container>
|
||
</Toolbar>
|
||
{searching && <LinearProgress />}
|
||
<PerfectScrollbar component="div">
|
||
<TableContainer sx={{ overflow: 'unset' }}>
|
||
<Table sx={{ minWidth: 800 }}>
|
||
<KeywordTableHead
|
||
order={order}
|
||
orderBy={orderBy}
|
||
onRequestSort={handleSort}
|
||
headLabel={[
|
||
{
|
||
id: 'created_at',
|
||
label: '时间',
|
||
disableSort: false
|
||
},
|
||
{
|
||
id: 'channel_id',
|
||
label: '渠道',
|
||
disableSort: false,
|
||
hide: !userIsAdmin
|
||
},
|
||
{
|
||
id: 'user_id',
|
||
label: '用户',
|
||
disableSort: false,
|
||
hide: !userIsAdmin
|
||
},
|
||
{
|
||
id: 'token_name',
|
||
label: '令牌',
|
||
disableSort: false
|
||
},
|
||
{
|
||
id: 'type',
|
||
label: '类型',
|
||
disableSort: false
|
||
},
|
||
{
|
||
id: 'model_name',
|
||
label: '模型',
|
||
disableSort: false
|
||
},
|
||
{
|
||
id: 'duration',
|
||
label: '耗时',
|
||
tooltip: 't/s:输出令牌的数量除以总生成时间,表示生成速度',
|
||
disableSort: true
|
||
},
|
||
{
|
||
id: 'message',
|
||
label: '输入',
|
||
disableSort: true
|
||
},
|
||
{
|
||
id: 'completion',
|
||
label: '输出',
|
||
disableSort: true
|
||
},
|
||
{
|
||
id: 'quota',
|
||
label: '额度',
|
||
disableSort: true
|
||
},
|
||
{
|
||
id: 'detail',
|
||
label: '详情',
|
||
disableSort: true
|
||
}
|
||
]}
|
||
/>
|
||
<TableBody>
|
||
{logs.map((row, index) => (
|
||
<LogTableRow item={row} key={`${row.id}_${index}`} userIsAdmin={userIsAdmin} />
|
||
))}
|
||
</TableBody>
|
||
</Table>
|
||
</TableContainer>
|
||
</PerfectScrollbar>
|
||
<TablePagination
|
||
page={page}
|
||
component="div"
|
||
count={listCount}
|
||
rowsPerPage={rowsPerPage}
|
||
onPageChange={handleChangePage}
|
||
rowsPerPageOptions={[10, 25, 30]}
|
||
onRowsPerPageChange={handleChangeRowsPerPage}
|
||
showFirstButton
|
||
showLastButton
|
||
/>
|
||
</Card>
|
||
</>
|
||
);
|
||
}
|