From 1df0f2e4e236365d0f809452ec94ec55e8799096 Mon Sep 17 00:00:00 2001 From: ttipo Date: Mon, 22 Jun 2026 16:50:21 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=97=85=EB=AC=B4=20=EC=88=98=EC=A0=95?= =?UTF-8?q?/=ED=8E=B8=EC=A7=91=EC=9D=84=20=EC=A7=80=EC=8B=9C=EC=9E=90=20?= =?UTF-8?q?=EC=A0=84=EC=9A=A9=EC=9C=BC=EB=A1=9C=20+=20=EB=8D=94=EB=B3=B4?= =?UTF-8?q?=EA=B8=B0=20=EB=A9=94=EB=89=B4=EB=A5=BC=20=EC=82=AD=EC=A0=9C?= =?UTF-8?q?=EB=A7=8C=20=EB=82=A8=EA=B9=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 상세 우측 상단 액션(수정 버튼 + 더보기 메뉴) 전체를 isIssuer 일 때만 노출 - 더보기 메뉴에서 업무 복제·링크 복사 제거, 업무 삭제만 유지 - 편집 화면(/edit) 진입을 지시자 본인만 허용(그 외 상세로 리다이렉트). 생성 모드는 기존대로 관리자만 Co-Authored-By: Claude Opus 4.8 (1M context) --- frontend/src/pages/relay/TaskCreatePage.vue | 11 ++++-- frontend/src/pages/relay/TaskDetailPage.vue | 40 +++------------------ 2 files changed, 12 insertions(+), 39 deletions(-) diff --git a/frontend/src/pages/relay/TaskCreatePage.vue b/frontend/src/pages/relay/TaskCreatePage.vue index af20acf..b3bc399 100644 --- a/frontend/src/pages/relay/TaskCreatePage.vue +++ b/frontend/src/pages/relay/TaskCreatePage.vue @@ -64,9 +64,8 @@ const repo = ref(null) async function loadProject() { try { repo.value = await projectStore.fetchOne(projectId.value) - // 업무 작성/수정은 프로젝트 관리자만 가능 — 일반 멤버는 진입 즉시 상세로 돌려보낸다 - // (백엔드도 admin 전용이지만, 폼 화면 자체를 열지 못하게 막는다) - if (repo.value && !repo.value.canManage) { + // 생성 모드: 프로젝트 관리자만 진입 가능. (편집 모드 권한은 지시자 기준으로 loadTaskForEdit 에서 검사) + if (!isEdit.value && repo.value && !repo.value.canManage) { void dialog.alert('업무 작성은 프로젝트 관리자만 가능합니다.', { variant: 'warning' }) await router.replace(`/projects/${projectId.value}`) } @@ -87,6 +86,12 @@ async function loadTaskForEdit() { if (taskId.value === null) return try { const t = await taskApi.get(projectId.value, taskId.value) + // 편집은 지시자 본인만 — 그 외에는 상세로 돌려보낸다 + if (t.issuer?.id !== authStore.user?.id) { + void dialog.alert('업무 수정은 지시자만 가능합니다.', { variant: 'warning' }) + await router.replace(`/projects/${projectId.value}/tasks/${taskId.value}`) + return + } title.value = t.title contentText.value = t.content.join('\n') dueDate.value = t.dueDate ? toDateInput(t.dueDate) : '' diff --git a/frontend/src/pages/relay/TaskDetailPage.vue b/frontend/src/pages/relay/TaskDetailPage.vue index 3d965ce..59076c9 100644 --- a/frontend/src/pages/relay/TaskDetailPage.vue +++ b/frontend/src/pages/relay/TaskDetailPage.vue @@ -533,7 +533,10 @@ function badgeFor(name: string | undefined): { label: string; cls: string } { {{ task.title }} -
+
- - -