Merge commit from fork

fix: harden token search with pagination, rate limiting and input validation
This commit is contained in:
Calcium-Ion
2026-02-06 17:54:40 +08:00
committed by GitHub
11 changed files with 282 additions and 20 deletions

View File

@@ -78,6 +78,9 @@ const OperationSetting = () => {
'checkin_setting.enabled': false,
'checkin_setting.min_quota': 1000,
'checkin_setting.max_quota': 10000,
/* 令牌设置 */
'token_setting.max_user_tokens': 1000,
});
let [loading, setLoading] = useState(false);

View File

@@ -40,6 +40,7 @@ export const useTokensData = (openFluentNotification) => {
const [tokenCount, setTokenCount] = useState(0);
const [pageSize, setPageSize] = useState(ITEMS_PER_PAGE);
const [searching, setSearching] = useState(false);
const [searchMode, setSearchMode] = useState(false); // 是否处于搜索结果视图
// Selection state
const [selectedKeys, setSelectedKeys] = useState([]);
@@ -91,6 +92,7 @@ export const useTokensData = (openFluentNotification) => {
// Load tokens function
const loadTokens = async (page = 1, size = pageSize) => {
setLoading(true);
setSearchMode(false);
const res = await API.get(`/api/token/?p=${page}&size=${size}`);
const { success, message, data } = res.data;
if (success) {
@@ -188,21 +190,21 @@ export const useTokensData = (openFluentNotification) => {
};
// Search tokens function
const searchTokens = async () => {
const searchTokens = async (page = 1, size = pageSize) => {
const { searchKeyword, searchToken } = getFormValues();
if (searchKeyword === '' && searchToken === '') {
setSearchMode(false);
await loadTokens(1);
return;
}
setSearching(true);
const res = await API.get(
`/api/token/search?keyword=${searchKeyword}&token=${searchToken}`,
`/api/token/search?keyword=${encodeURIComponent(searchKeyword)}&token=${encodeURIComponent(searchToken)}&p=${page}&size=${size}`,
);
const { success, message, data } = res.data;
if (success) {
setTokens(data);
setTokenCount(data.length);
setActivePage(1);
setSearchMode(true);
syncPageData(data);
} else {
showError(message);
}
@@ -226,12 +228,20 @@ export const useTokensData = (openFluentNotification) => {
// Page handlers
const handlePageChange = (page) => {
loadTokens(page, pageSize).then();
if (searchMode) {
searchTokens(page, pageSize).then();
} else {
loadTokens(page, pageSize).then();
}
};
const handlePageSizeChange = async (size) => {
setPageSize(size);
await loadTokens(1, size);
if (searchMode) {
await searchTokens(1, size);
} else {
await loadTokens(1, size);
}
};
// Row selection handlers

View File

@@ -56,6 +56,7 @@ export default function GeneralSettings(props) {
DefaultCollapseSidebar: false,
DemoSiteEnabled: false,
SelfUseModeEnabled: false,
'token_setting.max_user_tokens': 1000,
});
const refForm = useRef();
const [inputsRow, setInputsRow] = useState(inputs);
@@ -287,6 +288,19 @@ export default function GeneralSettings(props) {
/>
</Col>
</Row>
<Row gutter={16}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.InputNumber
label={t('用户最大令牌数量')}
field={'token_setting.max_user_tokens'}
step={1}
min={1}
extraText={t('每个用户最多可创建的令牌数量,默认 1000设置过大可能会影响性能')}
placeholder={'1000'}
onChange={handleFieldChange('token_setting.max_user_tokens')}
/>
</Col>
</Row>
<Row>
<Button size='default' onClick={onSubmit}>
{t('保存通用设置')}