feat(project): 내업무 트리·벨 애니메이션·타임라인 그룹·리스트 정렬/리사이즈·검정 탭
- 홈 '내 업무': 프로젝트별 그룹 트리, 업무 아래 날짜 기간 작은 글씨 - 알림 벨: 미읽음 있으면 종 흔들림 애니메이션 + 숫자 배지(기존) - 타임라인: 프로젝트 전체 기간을 연한 색 배경으로 칠하고(그룹 행) 그 안에 업무 막대 표시 → 업무명에 프로젝트명 불필요 - 리스트: 컬럼 헤더 클릭 정렬(오름/내림 아이콘), 컬럼 너비 드래그 조절+ localStorage 저장, 헤더 글씨 크고 굵게 - 상단 뷰 탭 선택 시 검은 배경 흰 글씨 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -321,6 +321,21 @@ async def index(request: Request) -> HTMLResponse:
|
||||
)
|
||||
tree = _build_tree(projects)
|
||||
my_tasks = st.list_tasks(assignee_email=user["email"], limit=500)
|
||||
# 내 업무를 프로젝트별로 묶어 트리로 표시
|
||||
my_groups: dict[int, dict[str, Any]] = {}
|
||||
for t in my_tasks:
|
||||
pid = t.get("project_id")
|
||||
g = my_groups.get(pid)
|
||||
if g is None:
|
||||
g = {
|
||||
"id": pid,
|
||||
"name": t.get("project_name") or "프로젝트",
|
||||
"color": t.get("project_color") or "#4573d2",
|
||||
"tasks": [],
|
||||
}
|
||||
my_groups[pid] = g
|
||||
g["tasks"].append(t)
|
||||
my_projects = list(my_groups.values())
|
||||
return render_template(
|
||||
request,
|
||||
"project/index.html",
|
||||
@@ -331,7 +346,7 @@ async def index(request: Request) -> HTMLResponse:
|
||||
"page_title": "프로젝트 관리",
|
||||
"page_subtitle": "달력·타임라인·보드로 프로젝트를 관리하세요.",
|
||||
"tree": tree,
|
||||
"my_tasks": my_tasks,
|
||||
"my_projects": my_projects,
|
||||
"today": today_kst().isoformat(),
|
||||
},
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends "erp_base.html" %}
|
||||
|
||||
{% block head_extra %}
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260625o" />
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260625p" />
|
||||
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
|
||||
{% endblock %}
|
||||
|
||||
@@ -45,5 +45,5 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<script src="/static/project.js?v=20260625o" defer></script>
|
||||
<script src="/static/project.js?v=20260625p" defer></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends "erp_base.html" %}
|
||||
|
||||
{% block head_extra %}
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260625o" />
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260625p" />
|
||||
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
|
||||
{% endblock %}
|
||||
|
||||
@@ -54,22 +54,38 @@
|
||||
<!-- 내 업무 -->
|
||||
<aside class="pj-home-side">
|
||||
<div class="pj-section-head"><h2>내 업무</h2></div>
|
||||
{% if not my_tasks %}
|
||||
{% if not my_projects %}
|
||||
<div class="pj-empty pj-empty-sm">배정된 업무가 없습니다.</div>
|
||||
{% else %}
|
||||
<ul class="pj-mytask-list">
|
||||
{% for t in my_tasks %}
|
||||
<li class="pj-mytask {% if t.completed_at %}is-done{% endif %}">
|
||||
<a href="/project/p/{{ t.project_id }}">
|
||||
<span class="pj-mytask-dot" style="background: {{ t.project_color }}"></span>
|
||||
<span class="pj-mytask-title">{{ t.title }}</span>
|
||||
<span class="pj-mytask-meta">
|
||||
{{ t.project_name }}{% if t.due_date %} · {{ t.due_date }}{% endif %}
|
||||
</span>
|
||||
<div class="pj-mytree">
|
||||
{% for p in my_projects %}
|
||||
<div class="pj-mytree-group">
|
||||
<a class="pj-mytree-proj" href="/project/p/{{ p.id }}">
|
||||
<span class="material-symbols-outlined" style="color: {{ p.color }}; font-size:18px;">folder</span>
|
||||
<span class="pj-mytree-proj-name">{{ p.name }}</span>
|
||||
</a>
|
||||
</li>
|
||||
<ul class="pj-mytree-tasks">
|
||||
{% for t in p.tasks %}
|
||||
<li class="pj-mytree-task {% if t.completed_at %}is-done{% endif %}">
|
||||
<a href="/project/p/{{ t.project_id }}?task={{ t.id }}">
|
||||
<span class="material-symbols-outlined pj-mytree-ic" style="color: {{ t.project_color }};">{% if t.completed_at %}task_alt{% else %}radio_button_unchecked{% endif %}</span>
|
||||
<span class="pj-mytree-body">
|
||||
<span class="pj-mytree-title">{{ t.title }}</span>
|
||||
{% if t.start_date or t.due_date %}
|
||||
<span class="pj-mytree-dates">
|
||||
{% if t.start_date and t.due_date %}{{ t.start_date }} ~ {{ t.due_date }}
|
||||
{% elif t.due_date %}~ {{ t.due_date }}
|
||||
{% else %}{{ t.start_date }} ~{% endif %}
|
||||
</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
</aside>
|
||||
</div>
|
||||
@@ -100,5 +116,5 @@
|
||||
<script>
|
||||
window.PJ_COLORS = {{ ["#4573d2","#37a3a3","#62a420","#e8a33d","#e8384f","#aa62e3","#f06a6a","#5a6772"] | tojson }};
|
||||
</script>
|
||||
<script src="/static/project.js?v=20260625o" defer></script>
|
||||
<script src="/static/project.js?v=20260625p" defer></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends "erp_base.html" %}
|
||||
|
||||
{% block head_extra %}
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260625o" />
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260625p" />
|
||||
<!-- 구글 머티리얼 심볼(담당자 아이콘 등) — self-host -->
|
||||
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
|
||||
<!-- 타임라인 vis-timeline — self-host -->
|
||||
@@ -297,5 +297,5 @@
|
||||
</script>
|
||||
|
||||
<script src="/static/vendor/vis-timeline/vis-timeline-graph2d.min.js"></script>
|
||||
<script src="/static/project.js?v=20260625o" defer></script>
|
||||
<script src="/static/project.js?v=20260625p" defer></script>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user