diff --git a/app/modules/project/templates/project/inbox.html b/app/modules/project/templates/project/inbox.html
index ad0c92a..ffb35ed 100644
--- a/app/modules/project/templates/project/inbox.html
+++ b/app/modules/project/templates/project/inbox.html
@@ -1,7 +1,7 @@
{% extends "erp_base.html" %}
{% block head_extra %}
-
+
{% endblock %}
@@ -45,5 +45,5 @@
{% endif %}
-
+
{% endblock %}
diff --git a/app/modules/project/templates/project/index.html b/app/modules/project/templates/project/index.html
index f278d0f..4217a8f 100644
--- a/app/modules/project/templates/project/index.html
+++ b/app/modules/project/templates/project/index.html
@@ -1,7 +1,7 @@
{% extends "erp_base.html" %}
{% block head_extra %}
-
+
{% endblock %}
@@ -100,5 +100,5 @@
-
+
{% endblock %}
diff --git a/app/modules/project/templates/project/project.html b/app/modules/project/templates/project/project.html
index 040c358..cdc913a 100644
--- a/app/modules/project/templates/project/project.html
+++ b/app/modules/project/templates/project/project.html
@@ -1,7 +1,7 @@
{% extends "erp_base.html" %}
{% block head_extra %}
-
+
@@ -290,5 +290,5 @@
-
+
{% endblock %}
diff --git a/app/static/project.js b/app/static/project.js
index ff12b57..476977d 100644
--- a/app/static/project.js
+++ b/app/static/project.js
@@ -242,9 +242,39 @@
});
if (timeline) { timeline.destroy(); timeline = null; }
if (!items.length) { node.innerHTML = '
기간이 설정된 업무가 없습니다.
'; return; }
+ const koWd = function (d) { return ["일", "월", "화", "수", "목", "금", "토"][d.getDay()]; };
+ const pad2 = function (n) { return ("0" + n).slice(-2); };
timeline = new vis.Timeline(node, new vis.DataSet(items), {
- locale: "ko", stack: true, height: "520px", zoomKey: "ctrlKey",
+ stack: true, height: "520px",
+ horizontalScroll: true, // 마우스 휠 = 좌우 이동(패닝)
+ verticalScroll: false,
+ zoomKey: "ctrlKey", // 확대/축소는 Ctrl+휠
margin: { item: 8 },
+ format: {
+ minorLabels: function (date, scale) {
+ const d = new Date(date.valueOf());
+ switch (scale) {
+ case "millisecond": case "second": case "minute": case "hour":
+ return pad2(d.getHours()) + ":" + pad2(d.getMinutes());
+ case "weekday": case "day": return d.getDate() + "일 (" + koWd(d) + ")";
+ case "week": return d.getDate() + "일";
+ case "month": return (d.getMonth() + 1) + "월";
+ case "year": return d.getFullYear() + "년";
+ default: return d.getDate() + "일";
+ }
+ },
+ majorLabels: function (date, scale) {
+ const d = new Date(date.valueOf());
+ switch (scale) {
+ case "millisecond": case "second": case "minute": case "hour":
+ return (d.getMonth() + 1) + "월 " + d.getDate() + "일 (" + koWd(d) + ")";
+ case "weekday": case "day": case "week":
+ return d.getFullYear() + "년 " + (d.getMonth() + 1) + "월";
+ case "month": return d.getFullYear() + "년";
+ default: return "";
+ }
+ },
+ },
});
timeline.on("select", function (props) {
if (!canManage || !props.items.length) return;
@@ -709,9 +739,15 @@
// 최초 렌더 — 달력은 서버 렌더, 클릭 핸들러만 연결
wireCalendar();
- // 사이드 트리에서 업무 클릭(?task=ID)으로 들어오면 해당 업무 모달 자동 열기
- const taskParam = new URLSearchParams(location.search).get("task");
+ // 사이드 트리에서 업무 클릭(?task=ID)으로 들어오면 해당 업무 모달 자동 열기.
+ // 단, 처리 후 URL 에서 task 파라미터를 제거한다 — 드래그 이동 후 location.reload()
+ // 시 이 파라미터가 남아 모달이 다시 뜨는 것을 방지.
+ const params = new URLSearchParams(location.search);
+ const taskParam = params.get("task");
if (taskParam) {
+ params.delete("task");
+ const qs = params.toString();
+ history.replaceState({}, "", location.pathname + (qs ? "?" + qs : ""));
const t = tasks.find(function (x) { return String(x.id) === String(taskParam); });
if (t) openTaskModal(t);
}