diff --git a/worker.js b/worker.js index 52de3f3..282db93 100644 --- a/worker.js +++ b/worker.js @@ -1,2097 +1,2155 @@ -addEventListener('fetch', (event) => { - event.respondWith(handleRequest(event.request)); - }); - - async function handleRequest(request) { - const url = new URL(request.url); - const { pathname } = url; - - try { - // 登录请求处理 - if (pathname === '/login' && request.method === 'POST') { - const formData = new URLSearchParams(await request.text()); - const username = formData.get('username'); - const password = formData.get('password'); - - if (username === envusername && password === envpassword) { - return new Response(await renderNavigationPage(), { - headers: { 'Content-Type': 'text/html; charset=utf-8' }, - }); - } - // 登录失败时直接返回登录页面并显示错误 - return new Response(await renderLoginPage(true), { - headers: { 'Content-Type': 'text/html; charset=utf-8' } - }); - } - - // 路由处理 - switch (pathname) { - case '/': - case '/login.html': - return new Response(await renderLoginPage(), { - headers: { 'Content-Type': 'text/html; charset=utf-8' } - }); - - case '/privacy': - return serveStaticFile('privacy.html'); - - case '/data': - return fetchNavigationData(); - - case '/add-category': - if (request.method === 'POST') return addCategory(request); - break; - - case '/add-site': - if (request.method === 'POST') return addSite(request); - break; - - case '/delete-category': - if (request.method === 'POST') return deleteCategory(request); - break; - - case '/delete-site': - if (request.method === 'POST') return deleteSite(request); - break; - - case '/edit-site': - if (request.method === 'POST') return editSite(request); - break; - case '/edit-category': - if (request.method === 'POST') return editCategory(request); - break; - // 在handleRequest中添加切换分类状态的路由 - case '/toggle-category': - if (request.method === 'POST') return toggleCategory(request); - break; - // 在handleRequest的switch语句中添加新路由 - case '/reorder-site': - if (request.method === 'POST') return reorderSite(request); - break; - case '/load-notification': - return loadNotification(); - } - - // 未匹配的路由返回404 - return serveStaticFile('NotFound.html', 404); - } catch (error) { - console.error('Error handling request:', error); - return new Response('Internal Server Error', { status: 500 }); - } - } - - // KV 数据操作函数 - async function getNavigationData() { - const data = await NAVIGATION_DATA.get('data'); - const parsedData = data ? JSON.parse(data) : { categories: [] }; - - // 初始化折叠状态 - parsedData.categories.forEach(category => { - if (typeof category.collapsed === 'undefined') { - category.collapsed = false; // 默认展开状态 - } - }); - - return parsedData; - } - // 添加站点重新排序功能 - async function reorderSite(request) { - const requestBody = await request.json(); - const { categoryIndex, oldIndex, newIndex } = requestBody; - const navigationData = await getNavigationData(); - - // 验证分类索引 - if (categoryIndex < 0 || categoryIndex >= navigationData.categories.length) { - return new Response(JSON.stringify({ error: '无效分类索引' }), { - status: 400, - headers: { 'Content-Type': 'application/json' } - }); - } - - const category = navigationData.categories[categoryIndex]; - // 验证站点索引 - if (oldIndex < 0 || oldIndex >= category.sites.length || - newIndex < 0 || newIndex >= category.sites.length) { - return new Response(JSON.stringify({ error: '无效站点索引' }), { - status: 400, - headers: { 'Content-Type': 'application/json' } - }); - } - - // 移动站点位置 - const siteToMove = category.sites.splice(oldIndex, 1)[0]; - category.sites.splice(newIndex, 0, siteToMove); - - await setNavigationData(navigationData); - return new Response(JSON.stringify({ message: '站点顺序已更新' }), { - headers: { 'Content-Type': 'application/json; charset=utf-8' } - }); - } - // 添加编辑分类的API处理函数 -async function editCategory(request) { - const requestBody = await request.json(); - const navigationData = await getNavigationData(); - - // 验证索引有效性 - if (requestBody.categoryIndex < 0 || - requestBody.categoryIndex >= navigationData.categories.length) { - return new Response(JSON.stringify({ error: '无效分类索引' }), { - status: 400, - headers: { 'Content-Type': 'application/json' } - }); - } - - // 检查新名称是否已存在 - const newName = requestBody.newName.trim(); - const categoryExists = navigationData.categories.some( - (cat, index) => index !== requestBody.categoryIndex && cat.name === newName - ); - - if (categoryExists) { - return new Response(JSON.stringify({ error: '分类名称已存在' }), { - status: 400, - headers: { 'Content-Type': 'application/json' } - }); - } - - // 更新分类名称 - navigationData.categories[requestBody.categoryIndex].name = newName; - - await setNavigationData(navigationData); - return new Response(JSON.stringify({ message: '分类名称修改成功' }), { - headers: { 'Content-Type': 'application/json; charset=utf-8' } - }); - } - // 添加切换分类折叠状态的API处理函数 -async function toggleCategory(request) { - const requestBody = await request.json(); - const navigationData = await getNavigationData(); - - // 验证索引有效性 - if (requestBody.categoryIndex < 0 || - requestBody.categoryIndex >= navigationData.categories.length) { - return new Response(JSON.stringify({ error: '无效分类索引' }), { - status: 400, - headers: { 'Content-Type': 'application/json' } - }); - } - - // 切换折叠状态 - const category = navigationData.categories[requestBody.categoryIndex]; - category.collapsed = !category.collapsed; - - await setNavigationData(navigationData); - return new Response(JSON.stringify({ - message: '状态更新成功', - collapsed: category.collapsed - }), { - headers: { 'Content-Type': 'application/json; charset=utf-8' } - }); - } - - // 切换分类折叠状态 -async function toggleCategoryState(categoryIndex) { - const response = await fetch('/toggle-category', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ categoryIndex }) - }); - - if (response.ok) { - const result = await response.json(); - const categoryElement = document.getElementById(`category-sites-${categoryIndex}`); - const toggleIcon = document.querySelector(`.toggle-btn[onclick="toggleCategoryState(${categoryIndex})"] .iconify`); - - if (result.collapsed) { - categoryElement.style.display = 'none'; - toggleIcon.setAttribute('data-icon', 'mdi:chevron-right'); - } else { - categoryElement.style.display = 'flex'; - toggleIcon.setAttribute('data-icon', 'mdi:chevron-down'); - } - } - } - - - async function setNavigationData(data) { - await NAVIGATION_DATA.put('data', JSON.stringify(data)); - } - - // 静态文件服务 - async function serveStaticFile(filename, status = 200) { - const content = await STATIC_FILES.get(filename); - if (content) { - return new Response(content, { - status, - headers: { 'Content-Type': 'text/html; charset=utf-8' } - }); - } - return new Response(`${filename} not found`, { status: 404 }); - } - - // API 端点处理函数 - async function fetchNavigationData() { - const navigationData = await getNavigationData(); - return new Response(JSON.stringify(navigationData), { - headers: { - 'Content-Type': 'application/json; charset=utf-8', - 'Cache-Control': 'no-cache' - } - }); - } - - async function addCategory(request) { - const requestBody = await request.json(); - const navigationData = await getNavigationData(); - - // 检查分类是否已存在 - const categoryExists = navigationData.categories.some( - cat => cat.name === requestBody.name - ); - - if (categoryExists) { - return new Response(JSON.stringify({ error: '分类已存在' }), { - status: 400, - headers: { 'Content-Type': 'application/json' } - }); - } - - navigationData.categories.push({ - name: requestBody.name, - sites: [] - }); - - await setNavigationData(navigationData); - return new Response(JSON.stringify({ message: '分类添加成功' }), { - headers: { 'Content-Type': 'application/json; charset=utf-8' } - }); - } - - async function addSite(request) { - const requestBody = await request.json(); - const navigationData = await getNavigationData(); - - // 验证索引有效性 - if (requestBody.categoryIndex < 0 || - requestBody.categoryIndex >= navigationData.categories.length) { - return new Response(JSON.stringify({ error: '无效分类索引' }), { - status: 400, - headers: { 'Content-Type': 'application/json' } - }); - } - - // 添加站点描述字段 - navigationData.categories[requestBody.categoryIndex].sites.push({ - name: requestBody.siteName, - url: requestBody.siteUrl, - icon: requestBody.siteIcon, - info: requestBody.siteInfo || '' // 添加站点描述 - }); - - await setNavigationData(navigationData); - return new Response(JSON.stringify({ message: '站点添加成功' }), { - headers: { 'Content-Type': 'application/json; charset=utf-8' } - }); - } - - async function editSite(request) { - const requestBody = await request.json(); - const navigationData = await getNavigationData(); - - // 获取原始分类索引和新分类索引 - const originalCategoryIndex = requestBody.originalCategoryIndex; - const newCategoryIndex = requestBody.newCategoryIndex; - const siteIndex = requestBody.siteIndex; - - // 验证索引有效性 - if (originalCategoryIndex < 0 || - originalCategoryIndex >= navigationData.categories.length || - newCategoryIndex < 0 || - newCategoryIndex >= navigationData.categories.length) { - return new Response(JSON.stringify({ error: '无效分类索引' }), { - status: 400, - headers: { 'Content-Type': 'application/json' } - }); - } - - const originalCategory = navigationData.categories[originalCategoryIndex]; - if (siteIndex < 0 || siteIndex >= originalCategory.sites.length) { - return new Response(JSON.stringify({ error: '无效站点索引' }), { - status: 400, - headers: { 'Content-Type': 'application/json' } - }); - } - - // 获取站点对象 - const site = originalCategory.sites[siteIndex]; - - // 更新站点信息 - site.name = requestBody.siteName; - site.url = requestBody.siteUrl; - site.icon = requestBody.siteIcon; - site.info = requestBody.siteInfo || ''; - - // 如果分类发生变化,移动站点到新分类 - if (originalCategoryIndex !== newCategoryIndex) { - // 从原分类移除 - originalCategory.sites.splice(siteIndex, 1); - - // 添加到新分类 - navigationData.categories[newCategoryIndex].sites.push(site); - } - - await setNavigationData(navigationData); - return new Response(JSON.stringify({ message: '站点更新成功' }), { - headers: { 'Content-Type': 'application/json; charset=utf-8' } - }); - } - - async function deleteCategory(request) { - const requestBody = await request.json(); - const navigationData = await getNavigationData(); - - // 验证索引有效性 - if (requestBody.categoryIndex < 0 || - requestBody.categoryIndex >= navigationData.categories.length) { - return new Response(JSON.stringify({ error: '无效分类索引' }), { - status: 400, - headers: { 'Content-Type': 'application/json' } - }); - } - - navigationData.categories.splice(requestBody.categoryIndex, 1); - await setNavigationData(navigationData); - return new Response(JSON.stringify({ message: '分类删除成功' }), { - headers: { 'Content-Type': 'application/json; charset=utf-8' } - }); - } - - async function deleteSite(request) { - const requestBody = await request.json(); - const navigationData = await getNavigationData(); - - // 验证索引有效性 - if (requestBody.categoryIndex < 0 || - requestBody.categoryIndex >= navigationData.categories.length) { - return new Response(JSON.stringify({ error: '无效分类索引' }), { - status: 400, - headers: { 'Content-Type': 'application/json' } - }); - } - - const category = navigationData.categories[requestBody.categoryIndex]; - if (requestBody.siteIndex < 0 || requestBody.siteIndex >= category.sites.length) { - return new Response(JSON.stringify({ error: '无效站点索引' }), { - status: 400, - headers: { 'Content-Type': 'application/json' } - }); - } - - category.sites.splice(requestBody.siteIndex, 1); - await setNavigationData(navigationData); - return new Response(JSON.stringify({ message: '站点删除成功' }), { - headers: { 'Content-Type': 'application/json; charset=utf-8' } - }); - } - - async function loadNotification() { - const notification = await NAVIGATION_DATA.get('info'); - return new Response(notification || '', { - headers: { 'Cache-Control': 'no-cache' } - }); - } - - // 页面渲染函数 - async function renderLoginPage(showError = false) { - return ` - - - - - - Dispark|点滴星火登录页 - - - -

- - Prometheus Icon - - Dispark|点滴星火 -

- -
-
用户名或密码错误,请重试
-
- - - -
-
- - - - `; - } - - async function renderNavigationPage() { - const navigationData = await getNavigationData(); - - const html = ` - - - - - - Dispark|点滴星火 - - - - - -
- -
- -
-
- - Logo -

Dispark

-
-
-
- 正在加载时间... -
-
- - -
- - - -
-
- - -
- -
点滴星火导航站
-
探索 · 连接 · 发现
-
- - -
- - - - - - - -
-
-
- -
- ${renderCategories(navigationData.categories)} - -
- -
-
-
-
- - -
-
-
- - - - - - - - - - - - - - - - `; - - return html; - } - - /// 修复renderCategories函数 - 关键修改 -function renderCategories(categories) { - return categories.map((category, categoryIndex) => ` -
-

- - - - ${category.name} - - - - - - - - - -

- - -
- `).join(''); -} - - // 辅助函数:转义特殊字符 - function escapeString(str) { - return str ? str - .replace(/\\/g, '\\\\') - .replace(/'/g, "\\'") - .replace(/"/g, '\\"') - .replace(/\n/g, '\\n') - .replace(/\r/g, '\\r') : ''; - } +addEventListener('fetch', (event) => { + event.respondWith(handleRequest(event.request)); + }); + + async function handleRequest(request) { + const url = new URL(request.url); + const { pathname } = url; + + try { + // 登录请求处理 + if (pathname === '/login' && request.method === 'POST') { + const formData = new URLSearchParams(await request.text()); + const username = formData.get('username'); + const password = formData.get('password'); + + if (username === envusername && password === envpassword) { + return new Response(await renderNavigationPage(), { + headers: { 'Content-Type': 'text/html; charset=utf-8' }, + }); + } + // 登录失败时直接返回登录页面并显示错误 + return new Response(await renderLoginPage(true), { + headers: { 'Content-Type': 'text/html; charset=utf-8' } + }); + } + + // 路由处理 + switch (pathname) { + case '/': + case '/login.html': + return new Response(await renderLoginPage(), { + headers: { 'Content-Type': 'text/html; charset=utf-8' } + }); + + case '/privacy': + return serveStaticFile('privacy.html'); + + case '/data': + return fetchNavigationData(); + + case '/add-category': + if (request.method === 'POST') return addCategory(request); + break; + + case '/add-site': + if (request.method === 'POST') return addSite(request); + break; + + case '/delete-category': + if (request.method === 'POST') return deleteCategory(request); + break; + + case '/delete-site': + if (request.method === 'POST') return deleteSite(request); + break; + + case '/edit-site': + if (request.method === 'POST') return editSite(request); + break; + case '/edit-category': + if (request.method === 'POST') return editCategory(request); + break; + // 在handleRequest中添加切换分类状态的路由 + case '/toggle-category': + if (request.method === 'POST') return toggleCategory(request); + break; + // 在handleRequest的switch语句中添加新路由 + case '/reorder-site': + if (request.method === 'POST') return reorderSite(request); + break; + case '/load-notification': + return loadNotification(); + case '/export': + return exportData(); // 导出接口 + + case '/import': + if (request.method === 'POST') return importData(request); + break; + } + + // 未匹配的路由返回404 + return serveStaticFile('NotFound.html', 404); + } catch (error) { + console.error('Error handling request:', error); + return new Response('Internal Server Error', { status: 500 }); + } + } + + // KV 数据操作函数 + async function getNavigationData() { + const data = await NAVIGATION_DATA.get('data'); + const parsedData = data ? JSON.parse(data) : { categories: [] }; + + // 初始化折叠状态 + parsedData.categories.forEach(category => { + if (typeof category.collapsed === 'undefined') { + category.collapsed = false; // 默认展开状态 + } + }); + + return parsedData; + } + // 导出导航数据为 JSON 文件 + async function exportData() { + const navigationData = await getNavigationData(); // 复用已有函数 + const jsonStr = JSON.stringify(navigationData, null, 2); + + return new Response(jsonStr, { + headers: { + 'Content-Type': 'application/json', + 'Content-Disposition': 'attachment; filename="navigation_backup.json"', + }, + }); + } + // 从上传的 JSON 文件导入导航数据 + async function importData(request) { + try { + const formData = await request.formData(); + const file = formData.get('file'); + + if (!file) { + return new Response(JSON.stringify({ error: '请选择要导入的文件' }), { + status: 400, + headers: { 'Content-Type': 'application/json' }, + }); + } + + // 读取文件内容 + const fileText = await file.text(); + const importedData = JSON.parse(fileText); + + // 简单验证格式:必须包含 categories 数组 + if (!importedData || !Array.isArray(importedData.categories)) { + return new Response(JSON.stringify({ error: '无效的备份文件格式,缺少 categories 数组' }), { + status: 400, + headers: { 'Content-Type': 'application/json' }, + }); + } + + // 可选:进一步验证每个分类和站点结构(这里略,可根据需要补充) + + // 写入 KV + await NAVIGATION_DATA.put('data', JSON.stringify(importedData)); + + return new Response(JSON.stringify({ message: '数据导入成功' }), { + headers: { 'Content-Type': 'application/json; charset=utf-8' }, + }); + } catch (error) { + return new Response(JSON.stringify({ error: '导入失败:' + error.message }), { + status: 500, + headers: { 'Content-Type': 'application/json' }, + }); + } + } + // 添加站点重新排序功能 + async function reorderSite(request) { + const requestBody = await request.json(); + const { categoryIndex, oldIndex, newIndex } = requestBody; + const navigationData = await getNavigationData(); + + // 验证分类索引 + if (categoryIndex < 0 || categoryIndex >= navigationData.categories.length) { + return new Response(JSON.stringify({ error: '无效分类索引' }), { + status: 400, + headers: { 'Content-Type': 'application/json' } + }); + } + + const category = navigationData.categories[categoryIndex]; + // 验证站点索引 + if (oldIndex < 0 || oldIndex >= category.sites.length || + newIndex < 0 || newIndex >= category.sites.length) { + return new Response(JSON.stringify({ error: '无效站点索引' }), { + status: 400, + headers: { 'Content-Type': 'application/json' } + }); + } + + // 移动站点位置 + const siteToMove = category.sites.splice(oldIndex, 1)[0]; + category.sites.splice(newIndex, 0, siteToMove); + + await setNavigationData(navigationData); + return new Response(JSON.stringify({ message: '站点顺序已更新' }), { + headers: { 'Content-Type': 'application/json; charset=utf-8' } + }); + } + // 添加编辑分类的API处理函数 +async function editCategory(request) { + const requestBody = await request.json(); + const navigationData = await getNavigationData(); + + // 验证索引有效性 + if (requestBody.categoryIndex < 0 || + requestBody.categoryIndex >= navigationData.categories.length) { + return new Response(JSON.stringify({ error: '无效分类索引' }), { + status: 400, + headers: { 'Content-Type': 'application/json' } + }); + } + + // 检查新名称是否已存在 + const newName = requestBody.newName.trim(); + const categoryExists = navigationData.categories.some( + (cat, index) => index !== requestBody.categoryIndex && cat.name === newName + ); + + if (categoryExists) { + return new Response(JSON.stringify({ error: '分类名称已存在' }), { + status: 400, + headers: { 'Content-Type': 'application/json' } + }); + } + + // 更新分类名称 + navigationData.categories[requestBody.categoryIndex].name = newName; + + await setNavigationData(navigationData); + return new Response(JSON.stringify({ message: '分类名称修改成功' }), { + headers: { 'Content-Type': 'application/json; charset=utf-8' } + }); + } + // 添加切换分类折叠状态的API处理函数 +async function toggleCategory(request) { + const requestBody = await request.json(); + const navigationData = await getNavigationData(); + + // 验证索引有效性 + if (requestBody.categoryIndex < 0 || + requestBody.categoryIndex >= navigationData.categories.length) { + return new Response(JSON.stringify({ error: '无效分类索引' }), { + status: 400, + headers: { 'Content-Type': 'application/json' } + }); + } + + // 切换折叠状态 + const category = navigationData.categories[requestBody.categoryIndex]; + category.collapsed = !category.collapsed; + + await setNavigationData(navigationData); + return new Response(JSON.stringify({ + message: '状态更新成功', + collapsed: category.collapsed + }), { + headers: { 'Content-Type': 'application/json; charset=utf-8' } + }); + } + + // 切换分类折叠状态 +async function toggleCategoryState(categoryIndex) { + const response = await fetch('/toggle-category', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ categoryIndex }) + }); + + if (response.ok) { + const result = await response.json(); + const categoryElement = document.getElementById(`category-sites-${categoryIndex}`); + const toggleIcon = document.querySelector(`.toggle-btn[onclick="toggleCategoryState(${categoryIndex})"] .iconify`); + + if (result.collapsed) { + categoryElement.style.display = 'none'; + toggleIcon.setAttribute('data-icon', 'mdi:chevron-right'); + } else { + categoryElement.style.display = 'flex'; + toggleIcon.setAttribute('data-icon', 'mdi:chevron-down'); + } + } + } + + + async function setNavigationData(data) { + await NAVIGATION_DATA.put('data', JSON.stringify(data)); + } + + // 静态文件服务 + async function serveStaticFile(filename, status = 200) { + const content = await STATIC_FILES.get(filename); + if (content) { + return new Response(content, { + status, + headers: { 'Content-Type': 'text/html; charset=utf-8' } + }); + } + return new Response(`${filename} not found`, { status: 404 }); + } + + // API 端点处理函数 + async function fetchNavigationData() { + const navigationData = await getNavigationData(); + return new Response(JSON.stringify(navigationData), { + headers: { + 'Content-Type': 'application/json; charset=utf-8', + 'Cache-Control': 'no-cache' + } + }); + } + + async function addCategory(request) { + const requestBody = await request.json(); + const navigationData = await getNavigationData(); + + // 检查分类是否已存在 + const categoryExists = navigationData.categories.some( + cat => cat.name === requestBody.name + ); + + if (categoryExists) { + return new Response(JSON.stringify({ error: '分类已存在' }), { + status: 400, + headers: { 'Content-Type': 'application/json' } + }); + } + + navigationData.categories.push({ + name: requestBody.name, + sites: [] + }); + + await setNavigationData(navigationData); + return new Response(JSON.stringify({ message: '分类添加成功' }), { + headers: { 'Content-Type': 'application/json; charset=utf-8' } + }); + } + + async function addSite(request) { + const requestBody = await request.json(); + const navigationData = await getNavigationData(); + + // 验证索引有效性 + if (requestBody.categoryIndex < 0 || + requestBody.categoryIndex >= navigationData.categories.length) { + return new Response(JSON.stringify({ error: '无效分类索引' }), { + status: 400, + headers: { 'Content-Type': 'application/json' } + }); + } + + // 添加站点描述字段 + navigationData.categories[requestBody.categoryIndex].sites.push({ + name: requestBody.siteName, + url: requestBody.siteUrl, + icon: requestBody.siteIcon, + info: requestBody.siteInfo || '' // 添加站点描述 + }); + + await setNavigationData(navigationData); + return new Response(JSON.stringify({ message: '站点添加成功' }), { + headers: { 'Content-Type': 'application/json; charset=utf-8' } + }); + } + + async function editSite(request) { + const requestBody = await request.json(); + const navigationData = await getNavigationData(); + + // 获取原始分类索引和新分类索引 + const originalCategoryIndex = requestBody.originalCategoryIndex; + const newCategoryIndex = requestBody.newCategoryIndex; + const siteIndex = requestBody.siteIndex; + + // 验证索引有效性 + if (originalCategoryIndex < 0 || + originalCategoryIndex >= navigationData.categories.length || + newCategoryIndex < 0 || + newCategoryIndex >= navigationData.categories.length) { + return new Response(JSON.stringify({ error: '无效分类索引' }), { + status: 400, + headers: { 'Content-Type': 'application/json' } + }); + } + + const originalCategory = navigationData.categories[originalCategoryIndex]; + if (siteIndex < 0 || siteIndex >= originalCategory.sites.length) { + return new Response(JSON.stringify({ error: '无效站点索引' }), { + status: 400, + headers: { 'Content-Type': 'application/json' } + }); + } + + // 获取站点对象 + const site = originalCategory.sites[siteIndex]; + + // 更新站点信息 + site.name = requestBody.siteName; + site.url = requestBody.siteUrl; + site.icon = requestBody.siteIcon; + site.info = requestBody.siteInfo || ''; + + // 如果分类发生变化,移动站点到新分类 + if (originalCategoryIndex !== newCategoryIndex) { + // 从原分类移除 + originalCategory.sites.splice(siteIndex, 1); + + // 添加到新分类 + navigationData.categories[newCategoryIndex].sites.push(site); + } + + await setNavigationData(navigationData); + return new Response(JSON.stringify({ message: '站点更新成功' }), { + headers: { 'Content-Type': 'application/json; charset=utf-8' } + }); + } + + async function deleteCategory(request) { + const requestBody = await request.json(); + const navigationData = await getNavigationData(); + + // 验证索引有效性 + if (requestBody.categoryIndex < 0 || + requestBody.categoryIndex >= navigationData.categories.length) { + return new Response(JSON.stringify({ error: '无效分类索引' }), { + status: 400, + headers: { 'Content-Type': 'application/json' } + }); + } + + navigationData.categories.splice(requestBody.categoryIndex, 1); + await setNavigationData(navigationData); + return new Response(JSON.stringify({ message: '分类删除成功' }), { + headers: { 'Content-Type': 'application/json; charset=utf-8' } + }); + } + + async function deleteSite(request) { + const requestBody = await request.json(); + const navigationData = await getNavigationData(); + + // 验证索引有效性 + if (requestBody.categoryIndex < 0 || + requestBody.categoryIndex >= navigationData.categories.length) { + return new Response(JSON.stringify({ error: '无效分类索引' }), { + status: 400, + headers: { 'Content-Type': 'application/json' } + }); + } + + const category = navigationData.categories[requestBody.categoryIndex]; + if (requestBody.siteIndex < 0 || requestBody.siteIndex >= category.sites.length) { + return new Response(JSON.stringify({ error: '无效站点索引' }), { + status: 400, + headers: { 'Content-Type': 'application/json' } + }); + } + + category.sites.splice(requestBody.siteIndex, 1); + await setNavigationData(navigationData); + return new Response(JSON.stringify({ message: '站点删除成功' }), { + headers: { 'Content-Type': 'application/json; charset=utf-8' } + }); + } + + async function loadNotification() { + const notification = await NAVIGATION_DATA.get('info'); + return new Response(notification || '', { + headers: { 'Cache-Control': 'no-cache' } + }); + } + + // 页面渲染函数 + async function renderLoginPage(showError = false) { + return ` + + + + + + Dispark|点滴星火登录页 + + + +

+ + Prometheus Icon + + Dispark|点滴星火 +

+ +
+
用户名或密码错误,请重试
+
+ + + +
+
+ + + + `; + } + + async function renderNavigationPage() { + const navigationData = await getNavigationData(); + + const html = ` + + + + + + Dispark|点滴星火 + + + + + +
+ +
+ +
+
+ + Logo +

Dispark

+
+
+
+ 正在加载时间... +
+
+ + +
+ + + +
+
+ + +
+ +
点滴星火导航站
+
探索 · 连接 · 发现
+
+ + +
+ + + + + + + +
+
+
+ +
+ ${renderCategories(navigationData.categories)} + +
+ +
+
+
+
+ + +
+
+
+ + + + + + + + + + + + + + + + `; + + return html; + } + + /// 修复renderCategories函数 - 关键修改 +function renderCategories(categories) { + return categories.map((category, categoryIndex) => ` +
+

+ + + + ${category.name} + + + + + + + + + +

+ + +
+ `).join(''); +} + + // 辅助函数:转义特殊字符 + function escapeString(str) { + return str ? str + .replace(/\\/g, '\\\\') + .replace(/'/g, "\\'") + .replace(/"/g, '\\"') + .replace(/\n/g, '\\n') + .replace(/\r/g, '\\r') : ''; + }