refactor(settings): 规范化缩写词命名并优化前端帮助界面
- 后端:将 Smtp/Api/Doc 字段改为 SMTP/API/Doc(遵循 Go 命名规范) - 前端:添加 Gemini 帮助按钮,简化配额说明展示
This commit is contained in:
@@ -36,22 +36,22 @@ func (h *SettingHandler) GetSettings(c *gin.Context) {
|
||||
response.Success(c, dto.SystemSettings{
|
||||
RegistrationEnabled: settings.RegistrationEnabled,
|
||||
EmailVerifyEnabled: settings.EmailVerifyEnabled,
|
||||
SmtpHost: settings.SmtpHost,
|
||||
SmtpPort: settings.SmtpPort,
|
||||
SmtpUsername: settings.SmtpUsername,
|
||||
SmtpPassword: settings.SmtpPassword,
|
||||
SmtpFrom: settings.SmtpFrom,
|
||||
SmtpFromName: settings.SmtpFromName,
|
||||
SmtpUseTLS: settings.SmtpUseTLS,
|
||||
SMTPHost: settings.SMTPHost,
|
||||
SMTPPort: settings.SMTPPort,
|
||||
SMTPUsername: settings.SMTPUsername,
|
||||
SMTPPassword: settings.SMTPPassword,
|
||||
SMTPFrom: settings.SMTPFrom,
|
||||
SMTPFromName: settings.SMTPFromName,
|
||||
SMTPUseTLS: settings.SMTPUseTLS,
|
||||
TurnstileEnabled: settings.TurnstileEnabled,
|
||||
TurnstileSiteKey: settings.TurnstileSiteKey,
|
||||
TurnstileSecretKey: settings.TurnstileSecretKey,
|
||||
SiteName: settings.SiteName,
|
||||
SiteLogo: settings.SiteLogo,
|
||||
SiteSubtitle: settings.SiteSubtitle,
|
||||
ApiBaseUrl: settings.ApiBaseUrl,
|
||||
APIBaseURL: settings.APIBaseURL,
|
||||
ContactInfo: settings.ContactInfo,
|
||||
DocUrl: settings.DocUrl,
|
||||
DocURL: settings.DocURL,
|
||||
DefaultConcurrency: settings.DefaultConcurrency,
|
||||
DefaultBalance: settings.DefaultBalance,
|
||||
EnableModelFallback: settings.EnableModelFallback,
|
||||
@@ -69,13 +69,13 @@ type UpdateSettingsRequest struct {
|
||||
EmailVerifyEnabled bool `json:"email_verify_enabled"`
|
||||
|
||||
// 邮件服务设置
|
||||
SmtpHost string `json:"smtp_host"`
|
||||
SmtpPort int `json:"smtp_port"`
|
||||
SmtpUsername string `json:"smtp_username"`
|
||||
SmtpPassword string `json:"smtp_password"`
|
||||
SmtpFrom string `json:"smtp_from_email"`
|
||||
SmtpFromName string `json:"smtp_from_name"`
|
||||
SmtpUseTLS bool `json:"smtp_use_tls"`
|
||||
SMTPHost string `json:"smtp_host"`
|
||||
SMTPPort int `json:"smtp_port"`
|
||||
SMTPUsername string `json:"smtp_username"`
|
||||
SMTPPassword string `json:"smtp_password"`
|
||||
SMTPFrom string `json:"smtp_from_email"`
|
||||
SMTPFromName string `json:"smtp_from_name"`
|
||||
SMTPUseTLS bool `json:"smtp_use_tls"`
|
||||
|
||||
// Cloudflare Turnstile 设置
|
||||
TurnstileEnabled bool `json:"turnstile_enabled"`
|
||||
@@ -86,9 +86,9 @@ type UpdateSettingsRequest struct {
|
||||
SiteName string `json:"site_name"`
|
||||
SiteLogo string `json:"site_logo"`
|
||||
SiteSubtitle string `json:"site_subtitle"`
|
||||
ApiBaseUrl string `json:"api_base_url"`
|
||||
APIBaseURL string `json:"api_base_url"`
|
||||
ContactInfo string `json:"contact_info"`
|
||||
DocUrl string `json:"doc_url"`
|
||||
DocURL string `json:"doc_url"`
|
||||
|
||||
// 默认配置
|
||||
DefaultConcurrency int `json:"default_concurrency"`
|
||||
@@ -118,8 +118,8 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
|
||||
if req.DefaultBalance < 0 {
|
||||
req.DefaultBalance = 0
|
||||
}
|
||||
if req.SmtpPort <= 0 {
|
||||
req.SmtpPort = 587
|
||||
if req.SMTPPort <= 0 {
|
||||
req.SMTPPort = 587
|
||||
}
|
||||
|
||||
// Turnstile 参数验证
|
||||
@@ -155,22 +155,22 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
|
||||
settings := &service.SystemSettings{
|
||||
RegistrationEnabled: req.RegistrationEnabled,
|
||||
EmailVerifyEnabled: req.EmailVerifyEnabled,
|
||||
SmtpHost: req.SmtpHost,
|
||||
SmtpPort: req.SmtpPort,
|
||||
SmtpUsername: req.SmtpUsername,
|
||||
SmtpPassword: req.SmtpPassword,
|
||||
SmtpFrom: req.SmtpFrom,
|
||||
SmtpFromName: req.SmtpFromName,
|
||||
SmtpUseTLS: req.SmtpUseTLS,
|
||||
SMTPHost: req.SMTPHost,
|
||||
SMTPPort: req.SMTPPort,
|
||||
SMTPUsername: req.SMTPUsername,
|
||||
SMTPPassword: req.SMTPPassword,
|
||||
SMTPFrom: req.SMTPFrom,
|
||||
SMTPFromName: req.SMTPFromName,
|
||||
SMTPUseTLS: req.SMTPUseTLS,
|
||||
TurnstileEnabled: req.TurnstileEnabled,
|
||||
TurnstileSiteKey: req.TurnstileSiteKey,
|
||||
TurnstileSecretKey: req.TurnstileSecretKey,
|
||||
SiteName: req.SiteName,
|
||||
SiteLogo: req.SiteLogo,
|
||||
SiteSubtitle: req.SiteSubtitle,
|
||||
ApiBaseUrl: req.ApiBaseUrl,
|
||||
APIBaseURL: req.APIBaseURL,
|
||||
ContactInfo: req.ContactInfo,
|
||||
DocUrl: req.DocUrl,
|
||||
DocURL: req.DocURL,
|
||||
DefaultConcurrency: req.DefaultConcurrency,
|
||||
DefaultBalance: req.DefaultBalance,
|
||||
EnableModelFallback: req.EnableModelFallback,
|
||||
@@ -195,22 +195,22 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
|
||||
response.Success(c, dto.SystemSettings{
|
||||
RegistrationEnabled: updatedSettings.RegistrationEnabled,
|
||||
EmailVerifyEnabled: updatedSettings.EmailVerifyEnabled,
|
||||
SmtpHost: updatedSettings.SmtpHost,
|
||||
SmtpPort: updatedSettings.SmtpPort,
|
||||
SmtpUsername: updatedSettings.SmtpUsername,
|
||||
SmtpPassword: updatedSettings.SmtpPassword,
|
||||
SmtpFrom: updatedSettings.SmtpFrom,
|
||||
SmtpFromName: updatedSettings.SmtpFromName,
|
||||
SmtpUseTLS: updatedSettings.SmtpUseTLS,
|
||||
SMTPHost: updatedSettings.SMTPHost,
|
||||
SMTPPort: updatedSettings.SMTPPort,
|
||||
SMTPUsername: updatedSettings.SMTPUsername,
|
||||
SMTPPassword: updatedSettings.SMTPPassword,
|
||||
SMTPFrom: updatedSettings.SMTPFrom,
|
||||
SMTPFromName: updatedSettings.SMTPFromName,
|
||||
SMTPUseTLS: updatedSettings.SMTPUseTLS,
|
||||
TurnstileEnabled: updatedSettings.TurnstileEnabled,
|
||||
TurnstileSiteKey: updatedSettings.TurnstileSiteKey,
|
||||
TurnstileSecretKey: updatedSettings.TurnstileSecretKey,
|
||||
SiteName: updatedSettings.SiteName,
|
||||
SiteLogo: updatedSettings.SiteLogo,
|
||||
SiteSubtitle: updatedSettings.SiteSubtitle,
|
||||
ApiBaseUrl: updatedSettings.ApiBaseUrl,
|
||||
APIBaseURL: updatedSettings.APIBaseURL,
|
||||
ContactInfo: updatedSettings.ContactInfo,
|
||||
DocUrl: updatedSettings.DocUrl,
|
||||
DocURL: updatedSettings.DocURL,
|
||||
DefaultConcurrency: updatedSettings.DefaultConcurrency,
|
||||
DefaultBalance: updatedSettings.DefaultBalance,
|
||||
EnableModelFallback: updatedSettings.EnableModelFallback,
|
||||
@@ -221,30 +221,30 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestSmtpRequest 测试SMTP连接请求
|
||||
type TestSmtpRequest struct {
|
||||
SmtpHost string `json:"smtp_host" binding:"required"`
|
||||
SmtpPort int `json:"smtp_port"`
|
||||
SmtpUsername string `json:"smtp_username"`
|
||||
SmtpPassword string `json:"smtp_password"`
|
||||
SmtpUseTLS bool `json:"smtp_use_tls"`
|
||||
// TestSMTPRequest 测试SMTP连接请求
|
||||
type TestSMTPRequest struct {
|
||||
SMTPHost string `json:"smtp_host" binding:"required"`
|
||||
SMTPPort int `json:"smtp_port"`
|
||||
SMTPUsername string `json:"smtp_username"`
|
||||
SMTPPassword string `json:"smtp_password"`
|
||||
SMTPUseTLS bool `json:"smtp_use_tls"`
|
||||
}
|
||||
|
||||
// TestSmtpConnection 测试SMTP连接
|
||||
// POST /api/v1/admin/settings/test-smtp
|
||||
func (h *SettingHandler) TestSmtpConnection(c *gin.Context) {
|
||||
var req TestSmtpRequest
|
||||
var req TestSMTPRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "Invalid request: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if req.SmtpPort <= 0 {
|
||||
req.SmtpPort = 587
|
||||
if req.SMTPPort <= 0 {
|
||||
req.SMTPPort = 587
|
||||
}
|
||||
|
||||
// 如果未提供密码,从数据库获取已保存的密码
|
||||
password := req.SmtpPassword
|
||||
password := req.SMTPPassword
|
||||
if password == "" {
|
||||
savedConfig, err := h.emailService.GetSmtpConfig(c.Request.Context())
|
||||
if err == nil && savedConfig != nil {
|
||||
@@ -253,11 +253,11 @@ func (h *SettingHandler) TestSmtpConnection(c *gin.Context) {
|
||||
}
|
||||
|
||||
config := &service.SmtpConfig{
|
||||
Host: req.SmtpHost,
|
||||
Port: req.SmtpPort,
|
||||
Username: req.SmtpUsername,
|
||||
Host: req.SMTPHost,
|
||||
Port: req.SMTPPort,
|
||||
Username: req.SMTPUsername,
|
||||
Password: password,
|
||||
UseTLS: req.SmtpUseTLS,
|
||||
UseTLS: req.SMTPUseTLS,
|
||||
}
|
||||
|
||||
err := h.emailService.TestSmtpConnectionWithConfig(config)
|
||||
@@ -272,13 +272,13 @@ func (h *SettingHandler) TestSmtpConnection(c *gin.Context) {
|
||||
// SendTestEmailRequest 发送测试邮件请求
|
||||
type SendTestEmailRequest struct {
|
||||
Email string `json:"email" binding:"required,email"`
|
||||
SmtpHost string `json:"smtp_host" binding:"required"`
|
||||
SmtpPort int `json:"smtp_port"`
|
||||
SmtpUsername string `json:"smtp_username"`
|
||||
SmtpPassword string `json:"smtp_password"`
|
||||
SmtpFrom string `json:"smtp_from_email"`
|
||||
SmtpFromName string `json:"smtp_from_name"`
|
||||
SmtpUseTLS bool `json:"smtp_use_tls"`
|
||||
SMTPHost string `json:"smtp_host" binding:"required"`
|
||||
SMTPPort int `json:"smtp_port"`
|
||||
SMTPUsername string `json:"smtp_username"`
|
||||
SMTPPassword string `json:"smtp_password"`
|
||||
SMTPFrom string `json:"smtp_from_email"`
|
||||
SMTPFromName string `json:"smtp_from_name"`
|
||||
SMTPUseTLS bool `json:"smtp_use_tls"`
|
||||
}
|
||||
|
||||
// SendTestEmail 发送测试邮件
|
||||
@@ -290,12 +290,12 @@ func (h *SettingHandler) SendTestEmail(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if req.SmtpPort <= 0 {
|
||||
req.SmtpPort = 587
|
||||
if req.SMTPPort <= 0 {
|
||||
req.SMTPPort = 587
|
||||
}
|
||||
|
||||
// 如果未提供密码,从数据库获取已保存的密码
|
||||
password := req.SmtpPassword
|
||||
password := req.SMTPPassword
|
||||
if password == "" {
|
||||
savedConfig, err := h.emailService.GetSmtpConfig(c.Request.Context())
|
||||
if err == nil && savedConfig != nil {
|
||||
@@ -304,13 +304,13 @@ func (h *SettingHandler) SendTestEmail(c *gin.Context) {
|
||||
}
|
||||
|
||||
config := &service.SmtpConfig{
|
||||
Host: req.SmtpHost,
|
||||
Port: req.SmtpPort,
|
||||
Username: req.SmtpUsername,
|
||||
Host: req.SMTPHost,
|
||||
Port: req.SMTPPort,
|
||||
Username: req.SMTPUsername,
|
||||
Password: password,
|
||||
From: req.SmtpFrom,
|
||||
FromName: req.SmtpFromName,
|
||||
UseTLS: req.SmtpUseTLS,
|
||||
From: req.SMTPFrom,
|
||||
FromName: req.SMTPFromName,
|
||||
UseTLS: req.SMTPUseTLS,
|
||||
}
|
||||
|
||||
siteName := h.settingService.GetSiteName(c.Request.Context())
|
||||
|
||||
@@ -5,13 +5,13 @@ type SystemSettings struct {
|
||||
RegistrationEnabled bool `json:"registration_enabled"`
|
||||
EmailVerifyEnabled bool `json:"email_verify_enabled"`
|
||||
|
||||
SmtpHost string `json:"smtp_host"`
|
||||
SmtpPort int `json:"smtp_port"`
|
||||
SmtpUsername string `json:"smtp_username"`
|
||||
SmtpPassword string `json:"smtp_password,omitempty"`
|
||||
SmtpFrom string `json:"smtp_from_email"`
|
||||
SmtpFromName string `json:"smtp_from_name"`
|
||||
SmtpUseTLS bool `json:"smtp_use_tls"`
|
||||
SMTPHost string `json:"smtp_host"`
|
||||
SMTPPort int `json:"smtp_port"`
|
||||
SMTPUsername string `json:"smtp_username"`
|
||||
SMTPPassword string `json:"smtp_password,omitempty"`
|
||||
SMTPFrom string `json:"smtp_from_email"`
|
||||
SMTPFromName string `json:"smtp_from_name"`
|
||||
SMTPUseTLS bool `json:"smtp_use_tls"`
|
||||
|
||||
TurnstileEnabled bool `json:"turnstile_enabled"`
|
||||
TurnstileSiteKey string `json:"turnstile_site_key"`
|
||||
@@ -20,9 +20,9 @@ type SystemSettings struct {
|
||||
SiteName string `json:"site_name"`
|
||||
SiteLogo string `json:"site_logo"`
|
||||
SiteSubtitle string `json:"site_subtitle"`
|
||||
ApiBaseUrl string `json:"api_base_url"`
|
||||
APIBaseURL string `json:"api_base_url"`
|
||||
ContactInfo string `json:"contact_info"`
|
||||
DocUrl string `json:"doc_url"`
|
||||
DocURL string `json:"doc_url"`
|
||||
|
||||
DefaultConcurrency int `json:"default_concurrency"`
|
||||
DefaultBalance float64 `json:"default_balance"`
|
||||
@@ -43,8 +43,8 @@ type PublicSettings struct {
|
||||
SiteName string `json:"site_name"`
|
||||
SiteLogo string `json:"site_logo"`
|
||||
SiteSubtitle string `json:"site_subtitle"`
|
||||
ApiBaseUrl string `json:"api_base_url"`
|
||||
APIBaseURL string `json:"api_base_url"`
|
||||
ContactInfo string `json:"contact_info"`
|
||||
DocUrl string `json:"doc_url"`
|
||||
DocURL string `json:"doc_url"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
@@ -39,9 +39,9 @@ func (h *SettingHandler) GetPublicSettings(c *gin.Context) {
|
||||
SiteName: settings.SiteName,
|
||||
SiteLogo: settings.SiteLogo,
|
||||
SiteSubtitle: settings.SiteSubtitle,
|
||||
ApiBaseUrl: settings.ApiBaseUrl,
|
||||
APIBaseURL: settings.APIBaseURL,
|
||||
ContactInfo: settings.ContactInfo,
|
||||
DocUrl: settings.DocUrl,
|
||||
DocURL: settings.DocURL,
|
||||
Version: h.version,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -79,9 +79,9 @@ func (s *SettingService) GetPublicSettings(ctx context.Context) (*PublicSettings
|
||||
SiteName: s.getStringOrDefault(settings, SettingKeySiteName, "Sub2API"),
|
||||
SiteLogo: settings[SettingKeySiteLogo],
|
||||
SiteSubtitle: s.getStringOrDefault(settings, SettingKeySiteSubtitle, "Subscription to API Conversion Platform"),
|
||||
ApiBaseUrl: settings[SettingKeyApiBaseUrl],
|
||||
APIBaseURL: settings[SettingKeyApiBaseUrl],
|
||||
ContactInfo: settings[SettingKeyContactInfo],
|
||||
DocUrl: settings[SettingKeyDocUrl],
|
||||
DocURL: settings[SettingKeyDocUrl],
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -94,15 +94,15 @@ func (s *SettingService) UpdateSettings(ctx context.Context, settings *SystemSet
|
||||
updates[SettingKeyEmailVerifyEnabled] = strconv.FormatBool(settings.EmailVerifyEnabled)
|
||||
|
||||
// 邮件服务设置(只有非空才更新密码)
|
||||
updates[SettingKeySmtpHost] = settings.SmtpHost
|
||||
updates[SettingKeySmtpPort] = strconv.Itoa(settings.SmtpPort)
|
||||
updates[SettingKeySmtpUsername] = settings.SmtpUsername
|
||||
if settings.SmtpPassword != "" {
|
||||
updates[SettingKeySmtpPassword] = settings.SmtpPassword
|
||||
updates[SettingKeySmtpHost] = settings.SMTPHost
|
||||
updates[SettingKeySmtpPort] = strconv.Itoa(settings.SMTPPort)
|
||||
updates[SettingKeySmtpUsername] = settings.SMTPUsername
|
||||
if settings.SMTPPassword != "" {
|
||||
updates[SettingKeySmtpPassword] = settings.SMTPPassword
|
||||
}
|
||||
updates[SettingKeySmtpFrom] = settings.SmtpFrom
|
||||
updates[SettingKeySmtpFromName] = settings.SmtpFromName
|
||||
updates[SettingKeySmtpUseTLS] = strconv.FormatBool(settings.SmtpUseTLS)
|
||||
updates[SettingKeySmtpFrom] = settings.SMTPFrom
|
||||
updates[SettingKeySmtpFromName] = settings.SMTPFromName
|
||||
updates[SettingKeySmtpUseTLS] = strconv.FormatBool(settings.SMTPUseTLS)
|
||||
|
||||
// Cloudflare Turnstile 设置(只有非空才更新密钥)
|
||||
updates[SettingKeyTurnstileEnabled] = strconv.FormatBool(settings.TurnstileEnabled)
|
||||
@@ -115,9 +115,9 @@ func (s *SettingService) UpdateSettings(ctx context.Context, settings *SystemSet
|
||||
updates[SettingKeySiteName] = settings.SiteName
|
||||
updates[SettingKeySiteLogo] = settings.SiteLogo
|
||||
updates[SettingKeySiteSubtitle] = settings.SiteSubtitle
|
||||
updates[SettingKeyApiBaseUrl] = settings.ApiBaseUrl
|
||||
updates[SettingKeyApiBaseUrl] = settings.APIBaseURL
|
||||
updates[SettingKeyContactInfo] = settings.ContactInfo
|
||||
updates[SettingKeyDocUrl] = settings.DocUrl
|
||||
updates[SettingKeyDocUrl] = settings.DocURL
|
||||
|
||||
// 默认配置
|
||||
updates[SettingKeyDefaultConcurrency] = strconv.Itoa(settings.DefaultConcurrency)
|
||||
@@ -223,26 +223,26 @@ func (s *SettingService) parseSettings(settings map[string]string) *SystemSettin
|
||||
result := &SystemSettings{
|
||||
RegistrationEnabled: settings[SettingKeyRegistrationEnabled] == "true",
|
||||
EmailVerifyEnabled: settings[SettingKeyEmailVerifyEnabled] == "true",
|
||||
SmtpHost: settings[SettingKeySmtpHost],
|
||||
SmtpUsername: settings[SettingKeySmtpUsername],
|
||||
SmtpFrom: settings[SettingKeySmtpFrom],
|
||||
SmtpFromName: settings[SettingKeySmtpFromName],
|
||||
SmtpUseTLS: settings[SettingKeySmtpUseTLS] == "true",
|
||||
SMTPHost: settings[SettingKeySmtpHost],
|
||||
SMTPUsername: settings[SettingKeySmtpUsername],
|
||||
SMTPFrom: settings[SettingKeySmtpFrom],
|
||||
SMTPFromName: settings[SettingKeySmtpFromName],
|
||||
SMTPUseTLS: settings[SettingKeySmtpUseTLS] == "true",
|
||||
TurnstileEnabled: settings[SettingKeyTurnstileEnabled] == "true",
|
||||
TurnstileSiteKey: settings[SettingKeyTurnstileSiteKey],
|
||||
SiteName: s.getStringOrDefault(settings, SettingKeySiteName, "Sub2API"),
|
||||
SiteLogo: settings[SettingKeySiteLogo],
|
||||
SiteSubtitle: s.getStringOrDefault(settings, SettingKeySiteSubtitle, "Subscription to API Conversion Platform"),
|
||||
ApiBaseUrl: settings[SettingKeyApiBaseUrl],
|
||||
APIBaseURL: settings[SettingKeyApiBaseUrl],
|
||||
ContactInfo: settings[SettingKeyContactInfo],
|
||||
DocUrl: settings[SettingKeyDocUrl],
|
||||
DocURL: settings[SettingKeyDocUrl],
|
||||
}
|
||||
|
||||
// 解析整数类型
|
||||
if port, err := strconv.Atoi(settings[SettingKeySmtpPort]); err == nil {
|
||||
result.SmtpPort = port
|
||||
result.SMTPPort = port
|
||||
} else {
|
||||
result.SmtpPort = 587
|
||||
result.SMTPPort = 587
|
||||
}
|
||||
|
||||
if concurrency, err := strconv.Atoi(settings[SettingKeyDefaultConcurrency]); err == nil {
|
||||
@@ -259,7 +259,7 @@ func (s *SettingService) parseSettings(settings map[string]string) *SystemSettin
|
||||
}
|
||||
|
||||
// 敏感信息直接返回,方便测试连接时使用
|
||||
result.SmtpPassword = settings[SettingKeySmtpPassword]
|
||||
result.SMTPPassword = settings[SettingKeySmtpPassword]
|
||||
result.TurnstileSecretKey = settings[SettingKeyTurnstileSecretKey]
|
||||
|
||||
// Model fallback settings
|
||||
|
||||
@@ -4,13 +4,13 @@ type SystemSettings struct {
|
||||
RegistrationEnabled bool
|
||||
EmailVerifyEnabled bool
|
||||
|
||||
SmtpHost string
|
||||
SmtpPort int
|
||||
SmtpUsername string
|
||||
SmtpPassword string
|
||||
SmtpFrom string
|
||||
SmtpFromName string
|
||||
SmtpUseTLS bool
|
||||
SMTPHost string
|
||||
SMTPPort int
|
||||
SMTPUsername string
|
||||
SMTPPassword string
|
||||
SMTPFrom string
|
||||
SMTPFromName string
|
||||
SMTPUseTLS bool
|
||||
|
||||
TurnstileEnabled bool
|
||||
TurnstileSiteKey string
|
||||
@@ -19,9 +19,9 @@ type SystemSettings struct {
|
||||
SiteName string
|
||||
SiteLogo string
|
||||
SiteSubtitle string
|
||||
ApiBaseUrl string
|
||||
APIBaseURL string
|
||||
ContactInfo string
|
||||
DocUrl string
|
||||
DocURL string
|
||||
|
||||
DefaultConcurrency int
|
||||
DefaultBalance float64
|
||||
@@ -42,8 +42,8 @@ type PublicSettings struct {
|
||||
SiteName string
|
||||
SiteLogo string
|
||||
SiteSubtitle string
|
||||
ApiBaseUrl string
|
||||
APIBaseURL string
|
||||
ContactInfo string
|
||||
DocUrl string
|
||||
DocURL string
|
||||
Version string
|
||||
}
|
||||
|
||||
@@ -338,7 +338,19 @@
|
||||
|
||||
<!-- Account Type Selection (Gemini) -->
|
||||
<div v-if="form.platform === 'gemini'">
|
||||
<label class="input-label">{{ t('admin.accounts.accountType') }}</label>
|
||||
<div class="flex items-center justify-between">
|
||||
<label class="input-label">{{ t('admin.accounts.accountType') }}</label>
|
||||
<button
|
||||
type="button"
|
||||
@click="showGeminiHelpDialog = true"
|
||||
class="flex items-center gap-1 rounded px-2 py-1 text-xs text-blue-600 hover:bg-blue-50 dark:text-blue-400 dark:hover:bg-blue-900/20"
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9 5.25h.008v.008H12v-.008z" />
|
||||
</svg>
|
||||
{{ t('admin.accounts.gemini.helpButton') }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="mt-2 grid grid-cols-2 gap-3" data-tour="account-form-type">
|
||||
<button
|
||||
type="button"
|
||||
@@ -439,15 +451,6 @@
|
||||
>
|
||||
{{ t('admin.accounts.gemini.accountType.apiKeyLink') }}
|
||||
</a>
|
||||
<span class="text-purple-400">·</span>
|
||||
<a
|
||||
:href="geminiHelpLinks.aiStudioPricing"
|
||||
class="font-medium text-blue-600 hover:underline dark:text-blue-400"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.accountType.quotaLink') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -687,79 +690,6 @@
|
||||
</div>
|
||||
<p class="input-hint">{{ t('admin.accounts.gemini.tier.hint') }}</p>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 rounded-lg border border-blue-200 bg-blue-50 p-4 text-xs text-blue-900 dark:border-blue-800/40 dark:bg-blue-900/20 dark:text-blue-200">
|
||||
<div class="flex items-start gap-3">
|
||||
<svg
|
||||
class="h-5 w-5 flex-shrink-0 text-blue-600 dark:text-blue-400"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<div class="min-w-0">
|
||||
<p class="text-sm font-medium text-blue-800 dark:text-blue-300">
|
||||
{{ t('admin.accounts.gemini.setupGuide.title') }}
|
||||
</p>
|
||||
<div class="mt-2 space-y-2">
|
||||
<div>
|
||||
<p class="font-semibold text-blue-800 dark:text-blue-300">
|
||||
{{ t('admin.accounts.gemini.setupGuide.checklistTitle') }}
|
||||
</p>
|
||||
<ul class="mt-1 list-disc space-y-1 pl-4">
|
||||
<li>
|
||||
{{ t('admin.accounts.gemini.setupGuide.checklistItems.usIp') }}
|
||||
<a
|
||||
:href="geminiHelpLinks.countryCheck"
|
||||
class="ml-1 text-blue-600 hover:underline dark:text-blue-400"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.setupGuide.links.countryCheck') }}
|
||||
</a>
|
||||
</li>
|
||||
<li>{{ t('admin.accounts.gemini.setupGuide.checklistItems.age') }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="font-semibold text-blue-800 dark:text-blue-300">
|
||||
{{ t('admin.accounts.gemini.setupGuide.activationTitle') }}
|
||||
</p>
|
||||
<ul class="mt-1 list-disc space-y-1 pl-4">
|
||||
<li>
|
||||
{{ t('admin.accounts.gemini.setupGuide.activationItems.geminiWeb') }}
|
||||
<a
|
||||
:href="geminiHelpLinks.geminiWebActivation"
|
||||
class="ml-1 text-blue-600 hover:underline dark:text-blue-400"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.setupGuide.links.geminiWebActivation') }}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
{{ t('admin.accounts.gemini.setupGuide.activationItems.gcpProject') }}
|
||||
<a
|
||||
:href="geminiHelpLinks.gcpProject"
|
||||
class="ml-1 text-blue-600 hover:underline dark:text-blue-400"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.setupGuide.links.gcpProject') }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Account Type Selection (Antigravity - OAuth only) -->
|
||||
@@ -1188,165 +1118,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Gemini 配额与限流政策说明 -->
|
||||
<div v-if="form.platform === 'gemini'" class="border-t border-gray-200 pt-4 dark:border-dark-600">
|
||||
<div class="rounded-lg bg-gray-50 p-4 dark:bg-gray-800/40">
|
||||
<div class="flex items-start gap-3">
|
||||
<svg
|
||||
class="h-5 w-5 flex-shrink-0 text-gray-500 dark:text-gray-400"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"
|
||||
/>
|
||||
</svg>
|
||||
<div class="min-w-0">
|
||||
<p class="text-sm font-medium text-gray-800 dark:text-gray-200">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.title') }}
|
||||
</p>
|
||||
<p class="mt-1 text-xs text-gray-600 dark:text-gray-400">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.note') }}
|
||||
</p>
|
||||
<div class="mt-3 overflow-x-auto">
|
||||
<table class="min-w-full text-xs text-gray-700 dark:text-gray-300">
|
||||
<thead>
|
||||
<tr class="border-b border-gray-200 dark:border-gray-700">
|
||||
<th class="px-2 py-1.5 text-left font-semibold">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.columns.channel') }}
|
||||
</th>
|
||||
<th class="px-2 py-1.5 text-left font-semibold">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.columns.account') }}
|
||||
</th>
|
||||
<th class="px-2 py-1.5 text-left font-semibold">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.columns.limits') }}
|
||||
</th>
|
||||
<th class="px-2 py-1.5 text-left font-semibold">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.columns.docs') }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="border-b border-gray-100 dark:border-gray-800">
|
||||
<td class="px-2 py-1.5 align-top" rowspan="2">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.cli.channel') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.cli.free') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.cli.limitsFree') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5 align-top" rowspan="2">
|
||||
<a
|
||||
:href="geminiQuotaDocs.codeAssist"
|
||||
class="text-blue-600 hover:underline dark:text-blue-400"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.docs.codeAssist') }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-100 dark:border-gray-800">
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.cli.premium') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.cli.limitsPremium') }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-100 dark:border-gray-800">
|
||||
<td class="px-2 py-1.5 align-top">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.gcloud.channel') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.gcloud.account') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.gcloud.limits') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5 align-top">
|
||||
<a
|
||||
:href="geminiQuotaDocs.codeAssist"
|
||||
class="text-blue-600 hover:underline dark:text-blue-400"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.docs.codeAssist') }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-100 dark:border-gray-800">
|
||||
<td class="px-2 py-1.5 align-top" rowspan="2">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.aiStudio.channel') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.aiStudio.free') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.aiStudio.limitsFree') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5 align-top" rowspan="2">
|
||||
<a
|
||||
:href="geminiQuotaDocs.aiStudio"
|
||||
class="text-blue-600 hover:underline dark:text-blue-400"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.docs.aiStudio') }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-100 dark:border-gray-800">
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.aiStudio.paid') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.aiStudio.limitsPaid') }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-2 py-1.5 align-top" rowspan="2">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.customOAuth.channel') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.customOAuth.free') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.customOAuth.limitsFree') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5 align-top" rowspan="2">
|
||||
<a
|
||||
:href="geminiQuotaDocs.vertex"
|
||||
class="text-blue-600 hover:underline dark:text-blue-400"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.docs.vertex') }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.customOAuth.paid') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.customOAuth.limitsPaid') }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Temp Unschedulable Rules -->
|
||||
@@ -1717,6 +1488,214 @@
|
||||
</div>
|
||||
</template>
|
||||
</BaseDialog>
|
||||
|
||||
<!-- Gemini Help Dialog -->
|
||||
<BaseDialog
|
||||
:show="showGeminiHelpDialog"
|
||||
:title="t('admin.accounts.gemini.helpDialog.title')"
|
||||
@close="showGeminiHelpDialog = false"
|
||||
max-width="max-w-3xl"
|
||||
>
|
||||
<div class="space-y-6">
|
||||
<!-- Setup Guide Section -->
|
||||
<div>
|
||||
<h3 class="mb-3 text-sm font-semibold text-gray-900 dark:text-white">
|
||||
{{ t('admin.accounts.gemini.setupGuide.title') }}
|
||||
</h3>
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<p class="mb-2 text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ t('admin.accounts.gemini.setupGuide.checklistTitle') }}
|
||||
</p>
|
||||
<ul class="list-inside list-disc space-y-1 text-sm text-gray-600 dark:text-gray-400">
|
||||
<li>{{ t('admin.accounts.gemini.setupGuide.checklistItems.usIp') }}</li>
|
||||
<li>{{ t('admin.accounts.gemini.setupGuide.checklistItems.age') }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="mb-2 text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ t('admin.accounts.gemini.setupGuide.activationTitle') }}
|
||||
</p>
|
||||
<ul class="list-inside list-disc space-y-1 text-sm text-gray-600 dark:text-gray-400">
|
||||
<li>{{ t('admin.accounts.gemini.setupGuide.activationItems.geminiWeb') }}</li>
|
||||
<li>{{ t('admin.accounts.gemini.setupGuide.activationItems.gcpProject') }}</li>
|
||||
</ul>
|
||||
<div class="mt-2 flex flex-wrap gap-2">
|
||||
<a
|
||||
href="https://gemini.google.com/faq#location"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
class="text-sm text-blue-600 hover:underline dark:text-blue-400"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.setupGuide.links.countryCheck') }}
|
||||
</a>
|
||||
<span class="text-gray-400">·</span>
|
||||
<a
|
||||
href="https://gemini.google.com"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
class="text-sm text-blue-600 hover:underline dark:text-blue-400"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.setupGuide.links.geminiWebActivation') }}
|
||||
</a>
|
||||
<span class="text-gray-400">·</span>
|
||||
<a
|
||||
href="https://console.cloud.google.com"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
class="text-sm text-blue-600 hover:underline dark:text-blue-400"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.setupGuide.links.gcpProject') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quota Policy Section -->
|
||||
<div class="border-t border-gray-200 pt-6 dark:border-dark-600">
|
||||
<h3 class="mb-3 text-sm font-semibold text-gray-900 dark:text-white">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.title') }}
|
||||
</h3>
|
||||
<p class="mb-4 text-xs text-amber-600 dark:text-amber-400">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.note') }}
|
||||
</p>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full text-xs">
|
||||
<thead class="bg-gray-50 dark:bg-dark-600">
|
||||
<tr>
|
||||
<th class="px-3 py-2 text-left font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.columns.channel') }}
|
||||
</th>
|
||||
<th class="px-3 py-2 text-left font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.columns.account') }}
|
||||
</th>
|
||||
<th class="px-3 py-2 text-left font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.columns.limits') }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-200 dark:divide-dark-600">
|
||||
<tr>
|
||||
<td class="px-3 py-2 text-gray-900 dark:text-white">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.googleOne.channel') }}
|
||||
</td>
|
||||
<td class="px-3 py-2 text-gray-600 dark:text-gray-400">Free</td>
|
||||
<td class="px-3 py-2 text-gray-600 dark:text-gray-400">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.googleOne.limitsFree') }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-3 py-2 text-gray-900 dark:text-white"></td>
|
||||
<td class="px-3 py-2 text-gray-600 dark:text-gray-400">Pro</td>
|
||||
<td class="px-3 py-2 text-gray-600 dark:text-gray-400">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.googleOne.limitsPro') }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-3 py-2 text-gray-900 dark:text-white"></td>
|
||||
<td class="px-3 py-2 text-gray-600 dark:text-gray-400">Ultra</td>
|
||||
<td class="px-3 py-2 text-gray-600 dark:text-gray-400">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.googleOne.limitsUltra') }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-3 py-2 text-gray-900 dark:text-white">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.gcp.channel') }}
|
||||
</td>
|
||||
<td class="px-3 py-2 text-gray-600 dark:text-gray-400">Standard</td>
|
||||
<td class="px-3 py-2 text-gray-600 dark:text-gray-400">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.gcp.limitsStandard') }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-3 py-2 text-gray-900 dark:text-white"></td>
|
||||
<td class="px-3 py-2 text-gray-600 dark:text-gray-400">Enterprise</td>
|
||||
<td class="px-3 py-2 text-gray-600 dark:text-gray-400">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.gcp.limitsEnterprise') }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-3 py-2 text-gray-900 dark:text-white">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.aiStudio.channel') }}
|
||||
</td>
|
||||
<td class="px-3 py-2 text-gray-600 dark:text-gray-400">Free</td>
|
||||
<td class="px-3 py-2 text-gray-600 dark:text-gray-400">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.aiStudio.limitsFree') }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-3 py-2 text-gray-900 dark:text-white"></td>
|
||||
<td class="px-3 py-2 text-gray-600 dark:text-gray-400">Paid</td>
|
||||
<td class="px-3 py-2 text-gray-600 dark:text-gray-400">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.aiStudio.limitsPaid') }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="mt-4 flex flex-wrap gap-3">
|
||||
<a
|
||||
:href="geminiQuotaDocs.codeAssist"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
class="text-sm text-blue-600 hover:underline dark:text-blue-400"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.docs.codeAssist') }}
|
||||
</a>
|
||||
<a
|
||||
:href="geminiQuotaDocs.aiStudio"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
class="text-sm text-blue-600 hover:underline dark:text-blue-400"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.docs.aiStudio') }}
|
||||
</a>
|
||||
<a
|
||||
:href="geminiQuotaDocs.vertex"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
class="text-sm text-blue-600 hover:underline dark:text-blue-400"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.docs.vertex') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- API Key Links Section -->
|
||||
<div class="border-t border-gray-200 pt-6 dark:border-dark-600">
|
||||
<h3 class="mb-3 text-sm font-semibold text-gray-900 dark:text-white">
|
||||
{{ t('admin.accounts.gemini.helpDialog.apiKeySection') }}
|
||||
</h3>
|
||||
<div class="flex flex-wrap gap-3">
|
||||
<a
|
||||
:href="geminiHelpLinks.apiKey"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
class="text-sm text-blue-600 hover:underline dark:text-blue-400"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.accountType.apiKeyLink') }}
|
||||
</a>
|
||||
<a
|
||||
:href="geminiHelpLinks.aiStudioPricing"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
class="text-sm text-blue-600 hover:underline dark:text-blue-400"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.accountType.quotaLink') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="flex justify-end">
|
||||
<button @click="showGeminiHelpDialog = false" type="button" class="btn btn-primary">
|
||||
{{ t('common.close') }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</BaseDialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -1860,6 +1839,7 @@ const tempUnschedRules = ref<TempUnschedRuleForm[]>([])
|
||||
const geminiOAuthType = ref<'code_assist' | 'google_one' | 'ai_studio'>('google_one')
|
||||
const geminiAIStudioOAuthEnabled = ref(false)
|
||||
const showAdvancedOAuth = ref(false)
|
||||
const showGeminiHelpDialog = ref(false)
|
||||
|
||||
// Gemini tier selection (used as fallback when auto-detection is unavailable/fails)
|
||||
const geminiTierGoogleOne = ref<'google_one_free' | 'google_ai_pro' | 'google_ai_ultra'>('google_one_free')
|
||||
|
||||
@@ -1252,28 +1252,33 @@ export default {
|
||||
},
|
||||
// Gemini specific (platform-wide)
|
||||
gemini: {
|
||||
helpButton: 'Help',
|
||||
helpDialog: {
|
||||
title: 'Gemini Usage Guide',
|
||||
apiKeySection: 'API Key Links'
|
||||
},
|
||||
modelPassthrough: 'Gemini Model Passthrough',
|
||||
modelPassthroughDesc:
|
||||
'All model requests are forwarded directly to the Gemini API without model restrictions or mappings.',
|
||||
baseUrlHint: 'Leave default for official Gemini API',
|
||||
apiKeyHint: 'Your Gemini API Key (starts with AIza)',
|
||||
tier: {
|
||||
label: 'Tier (Quota Level)',
|
||||
label: 'Account Tier',
|
||||
hint: 'Tip: The system will try to auto-detect the tier first; if auto-detection is unavailable or fails, your selected tier is used as a fallback (simulated quota).',
|
||||
aiStudioHint:
|
||||
'AI Studio quotas are per-model (Pro/Flash are limited independently). If billing is enabled, choose Pay-as-you-go.',
|
||||
googleOne: {
|
||||
free: 'Google One Free (1000 RPD / 60 RPM, shared pool)',
|
||||
pro: 'Google AI Pro (1500 RPD / 120 RPM, shared pool)',
|
||||
ultra: 'Google AI Ultra (2000 RPD / 120 RPM, shared pool)'
|
||||
free: 'Google One Free',
|
||||
pro: 'Google One Pro',
|
||||
ultra: 'Google One Ultra'
|
||||
},
|
||||
gcp: {
|
||||
standard: 'GCP Standard (1500 RPD / 120 RPM, shared pool)',
|
||||
enterprise: 'GCP Enterprise (2000 RPD / 120 RPM, shared pool)'
|
||||
standard: 'GCP Standard',
|
||||
enterprise: 'GCP Enterprise'
|
||||
},
|
||||
aiStudio: {
|
||||
free: 'AI Studio Free Tier (Pro: 50 RPD / 2 RPM; Flash: 1500 RPD / 15 RPM)',
|
||||
paid: 'AI Studio Pay-as-you-go (Pro: ∞ RPD / 1000 RPM; Flash: ∞ RPD / 2000 RPM)'
|
||||
free: 'Google AI Free',
|
||||
paid: 'Google AI Pay-as-you-go'
|
||||
}
|
||||
},
|
||||
accountType: {
|
||||
|
||||
@@ -1391,26 +1391,31 @@ export default {
|
||||
},
|
||||
// Gemini specific (platform-wide)
|
||||
gemini: {
|
||||
helpButton: '使用帮助',
|
||||
helpDialog: {
|
||||
title: 'Gemini 使用指南',
|
||||
apiKeySection: 'API Key 相关链接'
|
||||
},
|
||||
modelPassthrough: 'Gemini 直接转发模型',
|
||||
modelPassthroughDesc: '所有模型请求将直接转发至 Gemini API,不进行模型限制或映射。',
|
||||
baseUrlHint: '留空使用官方 Gemini API',
|
||||
apiKeyHint: '您的 Gemini API Key(以 AIza 开头)',
|
||||
tier: {
|
||||
label: 'Tier(配额等级)',
|
||||
hint: '提示:系统会优先尝试自动识别 Tier;若自动识别不可用或失败,则使用你选择的 Tier 作为回退(本地模拟配额)。',
|
||||
label: '账号等级',
|
||||
hint: '提示:系统会优先尝试自动识别账号等级;若自动识别不可用或失败,则使用你选择的等级作为回退(本地模拟配额)。',
|
||||
aiStudioHint: 'AI Studio 的配额是按模型分别限流(Pro/Flash 独立)。若已绑卡(按量付费),请选 Pay-as-you-go。',
|
||||
googleOne: {
|
||||
free: 'Google One Free(1000 RPD / 60 RPM,共享池)',
|
||||
pro: 'Google AI Pro(1500 RPD / 120 RPM,共享池)',
|
||||
ultra: 'Google AI Ultra(2000 RPD / 120 RPM,共享池)'
|
||||
free: 'Google One Free',
|
||||
pro: 'Google One Pro',
|
||||
ultra: 'Google One Ultra'
|
||||
},
|
||||
gcp: {
|
||||
standard: 'GCP Standard(1500 RPD / 120 RPM,共享池)',
|
||||
enterprise: 'GCP Enterprise(2000 RPD / 120 RPM,共享池)'
|
||||
standard: 'GCP Standard',
|
||||
enterprise: 'GCP Enterprise'
|
||||
},
|
||||
aiStudio: {
|
||||
free: 'AI Studio Free Tier(Pro: 50 RPD / 2 RPM;Flash: 1500 RPD / 15 RPM)',
|
||||
paid: 'AI Studio Pay-as-you-go(Pro: ∞ RPD / 1000 RPM;Flash: ∞ RPD / 2000 RPM)'
|
||||
free: 'Google AI Free',
|
||||
paid: 'Google AI Pay-as-you-go'
|
||||
}
|
||||
},
|
||||
accountType: {
|
||||
|
||||
Reference in New Issue
Block a user