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:
+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