Cookie 管理优化
This commit is contained in:
@@ -37,6 +37,8 @@ def list_cookies(
|
|||||||
"batch_id": t.batch_id,
|
"batch_id": t.batch_id,
|
||||||
"account_id": t.account_id,
|
"account_id": t.account_id,
|
||||||
"account_username": acc.username if acc else "",
|
"account_username": acc.username if acc else "",
|
||||||
|
"assigned_to": acc.assigned_to,
|
||||||
|
"assigned_username": acc.assigned_user.username if acc and acc.assigned_user else None,
|
||||||
"created_at": t.finished_at.isoformat() if t.finished_at else None,
|
"created_at": t.finished_at.isoformat() if t.finished_at else None,
|
||||||
}
|
}
|
||||||
# 只有有 cookie:view 权限才返回 cookie 内容
|
# 只有有 cookie:view 权限才返回 cookie 内容
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { Table, Button, Card, Row, Col, Statistic, message, Tag, Popconfirm, Space } from 'antd';
|
import { Table, Button, Card, Row, Col, Statistic, message, Tag, Popconfirm, Space, Typography, Input } from 'antd';
|
||||||
import { DownloadOutlined, DeleteOutlined, CopyOutlined } from '@ant-design/icons';
|
import { DownloadOutlined, DeleteOutlined, CopyOutlined, SearchOutlined } from '@ant-design/icons';
|
||||||
import { cookieApi } from '../api/modules';
|
import { cookieApi } from '../api/modules';
|
||||||
import { getUser, hasPerm } from '../store/auth';
|
import { getUser, hasPerm } from '../store/auth';
|
||||||
|
|
||||||
|
const { Text } = Typography;
|
||||||
|
|
||||||
export default function CookiePage() {
|
export default function CookiePage() {
|
||||||
const [cookies, setCookies] = useState<any[]>([]);
|
const [cookies, setCookies] = useState<any[]>([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
|
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
|
||||||
|
const [searchText, setSearchText] = useState('');
|
||||||
const user = getUser();
|
const user = getUser();
|
||||||
|
|
||||||
const canView = hasPerm(user, 'cookie:view');
|
const canView = hasPerm(user, 'cookie:view');
|
||||||
@@ -83,9 +86,32 @@ export default function CookiePage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 筛选
|
||||||
|
const filteredCookies = cookies.filter((c) => {
|
||||||
|
if (!searchText) return true;
|
||||||
|
const s = searchText.toLowerCase();
|
||||||
|
return (
|
||||||
|
c.account_username?.toLowerCase().includes(s) ||
|
||||||
|
c.assigned_username?.toLowerCase().includes(s)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
const columns: any[] = [
|
const columns: any[] = [
|
||||||
{ title: 'ID', dataIndex: 'id', width: 60 },
|
{ title: 'ID', dataIndex: 'id', width: 60, align: 'center' },
|
||||||
{ title: '账号', dataIndex: 'account_username' },
|
{
|
||||||
|
title: '账号',
|
||||||
|
dataIndex: 'account_username',
|
||||||
|
width: 140,
|
||||||
|
ellipsis: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '分配',
|
||||||
|
dataIndex: 'assigned_username',
|
||||||
|
width: 100,
|
||||||
|
align: 'center',
|
||||||
|
render: (name: string | null) =>
|
||||||
|
name ? <Tag color="green" size="small">{name}</Tag> : <Text type="secondary" style={{ fontSize: 12 }}>未分配</Text>,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'Cookie',
|
title: 'Cookie',
|
||||||
dataIndex: 'cookie_preview',
|
dataIndex: 'cookie_preview',
|
||||||
@@ -95,10 +121,18 @@ export default function CookiePage() {
|
|||||||
return <span style={{ fontFamily: 'monospace', fontSize: 12 }}>{val}</span>;
|
return <span style={{ fontFamily: 'monospace', fontSize: 12 }}>{val}</span>;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ title: '时间', dataIndex: 'created_at', width: 170 },
|
{
|
||||||
|
title: '时间',
|
||||||
|
dataIndex: 'created_at',
|
||||||
|
width: 180,
|
||||||
|
align: 'center',
|
||||||
|
render: (val: string) => val ? val.replace('T', ' ').slice(0, 19) : '-',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
width: 160,
|
width: 130,
|
||||||
|
align: 'center',
|
||||||
|
fixed: 'right',
|
||||||
render: (_: any, record: any) => (
|
render: (_: any, record: any) => (
|
||||||
<Space size={4}>
|
<Space size={4}>
|
||||||
<Button
|
<Button
|
||||||
@@ -118,10 +152,13 @@ export default function CookiePage() {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const assignedCount = cookies.filter((c) => c.assigned_to).length;
|
||||||
|
const unassignedCount = cookies.length - assignedCount;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between' }}>
|
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||||
<h2>Cookie 管理</h2>
|
<h2 style={{ margin: 0 }}>Cookie 管理</h2>
|
||||||
<Space>
|
<Space>
|
||||||
<Button
|
<Button
|
||||||
icon={<CopyOutlined />}
|
icon={<CopyOutlined />}
|
||||||
@@ -137,22 +174,52 @@ export default function CookiePage() {
|
|||||||
)}
|
)}
|
||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
<Row gutter={16} style={{ marginBottom: 16 }}>
|
<Row gutter={12} style={{ marginBottom: 16 }}>
|
||||||
<Col span={6}>
|
<Col span={6}>
|
||||||
<Card size="small"><Statistic title="Cookie 总数" value={cookies.length} /></Card>
|
<Card size="small"><Statistic title="Cookie 总数" value={cookies.length} /></Card>
|
||||||
</Col>
|
</Col>
|
||||||
|
<Col span={6}>
|
||||||
|
<Card size="small">
|
||||||
|
<Statistic
|
||||||
|
title="已分配"
|
||||||
|
value={assignedCount}
|
||||||
|
valueStyle={{ color: '#3f8600' }}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
<Col span={6}>
|
||||||
|
<Card size="small">
|
||||||
|
<Statistic
|
||||||
|
title="未分配"
|
||||||
|
value={unassignedCount}
|
||||||
|
valueStyle={{ color: '#cf1322' }}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
<div style={{ marginBottom: 12 }}>
|
||||||
|
<Input.Search
|
||||||
|
placeholder="搜索账号或分配客服"
|
||||||
|
allowClear
|
||||||
|
value={searchText}
|
||||||
|
onChange={(e) => setSearchText(e.target.value)}
|
||||||
|
style={{ width: 260 }}
|
||||||
|
size="small"
|
||||||
|
prefix={<SearchOutlined />}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<Table
|
<Table
|
||||||
rowSelection={{
|
rowSelection={{
|
||||||
selectedRowKeys,
|
selectedRowKeys,
|
||||||
onChange: (keys) => setSelectedRowKeys(keys),
|
onChange: (keys) => setSelectedRowKeys(keys),
|
||||||
}}
|
}}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
dataSource={cookies}
|
dataSource={filteredCookies}
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
loading={loading}
|
loading={loading}
|
||||||
size="small"
|
size="small"
|
||||||
pagination={{ pageSize: 20 }}
|
pagination={{ pageSize: 20, showSizeChanger: true, showTotal: (t) => `共 ${t} 条` }}
|
||||||
|
scroll={{ x: 900 }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user