diff --git a/README.md b/README.md index 6c888e62..8e2e48e3 100644 --- a/README.md +++ b/README.md @@ -44,8 +44,7 @@ _✨ All in one 的 OpenAI 接口,整合各种 API 访问方式,开箱即用 赞赏支持
-> **Warning**:从 `v0.2` 版本升级到 `v0.3` 版本需要手动迁移数据库,请手动执行[数据库迁移脚本](./bin/migration_v0.2-v0.3.sql)。 - +> **Warning**:使用 Docker 拉取的最新镜像可能是 `alpha` 版本,如果追求稳定性请手动指定版本。 ## 功能 1. 支持多种 API 访问渠道,欢迎 PR 或提 issue 添加更多渠道: @@ -65,16 +64,18 @@ _✨ All in one 的 OpenAI 接口,整合各种 API 访问方式,开箱即用 5. 支持**令牌管理**,设置令牌的过期时间和使用次数。 6. 支持**兑换码管理**,支持批量生成和导出兑换码,可使用兑换码为账户进行充值。 7. 支持**通道管理**,批量创建通道。 -8. 支持发布公告,设置充值链接,设置新用户初始额度。 -9. 支持丰富的**自定义**设置, - 1. 支持自定义系统名称,logo 以及页脚。 - 2. 支持自定义首页和关于页面,可以选择使用 HTML & Markdown 代码进行自定义,或者使用一个单独的网页通过 iframe 嵌入。 -10. 支持通过系统访问令牌访问管理 API。 -11. 支持用户管理,支持**多种用户登录注册方式**: +8. 支持**用户分组**以及**渠道分组**。 +9. 支持渠道**设置模型列表**。 +10. 支持发布公告,设置充值链接,设置新用户初始额度。 +11. 支持丰富的**自定义**设置, + 1. 支持自定义系统名称,logo 以及页脚。 + 2. 支持自定义首页和关于页面,可以选择使用 HTML & Markdown 代码进行自定义,或者使用一个单独的网页通过 iframe 嵌入。 +12. 支持通过系统访问令牌访问管理 API。 +13. 支持用户管理,支持**多种用户登录注册方式**: + 邮箱登录注册以及通过邮箱进行密码重置。 + [GitHub 开放授权](https://github.com/settings/applications/new)。 + 微信公众号授权(需要额外部署 [WeChat Server](https://github.com/songquanpeng/wechat-server))。 -12. 未来其他大模型开放 API 后,将第一时间支持,并将其封装成同样的 API 访问方式。 +14. 未来其他大模型开放 API 后,将第一时间支持,并将其封装成同样的 API 访问方式。 ## 部署 ### 基于 Docker 进行部署 diff --git a/controller/user.go b/controller/user.go index 46f5d869..045e0841 100644 --- a/controller/user.go +++ b/controller/user.go @@ -228,7 +228,7 @@ func GetUser(c *gin.Context) { return } myRole := c.GetInt("role") - if myRole <= user.Role { + if myRole <= user.Role && myRole != common.RoleRootUser { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "无权获取同级或更高等级用户的信息", @@ -326,14 +326,14 @@ func UpdateUser(c *gin.Context) { return } myRole := c.GetInt("role") - if myRole <= originUser.Role { + if myRole <= originUser.Role && myRole != common.RoleRootUser { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "无权更新同权限等级或更高权限等级的用户信息", }) return } - if myRole <= updatedUser.Role { + if myRole <= updatedUser.Role && myRole != common.RoleRootUser { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "无权将其他用户权限等级提升到大于等于自己的权限等级", diff --git a/model/ability.go b/model/ability.go index 1270ea8a..f3dae7ac 100644 --- a/model/ability.go +++ b/model/ability.go @@ -9,7 +9,7 @@ type Ability struct { Group string `json:"group" gorm:"type:varchar(32);primaryKey;autoIncrement:false"` Model string `json:"model" gorm:"primaryKey;autoIncrement:false"` ChannelId int `json:"channel_id" gorm:"primaryKey;autoIncrement:false;index"` - Enabled bool `json:"enabled" gorm:"default:1"` + Enabled bool `json:"enabled"` } func GetRandomSatisfiedChannel(group string, model string) (*Channel, error) { @@ -68,5 +68,5 @@ func (channel *Channel) UpdateAbilities() error { } func UpdateAbilityStatus(channelId int, status bool) error { - return DB.Model(&Ability{}).Where("channel_id = ?", channelId).Update("enabled", status).Error + return DB.Model(&Ability{}).Where("channel_id = ?", channelId).Select("enabled").Update("enabled", status).Error } diff --git a/model/channel.go b/model/channel.go index 006a67d9..fdc89eb9 100644 --- a/model/channel.go +++ b/model/channel.go @@ -91,6 +91,7 @@ func (channel *Channel) Update() error { if err != nil { return err } + DB.Model(channel).First(channel, "id = ?", channel.Id) err = channel.UpdateAbilities() return err } diff --git a/web/src/components/UsersTable.js b/web/src/components/UsersTable.js index 9906bca7..f2e8521e 100644 --- a/web/src/components/UsersTable.js +++ b/web/src/components/UsersTable.js @@ -302,7 +302,6 @@ const UsersTable = () => { size={'small'} as={Link} to={'/user/edit/' + user.id} - disabled={user.role === 100} > 编辑 diff --git a/web/src/pages/Channel/EditChannel.js b/web/src/pages/Channel/EditChannel.js index 05607f98..022a9fe4 100644 --- a/web/src/pages/Channel/EditChannel.js +++ b/web/src/pages/Channel/EditChannel.js @@ -1,7 +1,7 @@ import React, { useEffect, useState } from 'react'; import { Button, Form, Header, Message, Segment } from 'semantic-ui-react'; import { useParams } from 'react-router-dom'; -import { API, showError, showSuccess } from '../../helpers'; +import { API, showError, showInfo, showSuccess } from '../../helpers'; import { CHANNEL_OPTIONS } from '../../constants'; const EditChannel = () => { @@ -15,13 +15,15 @@ const EditChannel = () => { key: '', base_url: '', other: '', + group: 'default', models: [], }; const [batch, setBatch] = useState(false); const [inputs, setInputs] = useState(originInputs); const [modelOptions, setModelOptions] = useState([]); + const [basicModels, setBasicModels] = useState([]); + const [fullModels, setFullModels] = useState([]); const handleInputChange = (e, { name, value }) => { - console.log(name, value); setInputs((inputs) => ({ ...inputs, [name]: value })); }; @@ -49,8 +51,10 @@ const EditChannel = () => { text: model.id, value: model.id, }))); + setFullModels(res.data.data.map((model) => model.id)); + setBasicModels(res.data.data.filter((model) => !model.id.startsWith("gpt-4")).map((model) => model.id)); } catch (error) { - console.error('Error fetching models:', error); + showError(error.message); } }; @@ -62,7 +66,10 @@ const EditChannel = () => { }, []); const submit = async () => { - if (!isEdit && (inputs.name === '' || inputs.key === '')) return; + if (!isEdit && (inputs.name === '' || inputs.key === '')) { + showInfo('请填写渠道名称和渠道密钥!'); + return; + } let localInputs = inputs; if (localInputs.base_url.endsWith('/')) { localInputs.base_url = localInputs.base_url.slice(0, localInputs.base_url.length - 1); @@ -159,9 +166,20 @@ const EditChannel = () => { autoComplete='new-password' /> +