feat(project): 프로젝트 멤버 아이콘으로 업무 팝업, 편집후 목록유지, 사이드바 스타일

- 좌측 "프로젝트 멤버" 아이콘 클릭 시 이 프로젝트 안에서 그 사람이 담당하는
  업무 팝업(전체 멤버 팝업과 같은 UI/정렬/더블클릭 편집). 제목은
  "[프로젝트 이름]의 [사용자]님의 업무" + 아이콘. GET /api/users/tasks 에
  project_id 옵션 추가(멀티호밍 포함 단일 프로젝트 조회 재사용)
- 멤버 업무 팝업에서 더블클릭으로 업무 편집 후 닫으면, 그 자리에 같은
  목록을 다시 열어 유지(MutationObserver로 taskModal 닫힘 감지 후 재오픈)
- 멤버 업무 팝업 제목에 아바타 아이콘 추가, "닫기" 버튼 accent 색 적용
- 좌측 "프로젝트"/"프로젝트 멤버" 헤더 더 굵게, 프로젝트 멤버 아이콘 2배 확대

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-17 13:48:05 +09:00
parent b21e42e949
commit bb6a2c12a3
6 changed files with 77 additions and 17 deletions
+12 -4
View File
@@ -805,12 +805,20 @@ async def api_all_users(request: Request) -> JSONResponse:
@router.get("/api/users/tasks")
async def api_user_tasks(request: Request, email: str) -> JSONResponse:
"""'전체 멤버' 아이콘 클릭 팝업 — 지정한 사용자가 담당자인 업무 목록
(프로젝트/세션/마감일). /api/my-tasks 와 같은 조회를 이메일만 바꿔 재사용."""
async def api_user_tasks(
request: Request, email: str, project_id: int | None = None
) -> JSONResponse:
"""'전체 멤버'/사이드바 '프로젝트 멤버' 아이콘 클릭 팝업 — 지정한 사용자가
담당자인 업무 목록(프로젝트/세션/마감일). project_id 를 주면 그 프로젝트
안에서 담당하는 업무만(멀티호밍으로 연결된 업무 포함, list_tasks 의
project_id 단일 조회 경로 재사용). 안 주면 전체 프로젝트 대상."""
_require_user(request)
st = _db_or_503(request)
return JSONResponse({"tasks": st.list_tasks(assignee_email=email, limit=500)})
if project_id is not None:
tasks = st.list_tasks(project_id=project_id, assignee_email=email, limit=500)
else:
tasks = st.list_tasks(assignee_email=email, limit=500)
return JSONResponse({"tasks": tasks})
@router.get("/api/projects/{project_id}/members")
@@ -1,7 +1,7 @@
{% extends "erp_base.html" %}
{% block head_extra %}
<link rel="stylesheet" href="/static/project.css?v=20260917o" />
<link rel="stylesheet" href="/static/project.css?v=20260917p" />
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
{% endblock %}
@@ -45,5 +45,5 @@
{% endif %}
</div>
<script src="/static/project.js?v=20260917s" defer></script>
<script src="/static/project.js?v=20260917t" defer></script>
{% endblock %}
@@ -1,7 +1,7 @@
{% extends "erp_base.html" %}
{% block head_extra %}
<link rel="stylesheet" href="/static/project.css?v=20260917o" />
<link rel="stylesheet" href="/static/project.css?v=20260917p" />
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
{% endblock %}
@@ -398,5 +398,5 @@
<script>
window.PJ_COLORS = {{ ["#4573d2","#37a3a3","#62a420","#e8a33d","#e8384f","#aa62e3","#f06a6a","#5a6772"] | tojson }};
</script>
<script src="/static/project.js?v=20260917s" defer></script>
<script src="/static/project.js?v=20260917t" defer></script>
{% endblock %}
@@ -1,7 +1,7 @@
{% extends "erp_base.html" %}
{% block head_extra %}
<link rel="stylesheet" href="/static/project.css?v=20260917o" />
<link rel="stylesheet" href="/static/project.css?v=20260917p" />
<!-- 구글 머티리얼 심볼(담당자 아이콘 등) — self-host -->
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
<!-- 타임라인 vis-timeline — self-host -->
@@ -511,7 +511,7 @@
<ul class="pj-mt-list" id="pj-mt-list"></ul>
<div class="pj-modal-actions">
<span style="flex:1"></span>
<button type="button" class="pj-btn" data-close>닫기</button>
<button type="button" class="pj-btn pj-btn-primary" data-close>닫기</button>
</div>
</div>
</div>
@@ -538,5 +538,5 @@
</script>
<script src="/static/vendor/vis-timeline/vis-timeline-graph2d.min.js"></script>
<script src="/static/project.js?v=20260917s" defer></script>
<script src="/static/project.js?v=20260917t" defer></script>
{% endblock %}