feat(cafe24): 예약 시각을 한글 형식("2026년 08월 20일" / "오후 07시 30분")으로 표시

datetime-local 을 date+time 으로 나눈 뒤에도 여전히 브라우저가 강제하는 표시
형식("2026. 08. 20.", "오후 07:30")이 남아 있었다. 네이티브 date/time input 은
표시 형식을 CSS 로 바꿀 수 없다(브라우저·로캘가 강제) — 지원되는 방법이 없다.

코드 편집기의 오버레이 방식(.cf24-code-input 투명 textarea 를 .cf24-code-hl 색칠된
글자 위에 겹치는 것)을 그대로 적용했다. 네이티브 date/time input 을 opacity:0 으로
완전히 투명하게 두고, 우리가 형식화한 텍스트(.cf24-dt-display) 바로 위에 포개 놓는다.
클릭·키보드·달력 팝업은 네이티브가 그대로 처리하고(elementFromPoint 로 클릭이
네이티브에 도달하는지 확인함), 화면에 보이는 글자만 JS(paintDate/paintTime)가
input/change 마다 다시 그린다. input.value 자체는 형식과 무관하게 항상
YYYY-MM-DD / HH:MM 이라 제출 시 합치는 로직(store.parse_schedule_at 이 받는 형식)은
전혀 바뀌지 않았다.

정오/자정 12시간제 변환(0시→오전 12시, 12시→오후 12시)을 포함해 처리한다.

폭도 줄여달라는 요청에 맞춰, 실측으로 잘리지 않는 최소값(글자크기 12px·필드폭
117px)을 찾아 적용했다 — 이전 174px 대비 크게 줄었다.

검증(브라우저 실측): 표시 텍스트가 정확한 한글 형식으로 나옴, 정오/자정 처리 정확,
잘림 없음, 클릭이 실제 네이티브 input 에 도달, 제출 시 hidden 필드가
"2026-08-20T19:30" 으로 정확히 조합됨, 가로 스크롤 없음. 백엔드 무변경이라
유닛테스트 61개 그대로 통과.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-14 17:37:52 +09:00
parent 0862c5572b
commit 86914f0bc6
6 changed files with 114 additions and 13 deletions
@@ -96,9 +96,22 @@
<div class="cf24-schedule-grid">
<label class="cf24-schedule-datetime">
<span>예약 시각</span>
{# 네이티브 date/time input 은 브라우저가 표시 형식을 강제한다(CSS로 못 바꿈).
그래서 코드 편집기와 같은 방식을 쓴다 — 투명한 네이티브 input 을 우리가
그린 형식화된 텍스트 위에 겹친다. 클릭·키보드·달력 팝업은 네이티브 그대로
동작하고, 보이는 글자만 "2026년 08월 20일"/"오후 07시 30분" 형식이다.
value 는 그대로 YYYY-MM-DD / HH:MM 이라 제출 시 합치는 로직은 그대로다. #}
<span class="cf24-schedule-datetime-row">
<input class="cf24-schedule-input" type="date" id="cf24-schedule-date" required />
<input class="cf24-schedule-input" type="time" id="cf24-schedule-time" required />
<span class="cf24-dt-field">
<span class="cf24-dt-display" id="cf24-schedule-date-display" aria-hidden="true">연도.월.일</span>
<input class="cf24-dt-native" type="date" id="cf24-schedule-date"
aria-label="예약 날짜" required />
</span>
<span class="cf24-dt-field">
<span class="cf24-dt-display" id="cf24-schedule-time-display" aria-hidden="true">시:분</span>
<input class="cf24-dt-native" type="time" id="cf24-schedule-time"
aria-label="예약 시간" required />
</span>
</span>
</label>
<label>
@@ -1,7 +1,7 @@
{% extends "erp_base.html" %}
{% block head_extra %}
<link rel="stylesheet" href="/static/cafe24.css?v=20260814u" />
<link rel="stylesheet" href="/static/cafe24.css?v=20260814v" />
{% endblock %}
{% block content %}
@@ -234,6 +234,44 @@
});
}
// 예약 시각 — 네이티브 date/time input 은 투명하게 두고(opacity:0), 보이는
// 글자는 우리가 원하는 형식으로 직접 그린다("2026년 08월 20일" / "오후 07시 30분").
// input 의 value 자체는 그대로 YYYY-MM-DD / HH:MM 이라 제출 로직은 안 바뀐다.
(function setupScheduleDateTime() {
var dateEl = document.getElementById("cf24-schedule-date");
var timeEl = document.getElementById("cf24-schedule-time");
var dateOut = document.getElementById("cf24-schedule-date-display");
var timeOut = document.getElementById("cf24-schedule-time-display");
if (!dateEl || !timeEl) return;
function pad2(n) { return (n < 10 ? "0" : "") + n; }
function paintDate() {
var v = dateEl.value; // "YYYY-MM-DD"
if (!v) { dateOut.textContent = "연도.월.일"; return; }
var p = v.split("-");
dateOut.textContent = p[0] + "년 " + p[1] + "월 " + p[2] + "일";
}
function paintTime() {
var v = timeEl.value; // "HH:MM" (24시간제 고정 — 로캘과 무관)
if (!v) { timeOut.textContent = "시:분"; return; }
var parts = v.split(":");
var h = parseInt(parts[0], 10);
var period = h < 12 ? "오전" : "오후";
var h12 = h % 12;
if (h12 === 0) h12 = 12;
timeOut.textContent = period + " " + pad2(h12) + "시 " + parts[1] + "분";
}
dateEl.addEventListener("input", paintDate);
dateEl.addEventListener("change", paintDate);
timeEl.addEventListener("input", paintTime);
timeEl.addEventListener("change", paintTime);
paintDate();
paintTime();
})();
// 예약 폼 — 편집기 내용을 hidden 에 복사해 함께 보낸다(폼이 서로 형제라서).
// 날짜·시간도 두 개의 별도 input 값을 합쳐 서버가 기대하는 형식으로 만든다.
var schedForm = pane.querySelector("#cf24-schedule-form");
@@ -1,7 +1,7 @@
{% extends "erp_base.html" %}
{% block head_extra %}
<link rel="stylesheet" href="/static/cafe24.css?v=20260814u" />
<link rel="stylesheet" href="/static/cafe24.css?v=20260814v" />
{% endblock %}
{% block content %}
@@ -1,7 +1,7 @@
{% extends "erp_base.html" %}
{% block head_extra %}
<link rel="stylesheet" href="/static/cafe24.css?v=20260814u" />
<link rel="stylesheet" href="/static/cafe24.css?v=20260814v" />
{% endblock %}
{% block content %}
+45 -4
View File
@@ -622,20 +622,61 @@
/* 날짜/시간을 별도 input 으로 나눈다 — datetime-local 은 한국어 로캘에서
"2026. 08. 14. 오후 07:00" 형태로 길어져 auto-fit minmax(160px, 1fr) 칸에
잘렸다(실측). date/time 은 각각 폭이 고정이라 잘릴 일이 없다. */
잘렸다(실측). 지금은 표시 텍스트를 우리가 직접 그리므로(아래 .cf24-dt-*) 폭이
예측 가능해 예전만큼 넓게 잡을 필요가 없다. */
.cf24-schedule-datetime {
grid-column: span 2;
min-width: 220px;
max-width: 240px;
}
.cf24-schedule-datetime-row {
display: flex;
gap: var(--sp-8, 8px);
gap: 6px;
}
.cf24-schedule-datetime-row .cf24-schedule-input {
/* ── 날짜/시간 표시 형식을 직접 그리는 오버레이 ──
네이티브 date/time input 은 표시 형식을 CSS 로 바꿀 수 없다(브라우저·로캘가
강제). 코드 편집기(.cf24-code-input 위 .cf24-code-hl)와 같은 원리로, 투명한
네이티브 input 을 우리가 그린 텍스트 위에 완전히 겹쳐 클릭·키보드·달력 팝업은
네이티브 그대로 쓰고 보이는 글자만 형식화한다. */
.cf24-dt-field {
position: relative;
flex: 1 1 0;
min-width: 0;
height: 32px;
}
.cf24-dt-display {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
box-sizing: border-box;
padding: 0 6px;
border: 1px solid var(--color-subtle-ash, #e5e5e5);
border-radius: var(--r-lg, 10px);
background: var(--color-canvas-white, #fff);
color: var(--color-rich-black, #0a0a0a);
/* 12px 는 실측으로 고른 값 — "2026년 08월 20일" 이 117px 칸에 잘리지 않는 최소
폭·글자크기 조합이다(13px 는 4px 부족해 잘렸다). */
font-size: 12px;
white-space: nowrap;
overflow: hidden;
pointer-events: none; /* 클릭은 위에 겹친 네이티브 input 이 받는다 */
}
.cf24-dt-native {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
border: 0;
background: transparent;
opacity: 0; /* 완전히 투명 — 아래 .cf24-dt-display 가 그대로 비쳐 보인다 */
cursor: pointer;
}
.cf24-schedule-input {
+13 -4
View File
@@ -176,10 +176,19 @@ app/modules/cafe24/ ← 상품관리 모듈
JS 가 hidden 에 복사해 함께 보낸다.
- **입력은 날짜/시간 별도 input** 이다(`type=date` + `type=time`). `datetime-local`
단일 입력은 한국어 로캘에서 표시 폭이 브라우저마다 달라 잘리는 사고가 있었다(실제
발생 — "2026. 08. 14. 오후 07:00" 형태). 두 input 은 각각 폭이 고정이라 잘릴 일이
없다. 제출 직전 JS 가 두 값을 `"YYYY-MM-DD" + "T" + "HH:MM"` 로 합쳐 hidden
`scheduled_at` 에 넣는다 — 서버(`store.parse_schedule_at`)는 예전과 같은 형식을
받으므로 백엔드는 그대로다.
발생 — "2026. 08. 14. 오후 07:00" 형태).
- **보이는 글자는 우리가 직접 그린다** — 네이티브 date/time input 은 표시 형식을
CSS 로 바꿀 수 없어서(브라우저·로캘가 강제), 코드 편집기(`.cf24-code-input`
`.cf24-code-hl`)와 같은 원리로 투명한(`opacity:0`) 네이티브 input 을 형식화한
텍스트(`.cf24-dt-display`, `"2026년 08월 20일"` / `"오후 07시 30분"`) 위에 완전히
겹친다. 클릭·키보드·달력 팝업은 네이티브 그대로 동작하고(`elementFromPoint`
클릭이 네이티브에 꽂히는지 확인함), 보이는 글자만 형식화된다. `input`/`change`
이벤트마다 JS(`paintDate`/`paintTime`)가 다시 그린다.
글자크기 12px·필드폭 117px 는 "2026년 08월 20일" 이 잘리지 않는 실측 최소값이다
(13px 는 4px 부족해 잘렸다).
- 제출 직전 JS 가 두 input 의 `value`(형식과 무관하게 항상 `YYYY-MM-DD` / `HH:MM`)를
`"YYYY-MM-DD" + "T" + "HH:MM"` 로 합쳐 hidden `scheduled_at` 에 넣는다 —
서버(`store.parse_schedule_at`)는 예전과 같은 형식을 받으므로 백엔드는 그대로다.
- **시각은 KST 로 해석**한다. 과거 시각은 거부하되
폼을 채우는 동안 시간이 흐른 경우를 위해 1분 여유를 둔다.
- **실행은 `app/modules/cafe24/worker.py`** — compose 서비스 `dbx-cafe24-worker`