diff --git a/controller/channel.go b/controller/channel.go index a2ee5743..440815cc 100644 --- a/controller/channel.go +++ b/controller/channel.go @@ -71,6 +71,13 @@ func parseStatusFilter(statusParam string) int { } } +func clearChannelInfo(channel *model.Channel) { + if channel.ChannelInfo.IsMultiKey { + channel.ChannelInfo.MultiKeyDisabledReason = nil + channel.ChannelInfo.MultiKeyDisabledTime = nil + } +} + func GetAllChannels(c *gin.Context) { pageInfo := common.GetPageQuery(c) channelData := make([]*model.Channel, 0) @@ -145,6 +152,10 @@ func GetAllChannels(c *gin.Context) { } } + for _, datum := range channelData { + clearChannelInfo(datum) + } + countQuery := model.DB.Model(&model.Channel{}) if statusFilter == common.ChannelStatusEnabled { countQuery = countQuery.Where("status = ?", common.ChannelStatusEnabled) @@ -371,6 +382,10 @@ func SearchChannels(c *gin.Context) { pagedData := channelData[startIdx:endIdx] + for _, datum := range pagedData { + clearChannelInfo(datum) + } + c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", @@ -394,6 +409,9 @@ func GetChannel(c *gin.Context) { common.ApiError(c, err) return } + if channel != nil { + clearChannelInfo(channel) + } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", @@ -827,6 +845,7 @@ func UpdateChannel(c *gin.Context) { } model.InitChannelCache() channel.Key = "" + clearChannelInfo(&channel.Channel) c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", @@ -1036,11 +1055,21 @@ type MultiKeyManageRequest struct { ChannelId int `json:"channel_id"` Action string `json:"action"` // "disable_key", "enable_key", "delete_disabled_keys", "get_key_status" KeyIndex *int `json:"key_index,omitempty"` // for disable_key and enable_key actions + Page int `json:"page,omitempty"` // for get_key_status pagination + PageSize int `json:"page_size,omitempty"` // for get_key_status pagination } // MultiKeyStatusResponse represents the response for key status query type MultiKeyStatusResponse struct { - Keys []KeyStatus `json:"keys"` + Keys []KeyStatus `json:"keys"` + Total int `json:"total"` + Page int `json:"page"` + PageSize int `json:"page_size"` + TotalPages int `json:"total_pages"` + // Statistics + EnabledCount int `json:"enabled_count"` + ManualDisabledCount int `json:"manual_disabled_count"` + AutoDisabledCount int `json:"auto_disabled_count"` } type KeyStatus struct { @@ -1080,8 +1109,35 @@ func ManageMultiKeys(c *gin.Context) { switch request.Action { case "get_key_status": keys := channel.GetKeys() - var keyStatusList []KeyStatus + total := len(keys) + // Default pagination parameters + page := request.Page + pageSize := request.PageSize + if page <= 0 { + page = 1 + } + if pageSize <= 0 { + pageSize = 50 // Default page size + } + + // Calculate pagination + totalPages := (total + pageSize - 1) / pageSize + if page > totalPages && totalPages > 0 { + page = totalPages + } + + // Calculate range + start := (page - 1) * pageSize + end := start + pageSize + if end > total { + end = total + } + + // Statistics for all keys + var enabledCount, manualDisabledCount, autoDisabledCount int + + var keyStatusList []KeyStatus for i, key := range keys { status := 1 // default enabled var disabledTime int64 @@ -1093,34 +1149,56 @@ func ManageMultiKeys(c *gin.Context) { } } - if status != 1 { - if channel.ChannelInfo.MultiKeyDisabledTime != nil { - disabledTime = channel.ChannelInfo.MultiKeyDisabledTime[i] - } - if channel.ChannelInfo.MultiKeyDisabledReason != nil { - reason = channel.ChannelInfo.MultiKeyDisabledReason[i] - } + // Count for statistics + switch status { + case 1: + enabledCount++ + case 2: + manualDisabledCount++ + case 3: + autoDisabledCount++ } - // Create key preview (first 10 chars) - keyPreview := key - if len(key) > 10 { - keyPreview = key[:10] + "..." - } + // Only include keys in current page + if i >= start && i < end { + if status != 1 { + if channel.ChannelInfo.MultiKeyDisabledTime != nil { + disabledTime = channel.ChannelInfo.MultiKeyDisabledTime[i] + } + if channel.ChannelInfo.MultiKeyDisabledReason != nil { + reason = channel.ChannelInfo.MultiKeyDisabledReason[i] + } + } - keyStatusList = append(keyStatusList, KeyStatus{ - Index: i, - Status: status, - DisabledTime: disabledTime, - Reason: reason, - KeyPreview: keyPreview, - }) + // Create key preview (first 10 chars) + keyPreview := key + if len(key) > 10 { + keyPreview = key[:10] + "..." + } + + keyStatusList = append(keyStatusList, KeyStatus{ + Index: i, + Status: status, + DisabledTime: disabledTime, + Reason: reason, + KeyPreview: keyPreview, + }) + } } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", - "data": MultiKeyStatusResponse{Keys: keyStatusList}, + "data": MultiKeyStatusResponse{ + Keys: keyStatusList, + Total: total, + Page: page, + PageSize: pageSize, + TotalPages: totalPages, + EnabledCount: enabledCount, + ManualDisabledCount: manualDisabledCount, + AutoDisabledCount: autoDisabledCount, + }, }) return diff --git a/model/channel.go b/model/channel.go index 502171fa..280781f1 100644 --- a/model/channel.go +++ b/model/channel.go @@ -53,12 +53,12 @@ type Channel struct { } type ChannelInfo struct { - IsMultiKey bool `json:"is_multi_key"` // 是否多Key模式 - MultiKeySize int `json:"multi_key_size"` // 多Key模式下的Key数量 - MultiKeyStatusList map[int]int `json:"multi_key_status_list"` // key状态列表,key index -> status - MultiKeyDisabledReason map[int]string `json:"multi_key_disabled_reason"` // key禁用原因列表,key index -> reason - MultiKeyDisabledTime map[int]int64 `json:"multi_key_disabled_time"` // key禁用时间列表,key index -> time - MultiKeyPollingIndex int `json:"multi_key_polling_index"` // 多Key模式下轮询的key索引 + IsMultiKey bool `json:"is_multi_key"` // 是否多Key模式 + MultiKeySize int `json:"multi_key_size"` // 多Key模式下的Key数量 + MultiKeyStatusList map[int]int `json:"multi_key_status_list"` // key状态列表,key index -> status + MultiKeyDisabledReason map[int]string `json:"multi_key_disabled_reason,omitempty"` // key禁用原因列表,key index -> reason + MultiKeyDisabledTime map[int]int64 `json:"multi_key_disabled_time,omitempty"` // key禁用时间列表,key index -> time + MultiKeyPollingIndex int `json:"multi_key_polling_index"` // 多Key模式下轮询的key索引 MultiKeyMode constant.MultiKeyMode `json:"multi_key_mode"` } diff --git a/web/src/components/table/channels/modals/MultiKeyManageModal.jsx b/web/src/components/table/channels/modals/MultiKeyManageModal.jsx index 9ae46ea3..44f16c03 100644 --- a/web/src/components/table/channels/modals/MultiKeyManageModal.jsx +++ b/web/src/components/table/channels/modals/MultiKeyManageModal.jsx @@ -30,7 +30,9 @@ import { Popconfirm, Empty, Spin, - Banner + Banner, + Select, + Pagination } from '@douyinfe/semi-ui'; import { IconRefresh, @@ -53,24 +55,48 @@ const MultiKeyManageModal = ({ const [loading, setLoading] = useState(false); const [keyStatusList, setKeyStatusList] = useState([]); const [operationLoading, setOperationLoading] = useState({}); + + // Pagination states + const [currentPage, setCurrentPage] = useState(1); + const [pageSize, setPageSize] = useState(50); + const [total, setTotal] = useState(0); + const [totalPages, setTotalPages] = useState(0); + + // Statistics states + const [enabledCount, setEnabledCount] = useState(0); + const [manualDisabledCount, setManualDisabledCount] = useState(0); + const [autoDisabledCount, setAutoDisabledCount] = useState(0); // Load key status data - const loadKeyStatus = async () => { + const loadKeyStatus = async (page = currentPage, size = pageSize) => { if (!channel?.id) return; setLoading(true); try { const res = await API.post('/api/channel/multi_key/manage', { channel_id: channel.id, - action: 'get_key_status' + action: 'get_key_status', + page: page, + page_size: size }); if (res.data.success) { - setKeyStatusList(res.data.data.keys || []); + const data = res.data.data; + setKeyStatusList(data.keys || []); + setTotal(data.total || 0); + setCurrentPage(data.page || 1); + setPageSize(data.page_size || 50); + setTotalPages(data.total_pages || 0); + + // Update statistics + setEnabledCount(data.enabled_count || 0); + setManualDisabledCount(data.manual_disabled_count || 0); + setAutoDisabledCount(data.auto_disabled_count || 0); } else { showError(res.data.message); } } catch (error) { + console.error(error); showError(t('获取密钥状态失败')); } finally { setLoading(false); @@ -91,7 +117,7 @@ const MultiKeyManageModal = ({ if (res.data.success) { showSuccess(t('密钥已禁用')); - await loadKeyStatus(); // Reload data + await loadKeyStatus(currentPage, pageSize); // Reload current page onRefresh && onRefresh(); // Refresh parent component } else { showError(res.data.message); @@ -117,7 +143,7 @@ const MultiKeyManageModal = ({ if (res.data.success) { showSuccess(t('密钥已启用')); - await loadKeyStatus(); // Reload data + await loadKeyStatus(currentPage, pageSize); // Reload current page onRefresh && onRefresh(); // Refresh parent component } else { showError(res.data.message); @@ -141,7 +167,9 @@ const MultiKeyManageModal = ({ if (res.data.success) { showSuccess(res.data.message); - await loadKeyStatus(); // Reload data + // Reset to first page after deletion as data structure might change + setCurrentPage(1); + await loadKeyStatus(1, pageSize); onRefresh && onRefresh(); // Refresh parent component } else { showError(res.data.message); @@ -153,13 +181,40 @@ const MultiKeyManageModal = ({ } }; + // Handle page change + const handlePageChange = (page) => { + setCurrentPage(page); + loadKeyStatus(page, pageSize); + }; + + // Handle page size change + const handlePageSizeChange = (size) => { + setPageSize(size); + setCurrentPage(1); // Reset to first page + loadKeyStatus(1, size); + }; + // Effect to load data when modal opens useEffect(() => { if (visible && channel?.id) { - loadKeyStatus(); + setCurrentPage(1); // Reset to first page when opening + loadKeyStatus(1, pageSize); } }, [visible, channel?.id]); + // Reset pagination when modal closes + useEffect(() => { + if (!visible) { + setCurrentPage(1); + setKeyStatusList([]); + setTotal(0); + setTotalPages(0); + setEnabledCount(0); + setManualDisabledCount(0); + setAutoDisabledCount(0); + } + }, [visible]); + // Get status tag component const renderStatusTag = (status) => { switch (status) { @@ -270,12 +325,6 @@ const MultiKeyManageModal = ({ }, ]; - // Calculate statistics - const enabledCount = keyStatusList.filter(key => key.status === 1).length; - const manualDisabledCount = keyStatusList.filter(key => key.status === 2).length; - const autoDisabledCount = keyStatusList.filter(key => key.status === 3).length; - const totalCount = keyStatusList.length; - return ( {t('关闭')}