feat(settings): 添加文档链接配置功能

- 后台系统设置新增文档链接(doc_url)配置项
- 首页顶部导航栏显示文档链接图标(条件渲染)
- Footer区域添加文档链接和GitHub链接
- 支持中英文国际化
This commit is contained in:
shaw
2025-12-24 21:30:19 +08:00
parent e65e9587b4
commit 2e7818d688
10 changed files with 66 additions and 6 deletions

View File

@@ -60,6 +60,7 @@ type UpdateSettingsRequest struct {
SiteSubtitle string `json:"site_subtitle"`
ApiBaseUrl string `json:"api_base_url"`
ContactInfo string `json:"contact_info"`
DocUrl string `json:"doc_url"`
// 默认配置
DefaultConcurrency int `json:"default_concurrency"`
@@ -104,6 +105,7 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
SiteSubtitle: req.SiteSubtitle,
ApiBaseUrl: req.ApiBaseUrl,
ContactInfo: req.ContactInfo,
DocUrl: req.DocUrl,
DefaultConcurrency: req.DefaultConcurrency,
DefaultBalance: req.DefaultBalance,
}

View File

@@ -42,6 +42,7 @@ const (
SettingKeySiteSubtitle = "site_subtitle" // 网站副标题
SettingKeyApiBaseUrl = "api_base_url" // API端点地址用于客户端配置和导入
SettingKeyContactInfo = "contact_info" // 客服联系方式
SettingKeyDocUrl = "doc_url" // 文档链接
// 默认配置
SettingKeyDefaultConcurrency = "default_concurrency" // 新用户默认并发量
@@ -80,6 +81,7 @@ type SystemSettings struct {
SiteSubtitle string `json:"site_subtitle"`
ApiBaseUrl string `json:"api_base_url"`
ContactInfo string `json:"contact_info"`
DocUrl string `json:"doc_url"`
// 默认配置
DefaultConcurrency int `json:"default_concurrency"`
@@ -97,5 +99,6 @@ type PublicSettings struct {
SiteSubtitle string `json:"site_subtitle"`
ApiBaseUrl string `json:"api_base_url"`
ContactInfo string `json:"contact_info"`
DocUrl string `json:"doc_url"`
Version string `json:"version"`
}

View File

@@ -54,6 +54,7 @@ func (s *SettingService) GetPublicSettings(ctx context.Context) (*model.PublicSe
model.SettingKeySiteSubtitle,
model.SettingKeyApiBaseUrl,
model.SettingKeyContactInfo,
model.SettingKeyDocUrl,
}
settings, err := s.settingRepo.GetMultiple(ctx, keys)
@@ -71,6 +72,7 @@ func (s *SettingService) GetPublicSettings(ctx context.Context) (*model.PublicSe
SiteSubtitle: s.getStringOrDefault(settings, model.SettingKeySiteSubtitle, "Subscription to API Conversion Platform"),
ApiBaseUrl: settings[model.SettingKeyApiBaseUrl],
ContactInfo: settings[model.SettingKeyContactInfo],
DocUrl: settings[model.SettingKeyDocUrl],
}, nil
}
@@ -106,6 +108,7 @@ func (s *SettingService) UpdateSettings(ctx context.Context, settings *model.Sys
updates[model.SettingKeySiteSubtitle] = settings.SiteSubtitle
updates[model.SettingKeyApiBaseUrl] = settings.ApiBaseUrl
updates[model.SettingKeyContactInfo] = settings.ContactInfo
updates[model.SettingKeyDocUrl] = settings.DocUrl
// 默认配置
updates[model.SettingKeyDefaultConcurrency] = strconv.Itoa(settings.DefaultConcurrency)
@@ -210,6 +213,7 @@ func (s *SettingService) parseSettings(settings map[string]string) *model.System
SiteSubtitle: s.getStringOrDefault(settings, model.SettingKeySiteSubtitle, "Subscription to API Conversion Platform"),
ApiBaseUrl: settings[model.SettingKeyApiBaseUrl],
ContactInfo: settings[model.SettingKeyContactInfo],
DocUrl: settings[model.SettingKeyDocUrl],
}
// 解析整数类型

View File

@@ -21,6 +21,7 @@ export interface SystemSettings {
site_subtitle: string;
api_base_url: string;
contact_info: string;
doc_url: string;
// SMTP settings
smtp_host: string;
smtp_port: number;

View File

@@ -2,6 +2,8 @@ export default {
// Home Page
home: {
viewOnGithub: 'View on GitHub',
viewDocs: 'View Documentation',
docs: 'Docs',
switchToLight: 'Switch to Light Mode',
switchToDark: 'Switch to Dark Mode',
dashboard: 'Dashboard',
@@ -1077,6 +1079,8 @@ export default {
contactInfo: 'Contact Info',
contactInfoPlaceholder: 'e.g., QQ: 123456789',
contactInfoHint: 'Customer support contact info, displayed on redeem page, profile, etc.',
docUrl: 'Documentation URL',
docUrlHint: 'Link to your documentation site. Leave empty to hide the documentation link.',
siteLogo: 'Site Logo',
uploadImage: 'Upload Image',
remove: 'Remove',

View File

@@ -2,6 +2,8 @@ export default {
// Home Page
home: {
viewOnGithub: '在 GitHub 上查看',
viewDocs: '查看文档',
docs: '文档',
switchToLight: '切换到浅色模式',
switchToDark: '切换到深色模式',
dashboard: '控制台',
@@ -1301,6 +1303,8 @@ export default {
contactInfo: '客服联系方式',
contactInfoPlaceholder: '例如QQ: 123456789',
contactInfoHint: '填写客服联系方式,将展示在兑换页面、个人资料等位置',
docUrl: '文档链接',
docUrlHint: '文档网站的链接。留空则隐藏文档链接。',
siteLogo: '站点Logo',
uploadImage: '上传图片',
remove: '移除',

View File

@@ -25,6 +25,7 @@ export const useAppStore = defineStore('app', () => {
const siteVersion = ref<string>('');
const contactInfo = ref<string>('');
const apiBaseUrl = ref<string>('');
const docUrl = ref<string>('');
// Version cache state
const versionLoaded = ref<boolean>(false);
@@ -297,6 +298,7 @@ export const useAppStore = defineStore('app', () => {
site_subtitle: '',
api_base_url: apiBaseUrl.value,
contact_info: contactInfo.value,
doc_url: docUrl.value,
version: siteVersion.value,
};
}
@@ -314,6 +316,7 @@ export const useAppStore = defineStore('app', () => {
siteVersion.value = data.version || '';
contactInfo.value = data.contact_info || '';
apiBaseUrl.value = data.api_base_url || '';
docUrl.value = data.doc_url || '';
publicSettingsLoaded.value = true;
return data;
} catch (error) {
@@ -347,6 +350,7 @@ export const useAppStore = defineStore('app', () => {
siteVersion,
contactInfo,
apiBaseUrl,
docUrl,
// Version state
versionLoaded,

View File

@@ -53,6 +53,7 @@ export interface PublicSettings {
site_subtitle: string;
api_base_url: string;
contact_info: string;
doc_url: string;
version: string;
}

View File

@@ -24,16 +24,17 @@
<!-- Language Switcher -->
<LocaleSwitcher />
<!-- GitHub Link -->
<!-- Doc Link -->
<a
:href="githubUrl"
v-if="docUrl"
:href="docUrl"
target="_blank"
rel="noopener noreferrer"
class="p-2 rounded-lg text-gray-500 hover:text-gray-700 dark:text-dark-400 dark:hover:text-white hover:bg-gray-100 dark:hover:bg-dark-800 transition-colors"
:title="t('home.viewOnGithub')"
:title="t('home.viewDocs')"
>
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 2C6.477 2 2 6.477 2 12c0 4.42 2.865 8.17 6.839 9.49.5.092.682-.217.682-.482 0-.237-.008-.866-.013-1.7-2.782.604-3.369-1.34-3.369-1.34-.454-1.156-1.11-1.464-1.11-1.464-.908-.62.069-.608.069-.608 1.003.07 1.531 1.03 1.531 1.03.892 1.529 2.341 1.087 2.91.831.092-.646.35-1.086.636-1.336-2.22-.253-4.555-1.11-4.555-4.943 0-1.091.39-1.984 1.029-2.683-.103-.253-.446-1.27.098-2.647 0 0 .84-.269 2.75 1.025A9.578 9.578 0 0112 6.836c.85.004 1.705.114 2.504.336 1.909-1.294 2.747-1.025 2.747-1.025.546 1.377.203 2.394.1 2.647.64.699 1.028 1.592 1.028 2.683 0 3.842-2.339 4.687-4.566 4.935.359.309.678.919.678 1.852 0 1.336-.012 2.415-.012 2.743 0 .267.18.578.688.48C19.138 20.167 22 16.418 22 12c0-5.523-4.477-10-10-10z" />
<svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 6.042A8.967 8.967 0 006 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 016 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 016-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0018 18a8.967 8.967 0 00-6 2.292m0-14.25v14.25" />
</svg>
</a>
@@ -253,10 +254,29 @@
<!-- Footer -->
<footer class="relative z-10 px-6 py-8 border-t border-gray-200/50 dark:border-dark-800/50">
<div class="max-w-6xl mx-auto text-center">
<div class="max-w-6xl mx-auto flex flex-col sm:flex-row items-center justify-center gap-4 text-center sm:text-left">
<p class="text-sm text-gray-500 dark:text-dark-400">
&copy; {{ currentYear }} {{ siteName }}. {{ t('home.footer.allRightsReserved') }}
</p>
<div class="flex items-center gap-4">
<a
v-if="docUrl"
:href="docUrl"
target="_blank"
rel="noopener noreferrer"
class="text-sm text-gray-500 hover:text-gray-700 dark:text-dark-400 dark:hover:text-white transition-colors"
>
{{ t('home.docs') }}
</a>
<a
:href="githubUrl"
target="_blank"
rel="noopener noreferrer"
class="text-sm text-gray-500 hover:text-gray-700 dark:text-dark-400 dark:hover:text-white transition-colors"
>
GitHub
</a>
</div>
</div>
</footer>
</div>
@@ -277,6 +297,7 @@ const authStore = useAuthStore();
const siteName = ref('Sub2API');
const siteLogo = ref('');
const siteSubtitle = ref('AI API Gateway Platform');
const docUrl = ref('');
// Theme
const isDark = ref(document.documentElement.classList.contains('dark'));
@@ -322,6 +343,7 @@ onMounted(async () => {
siteName.value = settings.site_name || 'Sub2API';
siteLogo.value = settings.site_logo || '';
siteSubtitle.value = settings.site_subtitle || 'AI API Gateway Platform';
docUrl.value = settings.doc_url || '';
} catch (error) {
console.error('Failed to load public settings:', error);
}

View File

@@ -287,6 +287,20 @@
<p class="mt-1.5 text-xs text-gray-500 dark:text-gray-400">{{ t('admin.settings.site.contactInfoHint') }}</p>
</div>
<!-- Doc URL -->
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
{{ t('admin.settings.site.docUrl') }}
</label>
<input
v-model="form.doc_url"
type="url"
class="input font-mono text-sm"
placeholder="https://docs.example.com"
/>
<p class="mt-1.5 text-xs text-gray-500 dark:text-gray-400">{{ t('admin.settings.site.docUrlHint') }}</p>
</div>
<!-- Site Logo Upload -->
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
@@ -541,6 +555,7 @@ const form = reactive<SystemSettings>({
site_subtitle: 'Subscription to API Conversion Platform',
api_base_url: '',
contact_info: '',
doc_url: '',
smtp_host: '',
smtp_port: 587,
smtp_username: '',