diff --git a/backend/router/v1/chat/protocol.py b/backend/router/v1/chat/protocol.py index 33a7835..74f2081 100644 --- a/backend/router/v1/chat/protocol.py +++ b/backend/router/v1/chat/protocol.py @@ -63,6 +63,7 @@ class Res_ChatInit(Res_WebPacketProtocol): session_id: str = Field("", description="협상 세션 uuid") session_status: int = Field(0, description="세션 상태 코드 (SessionStatus: 1=생성 2=진행중 3=완료 4=미참여 5=거부)") quotation_id: str = Field("", description="소속 견적 uuid") + qt_number: str = Field("", description="견적번호(EST-...)") quotation_end_time: str = Field("", description="견적 마감 시각 (ISO 8601, 타이머용)") quotation_memo: str = Field("", description="견적 메모") item_id: str = Field("", description="상품 uuid") diff --git a/backend/services/chat_service.py b/backend/services/chat_service.py index 6f7691c..0b30355 100644 --- a/backend/services/chat_service.py +++ b/backend/services/chat_service.py @@ -238,6 +238,7 @@ class ChatService: res.session_id = str(sess.session_id) res.session_status = sess.status res.quotation_id = str(sess.quotation_id) + res.qt_number = sess.qt_number or "" res.quotation_end_time = quote.end_time.isoformat(timespec="seconds") if quote.end_time else "" res.quotation_memo = quote.memo or "" res.item_id = str(item.item_id) diff --git a/frontend/src/apis/chat/chat.type.ts b/frontend/src/apis/chat/chat.type.ts index 913f6bd..f3bded6 100644 --- a/frontend/src/apis/chat/chat.type.ts +++ b/frontend/src/apis/chat/chat.type.ts @@ -32,6 +32,7 @@ export interface ChatInitResponse { session_id: string session_status: number quotation_id: string + qt_number?: string quotation_end_time: string quotation_memo?: string item_id: string @@ -90,6 +91,7 @@ export function mapInit(r: ChatInitResponse): ChatInitData { session_status: r.session_status, item_id: r.item_id, quotation_id: r.quotation_id, + qt_number: r.qt_number ?? '', item_name: r.item_name, item_code: r.item_code ?? '', item_image: r.item_image ?? '', diff --git a/frontend/src/features/chat/stores/useChatInitStore.ts b/frontend/src/features/chat/stores/useChatInitStore.ts index 959cc87..ef4b281 100644 --- a/frontend/src/features/chat/stores/useChatInitStore.ts +++ b/frontend/src/features/chat/stores/useChatInitStore.ts @@ -16,6 +16,7 @@ const initialState: ChatInitData = { session_status: 0, item_id: '', quotation_id: '', + qt_number: '', item_name: '', item_code: '', item_image: '', diff --git a/frontend/src/features/chat/types.ts b/frontend/src/features/chat/types.ts index 500fbf9..5dd511a 100644 --- a/frontend/src/features/chat/types.ts +++ b/frontend/src/features/chat/types.ts @@ -70,6 +70,7 @@ export type ChatInitData = { session_status: number // SessionStatus 코드 (진입 시점 기준) item_id: string quotation_id: string + qt_number: string item_name: string item_code: string item_image: string diff --git a/frontend/src/pages/ChatPage.tsx b/frontend/src/pages/ChatPage.tsx index a4c0a25..57ef0e0 100644 --- a/frontend/src/pages/ChatPage.tsx +++ b/frontend/src/pages/ChatPage.tsx @@ -2,18 +2,22 @@ import { type ReactNode } from 'react' import { useNavigate, useSearchParams, Navigate } from 'react-router' import { ArrowLeft, Package, ClipboardList } from 'lucide-react' import { cn, interactive } from '@/lib' +import { Logo } from '@/components' import { MainLayout, MainHeaderBar } from '@/layouts' import { ChatContainer, ItemSection, RemainingTime } from '@/features/chat' import { MobileDrawer } from '@/features/chat/components/MobileDrawer' import { MenuSection } from '@/features/chat/components/menu/MenuSection' import { useChatUiStore } from '@/features/chat/stores/useChatUiStore' -import { SidebarFooter } from '@/features/auth' +import { useChatInitStore } from '@/features/chat/stores/useChatInitStore' +import { SidebarFooter, usePreLoginBranding } from '@/features/auth' export function ChatPage() { const [searchParams] = useSearchParams() const sessionId = searchParams.get('session_id') ?? '' const drawer = useChatUiStore((s) => s.drawer) const close = useChatUiStore((s) => s.close) + const qtNumber = useChatInitStore((s) => s.qt_number) + const itemName = useChatInitStore((s) => s.item_name) // session_id 없이 진입하면 목록으로 되돌린다. if (!sessionId) return @@ -27,15 +31,21 @@ export function ChatPage() { {/* min-w-0: flex 기본 min-width:auto 라 자식이 안 줄어들어 헤더 밖으로 넘치던 것 방지 */}
-
+
- - - - 실시간 구매 협상 채널 + + {/* 헤더 대표값: 협상 중인 상품명 — 여러 협상건 중 '이 건'을 식별하는 기준 */} + + {itemName || '가격 협상'} + {/* 견적번호: 정확한 참조용 보조값. 좁은 모바일에선 숨기고 상품 드로어에서 확인 */} + {qtNumber && ( + + {qtNumber} + + )}
-
+
} label="상품" panel="product" /> } label="현황" panel="status" /> @@ -49,6 +59,8 @@ export function ChatPage() { {/* 모바일 드로어 (lg 미만) */} + {/* 데스크톱 사이드바 상단(구매사 로고)이 모바일에선 숨으므로, 드로어에서 브랜드+견적번호를 노출 */} + @@ -72,11 +84,27 @@ function BackToListButton() { )} > - 목록으로 돌아가기 + 목록 ) } +// 모바일 상품 드로어 상단: 구매사 로고 + 서비스명 + 견적번호(데스크톱 사이드바 상단의 모바일 대체) +function BuyerBrandStrip() { + const branding = usePreLoginBranding() + const qtNumber = useChatInitStore((s) => s.qt_number) + return ( +
+ + {qtNumber && ( + + {qtNumber} + + )} +
+ ) +} + // 헤더 우측: 상품/현황 패널 드로어 토글 (모바일 전용) function PanelToggle({ icon,