174 lines
4.1 KiB
TypeScript
174 lines
4.1 KiB
TypeScript
|
|
// lib/api/quote.ts
|
||
|
|
// 견적 자동산출 API 클라이언트
|
||
|
|
import { ApiClient } from './client';
|
||
|
|
import { AUTH_CONFIG } from './auth/auth-config';
|
||
|
|
|
||
|
|
// ===================================
|
||
|
|
// 타입 정의
|
||
|
|
// ===================================
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 산출된 변수 정보
|
||
|
|
*/
|
||
|
|
interface CalculationVariable {
|
||
|
|
name: string;
|
||
|
|
value: number;
|
||
|
|
category: string;
|
||
|
|
type: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 산출된 품목 정보
|
||
|
|
*/
|
||
|
|
interface CalculationItem {
|
||
|
|
item_code: string;
|
||
|
|
item_name: string;
|
||
|
|
specification?: string;
|
||
|
|
unit?: string;
|
||
|
|
quantity: number;
|
||
|
|
unit_price: number;
|
||
|
|
total_price: number;
|
||
|
|
formula_variable: string;
|
||
|
|
formula_category?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 비용 합계
|
||
|
|
*/
|
||
|
|
interface CalculationCosts {
|
||
|
|
material_cost: number;
|
||
|
|
labor_cost: number;
|
||
|
|
install_cost: number;
|
||
|
|
subtotal: number;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 견적 산출 결과
|
||
|
|
*/
|
||
|
|
export interface CalculationResult {
|
||
|
|
inputs: Record<string, number | string>;
|
||
|
|
outputs: Record<string, CalculationVariable>;
|
||
|
|
items: CalculationItem[];
|
||
|
|
costs: CalculationCosts;
|
||
|
|
errors: string[];
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 견적 산출 요청
|
||
|
|
*/
|
||
|
|
export interface CalculateRequest {
|
||
|
|
inputs: {
|
||
|
|
W0: number; // 오픈사이즈 가로 (mm)
|
||
|
|
H0: number; // 오픈사이즈 세로 (mm)
|
||
|
|
QTY?: number; // 수량
|
||
|
|
INSTALL_TYPE?: string; // 설치 유형 (wall, ceiling, floor)
|
||
|
|
CONTROL_TYPE?: string; // 제어 방식 (switch, remote, smart)
|
||
|
|
MOTOR_TYPE?: string; // 모터 유형 (standard, heavy)
|
||
|
|
CHAIN_SIDE?: string; // 체인 위치 (left, right)
|
||
|
|
};
|
||
|
|
product_category: 'screen' | 'steel';
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 입력 스키마 필드 정의
|
||
|
|
*/
|
||
|
|
interface InputSchemaField {
|
||
|
|
label: string;
|
||
|
|
type: 'number' | 'integer' | 'select' | 'text';
|
||
|
|
unit?: string;
|
||
|
|
required?: boolean;
|
||
|
|
min?: number;
|
||
|
|
max?: number;
|
||
|
|
step?: number;
|
||
|
|
default?: string | number;
|
||
|
|
options?: Array<{ value: string; label: string }>;
|
||
|
|
description?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* API 응답 공통 형식
|
||
|
|
*/
|
||
|
|
interface ApiResponse<T> {
|
||
|
|
success: boolean;
|
||
|
|
message: string;
|
||
|
|
data: T;
|
||
|
|
}
|
||
|
|
|
||
|
|
// ===================================
|
||
|
|
// Quote API 클라이언트
|
||
|
|
// ===================================
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 견적 자동산출 API 클라이언트
|
||
|
|
*
|
||
|
|
* @example
|
||
|
|
* ```typescript
|
||
|
|
* // 자동 산출
|
||
|
|
* const result = await quoteApi.calculate({
|
||
|
|
* inputs: { W0: 3000, H0: 2500 },
|
||
|
|
* product_category: 'screen'
|
||
|
|
* });
|
||
|
|
*
|
||
|
|
* // 입력 스키마 조회
|
||
|
|
* const schema = await quoteApi.getCalculationSchema('screen');
|
||
|
|
* ```
|
||
|
|
*/
|
||
|
|
class QuoteApiClient extends ApiClient {
|
||
|
|
constructor() {
|
||
|
|
super({
|
||
|
|
mode: 'bearer',
|
||
|
|
apiKey: process.env.NEXT_PUBLIC_API_KEY,
|
||
|
|
getToken: () => {
|
||
|
|
if (typeof window !== 'undefined') {
|
||
|
|
return localStorage.getItem('auth_token');
|
||
|
|
}
|
||
|
|
return null;
|
||
|
|
},
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 자동 견적 산출
|
||
|
|
*
|
||
|
|
* @param request - 산출 요청 파라미터
|
||
|
|
* @returns 산출 결과 (변수, 품목, 비용)
|
||
|
|
*/
|
||
|
|
async calculate(request: CalculateRequest): Promise<ApiResponse<CalculationResult>> {
|
||
|
|
return this.post<ApiResponse<CalculationResult>>('/api/v1/quotes/calculate', request);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 견적 미리보기 (저장 없이 계산만)
|
||
|
|
*
|
||
|
|
* @param request - 산출 요청 파라미터
|
||
|
|
* @returns 미리보기 결과
|
||
|
|
*/
|
||
|
|
async preview(request: CalculateRequest): Promise<ApiResponse<CalculationResult>> {
|
||
|
|
return this.post<ApiResponse<CalculationResult>>('/api/v1/quotes/preview', request);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 입력 스키마 조회 (동적 폼 생성용)
|
||
|
|
*
|
||
|
|
* @param productCategory - 제품 카테고리 (screen, steel)
|
||
|
|
* @returns 입력 필드 스키마
|
||
|
|
*/
|
||
|
|
async getCalculationSchema(
|
||
|
|
productCategory?: 'screen' | 'steel'
|
||
|
|
): Promise<ApiResponse<Record<string, InputSchemaField>>> {
|
||
|
|
const query = productCategory ? `?product_category=${productCategory}` : '';
|
||
|
|
return this.get<ApiResponse<Record<string, InputSchemaField>>>(`/api/v1/quotes/calculation-schema${query}`);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 싱글톤 인스턴스 내보내기
|
||
|
|
export const quoteApi = new QuoteApiClient();
|
||
|
|
|
||
|
|
// 타입 내보내기
|
||
|
|
export type {
|
||
|
|
CalculationVariable,
|
||
|
|
CalculationItem,
|
||
|
|
CalculationCosts,
|
||
|
|
InputSchemaField,
|
||
|
|
ApiResponse
|
||
|
|
};
|