[feat] negodata/front: 상품 UI 보강 — 매입가·판매가 입력 등

상품 등록/목록·엑셀 업로드 화면에 매입가·판매가 등 가격 필드 반영.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Mina Choi 2026-06-29 13:32:13 +09:00
parent a40257ddc1
commit b42d084063
5 changed files with 11 additions and 11 deletions

View File

@ -171,7 +171,9 @@ function toItemCreate(row: RawRow): ItemCreate {
delivery_type: DELIVERY_LABEL_TO_CODE[row.delivery_type.trim()] ?? undefined,
vat_yn: row.vat_yn.trim() ? parseYn(row.vat_yn) : undefined,
delivery_fee_yn: row.delivery_fee_yn.trim() ? parseYn(row.delivery_fee_yn) : undefined,
internet_lowest_price_yn: false,
// minPrice(최저한도) = 인터넷 최저가(실값) → internet_lowest_price 로 저장(수기 폼과 동일).
internet_lowest_price: row.minPrice,
internet_lowest_price_yn: row.minPrice > 0,
};
}

View File

@ -12,7 +12,7 @@ import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Sheet } from '@/components/ui/sheet';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { type Product, toMinPrice } from '../types';
import { type Product } from '../types';
// 폼 검증 스키마. 필수: 상품명/상품코드/단가/최저가. 나머지는 선택.
const schema = z.object({
@ -60,7 +60,7 @@ function buildDefaults(mode: 'create' | 'edit', product: Product | null): FormVa
code: product.code || '',
category: product.category || '',
price: product.price || 0,
minPrice: toMinPrice(product.price),
minPrice: product.internet_lowest_price ?? 0,
modelName: product.model_name || '',
specification: product.spec || '',
manufacturer: product.manufacturer || '',
@ -129,7 +129,7 @@ export function ProductFormSheet({
const deliveryTypes = DELIVERY_TYPE_OPTIONS;
// minPrice는 화면 전용(서버 미전송). 검증된 값만 payload로.
// minPrice = 인터넷 최저가(실값) → internet_lowest_price 로 저장한다.
const onValid = async (v: FormValues) => {
// 기존 카테고리면 그 category_type(id) 재사용, 처음 쓰는 카테고리면 max+1 부여.
const categoryName = v.category.trim();
@ -151,6 +151,7 @@ export function ProductFormSheet({
vat_yn: v.vatYn,
delivery_fee_yn: v.deliveryFeeYn,
internet_lowest_price_yn: v.internetLowestPriceYn,
internet_lowest_price: v.minPrice,
purchase_price: v.purchasePrice,
selling_price: v.sellingPrice,
};

View File

@ -2,7 +2,7 @@ import { Image as ImageIcon } from 'lucide-react';
import { Badge } from '@/components/ui/badge';
import { DataTable } from '@/components/ui/data-table';
import { TablePagination } from '@/components/ui/table-pagination';
import { type Product, toMinPrice } from '../types';
import { type Product } from '../types';
type ProductTableProps = {
data: Product[];
@ -91,7 +91,7 @@ export function ProductTable({
header: '인터넷 최저가',
align: 'right',
cellClassName: 'font-mono font-semibold text-rose-600 dark:text-rose-400',
cell: (prod) => `₩${(prod.minPrice || toMinPrice(prod.price)).toLocaleString()}`,
cell: (prod) => (prod.internet_lowest_price != null ? `₩${Number(prod.internet_lowest_price).toLocaleString()}` : '-'),
},
]}
/>

View File

@ -12,7 +12,7 @@ import type { ReqUpdateItem } from '@/api/generated/model/reqUpdateItem';
import type { ResItem } from '@/api/generated/model/resItem';
import type { ItemData } from '@/api/generated/model/itemData';
import type { BulkFailure } from '@/lib/excel';
import { type Product, toMinPrice } from '../types';
import { type Product } from '../types';
// 엑셀 중복검사 + 최저가 모달은 "현재 페이지 밖"의 상품도 코드/ID로 조회해야 해서
// 전체 목록(최대 100건)을 따로 받는다. (카테고리 목록은 더 이상 여기서 만들지 않는다 — 아래 categoriesQuery.)
@ -20,7 +20,7 @@ const META_PARAMS: ListItemsParams = { size: 100 };
// 서버 ItemData → UI Product (화면 전용 파생 필드 부여).
function toProduct(it: ItemData): Product {
return { ...it, id: it.item_id, minPrice: toMinPrice(it.price), status: 'ACTIVE' };
return { ...it, id: it.item_id, minPrice: it.internet_lowest_price ?? 0, status: 'ACTIVE' };
}
// 서버 공통응답(result.success=false)을 한글 사유로 변환. 정상이면 null.

View File

@ -1,4 +1 @@
export type { Product } from '@/types';
// 인터넷 최저가 데모 산정(표준 단가의 83%). 서버 미연동 — 표시/초기값 용도.
export const toMinPrice = (price?: number | null) => Math.round((price || 0) * 0.83);