fix(project): 타임라인 배경을 프로젝트 시작/마감일 기준으로 표시
배경(전체 일정)을 업무 최소~최대가 아니라 프로젝트 자체 start_date~ due_date 로 칠한다. 업무가 그 밖에 있으면 범위를 넓혀 가리지 않게 유지. projects_meta 에 start_date/due_date 추가. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -399,6 +399,8 @@ async def project_page(request: Request, project_id: int) -> HTMLResponse:
|
|||||||
"id": p["id"],
|
"id": p["id"],
|
||||||
"name": p["name"],
|
"name": p["name"],
|
||||||
"color": p.get("color") or "#4573d2",
|
"color": p.get("color") or "#4573d2",
|
||||||
|
"start_date": p.get("start_date"),
|
||||||
|
"due_date": p.get("due_date"),
|
||||||
})
|
})
|
||||||
nav_projects.append({
|
nav_projects.append({
|
||||||
"id": p["id"],
|
"id": p["id"],
|
||||||
|
|||||||
@@ -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=20260625t" />
|
<link rel="stylesheet" href="/static/project.css?v=20260625u" />
|
||||||
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
|
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@@ -164,5 +164,5 @@
|
|||||||
<script>
|
<script>
|
||||||
window.PJ_COLORS = {{ ["#4573d2","#37a3a3","#62a420","#e8a33d","#e8384f","#aa62e3","#f06a6a","#5a6772"] | tojson }};
|
window.PJ_COLORS = {{ ["#4573d2","#37a3a3","#62a420","#e8a33d","#e8384f","#aa62e3","#f06a6a","#5a6772"] | tojson }};
|
||||||
</script>
|
</script>
|
||||||
<script src="/static/project.js?v=20260625t" defer></script>
|
<script src="/static/project.js?v=20260625u" defer></script>
|
||||||
{% 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=20260625t" />
|
<link rel="stylesheet" href="/static/project.css?v=20260625u" />
|
||||||
<!-- 구글 머티리얼 심볼(담당자 아이콘 등) — 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 -->
|
||||||
@@ -289,5 +289,5 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script src="/static/vendor/vis-timeline/vis-timeline-graph2d.min.js"></script>
|
<script src="/static/vendor/vis-timeline/vis-timeline-graph2d.min.js"></script>
|
||||||
<script src="/static/project.js?v=20260625t" defer></script>
|
<script src="/static/project.js?v=20260625u" defer></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
+15
-4
@@ -441,6 +441,10 @@
|
|||||||
const dated = tasks.filter(function (t) { return t.start_date || t.due_date; });
|
const dated = tasks.filter(function (t) { return t.start_date || t.due_date; });
|
||||||
if (!dated.length) { node.innerHTML = '<div class="pj-empty">기간이 설정된 업무가 없습니다.</div>'; return; }
|
if (!dated.length) { node.innerHTML = '<div class="pj-empty">기간이 설정된 업무가 없습니다.</div>'; return; }
|
||||||
|
|
||||||
|
// 프로젝트 메타(시작/마감/색) 조회용
|
||||||
|
const projById = {};
|
||||||
|
projectsMeta.forEach(function (p) { projById[p.id] = p; });
|
||||||
|
|
||||||
// 프로젝트별로 업무를 묶어 그룹(행) 생성
|
// 프로젝트별로 업무를 묶어 그룹(행) 생성
|
||||||
const byProj = {};
|
const byProj = {};
|
||||||
dated.forEach(function (t) { (byProj[t.project_id] = byProj[t.project_id] || []).push(t); });
|
dated.forEach(function (t) { (byProj[t.project_id] = byProj[t.project_id] || []).push(t); });
|
||||||
@@ -450,8 +454,9 @@
|
|||||||
Object.keys(byProj).forEach(function (pid) {
|
Object.keys(byProj).forEach(function (pid) {
|
||||||
const list = byProj[pid];
|
const list = byProj[pid];
|
||||||
const grp = "P" + pid;
|
const grp = "P" + pid;
|
||||||
const projColor = list[0].project_color || "#4573d2";
|
const meta = projById[pid] || {};
|
||||||
groupRows.push({ id: grp, content: list[0].project_name || "프로젝트" });
|
const projColor = list[0].project_color || meta.color || "#4573d2";
|
||||||
|
groupRows.push({ id: grp, content: list[0].project_name || meta.name || "프로젝트" });
|
||||||
let minMs = Infinity, maxMs = -Infinity;
|
let minMs = Infinity, maxMs = -Infinity;
|
||||||
list.forEach(function (t) {
|
list.forEach(function (t) {
|
||||||
const s = t.start_date || t.due_date;
|
const s = t.start_date || t.due_date;
|
||||||
@@ -470,10 +475,16 @@
|
|||||||
if (sm < minMs) minMs = sm;
|
if (sm < minMs) minMs = sm;
|
||||||
if (em > maxMs) maxMs = em;
|
if (em > maxMs) maxMs = em;
|
||||||
});
|
});
|
||||||
maxMs += 86400000; // 마지막 날 하루를 덮도록 +1일
|
// 배경(프로젝트 전체 일정) = 프로젝트 자체 시작/마감일 우선, 없으면 업무 최소~최대.
|
||||||
|
let bgStart = meta.start_date ? new Date(meta.start_date + "T00:00:00").getTime() : minMs;
|
||||||
|
let bgEnd = meta.due_date ? new Date(meta.due_date + "T00:00:00").getTime() : maxMs;
|
||||||
|
// 업무가 프로젝트 기간 밖에 있어도 가려지지 않게 범위를 넓힌다.
|
||||||
|
bgStart = Math.min(bgStart, minMs);
|
||||||
|
bgEnd = Math.max(bgEnd, maxMs);
|
||||||
|
bgEnd += 86400000; // 마지막 날 하루를 덮도록 +1일
|
||||||
items.push({
|
items.push({
|
||||||
id: "bg" + pid, group: grp, type: "background",
|
id: "bg" + pid, group: grp, type: "background",
|
||||||
start: new Date(minMs), end: new Date(maxMs),
|
start: new Date(bgStart), end: new Date(bgEnd),
|
||||||
style: "background-color:" + projColor + "22;",
|
style: "background-color:" + projColor + "22;",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user