fix(project): 완료 프로젝트 숨기기 버튼 동작 안 하던 CSS 특이도 문제 수정
- .pj-project-grid[hidden] 규칙 추가 — display:grid 규칙과 특이도가 같아 [hidden] 속성이 무시되던 버그 - 홈 카드 업무 미리보기에 단계(stage_name) 칩 표시 - 홈 화면 날짜 표기를 yy/mm/dd(요일) 형식으로 통일(프로젝트 마감·업무 마감·내 업무 기간) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -191,6 +191,20 @@ def _render_config_needed(request: Request, user: dict[str, Any]) -> HTMLRespons
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
_WEEKDAYS_KR = ["월", "화", "수", "목", "금", "토", "일"]
|
||||||
|
|
||||||
|
|
||||||
|
def _fmt_date_kr(d: str | None) -> str:
|
||||||
|
"""'YYYY-MM-DD' → 'yy/mm/dd(요일)'. 형식이 아니면 원본 그대로."""
|
||||||
|
if not d:
|
||||||
|
return ""
|
||||||
|
try:
|
||||||
|
dd = date.fromisoformat(d[:10])
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
return d
|
||||||
|
return dd.strftime("%y/%m/%d") + f"({_WEEKDAYS_KR[dd.weekday()]})"
|
||||||
|
|
||||||
|
|
||||||
def _build_tree(projects: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
def _build_tree(projects: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
||||||
"""평면 프로젝트 목록 → parent_id 기준 트리(children 키)."""
|
"""평면 프로젝트 목록 → parent_id 기준 트리(children 키)."""
|
||||||
by_id: dict[int, dict[str, Any]] = {}
|
by_id: dict[int, dict[str, Any]] = {}
|
||||||
@@ -367,13 +381,18 @@ async def index(request: Request) -> HTMLResponse:
|
|||||||
)
|
)
|
||||||
d = t.get("due_date")
|
d = t.get("due_date")
|
||||||
t["due_overdue"] = bool(d and d[:10] < today_iso and not t.get("completed_at"))
|
t["due_overdue"] = bool(d and d[:10] < today_iso and not t.get("completed_at"))
|
||||||
|
t["due_label"] = _fmt_date_kr(d)
|
||||||
p["task_total"] = total
|
p["task_total"] = total
|
||||||
p["task_done"] = len(done_tasks)
|
p["task_done"] = len(done_tasks)
|
||||||
p["task_percent"] = round(len(done_tasks) * 100 / total) if total else 0
|
p["task_percent"] = round(len(done_tasks) * 100 / total) if total else 0
|
||||||
p["task_preview"] = ordered_tasks[:8]
|
p["task_preview"] = ordered_tasks[:8]
|
||||||
p["task_more"] = max(0, len(ordered_tasks) - 8)
|
p["task_more"] = max(0, len(ordered_tasks) - 8)
|
||||||
|
p["due_label"] = _fmt_date_kr(p.get("due_date"))
|
||||||
|
|
||||||
my_tasks = st.list_tasks(assignee_email=user["email"], limit=500)
|
my_tasks = st.list_tasks(assignee_email=user["email"], limit=500)
|
||||||
|
for t in my_tasks:
|
||||||
|
t["start_label"] = _fmt_date_kr(t.get("start_date"))
|
||||||
|
t["due_label"] = _fmt_date_kr(t.get("due_date"))
|
||||||
# 내 업무를 프로젝트별로 묶어 트리로 표시
|
# 내 업무를 프로젝트별로 묶어 트리로 표시
|
||||||
my_groups: dict[int, dict[str, Any]] = {}
|
my_groups: dict[int, dict[str, Any]] = {}
|
||||||
for t in my_tasks:
|
for t in my_tasks:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{% extends "erp_base.html" %}
|
{% extends "erp_base.html" %}
|
||||||
|
|
||||||
{% block head_extra %}
|
{% block head_extra %}
|
||||||
<link rel="stylesheet" href="/static/project.css?v=20260915b" />
|
<link rel="stylesheet" href="/static/project.css?v=20260915c" />
|
||||||
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
|
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{% extends "erp_base.html" %}
|
{% extends "erp_base.html" %}
|
||||||
|
|
||||||
{% block head_extra %}
|
{% block head_extra %}
|
||||||
<link rel="stylesheet" href="/static/project.css?v=20260915b" />
|
<link rel="stylesheet" href="/static/project.css?v=20260915c" />
|
||||||
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
|
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% if p.description %}<div class="pj-project-desc">{{ p.description }}</div>{% endif %}
|
{% if p.description %}<div class="pj-project-desc">{{ p.description }}</div>{% endif %}
|
||||||
<div class="pj-project-meta">
|
<div class="pj-project-meta">
|
||||||
{% if p.due_date %}<span class="pj-chip">마감 {{ p.due_date }}</span>{% endif %}
|
{% if p.due_date %}<span class="pj-chip">마감 {{ p.due_label }}</span>{% endif %}
|
||||||
{% if p.task_total %}<span class="pj-chip">업무 {{ p.task_done }}/{{ p.task_total }}</span>{% endif %}
|
{% if p.task_total %}<span class="pj-chip">업무 {{ p.task_done }}/{{ p.task_total }}</span>{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% if p.task_total %}
|
{% if p.task_total %}
|
||||||
@@ -52,6 +52,7 @@
|
|||||||
<a href="/project/p/{{ p.id }}?task={{ t.id }}">
|
<a href="/project/p/{{ p.id }}?task={{ t.id }}">
|
||||||
<span class="material-symbols-outlined pj-project-task-ic">{% if t.completed_at %}task_alt{% else %}radio_button_unchecked{% endif %}</span>
|
<span class="material-symbols-outlined pj-project-task-ic">{% if t.completed_at %}task_alt{% else %}radio_button_unchecked{% endif %}</span>
|
||||||
<span class="pj-project-task-title">{{ t.title }}</span>
|
<span class="pj-project-task-title">{{ t.title }}</span>
|
||||||
|
{% if t.stage_name %}<span class="pj-project-task-stage">{{ t.stage_name }}</span>{% endif %}
|
||||||
{% if t.assignee_display %}
|
{% if t.assignee_display %}
|
||||||
<span class="pj-project-task-assignee">
|
<span class="pj-project-task-assignee">
|
||||||
{% if avatars.get(t.assignee_email | lower) %}
|
{% if avatars.get(t.assignee_email | lower) %}
|
||||||
@@ -61,7 +62,7 @@
|
|||||||
</span>
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if t.due_date %}
|
{% if t.due_date %}
|
||||||
<span class="pj-project-task-due {% if t.due_overdue %}is-overdue{% endif %}">{{ t.due_date[:10] }}</span>
|
<span class="pj-project-task-due {% if t.due_overdue %}is-overdue{% endif %}">{{ t.due_label }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -143,9 +144,9 @@
|
|||||||
<span class="pj-mytree-title">{{ t.title }}</span>
|
<span class="pj-mytree-title">{{ t.title }}</span>
|
||||||
{% if t.start_date or t.due_date %}
|
{% if t.start_date or t.due_date %}
|
||||||
<span class="pj-mytree-dates">
|
<span class="pj-mytree-dates">
|
||||||
{% if t.start_date and t.due_date %}{{ t.start_date }} ~ {{ t.due_date }}
|
{% if t.start_date and t.due_date %}{{ t.start_label }} ~ {{ t.due_label }}
|
||||||
{% elif t.due_date %}~ {{ t.due_date }}
|
{% elif t.due_date %}~ {{ t.due_label }}
|
||||||
{% else %}{{ t.start_date }} ~{% endif %}
|
{% else %}{{ t.start_label }} ~{% endif %}
|
||||||
</span>
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{% extends "erp_base.html" %}
|
{% extends "erp_base.html" %}
|
||||||
|
|
||||||
{% block head_extra %}
|
{% block head_extra %}
|
||||||
<link rel="stylesheet" href="/static/project.css?v=20260915b" />
|
<link rel="stylesheet" href="/static/project.css?v=20260915c" />
|
||||||
<!-- 구글 머티리얼 심볼(담당자 아이콘 등) — self-host -->
|
<!-- 구글 머티리얼 심볼(담당자 아이콘 등) — self-host -->
|
||||||
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
|
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
|
||||||
<!-- 타임라인 vis-timeline — self-host -->
|
<!-- 타임라인 vis-timeline — self-host -->
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
@media (max-width: 980px) { .pj-home { grid-template-columns: 1fr; } }
|
@media (max-width: 980px) { .pj-home { grid-template-columns: 1fr; } }
|
||||||
|
|
||||||
.pj-project-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 14px; align-items: start; }
|
.pj-project-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 14px; align-items: start; }
|
||||||
|
.pj-project-grid[hidden] { display: none; }
|
||||||
.pj-project-card {
|
.pj-project-card {
|
||||||
position: relative; border: 1px solid #e7e9ec; border-radius: 14px;
|
position: relative; border: 1px solid #e7e9ec; border-radius: 14px;
|
||||||
background: #fff; transition: box-shadow .14s, transform .1s;
|
background: #fff; transition: box-shadow .14s, transform .1s;
|
||||||
@@ -72,6 +73,11 @@
|
|||||||
font-size: 12.5px; font-weight: 600; flex: 1; min-width: 0;
|
font-size: 12.5px; font-weight: 600; flex: 1; min-width: 0;
|
||||||
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
.pj-project-task-stage {
|
||||||
|
flex: 0 0 auto; font-size: 10px; font-weight: 700; color: #6b7280;
|
||||||
|
background: #eef0f2; border-radius: 999px; padding: 1px 7px;
|
||||||
|
max-width: 70px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
||||||
|
}
|
||||||
.pj-project-task-assignee {
|
.pj-project-task-assignee {
|
||||||
display: inline-flex; align-items: center; gap: 4px; font-size: 11px; color: #6b7280;
|
display: inline-flex; align-items: center; gap: 4px; font-size: 11px; color: #6b7280;
|
||||||
flex: 0 0 auto; max-width: 90px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
flex: 0 0 auto; max-width: 90px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
||||||
|
|||||||
Reference in New Issue
Block a user