AIClient-2-API/static/app/routing-examples.js
hex2077 fa8150701f feat(i18n): 添加多语言支持并实现国际化功能
实现中英文双语支持,包括:
1. 添加i18n.js核心模块处理语言切换和翻译
2. 创建语言切换器组件
3. 更新所有UI文本使用翻译键
4. 添加I18N_GUIDE.md文档说明使用方法
5. 修改样式适配语言切换器
6. 添加adm-zip依赖支持配置文件打包下载
7. 更新登录页面支持多语言
8. 重构toast消息显示支持多语言标题
2025-12-20 17:27:30 +08:00

338 lines
No EOL
10 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 路径路由示例功能模块
import { showToast } from './utils.js';
import { t } from './i18n.js';
/**
* 初始化路径路由示例功能
*/
function initRoutingExamples() {
// 延迟初始化确保所有DOM都加载完成
setTimeout(() => {
initProtocolTabs();
initCopyButtons();
initCardInteractions();
}, 100);
}
/**
* 初始化协议标签切换功能
*/
function initProtocolTabs() {
// 使用事件委托方式绑定点击事件
document.addEventListener('click', function(e) {
// 检查点击的是不是协议标签或者其子元素
const tab = e.target.classList.contains('protocol-tab') ? e.target : e.target.closest('.protocol-tab');
if (tab) {
e.preventDefault();
e.stopPropagation();
const targetProtocol = tab.dataset.protocol;
const card = tab.closest('.routing-example-card');
if (!card) {
return;
}
// 移除当前卡片中所有标签和内容的活动状态
const cardTabs = card.querySelectorAll('.protocol-tab');
const cardContents = card.querySelectorAll('.protocol-content');
cardTabs.forEach(t => t.classList.remove('active'));
cardContents.forEach(c => c.classList.remove('active'));
// 为当前标签和对应内容添加活动状态
tab.classList.add('active');
// 使用更精确的选择器来查找对应的内容
const targetContent = card.querySelector(`.protocol-content[data-protocol="${targetProtocol}"]`);
if (targetContent) {
targetContent.classList.add('active');
}
}
});
}
/**
* 初始化复制按钮功能
*/
function initCopyButtons() {
document.addEventListener('click', async function(e) {
if (e.target.closest('.copy-btn')) {
e.stopPropagation();
const button = e.target.closest('.copy-btn');
const path = button.dataset.path;
if (!path) return;
try {
await navigator.clipboard.writeText(path);
showToast(t('common.success'), `${t('common.success')}: ${path}`, 'success');
// 临时更改按钮图标
const icon = button.querySelector('i');
if (icon) {
const originalClass = icon.className;
icon.className = 'fas fa-check';
button.style.color = 'var(--success-color)';
setTimeout(() => {
icon.className = originalClass;
button.style.color = '';
}, 2000);
}
} catch (error) {
console.error('Failed to copy to clipboard:', error);
showToast(t('common.error'), t('common.error'), 'error');
}
}
});
}
/**
* 初始化卡片交互功能
*/
function initCardInteractions() {
const routingCards = document.querySelectorAll('.routing-example-card');
routingCards.forEach(card => {
// 添加悬停效果
card.addEventListener('mouseenter', () => {
card.style.transform = 'translateY(-4px)';
card.style.boxShadow = 'var(--shadow-lg)';
});
card.addEventListener('mouseleave', () => {
card.style.transform = '';
card.style.boxShadow = '';
});
});
}
/**
* 获取所有可用的路由端点
* @returns {Array} 路由端点数组
*/
function getAvailableRoutes() {
return [
{
provider: 'claude-custom',
name: 'Claude Custom',
paths: {
openai: '/claude-custom/v1/chat/completions',
claude: '/claude-custom/v1/messages'
},
description: t('dashboard.routing.official'),
badge: t('dashboard.routing.official'),
badgeClass: 'official'
},
{
provider: 'claude-kiro-oauth',
name: 'Claude Kiro OAuth',
paths: {
openai: '/claude-kiro-oauth/v1/chat/completions',
claude: '/claude-kiro-oauth/v1/messages'
},
description: t('dashboard.routing.free'),
badge: t('dashboard.routing.free'),
badgeClass: 'oauth'
},
{
provider: 'openai-custom',
name: 'OpenAI Custom',
paths: {
openai: '/openai-custom/v1/chat/completions',
claude: '/openai-custom/v1/messages'
},
description: t('dashboard.routing.official'),
badge: t('dashboard.routing.official'),
badgeClass: 'official'
},
{
provider: 'gemini-cli-oauth',
name: 'Gemini CLI OAuth',
paths: {
openai: '/gemini-cli-oauth/v1/chat/completions',
claude: '/gemini-cli-oauth/v1/messages'
},
description: t('dashboard.routing.oauth'),
badge: t('dashboard.routing.oauth'),
badgeClass: 'oauth'
},
{
provider: 'openai-qwen-oauth',
name: 'Qwen OAuth',
paths: {
openai: '/openai-qwen-oauth/v1/chat/completions',
claude: '/openai-qwen-oauth/v1/messages'
},
description: 'Qwen Code Plus',
badge: t('dashboard.routing.oauth'),
badgeClass: 'oauth'
},
{
provider: 'openaiResponses-custom',
name: 'OpenAI Responses',
paths: {
openai: '/openaiResponses-custom/v1/responses',
claude: '/openaiResponses-custom/v1/messages'
},
description: '结构化对话API',
badge: 'Responses',
badgeClass: 'responses'
}
];
}
/**
* 高亮显示特定提供商路由
* @param {string} provider - 提供商标识
*/
function highlightProviderRoute(provider) {
const card = document.querySelector(`[data-provider="${provider}"]`);
if (card) {
card.scrollIntoView({ behavior: 'smooth', block: 'center' });
card.style.borderColor = 'var(--success-color)';
card.style.boxShadow = '0 0 0 3px rgba(16, 185, 129, 0.1)';
setTimeout(() => {
card.style.borderColor = '';
card.style.boxShadow = '';
}, 3000);
showToast(t('common.success'), t('common.success') + `: ${provider}`, 'success');
}
}
/**
* 复制curl命令示例
* @param {string} provider - 提供商标识
* @param {Object} options - 选项参数
*/
async function copyCurlExample(provider, options = {}) {
const routes = getAvailableRoutes();
const route = routes.find(r => r.provider === provider);
if (!route) {
showToast(t('common.error'), t('common.error'), 'error');
return;
}
const { protocol = 'openai', model = 'default-model', message = 'Hello!' } = options;
const path = route.paths[protocol];
if (!path) {
showToast(t('common.error'), t('common.error'), 'error');
return;
}
let curlCommand = '';
// 根据不同提供商和协议生成对应的curl命令
switch (provider) {
case 'claude-custom':
case 'claude-kiro-oauth':
if (protocol === 'openai') {
curlCommand = `curl http://localhost:3000${path} \\
-H "Content-Type: application/json" \\
-H "Authorization: Bearer YOUR_API_KEY" \\
-d '{
"model": "${model}",
"messages": [{"role": "user", "content": "${message}"}],
"max_tokens": 1000
}'`;
} else {
curlCommand = `curl http://localhost:3000${path} \\
-H "Content-Type: application/json" \\
-d '{
"model": "${model}",
"max_tokens": 1000,
"messages": [{"role": "user", "content": "${message}"}]
}'`;
}
break;
case 'openai-custom':
case 'openai-qwen-oauth':
if (protocol === 'openai') {
curlCommand = `curl http://localhost:3000${path} \\
-H "Content-Type: application/json" \\
-H "Authorization: Bearer YOUR_API_KEY" \\
-d '{
"model": "${model}",
"messages": [{"role": "user", "content": "${message}"}],
"max_tokens": 1000
}'`;
} else {
curlCommand = `curl http://localhost:3000${path} \\
-H "Content-Type: application/json" \\
-H "X-API-Key: YOUR_API_KEY" \\
-d '{
"model": "${model}",
"max_tokens": 1000,
"messages": [{"role": "user", "content": "${message}"}]
}'`;
}
break;
case 'gemini-cli-oauth':
if (protocol === 'openai') {
curlCommand = `curl http://localhost:3000${path} \\
-H "Content-Type: application/json" \\
-d '{
"model": "gemini-2.0-flash-exp",
"messages": [{"role": "user", "content": "${message}"}],
"max_tokens": 1000
}'`;
} else {
curlCommand = `curl http://localhost:3000${path} \\
-H "Content-Type: application/json" \\
-d '{
"model": "gemini-2.0-flash-exp",
"max_tokens": 1000,
"messages": [{"role": "user", "content": "${message}"}]
}'`;
}
break;
case 'openaiResponses-custom':
if (protocol === 'openai') {
curlCommand = `curl http://localhost:3000${path} \\
-H "Content-Type: application/json" \\
-H "Authorization: Bearer YOUR_API_KEY" \\
-d '{
"model": "${model}",
"input": "${message}",
"max_output_tokens": 1000
}'`;
} else {
curlCommand = `curl http://localhost:3000${path} \\
-H "Content-Type: application/json" \\
-H "X-API-Key: YOUR_API_KEY" \\
-d '{
"model": "${model}",
"max_tokens": 1000,
"messages": [{"role": "user", "content": "${message}"}]
}'`;
}
break;
}
try {
await navigator.clipboard.writeText(curlCommand);
showToast(t('common.success'), t('oauth.success.msg'), 'success');
} catch (error) {
console.error('Failed to copy curl command:', error);
showToast(t('common.error'), t('common.error'), 'error');
}
}
export {
initRoutingExamples,
getAvailableRoutes,
highlightProviderRoute,
copyCurlExample
};