feat(project): 홈 화면 진행중/완료 프로젝트 구분, 완료 업무 취소선 유지
- 프로젝트 카드를 "진행중"/"완료" 두 섹션으로 분리(완료는 접기/펼치기) - 완료된 업무도 미리보기 목록에서 숨기지 않고 취소선으로 계속 표시 - 사이드바 빠른 프로젝트 생성(+)에도 마감일 입력 추가 (홈 새 프로젝트 모달은 기존에 지원) - 카드 편집/삭제 버튼이 완료 섹션 카드도 인식하도록 수정 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{% extends "erp_base.html" %}
|
||||
|
||||
{% block head_extra %}
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260625p" />
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260915b" />
|
||||
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
|
||||
{% endblock %}
|
||||
|
||||
@@ -45,5 +45,5 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<script src="/static/project.js?v=20260625p" defer></script>
|
||||
<script src="/static/project.js?v=20260915b" defer></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends "erp_base.html" %}
|
||||
|
||||
{% block head_extra %}
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260915a" />
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260915b" />
|
||||
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
|
||||
{% endblock %}
|
||||
|
||||
@@ -10,18 +10,78 @@
|
||||
data-is-super="{{ 'true' if user.is_super_admin else 'false' }}"
|
||||
data-me="{{ user.email }}">
|
||||
|
||||
{% macro project_card(p) %}
|
||||
<div class="pj-project-card {% if p.status == 'completed' %}is-done{% endif %}"
|
||||
style="--pj-color: {{ p.color }}"
|
||||
data-id="{{ p.id }}"
|
||||
data-name="{{ p.name }}"
|
||||
data-desc="{{ p.description or '' }}"
|
||||
data-start="{{ p.start_date or '' }}"
|
||||
data-due="{{ p.due_date or '' }}"
|
||||
data-color="{{ p.color }}"
|
||||
data-status="{{ p.status or 'active' }}"
|
||||
data-creator="{{ p.created_by or '' }}">
|
||||
<a class="pj-project-cardlink" href="/project/p/{{ p.id }}">
|
||||
<span class="pj-project-dot"></span>
|
||||
<div class="pj-project-body">
|
||||
<div class="pj-project-name">{{ p.name }}
|
||||
{% if p.status == 'completed' %}<span class="pj-chip pj-chip-sm">완료</span>{% endif %}
|
||||
</div>
|
||||
{% if p.description %}<div class="pj-project-desc">{{ p.description }}</div>{% endif %}
|
||||
<div class="pj-project-meta">
|
||||
{% if p.due_date %}<span class="pj-chip">마감 {{ p.due_date }}</span>{% endif %}
|
||||
{% if p.task_total %}<span class="pj-chip">업무 {{ p.task_done }}/{{ p.task_total }}</span>{% endif %}
|
||||
</div>
|
||||
{% if p.task_total %}
|
||||
<div class="pj-project-progress">
|
||||
<div class="pj-project-progress-bar" style="width: {{ p.task_percent }}%"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</a>
|
||||
{% if is_admin %}
|
||||
<button type="button" class="pj-icon-btn pj-card-edit" title="프로젝트 수정">
|
||||
<span class="material-symbols-outlined">edit</span>
|
||||
</button>
|
||||
{% endif %}
|
||||
|
||||
{% if p.task_preview %}
|
||||
<ul class="pj-project-tasklist">
|
||||
{% for t in p.task_preview %}
|
||||
<li class="pj-project-taskrow {% if t.completed_at %}is-done{% endif %}">
|
||||
<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="pj-project-task-title">{{ t.title }}</span>
|
||||
{% if t.assignee_display %}
|
||||
<span class="pj-project-task-assignee">
|
||||
{% if avatars.get(t.assignee_email | lower) %}
|
||||
<img class="pj-avatar pj-gicon-sm" src="{{ avatars[t.assignee_email | lower] }}" alt="" />
|
||||
{% endif %}
|
||||
{{ t.assignee_display }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if t.due_date %}
|
||||
<span class="pj-project-task-due {% if t.due_overdue %}is-overdue{% endif %}">{{ t.due_date[:10] }}</span>
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% if p.task_more %}
|
||||
<a class="pj-project-more" href="/project/p/{{ p.id }}">+{{ p.task_more }}개 업무 더보기</a>
|
||||
{% endif %}
|
||||
{% elif p.task_total == 0 %}
|
||||
<div class="pj-project-tasks-empty">진행 중인 업무가 없습니다.</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
<div class="pj-home">
|
||||
<!-- 프로젝트 목록 -->
|
||||
<section class="pj-home-main">
|
||||
<div class="pj-section-head">
|
||||
<h2>프로젝트</h2>
|
||||
<h2>진행중인 프로젝트</h2>
|
||||
<div class="pj-toolbar-right">
|
||||
{% set done_count = tree | selectattr('status', 'equalto', 'completed') | list | length %}
|
||||
{% if done_count %}
|
||||
<button type="button" class="pj-btn" id="pj-toggle-done" data-count="{{ done_count }}">
|
||||
완료 {{ done_count }}개 숨기기
|
||||
</button>
|
||||
{% endif %}
|
||||
<a class="pj-bell" href="/project/inbox" title="알림센터">
|
||||
<span class="material-symbols-outlined">notifications</span>
|
||||
<span class="pj-bell-badge" id="pj-bell-badge" hidden>0</span>
|
||||
@@ -34,81 +94,31 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if not tree %}
|
||||
{% if not active_projects and not done_projects %}
|
||||
<div class="pj-empty">
|
||||
아직 프로젝트가 없습니다.
|
||||
{% if is_admin %}상단의 <b>새 프로젝트</b> 버튼으로 만들어 보세요.
|
||||
{% else %}관리자가 프로젝트에 배정하면 여기에 표시됩니다.{% endif %}
|
||||
</div>
|
||||
{% elif not active_projects %}
|
||||
<div class="pj-empty pj-empty-sm">진행중인 프로젝트가 없습니다.</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="pj-project-grid" id="pj-project-grid">
|
||||
{% for p in tree %}
|
||||
<div class="pj-project-card {% if p.status == 'completed' %}is-done{% endif %}"
|
||||
style="--pj-color: {{ p.color }}"
|
||||
data-id="{{ p.id }}"
|
||||
data-name="{{ p.name }}"
|
||||
data-desc="{{ p.description or '' }}"
|
||||
data-start="{{ p.start_date or '' }}"
|
||||
data-due="{{ p.due_date or '' }}"
|
||||
data-color="{{ p.color }}"
|
||||
data-status="{{ p.status or 'active' }}"
|
||||
data-creator="{{ p.created_by or '' }}">
|
||||
<a class="pj-project-cardlink" href="/project/p/{{ p.id }}">
|
||||
<span class="pj-project-dot"></span>
|
||||
<div class="pj-project-body">
|
||||
<div class="pj-project-name">{{ p.name }}
|
||||
{% if p.status == 'completed' %}<span class="pj-chip pj-chip-sm">완료</span>{% endif %}
|
||||
</div>
|
||||
{% if p.description %}<div class="pj-project-desc">{{ p.description }}</div>{% endif %}
|
||||
<div class="pj-project-meta">
|
||||
{% if p.due_date %}<span class="pj-chip">마감 {{ p.due_date }}</span>{% endif %}
|
||||
{% if p.task_total %}<span class="pj-chip">업무 {{ p.task_done }}/{{ p.task_total }}</span>{% endif %}
|
||||
</div>
|
||||
{% if p.task_total %}
|
||||
<div class="pj-project-progress">
|
||||
<div class="pj-project-progress-bar" style="width: {{ p.task_percent }}%"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</a>
|
||||
{% if is_admin %}
|
||||
<button type="button" class="pj-icon-btn pj-card-edit" title="프로젝트 수정">
|
||||
<span class="material-symbols-outlined">edit</span>
|
||||
</button>
|
||||
{% endif %}
|
||||
|
||||
{% if p.task_preview %}
|
||||
<ul class="pj-project-tasklist">
|
||||
{% for t in p.task_preview %}
|
||||
<li class="pj-project-taskrow">
|
||||
<a href="/project/p/{{ p.id }}?task={{ t.id }}">
|
||||
<span class="material-symbols-outlined pj-project-task-ic">radio_button_unchecked</span>
|
||||
<span class="pj-project-task-title">{{ t.title }}</span>
|
||||
{% if t.assignee_display %}
|
||||
<span class="pj-project-task-assignee">
|
||||
{% if avatars.get(t.assignee_email | lower) %}
|
||||
<img class="pj-avatar pj-gicon-sm" src="{{ avatars[t.assignee_email | lower] }}" alt="" />
|
||||
{% endif %}
|
||||
{{ t.assignee_display }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if t.due_date %}
|
||||
<span class="pj-project-task-due {% if t.due_overdue %}is-overdue{% endif %}">{{ t.due_date[:10] }}</span>
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% if p.task_more %}
|
||||
<a class="pj-project-more" href="/project/p/{{ p.id }}">+{{ p.task_more }}개 업무 더보기</a>
|
||||
{% endif %}
|
||||
{% elif p.task_total == 0 %}
|
||||
<div class="pj-project-tasks-empty">진행 중인 업무가 없습니다.</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% for p in active_projects %}{{ project_card(p) }}{% endfor %}
|
||||
</div>
|
||||
|
||||
{% if done_projects %}
|
||||
<div class="pj-section-head pj-section-head-done">
|
||||
<h2>완료된 프로젝트</h2>
|
||||
<button type="button" class="pj-btn" id="pj-toggle-done" data-count="{{ done_projects | length }}">
|
||||
완료 {{ done_projects | length }}개 숨기기
|
||||
</button>
|
||||
</div>
|
||||
<div class="pj-project-grid" id="pj-project-grid-done">
|
||||
{% for p in done_projects %}{{ project_card(p) }}{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</section>
|
||||
|
||||
<!-- 내 업무 -->
|
||||
@@ -202,5 +212,5 @@
|
||||
<script>
|
||||
window.PJ_COLORS = {{ ["#4573d2","#37a3a3","#62a420","#e8a33d","#e8384f","#aa62e3","#f06a6a","#5a6772"] | tojson }};
|
||||
</script>
|
||||
<script src="/static/project.js?v=20260626b" defer></script>
|
||||
<script src="/static/project.js?v=20260915b" defer></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends "erp_base.html" %}
|
||||
|
||||
{% block head_extra %}
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260626b" />
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260915b" />
|
||||
<!-- 구글 머티리얼 심볼(담당자 아이콘 등) — self-host -->
|
||||
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
|
||||
<!-- 타임라인 vis-timeline — self-host -->
|
||||
@@ -291,5 +291,5 @@
|
||||
</script>
|
||||
|
||||
<script src="/static/vendor/vis-timeline/vis-timeline-graph2d.min.js"></script>
|
||||
<script src="/static/project.js?v=20260626b" defer></script>
|
||||
<script src="/static/project.js?v=20260915b" defer></script>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user