修复网址数据服务器持久化存储

This commit is contained in:
rjb
2025-12-23 11:09:02 +08:00
parent e5a9b31a6c
commit cd8b30e0d4
15 changed files with 1755 additions and 20 deletions

117
script.js
View File

@@ -9,20 +9,35 @@ class UrlManager {
this.currentTag = '';
this.viewMode = 'grid';
this.editingUrlId = null;
this.init();
}
init() {
this.loadData();
async init() {
await this.loadData();
this.setupEventListeners();
this.render();
this.setupKeyboardShortcuts();
}
// 数据存储
loadData() {
// 加载默认数据或从localStorage加载
async loadData() {
try {
// 优先从服务器加载数据
const response = await fetch('/api/urls');
if (response.ok) {
const data = await response.json();
this.urls = data.urls && data.urls.length > 0 ? data.urls : this.getDefaultUrls();
this.categories = data.categories && data.categories.length > 0 ? data.categories : this.getDefaultCategories();
// 同时保存到 localStorage 作为备份
localStorage.setItem('urlManager_urls', JSON.stringify(this.urls));
localStorage.setItem('urlManager_categories', JSON.stringify(this.categories));
return;
}
} catch (error) {
console.warn('从服务器加载数据失败,尝试从 localStorage 加载:', error);
}
// 降级到 localStorage
const savedUrls = localStorage.getItem('urlManager_urls');
const savedCategories = localStorage.getItem('urlManager_categories');
@@ -40,15 +55,49 @@ class UrlManager {
}
}
saveData() {
async saveData() {
try {
localStorage.setItem('urlManager_urls', JSON.stringify(this.urls));
localStorage.setItem('urlManager_categories', JSON.stringify(this.categories));
const dataToSave = {
urls: this.urls || [],
categories: this.categories || []
};
console.log('保存数据:', {
urlsCount: dataToSave.urls.length,
categoriesCount: dataToSave.categories.length
});
// 优先保存到服务器
const response = await fetch('/api/urls', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(dataToSave)
});
if (response.ok) {
const result = await response.json();
console.log('服务器保存成功:', result);
// 服务器保存成功,同时保存到 localStorage 作为备份
localStorage.setItem('urlManager_urls', JSON.stringify(this.urls));
localStorage.setItem('urlManager_categories', JSON.stringify(this.categories));
return true;
} else {
const errorText = await response.text();
console.error('服务器返回错误:', response.status, errorText);
throw new Error(`服务器返回错误: ${response.status} - ${errorText}`);
}
} catch (error) {
console.error('保存数据到localStorage失败:', error);
// 如果localStorage已满或其他错误,只记录错误,不抛出异常
// 因为数据已经在内存中了,只是无法持久化
// 抛出异常会导致误报"保存失败"
console.error('保存到服务器失败:', error);
// 降级到 localStorage
try {
localStorage.setItem('urlManager_urls', JSON.stringify(this.urls));
localStorage.setItem('urlManager_categories', JSON.stringify(this.categories));
console.warn('已降级保存到 localStorage');
} catch (e) {
console.error('保存数据到localStorage也失败:', e);
}
throw error; // 重新抛出错误,让调用者知道保存失败
}
}
@@ -809,20 +858,47 @@ class UrlManager {
if (!file) return;
const reader = new FileReader();
reader.onload = (e) => {
reader.onload = async (e) => {
try {
const data = JSON.parse(e.target.result);
console.log('导入数据:', data);
if (confirm('导入数据将覆盖当前的所有数据,确定要继续吗?')) {
if (data.urls) this.urls = data.urls;
if (data.categories) this.categories = data.categories;
this.saveData();
// 更新数据
if (data.urls) {
this.urls = data.urls;
console.log('导入网址数量:', this.urls.length);
} else {
this.urls = [];
}
if (data.categories) {
this.categories = data.categories;
console.log('导入分类数量:', this.categories.length);
} else {
this.categories = [];
}
// 等待数据保存到服务器
console.log('开始保存数据到服务器...');
await this.saveData();
console.log('数据保存完成');
// 验证保存是否成功
const verifyResponse = await fetch('/api/urls');
if (verifyResponse.ok) {
const savedData = await verifyResponse.json();
console.log('服务器上的数据:', savedData);
console.log('服务器网址数量:', savedData.urls ? savedData.urls.length : 0);
}
this.render();
this.closeAllModals();
alert('数据导入成功!');
alert(`数据导入成功!已导入 ${this.urls.length} 个网址,${this.categories.length} 个分类,并已保存到服务器!`);
}
} catch (error) {
alert('文件格式错误请选择有效的JSON文件');
console.error('导入数据失败:', error);
alert('文件格式错误或保存失败: ' + error.message);
}
};
reader.readAsText(file);
@@ -1019,6 +1095,7 @@ class UrlManager {
}
// 初始化应用
document.addEventListener('DOMContentLoaded', () => {
document.addEventListener('DOMContentLoaded', async () => {
window.urlManager = new UrlManager();
await window.urlManager.init();
});