@@ -1611,12 +1627,10 @@
const activeProjs = projs.filter(p => activeStatus[p.id] !== false);
const archivedProjs = projs.filter(p => activeStatus[p.id] === false);
- if (activeProjs.length > 0 || getTextBlocks().length > 0) {
- const textBlocks = getTextBlocks();
+ if (activeProjs.length > 0) {
const secId = 'section-web-active';
- html += `
`;
+ html += `
`;
activeProjs.forEach(p => { html += renderProjectCard(p, true); });
- textBlocks.forEach(b => { html += renderTextBlock(b); });
html += '
';
}
@@ -1633,18 +1647,6 @@
html += '
';
}
}
-
- // 如果没有Web服务项目但有文本块,单独渲染文本块区域
- if (!grouped['web'] && (currentFilter === 'all' || currentFilter === 'web')) {
- const textBlocks = getTextBlocks();
- if (textBlocks.length > 0) {
- const secId = 'section-web-active';
- html += `
`;
- textBlocks.forEach(b => { html += renderTextBlock(b); });
- html += '
';
- }
- }
-
list.innerHTML = html;
// 应用已保存的折叠状态
setTimeout(() => {
@@ -1872,124 +1874,66 @@
localStorage.setItem('customServices', JSON.stringify(services));
}
- // ==================== 文本块管理 ====================
+ // ==================== 新增Web服务管理 ====================
- function getTextBlocks() {
- const stored = localStorage.getItem('textBlocks');
- return stored ? JSON.parse(stored) : [];
+ function showAddWebModal() {
+ document.getElementById('addWebForm').reset();
+ document.getElementById('addWebModal').classList.remove('hidden');
}
- function saveTextBlocks(blocks) {
- localStorage.setItem('textBlocks', JSON.stringify(blocks));
+ function closeAddWebModal() {
+ document.getElementById('addWebModal').classList.add('hidden');
}
- function showTextBlockModal(blockId = null) {
- const modal = document.getElementById('textBlockModal');
- const title = document.getElementById('textBlockModalTitle');
- const form = document.getElementById('textBlockForm');
-
- if (blockId) {
- // 编辑模式
- const blocks = getTextBlocks();
- const block = blocks.find(b => b.id === blockId);
- if (!block) return;
-
- title.textContent = '编辑文本块';
- document.getElementById('textBlockId').value = block.id;
- document.getElementById('textBlockTitle').value = block.title;
- document.getElementById('textBlockContent').value = block.content;
- document.getElementById('textBlockColor').value = block.color || 'blue';
- } else {
- // 新增模式
- title.textContent = '新增文本块';
- form.reset();
- document.getElementById('textBlockId').value = '';
- }
-
- modal.classList.remove('hidden');
- }
-
- function closeTextBlockModal() {
- document.getElementById('textBlockModal').classList.add('hidden');
- }
-
- function saveTextBlock(event) {
+ function saveWebProject(event) {
event.preventDefault();
- const id = document.getElementById('textBlockId').value;
- const title = document.getElementById('textBlockTitle').value.trim();
- const content = document.getElementById('textBlockContent').value.trim();
- const color = document.getElementById('textBlockColor').value;
+ const id = document.getElementById('webProjectId').value.trim();
+ const name = document.getElementById('webProjectName').value.trim();
+ const portsStr = document.getElementById('webProjectPorts').value.trim();
+ const directory = document.getElementById('webProjectDir').value.trim();
+ const startCmd = document.getElementById('webProjectStartCmd').value.trim();
+ const stopCmd = document.getElementById('webProjectStopCmd').value.trim();
+ const adminUrl = document.getElementById('webProjectAdminUrl').value.trim();
+ const description = document.getElementById('webProjectDesc').value.trim();
- if (!title || !content) {
- alert('请填写标题和内容');
+ // 解析端口
+ const ports = portsStr.split(',').map(p => parseInt(p.trim())).filter(p => !isNaN(p));
+ if (ports.length === 0) {
+ alert('请输入有效的端口号');
return;
}
- const blocks = getTextBlocks();
-
- if (id) {
- // 更新现有文本块
- const index = blocks.findIndex(b => b.id === id);
- if (index !== -1) {
- blocks[index] = { ...blocks[index], title, content, color, updatedAt: new Date().toISOString() };
- }
- } else {
- // 创建新文本块
- const newBlock = {
- id: 'tb_' + Date.now(),
- title,
- content,
- color,
- createdAt: new Date().toISOString(),
- updatedAt: new Date().toISOString()
- };
- blocks.push(newBlock);
- }
-
- saveTextBlocks(blocks);
- closeTextBlockModal();
- renderProjects();
- }
-
- function deleteTextBlock(blockId) {
- if (!confirm('确定删除此文本块?')) return;
-
- const blocks = getTextBlocks();
- const filtered = blocks.filter(b => b.id !== blockId);
- saveTextBlocks(filtered);
- renderProjects();
- }
-
- function renderTextBlock(block) {
- const colorMap = {
- blue: { border: 'border-blue-500/30', bg: 'bg-blue-500/10', text: 'text-blue-400', icon: 'ri-information-line' },
- green: { border: 'border-green-500/30', bg: 'bg-green-500/10', text: 'text-green-400', icon: 'ri-check-line' },
- yellow: { border: 'border-yellow-500/30', bg: 'bg-yellow-500/10', text: 'text-yellow-400', icon: 'ri-alert-line' },
- red: { border: 'border-red-500/30', bg: 'bg-red-500/10', text: 'text-red-400', icon: 'ri-error-warning-line' },
- purple: { border: 'border-purple-500/30', bg: 'bg-purple-500/10', text: 'text-purple-400', icon: 'ri-lightbulb-line' },
- gray: { border: 'border-gray-500/30', bg: 'bg-gray-500/10', text: 'text-gray-400', icon: 'ri-file-text-line' }
+ const data = {
+ id: id,
+ name: name,
+ type: 'web',
+ ports: ports,
+ directory: directory,
+ start_cmd: startCmd || 'python3 app.py',
+ stop_cmd: stopCmd,
+ admin_url: adminUrl,
+ description: description
};
- const c = colorMap[block.color] || colorMap.blue;
- const contentLines = block.content.split('\n').filter(l => l.trim()).slice(0, 5).join('
');
- const hasMore = block.content.split('\n').filter(l => l.trim()).length > 5;
-
- return `
-
-
-
-
-
${block.title}
-
-
-
-
-
-
-
${contentLines}${hasMore ? '...' : ''}
-
- `;
+ fetch('/api/projects/add', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(data)
+ })
+ .then(res => res.json())
+ .then(result => {
+ if (result.error) {
+ alert('错误: ' + result.error);
+ return;
+ }
+ closeAddWebModal();
+ loadProjects();
+ alert('Web服务添加成功!');
+ })
+ .catch(err => {
+ alert('添加失败: ' + err.message);
+ });
}
// ==================== 邮件通知规则管理 ====================