feat(WEB): 입력 컴포넌트 공통화 및 UI 개선

- 숫자/통화/전화번호/사업자번호 등 특수 입력 컴포넌트 추가
- MobileCard 컴포넌트 통합 (ListMobileCard 제거)
- IntegratedListTemplateV2 페이지네이션 버그 수정 (NaN 이슈)
- IntegratedDetailTemplate 타이틀 중복 수정
- 문서 시스템 컴포넌트 추가
- 헤더 벨 아이콘 포커스 스타일 개선

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
유병철
2026-01-21 20:56:17 +09:00
parent cfa72fe19b
commit 835c06ce94
190 changed files with 8575 additions and 2354 deletions

View File

@@ -79,12 +79,116 @@ function transformToWorkerScreenFormat(api: WorkOrderApiItem): WorkOrder {
};
}
// ===== 목 데이터 (API 연동 전 UI 확인용) =====
const USE_MOCK_DATA = false; // API 연동 시 false로 변경
const MOCK_WORK_ORDERS: WorkOrder[] = [
{
id: '1',
orderNo: 'KD-WO-260121-01',
productName: '스크린 셔터 (표준형)',
processCode: 'P-001',
processName: '스크린',
client: '삼성물산(주)',
projectName: '강남 타워 신축현장',
assignees: ['홍길동'],
quantity: 50,
dueDate: '2026-01-25',
priority: 1,
status: 'inProgress',
isUrgent: true,
isDelayed: false,
instruction: '1층 우선 생산',
createdAt: '2026-01-20T09:00:00Z',
},
{
id: '2',
orderNo: 'KD-WO-260121-02',
productName: '슬랫 (알루미늄)',
processCode: 'P-002',
processName: '슬랫',
client: '현대건설(주)',
projectName: '판교 테크노밸리 2단지',
assignees: ['홍길동', '김철수'],
quantity: 120,
dueDate: '2026-01-22',
priority: 2,
status: 'waiting',
isUrgent: false,
isDelayed: true,
delayDays: 1,
instruction: '색상 샘플 확인 후 작업',
createdAt: '2026-01-19T14:30:00Z',
},
{
id: '3',
orderNo: 'KD-WO-260121-03',
productName: '절곡판 (스틸)',
processCode: 'P-003',
processName: '절곡',
client: 'GS건설(주)',
projectName: '마포 래미안 재건축',
assignees: ['홍길동'],
quantity: 30,
dueDate: '2026-01-28',
priority: 3,
status: 'waiting',
isUrgent: false,
isDelayed: false,
createdAt: '2026-01-21T08:00:00Z',
},
{
id: '4',
orderNo: 'KD-WO-260120-01',
productName: '스크린 셔터 (고급형)',
processCode: 'P-001',
processName: '스크린',
client: '롯데건설(주)',
projectName: '잠실 롯데캐슬',
assignees: ['홍길동'],
quantity: 80,
dueDate: '2026-01-23',
priority: 1,
status: 'inProgress',
isUrgent: true,
isDelayed: false,
instruction: '긴급 납품 요청',
createdAt: '2026-01-20T10:00:00Z',
},
{
id: '5',
orderNo: 'KD-WO-260119-02',
productName: '슬랫 (목재)',
processCode: 'P-002',
processName: '슬랫',
client: '대우건설(주)',
projectName: '송도 센트럴파크',
assignees: ['홍길동', '박영희'],
quantity: 200,
dueDate: '2026-01-30',
priority: 4,
status: 'waiting',
isUrgent: false,
isDelayed: false,
createdAt: '2026-01-19T11:00:00Z',
},
];
// ===== 내 작업 목록 조회 =====
export async function getMyWorkOrders(): Promise<{
success: boolean;
data: WorkOrder[];
error?: string;
}> {
// 목 데이터 사용 시
if (USE_MOCK_DATA) {
console.log('[WorkerScreenActions] Using MOCK data');
return {
success: true,
data: MOCK_WORK_ORDERS,
};
}
try {
// 작업 대기 + 작업중 상태만 조회 (완료 제외)
const url = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/work-orders?per_page=100&assigned_to_me=1`;
@@ -148,6 +252,13 @@ export async function completeWorkOrder(
id: string,
materials?: { materialId: number; quantity: number; lotNo?: string }[]
): Promise<{ success: boolean; lotNo?: string; error?: string }> {
// 목 데이터 사용 시
if (USE_MOCK_DATA) {
console.log('[WorkerScreenActions] MOCK complete work order:', id, materials);
const lotNo = `KD-SA-${new Date().toISOString().slice(2, 10).replace(/-/g, '')}-01`;
return { success: true, lotNo };
}
try {
// 상태를 completed로 변경
const { response, error } = await serverFetch(
@@ -205,6 +316,15 @@ export interface MaterialForInput {
fifoRank: number;
}
// 목 자재 데이터
const MOCK_MATERIALS: MaterialForInput[] = [
{ id: 1, materialCode: 'MAT-001', materialName: '알루미늄 판재 (T1.2)', unit: 'EA', currentStock: 150, fifoRank: 1 },
{ id: 2, materialCode: 'MAT-002', materialName: '스테인레스 볼트 M6', unit: 'EA', currentStock: 500, fifoRank: 1 },
{ id: 3, materialCode: 'MAT-003', materialName: '방음재 (폴리우레탄)', unit: 'M', currentStock: 80, fifoRank: 2 },
{ id: 4, materialCode: 'MAT-004', materialName: '실리콘 씰링재', unit: 'EA', currentStock: 45, fifoRank: 1 },
{ id: 5, materialCode: 'MAT-005', materialName: '스프링 (φ8)', unit: 'EA', currentStock: 200, fifoRank: 3 },
];
export async function getMaterialsForWorkOrder(
workOrderId: string
): Promise<{
@@ -212,6 +332,15 @@ export async function getMaterialsForWorkOrder(
data: MaterialForInput[];
error?: string;
}> {
// 목 데이터 사용 시
if (USE_MOCK_DATA) {
console.log('[WorkerScreenActions] MOCK materials for work order:', workOrderId);
return {
success: true,
data: MOCK_MATERIALS,
};
}
try {
// 작업지시 BOM 기준 자재 목록 조회
const url = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/work-orders/${workOrderId}/materials`;
@@ -285,6 +414,12 @@ export async function registerMaterialInput(
workOrderId: string,
materialIds: number[]
): Promise<{ success: boolean; error?: string }> {
// 목 데이터 사용 시
if (USE_MOCK_DATA) {
console.log('[WorkerScreenActions] MOCK register material input:', workOrderId, materialIds);
return { success: true };
}
try {
const { response, error } = await serverFetch(
`${process.env.NEXT_PUBLIC_API_URL}/api/v1/work-orders/${workOrderId}/material-inputs`,
@@ -331,6 +466,12 @@ export async function reportIssue(
priority?: 'low' | 'medium' | 'high';
}
): Promise<{ success: boolean; error?: string }> {
// 목 데이터 사용 시
if (USE_MOCK_DATA) {
console.log('[WorkerScreenActions] MOCK report issue:', workOrderId, data);
return { success: true };
}
try {
const { response, error } = await serverFetch(
`${process.env.NEXT_PUBLIC_API_URL}/api/v1/work-orders/${workOrderId}/issues`,