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

318
web/public/sync-data.html Normal file
View File

@@ -0,0 +1,318 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数据同步工具</title>
<style>
body {
font-family: Arial, sans-serif;
padding: 40px;
max-width: 800px;
margin: 0 auto;
background: #f5f5f5;
}
.container {
background: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
h1 {
color: #333;
margin-bottom: 10px;
}
.description {
color: #666;
margin-bottom: 30px;
line-height: 1.6;
}
.button-group {
display: flex;
gap: 10px;
margin: 20px 0;
}
button {
padding: 12px 24px;
font-size: 16px;
border: none;
border-radius: 4px;
cursor: pointer;
transition: all 0.3s;
}
.btn-primary {
background: #18a058;
color: white;
}
.btn-primary:hover {
background: #16915e;
}
.btn-secondary {
background: #f0f0f0;
color: #333;
}
.btn-secondary:hover {
background: #e0e0e0;
}
.btn-danger {
background: #d03050;
color: white;
}
.btn-danger:hover {
background: #b02848;
}
.result {
margin-top: 20px;
padding: 15px;
border-radius: 4px;
display: none;
}
.result.show {
display: block;
}
.result.success {
background: #f0f9ff;
border: 1px solid #18a058;
color: #18a058;
}
.result.error {
background: #fff0f0;
border: 1px solid #d03050;
color: #d03050;
}
.result.info {
background: #f8f9fa;
border: 1px solid #909399;
color: #606266;
}
pre {
background: #f5f5f5;
padding: 15px;
border-radius: 4px;
overflow-x: auto;
font-size: 12px;
line-height: 1.5;
}
.step {
background: #f8f9fa;
padding: 15px;
border-radius: 4px;
margin: 15px 0;
border-left: 4px solid #18a058;
}
.step-title {
font-weight: bold;
color: #18a058;
margin-bottom: 8px;
}
</style>
</head>
<body>
<div class="container">
<h1>🔄 数据同步工具</h1>
<p class="description">
由于系统使用了不同的 LocalStorage 键名,需要将数据从 <code>model-services</code> 同步到 <code>model-providers</code>
<br>点击下方按钮完成一键同步。
</p>
<div class="button-group">
<button class="btn-primary" onclick="syncData()">
✓ 一键同步数据
</button>
<button class="btn-secondary" onclick="checkData()">
🔍 检查当前数据
</button>
<button class="btn-danger" onclick="clearOldData()">
🗑️ 清理旧数据
</button>
</div>
<div id="result" class="result"></div>
<div class="step">
<div class="step-title">📋 同步步骤说明:</div>
<ol>
<li>点击"检查当前数据"查看两个键的数据状态</li>
<li>点击"一键同步数据"将 model-services 的数据复制到 model-providers</li>
<li>刷新聊天页面,模型列表将显示正确的数据</li>
<li>(可选) 同步完成后可以点击"清理旧数据"删除 model-services</li>
</ol>
</div>
</div>
<script>
function showResult(message, type = 'info') {
const resultDiv = document.getElementById('result')
resultDiv.innerHTML = message
resultDiv.className = `result ${type} show`
}
function syncData() {
try {
// 读取旧数据
const oldData = localStorage.getItem('model-services')
const newData = localStorage.getItem('model-providers')
if (!oldData) {
showResult('⚠️ 未找到 model-services 数据,无需同步', 'info')
return
}
// 解析并验证数据
let services
try {
services = JSON.parse(oldData)
if (!Array.isArray(services)) {
throw new Error('数据格式不正确')
}
} catch (e) {
showResult(`❌ 数据解析失败: ${e.message}`, 'error')
return
}
// 保存到新的键
localStorage.setItem('model-providers', oldData)
// 验证同步结果
const synced = localStorage.getItem('model-providers')
const syncedData = JSON.parse(synced)
let summary = `
<div style="font-size: 16px; font-weight: bold; margin-bottom: 10px;">
✓ 同步成功!
</div>
<div style="margin-bottom: 10px;">
已将 ${services.length} 个服务从 model-services 同步到 model-providers
</div>
<div style="margin-top: 15px;">
<strong>同步的服务:</strong>
<ul style="margin: 10px 0; padding-left: 20px;">
`
services.forEach(service => {
const modelCount = service.models?.length || 0
summary += `<li>${service.name} (${service.type}) - ${modelCount} 个模型</li>`
})
summary += `
</ul>
</div>
<div style="margin-top: 15px; padding: 10px; background: #fff3cd; border-radius: 4px;">
⚡ <strong>下一步:</strong> 请刷新聊天页面查看效果
</div>
`
showResult(summary, 'success')
// 自动刷新页面提示
setTimeout(() => {
if (confirm('数据同步成功!是否立即打开聊天页面查看效果?')) {
window.open('/', '_blank')
}
}, 1000)
} catch (error) {
showResult(`❌ 同步失败: ${error.message}`, 'error')
console.error('Sync error:', error)
}
}
function checkData() {
try {
const oldData = localStorage.getItem('model-services')
const newData = localStorage.getItem('model-providers')
let report = '<div style="font-size: 16px; font-weight: bold; margin-bottom: 15px;">📊 数据检查报告</div>'
// 检查 model-services
report += '<div style="margin-bottom: 20px;">'
report += '<strong>model-services (旧键):</strong><br>'
if (oldData) {
try {
const services = JSON.parse(oldData)
report += `✓ 找到数据 (${services.length} 个服务)<br>`
report += '<ul style="margin: 5px 0; padding-left: 20px;">'
services.forEach(s => {
report += `<li>${s.name} - ${s.models?.length || 0} 个模型</li>`
})
report += '</ul>'
} catch (e) {
report += `⚠️ 数据格式错误: ${e.message}`
}
} else {
report += '✗ 无数据'
}
report += '</div>'
// 检查 model-providers
report += '<div style="margin-bottom: 20px;">'
report += '<strong>model-providers (新键):</strong><br>'
if (newData) {
try {
const providers = JSON.parse(newData)
report += `✓ 找到数据 (${providers.length} 个服务)<br>`
report += '<ul style="margin: 5px 0; padding-left: 20px;">'
providers.forEach(p => {
report += `<li>${p.name} - ${p.models?.length || 0} 个模型</li>`
})
report += '</ul>'
} catch (e) {
report += `⚠️ 数据格式错误: ${e.message}`
}
} else {
report += '✗ 无数据'
}
report += '</div>'
// 建议
report += '<div style="padding: 10px; background: #f0f9ff; border-radius: 4px; border-left: 4px solid #18a058;">'
if (oldData && !newData) {
report += '💡 建议: 点击"一键同步数据"将旧数据迁移到新键'
} else if (oldData && newData) {
const oldServices = JSON.parse(oldData)
const newProviders = JSON.parse(newData)
if (oldServices.length > newProviders.length) {
report += '💡 建议: model-services 的数据更新,建议重新同步'
} else {
report += '✓ 数据已同步,可以点击"清理旧数据"删除 model-services'
}
} else if (!oldData && newData) {
report += '✓ 数据正常,新键已有数据'
} else {
report += '⚠️ 未找到任何模型服务数据,请先在"模型服务"页面添加服务'
}
report += '</div>'
showResult(report, 'info')
} catch (error) {
showResult(`❌ 检查失败: ${error.message}`, 'error')
console.error('Check error:', error)
}
}
function clearOldData() {
if (!confirm('确定要删除 model-services 的旧数据吗?\n\n请确保已经完成数据同步')) {
return
}
try {
const oldData = localStorage.getItem('model-services')
if (!oldData) {
showResult(' model-services 中没有数据', 'info')
return
}
localStorage.removeItem('model-services')
showResult('✓ 旧数据已清理完成', 'success')
} catch (error) {
showResult(`❌ 清理失败: ${error.message}`, 'error')
}
}
// 页面加载时自动检查
window.onload = function() {
checkData()
}
</script>
</body>
</html>