feat: 账号凭据默认脱敏并支持主动查看

This commit is contained in:
yml2213
2026-08-13 16:32:49 +08:00
parent a223cb726d
commit 2e207f726c
3 changed files with 108 additions and 6 deletions
+34 -5
View File
@@ -5,7 +5,7 @@ import {
} from 'antd';
import { message } from '../utils/antdMessage';
import type { TableProps } from 'antd';
import { ImportOutlined, DeleteOutlined, TagOutlined, FilterOutlined } from '@ant-design/icons';
import { ImportOutlined, DeleteOutlined, TagOutlined, FilterOutlined, EyeOutlined, EyeInvisibleOutlined } from '@ant-design/icons';
import { accountApi, userApi, type AccountItem, type BasicSummary, type UserInfo } from '../api/modules';
import { usePermissions } from '../hooks/usePermissions';
import { formatTime } from '../utils/time';
@@ -33,6 +33,7 @@ export default function AccountsPage() {
const [selectedAllMatching, setSelectedAllMatching] = useState(false);
const [batchTagInput, setBatchTagInput] = useState('');
const [batchTagVisible, setBatchTagVisible] = useState(false);
const [sensitiveVisible, setSensitiveVisible] = useState(false);
const [total, setTotal] = useState(0);
const [summary, setSummary] = useState<BasicSummary>({ total: 0, assigned_count: 0, unassigned_count: 0, tag_count: 0 });
const [pageSize, setPageSize] = useState(() => {
@@ -58,7 +59,7 @@ export default function AccountsPage() {
page: currentPage,
page_size: pageSize,
search: searchText.trim() || undefined,
include_sensitive: canViewFull,
include_sensitive: canViewFull && sensitiveVisible,
});
setAccounts(data.items);
setTotal(data.total);
@@ -67,7 +68,7 @@ export default function AccountsPage() {
} finally {
setLoading(false);
}
}, [canViewFull, currentPage, pageSize, searchText, tagFilter]);
}, [canViewFull, currentPage, pageSize, searchText, sensitiveVisible, tagFilter]);
const loadSummary = useCallback(async () => {
try {
@@ -224,6 +225,27 @@ export default function AccountsPage() {
}
};
const handleSensitiveVisibility = () => {
if (sensitiveVisible) {
// 立即清除已加载的敏感内容,再由 effect 重新获取脱敏列表。
setAccounts((previous) => previous.map((account) => ({
...account,
password: undefined,
email: undefined,
email_password: undefined,
})));
setSensitiveVisible(false);
return;
}
Modal.confirm({
title: '显示账号凭据?',
content: '密码、邮箱和邮箱密码将临时显示在当前页面。关闭或刷新页面后会恢复脱敏。',
okText: '显示',
cancelText: '取消',
onOk: () => setSensitiveVisible(true),
});
};
const columns: TableProps<AccountItem>['columns'] = [
{ title: 'ID', dataIndex: 'id', width: 60 },
{ title: '用户名', dataIndex: 'username' },
@@ -277,8 +299,7 @@ export default function AccountsPage() {
},
];
// 只有管理员可看完整字段(密码、邮箱等)
if (canViewFull) {
if (canViewFull && sensitiveVisible) {
columns.push(
{ title: '密码', dataIndex: 'password', width: 120 },
{ title: '邮箱', dataIndex: 'email' },
@@ -346,6 +367,14 @@ export default function AccountsPage() {
setCurrentPage(1);
}}
/>
{canViewFull && (
<Button
icon={sensitiveVisible ? <EyeInvisibleOutlined /> : <EyeOutlined />}
onClick={handleSensitiveVisibility}
>
{sensitiveVisible ? '隐藏凭据' : '显示凭据'}
</Button>
)}
{canImport && (
<Button
disabled={selectedCount === 0}