feat(WEB): 공정관리/작업지시/작업자화면 기능 강화 및 템플릿 개선

- 공정관리: ProcessDetail/ProcessForm/ProcessList 개선, StepDetail/StepForm 신규 추가
- 작업지시: WorkOrderDetail/Edit/List UI 개선, 작업지시서 문서 추가
- 작업자화면: WorkerScreen 대폭 개선, MaterialInputModal/WorkLogModal 수정, WorkItemCard 신규
- 영업주문: 주문 상세 페이지 개선
- 입고관리: 상세/actions 수정
- 템플릿: IntegratedDetailTemplate/IntegratedListTemplateV2/UniversalListPage 기능 확장
- UI: confirm-dialog 개선

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
유병철
2026-01-29 22:56:01 +09:00
parent 106ce09482
commit 3fc63d0b3e
50 changed files with 5801 additions and 1377 deletions

View File

@@ -24,7 +24,7 @@ import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { SupplierSearchModal } from './SupplierSearchModal';
// import { SupplierSearchModal } from './SupplierSearchModal';
import {
Select,
SelectContent,
@@ -62,6 +62,7 @@ const INITIAL_FORM_DATA: Partial<ReceivingDetailType> = {
specification: '',
unit: 'EA',
supplier: '',
manufacturer: '',
receivingQty: undefined,
receivingDate: '',
createdBy: '',
@@ -167,6 +168,7 @@ export function ReceivingDetail({ id, mode = 'view' }: Props) {
specification: result.data.specification || '',
unit: result.data.unit || 'EA',
supplier: result.data.supplier,
manufacturer: result.data.manufacturer || '',
receivingQty: result.data.receivingQty,
receivingDate: result.data.receivingDate || '',
createdBy: result.data.createdBy || '',
@@ -274,13 +276,14 @@ export function ReceivingDetail({ id, mode = 'view' }: Props) {
<CardTitle className="text-base font-medium"> </CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
{renderReadOnlyField('로트번호', detail.lotNo)}
{renderReadOnlyField('품목코드', detail.itemCode)}
{renderReadOnlyField('품목명', detail.itemName)}
{renderReadOnlyField('규격', detail.specification)}
{renderReadOnlyField('단위', detail.unit)}
{renderReadOnlyField('발주처', detail.supplier)}
{renderReadOnlyField('제조사', detail.manufacturer)}
{renderReadOnlyField('입고수량', detail.receivingQty)}
{renderReadOnlyField('입고일', detail.receivingDate)}
{renderReadOnlyField('작성자', detail.createdBy)}
@@ -334,7 +337,7 @@ export function ReceivingDetail({ id, mode = 'view' }: Props) {
<CardTitle className="text-base font-medium"> </CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
{/* 로트번호 - 읽기전용 */}
{renderReadOnlyField('로트번호', formData.lotNo, true)}
@@ -397,6 +400,20 @@ export function ReceivingDetail({ id, mode = 'view' }: Props) {
</div>
</div>
{/* 제조사 - 수정가능 */}
<div>
<Label htmlFor="manufacturer" className="text-sm text-muted-foreground">
</Label>
<Input
id="manufacturer"
value={formData.manufacturer || ''}
onChange={(e) => handleInputChange('manufacturer', e.target.value)}
className="mt-1.5"
placeholder="제조사 입력"
/>
</div>
{/* 입고수량 - 수정가능 */}
<div>
<Label htmlFor="receivingQty" className="text-sm text-muted-foreground">
@@ -569,7 +586,7 @@ export function ReceivingDetail({ id, mode = 'view' }: Props) {
}}
/>
{/* 발주처 검색 모달 */}
{/* 발주처 검색 모달 - TODO: SupplierSearchModal 컴포넌트 생성 필요
<SupplierSearchModal
open={isSupplierSearchOpen}
onOpenChange={setIsSupplierSearchOpen}
@@ -580,6 +597,7 @@ export function ReceivingDetail({ id, mode = 'view' }: Props) {
}));
}}
/>
*/}
{/* 수입검사 성적서 모달 */}
<InspectionModalV2

View File

@@ -14,7 +14,7 @@
'use server';
// ===== 목데이터 모드 플래그 =====
const USE_MOCK_DATA = false;
const USE_MOCK_DATA = true;
import { isNextRedirectError } from '@/lib/utils/redirect-error';
@@ -169,6 +169,7 @@ const MOCK_RECEIVING_DETAIL: Record<string, ReceivingDetail> = {
specification: '1000x2000x3T',
unit: 'EA',
supplier: '(주)대한철강',
manufacturer: '포스코',
receivingQty: 100,
receivingDate: '2026-01-26',
createdBy: '김철수',
@@ -190,6 +191,7 @@ const MOCK_RECEIVING_DETAIL: Record<string, ReceivingDetail> = {
specification: 'STM32F103C8T6',
unit: 'EA',
supplier: '삼성전자부품',
manufacturer: '삼성전자',
receivingQty: 500,
receivingDate: '2026-01-27',
createdBy: '이영희',
@@ -208,6 +210,7 @@ const MOCK_RECEIVING_DETAIL: Record<string, ReceivingDetail> = {
specification: '150x100x50',
unit: 'SET',
supplier: '한국플라스틱',
manufacturer: '한국플라스틱',
receivingQty: undefined,
receivingDate: undefined,
createdBy: '박민수',
@@ -226,6 +229,7 @@ const MOCK_RECEIVING_DETAIL: Record<string, ReceivingDetail> = {
specification: '40x40x2000L',
unit: 'EA',
supplier: '(주)대한철강',
manufacturer: '포스코',
receivingQty: 50,
receivingDate: '2026-01-28',
createdBy: '김철수',
@@ -244,6 +248,7 @@ const MOCK_RECEIVING_DETAIL: Record<string, ReceivingDetail> = {
specification: '24V 100RPM',
unit: 'EA',
supplier: '글로벌전자',
manufacturer: '글로벌전자',
receivingQty: undefined,
receivingDate: undefined,
createdBy: '최지훈',

View File

@@ -69,6 +69,7 @@ export interface ReceivingDetail {
specification?: string; // 규격 (읽기전용)
unit: string; // 단위 (읽기전용)
supplier: string; // 발주처 (수정가능)
manufacturer?: string; // 제조사 (수정가능)
receivingQty?: number; // 입고수량 (수정가능)
receivingDate?: string; // 입고일 (수정가능)
createdBy?: string; // 작성자 (읽기전용)

View File

@@ -46,7 +46,6 @@ interface AuditItem {
itemName: string;
specification: string;
unit: string;
calculatedQty: number;
actualQty: number;
newActualQty: number;
}
@@ -71,7 +70,6 @@ export function StockAuditModal({
itemName: stock.itemName,
specification: stock.specification || '',
unit: stock.unit,
calculatedQty: stock.calculatedQty,
actualQty: stock.actualQty,
newActualQty: stock.actualQty,
}))
@@ -154,13 +152,12 @@ export function StockAuditModal({
<TableHead className="text-center"></TableHead>
<TableHead className="text-center"></TableHead>
<TableHead className="text-center"></TableHead>
<TableHead className="text-center"> </TableHead>
<TableHead className="text-center"> </TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell colSpan={6} className="text-center py-12 text-gray-500">
<TableCell colSpan={5} className="text-center py-12 text-gray-500">
.
</TableCell>
</TableRow>
@@ -173,10 +170,9 @@ export function StockAuditModal({
<TableHeader className="sticky top-0 bg-gray-50 z-10">
<TableRow className="bg-gray-50">
<TableHead className="text-center font-medium w-[15%]"></TableHead>
<TableHead className="text-center font-medium w-[25%]"></TableHead>
<TableHead className="text-center font-medium w-[15%]"></TableHead>
<TableHead className="text-center font-medium w-[8%]"></TableHead>
<TableHead className="text-center font-medium w-[12%]"> </TableHead>
<TableHead className="text-center font-medium w-[30%]"></TableHead>
<TableHead className="text-center font-medium w-[20%]"></TableHead>
<TableHead className="text-center font-medium w-[10%]"></TableHead>
<TableHead className="text-center font-medium w-[15%]"> </TableHead>
</TableRow>
</TableHeader>
@@ -191,9 +187,6 @@ export function StockAuditModal({
</TableCell>
<TableCell className="text-center">{item.specification || '-'}</TableCell>
<TableCell className="text-center">{item.unit}</TableCell>
<TableCell className="text-center text-gray-600">
{item.calculatedQty}
</TableCell>
<TableCell className="text-center">
<Input
type="number"