diff --git a/controller/channel.go b/controller/channel.go index dae961d5..40b9cde4 100644 --- a/controller/channel.go +++ b/controller/channel.go @@ -3,12 +3,13 @@ package controller import ( "encoding/json" "fmt" - "github.com/gin-gonic/gin" "net/http" "one-api/common" "one-api/model" "strconv" "strings" + + "github.com/gin-gonic/gin" ) type OpenAIModel struct { @@ -48,41 +49,36 @@ func GetAllChannels(c *gin.Context) { if pageSize < 0 { pageSize = common.ItemsPerPage } + channelData := make([]*model.Channel, 0) idSort, _ := strconv.ParseBool(c.Query("id_sort")) - channels, err := model.GetAllChannels(p*pageSize, pageSize, false, idSort) - if err != nil { - c.JSON(http.StatusOK, gin.H{ - "success": false, - "message": err.Error(), - }) - return - } - tags := make(map[string]bool) - channelData := make([]*model.Channel, 0, len(channels)) - tagChannels := make([]*model.Channel, 0) - for _, channel := range channels { - channelTag := channel.GetTag() - if channelTag != "" && !tags[channelTag] { - tags[channelTag] = true - tagChannel, err := model.GetChannelsByTag(channelTag) - if err == nil { - tagChannels = append(tagChannels, tagChannel...) - } - } else { - channelData = append(channelData, channel) + enableTagMode, _ := strconv.ParseBool(c.Query("tag_mode")) + if enableTagMode { + tags, err := model.GetPaginatedTags(p*pageSize, pageSize) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "success": false, + "message": err.Error(), + }) + return } - } - for i, channel := range tagChannels { - find := false - for _, can := range channelData { - if channel.Id == can.Id { - find = true - break + for _, tag := range tags { + if tag != nil && *tag != "" { + tagChannel, err := model.GetChannelsByTag(*tag) + if err == nil { + channelData = append(channelData, tagChannel...) + } } } - if !find { - channelData = append(channelData, tagChannels[i]) + } else { + channels, err := model.GetAllChannels(p*pageSize, pageSize, false, idSort) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "success": false, + "message": err.Error(), + }) + return } + channelData = channels } c.JSON(http.StatusOK, gin.H{ "success": true, diff --git a/model/channel.go b/model/channel.go index 3fcb7611..9d59579f 100644 --- a/model/channel.go +++ b/model/channel.go @@ -2,9 +2,10 @@ package model import ( "encoding/json" - "gorm.io/gorm" "one-api/common" "strings" + + "gorm.io/gorm" ) type Channel struct { @@ -403,3 +404,9 @@ func DeleteDisabledChannel() (int64, error) { result := DB.Where("status = ? or status = ?", common.ChannelStatusAutoDisabled, common.ChannelStatusManuallyDisabled).Delete(&Channel{}) return result.RowsAffected, result.Error } + +func GetPaginatedTags(offset int, limit int) ([]*string, error) { + var tags []*string + err := DB.Model(&Channel{}).Select("DISTINCT tag").Where("tag != ''").Offset(offset).Limit(limit).Find(&tags).Error + return tags, err +} diff --git a/web/src/components/ChannelsTable.js b/web/src/components/ChannelsTable.js index 0e00a186..cae9f003 100644 --- a/web/src/components/ChannelsTable.js +++ b/web/src/components/ChannelsTable.js @@ -439,6 +439,7 @@ const ChannelsTable = () => { const [editingTag, setEditingTag] = useState(''); const [selectedChannels, setSelectedChannels] = useState([]); const [showEditPriority, setShowEditPriority] = useState(false); + const [enableTagMode, setEnableTagMode] = useState(false); const removeRecord = (record) => { @@ -464,13 +465,12 @@ const ChannelsTable = () => { } }; - const setChannelFormat = (channels) => { + const setChannelFormat = (channels, enableTagMode) => { let channelDates = []; let channelTags = {}; for (let i = 0; i < channels.length; i++) { channels[i].key = '' + channels[i].id; - - if (channels[i].tag === '' || channels[i].tag === null) { + if (!enableTagMode) { let test_models = []; channels[i].models.split(',').forEach((item, index) => { test_models.push({ @@ -554,10 +554,10 @@ const ChannelsTable = () => { } }; - const loadChannels = async (startIdx, pageSize, idSort) => { + const loadChannels = async (startIdx, pageSize, idSort, enableTagMode) => { setLoading(true); const res = await API.get( - `/api/channel/?p=${startIdx}&page_size=${pageSize}&id_sort=${idSort}` + `/api/channel/?p=${startIdx}&page_size=${pageSize}&id_sort=${idSort}&tag_mode=${enableTagMode}` ); if (res === undefined) { return; @@ -565,11 +565,11 @@ const ChannelsTable = () => { const { success, message, data } = res.data; if (success) { if (startIdx === 0) { - setChannelFormat(data); + setChannelFormat(data, enableTagMode); } else { let newChannels = [...channels]; newChannels.splice(startIdx * pageSize, data.length, ...data); - setChannelFormat(newChannels); + setChannelFormat(newChannels, enableTagMode); } } else { showError(message); @@ -602,7 +602,7 @@ const ChannelsTable = () => { }; const refresh = async () => { - await loadChannels(activePage - 1, pageSize, idSort); + await loadChannels(activePage - 1, pageSize, idSort, enableTagMode); }; useEffect(() => { @@ -612,7 +612,7 @@ const ChannelsTable = () => { parseInt(localStorage.getItem('page-size')) || ITEMS_PER_PAGE; setIdSort(localIdSort); setPageSize(localPageSize); - loadChannels(0, localPageSize, localIdSort) + loadChannels(0, localPageSize, localIdSort, enableTagMode) .then() .catch((reason) => { showError(reason); @@ -770,18 +770,22 @@ const ChannelsTable = () => { const searchChannels = async (searchKeyword, searchGroup, searchModel) => { if (searchKeyword === '' && searchGroup === '' && searchModel === '') { - // if keyword is blank, load files instead. - await loadChannels(0, pageSize, idSort); + await loadChannels(0, pageSize, idSort, enableTagMode); setActivePage(1); return; } setSearching(true); const res = await API.get( - `/api/channel/search?keyword=${searchKeyword}&group=${searchGroup}&model=${searchModel}&id_sort=${idSort}` + `/api/channel/search?keyword=${searchKeyword}&group=${searchGroup}&model=${searchModel}&id_sort=${idSort}&tag_mode=${enableTagMode}` ); const { success, message, data } = res.data; if (success) { - setChannelFormat(data); + if (enableTagMode) { + setChannelFormat(data, enableTagMode); + } else { + setChannels(data.map(channel => ({...channel, key: '' + channel.id}))); + setChannelCount(data.length); + } setActivePage(1); } else { showError(message); @@ -887,7 +891,7 @@ const ChannelsTable = () => { setActivePage(page); if (page === Math.ceil(channels.length / pageSize) + 1) { // In this case we have to load more data and then append them. - loadChannels(page - 1, pageSize, idSort).then((r) => { + loadChannels(page - 1, pageSize, idSort, enableTagMode).then((r) => { }); } }; @@ -896,7 +900,7 @@ const ChannelsTable = () => { localStorage.setItem('page-size', size + ''); setPageSize(size); setActivePage(1); - loadChannels(0, size, idSort) + loadChannels(0, size, idSort, enableTagMode) .then() .catch((reason) => { showError(reason); @@ -1052,7 +1056,7 @@ const ChannelsTable = () => { onChange={(v) => { localStorage.setItem('id-sort', v + ''); setIdSort(v); - loadChannels(0, pageSize, v) + loadChannels(0, pageSize, v, enableTagMode) .then() .catch((reason) => { showError(reason); @@ -1153,6 +1157,22 @@ const ChannelsTable = () => { +
+ + 标签聚合模式 + { + setEnableTagMode(v); + // 切换模式时重新加载数据 + loadChannels(0, pageSize, idSort, v); + }} + /> + +