update at 2025-10-14 21:52:11
This commit is contained in:
292
web/public/diagnose-storage.html
Normal file
292
web/public/diagnose-storage.html
Normal 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>
|
||||
Reference in New Issue
Block a user