diff --git a/common/constants.go b/common/constants.go
index fe412e1a..d07dcc8a 100644
--- a/common/constants.go
+++ b/common/constants.go
@@ -156,9 +156,10 @@ const (
)
const (
- ChannelStatusUnknown = 0
- ChannelStatusEnabled = 1 // don't use 0, 0 is the default value!
- ChannelStatusDisabled = 2 // also don't use 0
+ ChannelStatusUnknown = 0
+ ChannelStatusEnabled = 1 // don't use 0, 0 is the default value!
+ ChannelStatusManuallyDisabled = 2 // also don't use 0
+ ChannelStatusAutoDisabled = 3
)
const (
diff --git a/controller/channel-test.go b/controller/channel-test.go
index f7a565a2..1974ef6e 100644
--- a/controller/channel-test.go
+++ b/controller/channel-test.go
@@ -141,7 +141,7 @@ func disableChannel(channelId int, channelName string, reason string) {
if common.RootUserEmail == "" {
common.RootUserEmail = model.GetRootUserEmail()
}
- model.UpdateChannelStatusById(channelId, common.ChannelStatusDisabled)
+ model.UpdateChannelStatusById(channelId, common.ChannelStatusAutoDisabled)
subject := fmt.Sprintf("通道「%s」(#%d)已被禁用", channelName, channelId)
content := fmt.Sprintf("通道「%s」(#%d)已被禁用,原因:%s", channelName, channelId, reason)
err := common.SendEmail(subject, common.RootUserEmail, content)
diff --git a/controller/channel.go b/controller/channel.go
index 50b2b5f6..41a55550 100644
--- a/controller/channel.go
+++ b/controller/channel.go
@@ -127,6 +127,23 @@ func DeleteChannel(c *gin.Context) {
return
}
+func DeleteManuallyDisabledChannel(c *gin.Context) {
+ rows, err := model.DeleteChannelByStatus(common.ChannelStatusManuallyDisabled)
+ if err != nil {
+ c.JSON(http.StatusOK, gin.H{
+ "success": false,
+ "message": err.Error(),
+ })
+ return
+ }
+ c.JSON(http.StatusOK, gin.H{
+ "success": true,
+ "message": "",
+ "data": rows,
+ })
+ return
+}
+
func UpdateChannel(c *gin.Context) {
channel := model.Channel{}
err := c.ShouldBindJSON(&channel)
diff --git a/model/channel.go b/model/channel.go
index 61fe9093..36bb78a5 100644
--- a/model/channel.go
+++ b/model/channel.go
@@ -176,3 +176,8 @@ func updateChannelUsedQuota(id int, quota int) {
common.SysError("failed to update channel used quota: " + err.Error())
}
}
+
+func DeleteChannelByStatus(status int64) (int64, error) {
+ result := DB.Where("status = ?", status).Delete(&Channel{})
+ return result.RowsAffected, result.Error
+}
diff --git a/router/api-router.go b/router/api-router.go
index d12bc54b..5ec385dc 100644
--- a/router/api-router.go
+++ b/router/api-router.go
@@ -74,6 +74,7 @@ func SetApiRouter(router *gin.Engine) {
channelRoute.GET("/update_balance/:id", controller.UpdateChannelBalance)
channelRoute.POST("/", controller.AddChannel)
channelRoute.PUT("/", controller.UpdateChannel)
+ channelRoute.DELETE("/manually_disabled", controller.DeleteManuallyDisabledChannel)
channelRoute.DELETE("/:id", controller.DeleteChannel)
}
tokenRoute := apiRouter.Group("/token")
diff --git a/web/src/components/ChannelsTable.js b/web/src/components/ChannelsTable.js
index 7c8457d0..57d45c55 100644
--- a/web/src/components/ChannelsTable.js
+++ b/web/src/components/ChannelsTable.js
@@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
-import {Button, Form, Input, Label, Pagination, Popup, Table} from 'semantic-ui-react';
+import { Button, Form, Input, Label, Pagination, Popup, Table } from 'semantic-ui-react';
import { Link } from 'react-router-dom';
import { API, showError, showInfo, showNotice, showSuccess, timestamp2string } from '../helpers';
@@ -96,7 +96,7 @@ const ChannelsTable = () => {
});
}, []);
- const manageChannel = async (id, action, idx, priority) => {
+ const manageChannel = async (id, action, idx, value) => {
let data = { id };
let res;
switch (action) {
@@ -112,10 +112,20 @@ const ChannelsTable = () => {
res = await API.put('/api/channel/', data);
break;
case 'priority':
- if (priority === '') {
+ if (value === '') {
return;
}
- data.priority = parseInt(priority);
+ data.priority = parseInt(value);
+ res = await API.put('/api/channel/', data);
+ break;
+ case 'weight':
+ if (value === '') {
+ return;
+ }
+ data.weight = parseInt(value);
+ if (data.weight < 0) {
+ data.weight = 0;
+ }
res = await API.put('/api/channel/', data);
break;
}
@@ -142,9 +152,23 @@ const ChannelsTable = () => {
return ;
case 2:
return (
-
+
+ 已禁用
+ }
+ content='本渠道被手动禁用'
+ basic
+ />
+ );
+ case 3:
+ return (
+
+ 已禁用
+ }
+ content='本渠道被程序自动禁用'
+ basic
+ />
);
default:
return (
@@ -202,7 +226,7 @@ const ChannelsTable = () => {
showInfo(`通道 ${name} 测试成功,耗时 ${time.toFixed(2)} 秒。`);
} else {
showError(message);
- showNotice("当前版本测试是通过按照 OpenAI API 格式使用 gpt-3.5-turbo 模型进行非流式请求实现的,因此测试报错并不一定代表通道不可用,该功能后续会修复。")
+ showNotice('当前版本测试是通过按照 OpenAI API 格式使用 gpt-3.5-turbo 模型进行非流式请求实现的,因此测试报错并不一定代表通道不可用,该功能后续会修复。');
}
};
@@ -216,6 +240,17 @@ const ChannelsTable = () => {
}
};
+ const deleteAllManuallyDisabledChannels = async () => {
+ const res = await API.delete(`/api/channel/manually_disabled`);
+ const { success, message, data } = res.data;
+ if (success) {
+ showSuccess(`已删除所有手动禁用渠道,共计 ${data} 个`);
+ await refresh();
+ } else {
+ showError(message);
+ }
+ };
+
const updateChannelBalance = async (id, name, idx) => {
const res = await API.get(`/api/channel/update_balance/${id}/`);
const { success, message, balance } = res.data;
@@ -343,10 +378,10 @@ const ChannelsTable = () => {
余额
{
- sortChannel('priority');
- }}
+ style={{ cursor: 'pointer' }}
+ onClick={() => {
+ sortChannel('priority');
+ }}
>
优先级
@@ -390,18 +425,18 @@ const ChannelsTable = () => {
{
- manageChannel(
- channel.id,
- 'priority',
- idx,
- event.target.value,
- );
- }}>
-
- }
- content='渠道选择优先级,越高越优先'
- basic
+ trigger={ {
+ manageChannel(
+ channel.id,
+ 'priority',
+ idx,
+ event.target.value
+ );
+ }}>
+
+ }
+ content='渠道选择优先级,越高越优先'
+ basic
/>
@@ -481,6 +516,20 @@ const ChannelsTable = () => {
+
+ 删除所有手动禁用渠道
+
+ }
+ on='click'
+ flowing
+ hoverable
+ >
+
+