feat: [부서관리] 기능 보완 - 필드 확장, 검색/필터, UI 개선
- Department 타입에 code, description, isActive, sortOrder 필드 추가 - DepartmentDialog: Zod + react-hook-form 폼 검증 (5개 필드) - DepartmentToolbar: 상태 필터(전체/활성/비활성) + 검색 기능 - DepartmentTree: 트리 필터링 (검색어 + 상태) - DepartmentTreeItem: 코드 Badge, 부서명 볼드, 설명 표시, 체크박스 크기 조정 - convertApiToLocal에서 누락 필드 매핑 복원
This commit is contained in:
@@ -162,12 +162,7 @@ export function PricingListClient({
|
||||
|
||||
// 네비게이션 핸들러
|
||||
const handleRegister = (item: PricingListItem) => {
|
||||
// item_type_code는 품목 정보에서 자동으로 가져오므로 URL에 포함하지 않음
|
||||
const params = new URLSearchParams();
|
||||
params.set('mode', 'new');
|
||||
if (item.itemId) params.set('itemId', item.itemId);
|
||||
if (item.itemCode) params.set('itemCode', item.itemCode);
|
||||
router.push(`/sales/pricing-management?${params.toString()}`);
|
||||
router.push(`/sales/pricing-management/create?itemId=${item.itemId}`);
|
||||
};
|
||||
|
||||
const handleEdit = (item: PricingListItem) => {
|
||||
@@ -221,12 +216,12 @@ export function PricingListClient({
|
||||
) => {
|
||||
const { isSelected, onToggle } = handlers;
|
||||
|
||||
// 행 클릭 핸들러: 등록되지 않은 항목은 등록, 등록된 항목은 수정
|
||||
// 행 클릭 핸들러: 등록되지 않은 항목은 등록, 등록된 항목은 상세 조회
|
||||
const handleRowClick = () => {
|
||||
if (item.status === 'not_registered') {
|
||||
handleRegister(item);
|
||||
} else {
|
||||
handleEdit(item);
|
||||
router.push(`/sales/pricing-management/${item.id}`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -310,7 +305,7 @@ export function PricingListClient({
|
||||
statusBadge={renderStatusBadge(item)}
|
||||
isSelected={isSelected}
|
||||
onToggleSelection={onToggle}
|
||||
onCardClick={() => item.status !== 'not_registered' ? handleEdit(item) : handleRegister(item)}
|
||||
onCardClick={() => item.status !== 'not_registered' ? router.push(`/sales/pricing-management/${item.id}`) : handleRegister(item)}
|
||||
infoGrid={
|
||||
<div className="grid grid-cols-2 gap-x-4 gap-y-3">
|
||||
{item.specification && (
|
||||
|
||||
@@ -171,7 +171,7 @@ export async function getPricingById(id: string): Promise<PricingData | null> {
|
||||
}
|
||||
|
||||
export async function getItemInfo(itemId: string): Promise<ItemInfo | null> {
|
||||
interface ItemApiItem { id: number; code: string; name: string; item_type: string; specification?: string; unit?: string }
|
||||
interface ItemApiItem { id: number; item_code: string; code?: string; name: string; item_type: string; specification?: string; unit?: string }
|
||||
const result = await executeServerAction<ItemApiItem>({
|
||||
url: `${API_URL}/api/v1/items/${itemId}`,
|
||||
errorMessage: '품목 조회에 실패했습니다.',
|
||||
@@ -179,7 +179,7 @@ export async function getItemInfo(itemId: string): Promise<ItemInfo | null> {
|
||||
if (!result.success || !result.data) return null;
|
||||
const item = result.data;
|
||||
return {
|
||||
id: String(item.id), itemCode: item.code, itemName: item.name,
|
||||
id: String(item.id), itemCode: item.item_code || item.code || '', itemName: item.name,
|
||||
itemType: item.item_type || 'PT', specification: item.specification || undefined, unit: item.unit || 'EA',
|
||||
};
|
||||
}
|
||||
@@ -243,10 +243,17 @@ export async function finalizePricing(id: string): Promise<{ success: boolean; d
|
||||
interface ItemApiData {
|
||||
id: number;
|
||||
item_type: string; // FG, PT, SM, RM, CS (품목 유형)
|
||||
code: string;
|
||||
item_code?: string;
|
||||
code?: string;
|
||||
name: string;
|
||||
specification?: string;
|
||||
unit: string;
|
||||
category_id: number | null;
|
||||
attributes?: {
|
||||
salesPrice?: number;
|
||||
purchasePrice?: number;
|
||||
[key: string]: unknown;
|
||||
} | null;
|
||||
created_at: string;
|
||||
deleted_at: string | null;
|
||||
}
|
||||
@@ -330,11 +337,11 @@ export async function getPricingListData(): Promise<PricingListItem[]> {
|
||||
|
||||
const [itemsResult, pricingResult] = await Promise.all([
|
||||
executeServerAction<ItemsPaginatedResponse>({
|
||||
url: `${API_URL}/api/v1/items?group_id=1&size=100`,
|
||||
url: `${API_URL}/api/v1/items?group_id=1&size=10000`,
|
||||
errorMessage: '품목 목록 조회에 실패했습니다.',
|
||||
}),
|
||||
executeServerAction<PricingPaginatedResponse>({
|
||||
url: `${API_URL}/api/v1/pricing?size=100`,
|
||||
url: `${API_URL}/api/v1/pricing?size=10000`,
|
||||
errorMessage: '단가 목록 조회에 실패했습니다.',
|
||||
}),
|
||||
]);
|
||||
@@ -354,10 +361,13 @@ export async function getPricingListData(): Promise<PricingListItem[]> {
|
||||
const key = `${item.item_type}_${item.id}`;
|
||||
const pricing = pricingMap.get(key);
|
||||
|
||||
const itemCode = item.item_code || item.code || '';
|
||||
const specification = item.specification || undefined;
|
||||
|
||||
if (pricing) {
|
||||
return {
|
||||
id: String(pricing.id), itemId: String(item.id), itemCode: item.code, itemName: item.name,
|
||||
itemType: mapItemTypeForList(item.item_type), specification: undefined, unit: item.unit || 'EA',
|
||||
id: String(pricing.id), itemId: String(item.id), itemCode, itemName: item.name,
|
||||
itemType: mapItemTypeForList(item.item_type), specification, unit: item.unit || 'EA',
|
||||
purchasePrice: pricing.purchase_price ? parseFloat(pricing.purchase_price) : undefined,
|
||||
processingCost: pricing.processing_cost ? parseFloat(pricing.processing_cost) : undefined,
|
||||
salesPrice: pricing.sales_price ? parseFloat(pricing.sales_price) : undefined,
|
||||
@@ -367,10 +377,15 @@ export async function getPricingListData(): Promise<PricingListItem[]> {
|
||||
currentRevision: 0, isFinal: pricing.is_final, itemTypeCode: item.item_type,
|
||||
};
|
||||
} else {
|
||||
// prices 미등록 → items.attributes에서 참고 단가 표시
|
||||
const attrSalesPrice = item.attributes?.salesPrice ? Number(item.attributes.salesPrice) : undefined;
|
||||
const attrPurchasePrice = item.attributes?.purchasePrice ? Number(item.attributes.purchasePrice) : undefined;
|
||||
|
||||
return {
|
||||
id: `item_${item.id}`, itemId: String(item.id), itemCode: item.code, itemName: item.name,
|
||||
itemType: mapItemTypeForList(item.item_type), specification: undefined, unit: item.unit || 'EA',
|
||||
purchasePrice: undefined, processingCost: undefined, salesPrice: undefined, marginRate: undefined,
|
||||
id: `item_${item.id}`, itemId: String(item.id), itemCode, itemName: item.name,
|
||||
itemType: mapItemTypeForList(item.item_type), specification, unit: item.unit || 'EA',
|
||||
purchasePrice: attrPurchasePrice, processingCost: undefined,
|
||||
salesPrice: attrSalesPrice, marginRate: undefined,
|
||||
effectiveDate: undefined, status: 'not_registered' as const,
|
||||
currentRevision: 0, isFinal: false, itemTypeCode: item.item_type,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user