update at 2025-10-14 21:52:11

This commit is contained in:
douboer
2025-10-14 21:52:11 +08:00
parent ac3ed480ab
commit 4f5eea604e
40 changed files with 15231 additions and 126 deletions

View File

@@ -0,0 +1,292 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LocalStorage 诊断工具</title>
<style>
body {
font-family: 'Monaco', 'Menlo', monospace;
padding: 20px;
background: #1e1e1e;
color: #d4d4d4;
line-height: 1.6;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
h1 {
color: #4ec9b0;
border-bottom: 2px solid #4ec9b0;
padding-bottom: 10px;
}
h2 {
color: #dcdcaa;
margin-top: 30px;
}
.section {
background: #252526;
padding: 20px;
border-radius: 8px;
margin: 15px 0;
border: 1px solid #3c3c3c;
}
.key-name {
color: #9cdcfe;
font-weight: bold;
}
.value {
color: #ce9178;
}
pre {
background: #1e1e1e;
padding: 15px;
border-radius: 4px;
overflow-x: auto;
border: 1px solid #3c3c3c;
}
button {
background: #0e639c;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
margin: 5px;
font-size: 14px;
}
button:hover {
background: #1177bb;
}
.success { color: #4ec9b0; }
.error { color: #f48771; }
.warning { color: #dcdcaa; }
.info { color: #9cdcfe; }
table {
width: 100%;
border-collapse: collapse;
margin: 15px 0;
}
th, td {
padding: 10px;
text-align: left;
border-bottom: 1px solid #3c3c3c;
}
th {
background: #1e1e1e;
color: #4ec9b0;
}
.action-buttons {
display: flex;
gap: 10px;
flex-wrap: wrap;
margin: 20px 0;
}
</style>
</head>
<body>
<div class="container">
<h1>🔍 LocalStorage 完整诊断</h1>
<div class="action-buttons">
<button onclick="diagnose()">🔄 重新诊断</button>
<button onclick="fixData()">🔧 修复数据</button>
<button onclick="clearAll()">🗑️ 清空所有</button>
<button onclick="exportData()">💾 导出数据</button>
</div>
<div id="output"></div>
</div>
<script>
function diagnose() {
const output = document.getElementById('output')
let html = ''
// 1. 显示所有 LocalStorage 键
html += '<div class="section">'
html += '<h2>📋 所有 LocalStorage 键值对</h2>'
html += '<table>'
html += '<tr><th>键名</th><th>大小</th><th>数据类型</th><th>操作</th></tr>'
const allKeys = Object.keys(localStorage).sort()
if (allKeys.length === 0) {
html += '<tr><td colspan="4" class="warning">⚠️ LocalStorage 为空</td></tr>'
} else {
allKeys.forEach(key => {
const value = localStorage.getItem(key)
const size = new Blob([value]).size
let type = 'string'
try {
const parsed = JSON.parse(value)
type = Array.isArray(parsed) ? 'array' : typeof parsed
} catch (e) {
type = 'string'
}
html += `<tr>
<td class="key-name">${key}</td>
<td>${(size / 1024).toFixed(2)} KB</td>
<td>${type}</td>
<td><button onclick="viewKey('${key}')">查看</button></td>
</tr>`
})
}
html += '</table></div>'
// 2. 重点检查模型相关的键
html += '<div class="section">'
html += '<h2>🎯 模型服务相关键检查</h2>'
const modelKeys = [
'model-services',
'model-providers',
'model-service-config',
'services',
'providers'
]
modelKeys.forEach(key => {
const value = localStorage.getItem(key)
html += `<h3 class="key-name">${key}:</h3>`
if (!value) {
html += `<p class="error">✗ 不存在</p>`
} else {
try {
const parsed = JSON.parse(value)
if (Array.isArray(parsed)) {
html += `<p class="success">✓ 找到 ${parsed.length} 项</p>`
html += '<pre>' + JSON.stringify(parsed, null, 2) + '</pre>'
} else {
html += '<pre>' + JSON.stringify(parsed, null, 2) + '</pre>'
}
} catch (e) {
html += `<p class="warning">⚠️ 非JSON格式</p>`
html += '<pre>' + value.substring(0, 500) + '...</pre>'
}
}
})
html += '</div>'
// 3. 诊断建议
html += '<div class="section">'
html += '<h2>💡 诊断结果与建议</h2>'
const modelServices = localStorage.getItem('model-services')
const modelProviders = localStorage.getItem('model-providers')
if (!modelServices && !modelProviders) {
html += '<p class="error">❌ 未找到任何模型服务数据</p>'
html += '<p class="info">原因可能:</p>'
html += '<ul>'
html += '<li>数据保存失败(检查浏览器控制台是否有错误)</li>'
html += '<li>使用了不同的存储方式sessionStorage、IndexedDB等</li>'
html += '<li>页面域名不同导致 LocalStorage 隔离</li>'
html += '</ul>'
html += '<p class="warning">🔧 建议:点击"修复数据"按钮创建测试数据</p>'
} else if (modelServices && !modelProviders) {
html += '<p class="warning">⚠️ 找到 model-services 但缺少 model-providers</p>'
html += '<p class="info">需要同步数据到 model-providers</p>'
} else if (!modelServices && modelProviders) {
html += '<p class="success">✓ model-providers 有数据(正确的键)</p>'
html += '<p class="info">可以清理旧的 model-services 键</p>'
} else {
html += '<p class="info"> 两个键都存在,需要判断哪个是最新的</p>'
}
html += '</div>'
output.innerHTML = html
}
function viewKey(key) {
const value = localStorage.getItem(key)
const newWindow = window.open('', '_blank')
newWindow.document.write('<pre>' + JSON.stringify(JSON.parse(value), null, 2) + '</pre>')
}
function fixData() {
// 检查是否有 model-services 数据
const modelServices = localStorage.getItem('model-services')
if (modelServices) {
// 复制到 model-providers
localStorage.setItem('model-providers', modelServices)
alert('✓ 已将 model-services 同步到 model-providers')
} else {
// 创建测试数据
const testData = [
{
id: 'test-dashscope',
name: '阿里大模型',
type: 'dashscope',
url: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
apiKey: 'sk-test',
enabled: true,
connected: true,
status: 'connected',
models: [
{ id: 'qwen-max', name: 'Qwen Max' },
{ id: 'qwen-plus', name: 'Qwen Plus' }
]
},
{
id: 'test-volcengine',
name: '火山大模型',
type: 'volcengine',
url: 'https://ark.cn-beijing.volces.com/api/v3',
apiKey: 'test-key',
enabled: true,
connected: true,
status: 'connected',
models: [
{ id: 'doubao-pro-4k', name: 'Doubao Pro 4K' },
{ id: 'doubao-pro-32k', name: 'Doubao Pro 32K' }
]
}
]
localStorage.setItem('model-providers', JSON.stringify(testData))
localStorage.setItem('model-services', JSON.stringify(testData))
alert('✓ 已创建测试数据')
}
diagnose()
}
function clearAll() {
if (confirm('确定要清空所有 LocalStorage 数据吗?')) {
localStorage.clear()
alert('✓ 已清空')
diagnose()
}
}
function exportData() {
const data = {}
Object.keys(localStorage).forEach(key => {
try {
data[key] = JSON.parse(localStorage.getItem(key))
} catch (e) {
data[key] = localStorage.getItem(key)
}
})
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = 'localStorage-backup.json'
a.click()
}
// 页面加载时自动诊断
window.onload = diagnose
</script>
</body>
</html>