fix: TypeScript 타입 오류 수정 및 설정 페이지 추가
- BOMItem Omit 타입 시그니처 통일 (useTemplateManagement, SectionsTab, ItemMasterContext) - HeadersInit → Record<string, string> 타입 변경 - Zustand useShallow 마이그레이션 (zustand/react/shallow) - DataTable, ListPageTemplate 제네릭 타입 제약 추가 - 설정 관리 페이지 추가 (직급, 직책, 휴가정책, 근무일정, 권한) - HR 관리 페이지 추가 (급여, 휴가) - 단가관리 페이지 리팩토링 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,8 +14,9 @@ export type MaterialType = typeof MATERIAL_TYPES[number];
|
||||
/**
|
||||
* Material 타입인지 확인
|
||||
*/
|
||||
export function isMaterialType(itemType: string | null | undefined): boolean {
|
||||
return itemType ? MATERIAL_TYPES.includes(itemType as MaterialType) : false;
|
||||
export function isMaterialType(itemType: string | null | undefined): itemType is MaterialType {
|
||||
if (!itemType) return false;
|
||||
return (MATERIAL_TYPES as readonly string[]).includes(itemType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -34,11 +35,13 @@ export function convertStandardFieldsToOptions(data: DynamicFormData): {
|
||||
const remainingData: DynamicFormData = {};
|
||||
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
// standard_로 시작하는 필드 또는 옵션 관련 필드 탐지
|
||||
const isStandardField = key.startsWith('standard_') ||
|
||||
key.startsWith('option_') ||
|
||||
/^[0-9]+_standard_/.test(key) || // "{id}_standard_1" 형식
|
||||
/^[0-9]+_option_/.test(key); // "{id}_option_1" 형식
|
||||
// 규격 옵션 필드 탐지 (specification_*, standard_*, option_* 패턴)
|
||||
const isStandardField = key.startsWith('specification_') || // specification_1, specification_2
|
||||
key.startsWith('standard_') || // standard_1, standard_2
|
||||
key.startsWith('option_') || // option_1, option_2
|
||||
/^[0-9]+_specification_/.test(key) || // "{id}_specification_1" 형식
|
||||
/^[0-9]+_standard_/.test(key) || // "{id}_standard_1" 형식
|
||||
/^[0-9]+_option_/.test(key); // "{id}_option_1" 형식
|
||||
|
||||
if (isStandardField && value && typeof value === 'string' && value.trim()) {
|
||||
// standard_* 필드는 options 배열로 변환
|
||||
@@ -82,18 +85,29 @@ export function convertOptionsToStandardFields(
|
||||
* Material 저장 데이터 변환 (등록/수정 공통)
|
||||
*
|
||||
* 프론트엔드 폼 데이터를 백엔드 Material API 형식으로 변환
|
||||
*
|
||||
* - SM(철판), RM(원자재): standard_* 필드 조합으로 specification 자동 생성
|
||||
* - CS(소모품): spec 필드에 직접 입력한 값 사용
|
||||
*/
|
||||
export function transformMaterialDataForSave(
|
||||
data: DynamicFormData,
|
||||
itemType: string
|
||||
): DynamicFormData {
|
||||
// standard_* 필드들을 options 배열로 변환
|
||||
const { options, specification, remainingData } = convertStandardFieldsToOptions(data);
|
||||
const { options, specification: optionSpecification, remainingData } = convertStandardFieldsToOptions(data);
|
||||
|
||||
// Material 품목코드 생성: 품목명-규격(옵션조합)
|
||||
// CS(소모품)은 spec 필드 직접 입력, SM/RM은 옵션 조합
|
||||
const isConsumable = itemType === 'CS';
|
||||
const directSpec = (remainingData.spec || remainingData.specification || '') as string;
|
||||
const finalSpecification = isConsumable
|
||||
? (directSpec || null) // CS: 직접 입력한 spec 값 사용
|
||||
: (optionSpecification || null); // SM, RM: 옵션 조합값 사용
|
||||
|
||||
// Material 품목코드 생성: 품목명-규격
|
||||
const materialName = (remainingData.name || remainingData.item_name || '') as string;
|
||||
const specForCode = finalSpecification || '';
|
||||
const materialCode = remainingData.code ||
|
||||
(specification ? `${materialName}-${specification}` : materialName);
|
||||
(specForCode ? `${materialName}-${specForCode}` : materialName);
|
||||
|
||||
return {
|
||||
...remainingData,
|
||||
@@ -101,11 +115,12 @@ export function transformMaterialDataForSave(
|
||||
material_type: (remainingData.product_type as string) || itemType,
|
||||
remarks: remainingData.note as string, // note → remarks 변환
|
||||
material_code: materialCode,
|
||||
specification: specification || null, // 옵션 조합값을 specification으로 저장
|
||||
specification: finalSpecification, // CS: 직접 입력값, SM/RM: 옵션 조합값
|
||||
options: options.length > 0 ? options : null, // options 배열로 저장
|
||||
// 불필요한 필드 제거
|
||||
code: undefined,
|
||||
product_type: undefined,
|
||||
note: undefined,
|
||||
spec: undefined, // spec → specification으로 통합됨
|
||||
};
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ const itemNameSchema = z.preprocess(
|
||||
* 품목 유형 검증
|
||||
*/
|
||||
const itemTypeSchema = z.enum(['FG', 'PT', 'SM', 'RM', 'CS'], {
|
||||
errorMap: () => ({ message: '품목 유형을 선택해주세요' }),
|
||||
message: '품목 유형을 선택해주세요',
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user