Commit aa6f2533 authored by IanShaw027's avatar IanShaw027
Browse files

merge: 合并 upstream/main 并解决冲突

解决了以下文件的冲突:
- backend/internal/handler/admin/setting_handler.go
  - 采用 upstream 的字段对齐风格和 *Configured 字段名
  - 添加 EnableIdentityPatch 和 IdentityPatchPrompt 字段

- backend/internal/handler/gateway_handler.go
  - 采用 upstream 的 billingErrorDetails 错误处理方式

- frontend/src/api/admin/settings.ts
  - 采用 upstream 的 *_configured 字段名
  - 添加 enable_identity_patch 和 identity_patch_prompt 字段

- frontend/src/views/admin/SettingsView.vue
  - 合并 turnstile_secret_key_configured 字段
  - 保留 enable_identity_patch 和 identity_patch_prompt 字段
parents f60f943d 46dda583
...@@ -493,6 +493,7 @@ import { useI18n } from 'vue-i18n' ...@@ -493,6 +493,7 @@ import { useI18n } from 'vue-i18n'
import { getPublicSettings } from '@/api/auth' import { getPublicSettings } from '@/api/auth'
import { useAuthStore } from '@/stores' import { useAuthStore } from '@/stores'
import LocaleSwitcher from '@/components/common/LocaleSwitcher.vue' import LocaleSwitcher from '@/components/common/LocaleSwitcher.vue'
import { sanitizeUrl } from '@/utils/url'
const { t } = useI18n() const { t } = useI18n()
...@@ -549,9 +550,9 @@ onMounted(async () => { ...@@ -549,9 +550,9 @@ onMounted(async () => {
try { try {
const settings = await getPublicSettings() const settings = await getPublicSettings()
siteName.value = settings.site_name || 'Sub2API' siteName.value = settings.site_name || 'Sub2API'
siteLogo.value = settings.site_logo || '' siteLogo.value = sanitizeUrl(settings.site_logo || '', { allowRelative: true })
siteSubtitle.value = settings.site_subtitle || 'AI API Gateway Platform' siteSubtitle.value = settings.site_subtitle || 'AI API Gateway Platform'
docUrl.value = settings.doc_url || '' docUrl.value = sanitizeUrl(settings.doc_url || '', { allowRelative: true })
} catch (error) { } catch (error) {
console.error('Failed to load public settings:', error) console.error('Failed to load public settings:', error)
} }
......
...@@ -255,7 +255,11 @@ ...@@ -255,7 +255,11 @@
placeholder="0x4AAAAAAA..." placeholder="0x4AAAAAAA..."
/> />
<p class="mt-1.5 text-xs text-gray-500 dark:text-gray-400"> <p class="mt-1.5 text-xs text-gray-500 dark:text-gray-400">
{{ t('admin.settings.turnstile.secretKeyHint') }} {{
form.turnstile_secret_key_configured
? t('admin.settings.turnstile.secretKeyConfiguredHint')
: t('admin.settings.turnstile.secretKeyHint')
}}
</p> </p>
</div> </div>
</div> </div>
...@@ -577,10 +581,18 @@ ...@@ -577,10 +581,18 @@
v-model="form.smtp_password" v-model="form.smtp_password"
type="password" type="password"
class="input" class="input"
:placeholder="t('admin.settings.smtp.passwordPlaceholder')" :placeholder="
form.smtp_password_configured
? t('admin.settings.smtp.passwordConfiguredPlaceholder')
: t('admin.settings.smtp.passwordPlaceholder')
"
/> />
<p class="mt-1.5 text-xs text-gray-500 dark:text-gray-400"> <p class="mt-1.5 text-xs text-gray-500 dark:text-gray-400">
{{ t('admin.settings.smtp.passwordHint') }} {{
form.smtp_password_configured
? t('admin.settings.smtp.passwordConfiguredHint')
: t('admin.settings.smtp.passwordHint')
}}
</p> </p>
</div> </div>
<div> <div>
...@@ -713,7 +725,7 @@ ...@@ -713,7 +725,7 @@
import { ref, reactive, onMounted } from 'vue' import { ref, reactive, onMounted } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { adminAPI } from '@/api' import { adminAPI } from '@/api'
import type { SystemSettings } from '@/api/admin/settings' import type { SystemSettings, UpdateSettingsRequest } from '@/api/admin/settings'
import AppLayout from '@/components/layout/AppLayout.vue' import AppLayout from '@/components/layout/AppLayout.vue'
import Toggle from '@/components/common/Toggle.vue' import Toggle from '@/components/common/Toggle.vue'
import { useAppStore } from '@/stores' import { useAppStore } from '@/stores'
...@@ -735,7 +747,12 @@ const adminApiKeyMasked = ref('') ...@@ -735,7 +747,12 @@ const adminApiKeyMasked = ref('')
const adminApiKeyOperating = ref(false) const adminApiKeyOperating = ref(false)
const newAdminApiKey = ref('') const newAdminApiKey = ref('')
const form = reactive<SystemSettings>({ type SettingsForm = SystemSettings & {
smtp_password: string
turnstile_secret_key: string
}
const form = reactive<SettingsForm>({
registration_enabled: true, registration_enabled: true,
email_verify_enabled: false, email_verify_enabled: false,
default_balance: 0, default_balance: 0,
...@@ -750,6 +767,7 @@ const form = reactive<SystemSettings>({ ...@@ -750,6 +767,7 @@ const form = reactive<SystemSettings>({
smtp_port: 587, smtp_port: 587,
smtp_username: '', smtp_username: '',
smtp_password: '', smtp_password: '',
smtp_password_configured: false,
smtp_from_email: '', smtp_from_email: '',
smtp_from_name: '', smtp_from_name: '',
smtp_use_tls: true, smtp_use_tls: true,
...@@ -757,6 +775,7 @@ const form = reactive<SystemSettings>({ ...@@ -757,6 +775,7 @@ const form = reactive<SystemSettings>({
turnstile_enabled: false, turnstile_enabled: false,
turnstile_site_key: '', turnstile_site_key: '',
turnstile_secret_key: '', turnstile_secret_key: '',
turnstile_secret_key_configured: false,
// Identity patch (Claude -> Gemini) // Identity patch (Claude -> Gemini)
enable_identity_patch: true, enable_identity_patch: true,
identity_patch_prompt: '' identity_patch_prompt: ''
...@@ -805,6 +824,8 @@ async function loadSettings() { ...@@ -805,6 +824,8 @@ async function loadSettings() {
try { try {
const settings = await adminAPI.settings.getSettings() const settings = await adminAPI.settings.getSettings()
Object.assign(form, settings) Object.assign(form, settings)
form.smtp_password = ''
form.turnstile_secret_key = ''
} catch (error: any) { } catch (error: any) {
appStore.showError( appStore.showError(
t('admin.settings.failedToLoad') + ': ' + (error.message || t('common.unknownError')) t('admin.settings.failedToLoad') + ': ' + (error.message || t('common.unknownError'))
...@@ -817,7 +838,32 @@ async function loadSettings() { ...@@ -817,7 +838,32 @@ async function loadSettings() {
async function saveSettings() { async function saveSettings() {
saving.value = true saving.value = true
try { try {
await adminAPI.settings.updateSettings(form) const payload: UpdateSettingsRequest = {
registration_enabled: form.registration_enabled,
email_verify_enabled: form.email_verify_enabled,
default_balance: form.default_balance,
default_concurrency: form.default_concurrency,
site_name: form.site_name,
site_logo: form.site_logo,
site_subtitle: form.site_subtitle,
api_base_url: form.api_base_url,
contact_info: form.contact_info,
doc_url: form.doc_url,
smtp_host: form.smtp_host,
smtp_port: form.smtp_port,
smtp_username: form.smtp_username,
smtp_password: form.smtp_password || undefined,
smtp_from_email: form.smtp_from_email,
smtp_from_name: form.smtp_from_name,
smtp_use_tls: form.smtp_use_tls,
turnstile_enabled: form.turnstile_enabled,
turnstile_site_key: form.turnstile_site_key,
turnstile_secret_key: form.turnstile_secret_key || undefined
}
const updated = await adminAPI.settings.updateSettings(payload)
Object.assign(form, updated)
form.smtp_password = ''
form.turnstile_secret_key = ''
// Refresh cached public settings so sidebar/header update immediately // Refresh cached public settings so sidebar/header update immediately
await appStore.fetchPublicSettings(true) await appStore.fetchPublicSettings(true)
appStore.showSuccess(t('admin.settings.settingsSaved')) appStore.showSuccess(t('admin.settings.settingsSaved'))
......
...@@ -277,6 +277,14 @@ const errors = reactive({ ...@@ -277,6 +277,14 @@ const errors = reactive({
// ==================== Lifecycle ==================== // ==================== Lifecycle ====================
onMounted(async () => { onMounted(async () => {
const expiredFlag = sessionStorage.getItem('auth_expired')
if (expiredFlag) {
sessionStorage.removeItem('auth_expired')
const message = t('auth.reloginRequired')
errorMessage.value = message
appStore.showWarning(message)
}
try { try {
const settings = await getPublicSettings() const settings = await getPublicSettings()
turnstileEnabled.value = settings.turnstile_enabled turnstileEnabled.value = settings.turnstile_enabled
......
This diff is collapsed.
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import checker from 'vite-plugin-checker';
import { resolve } from 'path';
export default defineConfig({
plugins: [
vue(),
checker({
typescript: true,
vueTsc: true
})
],
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
},
build: {
outDir: '../backend/internal/web/dist',
emptyOutDir: true
},
server: {
host: '0.0.0.0',
port: 3000,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true
},
'/setup': {
target: 'http://localhost:8080',
changeOrigin: true
}
}
}
});
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment