From e02c0bd183d716351b56c439a4d8c8b9c542e6e6 Mon Sep 17 00:00:00 2001 From: mac Date: Tue, 16 Jun 2026 10:32:34 +0800 Subject: [PATCH] =?UTF-8?q?v1.4.0=20=E2=80=94=20=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E9=9D=A2=E6=9D=BF=E7=BB=9F=E4=B8=80=E4=BA=AE=E8=89=B2=20+=20?= =?UTF-8?q?=E7=82=B9=E5=87=BB=E4=BB=BB=E5=8A=A1=E5=8F=AF=E7=BC=96=E8=BE=91?= =?UTF-8?q?=20+=20=E4=BB=BB=E5=8A=A1=E8=AF=B4=E6=98=8E=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E6=8D=A2=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/app.js | 60 +++++++++++++++++++++++++++++++++++++---------- static/styles.css | 53 +++++++++++++++++++++-------------------- 2 files changed, 74 insertions(+), 39 deletions(-) diff --git a/static/app.js b/static/app.js index fbca030..e101b51 100644 --- a/static/app.js +++ b/static/app.js @@ -171,21 +171,54 @@ window.createProposal = (event) => createResource(event, "proposals"); window.createOperation = (event) => createResource(event, "operations"); window.createProduct = (event) => createResource(event, "products"); -async function createTask(event, projectId) { +window.openTaskForm = (projectId, taskId) => { + const form = document.querySelector(`#task-form-${projectId}`); + form.classList.remove("hidden"); + if (taskId === null) { + // new task + document.querySelector(`#task-id-${projectId}`).value = ""; + document.querySelector(`#task-name-${projectId}`).value = ""; + document.querySelector(`#task-phase-${projectId}`).value = "项目准备"; + document.querySelector(`#task-owner-${projectId}`).value = ""; + document.querySelector(`#task-due-${projectId}`).value = ""; + document.querySelector(`#task-notes-${projectId}`).value = ""; + document.querySelector(`#task-submit-btn-${projectId}`).textContent = "确认新增"; + } else { + // edit task + const task = (state.data.tasks || []).find((t) => t.id === taskId); + if (!task) return; + document.querySelector(`#task-id-${projectId}`).value = task.id; + document.querySelector(`#task-name-${projectId}`).value = task.task || ""; + document.querySelector(`#task-phase-${projectId}`).value = task.phase || "项目准备"; + document.querySelector(`#task-owner-${projectId}`).value = task.owner || ""; + document.querySelector(`#task-due-${projectId}`).value = task.due_date || ""; + document.querySelector(`#task-notes-${projectId}`).value = task.notes || ""; + document.querySelector(`#task-submit-btn-${projectId}`).textContent = "保存修改"; + } + form.scrollIntoView({ behavior: "smooth" }); +}; + +window.submitTaskForm = async (event, projectId) => { event.preventDefault(); const form = event.currentTarget; const data = Object.fromEntries(new FormData(form).entries()); data.project_id = projectId; + const taskId = data.task_id; + delete data.task_id; try { - await api("/api/tasks", { method: "POST", body: JSON.stringify({ data }) }); + if (taskId) { + await api(`/api/tasks/${taskId}`, { method: "PUT", body: JSON.stringify({ data }) }); + } else { + await api("/api/tasks", { method: "POST", body: JSON.stringify({ data }) }); + } form.reset(); form.classList.add("hidden"); await load(); showTaskModal(projectId); } catch (error) { - alert("创建失败:" + error.message); + alert("保存失败:" + error.message); } -} +}; window.createFinance = (event) => createResource(event, "finance"); window.switchTab = switchTab; @@ -224,24 +257,25 @@ function showTaskModal(projectId) { const project = state.data.operations.find((x) => x.id === projectId); const tasks = (state.data.tasks || []).filter((t) => t.project_id === projectId); const phases = ["项目准备", "项目执行", "项目验收", "验收完毕"]; - document.querySelector("#taskModal").innerHTML = `

${project.project_name} · 任务清单

- `; document.querySelector("#taskModal").classList.add("active"); if (window.lucide) window.lucide.createIcons(); diff --git a/static/styles.css b/static/styles.css index 6c30cf9..9f9e174 100644 --- a/static/styles.css +++ b/static/styles.css @@ -494,63 +494,64 @@ td { .task-modal { display: none; } .task-modal.active { display: block; } .task-overlay { - position: fixed; inset: 0; background: rgba(10,12,16,0.5); z-index: 200; + position: fixed; inset: 0; background: rgba(15,23,42,0.35); z-index: 200; display: flex; align-items: flex-start; justify-content: center; padding-top: 48px; overflow-y: auto; } .task-panel { - background: #18191c; border-radius: 12px; width: 1000px; max-width: 96vw; - box-shadow: 0 24px 80px rgba(0,0,0,0.4); margin-bottom: 48px; + background: #fff; border-radius: 12px; width: 1000px; max-width: 96vw; + box-shadow: 0 20px 60px rgba(0,0,0,0.12); margin-bottom: 48px; } .task-header { display: flex; align-items: center; justify-content: space-between; - padding: 16px 20px; border-bottom: 1px solid #2a2d34; + padding: 16px 20px; border-bottom: 1px solid #e2e8f0; } -.task-title { color: #e4e5e7; font-size: 15px; font-weight: 600; } +.task-title { color: #1e293b; font-size: 15px; font-weight: 600; } .task-close { - color: #6b6d75; background: none; border: none; cursor: pointer; + color: #94a3b8; background: none; border: none; cursor: pointer; padding: 4px; border-radius: 6px; display: flex; } -.task-close:hover { color: #e4e5e7; background: #2a2d34; } +.task-close:hover { color: #475569; background: #f1f5f9; } .task-body { padding: 20px; display: flex; flex-direction: column; gap: 16px; } .task-group { - background: #1e2025; border-radius: 8px; - border: 1px solid #2a2d34; overflow: hidden; + background: #fff; border-radius: 8px; + border: 1px solid #e2e8f0; overflow: hidden; } .task-group-hd { display: flex; align-items: center; gap: 8px; - padding: 10px 14px; + padding: 10px 16px; background: #f8fafc; } -.task-group-icon { color: #6b6d75; display: flex; } -.task-group-label { color: #aeafb4; font-size: 13px; font-weight: 600; } +.task-group-icon { color: #64748b; display: flex; } +.task-group-label { color: #334155; font-size: 13px; font-weight: 600; } .task-group-n { - background: #2a2d34; color: #6b6d75; font-size: 11px; + background: #e2e8f0; color: #64748b; font-size: 11px; padding: 1px 7px; border-radius: 10px; } .task-group-list { display: flex; flex-direction: column; } .task-row { display: flex; align-items: center; gap: 16px; - padding: 10px 16px; border-top: 1px solid #24272d; + padding: 10px 16px; border-top: 1px solid #f1f5f9; + cursor: pointer; } -.task-row:hover { background: #1a1c21; } -.task-dot { display: flex; color: #4b4d54; flex-shrink: 0; } +.task-row:hover { background: #f8fafc; } +.task-dot { display: flex; color: #cbd5e1; flex-shrink: 0; } .task-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; } -.task-name { color: #c5c6ca; font-size: 13px; } -.task-desc { color: #5a5c63; font-size: 12px; } -.task-col { color: #898b94; font-size: 12px; white-space: nowrap; width: 100px; text-align: right; } -.task-col-badge { color: #898b94; font-size: 12px; white-space: nowrap; width: 80px; text-align: right; } -.task-none { color: #4b4d54; font-size: 13px; padding: 12px 14px; text-align: center; border-top: 1px solid #24272d; } +.task-name { color: #1e293b; font-size: 13px; } +.task-desc { color: #94a3b8; font-size: 12px; word-wrap: break-word; overflow-wrap: break-word; } +.task-col { color: #64748b; font-size: 12px; white-space: nowrap; width: 100px; text-align: right; } +.task-col-badge { color: #64748b; font-size: 12px; white-space: nowrap; width: 90px; text-align: right; } +.task-none { color: #94a3b8; font-size: 13px; padding: 12px 14px; text-align: center; border-top: 1px solid #f1f5f9; } .task-form { - background: #141518; border: 1px solid #2a2d34; border-radius: 8px; + background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px; padding: 14px; margin-bottom: 16px; } .task-field { display: flex; flex-direction: column; gap: 4px; } -.task-field span { color: #6b6d75; font-size: 12px; } +.task-field span { color: #64748b; font-size: 12px; } .task-field input, .task-field select, .task-field textarea { - background: #1e2025; border: 1px solid #2a2d34; border-radius: 6px; - color: #e4e5e7; font-size: 13px; padding: 6px 10px; outline: none; + background: #fff; border: 1px solid #e2e8f0; border-radius: 6px; + color: #1e293b; font-size: 13px; padding: 6px 10px; outline: none; } -.task-field input:focus, .task-field select:focus, .task-field textarea:focus { border-color: #4a6cf7; } +.task-field input:focus, .task-field select:focus, .task-field textarea:focus { border-color: #2563eb; } .col-span-2 { grid-column: span 2; } .task-group-add { display: block; width: 100%; padding: 10px; text-align: center;