[refactor] negodata/front: 전역 타입 정리 — 공유(2+) 타입만 글로벌, 중복 제거
- src/types.ts: DB 미러 중복 제거, generated DTO 기반 별칭만(Product/Partner/NegotiationCard/PageType) - products/partners 의 로컬 Product/Partner 중복 → 글로벌 단일 정본 재수출 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
eb6612af1c
commit
ae103fd0f1
@ -1,11 +1,4 @@
|
||||
import type { SupplierData } from '@/api/generated/model/supplierData';
|
||||
|
||||
// UI에서 쓰는 협력사 타입. 서버 SupplierData에 화면 전용 파생 필드만 얹는다.
|
||||
// (level/rank/status 등 서버 미연동 가짜 필드는 두지 않는다 — 표시 가능한 건 priority뿐.)
|
||||
export type Partner = SupplierData & {
|
||||
deleted?: boolean;
|
||||
id?: string;
|
||||
};
|
||||
export type { Partner } from '@/types';
|
||||
|
||||
// 우선순위 필터 목록. 'ALL'은 필터 전용(폼에서는 제외).
|
||||
export const prioritiesList = ['ALL', 'HIGH', 'MEDIUM', 'LOW'];
|
||||
|
||||
@ -1,14 +1,4 @@
|
||||
import type { ItemData } from '@/api/generated/model/itemData';
|
||||
|
||||
// UI에서 쓰는 상품 타입. 서버 ItemData에 화면 전용 파생 필드를 얹는다.
|
||||
export type Product = ItemData & {
|
||||
deleted?: boolean;
|
||||
id?: string;
|
||||
minPrice?: number;
|
||||
status?: string;
|
||||
};
|
||||
|
||||
// 분류 카테고리는 서버 items 에서 distinct 로 파생한다(useProducts). 하드코딩 상수 제거됨.
|
||||
export type { Product } from '@/types';
|
||||
|
||||
// 인터넷 최저가 데모 산정(표준 단가의 83%). 서버 미연동 — 표시/초기값 용도.
|
||||
export const toMinPrice = (price?: number | null) => Math.round((price || 0) * 0.83);
|
||||
|
||||
@ -1,306 +1,35 @@
|
||||
// ============================================================
|
||||
// Negosium/NegoData ERD Type Definitions (TypeScript)
|
||||
// ------------------------------------------------------------
|
||||
// 기준: postgres-init/01-schema.sql (negosium_db, 도메인별 schema) + 현행 백엔드 API 계약.
|
||||
// 표기 규칙:
|
||||
// - 코드값(status/role/type/quantity_unit/delivery_type 등)은 DB에서 SMALLINT 정수코드지만,
|
||||
// 현행 API(openapi.json) 가 문자열로 직렬화하므로 여기서는 string 으로 둔다(주석에 DB 타입 명시).
|
||||
// - DB 에 대응 테이블/컬럼이 없는 항목은 "⚠ DB 없음" 으로 표시한다.
|
||||
// ============================================================
|
||||
// 2개 이상 feature가 공유하는 타입만 둔다. 단일 feature 전용은 그 feature/types.ts 로.
|
||||
import type { ItemData } from '@/api/generated/model/itemData';
|
||||
import type { SupplierData } from '@/api/generated/model/supplierData';
|
||||
|
||||
// Base abstract structure properties
|
||||
interface BaseEntity {
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
deleted: boolean;
|
||||
}
|
||||
|
||||
// 1. Companies (고객사) — company.companies
|
||||
export interface Company extends BaseEntity {
|
||||
company_id: string; // uuid (Primary Key)
|
||||
name: string; // 회사명
|
||||
business_number: string | null; // 사업자등록번호
|
||||
code: number | null; // 회사코드 (내부 인덱스용)
|
||||
representative_name: string | null; // 대표자 명
|
||||
email: string | null; // 대표 이메일
|
||||
contact_number: string | null; // 대표 연락처
|
||||
website_url: string | null; // 홈페이지 URL
|
||||
industry: string | null; // 업종 (DB: SMALLINT 코드)
|
||||
status: string; // 상태 (DB: SMALLINT NOT NULL, 1=active 2=inactive)
|
||||
}
|
||||
|
||||
// 2. Users (유저) — company.users
|
||||
export interface User extends BaseEntity {
|
||||
user_id: string; // uuid (Primary Key)
|
||||
company_id: string; // 회사 아이디 (company.companies.company_id)
|
||||
id: string; // 로그인시, 입력 아이디
|
||||
password: string; // 비밀번호 (해시)
|
||||
name: string | null; // 이름
|
||||
email: string | null; // 이메일
|
||||
contact_number: string | null; // 전화번호
|
||||
last_accessed_at: string; // 마지막 접속 시간
|
||||
status: string; // 상태 (DB: SMALLINT, 1=active 2=inactive)
|
||||
role: string; // 권한 (DB: SMALLINT, 1=user 2=manager)
|
||||
}
|
||||
|
||||
// 3. User Tokens (유저 토큰) — company.user_tokens
|
||||
export interface UserToken extends BaseEntity {
|
||||
user_tokens_id: string; // uuid (Primary Key) — DB 컬럼명 user_tokens_id
|
||||
user_id: string; // 유저 아이디 (company.users.user_id)
|
||||
type: string; // 토큰 타입 (DB: SMALLINT 코드)
|
||||
token: any; // 토큰 값 (JSONB)
|
||||
issued_at: string;
|
||||
expired_at: string;
|
||||
}
|
||||
|
||||
// 4. Suppliers (협력사) - 기존 Partner 대응 — partner.suppliers
|
||||
export interface Supplier extends BaseEntity {
|
||||
supplier_id: string; // uuid (Primary Key)
|
||||
company_id: string; // 회사 아이디 (company.companies.company_id)
|
||||
user_id: string; // 등록 유저 (company.users.user_id) — DB NOT NULL
|
||||
name: string; // 협력사명
|
||||
code: string | null; // 협력사코드
|
||||
manager_name: string | null; // 담당자명
|
||||
manager_email: string | null; // 담당자 이메일
|
||||
manager_contact_number: string | null; // 담당자 연락처 (DB 철자 정상 — 기존 typo 가정은 오류였음)
|
||||
priority: string | null; // 우선순위 (DB: VARCHAR, 고객사별 문자열 유지)
|
||||
}
|
||||
|
||||
// 5. Items (상품 정보) - 기존 Product 대응 — partner.items
|
||||
export interface Item extends BaseEntity {
|
||||
item_id: string; // uuid (Primary Key)
|
||||
company_id: string; // 회사 아이디 (company.companies.company_id)
|
||||
user_id: string; // 등록 유저 (company.users.user_id) — DB NOT NULL
|
||||
name: string; // 상품명
|
||||
code: string | null; // 상품코드
|
||||
price: number | null; // 상품 단가 (DB: BIGINT)
|
||||
category: string | null; // 상품 카테고리 (free text)
|
||||
category_type: number; // 카테고리 조회용 정수 (DB: INTEGER NOT NULL DEFAULT 1, 자동증가 아님)
|
||||
image_url: string | null; // 상품 이미지 URL
|
||||
model_name: string | null; // 상품 모델명
|
||||
spec: string | null; // 상품 규격
|
||||
moq: string | null; // 상품 MOQ
|
||||
lead_time: number | null; // 상품 리드타임 (DB: SMALLINT)
|
||||
manufacturer: string | null; // 상품 제조사
|
||||
made_in: string | null; // 상품 제조 국가
|
||||
quantity_unit: string | null; // 상품 취급 단위 (DB: SMALLINT 코드)
|
||||
delivery_type: string | null; // 상품 배송형태 (DB: SMALLINT 코드)
|
||||
vat_yn: boolean | null; // VAT 포함 여부
|
||||
delivery_fee_yn: boolean | null; // 배송비 포함 여부
|
||||
internet_lowest_price_yn: boolean; // 인터넷 최저가 보조 플래그
|
||||
}
|
||||
|
||||
// 6. Item Internet Lowest Prices — partner.item_internet_lowest_prices
|
||||
// (※ 기존 url/crawled_at 필드는 DB 에 없어 제거. 실제 DB 컬럼에 맞춤.)
|
||||
export interface ItemInternetLowestPrice extends BaseEntity {
|
||||
lp_id: string; // uuid (Primary Key)
|
||||
item_id: string; // 상품 아이디 (partner.items.item_id)
|
||||
lp_price: number | null; // 크롤링한 최저가 (DB: BIGINT)
|
||||
website: number; // 크롤링 대상 사이트 (DB: SMALLINT 코드)
|
||||
success_yn: boolean; // 크롤링 성공 여부
|
||||
fail_reason: string | null; // 실패 사유
|
||||
ai_model: number | null; // 사용한 AI 모델 (DB: SMALLINT 코드)
|
||||
crawl_duration_ms: number | null; // 크롤링 소요 시간(ms)
|
||||
crawl_end_time: string; // 크롤링 종료 시각
|
||||
}
|
||||
|
||||
// 7. Quotation Settings (견적 세팅) — quotation.quotation_settings
|
||||
// (※ DB·API 모두 user_id 보유. 전역 기본 설정은 NULL 가능.)
|
||||
export interface QuotationSetting extends BaseEntity {
|
||||
qt_setting_id: string; // uuid (Primary Key)
|
||||
user_id: string; // 유저 아이디 (company.users.user_id). DB 는 nullable(전역 기본=NULL)이나 UI 매퍼가 '' 로 정규화
|
||||
target_margin: string; // 목표 마진율 (DB: NUMERIC(8,6))
|
||||
anchoring_value: string; // 앵커링 설정 값 (DB: NUMERIC(8,6))
|
||||
card_use_count: string; // 협상 카드 사용 횟수 (DB: card_count INTEGER)
|
||||
}
|
||||
|
||||
// 8. Quotations (견적) - 기존 Estimate 대응 — quotation.quotations
|
||||
// (※ company_id 는 DB/API 모두에 없어 제거. 회사 스코프는 user_id 경유.)
|
||||
export interface Quotation extends BaseEntity {
|
||||
qt_id: string; // uuid (Primary Key)
|
||||
user_id: string; // 유저 아이디 (company.users.user_id)
|
||||
qt_setting_id: string; // 견적 세팅 아이디 (quotation.quotation_settings.qt_setting_id)
|
||||
version_id: string; // 협상전략 버전 (card.versions.version_id) — DB NOT NULL
|
||||
name: string; // 견적 명
|
||||
number: string; // 견적 번호
|
||||
type: string; // 견적 타입 (DB: SMALLINT, 1=renego 2=requote)
|
||||
round: number; // 견적 차수 (기본 1)
|
||||
status: string; // 견적 상태 (DB: SMALLINT 코드)
|
||||
start_time: string; // 견적 시작 시간
|
||||
end_time: string; // 견적 마감 시간
|
||||
manager_name: string | null; // 견적 담당자 명
|
||||
manager_email: string | null; // 견적 담당자 이메일
|
||||
manager_contact_number: string | null; // 견적 담당자 연락처
|
||||
memo: string | null; // 견적 안내사항
|
||||
iteration: number; // 반복 횟수 (DB NOT NULL DEFAULT 0)
|
||||
preferred_sp_yn: boolean | null; // 선호 공급사 지정 여부
|
||||
preferred_sp_id: string | null; // 선호 공급사 (partner.suppliers.supplier_id)
|
||||
preferred_sp_name: string | null; // 선호 공급사명(스냅샷)
|
||||
equal_bid_yn: boolean | null; // 동일가 입찰 발생 여부
|
||||
equal_bid_data: any | null; // 동일가 입찰 상세 (JSONB)
|
||||
}
|
||||
|
||||
// 9. Nego Cards (협상카드) — card.nego_cards
|
||||
// (※ company_id 는 DB 에 없어 제거. 소유는 user_id(nullable) 만.)
|
||||
export interface NegoCard extends BaseEntity {
|
||||
nego_card_id: string; // uuid (Primary Key)
|
||||
user_id: string | null; // 유저 아이디 (o2o 기본 카드는 NULL)
|
||||
name: string | null; // 카드 이름
|
||||
number: string | null; // 카드 번호 (식별번호)
|
||||
script: string | null; // 스크립트
|
||||
edit_script: any | null; // 편집 스크립트 (JSONB)
|
||||
}
|
||||
|
||||
// 10. Wild Cards (와일드 카드) — card.wild_cards
|
||||
// (※ company_id 는 DB 에 없어 제거.)
|
||||
export interface WildCard extends BaseEntity {
|
||||
wild_card_id: string; // uuid (Primary Key)
|
||||
user_id: string | null; // 유저 아이디 (o2o 기본 카드는 NULL)
|
||||
name: string | null; // 카드 이름
|
||||
number: string | null; // 카드 번호 (식별번호)
|
||||
script: string | null; // 스크립트
|
||||
edit_script: any | null; // 편집 스크립트 (JSONB)
|
||||
condition: string | null; // 카드 사용 조건
|
||||
available: boolean; // 협상 적용 가능 여부
|
||||
memo: string | null; // 메모
|
||||
}
|
||||
|
||||
// 11. Sessions (세션) - 기존 ChatSession 대응 — negotiation.sessions
|
||||
// (※ user_id, bid_summary_id 는 DB sessions 에 없어 제거. bid_summary 개념은 quotations 로 흡수됨.)
|
||||
export interface Session extends BaseEntity {
|
||||
session_id: string; // uuid (Primary Key)
|
||||
quotation_id: string; // 소속 견적 (quotation.quotations.qt_id) — DB 컬럼명 quotation_id
|
||||
item_id: string; // 상품 아이디 (partner.items.item_id)
|
||||
supplier_id: string; // 협력사 아이디 (partner.suppliers.supplier_id)
|
||||
qt_number: string; // 견적번호(스냅샷)
|
||||
qt_round: number; // 견적 차수(스냅샷)
|
||||
qt_type: string; // 견적 타입(스냅샷, DB: SMALLINT)
|
||||
target_price: number; // 목표 가격 (DB: BIGINT)
|
||||
status: string; // 협상 상태 (DB: SMALLINT 코드)
|
||||
bid_price: number | null; // 최종 입찰 가격
|
||||
bid_at: string | null; // 최종 입찰 시간
|
||||
end_time: string; // 협상 종료 시간
|
||||
reject_reason: string | null; // 협상 거부 사유
|
||||
reject_price: number | null; // 협상 거부 가격
|
||||
reject_delivery_type: string | null; // 협상 거부 시 배송 형태 (DB: SMALLINT 코드)
|
||||
}
|
||||
|
||||
// 12. Bid Summary (견적 입찰 정보)
|
||||
// ⚠ DB 없음: 별도 테이블이 없고 quotation.quotations 의 preferred_sp_* / equal_bid_* 컬럼으로 흡수됨.
|
||||
// UI(QuotationDetailSheet) 의 입찰 요약 표시용 파생 모델로만 존재.
|
||||
export interface BidSummary {
|
||||
bid_summary_id: string; // (파생) UI 식별자
|
||||
qt_id: string; // 견적 아이디 (quotation.quotations.qt_id)
|
||||
qt_type: string; // 견적 타입 (재협상/재견적)
|
||||
qt_iteration: number; // 견적 반복횟수 (← quotations.iteration)
|
||||
status: string; // 입찰 상태 (← quotations.status)
|
||||
has_preferred: boolean; // ← quotations.preferred_sp_yn
|
||||
preferred_sp_id: string | null; // ← quotations.preferred_sp_id
|
||||
preferred_sp_name: string | null; // ← quotations.preferred_sp_name
|
||||
equal_data: any | null; // ← quotations.equal_bid_data (JSONB)
|
||||
}
|
||||
|
||||
// 13. Results (세션 결과) — negotiation.results (스키마 미확정 스텁)
|
||||
export interface Result extends BaseEntity {
|
||||
result_id: string; // uuid (Primary Key) — DB 컬럼명 result_id
|
||||
}
|
||||
|
||||
// 14. Quotation Cards (견적↔카드 연결)
|
||||
// API(QuotationCardResponse) 로는 노출되나, 33KB DB 에는 quotation_cards 테이블이 없고
|
||||
// card.version_nego_cards / card.version_wild_cards (버전↔카드) 매핑으로 실현된다
|
||||
// (quotation.version_id → version_*_cards → nego/wild_cards).
|
||||
export interface QuotationCard {
|
||||
session_card_id: string; // uuid (Primary Key, API 기준)
|
||||
wild_card_id: string | null; // 와일드 카드 아이디 (card.wild_cards.wild_card_id)
|
||||
nego_card_id: string | null; // 협상카드 아이디 (card.nego_cards.nego_card_id)
|
||||
qt_id: string | null; // 견적 아이디 (quotation.quotations.qt_id)
|
||||
type: string | null; // 카드 타입 (DB: SMALLINT, 1=nego 2=wild)
|
||||
}
|
||||
|
||||
// 15. Chats (채팅 내역) — negotiation.chats
|
||||
// (※ API(ChatMessageResponse) 는 순번 컬럼을 index 로, DB 는 seq 로 부른다.)
|
||||
export interface Chat extends BaseEntity {
|
||||
chat_id: string; // uuid (Primary Key)
|
||||
session_id: string; // 소속 세션 (negotiation.sessions.session_id)
|
||||
card_id: string | null; // 사용된 카드 (card.nego_cards/wild_cards, 다형성)
|
||||
seq: number; // 세션 내 메시지 순번 (API: index)
|
||||
sender: string; // 발신자 구분 (DB: SMALLINT 코드)
|
||||
target_price: number; // 제시 목표가 (DB: BIGINT)
|
||||
card_used_yn: boolean | null; // 카드 사용 여부
|
||||
indicator_value: number | null; // 지표값 (DB: NUMERIC(8,6))
|
||||
card_type: string | null; // 카드 유형 (DB: SMALLINT, 1=nego 2=wild)
|
||||
}
|
||||
|
||||
// 16. CopyOfChat (채팅 임시/백업)
|
||||
// ⚠ DB 없음: 대응 테이블 없음 (프론트 임시 보관용).
|
||||
export interface CopyOfChat extends BaseEntity {
|
||||
id: string;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// React UI Compatibility Helper Types
|
||||
// ============================================================
|
||||
|
||||
export type Product = Partial<Item> & {
|
||||
id?: string; // item_id back-compatibility map
|
||||
minPrice?: number; // UI minimum reserve limit
|
||||
status?: string; // UI lifecycle state
|
||||
export type Product = ItemData & {
|
||||
deleted?: boolean;
|
||||
id?: string;
|
||||
minPrice?: number;
|
||||
status?: string;
|
||||
};
|
||||
|
||||
export type Partner = Partial<Supplier> & {
|
||||
id?: string; // supplier_id back-compatibility map
|
||||
managerName?: string; // manager_name
|
||||
managerEmail?: string; // manager_email
|
||||
managerPhone?: string; // manager_contact_number
|
||||
manager_contact_number?: string; // DB 컬럼 직접 매핑(철자 정상)
|
||||
rank?: 'A' | 'B' | 'C' | 'S'; // computed from priority
|
||||
status?: string; // mapped to deleted
|
||||
memo?: string; // back-compatible details
|
||||
export type Partner = SupplierData & {
|
||||
deleted?: boolean;
|
||||
id?: string;
|
||||
managerName?: string;
|
||||
managerEmail?: string;
|
||||
managerPhone?: string;
|
||||
rank?: 'A' | 'B' | 'C' | 'S';
|
||||
status?: string;
|
||||
memo?: string;
|
||||
};
|
||||
|
||||
export type Estimate = Partial<Quotation> & {
|
||||
id?: string; // qt_id back-compatibility map
|
||||
dueDate?: string; // end_time
|
||||
title?: string; // mapped to name in UI
|
||||
productId?: string; // mapped to association
|
||||
productName?: string; // 서버 목록 조인 상품명(products 목록에 없을 때 폴백)
|
||||
partnerIds?: string[]; // mapped B2B suppliers
|
||||
participationCount?: number;
|
||||
winnerPartnerId?: string | null;
|
||||
finalPrice?: number;
|
||||
isEqualPrice?: boolean;
|
||||
usedCardIds?: string[];
|
||||
settingApplied?: boolean | string;
|
||||
};
|
||||
|
||||
// UI Chat Message definition (corresponds to in-memory/rendered chats)
|
||||
export interface ChatMessage {
|
||||
id: string;
|
||||
sender: 'BOT' | 'PARTNER' | 'SYSTEM';
|
||||
timestamp: string;
|
||||
content: string;
|
||||
editorScript?: any; // Slate JSON structure
|
||||
}
|
||||
|
||||
export interface ChatSession {
|
||||
id: string; // matches supplier_id (or supplier.supplier_id)
|
||||
partnerName: string;
|
||||
status: 'NEGOTIATING' | 'COMPLETED' | 'REJECTED' | '협상생성' | '협상중' | '협상완료' | '미참여' | '협상거부';
|
||||
currentBid: number;
|
||||
bidTime: string;
|
||||
messages: ChatMessage[];
|
||||
}
|
||||
|
||||
export interface NegotiationCard {
|
||||
id: string; // nego_card_id or wild_card_id
|
||||
isWildcard: boolean; // mapping based on source table
|
||||
code: string; // number (식별번호) or custom code
|
||||
title: string; // name
|
||||
scriptPreview: string; // script
|
||||
editorScript: any; // edit_script (JSON)
|
||||
id: string;
|
||||
isWildcard: boolean;
|
||||
code: string;
|
||||
title: string;
|
||||
scriptPreview: string;
|
||||
editorScript: any;
|
||||
status: 'ACTIVE' | 'INACTIVE';
|
||||
triggerCondition?: string; // wild_card's condition
|
||||
memo?: string; // wild_card's memo
|
||||
triggerCondition?: string;
|
||||
memo?: string;
|
||||
}
|
||||
|
||||
export type PageType = 'PRODUCTS' | 'PARTNERS' | 'QUOTATION' | 'CARDS';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user