refactor: 简化模型管理,移除启用/禁用,优化测试和布局

- 移除供应商/模型启用禁用能力,清理DB schema/migration/API/前端
- 供应商测试改为Base URL连通性+/models探测
- 新增POST /api/models/test模型连接测试
- 新增GET /api/providers/options专用供应商选项接口
- 统一工具栏为ModelsToolbar,参考项目管理布局
- 模型弹窗优化:默认能力、响应式3列标签、并排数值
- 前后端正整数校验、供应商下拉loading/error/empty状态
- 表格列宽统一,操作列/名称列固定宽度
This commit is contained in:
2026-05-29 18:03:33 +08:00
parent 9241c782e6
commit 34e915ccf4
39 changed files with 895 additions and 961 deletions

View File

@@ -36,7 +36,6 @@ export function createModel(
capabilities: JSON.stringify(capabilities),
contextLength: request.contextLength ?? null,
createdAt: now,
enabled: true,
id,
maxOutputTokens: request.maxOutputTokens ?? null,
modelId,
@@ -66,32 +65,6 @@ export function deleteModel(raw: Database, id: string): { error: string; status:
return { success: true };
}
export function disableModel(raw: Database, id: string): { error: string; status: number } | { model: Model } {
const db = wrap(raw);
const existing = db.select().from(models).where(eq(models.id, id)).get();
if (!existing) return { error: "模型不存在", status: 404 };
if (!existing.enabled) return { error: "模型已禁用", status: 409 };
const now = new Date().toISOString();
db.update(models).set({ enabled: false, updatedAt: now }).where(eq(models.id, id)).run();
const updated = db.select().from(models).where(eq(models.id, id)).get();
return { model: toModel(updated!) };
}
export function enableModel(raw: Database, id: string): { error: string; status: number } | { model: Model } {
const db = wrap(raw);
const existing = db.select().from(models).where(eq(models.id, id)).get();
if (!existing) return { error: "模型不存在", status: 404 };
if (existing.enabled) return { error: "模型已启用", status: 409 };
const now = new Date().toISOString();
db.update(models).set({ enabled: true, updatedAt: now }).where(eq(models.id, id)).run();
const updated = db.select().from(models).where(eq(models.id, id)).get();
return { model: toModel(updated!) };
}
export function getModel(raw: Database, id: string): { error: string; status: number } | { model: Model } {
const db = wrap(raw);
const row = db.select().from(models).where(eq(models.id, id)).get();
@@ -222,7 +195,6 @@ function toModel(row: typeof models.$inferSelect): Model {
capabilities: JSON.parse(row.capabilities) as ModelCapability[],
contextLength: row.contextLength,
createdAt: row.createdAt,
enabled: row.enabled,
id: row.id,
maxOutputTokens: row.maxOutputTokens,
modelId: row.modelId,

View File

@@ -3,7 +3,7 @@ import type Database from "bun:sqlite";
import { and, desc, eq, like, sql } from "drizzle-orm";
import { drizzle } from "drizzle-orm/bun-sqlite";
import type { CreateProviderRequest, Provider, UpdateProviderRequest } from "../../shared/api";
import type { CreateProviderRequest, Provider, ProviderOption, UpdateProviderRequest } from "../../shared/api";
import { providers } from "./schema";
@@ -30,7 +30,6 @@ export function createProvider(
apiKey,
baseUrl,
createdAt: now,
enabled: true,
id,
name,
type: request.type,
@@ -58,32 +57,6 @@ export function deleteProvider(raw: Database, id: string): { error: string; stat
return { success: true };
}
export function disableProvider(raw: Database, id: string): { error: string; status: number } | { provider: Provider } {
const db = wrap(raw);
const existing = db.select().from(providers).where(eq(providers.id, id)).get();
if (!existing) return { error: "供应商不存在", status: 404 };
if (!existing.enabled) return { error: "供应商已禁用", status: 409 };
const now = new Date().toISOString();
db.update(providers).set({ enabled: false, updatedAt: now }).where(eq(providers.id, id)).run();
const updated = db.select().from(providers).where(eq(providers.id, id)).get();
return { provider: toProvider(updated!) };
}
export function enableProvider(raw: Database, id: string): { error: string; status: number } | { provider: Provider } {
const db = wrap(raw);
const existing = db.select().from(providers).where(eq(providers.id, id)).get();
if (!existing) return { error: "供应商不存在", status: 404 };
if (existing.enabled) return { error: "供应商已启用", status: 409 };
const now = new Date().toISOString();
db.update(providers).set({ enabled: true, updatedAt: now }).where(eq(providers.id, id)).run();
const updated = db.select().from(providers).where(eq(providers.id, id)).get();
return { provider: toProvider(updated!) };
}
export function getProvider(raw: Database, id: string): { error: string; status: number } | { provider: Provider } {
const db = wrap(raw);
const row = db.select().from(providers).where(eq(providers.id, id)).get();
@@ -92,6 +65,17 @@ export function getProvider(raw: Database, id: string): { error: string; status:
return { provider: toProvider(row) };
}
export function listProviderOptions(raw: Database): ProviderOption[] {
const db = wrap(raw);
const rows = db
.select({ id: providers.id, name: providers.name, type: providers.type })
.from(providers)
.orderBy(desc(providers.createdAt))
.all();
return rows;
}
export function listProviders(
raw: Database,
options: { keyword?: string; page: number; pageSize: number },
@@ -189,7 +173,6 @@ function toProvider(row: typeof providers.$inferSelect): Provider {
apiKey: row.apiKey,
baseUrl: row.baseUrl,
createdAt: row.createdAt,
enabled: row.enabled,
id: row.id,
name: row.name,
type: row.type,

View File

@@ -16,7 +16,6 @@ export const providers = sqliteTable("providers", {
apiKey: text("api_key").notNull(),
baseUrl: text("base_url").notNull(),
createdAt: text("created_at").notNull(),
enabled: integer("enabled", { mode: "boolean" }).notNull().default(true),
id: text("id").primaryKey(),
name: text("name").notNull().unique(),
type: text("type", { enum: ["anthropic", "openai", "openai-compatible"] })
@@ -31,7 +30,6 @@ export const models = sqliteTable(
capabilities: text("capabilities").notNull(),
contextLength: integer("context_length"),
createdAt: text("created_at").notNull(),
enabled: integer("enabled", { mode: "boolean" }).notNull().default(true),
id: text("id").primaryKey(),
maxOutputTokens: integer("max_output_tokens"),
modelId: text("model_id").notNull(),