Compare commits

...

21 Commits

Author SHA1 Message Date
hkfires
aa1dedc932 feat(ui): mark runtime-only auth files and disable actions 2025-11-07 22:02:29 +08:00
hkfires
61e75eee97 feat(auth-files): add AI Studio and Gemini CLI with filename masking 2025-11-07 21:46:46 +08:00
hkfires
3a2d96725f fix(ui): align file-item footer and adjust badge spacing 2025-11-06 14:23:07 +08:00
Supra4E8C
8283e99909 fix(app.js):尝试修复codex配置异常丢失数据的问题 2025-11-05 18:06:22 +08:00
hkfires
181cba6886 feat(logs): limit lines, incremental updates, and highlighting 2025-11-03 18:44:50 +08:00
hkfires
aa729914c5 fix(ui): position API Keys/Providers action buttons; prevent overlap 2025-11-03 16:31:29 +08:00
hkfires
f98f31f2ed fix(i18n, ui): correct syntax error in generateDynamicTypeLabel method
- Move generateDynamicTypeLabel method from inside updateAuthFileFilterButtons to proper class method location
- Fix JavaScript syntax error that prevented app from loading
- Preserve all internationalization functionality from 257260b

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 16:05:51 +08:00
hkfires
1e79f918e2 fix(ui): harden key list rendering and config handling 2025-10-31 16:24:43 +08:00
Supra4E8C
257260b1d2 feat(i18n, ui): enhance file type filtering with internationalization support
- Updated the file type display logic to utilize i18n for dynamic translations.
- Refactored filter button definitions to include data attributes for improved localization.
- Added new translation keys for various file types and filter options in both English and Chinese.
- Implemented a method to refresh button texts upon language change, ensuring consistent UI updates.
2025-10-26 17:46:57 +08:00
Supra4E8C
8372906820 为筛选按钮容器 .auth-file-filter 改用事件委托,并在重新渲染时移除旧监听器,避免多次绑定导致回调重复执行。 2025-10-26 17:33:06 +08:00
Supra4E8C
5feea2e345 Merge pull request #10 from coulsontl/new_ui
feat(ui): 添加类型筛选和详细信息视图来优化认证文件管理,并优化布局结构
2025-10-26 17:23:09 +08:00
coulsontl
825ad53c2c refactor(ui): streamline auth file actions with event delegation
- Updated the auth file action buttons to use data attributes for improved event handling.
- Implemented event delegation for button actions (show details, download, delete) to enhance performance and maintainability.
- Added a hidden class in CSS to manage file item visibility more effectively.
- Refactored modal button actions to utilize event delegation for better code organization.
2025-10-26 17:09:33 +08:00
coulsontl
3e9413172c feat(ui): enhance auth file management with type filtering and detailed view
- Implemented file type collection and dynamic filter button updates based on available file types.
- Added a detailed view for auth files, displaying JSON content in a modal with copy functionality.
- Improved UI layout for file items and added responsive design for better usability.
2025-10-26 16:43:06 +08:00
Supra4E8C
89099b58ff update README 2025-10-26 14:56:54 +08:00
Supra4E8C
7509a1eddc 更新补全i18n国际化文本 2025-10-26 14:54:07 +08:00
hkfires
e92784f951 feat(ui): add auth file success/failure stats; expand list height 2025-10-21 21:59:08 +08:00
hkfires
d26695da76 feat(ui,keys): granular masking, stats match, legacy format
- Make maskApiKey progressive for short keys to reduce exposure
- When aggregating usage, fall back to masked key to match stored stats
- Support legacy provider config `api-keys` by mapping to `api-key-entries`
- Add scrolling for provider lists >5 and reset styles when empty
- Improves privacy, fixes mismatched stats display, and preserves compatibility
2025-10-21 21:08:09 +08:00
Supra4E8C
8964030ade 尝试修复bug 2025-10-21 12:31:22 +08:00
hkfires
0b9abdf9b1 fix(logs): auto-scroll to latest on full reload 2025-10-20 14:57:15 +08:00
hkfires
a208a484ff feat(config-ui): add YAML config editor with save/reload support 2025-10-19 22:40:08 +08:00
Supra4E8C
369cf52346 0.1.7 2025-10-18 17:04:29 +08:00
7 changed files with 2497 additions and 229 deletions

2
.gitignore vendored
View File

@@ -22,4 +22,6 @@ package-lock.json
Thumbs.db Thumbs.db
CLAUDE.md CLAUDE.md
.claude
AGENTS.md AGENTS.md
.serena

View File

@@ -10,7 +10,7 @@ Example URL:
https://remote.router-for.me/ https://remote.router-for.me/
Minimum required version: ≥ 6.0.0 Minimum required version: ≥ 6.0.0
Recommended version: ≥ 6.1.3 Recommended version: ≥ 6.2.32
Since version 6.0.19, the WebUI has been rolled into the main program. You can access it by going to `/management.html` on the external port after firing up the main project. Since version 6.0.19, the WebUI has been rolled into the main program. You can access it by going to `/management.html` on the external port after firing up the main project.

View File

@@ -9,7 +9,7 @@ https://remote.router-for.me/
最低可用版本 ≥ 6.0.0 最低可用版本 ≥ 6.0.0
推荐版本 ≥ 6.1.3 推荐版本 ≥ 6.2.32
自6.0.19起WebUI已经集成在主程序中 可以通过主项目开启的外部端口的`/management.html`访问 自6.0.19起WebUI已经集成在主程序中 可以通过主项目开启的外部端口的`/management.html`访问

1522
app.js

File diff suppressed because it is too large Load Diff

124
i18n.js
View File

@@ -38,6 +38,9 @@ const i18n = {
'common.base_url': '地址', 'common.base_url': '地址',
'common.proxy_url': '代理', 'common.proxy_url': '代理',
'common.alias': '别名', 'common.alias': '别名',
'common.failure': '失败',
'common.unknown_error': '未知错误',
'common.copy': '复制',
// 页面标题 // 页面标题
'title.main': 'CLI Proxy API Management Center', 'title.main': 'CLI Proxy API Management Center',
@@ -82,6 +85,7 @@ const i18n = {
'nav.ai_providers': 'AI 提供商', 'nav.ai_providers': 'AI 提供商',
'nav.auth_files': '认证文件', 'nav.auth_files': '认证文件',
'nav.usage_stats': '使用统计', 'nav.usage_stats': '使用统计',
'nav.config_management': '配置管理',
'nav.logs': '日志查看', 'nav.logs': '日志查看',
'nav.system_info': '系统信息', 'nav.system_info': '系统信息',
@@ -218,6 +222,25 @@ const i18n = {
'auth_files.delete_success': '文件删除成功', 'auth_files.delete_success': '文件删除成功',
'auth_files.delete_all_success': '成功删除', 'auth_files.delete_all_success': '成功删除',
'auth_files.files_count': '个文件', 'auth_files.files_count': '个文件',
'auth_files.filter_all': '全部',
'auth_files.filter_qwen': 'Qwen',
'auth_files.filter_gemini': 'Gemini',
'auth_files.filter_gemini-cli': 'GeminiCLI',
'auth_files.filter_aistudio': 'AIStudio',
'auth_files.filter_claude': 'Claude',
'auth_files.filter_codex': 'Codex',
'auth_files.filter_iflow': 'iFlow',
'auth_files.filter_empty': '空文件',
'auth_files.filter_unknown': '其他',
'auth_files.type_qwen': 'Qwen',
'auth_files.type_gemini': 'Gemini',
'auth_files.type_gemini-cli': 'GeminiCLI',
'auth_files.type_aistudio': 'AIStudio',
'auth_files.type_claude': 'Claude',
'auth_files.type_codex': 'Codex',
'auth_files.type_iflow': 'iFlow',
'auth_files.type_empty': '空文件',
'auth_files.type_unknown': '其他',
// Codex OAuth // Codex OAuth
@@ -274,6 +297,7 @@ const i18n = {
'auth_login.qwen_oauth_status_error': '认证失败:', 'auth_login.qwen_oauth_status_error': '认证失败:',
'auth_login.qwen_oauth_start_error': '启动 Qwen OAuth 失败:', 'auth_login.qwen_oauth_start_error': '启动 Qwen OAuth 失败:',
'auth_login.qwen_oauth_polling_error': '检查认证状态失败:', 'auth_login.qwen_oauth_polling_error': '检查认证状态失败:',
'auth_login.missing_state': '无法获取认证状态参数',
// iFlow OAuth // iFlow OAuth
'auth_login.iflow_oauth_title': 'iFlow OAuth', 'auth_login.iflow_oauth_title': 'iFlow OAuth',
@@ -307,6 +331,8 @@ const i18n = {
'usage_stats.tokens_count': 'Token数量', 'usage_stats.tokens_count': 'Token数量',
'usage_stats.models': '模型统计', 'usage_stats.models': '模型统计',
'usage_stats.success_rate': '成功率', 'usage_stats.success_rate': '成功率',
'stats.success': '成功',
'stats.failure': '失败',
// 日志查看 // 日志查看
'logs.title': '日志查看', 'logs.title': '日志查看',
@@ -329,6 +355,25 @@ const i18n = {
'logs.upgrade_required_title': '需要升级 CLI Proxy API', 'logs.upgrade_required_title': '需要升级 CLI Proxy API',
'logs.upgrade_required_desc': '当前服务器版本不支持日志查看功能,请升级到最新版本的 CLI Proxy API 以使用此功能。', 'logs.upgrade_required_desc': '当前服务器版本不支持日志查看功能,请升级到最新版本的 CLI Proxy API 以使用此功能。',
// 配置管理
'config_management.title': '配置管理',
'config_management.editor_title': '配置文件',
'config_management.reload': '重新加载',
'config_management.save': '保存',
'config_management.description': '查看并编辑服务器上的 config.yaml 配置文件。保存前请确认语法正确。',
'config_management.status_idle': '等待操作',
'config_management.status_loading': '加载配置中...',
'config_management.status_loaded': '配置已加载',
'config_management.status_dirty': '有未保存的更改',
'config_management.status_disconnected': '请先连接服务器以加载配置',
'config_management.status_load_failed': '加载失败',
'config_management.status_saving': '正在保存配置...',
'config_management.status_saved': '配置保存完成',
'config_management.status_save_failed': '保存失败',
'config_management.save_success': '配置已保存',
'config_management.error_yaml_not_supported': '服务器未返回 YAML 格式,请确认 /config.yaml 接口可用',
'config_management.editor_placeholder': 'key: value',
// 系统信息 // 系统信息
'system_info.title': '系统信息', 'system_info.title': '系统信息',
'system_info.connection_status_title': '连接状态', 'system_info.connection_status_title': '连接状态',
@@ -383,6 +428,7 @@ const i18n = {
'notification.gemini_api_key': 'Gemini API密钥', 'notification.gemini_api_key': 'Gemini API密钥',
'notification.codex_api_key': 'Codex API密钥', 'notification.codex_api_key': 'Codex API密钥',
'notification.claude_api_key': 'Claude API密钥', 'notification.claude_api_key': 'Claude API密钥',
'notification.link_copied': '链接已复制到剪贴板',
// 语言切换 // 语言切换
'language.switch': '语言', 'language.switch': '语言',
@@ -397,6 +443,10 @@ const i18n = {
'theme.switch_to_dark': '切换到暗色模式', 'theme.switch_to_dark': '切换到暗色模式',
'theme.auto': '跟随系统', 'theme.auto': '跟随系统',
// 侧边栏
'sidebar.toggle_expand': '展开侧边栏',
'sidebar.toggle_collapse': '收起侧边栏',
// 页脚 // 页脚
'footer.version': '版本', 'footer.version': '版本',
'footer.author': '作者' 'footer.author': '作者'
@@ -434,6 +484,9 @@ const i18n = {
'common.base_url': 'Address', 'common.base_url': 'Address',
'common.proxy_url': 'Proxy', 'common.proxy_url': 'Proxy',
'common.alias': 'Alias', 'common.alias': 'Alias',
'common.failure': 'Failure',
'common.unknown_error': 'Unknown error',
'common.copy': 'Copy',
// Page titles // Page titles
'title.main': 'CLI Proxy API Management Center', 'title.main': 'CLI Proxy API Management Center',
@@ -478,6 +531,7 @@ const i18n = {
'nav.ai_providers': 'AI Providers', 'nav.ai_providers': 'AI Providers',
'nav.auth_files': 'Auth Files', 'nav.auth_files': 'Auth Files',
'nav.usage_stats': 'Usage Statistics', 'nav.usage_stats': 'Usage Statistics',
'nav.config_management': 'Config Management',
'nav.logs': 'Logs Viewer', 'nav.logs': 'Logs Viewer',
'nav.system_info': 'System Info', 'nav.system_info': 'System Info',
@@ -614,6 +668,25 @@ const i18n = {
'auth_files.delete_success': 'File deleted successfully', 'auth_files.delete_success': 'File deleted successfully',
'auth_files.delete_all_success': 'Successfully deleted', 'auth_files.delete_all_success': 'Successfully deleted',
'auth_files.files_count': 'files', 'auth_files.files_count': 'files',
'auth_files.filter_all': 'All',
'auth_files.filter_qwen': 'Qwen',
'auth_files.filter_gemini': 'Gemini',
'auth_files.filter_gemini-cli': 'GeminiCLI',
'auth_files.filter_aistudio': 'AIStudio',
'auth_files.filter_claude': 'Claude',
'auth_files.filter_codex': 'Codex',
'auth_files.filter_iflow': 'iFlow',
'auth_files.filter_empty': 'Empty',
'auth_files.filter_unknown': 'Other',
'auth_files.type_qwen': 'Qwen',
'auth_files.type_gemini': 'Gemini',
'auth_files.type_gemini-cli': 'GeminiCLI',
'auth_files.type_aistudio': 'AIStudio',
'auth_files.type_claude': 'Claude',
'auth_files.type_codex': 'Codex',
'auth_files.type_iflow': 'iFlow',
'auth_files.type_empty': 'Empty',
'auth_files.type_unknown': 'Other',
// Codex OAuth // Codex OAuth
'auth_login.codex_oauth_title': 'Codex OAuth', 'auth_login.codex_oauth_title': 'Codex OAuth',
@@ -669,6 +742,7 @@ const i18n = {
'auth_login.qwen_oauth_status_error': 'Authentication failed:', 'auth_login.qwen_oauth_status_error': 'Authentication failed:',
'auth_login.qwen_oauth_start_error': 'Failed to start Qwen OAuth:', 'auth_login.qwen_oauth_start_error': 'Failed to start Qwen OAuth:',
'auth_login.qwen_oauth_polling_error': 'Failed to check authentication status:', 'auth_login.qwen_oauth_polling_error': 'Failed to check authentication status:',
'auth_login.missing_state': 'Unable to retrieve authentication state parameter',
// iFlow OAuth // iFlow OAuth
'auth_login.iflow_oauth_title': 'iFlow OAuth', 'auth_login.iflow_oauth_title': 'iFlow OAuth',
@@ -702,6 +776,8 @@ const i18n = {
'usage_stats.tokens_count': 'Token Count', 'usage_stats.tokens_count': 'Token Count',
'usage_stats.models': 'Model Statistics', 'usage_stats.models': 'Model Statistics',
'usage_stats.success_rate': 'Success Rate', 'usage_stats.success_rate': 'Success Rate',
'stats.success': 'Success',
'stats.failure': 'Failure',
// Logs viewer // Logs viewer
'logs.title': 'Logs Viewer', 'logs.title': 'Logs Viewer',
@@ -724,6 +800,25 @@ const i18n = {
'logs.upgrade_required_title': 'Please Upgrade CLI Proxy API', 'logs.upgrade_required_title': 'Please Upgrade CLI Proxy API',
'logs.upgrade_required_desc': 'The current server version does not support the logs viewing feature. Please upgrade to the latest version of CLI Proxy API to use this feature.', 'logs.upgrade_required_desc': 'The current server version does not support the logs viewing feature. Please upgrade to the latest version of CLI Proxy API to use this feature.',
// Config management
'config_management.title': 'Config Management',
'config_management.editor_title': 'Configuration File',
'config_management.reload': 'Reload',
'config_management.save': 'Save',
'config_management.description': 'View and edit the server-side config.yaml file. Validate the syntax before saving.',
'config_management.status_idle': 'Waiting for action',
'config_management.status_loading': 'Loading configuration...',
'config_management.status_loaded': 'Configuration loaded',
'config_management.status_dirty': 'Unsaved changes',
'config_management.status_disconnected': 'Connect to the server to load the configuration',
'config_management.status_load_failed': 'Load failed',
'config_management.status_saving': 'Saving configuration...',
'config_management.status_saved': 'Configuration saved',
'config_management.status_save_failed': 'Save failed',
'config_management.save_success': 'Configuration saved successfully',
'config_management.error_yaml_not_supported': 'Server did not return YAML. Verify the /config.yaml endpoint is available.',
'config_management.editor_placeholder': 'key: value',
// System info // System info
'system_info.title': 'System Information', 'system_info.title': 'System Information',
'system_info.connection_status_title': 'Connection Status', 'system_info.connection_status_title': 'Connection Status',
@@ -778,6 +873,7 @@ const i18n = {
'notification.gemini_api_key': 'Gemini API key', 'notification.gemini_api_key': 'Gemini API key',
'notification.codex_api_key': 'Codex API key', 'notification.codex_api_key': 'Codex API key',
'notification.claude_api_key': 'Claude API key', 'notification.claude_api_key': 'Claude API key',
'notification.link_copied': 'Link copied to clipboard',
// Language switch // Language switch
'language.switch': 'Language', 'language.switch': 'Language',
@@ -792,6 +888,10 @@ const i18n = {
'theme.switch_to_dark': 'Switch to dark mode', 'theme.switch_to_dark': 'Switch to dark mode',
'theme.auto': 'Follow system', 'theme.auto': 'Follow system',
// Sidebar
'sidebar.toggle_expand': 'Expand sidebar',
'sidebar.toggle_collapse': 'Collapse sidebar',
// Footer // Footer
'footer.version': 'Version', 'footer.version': 'Version',
'footer.author': 'Author' 'footer.author': 'Author'
@@ -841,6 +941,30 @@ const i18n = {
} }
}); });
// 更新所有包含 data-i18n-placeholder 的输入框占位符
document.querySelectorAll('[data-i18n-placeholder]').forEach(element => {
const key = element.getAttribute('data-i18n-placeholder');
element.placeholder = this.t(key);
});
// 更新 data-i18n-title
document.querySelectorAll('[data-i18n-title]').forEach(element => {
const key = element.getAttribute('data-i18n-title');
element.title = this.t(key);
});
// 更新 data-i18n-tooltip
document.querySelectorAll('[data-i18n-tooltip]').forEach(element => {
const key = element.getAttribute('data-i18n-tooltip');
element.setAttribute('data-tooltip', this.t(key));
});
// 更新 data-i18n-text常用于按钮或标签
document.querySelectorAll('[data-i18n-text]').forEach(element => {
const key = element.getAttribute('data-i18n-text');
element.textContent = this.t(key);
});
// 更新所有带有 data-i18n-html 属性的元素支持HTML // 更新所有带有 data-i18n-html 属性的元素支持HTML
document.querySelectorAll('[data-i18n-html]').forEach(element => { document.querySelectorAll('[data-i18n-html]').forEach(element => {
const key = element.getAttribute('data-i18n-html'); const key = element.getAttribute('data-i18n-html');

View File

@@ -7,7 +7,13 @@
<title data-i18n="title.login">CLI Proxy API Management Center</title> <title data-i18n="title.login">CLI Proxy API Management Center</title>
<link rel="stylesheet" href="styles.css"> <link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.css">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/mode/yaml/yaml.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/edit/closebrackets.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/comment/comment.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/js-yaml@4.1.0/dist/js-yaml.min.js"></script>
<script src="i18n.js"></script> <script src="i18n.js"></script>
</head> </head>
@@ -71,8 +77,7 @@
<div class="form-group"> <div class="form-group">
<label for="login-api-base" data-i18n="login.custom_connection_label">自定义连接地址:</label> <label for="login-api-base" data-i18n="login.custom_connection_label">自定义连接地址:</label>
<div class="input-group"> <div class="input-group">
<input type="text" id="login-api-base" data-i18n="login.custom_connection_placeholder" <input type="text" id="login-api-base" data-i18n-placeholder="login.custom_connection_placeholder">
placeholder="例如: https://example.com:8317">
<button type="button" id="login-reset-api-base" <button type="button" id="login-reset-api-base"
class="btn btn-secondary connection-reset-btn"> class="btn btn-secondary connection-reset-btn">
<i class="fas fa-location-arrow"></i> <i class="fas fa-location-arrow"></i>
@@ -85,8 +90,7 @@
<div class="form-group"> <div class="form-group">
<label for="login-management-key" data-i18n="login.management_key_label">管理密钥:</label> <label for="login-management-key" data-i18n="login.management_key_label">管理密钥:</label>
<div class="input-group"> <div class="input-group">
<input type="password" id="login-management-key" <input type="password" id="login-management-key" data-i18n-placeholder="login.management_key_placeholder" required>
data-i18n="login.management_key_placeholder" placeholder="请输入管理密钥" required>
<button type="button" class="btn btn-secondary toggle-key-visibility"> <button type="button" class="btn btn-secondary toggle-key-visibility">
<i class="fas fa-eye"></i> <i class="fas fa-eye"></i>
</button> </button>
@@ -117,7 +121,7 @@
<button class="mobile-menu-btn" id="mobile-menu-btn"> <button class="mobile-menu-btn" id="mobile-menu-btn">
<i class="fas fa-bars"></i> <i class="fas fa-bars"></i>
</button> </button>
<button class="sidebar-toggle-btn-desktop" id="sidebar-toggle-btn-desktop" title="收起/展开侧边栏"> <button class="sidebar-toggle-btn-desktop" id="sidebar-toggle-btn-desktop" data-i18n-title="sidebar.toggle_collapse">
<i class="fas fa-bars"></i> <i class="fas fa-bars"></i>
</button> </button>
<div class="top-navbar-brand"> <div class="top-navbar-brand">
@@ -155,26 +159,29 @@
<nav class="sidebar" id="sidebar"> <nav class="sidebar" id="sidebar">
<!-- 导航菜单 --> <!-- 导航菜单 -->
<ul class="nav-menu"> <ul class="nav-menu">
<li data-tooltip="基础设置"><a href="#basic-settings" class="nav-item active" <li data-i18n-tooltip="nav.basic_settings"><a href="#basic-settings" class="nav-item active"
data-section="basic-settings"> data-section="basic-settings">
<i class="fas fa-sliders-h"></i> <span data-i18n="nav.basic_settings">基础设置</span> <i class="fas fa-sliders-h"></i> <span data-i18n="nav.basic_settings">基础设置</span>
</a></li> </a></li>
<li data-tooltip="API 密钥"><a href="#api-keys" class="nav-item" data-section="api-keys"> <li data-i18n-tooltip="nav.api_keys"><a href="#api-keys" class="nav-item" data-section="api-keys">
<i class="fas fa-key"></i> <span data-i18n="nav.api_keys">API 密钥</span> <i class="fas fa-key"></i> <span data-i18n="nav.api_keys">API 密钥</span>
</a></li> </a></li>
<li data-tooltip="AI 提供商"><a href="#ai-providers" class="nav-item" data-section="ai-providers"> <li data-i18n-tooltip="nav.ai_providers"><a href="#ai-providers" class="nav-item" data-section="ai-providers">
<i class="fas fa-robot"></i> <span data-i18n="nav.ai_providers">AI 提供商</span> <i class="fas fa-robot"></i> <span data-i18n="nav.ai_providers">AI 提供商</span>
</a></li> </a></li>
<li data-tooltip="认证文件"><a href="#auth-files" class="nav-item" data-section="auth-files"> <li data-i18n-tooltip="nav.auth_files"><a href="#auth-files" class="nav-item" data-section="auth-files">
<i class="fas fa-file-alt"></i> <span data-i18n="nav.auth_files">认证文件</span> <i class="fas fa-file-alt"></i> <span data-i18n="nav.auth_files">认证文件</span>
</a></li> </a></li>
<li data-tooltip="使用统计"><a href="#usage-stats" class="nav-item" data-section="usage-stats"> <li data-i18n-tooltip="nav.usage_stats"><a href="#usage-stats" class="nav-item" data-section="usage-stats">
<i class="fas fa-chart-line"></i> <span data-i18n="nav.usage_stats">使用统计</span> <i class="fas fa-chart-line"></i> <span data-i18n="nav.usage_stats">使用统计</span>
</a></li> </a></li>
<li id="logs-nav-item" data-tooltip="日志查看" style="display: none;"><a href="#logs" class="nav-item" data-section="logs"> <li data-i18n-tooltip="nav.config_management"><a href="#config-management" class="nav-item" data-section="config-management">
<i class="fas fa-cog"></i> <span data-i18n="nav.config_management">配置管理</span>
</a></li>
<li id="logs-nav-item" data-i18n-tooltip="nav.logs" style="display: none;"><a href="#logs" class="nav-item" data-section="logs">
<i class="fas fa-scroll"></i> <span data-i18n="nav.logs">日志查看</span> <i class="fas fa-scroll"></i> <span data-i18n="nav.logs">日志查看</span>
</a></li> </a></li>
<li data-tooltip="系统信息"><a href="#system-info" class="nav-item" data-section="system-info"> <li data-i18n-tooltip="nav.system_info"><a href="#system-info" class="nav-item" data-section="system-info">
<i class="fas fa-info-circle"></i> <span data-i18n="nav.system_info">系统信息</span> <i class="fas fa-info-circle"></i> <span data-i18n="nav.system_info">系统信息</span>
</a></li> </a></li>
</ul> </ul>
@@ -221,9 +228,7 @@
<label for="proxy-url" data-i18n="basic_settings.proxy_url_label">代理 <label for="proxy-url" data-i18n="basic_settings.proxy_url_label">代理
URL:</label> URL:</label>
<div class="input-group"> <div class="input-group">
<input type="text" id="proxy-url" <input type="text" id="proxy-url" data-i18n-placeholder="basic_settings.proxy_url_placeholder">
data-i18n="basic_settings.proxy_url_placeholder"
placeholder="例如: socks5://user:pass@127.0.0.1:1080/">
<button id="update-proxy" class="btn btn-primary" <button id="update-proxy" class="btn btn-primary"
data-i18n="basic_settings.proxy_update">更新</button> data-i18n="basic_settings.proxy_update">更新</button>
<button id="clear-proxy" class="btn btn-danger" <button id="clear-proxy" class="btn btn-danger"
@@ -413,9 +418,23 @@
<!-- 认证文件 --> <!-- 认证文件 -->
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header card-header-with-filter">
<div class="header-left">
<h3><i class="fas fa-file-alt"></i> <span <h3><i class="fas fa-file-alt"></i> <span
data-i18n="auth_files.title_section">认证文件</span></h3> data-i18n="auth_files.title_section">认证文件</span></h3>
<!-- 类型筛选 -->
<div class="auth-file-filter">
<button class="filter-btn active" data-type="all" data-i18n-text="auth_files.filter_all">All</button>
<button class="filter-btn" data-type="qwen" data-i18n-text="auth_files.filter_qwen">Qwen</button>
<button class="filter-btn" data-type="gemini" data-i18n-text="auth_files.filter_gemini">Gemini</button>
<button class="filter-btn" data-type="gemini-cli" data-i18n-text="auth_files.filter_gemini-cli">GeminiCLI</button>
<button class="filter-btn" data-type="aistudio" data-i18n-text="auth_files.filter_aistudio">AIStudio</button>
<button class="filter-btn" data-type="claude" data-i18n-text="auth_files.filter_claude">Claude</button>
<button class="filter-btn" data-type="codex" data-i18n-text="auth_files.filter_codex">Codex</button>
<button class="filter-btn" data-type="iflow" data-i18n-text="auth_files.filter_iflow">iFlow</button>
<button class="filter-btn" data-type="empty" data-i18n-text="auth_files.filter_empty">Empty</button>
</div>
</div>
<div class="header-actions"> <div class="header-actions">
<button id="upload-auth-file" class="btn btn-primary"> <button id="upload-auth-file" class="btn btn-primary">
<i class="fas fa-upload"></i> <span <i class="fas fa-upload"></i> <span
@@ -428,7 +447,7 @@
</div> </div>
</div> </div>
<div class="card-content"> <div class="card-content">
<div id="auth-files-list" class="file-list"></div> <div id="auth-files-list" class="file-list file-grid"></div>
<input type="file" id="auth-file-input" accept=".json" style="display: none;"> <input type="file" id="auth-file-input" accept=".json" style="display: none;">
</div> </div>
</div> </div>
@@ -524,8 +543,7 @@
data-i18n="auth_login.gemini_cli_project_id_label">Google Cloud 项目 ID data-i18n="auth_login.gemini_cli_project_id_label">Google Cloud 项目 ID
(可选):</label> (可选):</label>
<input type="text" id="gemini-cli-project-id" <input type="text" id="gemini-cli-project-id"
data-i18n="auth_login.gemini_cli_project_id_placeholder" data-i18n-placeholder="auth_login.gemini_cli_project_id_placeholder">
placeholder="输入 Google Cloud 项目 ID (可选)">
<div class="form-hint" data-i18n="auth_login.gemini_cli_project_id_hint"> <div class="form-hint" data-i18n="auth_login.gemini_cli_project_id_hint">
如果指定了项目 ID将使用该项目的认证信息。 如果指定了项目 ID将使用该项目的认证信息。
</div> </div>
@@ -766,6 +784,32 @@
</div> </div>
</section> </section>
<!-- 配置管理 -->
<section id="config-management" class="content-section">
<h2 data-i18n="config_management.title">配置管理</h2>
<div class="card">
<div class="card-header">
<h3><i class="fas fa-file-code"></i> <span data-i18n="config_management.editor_title">配置文件</span></h3>
<div class="editor-actions">
<button id="config-reload-btn" class="btn btn-secondary">
<i class="fas fa-sync-alt"></i> <span data-i18n="config_management.reload">重新加载</span>
</button>
<button id="config-save-btn" class="btn btn-primary">
<i class="fas fa-save"></i> <span data-i18n="config_management.save">保存</span>
</button>
</div>
</div>
<div class="card-content">
<p class="form-hint" data-i18n="config_management.description">查看并编辑服务器上的 config.yaml 配置文件。保存前请确认语法正确。</p>
<div class="yaml-editor-container">
<textarea id="config-editor" class="yaml-editor" spellcheck="false" data-i18n="config_management.editor_placeholder"></textarea>
<div id="config-editor-status" class="editor-status" data-i18n="config_management.status_idle">等待操作</div>
</div>
</div>
</div>
</section>
<!-- 系统信息 --> <!-- 系统信息 -->
<section id="system-info" class="content-section"> <section id="system-info" class="content-section">
<h2 data-i18n="system_info.title">系统信息</h2> <h2 data-i18n="system_info.title">系统信息</h2>
@@ -785,13 +829,6 @@
</div> </div>
<div class="info-value" id="display-api-url">-</div> <div class="info-value" id="display-api-url">-</div>
</div> </div>
<div class="info-item">
<div class="info-label">
<i class="fas fa-key"></i>
<span data-i18n="connection.management_key">管理密钥:</span>
</div>
<div class="info-value" id="display-management-key">-</div>
</div>
<div class="info-item"> <div class="info-item">
<div class="info-label"> <div class="info-label">
<i class="fas fa-circle"></i> <i class="fas fa-circle"></i>

File diff suppressed because it is too large Load Diff