feat: 모바일 반응형 UI 개선 및 공휴일/일정 시스템 통합
- MobileCard 접기/펼치기(collapsible) 기능 추가 및 반응형 레이아웃 개선 - DatePicker 공휴일/세무일정 색상 코딩 통합, DateTimePicker 신규 추가 - useCalendarScheduleInit 훅으로 전역 공휴일/일정 데이터 캐싱 - 전 도메인 날짜 필드 DatePicker 표준화 (104 files) - 생산대시보드/작업지시 모바일 호환성 강화 - 견적서/주문관리 반응형 그리드 적용 - 회계 모듈 기능 개선 (매입상세 결재연동, 미수금현황 조회조건 등) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,9 +7,10 @@
|
||||
|
||||
import { useState, useCallback, useEffect } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { Plus, X as XIcon, ChevronDown, Search } from 'lucide-react';
|
||||
import { Plus, Trash2, ChevronDown, Search } from 'lucide-react';
|
||||
import { getTodayString } from '@/lib/utils/date';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { DateTimePicker } from '@/components/ui/date-time-picker';
|
||||
import { DatePicker } from '@/components/ui/date-picker';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -378,7 +379,7 @@ export function ShipmentCreate() {
|
||||
<CardTitle className="text-base">기본 정보</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-6">
|
||||
<div className="grid grid-cols-1 gap-4">
|
||||
{/* 출고번호 - 자동생성 */}
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-1">출고번호</div>
|
||||
@@ -588,11 +589,10 @@ export function ShipmentCreate() {
|
||||
</Select>
|
||||
</TableCell>
|
||||
<TableCell className="p-1">
|
||||
<Input
|
||||
type="datetime-local"
|
||||
<DateTimePicker
|
||||
value={dispatch.arrivalDateTime}
|
||||
onChange={(e) => handleDispatchChange(index, 'arrivalDateTime', e.target.value)}
|
||||
className="h-8"
|
||||
onChange={(val) => handleDispatchChange(index, 'arrivalDateTime', val)}
|
||||
size="sm"
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
</TableCell>
|
||||
@@ -651,7 +651,7 @@ export function ShipmentCreate() {
|
||||
onClick={() => handleRemoveDispatch(index)}
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
<XIcon className="w-4 h-4 text-red-500" />
|
||||
<Trash2 className="w-4 h-4 text-red-500" />
|
||||
</Button>
|
||||
)}
|
||||
</TableCell>
|
||||
|
||||
@@ -38,6 +38,7 @@ import {
|
||||
DialogHeader,
|
||||
} from '@/components/ui/dialog';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { DateTimePicker } from '@/components/ui/date-time-picker';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { PhoneInput } from '@/components/ui/phone-input';
|
||||
import { DocumentViewer } from '@/components/document-system/viewer/DocumentViewer';
|
||||
@@ -327,7 +328,7 @@ export function ShipmentDetail({ id }: ShipmentDetailProps) {
|
||||
<CardTitle className="text-base">기본 정보</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-6">
|
||||
<div className="grid grid-cols-1 gap-4">
|
||||
{renderInfoField('로트번호', detail.lotNo)}
|
||||
{renderInfoField('현장명', detail.siteName)}
|
||||
{renderInfoField('수주처', detail.customerName)}
|
||||
@@ -577,12 +578,10 @@ export function ShipmentDetail({ id }: ShipmentDetailProps) {
|
||||
{targetStatus === 'ready' && (
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="loadingTime">상차 시간 (선택)</Label>
|
||||
<Input
|
||||
id="loadingTime"
|
||||
type="datetime-local"
|
||||
<DateTimePicker
|
||||
value={statusFormData.loadingTime}
|
||||
onChange={(e) =>
|
||||
setStatusFormData((prev) => ({ ...prev, loadingTime: e.target.value }))
|
||||
onChange={(val) =>
|
||||
setStatusFormData((prev) => ({ ...prev, loadingTime: val }))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
@@ -629,12 +628,10 @@ export function ShipmentDetail({ id }: ShipmentDetailProps) {
|
||||
{targetStatus === 'completed' && (
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="confirmedArrival">도착 확인 시간 (선택)</Label>
|
||||
<Input
|
||||
id="confirmedArrival"
|
||||
type="datetime-local"
|
||||
<DateTimePicker
|
||||
value={statusFormData.confirmedArrival}
|
||||
onChange={(e) =>
|
||||
setStatusFormData((prev) => ({ ...prev, confirmedArrival: e.target.value }))
|
||||
onChange={(val) =>
|
||||
setStatusFormData((prev) => ({ ...prev, confirmedArrival: val }))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
|
||||
import { useState, useCallback, useEffect } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { Plus, X as XIcon, ChevronDown, Search } from 'lucide-react';
|
||||
import { Plus, Trash2, ChevronDown, Search } from 'lucide-react';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { DateTimePicker } from '@/components/ui/date-time-picker';
|
||||
import { DatePicker } from '@/components/ui/date-picker';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -390,7 +391,7 @@ export function ShipmentEdit({ id }: ShipmentEditProps) {
|
||||
<CardTitle className="text-base">기본 정보</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-6">
|
||||
<div className="grid grid-cols-1 gap-4">
|
||||
<div className="space-y-1">
|
||||
<Label className="text-muted-foreground">로트번호</Label>
|
||||
<div className="font-medium">{detail.lotNo}</div>
|
||||
@@ -587,11 +588,10 @@ export function ShipmentEdit({ id }: ShipmentEditProps) {
|
||||
</Select>
|
||||
</TableCell>
|
||||
<TableCell className="p-1">
|
||||
<Input
|
||||
type="datetime-local"
|
||||
<DateTimePicker
|
||||
value={dispatch.arrivalDateTime}
|
||||
onChange={(e) => handleDispatchChange(index, 'arrivalDateTime', e.target.value)}
|
||||
className="h-8"
|
||||
onChange={(val) => handleDispatchChange(index, 'arrivalDateTime', val)}
|
||||
size="sm"
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
</TableCell>
|
||||
@@ -650,7 +650,7 @@ export function ShipmentEdit({ id }: ShipmentEditProps) {
|
||||
onClick={() => handleRemoveDispatch(index)}
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
<XIcon className="w-4 h-4 text-red-500" />
|
||||
<Trash2 className="w-4 h-4 text-red-500" />
|
||||
</Button>
|
||||
)}
|
||||
</TableCell>
|
||||
|
||||
@@ -335,7 +335,7 @@ export function ShipmentList() {
|
||||
headerBadges={
|
||||
<>
|
||||
<Badge variant="outline" className="text-xs">
|
||||
#{globalIndex}
|
||||
{globalIndex}
|
||||
</Badge>
|
||||
<Badge variant="outline" className="text-xs">
|
||||
{item.shipmentNo}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import { useState, useCallback, useEffect } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { DateTimePicker } from '@/components/ui/date-time-picker';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
@@ -266,10 +267,9 @@ export function VehicleDispatchEdit({ id }: VehicleDispatchEditProps) {
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label>입차일시</Label>
|
||||
<Input
|
||||
type="datetime-local"
|
||||
<DateTimePicker
|
||||
value={formData.arrivalDateTime}
|
||||
onChange={(e) => handleInputChange('arrivalDateTime', e.target.value)}
|
||||
onChange={(val) => handleInputChange('arrivalDateTime', val)}
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -271,7 +271,7 @@ export function VehicleDispatchList() {
|
||||
headerBadges={
|
||||
<>
|
||||
<Badge variant="outline" className="text-xs">
|
||||
#{globalIndex}
|
||||
{globalIndex}
|
||||
</Badge>
|
||||
<Badge variant="outline" className="text-xs">
|
||||
{item.dispatchNo}
|
||||
|
||||
Reference in New Issue
Block a user