resolve: 解决与upstream/dev的合并冲突

- 合并admin.js中的groupIds和autoStopOnWarning参数
- 统一AccountForm.vue中的错误提示文案和平台判断逻辑
- 保留AccountsView.vue中的分组过滤和ungrouped功能
- 确保Azure OpenAI账户创建和更新逻辑完整性

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
sczheng189
2025-09-02 20:32:42 +08:00
66 changed files with 11527 additions and 1581 deletions

View File

@@ -556,7 +556,17 @@
>
<div class="flex flex-wrap gap-2">
<label
v-for="model in ['gpt-4', 'gpt-4-turbo', 'gpt-35-turbo', 'gpt-35-turbo-16k']"
v-for="model in [
'gpt-4',
'gpt-4-turbo',
'gpt-4o',
'gpt-4o-mini',
'gpt-5',
'gpt-5-mini',
'gpt-35-turbo',
'gpt-35-turbo-16k',
'codex-mini'
]"
:key="model"
class="flex cursor-pointer items-center"
>
@@ -825,6 +835,25 @@
</p>
</div>
<!-- Claude 5小时限制自动停止调度选项 -->
<div v-if="form.platform === 'claude'" class="mt-4">
<label class="flex items-start">
<input
v-model="form.autoStopOnWarning"
class="mt-1 text-blue-600 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700"
type="checkbox"
/>
<div class="ml-3">
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">
5小时使用量接近限制时自动停止调度
</span>
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
当系统检测到账户接近5小时使用限制时自动暂停调度该账户。进入新的时间窗口后会自动恢复调度。
</p>
</div>
</label>
</div>
<!-- 所有平台的优先级设置 -->
<div>
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300"
@@ -1364,6 +1393,25 @@
</p>
</div>
<!-- Claude 5小时限制自动停止调度选项编辑模式 -->
<div v-if="form.platform === 'claude'" class="mt-4">
<label class="flex items-start">
<input
v-model="form.autoStopOnWarning"
class="mt-1 text-blue-600 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700"
type="checkbox"
/>
<div class="ml-3">
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">
5小时使用量接近限制时自动停止调度
</span>
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
当系统检测到账户接近5小时使用限制时自动暂停调度该账户。进入新的时间窗口后会自动恢复调度。
</p>
</div>
</label>
</div>
<!-- 所有平台的优先级设置(编辑模式) -->
<div>
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300"
@@ -1660,9 +1708,112 @@
</div>
</div>
<!-- Azure OpenAI 特定字段(编辑模式)-->
<div v-if="form.platform === 'azure_openai'" class="space-y-4">
<div>
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300"
>Azure Endpoint</label
>
<input
v-model="form.azureEndpoint"
class="form-input w-full dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
:class="{ 'border-red-500': errors.azureEndpoint }"
placeholder="https://your-resource.openai.azure.com"
type="url"
/>
<p v-if="errors.azureEndpoint" class="mt-1 text-xs text-red-500">
{{ errors.azureEndpoint }}
</p>
</div>
<div>
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300"
>API 版本</label
>
<input
v-model="form.apiVersion"
class="form-input w-full dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
placeholder="2024-02-01"
type="text"
/>
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
Azure OpenAI API 版本,默认使用最新稳定版本 2024-02-01
</p>
</div>
<div>
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300"
>部署名称</label
>
<input
v-model="form.deploymentName"
class="form-input w-full dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
:class="{ 'border-red-500': errors.deploymentName }"
placeholder="gpt-4"
type="text"
/>
<p v-if="errors.deploymentName" class="mt-1 text-xs text-red-500">
{{ errors.deploymentName }}
</p>
</div>
<div>
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300"
>API Key</label
>
<input
v-model="form.apiKey"
class="form-input w-full dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
:class="{ 'border-red-500': errors.apiKey }"
placeholder="留空表示不更新"
type="password"
/>
<p v-if="errors.apiKey" class="mt-1 text-xs text-red-500">
{{ errors.apiKey }}
</p>
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">留空表示不更新 API Key</p>
</div>
<div>
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300"
>支持的模型</label
>
<div class="flex flex-wrap gap-2">
<label
v-for="model in [
'gpt-4',
'gpt-4-turbo',
'gpt-4o',
'gpt-4o-mini',
'gpt-5',
'gpt-5-mini',
'gpt-35-turbo',
'gpt-35-turbo-16k',
'codex-mini'
]"
:key="model"
class="flex cursor-pointer items-center"
>
<input
v-model="form.supportedModels"
class="mr-2 text-blue-600 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700"
type="checkbox"
:value="model"
/>
<span class="text-sm text-gray-700 dark:text-gray-300">{{ model }}</span>
</label>
</div>
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">选择此部署支持的模型类型</p>
</div>
</div>
<!-- Token 更新 -->
<div
v-if="form.platform !== 'claude-console' && form.platform !== 'bedrock'"
v-if="
form.platform !== 'claude-console' &&
form.platform !== 'bedrock' &&
form.platform !== 'azure_openai'
"
class="rounded-lg border border-amber-200 bg-amber-50 p-4 dark:border-amber-700 dark:bg-amber-900/30"
>
<div class="mb-4 flex items-start gap-3">
@@ -1826,6 +1977,7 @@ const form = ref({
description: props.account?.description || '',
accountType: props.account?.accountType || 'shared',
subscriptionType: 'claude_max', // 默认为 Claude Max兼容旧数据
autoStopOnWarning: props.account?.autoStopOnWarning || false, // 5小时限制自动停止调度
groupId: '',
groupIds: [],
projectId: props.account?.projectId || '',
@@ -1839,16 +1991,16 @@ const form = ref({
priority: props.account?.priority || 50,
supportedModels: (() => {
const models = props.account?.supportedModels
if (!models) return ''
if (!models) return []
// 处理对象格式Claude Console 的新格式)
if (typeof models === 'object' && !Array.isArray(models)) {
return Object.keys(models).join('\n')
return Object.keys(models)
}
// 处理数组格式(向后兼容)
if (Array.isArray(models)) {
return models.join('\n')
return models
}
return ''
return []
})(),
userAgent: props.account?.userAgent || '',
enableRateLimit: props.account ? props.account.rateLimitDuration > 0 : true,
@@ -1859,7 +2011,11 @@ const form = ref({
region: props.account?.region || '',
sessionToken: props.account?.sessionToken || '',
defaultModel: props.account?.defaultModel || '',
smallFastModel: props.account?.smallFastModel || ''
smallFastModel: props.account?.smallFastModel || '',
// Azure OpenAI 特定字段
azureEndpoint: props.account?.azureEndpoint || '',
apiVersion: props.account?.apiVersion || '',
deploymentName: props.account?.deploymentName || ''
})
// 模型映射表数据
@@ -1896,7 +2052,9 @@ const errors = ref({
apiKey: '',
accessKeyId: '',
secretAccessKey: '',
region: ''
region: '',
azureEndpoint: '',
deploymentName: ''
})
// 计算是否可以进入下一步
@@ -2096,6 +2254,7 @@ const handleOAuthSuccess = async (tokenInfo) => {
// Claude使用claudeAiOauth字段
data.claudeAiOauth = tokenInfo.claudeAiOauth || tokenInfo
data.priority = form.value.priority || 50
data.autoStopOnWarning = form.value.autoStopOnWarning || false
// 添加订阅类型信息
data.subscriptionInfo = {
accountType: form.value.subscriptionType || 'claude_max',
@@ -2176,15 +2335,15 @@ const createAccount = async () => {
} else if (form.value.platform === 'azure_openai') {
// Azure OpenAI 验证
if (!form.value.azureEndpoint || form.value.azureEndpoint.trim() === '') {
errors.value.azureEndpoint = 'Azure Endpoint 是必填项'
errors.value.azureEndpoint = '请填写 Azure Endpoint'
hasError = true
}
if (!form.value.deploymentName || form.value.deploymentName.trim() === '') {
errors.value.deploymentName = 'Deployment Name 是必填项'
errors.value.deploymentName = '请填写部署名称'
hasError = true
}
if (!form.value.apiKey || form.value.apiKey.trim() === '') {
errors.value.apiKey = 'API Key 是必填项'
errors.value.apiKey = '请填写 API Key'
hasError = true
}
} else if (form.value.addType === 'manual') {
@@ -2257,6 +2416,7 @@ const createAccount = async () => {
scopes: [] // 手动添加没有 scopes
}
data.priority = form.value.priority || 50
data.autoStopOnWarning = form.value.autoStopOnWarning || false
// 添加订阅类型信息
data.subscriptionInfo = {
accountType: form.value.subscriptionType || 'claude_max',
@@ -2360,10 +2520,12 @@ const createAccount = async () => {
} else if (form.value.platform === 'azure_openai') {
// Azure OpenAI 账户特定数据
data.azureEndpoint = form.value.azureEndpoint
data.apiKey = form.value.apiKey
data.apiVersion = form.value.apiVersion || '2024-02-01'
data.deploymentName = form.value.deploymentName
data.apiKey = form.value.apiKey
data.supportedModels = form.value.supportedModels || []
data.supportedModels = Array.isArray(form.value.supportedModels)
? form.value.supportedModels
: []
data.priority = form.value.priority || 50
data.isActive = form.value.isActive !== false
data.schedulable = form.value.schedulable !== false
@@ -2507,6 +2669,7 @@ const updateAccount = async () => {
// Claude 官方账号优先级和订阅类型更新
if (props.account.platform === 'claude') {
data.priority = form.value.priority || 50
data.autoStopOnWarning = form.value.autoStopOnWarning || false
// 更新订阅类型信息
data.subscriptionInfo = {
accountType: form.value.subscriptionType || 'claude_max',
@@ -2565,6 +2728,21 @@ const updateAccount = async () => {
data.rateLimitDuration = form.value.enableRateLimit ? form.value.rateLimitDuration || 60 : 0
}
// Azure OpenAI 特定更新
if (props.account.platform === 'azure_openai') {
data.azureEndpoint = form.value.azureEndpoint
data.apiVersion = form.value.apiVersion || '2024-02-01'
data.deploymentName = form.value.deploymentName
data.supportedModels = Array.isArray(form.value.supportedModels)
? form.value.supportedModels
: []
data.priority = form.value.priority || 50
// 只有当有新的 API Key 时才更新
if (form.value.apiKey && form.value.apiKey.trim()) {
data.apiKey = form.value.apiKey
}
}
if (props.account.platform === 'claude') {
await accountsStore.updateClaudeAccount(props.account.id, data)
} else if (props.account.platform === 'claude-console') {
@@ -2629,6 +2807,26 @@ watch(
}
)
// 监听Azure Endpoint变化清除错误
watch(
() => form.value.azureEndpoint,
() => {
if (errors.value.azureEndpoint && form.value.azureEndpoint?.trim()) {
errors.value.azureEndpoint = ''
}
}
)
// 监听Deployment Name变化清除错误
watch(
() => form.value.deploymentName,
() => {
if (errors.value.deploymentName && form.value.deploymentName?.trim()) {
errors.value.deploymentName = ''
}
}
)
// 分组相关数据
const groups = ref([])
const loadingGroups = ref(false)
@@ -2872,6 +3070,7 @@ watch(
description: newAccount.description || '',
accountType: newAccount.accountType || 'shared',
subscriptionType: subscriptionType,
autoStopOnWarning: newAccount.autoStopOnWarning || false,
groupId: groupId,
groupIds: [],
projectId: newAccount.projectId || '',
@@ -2884,16 +3083,16 @@ watch(
priority: newAccount.priority || 50,
supportedModels: (() => {
const models = newAccount.supportedModels
if (!models) return ''
if (!models) return []
// 处理对象格式Claude Console 的新格式)
if (typeof models === 'object' && !Array.isArray(models)) {
return Object.keys(models).join('\n')
return Object.keys(models)
}
// 处理数组格式(向后兼容)
if (Array.isArray(models)) {
return models.join('\n')
return models
}
return ''
return []
})(),
userAgent: newAccount.userAgent || '',
enableRateLimit:
@@ -2905,7 +3104,11 @@ watch(
region: newAccount.region || '',
sessionToken: '', // 编辑模式不显示现有的会话令牌
defaultModel: newAccount.defaultModel || '',
smallFastModel: newAccount.smallFastModel || ''
smallFastModel: newAccount.smallFastModel || '',
// Azure OpenAI 特定字段
azureEndpoint: newAccount.azureEndpoint || '',
apiVersion: newAccount.apiVersion || '',
deploymentName: newAccount.deploymentName || ''
}
// 如果是分组类型加载分组ID