mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-08 02:17:46 +08:00
feat: 支持固定类型 Provider OAuth 授权
- 新增 provider_type 字段区分自定义/预置 Provider 类型(claude_code/codex/gemini_cli/antigravity) - 实现完整 OAuth 2.0 授权流程:start(生成授权 URL + PKCE)、complete(换取 token)、refresh - 前端 KeyFormDialog 添加 OAuth 授权 UI,支持开始授权、粘贴回调 URL、完成授权、强制刷新 - 请求时自动检测 token 过期并刷新(120s 预留窗口 + Redis 分布式锁防并发) - 固定类型 Provider 自动创建预置端点并锁定 base_url/custom_path - 数据库迁移:添加 providers.provider_type,扩展 api_key 列为 TEXT - 可选依赖 tls-client 用于 Claude token 请求的 TLS 指纹伪装
This commit is contained in:
@@ -27,13 +27,29 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="space-y-1.5">
|
||||
<Label for="website">主站链接</Label>
|
||||
<Input
|
||||
id="website"
|
||||
v-model="form.website"
|
||||
placeholder="https://..."
|
||||
type="url"
|
||||
/>
|
||||
<Label>提供商类型</Label>
|
||||
<Select
|
||||
v-model="form.provider_type"
|
||||
v-model:open="providerTypeSelectOpen"
|
||||
:disabled="isEditMode"
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="请选择" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="custom">自定义</SelectItem>
|
||||
<SelectItem value="claude_code">ClaudeCode</SelectItem>
|
||||
<SelectItem value="codex">Codex</SelectItem>
|
||||
<SelectItem value="gemini_cli">GeminiCli</SelectItem>
|
||||
<SelectItem value="antigravity">Antigravity</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<p
|
||||
v-if="!isEditMode && form.provider_type !== 'custom'"
|
||||
class="text-xs text-muted-foreground"
|
||||
>
|
||||
固定类型 Provider 将自动创建并锁定端点(base_url/custom_path 不可修改)。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -45,6 +61,15 @@
|
||||
placeholder="提供商描述(可选)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="space-y-1.5">
|
||||
<Label for="website">主站链接</Label>
|
||||
<Input
|
||||
id="website"
|
||||
v-model="form.website"
|
||||
placeholder="https://example.com(可选)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 计费与限流 / 请求配置 -->
|
||||
@@ -297,6 +322,7 @@ const emit = defineEmits<{
|
||||
|
||||
const { success, error: showError } = useToast()
|
||||
const loading = ref(false)
|
||||
const providerTypeSelectOpen = ref(false)
|
||||
const billingTypeSelectOpen = ref(false)
|
||||
|
||||
// 内部状态
|
||||
@@ -305,6 +331,7 @@ const internalOpen = computed(() => props.modelValue)
|
||||
// 表单数据
|
||||
const form = ref({
|
||||
name: '',
|
||||
provider_type: 'custom' as 'custom' | 'claude_code' | 'codex' | 'gemini_cli' | 'antigravity',
|
||||
description: '',
|
||||
website: '',
|
||||
// 计费配置
|
||||
@@ -335,6 +362,7 @@ const form = ref({
|
||||
function resetForm() {
|
||||
form.value = {
|
||||
name: '',
|
||||
provider_type: 'custom',
|
||||
description: '',
|
||||
website: '',
|
||||
billing_type: 'pay_as_you_go',
|
||||
@@ -367,6 +395,7 @@ function loadProviderData() {
|
||||
const proxy = props.provider.proxy
|
||||
form.value = {
|
||||
name: props.provider.name,
|
||||
provider_type: props.provider.provider_type || 'custom',
|
||||
description: props.provider.description || '',
|
||||
website: props.provider.website || '',
|
||||
billing_type: (props.provider.billing_type as 'monthly_quota' | 'pay_as_you_go' | 'free_tier') || 'pay_as_you_go',
|
||||
@@ -430,6 +459,7 @@ const handleSubmit = async () => {
|
||||
|
||||
const payload = {
|
||||
name: form.value.name,
|
||||
provider_type: form.value.provider_type,
|
||||
description: form.value.description || undefined,
|
||||
website: form.value.website || undefined,
|
||||
billing_type: form.value.billing_type,
|
||||
|
||||
Reference in New Issue
Block a user