b74d2be6d3
- 사이드 프로젝트 트리를 tasks 로부터 JS 로 재렌더(renderTree) - refreshActiveView 에서 트리도 갱신 → 새로고침 없이 좌측에 바로 표시 - 새 업무 추가 시 해당 프로젝트 자동 펼침 - projectsMeta 에 created_by 추가(트리 삭제 권한용) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
172 lines
7.0 KiB
HTML
172 lines
7.0 KiB
HTML
{% extends "erp_base.html" %}
|
|
|
|
{% block head_extra %}
|
|
<link rel="stylesheet" href="/static/project.css?v=20260626b" />
|
|
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="pj-wrap" data-is-admin="{{ 'true' if is_admin else 'false' }}"
|
|
data-is-super="{{ 'true' if user.is_super_admin else 'false' }}"
|
|
data-me="{{ user.email }}">
|
|
|
|
<div class="pj-home">
|
|
<!-- 프로젝트 목록 -->
|
|
<section class="pj-home-main">
|
|
<div class="pj-section-head">
|
|
<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>
|
|
</a>
|
|
{% if is_admin %}
|
|
<button type="button" class="pj-btn pj-btn-primary" id="pj-new-project">
|
|
+ 새 프로젝트
|
|
</button>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
{% if not tree %}
|
|
<div class="pj-empty">
|
|
아직 프로젝트가 없습니다.
|
|
{% if is_admin %}상단의 <b>새 프로젝트</b> 버튼으로 만들어 보세요.
|
|
{% else %}관리자가 프로젝트에 배정하면 여기에 표시됩니다.{% endif %}
|
|
</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 %}
|
|
</div>
|
|
</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 %}
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</section>
|
|
|
|
<!-- 내 업무 -->
|
|
<aside class="pj-home-side">
|
|
<div class="pj-section-head"><h2>내 업무</h2></div>
|
|
{% if not my_projects %}
|
|
<div class="pj-empty pj-empty-sm">배정된 업무가 없습니다.</div>
|
|
{% else %}
|
|
<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>
|
|
<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 %}
|
|
</div>
|
|
{% endif %}
|
|
</aside>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 새 프로젝트 모달 -->
|
|
{% if is_admin %}
|
|
<div class="pj-modal" id="pj-modal-project" hidden>
|
|
<div class="pj-modal-card">
|
|
<h3>새 프로젝트</h3>
|
|
<label>이름<input type="text" id="pj-f-name" placeholder="프로젝트 이름" /></label>
|
|
<label>설명<textarea id="pj-f-desc" rows="2"></textarea></label>
|
|
<div class="pj-form-row">
|
|
<label>시작일<input type="date" id="pj-f-start" /></label>
|
|
<label>마감일<input type="date" id="pj-f-due" /></label>
|
|
</div>
|
|
<label>색상
|
|
<span class="pj-color-palette" id="pj-f-colors"></span>
|
|
</label>
|
|
<div class="pj-modal-actions">
|
|
<button type="button" class="pj-btn" data-close>취소</button>
|
|
<button type="button" class="pj-btn pj-btn-primary" id="pj-save-project">만들기</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 프로젝트 수정 모달 -->
|
|
<div class="pj-modal" id="pj-modal-edit" hidden>
|
|
<div class="pj-modal-card">
|
|
<h3>프로젝트 수정</h3>
|
|
<input type="hidden" id="pj-e-id" />
|
|
<label>이름<input type="text" id="pj-e-name" placeholder="프로젝트 이름" /></label>
|
|
<label>설명<textarea id="pj-e-desc" rows="2"></textarea></label>
|
|
<div class="pj-form-row">
|
|
<label>시작일<input type="date" id="pj-e-start" /></label>
|
|
<label>마감일<input type="date" id="pj-e-due" /></label>
|
|
</div>
|
|
<label>색상
|
|
<span class="pj-color-palette" id="pj-e-colors"></span>
|
|
</label>
|
|
<label class="pj-time-toggle">
|
|
<input type="checkbox" id="pj-e-done" /> 프로젝트 완료 (목록 끝으로 이동·비활성)
|
|
</label>
|
|
<div class="pj-modal-actions">
|
|
<button type="button" class="pj-btn pj-btn-danger" id="pj-delete-project">삭제</button>
|
|
<span style="flex:1"></span>
|
|
<button type="button" class="pj-btn" data-close>취소</button>
|
|
<button type="button" class="pj-btn pj-btn-primary" id="pj-save-edit">저장</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<script>
|
|
window.PJ_COLORS = {{ ["#4573d2","#37a3a3","#62a420","#e8a33d","#e8384f","#aa62e3","#f06a6a","#5a6772"] | tojson }};
|
|
</script>
|
|
<script src="/static/project.js?v=20260626b" defer></script>
|
|
{% endblock %}
|