From dca1d822dadd7f24ef5d7b6c8c67d3665453c9f9 Mon Sep 17 00:00:00 2001 From: YoVinchen Date: Mon, 24 Nov 2025 22:56:04 +0800 Subject: [PATCH] chore: add deeplink testing HTML page Add a local HTML page for testing deeplink protocol functionality during development. This page allows developers to: - Test different deeplink URL formats (provider/prompt/mcp/skill) - Verify URL parsing and parameter encoding - Quickly validate deeplink imports without external tools - Debug protocol registration on different platforms Not intended for production use, only for development testing. --- deplink.html | 1041 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1041 insertions(+) diff --git a/deplink.html b/deplink.html index 900850b3d..eab057c34 100644 --- a/deplink.html +++ b/deplink.html @@ -923,6 +923,696 @@ + +
+

🏢 供应商导入 v3.8+

+ + + + + + +
+ + +
+

🔌 MCP Servers 导入 v3.8+

+ + + + + + + + +
+ + +
+

💬 Prompt 导入 v3.8+

+ + + + + + +
+ + +
+

🛠️ Skill 仓库导入 v3.8+

+ + +
+ + +
+

🚀 深链接生成器

+

+ 填写参数信息,自动生成深链接并导入到 CC Switch +

+ + +
+

🏢 供应商导入生成器

+ +
+ + +
+ +
+ + +
+ +
+ + + 您的 API 密钥 +
+ +
+ + + 完整的 API 端点 URL +
+ +
+ + +
+ +
+ + + 可选,留空使用系统默认 +
+ +
+ + +
+ +
+ + +
+ + + + +
+ + +
+

🔌 MCP Servers 导入生成器

+ +
+ + + 多个应用用逗号分隔 +
+ +
+ + + 完整的 MCP 配置 JSON +
+ +
+ + +
+ + + + +
+ + +
+

💬 Prompt 导入生成器

+ +
+ + +
+ +
+ + +
+ +
+ + + 支持 Markdown 格式,自动 Base64 编码 +
+ +
+ + +
+ +
+ + +
+ + + + +
+ + +
+

🛠️ Skill 仓库导入生成器

+ +
+ + + 格式: 所有者/仓库名 +
+ +
+ + +
+ +
+ + + 仓库中技能文件所在的子目录 +
+ +
+ + + 克隆到本地的目录名(可选) +
+ + + + +
+
+ + +
+

🔐 Base64 编解码器

+ +
+

编码器 (UTF-8 → Base64)

+
+ + +
+ + +
+ +
+

解码器 (Base64 → UTF-8)

+
+ + +
+ + +
+ +
+

💡 使用建议

+
    +
  • 编码配置文件:将 JSON 或 TOML 内容编码后用于 config 参数
  • +
  • 编码 Prompt:将 Markdown 提示词内容编码后用于 content 参数
  • +
  • 验证深链接:解码验证深链接中的配置内容是否正确
  • +
  • UTF-8 支持:完整支持中文及其他 Unicode 字符
  • +
+
+
+

⚠️ 使用注意事项

@@ -1109,6 +1799,22 @@
+
+ + + + 图标名称,用于在界面中显示 + +
+ +
+ + +
+
@@ -1274,6 +1980,8 @@ requires_openai_auth = true`; const endpoint = document.getElementById('endpoint').value.trim(); const apiKey = document.getElementById('apiKey').value.trim(); const model = document.getElementById('model').value.trim(); + const icon = document.getElementById('icon').value.trim(); + const enabled = document.getElementById('enabled').value; const notes = document.getElementById('notes').value.trim(); // Claude 专用字段 @@ -1309,6 +2017,8 @@ requires_openai_auth = true`; params.append('endpoint', endpoint); params.append('apiKey', apiKey); if (model) params.append('model', model); + if (icon) params.append('icon', icon); + if (enabled) params.append('enabled', enabled); if (notes) params.append('notes', notes); // 添加 Claude 专用模型字段 @@ -1366,6 +2076,8 @@ requires_openai_auth = true`; const overrideApiKey = document.getElementById('overrideApiKey').value.trim(); const overrideEndpoint = document.getElementById('overrideEndpoint').value.trim(); const model = document.getElementById('model').value.trim(); + const icon = document.getElementById('icon').value.trim(); + const enabled = document.getElementById('enabled').value; const notes = document.getElementById('notes').value.trim(); // Claude 专用字段 @@ -1391,6 +2103,8 @@ requires_openai_auth = true`; } if (model) params.append('model', model); + if (icon) params.append('icon', icon); + if (enabled) params.append('enabled', enabled); if (notes) params.append('notes', notes); // 添加 Claude 专用模型字段 @@ -1668,6 +2382,333 @@ requires_openai_auth = true`; // 初始化显示 Claude 字段 updateModelFields(); }); + + // Base64 编码功能 + function encodeToBase64() { + const input = document.getElementById('encodeInput').value; + + if (!input.trim()) { + alert('❌ 请输入要编码的内容!'); + return; + } + + try { + const encoded = utf8_to_b64(input); + document.getElementById('encodeOutput').textContent = encoded; + document.getElementById('encodeResult').style.display = 'block'; + + // 滚动到结果 + document.getElementById('encodeResult').scrollIntoView({ + behavior: 'smooth', + block: 'nearest' + }); + } catch (e) { + alert('❌ 编码失败:' + e.message); + console.error('Encode error:', e); + } + } + + // Base64 解码功能 + function decodeFromBase64() { + const input = document.getElementById('decodeInput').value.trim(); + + if (!input) { + alert('❌ 请输入要解码的 Base64 内容!'); + return; + } + + try { + const decoded = b64_to_utf8(input); + document.getElementById('decodeOutput').textContent = decoded; + document.getElementById('decodeResult').style.display = 'block'; + + // 检查是否是 JSON,如果是则显示格式化按钮 + try { + JSON.parse(decoded); + document.getElementById('jsonFormat').style.display = 'block'; + } catch { + document.getElementById('jsonFormat').style.display = 'none'; + } + + // 滚动到结果 + document.getElementById('decodeResult').scrollIntoView({ + behavior: 'smooth', + block: 'nearest' + }); + } catch (e) { + alert('❌ 解码失败:' + e.message + '\n\n请确保输入的是有效的 Base64 编码'); + console.error('Decode error:', e); + } + } + + // 格式化 JSON + function formatJson() { + try { + const text = document.getElementById('decodeOutput').textContent; + const obj = JSON.parse(text); + const formatted = JSON.stringify(obj, null, 2); + document.getElementById('decodeOutput').textContent = formatted; + } catch (e) { + alert('❌ JSON 格式化失败:' + e.message); + } + } + + // 复制编码结果 + function copyEncoded() { + const text = document.getElementById('encodeOutput').textContent; + navigator.clipboard.writeText(text).then(() => { + const btn = event.target; + const originalText = btn.textContent; + btn.textContent = '✅ 已复制!'; + btn.style.background = 'linear-gradient(135deg, #27ae60 0%, #229954 100%)'; + + setTimeout(() => { + btn.textContent = originalText; + btn.style.background = ''; + }, 2000); + }).catch(err => { + console.error('复制失败:', err); + alert('❌ 复制失败,请手动复制'); + }); + } + + // 复制解码结果 + function copyDecoded() { + const text = document.getElementById('decodeOutput').textContent; + navigator.clipboard.writeText(text).then(() => { + const btn = event.target; + const originalText = btn.textContent; + btn.textContent = '✅ 已复制!'; + btn.style.background = 'linear-gradient(135deg, #27ae60 0%, #229954 100%)'; + + setTimeout(() => { + btn.textContent = originalText; + btn.style.background = ''; + }, 2000); + }).catch(err => { + console.error('复制失败:', err); + alert('❌ 复制失败,请手动复制'); + }); + } + + // ==================== 深链接生成器函数 ==================== + + // 生成供应商深链接 + function generateProviderLink() { + const app = document.getElementById('providerApp').value; + const name = document.getElementById('providerName').value.trim(); + const apiKey = document.getElementById('providerApiKey').value.trim(); + const endpoint = document.getElementById('providerEndpoint').value.trim(); + const homepage = document.getElementById('providerHomepage').value.trim(); + const model = document.getElementById('providerModel').value.trim(); + const notes = document.getElementById('providerNotes').value.trim(); + const enabled = document.getElementById('providerEnabled').value; + + // 验证必填字段 + if (!name) { + alert('❌ 请填写供应商名称'); + return; + } + + if (!apiKey) { + alert('❌ 请填写 API Key'); + return; + } + + if (!endpoint) { + alert('❌ 请填写 API Endpoint'); + return; + } + + if (!homepage) { + alert('❌ 请填写主页链接'); + return; + } + + // 构建深链接 + let url = `ccswitch://v1/import?resource=provider&app=${app}&name=${encodeURIComponent(name)}&endpoint=${encodeURIComponent(endpoint)}&homepage=${encodeURIComponent(homepage)}&apiKey=${encodeURIComponent(apiKey)}`; + + if (model) { + url += `&model=${encodeURIComponent(model)}`; + } + + if (notes) { + url += `¬es=${encodeURIComponent(notes)}`; + } + + if (enabled === 'true') { + url += '&enabled=true'; + } + + // 显示结果 + document.getElementById('providerUrl').textContent = url; + document.getElementById('providerImportBtn').href = url; + document.getElementById('providerResult').style.display = 'block'; + + // 滚动到结果 + document.getElementById('providerResult').scrollIntoView({ + behavior: 'smooth', + block: 'nearest' + }); + } + + // 生成 MCP 深链接 + function generateMcpLink() { + const apps = document.getElementById('mcpApps').value.trim(); + const config = document.getElementById('mcpConfig').value.trim(); + const enabled = document.getElementById('mcpEnabled').value; + + if (!apps) { + alert('❌ 请填写目标应用'); + return; + } + + if (!config) { + alert('❌ 请填写 MCP 配置'); + return; + } + + try { + // 验证 JSON 格式 + const jsonObj = JSON.parse(config); + if (!jsonObj.mcpServers) { + alert('❌ 配置必须包含 mcpServers 字段'); + return; + } + + // Base64 编码配置 + const configB64 = utf8_to_b64(config); + + // 构建深链接 + let url = `ccswitch://v1/import?resource=mcp&apps=${encodeURIComponent(apps)}&config=${encodeURIComponent(configB64)}`; + + if (enabled === 'true') { + url += '&enabled=true'; + } + + // 显示结果 + document.getElementById('mcpUrl').textContent = url; + document.getElementById('mcpImportBtn').href = url; + document.getElementById('mcpResult').style.display = 'block'; + + // 滚动到结果 + document.getElementById('mcpResult').scrollIntoView({ + behavior: 'smooth', + block: 'nearest' + }); + } catch (e) { + alert('❌ JSON 格式错误:' + e.message); + } + } + + // 生成 Prompt 深链接 + function generatePromptLink() { + const app = document.getElementById('promptApp').value; + const name = document.getElementById('promptName').value.trim(); + const content = document.getElementById('promptContent').value.trim(); + const description = document.getElementById('promptDescription').value.trim(); + const enabled = document.getElementById('promptEnabled').value; + + if (!name) { + alert('❌ 请填写提示词名称'); + return; + } + + if (!content) { + alert('❌ 请填写提示词内容'); + return; + } + + // Base64 编码内容 + const contentB64 = utf8_to_b64(content); + + // 构建深链接 + let url = `ccswitch://v1/import?resource=prompt&app=${app}&name=${encodeURIComponent(name)}&content=${encodeURIComponent(contentB64)}`; + + if (description) { + url += `&description=${encodeURIComponent(description)}`; + } + + if (enabled === 'true') { + url += '&enabled=true'; + } + + // 显示结果 + document.getElementById('promptUrl').textContent = url; + document.getElementById('promptImportBtn').href = url; + document.getElementById('promptResult').style.display = 'block'; + + // 滚动到结果 + document.getElementById('promptResult').scrollIntoView({ + behavior: 'smooth', + block: 'nearest' + }); + } + + // 生成 Skill 深链接 + function generateSkillLink() { + const repo = document.getElementById('skillRepo').value.trim(); + const branch = document.getElementById('skillBranch').value.trim() || 'main'; + const skillsPath = document.getElementById('skillPath').value.trim() || 'skills'; + const directory = document.getElementById('skillDirectory').value.trim(); + + if (!repo) { + alert('❌ 请填写 GitHub 仓库'); + return; + } + + // 验证仓库格式 + if (!repo.includes('/')) { + alert('❌ 仓库格式应为: owner/repo-name'); + return; + } + + // 构建深链接 + let url = `ccswitch://v1/import?resource=skill&repo=${encodeURIComponent(repo)}&branch=${encodeURIComponent(branch)}&skills_path=${encodeURIComponent(skillsPath)}`; + + if (directory) { + url += `&directory=${encodeURIComponent(directory)}`; + } + + // 显示结果 + document.getElementById('skillUrl').textContent = url; + document.getElementById('skillImportBtn').href = url; + document.getElementById('skillResult').style.display = 'block'; + + // 滚动到结果 + document.getElementById('skillResult').scrollIntoView({ + behavior: 'smooth', + block: 'nearest' + }); + } + + // 复制生成的链接 + function copyGeneratedLink(elementId) { + const text = document.getElementById(elementId).textContent; + navigator.clipboard.writeText(text).then(() => { + const btn = event.target; + const originalText = btn.textContent; + btn.textContent = '✅ 已复制!'; + btn.style.background = 'linear-gradient(135deg, #27ae60 0%, #229954 100%)'; + + setTimeout(() => { + btn.textContent = originalText; + btn.style.background = ''; + }, 2000); + }).catch(err => { + console.error('复制失败:', err); + alert('❌ 复制失败,请手动复制'); + }); + } + + // 选中文本(点击 URL 时) + function selectText(element) { + const range = document.createRange(); + range.selectNodeContents(element); + const selection = window.getSelection(); + selection.removeAllRanges(); + selection.addRange(range); + }