fix(channel):修复渠道无法修改协议
This commit is contained in:
1 parent
6ff5c6e949
commit
f4debdfab2
5 files changed
+44
-3
No files matched your search
@@ -0,0 +1,5 @@
|
||||
# CodeGraph data files — local to each machine, not for committing.
|
||||
# Ignore everything in .codegraph/ except this file itself, so transient
|
||||
# files (the database, daemon.pid, sockets, logs) never show up in git.
|
||||
*
|
||||
!.gitignore
|
||||
@@ -11,7 +11,7 @@
|
||||
- **后端**:Go + GoFrame (v2) + goose(数据库迁移)
|
||||
- **数据库**:PostgreSQL(唯一,不用 MySQL/SQLite)
|
||||
- **缓存**:Redis + 内存缓存(双层缓存)
|
||||
- **前端**:Vue 3 + Vite + TailwindCSS + Naive UI(管理后台)
|
||||
- **前端**:Vue 3 + Vite + TailwindCSS + Arco Design Vue(管理后台)
|
||||
- **包管理**:bun
|
||||
- **对象存储**:S3 / OSS / COS / MinIO(禁止纯本地磁盘作为生产存储)
|
||||
|
||||
@@ -383,9 +383,9 @@ wallets 表包含 `frozen_balance` 字段,用于支付中/退款中的金额
|
||||
### 前端
|
||||
|
||||
- Vue 3 Composition API + `<script setup>` 语法
|
||||
- **管理后台**:使用 **Naive UI** 组件库,快速构建数据密集型页面(表格、表单、图表等),可参考 [Soybean Admin](https://github.com/soybeanjs/soybean-admin) 的架构设计(路由、权限、布局)
|
||||
- **管理后台**:使用 **Arco Design Vue** 组件库(`@arco-design/web-vue`),快速构建数据密集型页面(表格、表单、图表等),可参考 [Soybean Admin](https://github.com/soybeanjs/soybean-admin) 的架构设计(路由、权限、布局)
|
||||
- **租户控制台**:TailwindCSS 原子类 + 自建组件,面向客户,注重品牌调性和视觉差异化
|
||||
- TailwindCSS 作为基础样式层,两个控制台共用(Naive UI 的 CSS-in-JS 方案与 TailwindCSS 无冲突)
|
||||
- TailwindCSS 作为基础样式层,两个控制台共用(注意与 Arco 组件内置样式共存,避免全局 reset 冲突)
|
||||
- 状态管理用 Pinia
|
||||
- HTTP 请求封装 Axios,JWT 自动刷新,统一错误处理
|
||||
- 按钮级权限控制:无权限的按钮不渲染(`v-if="hasPermission('xxx')"`)
|
||||
|
||||
@@ -69,6 +69,7 @@ type ChannelUpdateReq struct {
|
||||
g.Meta `path:"/channels/{id}" method:"put" mime:"json" tags:"管理后台-渠道" summary:"更新渠道"`
|
||||
ID int64 `json:"id" in:"path" v:"required" dc:"渠道ID"`
|
||||
Name string `json:"name" dc:"渠道名称"`
|
||||
Type *int `json:"type" v:"min:1#请选择供应商类型" dc:"供应商类型(留空不修改)"`
|
||||
BaseURL string `json:"base_url" dc:"API 基础地址"`
|
||||
ApiKey *string `json:"api_key" dc:"更新 API Key(留空不更新)"`
|
||||
Priority int `json:"priority" dc:"优先级"`
|
||||
|
||||
@@ -294,6 +294,9 @@ func (s *sAdmin) UpdateChannel(ctx context.Context, req *v1.ChannelUpdateReq) (*
|
||||
if req.Name != "" {
|
||||
data.Name = req.Name
|
||||
}
|
||||
if req.Type != nil {
|
||||
data.Type = *req.Type
|
||||
}
|
||||
if req.BaseURL != "" {
|
||||
data.BaseUrl = req.BaseURL
|
||||
}
|
||||
|
||||
@@ -18,6 +18,30 @@ const activeTab = ref('info')
|
||||
|
||||
const statusTagColor: Record<string, string> = { active: 'green', disabled: 'orangered', testing: 'arcoblue' }
|
||||
const statusLabel: Record<string, string> = { active: '启用', disabled: '禁用', testing: '测试中' }
|
||||
|
||||
// 供应商类型选项(与渠道列表页保持一致,用于编辑时切换渠道协议类型)
|
||||
const providerTypeOptions = [
|
||||
{ label: 'OpenAI', value: 1 }, { label: 'Claude (Anthropic)', value: 2 },
|
||||
{ label: 'Gemini (Google)', value: 3 }, { label: 'Ali (百炼)', value: 4 },
|
||||
{ label: 'Tencent (混元)', value: 6 },
|
||||
{ label: 'Zhipu (智谱)', value: 7 }, { label: 'DeepSeek', value: 8 },
|
||||
{ label: 'Moonshot', value: 9 }, { label: 'Volcengine (火山)', value: 10 },
|
||||
{ label: 'AWS Bedrock', value: 11 }, { label: 'Azure OpenAI', value: 12 },
|
||||
{ label: 'Vertex AI', value: 13 },
|
||||
{ label: 'Mistral', value: 15 }, { label: 'xAI (Grok)', value: 16 },
|
||||
{ label: '360 智脑', value: 17 }, { label: 'Lingyi (零一万物)', value: 18 },
|
||||
{ label: 'Baidu V2', value: 19 }, { label: 'Cloudflare Workers AI', value: 20 },
|
||||
{ label: 'Ollama', value: 22 },
|
||||
{ label: 'SiliconFlow (硅基流动)', value: 25 }, { label: 'Xunfei (讯飞)', value: 26 },
|
||||
{ label: 'OpenRouter', value: 27 }, { label: 'XInference', value: 28 },
|
||||
{ label: 'MiniMax', value: 29 }, { label: 'Submodel', value: 30 },
|
||||
{ label: 'Coze (扣子)', value: 32 },
|
||||
{ label: 'Dify', value: 33 }, { label: 'Jimeng (即梦)', value: 34 },
|
||||
{ label: 'Codex', value: 35 },
|
||||
]
|
||||
function filterProviderOption(inputValue: string, option: { label: string; value: number }) {
|
||||
return option.label.toLowerCase().includes(inputValue.toLowerCase())
|
||||
}
|
||||
const healthColor = (score: number | null | undefined) => {
|
||||
if (score === null || score === undefined) return '#94a3b8'
|
||||
if (score >= 80) return '#10b981'
|
||||
@@ -46,6 +70,7 @@ const showEditModal = ref(false)
|
||||
const editLoading = ref(false)
|
||||
const editForm = reactive({
|
||||
name: '',
|
||||
type: 1,
|
||||
base_url: '',
|
||||
priority: 0,
|
||||
weight: 100,
|
||||
@@ -63,6 +88,7 @@ function openEditModal() {
|
||||
if (!detail.value) return
|
||||
Object.assign(editForm, {
|
||||
name: detail.value.name || '',
|
||||
type: detail.value.type || 1,
|
||||
base_url: detail.value.base_url || '',
|
||||
priority: detail.value.priority || 0,
|
||||
weight: detail.value.weight || 100,
|
||||
@@ -621,6 +647,12 @@ function formatHeaders(headers: Record<string, string>): string {
|
||||
<!-- Edit Channel Modal -->
|
||||
<AModal v-model:visible="showEditModal" title="编辑渠道" :width="600" :mask-closable="false" :on-before-ok="handleEditSubmit" :ok-loading="editLoading">
|
||||
<AForm :model="editForm" :auto-label-width="true" layout="vertical">
|
||||
<AFormItem label="供应商类型" field="type">
|
||||
<ASelect v-model="editForm.type" :options="providerTypeOptions" placeholder="搜索或选择" allow-search :filter-option="filterProviderOption" />
|
||||
<template #extra>
|
||||
<span class="field-help">切换协议类型会改变该渠道的转发适配器;请确认 Base URL 与已配置的模型能力与新类型匹配。</span>
|
||||
</template>
|
||||
</AFormItem>
|
||||
<ARow :gutter="16">
|
||||
<ACol :span="8">
|
||||
<AFormItem label="渠道名称"><AInput v-model="editForm.name" /></AFormItem>
|
||||
|
||||
Reference in new issue
Block a user