feat: 添加 Provider Ops 扩展操作系统,支持余额监控

主要更改:
- 新增 Provider Ops 服务框架,支持通过架构配置执行余额查询等扩展操作
- 后端:添加 provider_ops 服务层和 API 路由
- 前端:添加 ProviderAuthDialog 组件配置认证信息
- 前端:添加 providerOps API 和认证模板系统

UI/组件优化:
- Input 组件:新增 masked 属性,使用 CSS 遮蔽敏感信息,避免触发密码管理器
- Pagination 组件:移除首页/末页/上下页按钮,改为页码跳转输入框
- KeyFormDialog:使用 masked 属性简化 API Key 输入逻辑
- ProviderManagement:重新设计表格布局,显示余额监控数据
This commit is contained in:
fawney19
2026-01-17 19:50:35 +08:00
parent 3cdf471473
commit c71027c466
29 changed files with 4653 additions and 144 deletions

View File

@@ -0,0 +1,66 @@
/**
* 提供商认证模板注册表
*
* 集中管理所有认证模板。
*
* ## 添加新模板的步骤
*
* 1. 在 `auth-templates/` 目录下创建新的模板文件(如 `my-api.ts`
* 2. 实现 `AuthTemplate` 接口
* 3. 在本文件中导入并注册到 `templates` 数组
*
* ## 模板需要实现的内容
*
* - `id`: 模板唯一标识(对应后端的 architecture_id
* - `name`: 显示名称
* - `description`: 描述文本
* - `getFields()`: 返回表单字段定义
* - `buildRequest()`: 构建后端 API 请求
* - `parseConfig()`: 从已有配置解析表单数据
* - `validate()`: 验证表单数据
* - `formatQuota()`: (可选)格式化 quota 显示
*/
import type { AuthTemplate, AuthTemplateRegistry } from './types'
import { newApiTemplate } from './new-api'
// ==================== 模板注册 ====================
// 在这里添加新模板
const templates: AuthTemplate[] = [newApiTemplate]
// ==================== 注册表实现 ====================
const templateMap = new Map<string, AuthTemplate>()
// 初始化 Map
templates.forEach((template) => {
templateMap.set(template.id, template)
})
/**
* 认证模板注册表
*/
export const authTemplateRegistry: AuthTemplateRegistry = {
getAll(): AuthTemplate[] {
return templates
},
get(id: string): AuthTemplate | undefined {
return templateMap.get(id)
},
getDefault(): AuthTemplate {
return templates[0]
},
register(template: AuthTemplate): void {
templates.push(template)
templateMap.set(template.id, template)
},
}
// ==================== 导出 ====================
export * from './types'
export { newApiTemplate } from './new-api'

View File

@@ -0,0 +1,97 @@
/**
* New API 认证模板
*
* 适用于 New API 风格的中转站:
* - 使用 Bearer Token 认证
* - 需要 New-Api-User Header 传递用户 ID
* - quota 单位通常是 1/500000 美元
*/
import type { AuthTemplate, AuthTemplateFieldGroup } from './types'
import type { SaveConfigRequest } from '@/api/providerOps'
export const newApiTemplate: AuthTemplate = {
id: 'new_api',
name: 'New API',
description: '适用于 New API 风格的中转站,使用 Bearer Token + New-Api-User Header',
getFields(providerWebsite?: string): AuthTemplateFieldGroup[] {
return [
{
fields: [
{
key: 'base_url',
label: 'API 地址',
type: 'text',
placeholder: providerWebsite || 'https://api.example.com',
helpText: '提供商的 API 基础地址,留空则使用提供商官网',
required: false,
},
{
key: 'api_key',
label: '访问令牌 (API Key)',
type: 'password',
placeholder: 'sk-xxx',
required: true,
sensitive: true,
},
{
key: 'user_id',
label: '用户 ID',
type: 'text',
placeholder: '用户 ID',
required: true,
},
],
},
]
},
buildRequest(formData: Record<string, any>, providerWebsite?: string): SaveConfigRequest {
const baseUrl = formData.base_url || providerWebsite || ''
return {
architecture_id: 'new_api',
base_url: baseUrl,
connector: {
auth_type: 'api_key',
config: {
auth_method: 'bearer',
},
credentials: {
api_key: formData.api_key,
user_id: formData.user_id,
},
},
actions: {},
schedule: {},
}
},
parseConfig(config: any): Record<string, any> {
return {
base_url: config?.base_url || '',
api_key: config?.connector?.credentials?.api_key || '',
user_id: config?.connector?.credentials?.user_id || '',
}
},
validate(formData: Record<string, any>): string | null {
if (!formData.api_key?.trim()) {
return '请填写访问令牌'
}
if (!formData.user_id?.trim()) {
return '请填写用户 ID'
}
return null
},
formatQuota(quota: number): string {
// New API 的 quota 单位是 1/500000 美元
const usd = quota / 500000
if (usd >= 1) {
return `$${usd.toFixed(2)}`
}
return `$${usd.toFixed(4)}`
},
}

View File

@@ -0,0 +1,120 @@
/**
* 提供商认证模板类型定义
*
* 认证模板定义了:
* - 需要收集的表单字段
* - 如何构建后端请求
* - 如何解析已有配置
*/
import type { SaveConfigRequest } from '@/api/providerOps'
/**
* 表单字段类型
*/
export type FieldType = 'text' | 'password' | 'select' | 'textarea'
/**
* 表单字段定义
*/
export interface AuthTemplateField {
/** 字段 key用于表单数据 */
key: string
/** 显示标签 */
label: string
/** 字段类型 */
type: FieldType
/** 占位符 */
placeholder?: string
/** 帮助文本 */
helpText?: string
/** 是否必填 */
required?: boolean
/** 是否为敏感字段(使用 masked 输入) */
sensitive?: boolean
/** select 类型的选项 */
options?: Array<{ value: string; label: string }>
/** 默认值 */
defaultValue?: string
}
/**
* 表单字段分组
*/
export interface AuthTemplateFieldGroup {
/** 分组标题(可选,为空则不显示标题) */
title?: string
/** 分组内的字段 */
fields: AuthTemplateField[]
}
/**
* 验证结果数据
*/
export interface VerifyResultData {
username?: string
display_name?: string
email?: string
quota?: number
used_quota?: number
request_count?: number
extra?: Record<string, any>
}
/**
* 认证模板接口
*/
export interface AuthTemplate {
/** 模板 ID对应后端 architecture_id */
id: string
/** 显示名称 */
name: string
/** 描述 */
description: string
/**
* 获取表单字段定义
* @param providerWebsite 提供商官网(用于设置默认 base_url
*/
getFields(providerWebsite?: string): AuthTemplateFieldGroup[]
/**
* 构建保存请求
* @param formData 表单数据
* @param providerWebsite 提供商官网
*/
buildRequest(formData: Record<string, any>, providerWebsite?: string): SaveConfigRequest
/**
* 从已有配置解析表单数据
* @param config 已有配置
*/
parseConfig(config: any): Record<string, any>
/**
* 验证表单数据
* @param formData 表单数据
* @returns 错误消息,无错误返回 null
*/
validate(formData: Record<string, any>): string | null
/**
* 格式化验证结果中的 quota 显示
* @param quota quota 值
*/
formatQuota?(quota: number): string
}
/**
* 认证模板注册表类型
*/
export interface AuthTemplateRegistry {
/** 获取所有模板 */
getAll(): AuthTemplate[]
/** 根据 ID 获取模板 */
get(id: string): AuthTemplate | undefined
/** 获取默认模板 */
getDefault(): AuthTemplate
/** 注册模板 */
register(template: AuthTemplate): void
}