feat: 견적서 모달 회사정보 API 연동

- getCompanyInfo() API 함수 추가 (GET /api/v1/tenants)
- EstimateDocumentModal에 회사정보 API 연동
- 하드코딩된 회사명/주소/연락처 제거
- 결재란 견적자명 동적 표시
- constants.ts 모듈 유효성 수정
This commit is contained in:
2026-01-16 20:41:18 +09:00
committed by hskwon
parent 2465d739fe
commit dac1d9bc2b
3 changed files with 118 additions and 22 deletions

View File

@@ -1138,4 +1138,78 @@ export async function getEstimateOptions(): Promise<{
console.error('견적서 옵션 일괄 조회 오류:', error);
return { success: false, error: '견적서 옵션을 불러오는데 실패했습니다.' };
}
}
// ========================================
// 회사 정보 조회 (Tenant API)
// ========================================
/**
* 회사 정보 타입 (견적서용)
*/
export interface CompanyInfo {
companyName: string;
representativeName: string;
address: string;
phone: string;
fax: string;
email: string;
managerName: string;
managerPhone: string;
}
/**
* 회사 정보 조회 (견적서 모달용)
* GET /api/v1/tenants
*/
export async function getCompanyInfo(): Promise<{
success: boolean;
data?: CompanyInfo;
error?: string;
}> {
try {
const response = await apiClient.get<{
success: boolean;
message: string;
data: {
id: number;
company_name: string;
ceo_name?: string;
email?: string;
phone?: string;
fax?: string;
address?: string;
options?: {
manager_name?: string;
address_detail?: string;
zip_code?: string;
};
};
}>('/tenants');
const tenant = response.data;
const opts = tenant.options || {};
// 주소 조합: 우편번호 + 주소 + 상세주소
const fullAddress = [opts.zip_code, tenant.address, opts.address_detail]
.filter(Boolean)
.join(' ');
return {
success: true,
data: {
companyName: tenant.company_name || '',
representativeName: tenant.ceo_name || '',
address: fullAddress || tenant.address || '',
phone: tenant.phone || '',
fax: tenant.fax || '',
email: tenant.email || '',
managerName: opts.manager_name || '',
managerPhone: tenant.phone || '',
},
};
} catch (error) {
console.error('회사 정보 조회 오류:', error);
return { success: false, error: '회사 정보를 불러오는데 실패했습니다.' };
}
}

View File

@@ -1,6 +1,6 @@
'use client';
import { useCallback } from 'react';
import { useCallback, useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';
import { Printer, Pencil, Send, X as XIcon } from 'lucide-react';
import { Button } from '@/components/ui/button';
@@ -12,6 +12,7 @@ import {
} from '@/components/ui/dialog';
import { printArea } from '@/lib/print-utils';
import type { EstimateDetailFormData } from '../types';
import { getCompanyInfo, type CompanyInfo } from '../actions';
// 금액 포맷팅
function formatAmount(amount: number): string {
@@ -65,6 +66,20 @@ export function EstimateDocumentModal({
}: EstimateDocumentModalProps) {
const router = useRouter();
// 회사 정보 상태
const [companyInfo, setCompanyInfo] = useState<CompanyInfo | null>(null);
// 회사 정보 로드
useEffect(() => {
if (isOpen) {
getCompanyInfo().then((result) => {
if (result.success && result.data) {
setCompanyInfo(result.data);
}
});
}
}, [isOpen]);
// 인쇄
const handlePrint = useCallback(() => {
printArea({ title: '견적서 인쇄' });
@@ -78,22 +93,22 @@ export function EstimateDocumentModal({
}
}, [estimateId, onClose, router]);
// 견적서 문서 데이터
// 견적서 문서 데이터 (회사 정보는 API에서 로드)
const documentData = {
documentNo: formData.estimateCode || 'ABC123',
createdDate: formData.siteBriefing.briefingDate || '2025년 11월 11일',
documentNo: formData.estimateCode || '',
createdDate: formData.siteBriefing.briefingDate || '',
recipient: formData.siteBriefing.partnerName || '',
companyName: formData.siteBriefing.companyName || '(주) 주일기업',
companyName: companyInfo?.companyName || formData.siteBriefing.companyName || '',
projectName: formData.bidInfo.projectName || '',
address: '주소',
address: companyInfo?.address || '',
amount: formData.summaryItems.reduce((sum, item) => sum + item.totalCost, 0),
date: formData.bidInfo.bidDate || '2025년 12월 12일',
manager: formData.estimateCompanyManager || '',
managerContact: formData.estimateCompanyManagerContact || '',
date: formData.bidInfo.bidDate || '',
manager: companyInfo?.managerName || formData.estimateCompanyManager || '',
managerContact: companyInfo?.managerPhone || formData.estimateCompanyManagerContact || '',
contact: {
hp: '010-3679-2188',
tel: '(02) 849-5130',
fax: '(02) 6911-6315',
hp: companyInfo?.managerPhone || '',
tel: companyInfo?.phone || '',
fax: companyInfo?.fax || '',
},
note: '하기와 같이 보내합니다.',
};
@@ -160,13 +175,13 @@ export function EstimateDocumentModal({
</tr>
<tr>
<td className="border border-gray-400 px-2 py-3 text-center whitespace-nowrap"></td>
<td className="border border-gray-400 px-4 py-3 text-center whitespace-nowrap"></td>
<td className="border border-gray-400 px-4 py-3 text-center whitespace-nowrap"></td>
<td className="border border-gray-400 px-4 py-3 text-center whitespace-nowrap">{formData.estimatorName || ''}</td>
<td className="border border-gray-400 px-4 py-3 text-center whitespace-nowrap"></td>
</tr>
<tr>
<td className="border border-gray-400"></td>
<td className="border border-gray-400 px-4 py-1 text-center whitespace-nowrap"></td>
<td className="border border-gray-400 px-4 py-1 text-center whitespace-nowrap"></td>
<td className="border border-gray-400 px-4 py-1 text-center whitespace-nowrap"></td>
<td className="border border-gray-400 px-4 py-1 text-center whitespace-nowrap"></td>
</tr>
</tbody>
</table>

View File

@@ -1,6 +1,13 @@
// 견적서 상수 정의
// 모든 MOCK 데이터는 API로 대체됨:
// - 재료(material_type): getCommonCodeOptions('material_type')
// - 공과 품목: getExpenseItemOptions()
// - 도장/모터/제어기/시공비: getCommonCodeOptions('{group}')
// - 거래처/견적자: getClientOptions(), getUserOptions()
/**
* 견적서 상수 정의
*
* 모든 MOCK 데이터는 API로 대체됨:
* - 재료(material_type): getCommonCodeOptions('material_type')
* - 공과 품목: getExpenseItemOptions()
* - 도장/모터/제어기/시공비: getCommonCodeOptions('{group}')
* - 거래처/견적자: getClientOptions(), getUserOptions()
* - 회사 정보: getCompanyInfo()
*/
// 빈 export로 모듈 유효성 유지
export {};