일시정지 활용

This commit is contained in:
Hyojin Ahn 2026-06-19 11:00:54 -04:00
parent bb3bb7f03a
commit cc714be650
1 changed files with 30 additions and 17 deletions

View File

@ -1,9 +1,9 @@
import { useMemo, useState } from 'react' import { useMemo, useState } from 'react'
// ( ). // UCO .
// x = (km), y = // x = (km), y =
// = + (/). = / = + / = // = / (). = / = / 0=
// : + (/ ). : onSelect(driverId) // : + . : onSelect(driverId)
const W = 720, H = 470, PL = 56, PR = 680, PT = 44, PB = 400, R = 11 const W = 720, H = 470, PL = 56, PR = 680, PT = 44, PB = 400, R = 11
const ACCENT = '#2e7d32' const ACCENT = '#2e7d32'
@ -17,6 +17,7 @@ const fmtHM = (s) => {
if (isNaN(d)) return '—' if (isNaN(d)) return '—'
return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}` return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`
} }
const statusText = (s) => (s === 'C' ? '운행 종료' : s === 'P' ? '일시정지' : '운행 중')
// (BI) . y = baseline , 13px. // (BI) . y = baseline , 13px.
const TipIcon = ({ type, x, y, c }) => { const TipIcon = ({ type, x, y, c }) => {
@ -69,7 +70,7 @@ export default function EfficiencyScatter({ rows, onSelect, selectedId }) {
targetQty: Number(r.ddsTargetQty ?? 0), // () targetQty: Number(r.ddsTargetQty ?? 0), // ()
completed: Number(r.ddsCompletedCount ?? 0), completed: Number(r.ddsCompletedCount ?? 0),
targetCount: Number(r.ddsTargetCount ?? 0), // () targetCount: Number(r.ddsTargetCount ?? 0), // ()
running: r.ddsStatus !== 'C', // C = status: r.ddsStatus,
startAt: r.ddsStartAt, startAt: r.ddsStartAt,
endAt: r.ddsEndAt, endAt: r.ddsEndAt,
})) }))
@ -181,7 +182,7 @@ export default function EfficiencyScatter({ rows, onSelect, selectedId }) {
const { items, xTicks, yTicks, yOf, xOf } = model const { items, xTicks, yTicks, yOf, xOf } = model
if (!items.length) { if (!items.length) {
return <div className="dstat-empty">픽업이 기록드라이버가 없습니다.</div> return <div className="dstat-empty">목표가 배정드라이버가 없습니다.</div>
} }
// ( ) // ( )
@ -197,8 +198,10 @@ export default function EfficiencyScatter({ rows, onSelect, selectedId }) {
const k = isHover ? 1.18 : 1 const k = isHover ? 1.18 : 1
const r = R * k const r = R * k
const cx = d.mx, cy = d.my const cx = d.mx, cy = d.my
const empty = d.oil <= 0 // ( , ) const empty = d.oil <= 0 // 0 ( )
const f = d.targetQty > 0 ? Math.min(1, d.oil / d.targetQty) : 1 // 픽업량 / 목표량 (예상 없으면 가득) const ended = d.status === 'C'
const paused = d.status === 'P'
const f = d.targetQty > 0 ? Math.min(1, d.oil / d.targetQty) : 1 // 픽업량 / 목표량(고정)
const clipId = `dstatLiq${d.rowId}` const clipId = `dstatLiq${d.rowId}`
// ( ) + . f=0/1 . // ( ) + . f=0/1 .
@ -218,13 +221,13 @@ export default function EfficiencyScatter({ rows, onSelect, selectedId }) {
{isSel && <circle cx={cx} cy={cy} r={r + 5} fill="none" stroke={ACCENT} strokeWidth="1.5" opacity="0.5" />} {isSel && <circle cx={cx} cy={cy} r={r + 5} fill="none" stroke={ACCENT} strokeWidth="1.5" opacity="0.5" />}
{empty ? ( {empty ? (
// / = // 0 / =
<> <>
<circle cx={cx} cy={cy} r={r} fill="#ffffff" stroke="#b5c2b8" strokeWidth="1.5" strokeDasharray="2.5 2" /> <circle cx={cx} cy={cy} r={r} fill="#ffffff" stroke="#b5c2b8" strokeWidth="1.5" strokeDasharray="2.5 2" />
<text x={cx} y={cy + 4} textAnchor="middle" fontSize="10" fontWeight="600" fill="#9aa5a0">{d.num}</text> <text x={cx} y={cy + 4} textAnchor="middle" fontSize="10" fontWeight="600" fill="#9aa5a0">{d.num}</text>
</> </>
) : ( ) : (
// : (f = /) // : (f = /)
<> <>
<clipPath id={clipId}><circle cx={cx} cy={cy} r={r} /></clipPath> <clipPath id={clipId}><circle cx={cx} cy={cy} r={r} /></clipPath>
<circle cx={cx} cy={cy} r={r} fill="#eef3ef" filter="url(#dstatShadow)" /> <circle cx={cx} cy={cy} r={r} fill="#eef3ef" filter="url(#dstatShadow)" />
@ -232,13 +235,23 @@ export default function EfficiencyScatter({ rows, onSelect, selectedId }) {
<circle cx={cx} cy={cy} r={r} fill="none" stroke={ACCENT} strokeWidth="1.6" /> <circle cx={cx} cy={cy} r={r} fill="none" stroke={ACCENT} strokeWidth="1.6" />
<text x={cx} y={cy + 4} textAnchor="middle" fontSize="10" fontWeight="700" <text x={cx} y={cy + 4} textAnchor="middle" fontSize="10" fontWeight="700"
fill="#ffffff" stroke="#1f6b3a" strokeWidth="2.4" paintOrder="stroke">{d.num}</text> fill="#ffffff" stroke="#1f6b3a" strokeWidth="2.4" paintOrder="stroke">{d.num}</text>
{!d.running && ( </>
)}
{ended && (
//
<> <>
<circle cx={cx + r * 0.8} cy={cy - r * 0.8} r="5" fill={ACCENT} stroke="#fff" strokeWidth="1" /> <circle cx={cx + r * 0.8} cy={cy - r * 0.8} r="5" fill={ACCENT} stroke="#fff" strokeWidth="1" />
<path d={`M${(cx + r * 0.8 - 2.3).toFixed(1)} ${(cy - r * 0.8).toFixed(1)} l1.6 1.6 l2.7 -3.2`} <path d={`M${(cx + r * 0.8 - 2.3).toFixed(1)} ${(cy - r * 0.8).toFixed(1)} l1.6 1.6 l2.7 -3.2`}
fill="none" stroke="#fff" strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round" /> fill="none" stroke="#fff" strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round" />
</> </>
)} )}
{paused && (
// ( )
<>
<circle cx={cx + r * 0.8} cy={cy - r * 0.8} r="5" fill="#8a948c" stroke="#fff" strokeWidth="1" />
<line x1={cx + r * 0.8 - 1.4} y1={cy - r * 0.8 - 2} x2={cx + r * 0.8 - 1.4} y2={cy - r * 0.8 + 2} stroke="#fff" strokeWidth="1.2" strokeLinecap="round" />
<line x1={cx + r * 0.8 + 1.4} y1={cy - r * 0.8 - 2} x2={cx + r * 0.8 + 1.4} y2={cy - r * 0.8 + 2} stroke="#fff" strokeWidth="1.2" strokeLinecap="round" />
</> </>
)} )}
@ -263,7 +276,7 @@ export default function EfficiencyScatter({ rows, onSelect, selectedId }) {
: `${Math.round(d.oil).toLocaleString()} L` }, : `${Math.round(d.oil).toLocaleString()} L` },
{ ic: 'dist', t: d.kmText || `${d.km} km` }, { ic: 'dist', t: d.kmText || `${d.km} km` },
{ ic: 'visit', t: d.targetCount > 0 ? `${d.completed} / ${d.targetCount}` : '방문 목표 없음' }, { ic: 'visit', t: d.targetCount > 0 ? `${d.completed} / ${d.targetCount}` : '방문 목표 없음' },
{ ic: 'time', t: d.endAt ? `${fmtHM(d.startAt)} ~ ${fmtHM(d.endAt)}` : `${fmtHM(d.startAt)} ~ 운행 중` }, { ic: 'time', t: d.endAt ? `${fmtHM(d.startAt)} ~ ${fmtHM(d.endAt)}` : `${fmtHM(d.startAt)} ~ ${statusText(d.status)}` },
] ]
const lineH = 16 const lineH = 16
const tw = 168, th = 24 + rows.length * lineH const tw = 168, th = 24 + rows.length * lineH