feat(WEB): FCM 푸시 알림 시스템 구현
- FCMProvider 컨텍스트 및 useFCM 훅 추가 - Capacitor FCM 플러그인 통합 - 알림 사운드 파일 추가 (default.wav, push_notification.wav) - Firebase 메시징 패키지 의존성 추가
This commit is contained in:
@@ -1,158 +0,0 @@
|
||||
import type { WorkOrder, WorkerStatus, ProcessType } from './types';
|
||||
|
||||
// Mock 작업 지시 데이터
|
||||
export const generateMockWorkOrders = (): WorkOrder[] => {
|
||||
const processes: ProcessType[] = ['screen', 'slat', 'bending'];
|
||||
const clients = ['삼성물산(주)', '현대건설(주)', '대림건설(주)', '두산건설(주)', '(주)서울인테리어'];
|
||||
const projects = [
|
||||
'강남 타워 신축현장 (B동)',
|
||||
'강남 오피스 A동',
|
||||
'해운대 타워',
|
||||
'[E2E테스트] 강남 오피스 A동',
|
||||
'대치 레이크파크',
|
||||
'위례 청라 센트럴파크',
|
||||
'판교 물류센터',
|
||||
'삼성타운 종합',
|
||||
'분당 더 피스트',
|
||||
'연수 오피스텔',
|
||||
];
|
||||
const productNames = [
|
||||
'스크린 서터 (표준형) - 추가',
|
||||
'방연셔터 절곡 부품',
|
||||
'철재 슬랫 서터',
|
||||
'스크린 서터 (대형)',
|
||||
];
|
||||
const assigneePool = [
|
||||
'김스크린', '박스크린', '이스크린', '최스크린',
|
||||
'김슬랫', '박슬랫', '이절곡', '박절곡',
|
||||
'이정곡', '김술랫', '박술랫', '이슬랫',
|
||||
];
|
||||
|
||||
const orders: WorkOrder[] = [];
|
||||
|
||||
// 긴급 작업 (5개) - WorkOrders mockData와 매칭
|
||||
const urgentOrders = [
|
||||
{ orderNo: 'KD-WO-251217-12', process: 'screen' as ProcessType, client: '두산건설(주)', project: '위브 청라 센트럴파크', dueDate: '2025-12-30', status: 'completed' as const },
|
||||
{ orderNo: 'KD-WO-251217-11', process: 'screen' as ProcessType, client: '대영건설(주)', project: '대시앙 동탄 레이크파크', dueDate: '2026-02-08', status: 'inProgress' as const },
|
||||
{ orderNo: 'KD-WO-FLD-251216-01', process: 'bending' as ProcessType, client: '삼성물산(주)', project: '[E2E테스트] 절곡 전용 현장', dueDate: '2025-12-28', status: 'inProgress' as const },
|
||||
{ orderNo: 'KD-WO-251217-10', process: 'screen' as ProcessType, client: '포레나', project: '포레나 수지 더 퍼스트', dueDate: '2026-02-13', status: 'waiting' as const },
|
||||
{ orderNo: 'KD-WO-251217-09', process: 'slat' as ProcessType, client: '호반건설(주)', project: '써밋 광교 리버파크', dueDate: '2026-01-30', status: 'inProgress' as const },
|
||||
];
|
||||
|
||||
urgentOrders.forEach((item, i) => {
|
||||
orders.push({
|
||||
id: `urgent-${i + 1}`,
|
||||
orderNo: item.orderNo,
|
||||
productName: productNames[i % productNames.length],
|
||||
process: item.process,
|
||||
client: item.client,
|
||||
projectName: item.project,
|
||||
assignees: [assigneePool[i % assigneePool.length]],
|
||||
quantity: (i % 5) + 2, // 고정값 (2~6)
|
||||
dueDate: item.dueDate,
|
||||
priority: i + 1,
|
||||
status: item.status,
|
||||
isUrgent: true,
|
||||
isDelayed: false,
|
||||
instruction: i === 0 ? '추가분 주문, 기존 납품분과 동일 사양 유지' : undefined,
|
||||
createdAt: '2025-12-20T09:00:00.000Z', // 고정값
|
||||
});
|
||||
});
|
||||
|
||||
// 지연 작업 (5개) - WorkOrders mockData와 매칭
|
||||
const delayedOrders = [
|
||||
{ orderNo: 'KD-WO-251217-08', process: 'screen' as ProcessType, client: '삼성물산(주)', delayDays: 5 },
|
||||
{ orderNo: 'KD-WO-251217-07', process: 'screen' as ProcessType, client: '삼성물산(주)', delayDays: 3 },
|
||||
{ orderNo: 'KD-WO-FLD-251215-01', process: 'bending' as ProcessType, client: '삼성물산(주)', delayDays: 7 },
|
||||
{ orderNo: 'KD-WO-FLD-251212-01', process: 'bending' as ProcessType, client: '삼성물산(주)', delayDays: 10 },
|
||||
{ orderNo: 'KD-WO-FLD-251208-01', process: 'screen' as ProcessType, client: '삼성물산(주)', delayDays: 1 },
|
||||
];
|
||||
|
||||
delayedOrders.forEach((item, i) => {
|
||||
orders.push({
|
||||
id: `delayed-${i + 1}`,
|
||||
orderNo: item.orderNo,
|
||||
productName: productNames[i % productNames.length],
|
||||
process: item.process,
|
||||
client: item.client,
|
||||
projectName: projects[i % projects.length],
|
||||
assignees: [assigneePool[(i + 5) % assigneePool.length], assigneePool[(i + 6) % assigneePool.length]],
|
||||
quantity: (i % 5) + 2, // 고정값 (2~6)
|
||||
dueDate: '2025-01-15',
|
||||
priority: i + 1,
|
||||
status: 'inProgress',
|
||||
isUrgent: false,
|
||||
isDelayed: true,
|
||||
delayDays: item.delayDays,
|
||||
createdAt: '2025-12-20T09:00:00.000Z', // 고정값
|
||||
});
|
||||
});
|
||||
|
||||
// 일반 작업 (추가) - 대기/작업중 상태 위주로 추가
|
||||
for (let i = 0; i < 22; i++) {
|
||||
const process = processes[i % 3];
|
||||
// completed 비율을 줄이고 waiting/inProgress 위주로 생성
|
||||
const statusOptions: Array<'waiting' | 'inProgress' | 'completed'> = ['waiting', 'waiting', 'inProgress', 'inProgress', 'inProgress', 'completed'];
|
||||
orders.push({
|
||||
id: `work-${i + 1}`,
|
||||
orderNo: `KD-WO-${process === 'bending' ? 'FLD-' : ''}25${String(12).padStart(2, '0')}${String(i + 1).padStart(2, '0')}-${String((i % 3) + 1).padStart(2, '0')}`,
|
||||
productName: productNames[i % productNames.length],
|
||||
process,
|
||||
client: clients[i % clients.length],
|
||||
projectName: projects[i % projects.length],
|
||||
assignees: [assigneePool[i % assigneePool.length]],
|
||||
quantity: (i % 8) + 3, // 고정값 (3~10)
|
||||
dueDate: `2025-${String((i % 3) + 1).padStart(2, '0')}-${String((i % 28) + 1).padStart(2, '0')}`,
|
||||
priority: (i % 5) + 1,
|
||||
status: statusOptions[i % statusOptions.length],
|
||||
isUrgent: false,
|
||||
isDelayed: false,
|
||||
createdAt: '2025-12-20T09:00:00.000Z', // 고정값
|
||||
});
|
||||
}
|
||||
|
||||
// 작업자 화면용 추가 데이터 (대기/작업중 상태만)
|
||||
const additionalWaitingOrders = [
|
||||
{ orderNo: 'KD-WO-251201-01', process: 'screen' as ProcessType, client: '삼성물산(주)', project: '강남 타워 신축현장 (B동)', product: '스크린 서터 (표준형) - 추가', quantity: 3, priority: 1 },
|
||||
{ orderNo: 'KD-WO-251202-02', process: 'slat' as ProcessType, client: '현대건설(주)', project: '해운대 타워', product: '철재 슬랫 서터', quantity: 5, priority: 2 },
|
||||
{ orderNo: 'KD-WO-251203-03', process: 'screen' as ProcessType, client: '대림건설(주)', project: '대치 레이크파크', product: '스크린 서터 (대형)', quantity: 2, priority: 3 },
|
||||
{ orderNo: 'KD-WO-FLD-251204-01', process: 'bending' as ProcessType, client: '두산건설(주)', project: '위례 청라 센트럴파크', product: '방연셔터 절곡 부품', quantity: 8, priority: 1 },
|
||||
{ orderNo: 'KD-WO-251205-04', process: 'screen' as ProcessType, client: '(주)서울인테리어', project: '판교 물류센터', product: '스크린 서터 (표준형) - 추가', quantity: 4, priority: 2 },
|
||||
];
|
||||
|
||||
additionalWaitingOrders.forEach((item, i) => {
|
||||
orders.push({
|
||||
id: `additional-waiting-${i + 1}`,
|
||||
orderNo: item.orderNo,
|
||||
productName: item.product,
|
||||
process: item.process,
|
||||
client: item.client,
|
||||
projectName: item.project,
|
||||
assignees: [assigneePool[i % assigneePool.length]],
|
||||
quantity: item.quantity,
|
||||
dueDate: '2025-01-01',
|
||||
priority: item.priority,
|
||||
status: 'waiting',
|
||||
isUrgent: i === 0 || i === 3, // 1, 4번째 긴급
|
||||
isDelayed: false,
|
||||
instruction: i === 0 ? '추가분 주문, 기존 납품분과 동일 사양 유지' : undefined,
|
||||
createdAt: '2025-12-20T09:00:00.000Z',
|
||||
});
|
||||
});
|
||||
|
||||
return orders;
|
||||
};
|
||||
|
||||
// Mock 작업자 현황 데이터
|
||||
export const generateMockWorkerStatus = (): WorkerStatus[] => {
|
||||
return [
|
||||
{ id: 'w1', name: '김스크린', inProgress: 4, completed: 4, assigned: 9 },
|
||||
{ id: 'w2', name: '박스크린', inProgress: 4, completed: 4, assigned: 5 },
|
||||
{ id: 'w3', name: '김슬랫', inProgress: 0, completed: 3, assigned: 5 },
|
||||
{ id: 'w4', name: '박슬랫', inProgress: 0, completed: 2, assigned: 2 },
|
||||
{ id: 'w5', name: '이스크린', inProgress: 1, completed: 1, assigned: 2 },
|
||||
{ id: 'w6', name: '최절곡', inProgress: 0, completed: 2, assigned: 3 },
|
||||
{ id: 'w7', name: '이절곡', inProgress: 1, completed: 0, assigned: 1 },
|
||||
{ id: 'w8', name: '최스크린', inProgress: 0, completed: 1, assigned: 2 },
|
||||
];
|
||||
};
|
||||
@@ -1,488 +0,0 @@
|
||||
/**
|
||||
* 작업지시 관리 목업 데이터
|
||||
*/
|
||||
|
||||
import type {
|
||||
WorkOrder,
|
||||
SalesOrder,
|
||||
WorkOrderStats,
|
||||
BendingDetail,
|
||||
} from './types';
|
||||
|
||||
// 전개도 상세 목업 (절곡용)
|
||||
const bendingDetailsSample: BendingDetail[] = [
|
||||
{
|
||||
id: 'bd-1',
|
||||
code: 'SD30',
|
||||
name: '엘바',
|
||||
material: 'E.G.I 1.6T',
|
||||
quantity: 4,
|
||||
developWidth: '500mm',
|
||||
length: '3000mm',
|
||||
weight: '0.9kg',
|
||||
note: '-',
|
||||
developDimension: '75',
|
||||
},
|
||||
{
|
||||
id: 'bd-2',
|
||||
code: 'SD31',
|
||||
name: '하장바',
|
||||
material: 'E.G.I 1.6T',
|
||||
quantity: 2,
|
||||
developWidth: '500mm',
|
||||
length: '3000mm',
|
||||
weight: '1.158kg',
|
||||
note: '-',
|
||||
developDimension: '67→126→165→178→193',
|
||||
},
|
||||
{
|
||||
id: 'bd-3',
|
||||
code: 'SD32',
|
||||
name: '짜부가스켓',
|
||||
material: 'E.G.I 0.8T',
|
||||
quantity: 4,
|
||||
developWidth: '500mm',
|
||||
length: '3000mm',
|
||||
weight: '0.576kg',
|
||||
note: '80*4,50*8',
|
||||
developDimension: '48',
|
||||
},
|
||||
{
|
||||
id: 'bd-4',
|
||||
code: 'SD33',
|
||||
name: '50평철',
|
||||
material: 'E.G.I 1.2T',
|
||||
quantity: 2,
|
||||
developWidth: '500mm',
|
||||
length: '3000mm',
|
||||
weight: '0.3kg',
|
||||
note: '-',
|
||||
developDimension: '50',
|
||||
},
|
||||
{
|
||||
id: 'bd-5',
|
||||
code: 'SD36',
|
||||
name: '밑면 점검구',
|
||||
material: 'E.G.I 1.6T',
|
||||
quantity: 2,
|
||||
developWidth: '500mm',
|
||||
length: '2438mm',
|
||||
weight: '0.98kg',
|
||||
note: '500*380',
|
||||
developDimension: '90→240→310',
|
||||
},
|
||||
{
|
||||
id: 'bd-6',
|
||||
code: 'SD37',
|
||||
name: '후면코너부',
|
||||
material: 'E.G.I 1.2T',
|
||||
quantity: 4,
|
||||
developWidth: '500mm',
|
||||
length: '1219mm',
|
||||
weight: '0.45kg',
|
||||
note: '-',
|
||||
developDimension: '35→85→120',
|
||||
},
|
||||
];
|
||||
|
||||
// 작업지시 목업 데이터
|
||||
export const mockWorkOrders: WorkOrder[] = [
|
||||
{
|
||||
id: 'wo-1',
|
||||
workOrderNo: 'KD-WO-251217-12',
|
||||
lotNo: 'KD-TS-251217-10',
|
||||
processType: 'screen',
|
||||
status: 'shipped',
|
||||
client: '두산건설(주)',
|
||||
projectName: '위브 청라 센트럴파크',
|
||||
dueDate: '2025-12-30',
|
||||
assignee: '최스크린',
|
||||
orderDate: '2025-12-17',
|
||||
shipmentDate: '2025-12-28',
|
||||
isAssigned: true,
|
||||
isStarted: true,
|
||||
priority: 5,
|
||||
currentStep: 5,
|
||||
items: [
|
||||
{ id: 'item-1', no: 1, status: 'completed', productName: '스크린 셔터 (표준형)', floorCode: '1층/I-01', specification: '3500×2500', quantity: 1 },
|
||||
{ id: 'item-2', no: 2, status: 'completed', productName: '스크린 셔터 (표준형)', floorCode: '1층/I-02', specification: '3500×2500', quantity: 1 },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'wo-2',
|
||||
workOrderNo: 'KD-WO-251217-11',
|
||||
lotNo: 'KD-TS-251217-09',
|
||||
processType: 'screen',
|
||||
status: 'in_progress',
|
||||
client: '대영건설(주)',
|
||||
projectName: '대시앙 동탄 레이크파크',
|
||||
dueDate: '2026-02-08',
|
||||
assignee: '김스크린',
|
||||
orderDate: '2025-12-17',
|
||||
shipmentDate: '2026-02-01',
|
||||
isAssigned: true,
|
||||
isStarted: true,
|
||||
priority: 5,
|
||||
currentStep: 3,
|
||||
items: [
|
||||
{ id: 'item-3', no: 1, status: 'waiting', productName: '스크린 사타 (표준형)', floorCode: '1층/H-01', specification: '4000×3000', quantity: 1 },
|
||||
{ id: 'item-4', no: 2, status: 'waiting', productName: '스크린 사타 (표준형)', floorCode: '2층/H-02', specification: '4000×3000', quantity: 1 },
|
||||
],
|
||||
issues: [
|
||||
{
|
||||
id: 'issue-1',
|
||||
status: 'processing',
|
||||
type: '불량품발생',
|
||||
description: '앤드락 접착불량 - 전체 재작업 필요',
|
||||
createdAt: '2025-12-20',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'wo-3',
|
||||
workOrderNo: 'KD-WO-251217-10',
|
||||
lotNo: 'KD-TS-251217-08',
|
||||
processType: 'screen',
|
||||
status: 'waiting',
|
||||
client: '포레나',
|
||||
projectName: '포레나 수지 더 퍼스트',
|
||||
dueDate: '2026-02-13',
|
||||
assignee: '-',
|
||||
orderDate: '2025-12-17',
|
||||
shipmentDate: '2026-02-05',
|
||||
isAssigned: false,
|
||||
isStarted: false,
|
||||
priority: 7,
|
||||
currentStep: 0,
|
||||
items: [
|
||||
{ id: 'item-5', no: 1, status: 'waiting', productName: '스크린 셔터 (표준형)', floorCode: '1층/A-01', specification: '3000×2500', quantity: 1 },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'wo-4',
|
||||
workOrderNo: 'KD-WO-251217-09',
|
||||
lotNo: 'KD-TS-251217-07',
|
||||
processType: 'slat',
|
||||
status: 'in_progress',
|
||||
client: '호반건설(주)',
|
||||
projectName: '써밋 광교 리버파크',
|
||||
dueDate: '2026-01-30',
|
||||
assignee: '이슬랫',
|
||||
orderDate: '2025-12-17',
|
||||
shipmentDate: '2026-01-20',
|
||||
isAssigned: true,
|
||||
isStarted: true,
|
||||
priority: 5,
|
||||
currentStep: 1,
|
||||
items: [
|
||||
{ id: 'item-6', no: 1, status: 'waiting', productName: '철재 슬랫 셔터', floorCode: '3층/F-05', specification: '3500×2500', quantity: 1 },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'wo-5',
|
||||
workOrderNo: 'KD-WO-251217-08',
|
||||
lotNo: 'KD-TS-251217-07',
|
||||
processType: 'screen',
|
||||
status: 'completed',
|
||||
client: '삼성물산(주)',
|
||||
projectName: '써밋 광교 리버파크',
|
||||
dueDate: '2026-01-18',
|
||||
assignee: '박스크린',
|
||||
orderDate: '2025-12-17',
|
||||
shipmentDate: '2026-01-10',
|
||||
isAssigned: true,
|
||||
isStarted: true,
|
||||
priority: 5,
|
||||
currentStep: 5,
|
||||
items: [
|
||||
{ id: 'item-7', no: 1, status: 'completed', productName: '스크린 셔터 (표준형)', floorCode: '1층/A-01', specification: '3500×2500', quantity: 1 },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'wo-6',
|
||||
workOrderNo: 'KD-WO-FLD-251216-01',
|
||||
lotNo: 'KD-TS-251216-06',
|
||||
processType: 'bending',
|
||||
status: 'completed',
|
||||
client: '삼성물산(주)',
|
||||
projectName: '[E2E테스트] 절곡 전용 현장',
|
||||
dueDate: '2025-12-28',
|
||||
assignee: '최절곡',
|
||||
orderDate: '2025-12-16',
|
||||
shipmentDate: '2025-12-24',
|
||||
isAssigned: true,
|
||||
isStarted: true,
|
||||
priority: 3,
|
||||
currentStep: 4,
|
||||
items: [
|
||||
{ id: 'item-8', no: 1, status: 'waiting', productName: '방화셔터 절곡 부품 SET (E2E)', floorCode: '테스트층/E2E-G-01', specification: '3000×4000', quantity: 1 },
|
||||
],
|
||||
bendingDetails: bendingDetailsSample,
|
||||
issues: [
|
||||
{
|
||||
id: 'issue-2',
|
||||
status: 'processing',
|
||||
type: '불량품발생',
|
||||
description: '중간검사 불합격 - 절곡 각도 불량 1EA (90° 기준 ±2° 초과)',
|
||||
createdAt: '2025-12-22',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'wo-7',
|
||||
workOrderNo: 'KD-WO-251217-07',
|
||||
lotNo: 'KD-TS-251217-07',
|
||||
processType: 'screen',
|
||||
status: 'completed',
|
||||
client: '삼성물산(주)',
|
||||
projectName: '써밋 광교 리버파크',
|
||||
dueDate: '2026-01-08',
|
||||
assignee: '김스크린',
|
||||
orderDate: '2025-12-17',
|
||||
shipmentDate: '2025-12-30',
|
||||
isAssigned: true,
|
||||
isStarted: true,
|
||||
priority: 5,
|
||||
currentStep: 5,
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
id: 'wo-8',
|
||||
workOrderNo: 'KD-WO-251217-06',
|
||||
lotNo: 'KD-TS-251217-05',
|
||||
processType: 'screen',
|
||||
status: 'completed',
|
||||
client: '대산',
|
||||
projectName: '대산 송도 마린베이',
|
||||
dueDate: '2026-01-28',
|
||||
assignee: '최스크린',
|
||||
orderDate: '2025-12-17',
|
||||
shipmentDate: '2026-01-20',
|
||||
isAssigned: true,
|
||||
isStarted: true,
|
||||
priority: 5,
|
||||
currentStep: 5,
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
id: 'wo-9',
|
||||
workOrderNo: 'KD-WO-251217-05',
|
||||
lotNo: 'KD-TS-251217-04',
|
||||
processType: 'slat',
|
||||
status: 'completed',
|
||||
client: '자이',
|
||||
projectName: '자이 위례 더 퍼스트',
|
||||
dueDate: '2026-01-28',
|
||||
assignee: '이슬랫',
|
||||
orderDate: '2025-12-17',
|
||||
shipmentDate: '2026-01-20',
|
||||
isAssigned: true,
|
||||
isStarted: true,
|
||||
priority: 5,
|
||||
currentStep: 5,
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
id: 'wo-10',
|
||||
workOrderNo: 'KD-WO-251217-04',
|
||||
lotNo: 'KD-TS-251217-03',
|
||||
processType: 'screen',
|
||||
status: 'completed',
|
||||
client: '푸르지오',
|
||||
projectName: '푸르지오 일산 센트럴파크',
|
||||
dueDate: '2026-01-23',
|
||||
assignee: '박스크린',
|
||||
orderDate: '2025-12-17',
|
||||
shipmentDate: '2026-01-15',
|
||||
isAssigned: true,
|
||||
isStarted: true,
|
||||
priority: 5,
|
||||
currentStep: 5,
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
id: 'wo-11',
|
||||
workOrderNo: 'KD-WO-251217-03',
|
||||
lotNo: 'KD-TS-251217-02',
|
||||
processType: 'bending',
|
||||
status: 'completed',
|
||||
client: '힐스테이트',
|
||||
projectName: '힐스테이트 판교 더 퍼스트',
|
||||
dueDate: '2026-01-18',
|
||||
assignee: '최절곡',
|
||||
orderDate: '2025-12-17',
|
||||
shipmentDate: '2026-01-10',
|
||||
isAssigned: true,
|
||||
isStarted: true,
|
||||
priority: 5,
|
||||
currentStep: 4,
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
id: 'wo-12',
|
||||
workOrderNo: 'KD-WO-251217-02',
|
||||
lotNo: 'KD-TS-251217-82',
|
||||
processType: 'screen',
|
||||
status: 'completed',
|
||||
client: '힐스테이트',
|
||||
projectName: '힐스테이트 판교 더 머스트',
|
||||
dueDate: '2026-01-08',
|
||||
assignee: '김스크린',
|
||||
orderDate: '2025-12-17',
|
||||
shipmentDate: '2025-12-30',
|
||||
isAssigned: true,
|
||||
isStarted: true,
|
||||
priority: 5,
|
||||
currentStep: 5,
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
id: 'wo-13',
|
||||
workOrderNo: 'KD-WO-251217-01',
|
||||
lotNo: 'KD-TS-251217-81',
|
||||
processType: 'screen',
|
||||
status: 'completed',
|
||||
client: '레미안',
|
||||
projectName: '레미안 강남 프레스티지',
|
||||
dueDate: '2026-01-13',
|
||||
assignee: '최스크린',
|
||||
orderDate: '2025-12-17',
|
||||
shipmentDate: '2026-01-05',
|
||||
isAssigned: true,
|
||||
isStarted: true,
|
||||
priority: 5,
|
||||
currentStep: 5,
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
id: 'wo-14',
|
||||
workOrderNo: 'KD-WO-FLD-251215-01',
|
||||
lotNo: 'KD-TS-251215-01',
|
||||
processType: 'bending',
|
||||
status: 'completed',
|
||||
client: '삼성물산(주)',
|
||||
projectName: '송도 아파트 B동',
|
||||
dueDate: '2025-12-30',
|
||||
assignee: '최절곡',
|
||||
orderDate: '2025-12-15',
|
||||
shipmentDate: '2025-12-25',
|
||||
isAssigned: true,
|
||||
isStarted: true,
|
||||
priority: 5,
|
||||
currentStep: 4,
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
id: 'wo-15',
|
||||
workOrderNo: 'KD-WO-FLD-251212-01',
|
||||
lotNo: 'KD-TS-251212-81',
|
||||
processType: 'bending',
|
||||
status: 'completed',
|
||||
client: '삼성물산(주)',
|
||||
projectName: '판교 롯데센터',
|
||||
dueDate: '2025-12-26',
|
||||
assignee: '최절곡',
|
||||
orderDate: '2025-12-13',
|
||||
shipmentDate: '2025-12-22',
|
||||
isAssigned: true,
|
||||
isStarted: true,
|
||||
priority: 5,
|
||||
currentStep: 4,
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
id: 'wo-16',
|
||||
workOrderNo: 'KD-WO-FLD-251210-01',
|
||||
lotNo: 'KD-TS-251210-81',
|
||||
processType: 'screen',
|
||||
status: 'completed',
|
||||
client: '삼성물산(주)',
|
||||
projectName: '강남 타워 신축현장',
|
||||
dueDate: '2025-12-25',
|
||||
assignee: '김스크린',
|
||||
orderDate: '2025-12-10',
|
||||
shipmentDate: '2025-12-20',
|
||||
isAssigned: true,
|
||||
isStarted: true,
|
||||
priority: 5,
|
||||
currentStep: 5,
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
id: 'wo-17',
|
||||
workOrderNo: 'KD-WO-FLD-251208-01',
|
||||
lotNo: 'KD-TS-251288-01',
|
||||
processType: 'screen',
|
||||
status: 'completed',
|
||||
client: '삼성물산(주)',
|
||||
projectName: '배곧더 타워',
|
||||
dueDate: '2025-12-22',
|
||||
assignee: '박스크린',
|
||||
orderDate: '2025-12-08',
|
||||
shipmentDate: '2025-12-18',
|
||||
isAssigned: true,
|
||||
isStarted: true,
|
||||
priority: 5,
|
||||
currentStep: 5,
|
||||
items: [],
|
||||
},
|
||||
];
|
||||
|
||||
// 수주 목록 목업 데이터
|
||||
export const mockSalesOrders: SalesOrder[] = [
|
||||
{
|
||||
id: 'so-1',
|
||||
orderNo: 'KD-TS-251201-01',
|
||||
status: '생산지시완료',
|
||||
client: '삼성물산(주)',
|
||||
projectName: '삼성물산 레미안 강남 1차',
|
||||
dueDate: '2025-12-20',
|
||||
itemCount: 2,
|
||||
splitCount: 1,
|
||||
},
|
||||
{
|
||||
id: 'so-2',
|
||||
orderNo: 'KD-TS-251205-01-A',
|
||||
status: '생산지시완료',
|
||||
client: '삼성물산(주)',
|
||||
projectName: '삼성물산 레미안 강남 1차',
|
||||
dueDate: '2025-12-28',
|
||||
itemCount: 1,
|
||||
splitCount: 1,
|
||||
},
|
||||
{
|
||||
id: 'so-3',
|
||||
orderNo: 'KD-TS-251206-01',
|
||||
status: '생산지시완료',
|
||||
client: '(주)서울인테리어',
|
||||
projectName: '강남 오피스타워 인테리어',
|
||||
dueDate: '2025-12-29',
|
||||
itemCount: 2,
|
||||
splitCount: 2,
|
||||
},
|
||||
{
|
||||
id: 'so-4',
|
||||
orderNo: 'KD-TS-251207-01',
|
||||
status: '생산지시완료',
|
||||
client: '삼성물산(주)',
|
||||
projectName: '삼성물산 레미안 강남 2차',
|
||||
dueDate: '2025-12-28',
|
||||
itemCount: 1,
|
||||
splitCount: 1,
|
||||
},
|
||||
];
|
||||
|
||||
// 통계 계산
|
||||
export function calculateStats(orders: WorkOrder[]): WorkOrderStats {
|
||||
return {
|
||||
total: orders.length,
|
||||
unassigned: orders.filter((o) => o.status === 'unassigned').length,
|
||||
pending: orders.filter((o) => o.status === 'pending').length,
|
||||
waiting: orders.filter((o) => o.status === 'waiting').length,
|
||||
inProgress: orders.filter((o) => o.status === 'in_progress').length,
|
||||
completed: orders.filter((o) => o.status === 'completed' || o.status === 'shipped').length,
|
||||
};
|
||||
}
|
||||
|
||||
// 기본 통계
|
||||
export const mockStats: WorkOrderStats = calculateStats(mockWorkOrders);
|
||||
@@ -1,155 +0,0 @@
|
||||
/**
|
||||
* 작업실적 조회 Mock 데이터
|
||||
*/
|
||||
|
||||
import type { WorkResult, WorkResultStats } from './types';
|
||||
|
||||
// Mock 작업실적 데이터
|
||||
export const mockWorkResults: WorkResult[] = [
|
||||
{
|
||||
id: 'wr-1',
|
||||
lotNo: 'KD-TS-250212-01-01',
|
||||
workDate: '2025-02-12',
|
||||
workOrderNo: 'KD-PL-250122-01',
|
||||
processType: 'screen',
|
||||
productName: '스크린 셔터 (프리미엄)',
|
||||
specification: '8000x2800',
|
||||
productionQty: 1,
|
||||
goodQty: 0,
|
||||
defectQty: 1,
|
||||
defectRate: 100.0,
|
||||
inspection: true,
|
||||
packaging: false,
|
||||
worker: '이성산',
|
||||
},
|
||||
{
|
||||
id: 'wr-2',
|
||||
lotNo: 'KD-TS-250210-01-02',
|
||||
workDate: '2025-02-10',
|
||||
workOrderNo: 'KD-PL-250120-01',
|
||||
processType: 'screen',
|
||||
productName: '스크린 셔터 (표준형)',
|
||||
specification: '6500x2400',
|
||||
productionQty: 1,
|
||||
goodQty: 1,
|
||||
defectQty: 0,
|
||||
defectRate: 0.0,
|
||||
inspection: true,
|
||||
packaging: true,
|
||||
worker: '김성산',
|
||||
},
|
||||
{
|
||||
id: 'wr-3',
|
||||
lotNo: 'KD-TS-250210-01-01',
|
||||
workDate: '2025-02-10',
|
||||
workOrderNo: 'KD-PL-250120-01',
|
||||
processType: 'screen',
|
||||
productName: '스크린 셔터 (표준형)',
|
||||
specification: '7660x2550',
|
||||
productionQty: 1,
|
||||
goodQty: 1,
|
||||
defectQty: 0,
|
||||
defectRate: 0.0,
|
||||
inspection: true,
|
||||
packaging: true,
|
||||
worker: '김성산',
|
||||
},
|
||||
{
|
||||
id: 'wr-4',
|
||||
lotNo: 'KD-TS-250208-01-01',
|
||||
workDate: '2025-02-08',
|
||||
workOrderNo: 'KD-PL-250118-01',
|
||||
processType: 'slat',
|
||||
productName: '철재 슬랫 셔터',
|
||||
specification: '5000x3000',
|
||||
productionQty: 2,
|
||||
goodQty: 2,
|
||||
defectQty: 0,
|
||||
defectRate: 0.0,
|
||||
inspection: true,
|
||||
packaging: true,
|
||||
worker: '박철호',
|
||||
},
|
||||
{
|
||||
id: 'wr-5',
|
||||
lotNo: 'KD-TS-250205-01-01',
|
||||
workDate: '2025-02-05',
|
||||
workOrderNo: 'KD-PL-250115-01',
|
||||
processType: 'bending',
|
||||
productName: '방화셔터 절곡 부품 SET',
|
||||
specification: '3000x4000',
|
||||
productionQty: 3,
|
||||
goodQty: 2,
|
||||
defectQty: 1,
|
||||
defectRate: 33.3,
|
||||
inspection: true,
|
||||
packaging: true,
|
||||
worker: '최절곡',
|
||||
},
|
||||
{
|
||||
id: 'wr-6',
|
||||
lotNo: 'KD-TS-250203-01-01',
|
||||
workDate: '2025-02-03',
|
||||
workOrderNo: 'KD-PL-250113-01',
|
||||
processType: 'screen',
|
||||
productName: '스크린 셔터 (프리미엄)',
|
||||
specification: '9000x3200',
|
||||
productionQty: 1,
|
||||
goodQty: 1,
|
||||
defectQty: 0,
|
||||
defectRate: 0.0,
|
||||
inspection: true,
|
||||
packaging: true,
|
||||
worker: '이성산',
|
||||
},
|
||||
{
|
||||
id: 'wr-7',
|
||||
lotNo: 'KD-TS-250201-01-01',
|
||||
workDate: '2025-02-01',
|
||||
workOrderNo: 'KD-PL-250111-01',
|
||||
processType: 'slat',
|
||||
productName: '알루미늄 슬랫 셔터',
|
||||
specification: '4500x2800',
|
||||
productionQty: 2,
|
||||
goodQty: 1,
|
||||
defectQty: 1,
|
||||
defectRate: 50.0,
|
||||
inspection: true,
|
||||
packaging: true,
|
||||
worker: '박철호',
|
||||
},
|
||||
{
|
||||
id: 'wr-8',
|
||||
lotNo: 'KD-TS-250130-01-01',
|
||||
workDate: '2025-01-30',
|
||||
workOrderNo: 'KD-PL-250109-01',
|
||||
processType: 'screen',
|
||||
productName: '스크린 셔터 (표준형)',
|
||||
specification: '7000x2600',
|
||||
productionQty: 1,
|
||||
goodQty: 1,
|
||||
defectQty: 0,
|
||||
defectRate: 0.0,
|
||||
inspection: true,
|
||||
packaging: true,
|
||||
worker: '김성산',
|
||||
},
|
||||
];
|
||||
|
||||
// 통계 계산
|
||||
export function calculateWorkResultStats(results: WorkResult[]): WorkResultStats {
|
||||
const totalProduction = results.reduce((sum, r) => sum + r.productionQty, 0);
|
||||
const totalGood = results.reduce((sum, r) => sum + r.goodQty, 0);
|
||||
const totalDefect = results.reduce((sum, r) => sum + r.defectQty, 0);
|
||||
const defectRate = totalProduction > 0 ? (totalDefect / totalProduction) * 100 : 0;
|
||||
|
||||
return {
|
||||
totalProduction,
|
||||
totalGood,
|
||||
totalDefect,
|
||||
defectRate: Math.round(defectRate * 10) / 10,
|
||||
};
|
||||
}
|
||||
|
||||
// 기본 통계
|
||||
export const mockStats: WorkResultStats = calculateWorkResultStats(mockWorkResults);
|
||||
@@ -1,238 +0,0 @@
|
||||
import type {
|
||||
ComprehensiveAnalysisData,
|
||||
} from './types';
|
||||
|
||||
// 종합 경영 분석 목데이터
|
||||
export const comprehensiveAnalysisMockData: ComprehensiveAnalysisData = {
|
||||
// 오늘의 이슈
|
||||
todayIssue: {
|
||||
filterOptions: ['전체필터', '문서요청', '계약요청', '결재요청'],
|
||||
items: [
|
||||
{
|
||||
id: 'issue-1',
|
||||
category: '문서요청',
|
||||
description: '매입 XX일 후 완료처리/대물처리 처리',
|
||||
requiresApproval: true,
|
||||
time: '09:30',
|
||||
},
|
||||
{
|
||||
id: 'issue-2',
|
||||
category: '문서요청',
|
||||
description: '매입 XX 처리',
|
||||
requiresApproval: false,
|
||||
time: '10:15',
|
||||
},
|
||||
{
|
||||
id: 'issue-3',
|
||||
category: '문서요청',
|
||||
description: '문서요청 승인 / 미완료처리 중',
|
||||
requiresApproval: false,
|
||||
time: '11:00',
|
||||
},
|
||||
{
|
||||
id: 'issue-4',
|
||||
category: '계약요청',
|
||||
description: '문서의 후 XXXXXXXX처리',
|
||||
requiresApproval: true,
|
||||
time: '14:30',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// 당월 예상 지출 내역
|
||||
monthlyExpense: {
|
||||
cards: [
|
||||
{ id: 'expense-1', label: '노동 외상 매출금 비율', amount: 1123000 },
|
||||
{ id: 'expense-2', label: '노동 외상 매출금 비율', amount: 3123000 },
|
||||
{ id: 'expense-3', label: '노동 외상 매출금 비율', amount: 1123000 },
|
||||
{ id: 'expense-4', label: '노동 외상 매출금 비율', amount: 3123000 },
|
||||
],
|
||||
checkPoints: [
|
||||
{
|
||||
id: 'expense-cp-1',
|
||||
type: 'warning',
|
||||
message: '이번 달 예상 지출은',
|
||||
highlight: 'XXX,XX원이 될 것으로 예상되어 이번 달의 결산이 약간 미흡합니다.',
|
||||
},
|
||||
{
|
||||
id: 'expense-cp-2',
|
||||
type: 'success',
|
||||
message: '이번 달 예상 지출은 0000000원에 비해 발생한 잔액이 부족합니다.',
|
||||
},
|
||||
{
|
||||
id: 'expense-cp-3',
|
||||
type: 'info',
|
||||
message: '이번 달 예상 지출은 xx xxxxx원으로 상환을 낙관할 수 있습니다.',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// 카드/가지급금 관리
|
||||
cardManagement: {
|
||||
cards: [
|
||||
{ id: 'card-1', label: '노동 외상 매출금 비율', amount: 1123000 },
|
||||
{ id: 'card-2', label: '노동 외상 매출금 비율', amount: 3123000 },
|
||||
{ id: 'card-3', label: '노동 외상 매출금 비율', amount: 1123000 },
|
||||
{ id: 'card-4', label: '노동 외상 매출금 비율', amount: 1123000 },
|
||||
],
|
||||
checkPoints: [
|
||||
{
|
||||
id: 'card-cp-1',
|
||||
type: 'warning',
|
||||
message: '김철민 외 카드 미결제/미수금/미환급/이월이 발생 하여',
|
||||
highlight: '대조가 필요합니다.',
|
||||
},
|
||||
{
|
||||
id: 'card-cp-2',
|
||||
type: 'info',
|
||||
message: '회사 가지급금 1,000만원 → 3% 초과/부족 발 →',
|
||||
highlight: '개선방안: 매출 신규영업과 대상',
|
||||
},
|
||||
{
|
||||
id: 'card-cp-3',
|
||||
type: 'success',
|
||||
message: '현재 미지급금 감소추세 → 목표대비 양호 →',
|
||||
highlight: '1개월 순영업성과',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// 접대비 현황
|
||||
entertainment: {
|
||||
cards: [
|
||||
{ id: 'ent-1', label: '노동 외상 매출금 비율', amount: 1123000 },
|
||||
{ id: 'ent-2', label: '노동 외상 매출금 비율', amount: 1123000 },
|
||||
],
|
||||
checkPoints: [
|
||||
{
|
||||
id: 'ent-cp-1',
|
||||
type: 'warning',
|
||||
message: '김철민 씨 사용액 1,000원에 중복지출로',
|
||||
highlight: '비용 반영 준비가 필요합니다.',
|
||||
},
|
||||
{
|
||||
id: 'ent-cp-2',
|
||||
type: 'info',
|
||||
message: '관리비 이번 달 2% X X원이 비용처리로 이재현 증분의 확인이 필요합니다.',
|
||||
},
|
||||
{
|
||||
id: 'ent-cp-3',
|
||||
type: 'error',
|
||||
message: '김철민 고객접대비가 목표대비',
|
||||
highlight: '5%초과로 허용 초과처리 되었습니다.',
|
||||
},
|
||||
{
|
||||
id: 'ent-cp-4',
|
||||
type: 'warning',
|
||||
message: '이채호 외 3명에 대한 XXXXXXXXX 비용처리 불가입니다.',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// 복리후생비 현황
|
||||
welfare: {
|
||||
cards: [
|
||||
{ id: 'wf-1', label: '노동 복리후생비 대비 지출', amount: 3123000 },
|
||||
{ id: 'wf-2', label: '노동 복리후생비 수당 내역', amount: 1123000 },
|
||||
{ id: 'wf-3', label: '방송일 복리후생비 지출 내역', amount: 30123000 },
|
||||
{ id: 'wf-4', label: '방송일 복리후생비 수당 내역', amount: 3123000 },
|
||||
],
|
||||
checkPoints: [
|
||||
{
|
||||
id: 'wf-cp-1',
|
||||
type: 'warning',
|
||||
message: '직원 월 복리후생비 비율이 정상 범위(5~20%)에서 벗어난 것이 발견됨',
|
||||
},
|
||||
{
|
||||
id: 'wf-cp-2',
|
||||
type: 'info',
|
||||
message: '복리후생비 월 직원혜택 비 지출에 관심(00백)원을 초과했습니다. 초과분은 근로소득 과세대상입니다.',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// 미수금 현황
|
||||
receivable: {
|
||||
cards: [
|
||||
{
|
||||
id: 'rcv-1',
|
||||
label: '노동 외상 매출금 비율',
|
||||
amount: 30123000,
|
||||
subAmount: 8000000,
|
||||
subLabel: '미결',
|
||||
previousAmount: 5000000,
|
||||
previousLabel: '비용',
|
||||
},
|
||||
{
|
||||
id: 'rcv-2',
|
||||
label: '발행된 매출금 비율',
|
||||
amount: 30123000,
|
||||
subAmount: 8000000,
|
||||
subLabel: '미결',
|
||||
previousAmount: 5000000,
|
||||
previousLabel: '비용',
|
||||
},
|
||||
{
|
||||
id: 'rcv-3',
|
||||
label: '금일 매출원가 (외상제외)',
|
||||
amount: 3123000,
|
||||
subAmount: 800000,
|
||||
subLabel: '미결',
|
||||
previousAmount: 100000,
|
||||
previousLabel: '비용',
|
||||
},
|
||||
{
|
||||
id: 'rcv-4',
|
||||
label: '금일 수금원가 (외상제외)',
|
||||
amount: 3123000,
|
||||
subAmount: 500000,
|
||||
subLabel: '미결',
|
||||
previousAmount: 100000,
|
||||
previousLabel: '비용',
|
||||
},
|
||||
],
|
||||
checkPoints: [
|
||||
{
|
||||
id: 'rcv-cp-1',
|
||||
type: 'warning',
|
||||
message: '이부서 가장 큰의 미수금 3/21,500/20원 정도, 월수 초과가 발생합니다.',
|
||||
},
|
||||
{
|
||||
id: 'rcv-cp-2',
|
||||
type: 'error',
|
||||
message: '[주식회사]의 미수금 4,300만원으로 한계 미수금 초과입니다.',
|
||||
highlight: '거래 중단이 필요합니다.',
|
||||
},
|
||||
],
|
||||
hasDetailButton: true,
|
||||
detailButtonLabel: '거래처별 미수금 현황',
|
||||
detailButtonPath: '/accounting/receivables-status',
|
||||
},
|
||||
|
||||
// 채권추심 현황
|
||||
debtCollection: {
|
||||
cards: [
|
||||
{ id: 'debt-1', label: '노동 외상 매출금 비율', amount: 30123000 },
|
||||
{ id: 'debt-2', label: '노동 외상 매출금 비율', amount: 30123000 },
|
||||
{ id: 'debt-3', label: '노동 외상 매출금 비율', amount: 3123000 },
|
||||
{ id: 'debt-4', label: '노동 외상 매출금 비율', amount: 3123000 },
|
||||
],
|
||||
checkPoints: [
|
||||
{
|
||||
id: 'debt-cp-1',
|
||||
type: 'info',
|
||||
message: '[주식회사]의 건 직급상한 건수 첫째, 팔로 결제월이 약 3건 소요 예정입니다.',
|
||||
},
|
||||
{
|
||||
id: 'debt-cp-2',
|
||||
type: 'warning',
|
||||
message: '[주식회사]의 건 수 총 3건 중에, 현재 1건 보류상태입니다.',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
// 금액 포맷 함수
|
||||
export const formatAmount = (amount: number): string => {
|
||||
return new Intl.NumberFormat('ko-KR').format(amount) + '원';
|
||||
};
|
||||
Reference in New Issue
Block a user