feat(project): 서브프로젝트 제거, 사이드 트리를 프로젝트→업무 2단계로
요구에 따라 서브프로젝트 개념을 UI 에서 제거. 좌측 트리를 프로젝트(최상위)
→ 그 안의 업무 2단계로 재구성:
- 프로젝트 노드(folder) 펼치면 소속 업무가 체크 아이콘으로 표시
- 업무 클릭 → /project/p/{id}?task={tid} 로 이동 후 해당 업무 모달 자동 오픈
- 완료 업무는 취소선. 트리에서 프로젝트 삭제(관리자)
- 과거 parent_id 서브프로젝트는 트리/홈에서 숨김(최상위만 노출)
- 홈 카드의 '서브 N' 칩 제거
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -85,6 +85,8 @@
|
||||
.pj-tree-acts { display: none; gap: 0; flex: 0 0 auto; }
|
||||
.pj-tree-row:hover .pj-tree-acts { display: inline-flex; }
|
||||
.pj-tree-acts .pj-icon-btn { width: 22px; height: 22px; font-size: 14px; }
|
||||
.pj-tree-done { text-decoration: line-through; color: #9aa1a9; }
|
||||
.pj-tree-task .pj-tree-name { font-size: 13px; color: #444; }
|
||||
|
||||
/* 구글 머티리얼 심볼 아이콘(담당자) */
|
||||
.material-symbols-outlined { font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24; line-height: 1; vertical-align: middle; }
|
||||
|
||||
+9
-14
@@ -637,23 +637,11 @@
|
||||
}
|
||||
})();
|
||||
|
||||
// 서브프로젝트 추가 (트리 각 노드)
|
||||
document.querySelectorAll(".pj-tree-addsub").forEach(function (b) {
|
||||
b.addEventListener("click", async function (e) {
|
||||
e.preventDefault(); e.stopPropagation();
|
||||
const name = prompt("서브프로젝트 이름");
|
||||
if (!name || !name.trim()) return;
|
||||
try {
|
||||
await api("POST", "/project/api/projects/" + b.dataset.id + "/subprojects", { name: name.trim() });
|
||||
location.reload();
|
||||
} catch (err) { alert("생성 실패: " + err.message); }
|
||||
});
|
||||
});
|
||||
// 프로젝트/서브 삭제 (트리)
|
||||
// 프로젝트 삭제 (트리)
|
||||
document.querySelectorAll(".pj-tree-del").forEach(function (b) {
|
||||
b.addEventListener("click", async function (e) {
|
||||
e.preventDefault(); e.stopPropagation();
|
||||
if (!confirm("'" + (b.dataset.name || "") + "' 삭제할까요? 하위 서브프로젝트·업무도 모두 삭제됩니다.")) return;
|
||||
if (!confirm("'" + (b.dataset.name || "") + "' 프로젝트를 삭제할까요? 안의 업무도 모두 삭제됩니다.")) return;
|
||||
try {
|
||||
await api("DELETE", "/project/api/projects/" + b.dataset.id);
|
||||
if (String(b.dataset.id) === String(projectId)) location.href = "/project/";
|
||||
@@ -720,6 +708,13 @@
|
||||
|
||||
// 최초 렌더 — 달력은 서버 렌더, 클릭 핸들러만 연결
|
||||
wireCalendar();
|
||||
|
||||
// 사이드 트리에서 업무 클릭(?task=ID)으로 들어오면 해당 업무 모달 자동 열기
|
||||
const taskParam = new URLSearchParams(location.search).get("task");
|
||||
if (taskParam) {
|
||||
const t = tasks.find(function (x) { return String(x.id) === String(taskParam); });
|
||||
if (t) openTaskModal(t);
|
||||
}
|
||||
}
|
||||
|
||||
function idOf(email) {
|
||||
|
||||
Reference in New Issue
Block a user