- CEO 대시보드 전 섹션 공통 컴포넌트 기반 리팩토링 (SectionCard, StatItem 등) - CalendarSection 일정 CRUD 기능 확장 - validation.ts → validation/ 모듈 분리 (item-schemas, form-schemas, common, utils) - CLAUDE.md Git Workflow 섹션 추가 (develop/main 플로우 정의) - Jenkinsfile CI/CD 파이프라인 정비 (Slack 알림 추가) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
111 lines
3.0 KiB
TypeScript
111 lines
3.0 KiB
TypeScript
/**
|
|
* 공통 Zod 검증 스키마
|
|
*
|
|
* 품목명, 품목유형, 날짜, 숫자, BOM 등 여러 스키마에서 공유하는 기본 블록
|
|
*/
|
|
|
|
import { z } from 'zod';
|
|
|
|
// ===== 내부 전용 스키마 =====
|
|
|
|
/**
|
|
* 품목 코드 검증
|
|
* 형식: {업체코드}-{품목유형}-{일련번호}
|
|
* 예: KD-FG-001
|
|
*
|
|
* 현재 사용하지 않음 (품목 코드 자동 생성)
|
|
*/
|
|
export const _itemCodeSchema = z.string()
|
|
.min(1, '품목 코드를 입력해주세요')
|
|
.regex(
|
|
/^[A-Z0-9]+-[A-Z]{2}-\d+$/,
|
|
'품목 코드 형식이 올바르지 않습니다 (예: KD-FG-001)'
|
|
);
|
|
|
|
// ===== 공통 필드 스키마 =====
|
|
|
|
/**
|
|
* 품목명 검증
|
|
*/
|
|
export const itemNameSchema = z.preprocess(
|
|
(val) => val === undefined || val === null ? "" : val,
|
|
z.string().min(1, '품목명을 입력해주세요').max(200, '품목명은 200자 이내로 입력해주세요')
|
|
);
|
|
|
|
/**
|
|
* 품목 유형 검증
|
|
*/
|
|
export const itemTypeSchema = z.enum(['FG', 'PT', 'SM', 'RM', 'CS'], {
|
|
message: '품목 유형을 선택해주세요',
|
|
});
|
|
|
|
/**
|
|
* 단위 검증
|
|
*
|
|
* 현재 사용하지 않음 (materialUnitSchema로 대체)
|
|
*/
|
|
export const _unitSchema = z.string()
|
|
.min(1, '단위를 입력해주세요')
|
|
.max(20, '단위는 20자 이내로 입력해주세요');
|
|
|
|
/**
|
|
* 양수 검증 (가격, 수량 등)
|
|
* undefined나 빈 문자열은 검증하지 않음
|
|
*/
|
|
export const positiveNumberSchema = z.union([
|
|
z.number().positive('0보다 큰 값을 입력해주세요'),
|
|
z.string().transform((val) => parseFloat(val)).pipe(z.number().positive('0보다 큰 값을 입력해주세요')),
|
|
z.undefined(),
|
|
z.null(),
|
|
z.literal('')
|
|
]).optional();
|
|
|
|
/**
|
|
* 날짜 검증 (YYYY-MM-DD)
|
|
* 빈 문자열이나 undefined는 검증하지 않음
|
|
*/
|
|
export const dateSchema = z.preprocess(
|
|
(val) => {
|
|
if (val === undefined || val === null || val === '') return undefined;
|
|
return val;
|
|
},
|
|
z.string()
|
|
.regex(/^\d{4}-\d{2}-\d{2}$/, '날짜 형식이 올바르지 않습니다 (YYYY-MM-DD)')
|
|
.optional()
|
|
);
|
|
|
|
// ===== BOM 라인 스키마 =====
|
|
|
|
/**
|
|
* 절곡품 전개도 상세 스키마
|
|
*/
|
|
export const bendingDetailSchema = z.object({
|
|
id: z.string(),
|
|
no: z.number().int().positive(),
|
|
input: z.number(),
|
|
elongation: z.number().default(-1),
|
|
calculated: z.number(),
|
|
sum: z.number(),
|
|
shaded: z.boolean().default(false),
|
|
aAngle: z.number().optional(),
|
|
});
|
|
|
|
/**
|
|
* BOM 라인 스키마
|
|
*/
|
|
export const bomLineSchema = z.object({
|
|
id: z.string(),
|
|
childItemCode: z.string().min(1, '하위 품목 코드를 입력해주세요'),
|
|
childItemName: z.string().min(1, '하위 품목명을 입력해주세요'),
|
|
quantity: z.number().positive('수량은 0보다 커야 합니다'),
|
|
unit: z.string().min(1, '단위를 입력해주세요'),
|
|
unitPrice: positiveNumberSchema,
|
|
quantityFormula: z.string().optional(),
|
|
note: z.string().max(500).optional(),
|
|
|
|
// 절곡품 관련
|
|
isBending: z.boolean().optional(),
|
|
bendingDiagram: z.string().url().optional(),
|
|
bendingDetails: z.array(bendingDetailSchema).optional(),
|
|
});
|