feat: surveySale pdf 생성 방식 변경
- pdf 생성 시 response에 blob으로 반환하도록 방식 변경 - 제출 시 메일 href pdf 생성 페이지 링크에서 request url로 변경
This commit is contained in:
parent
c57bf8eebd
commit
5120764108
@ -7,6 +7,7 @@ import { HttpStatusCode } from 'axios'
|
||||
import { loggerWrapper } from '@/libs/api-wrapper'
|
||||
import { SurveySalesService } from '../service'
|
||||
import { ApiError } from 'next/dist/server/api-utils'
|
||||
import { SurveyBasicInfo } from '@/types/Survey'
|
||||
|
||||
/**
|
||||
* @api {GET} /api/survey-sales/:id 조사 매물 조회 API
|
||||
@ -17,7 +18,7 @@ import { ApiError } from 'next/dist/server/api-utils'
|
||||
* @apiParam {Number} id 조사 매물 PRIMARY KEY ID (required)
|
||||
* @apiParam {Boolean} isPdf pdf 데이터 조회 여부 (optional, default: false)
|
||||
*
|
||||
* @apiSuccess {Object} SurveySaleBasicInfo 조사 매물 기본 정보
|
||||
* @apiSuccess {Object} SurveySaleBasicInfo 조사 매물 기본 정보 | Blob 파일
|
||||
*
|
||||
* @apiError {Number} 401 세션 정보 없음 (로그인 필요)
|
||||
* @apiError {Number} 403 권한 없음
|
||||
@ -56,6 +57,18 @@ async function getSurveySaleDetail(request: NextRequest): Promise<NextResponse>
|
||||
if (result instanceof ApiError) {
|
||||
return NextResponse.json({ error: result.message }, { status: result.statusCode })
|
||||
}
|
||||
if (isPdf) {
|
||||
const pdfBlob = await service.createSurveyPdf(result as SurveyBasicInfo)
|
||||
if (pdfBlob instanceof ApiError) {
|
||||
return NextResponse.json({ error: pdfBlob.message }, { status: pdfBlob.statusCode })
|
||||
}
|
||||
return new NextResponse(pdfBlob, {
|
||||
headers: {
|
||||
'Content-Type': 'application/pdf',
|
||||
'Content-Disposition': `attachment; filename=${result.SRL_NO}.pdf; filename*=UTF-8''${encodeURIComponent(result.SRL_NO)}.pdf`,
|
||||
},
|
||||
})
|
||||
}
|
||||
return NextResponse.json(result)
|
||||
}
|
||||
|
||||
|
||||
@ -1,11 +1,14 @@
|
||||
import { prisma } from '@/libs/prisma'
|
||||
import { SurveyBasicInfo, SurveyRegistRequest, SurveySearchParams } from '@/types/Survey'
|
||||
import { convertToSnakeCase } from '@/utils/common-utils'
|
||||
import { convertToCamelCase, convertToSnakeCase } from '@/utils/common-utils'
|
||||
import { Prisma } from '@prisma/client'
|
||||
import type { SessionData } from '@/types/Auth'
|
||||
import { HttpStatusCode } from 'axios'
|
||||
import { ApiError } from 'next/dist/server/api-utils'
|
||||
import { ERROR_MESSAGE } from '@/hooks/useAlertMsg'
|
||||
import SurveySalePdf from '@/components/pdf/SurveySalePdf'
|
||||
import React from 'react'
|
||||
import { pdf, Document } from '@react-pdf/renderer'
|
||||
|
||||
type WhereCondition = {
|
||||
AND: any[]
|
||||
@ -115,6 +118,7 @@ export class SurveySalesService {
|
||||
where.OR = [
|
||||
{ AND: [{ STORE_ID: { equals: this.session?.storeId } }] },
|
||||
{ AND: [{ SUBMISSION_TARGET_ID: { equals: this.session?.storeId } }, { SUBMISSION_STATUS: { equals: true } }] },
|
||||
{ AND: [{ SUBMISSION_TARGET_NM: { equals: this.session?.storeNm } }, { SUBMISSION_STATUS: { equals: true } }] },
|
||||
]
|
||||
break
|
||||
case 'Admin_Sub':
|
||||
@ -130,6 +134,9 @@ export class SurveySalesService {
|
||||
{ SUBMISSION_STATUS: { equals: true } },
|
||||
],
|
||||
},
|
||||
{
|
||||
AND: [{ SUBMISSION_TARGET_NM: { equals: this.session?.storeNm } }, { SUBMISSION_STATUS: { equals: true } }],
|
||||
},
|
||||
]
|
||||
break
|
||||
case 'Builder':
|
||||
@ -259,7 +266,7 @@ export class SurveySalesService {
|
||||
* @param {number} id 조사 매물 ID
|
||||
* @returns {Promise<SurveyBasicInfo>} 조사 매물 데이터
|
||||
*/
|
||||
async fetchSurvey(id: number, isPdf: boolean): Promise<SurveyBasicInfo | ApiError> {
|
||||
async fetchSurvey(id: number, isPdf: boolean): Promise<SurveyBasicInfo | ApiError | Blob> {
|
||||
// @ts-ignore
|
||||
const result = await prisma.SD_SURVEY_SALES_BASIC_INFO.findFirst({
|
||||
where: { ID: id },
|
||||
@ -275,6 +282,23 @@ export class SurveySalesService {
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 조사 매물 PDF 생성
|
||||
* @param {SurveyBasicInfo} survey 조사 매물 데이터
|
||||
* @returns {Promise<Blob>} PDF Blob
|
||||
*/
|
||||
async createSurveyPdf(survey: SurveyBasicInfo): Promise<Blob | ApiError> {
|
||||
const convertedSurvey = convertToCamelCase(survey) as SurveyBasicInfo
|
||||
const content = React.createElement(Document, null, React.createElement(SurveySalePdf, { survey: convertedSurvey }))
|
||||
try {
|
||||
const pdfBlob = await pdf(content).toBlob()
|
||||
const arrayBuffer = await pdfBlob.arrayBuffer()
|
||||
return new Blob([arrayBuffer], { type: 'application/pdf' })
|
||||
} catch (error) {
|
||||
return new ApiError(HttpStatusCode.InternalServerError, ERROR_MESSAGE.PDF_GENERATION_ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 조사 매물 수정
|
||||
* @param {number} id 조사 매물 ID
|
||||
@ -364,9 +388,9 @@ export class SurveySalesService {
|
||||
if (!survey || !session) return false
|
||||
|
||||
const roleChecks = {
|
||||
T01: () => this.checkT01Role(survey),
|
||||
Admin: () => this.checkAdminRole(survey, session.storeId),
|
||||
Admin_Sub: () => this.checkAdminSubRole(survey, session.storeId),
|
||||
T01: () => this.checkT01Role(survey, session.userId),
|
||||
Admin: () => this.checkAdminRole(survey, session.storeId, session.storeNm),
|
||||
Admin_Sub: () => this.checkAdminSubRole(survey, session.storeId, session.storeNm),
|
||||
Partner: () => this.checkPartnerOrBuilderRole(survey, session.builderId),
|
||||
Builder: () => this.checkPartnerOrBuilderRole(survey, session.builderId),
|
||||
}
|
||||
@ -381,8 +405,8 @@ export class SurveySalesService {
|
||||
* @param {any} survey 조사 매물 데이터
|
||||
* @returns {boolean} 해당 매물의 조회 권한 여부 (true: 권한 있음, false: 권한 없음)
|
||||
*/
|
||||
private checkT01Role(survey: any): boolean {
|
||||
if (survey.REPRESENTATIVE_ID === this.session?.userId) {
|
||||
private checkT01Role(survey: any, userId: string | null): boolean {
|
||||
if (survey.REPRESENTATIVE_ID === userId) {
|
||||
return true
|
||||
}
|
||||
return survey.SRL_NO !== '一時保存'
|
||||
@ -396,9 +420,11 @@ export class SurveySalesService {
|
||||
* @param {string | null} storeId 판매점 ID
|
||||
* @returns {boolean} 해당 매물의 조회 권한 여부 (true: 권한 있음, false: 권한 없음)
|
||||
*/
|
||||
private checkAdminRole(survey: any, storeId: string | null): boolean {
|
||||
private checkAdminRole(survey: any, storeId: string | null, storeNm: string | null): boolean {
|
||||
if (!storeId) return false
|
||||
return survey.SUBMISSION_STATUS ? survey.SUBMISSION_TARGET_ID === storeId || survey.STORE_ID === storeId : survey.STORE_ID === storeId
|
||||
return survey.SUBMISSION_STATUS
|
||||
? survey.SUBMISSION_TARGET_ID === storeId || survey.SUBMISSION_TARGET_NM === storeNm || survey.STORE_ID === storeId
|
||||
: survey.STORE_ID === storeId
|
||||
}
|
||||
|
||||
/**
|
||||
@ -409,10 +435,12 @@ export class SurveySalesService {
|
||||
* @param {string | null} storeId 판매점 ID
|
||||
* @returns {boolean} 해당 매물의 조회 권한 여부 (true: 권한 있음, false: 권한 없음)
|
||||
*/
|
||||
private checkAdminSubRole(survey: any, storeId: string | null): boolean {
|
||||
private checkAdminSubRole(survey: any, storeId: string | null, storeNm: string | null): boolean {
|
||||
if (!storeId) return false
|
||||
return survey.SUBMISSION_STATUS
|
||||
? survey.SUBMISSION_TARGET_ID === storeId || (survey.STORE_ID === storeId && !survey.CONSTRUCTION_POINT_ID)
|
||||
? survey.SUBMISSION_TARGET_ID === storeId ||
|
||||
survey.SUBMISSION_TARGET_NM === storeNm ||
|
||||
(survey.STORE_ID === storeId && !survey.CONSTRUCTION_POINT_ID)
|
||||
: survey.STORE_ID === storeId && !survey.CONSTRUCTION_POINT_ID
|
||||
}
|
||||
|
||||
|
||||
@ -1,9 +0,0 @@
|
||||
import SurveySaleDownloadPdf from '@/components/pdf/SurveySaleDownloadPdf'
|
||||
|
||||
export default function page() {
|
||||
return (
|
||||
<>
|
||||
<SurveySaleDownloadPdf />
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -1,849 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import { useEffect, useRef } from 'react'
|
||||
import generatePDF, { Margin, Resolution } from 'react-to-pdf'
|
||||
import { useParams, useRouter } from 'next/navigation'
|
||||
import { useSurvey } from '@/hooks/useSurvey'
|
||||
import { radioEtcData, roofMaterial, selectBoxOptions, supplementaryFacilities } from '../survey-sale/detail/RoofForm'
|
||||
import { useSpinnerStore } from '@/store/spinnerStore'
|
||||
import { useSessionStore } from '@/store/session'
|
||||
import { ERROR_MESSAGE, SUCCESS_MESSAGE, useAlertMsg } from '@/hooks/useAlertMsg'
|
||||
|
||||
export default function SurveySaleDownloadPdf() {
|
||||
const params = useParams()
|
||||
const id = params.id
|
||||
const router = useRouter()
|
||||
|
||||
const { surveyDetail, isLoadingSurveyDetail } = useSurvey(Number(id), true)
|
||||
const { showErrorAlert, showSuccessAlert } = useAlertMsg()
|
||||
const { setIsShow } = useSpinnerStore()
|
||||
const { session } = useSessionStore()
|
||||
|
||||
const targetRef = useRef<HTMLDivElement>(null)
|
||||
const isGeneratedRef = useRef(false)
|
||||
|
||||
/** 페이지 랜더링 이후 PDF 생성 */
|
||||
useEffect(() => {
|
||||
if (isLoadingSurveyDetail || isGeneratedRef.current) return
|
||||
isGeneratedRef.current = true
|
||||
handleDownPdf()
|
||||
}, [surveyDetail?.id, isLoadingSurveyDetail])
|
||||
|
||||
const handleDownPdf = () => {
|
||||
setIsShow(true)
|
||||
const options = {
|
||||
method: 'open' as const,
|
||||
resolution: Resolution.HIGH,
|
||||
page: {
|
||||
margin: Margin.SMALL,
|
||||
format: 'A4',
|
||||
orientation: 'portrait' as const,
|
||||
},
|
||||
canvas: {
|
||||
mimeType: 'image/png' as const,
|
||||
qualityRatio: 1,
|
||||
},
|
||||
overrides: {
|
||||
pdf: {
|
||||
compress: true,
|
||||
},
|
||||
canvas: {
|
||||
useCORS: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
/** PDF 생성 이후 세션 여부에 따른 라우팅 처리 */
|
||||
generatePDF(targetRef, options)
|
||||
.then(() => {
|
||||
setIsShow(false)
|
||||
if (session?.isLoggedIn) {
|
||||
router.replace(`/survey-sale/${id}`)
|
||||
} else {
|
||||
router.replace('/')
|
||||
}
|
||||
showSuccessAlert(SUCCESS_MESSAGE.PDF_GENERATION_SUCCESS)
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.error('❌ PDF GENERATION ERROR', error)
|
||||
showErrorAlert(ERROR_MESSAGE.PDF_GENERATION_ERROR)
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
ref={targetRef}
|
||||
style={{
|
||||
width: '794px',
|
||||
minHeight: '1123px',
|
||||
transform: 'scale(1.0)',
|
||||
transformOrigin: 'top left',
|
||||
padding: '20px',
|
||||
boxSizing: 'border-box',
|
||||
backgroundColor: '#fff',
|
||||
fontSize: '12px',
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<div style={{ padding: '20px 20px 50px', borderBottom: '2px solid #2E3A59' }}>
|
||||
<div style={{ float: 'left', verticalAlign: 'middle', fontSize: '18px', color: '#101010', fontWeight: 600, fontFamily: 'M-Gothic' }}>
|
||||
HWJ 現地調査シート1/2
|
||||
</div>
|
||||
<div style={{ float: 'right', overflow: 'hidden' }}>
|
||||
<div style={{ float: 'left', marginRight: '20px' }}>
|
||||
<p style={{ margin: 0, padding: 0, fontSize: '13px', color: '#101010', fontWeight: 500, fontFamily: 'M-Gothic', textAlign: 'right' }}>
|
||||
現地明登施工店名
|
||||
</p>
|
||||
<p style={{ margin: 0, padding: 0, fontSize: '13px', color: '#FF5656', fontWeight: 400, fontFamily: 'M-Gothic' }}>
|
||||
{surveyDetail?.store ?? '-'}
|
||||
</p>
|
||||
</div>
|
||||
<div style={{ float: 'right' }}>
|
||||
<p style={{ margin: 0, padding: 0, fontSize: '13px', color: '#101010', fontWeight: 500, fontFamily: 'M-Gothic' }}>現地阴買日</p>
|
||||
<p style={{ margin: 0, padding: 0, fontSize: '13px', color: '#FF5656', fontWeight: 400, fontFamily: 'M-Gothic' }}>
|
||||
{surveyDetail?.investigationDate ?? '-'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ padding: '24px 20px 12px' }}>
|
||||
<table
|
||||
style={{ width: '100%', tableLayout: 'fixed', borderCollapse: 'collapse', fontFamily: 'M-Gothic', WebkitPrintColorAdjust: 'exact' }}
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th
|
||||
style={{
|
||||
padding: '10px',
|
||||
width: '73px',
|
||||
border: '1px solid #2E3A59',
|
||||
backgroundColor: '#F5F6FA',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#101010',
|
||||
textAlign: 'left',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
お客様名
|
||||
</th>
|
||||
<td
|
||||
style={{
|
||||
padding: '10px',
|
||||
border: '1px solid #2E3A59',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#FF5656',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{surveyDetail?.customerName ?? '-'}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
style={{
|
||||
padding: '10px',
|
||||
width: '73px',
|
||||
border: '1px solid #2E3A59',
|
||||
backgroundColor: '#F5F6FA',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#101010',
|
||||
textAlign: 'left',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
ご住所
|
||||
</th>
|
||||
<td
|
||||
style={{
|
||||
padding: '10px',
|
||||
border: '1px solid #2E3A59',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#FF5656',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{surveyDetail?.postCode ? `(${surveyDetail?.postCode}) ${surveyDetail?.address} ${surveyDetail?.addressDetail}` : '-'}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div style={{ padding: '12px 20px 12px' }}>
|
||||
<div style={{ fontSize: '14px', fontFamily: 'M-Gothic', color: '#101010', fontWeight: 500, marginBottom: '10px' }}>も気開係</div>
|
||||
<table
|
||||
style={{ width: '100%', tableLayout: 'fixed', borderCollapse: 'collapse', fontFamily: 'M-Gothic', WebkitPrintColorAdjust: 'exact' }}
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th
|
||||
style={{
|
||||
padding: '10px',
|
||||
width: '126px',
|
||||
border: '1px solid #2E3A59',
|
||||
backgroundColor: '#F5F6FA',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#101010',
|
||||
textAlign: 'left',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
雨気契约容国
|
||||
</th>
|
||||
<td
|
||||
style={{
|
||||
padding: '10px',
|
||||
border: '1px solid #2E3A59',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#FF5656',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{surveyDetail?.detailInfo?.contractCapacity ?? '-'}
|
||||
</td>
|
||||
<th
|
||||
style={{
|
||||
padding: '10px',
|
||||
width: '126px',
|
||||
border: '1px solid #2E3A59',
|
||||
backgroundColor: '#F5F6FA',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#101010',
|
||||
textAlign: 'left',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
電気契約会社
|
||||
</th>
|
||||
<td
|
||||
style={{
|
||||
padding: '10px',
|
||||
border: '1px solid #2E3A59',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#FF5656',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{surveyDetail?.detailInfo?.retailCompany ?? '-'}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
style={{
|
||||
padding: '10px',
|
||||
width: '126px',
|
||||
border: '1px solid #2E3A59',
|
||||
backgroundColor: '#F5F6FA',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#101010',
|
||||
textAlign: 'left',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
電気付带設備
|
||||
</th>
|
||||
<td
|
||||
colSpan={3}
|
||||
style={{
|
||||
padding: '10px',
|
||||
border: '1px solid #2E3A59',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#FF5656',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{surveyDetail?.detailInfo?.supplementaryFacilities
|
||||
? supplementaryFacilities
|
||||
.filter((facility) => surveyDetail?.detailInfo?.supplementaryFacilities?.includes(facility.id.toString()))
|
||||
.map((facility) => facility.name)
|
||||
.join(', ') +
|
||||
(surveyDetail?.detailInfo?.supplementaryFacilitiesEtc ? `, ${surveyDetail?.detailInfo?.supplementaryFacilitiesEtc}` : '')
|
||||
: surveyDetail?.detailInfo?.supplementaryFacilitiesEtc
|
||||
? `${surveyDetail?.detailInfo?.supplementaryFacilitiesEtc}`
|
||||
: '-'}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
style={{
|
||||
padding: '10px',
|
||||
width: '126px',
|
||||
border: '1px solid #2E3A59',
|
||||
backgroundColor: '#F5F6FA',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#101010',
|
||||
textAlign: 'left',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
設置希望システム
|
||||
</th>
|
||||
<td
|
||||
colSpan={3}
|
||||
style={{
|
||||
padding: '10px',
|
||||
border: '1px solid #2E3A59',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#FF5656',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{/* {selectBoxOptions.installationSystem.find ((system) => system.id.toString() === surveyDetail?.detailInfo?.installationSystem)
|
||||
?.name ?? surveyDetail?.detailInfo?.installationSystemEtc !== null
|
||||
? `${surveyDetail?.detailInfo?.installationSystemEtc}`
|
||||
: '-'} */}
|
||||
{surveyDetail?.detailInfo?.installationSystem === null && surveyDetail?.detailInfo?.installationSystemEtc === null
|
||||
? '-'
|
||||
: surveyDetail?.detailInfo?.installationSystemEtc
|
||||
? `${surveyDetail?.detailInfo?.installationSystemEtc}`
|
||||
: selectBoxOptions.installationSystem.find((system) => system.id.toString() === surveyDetail?.detailInfo?.installationSystem)
|
||||
?.name}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div style={{ padding: '12px 20px 12px' }}>
|
||||
<div style={{ fontSize: '14px', fontFamily: 'M-Gothic', color: '#101010', fontWeight: 500, marginBottom: '10px' }}>屋根眀係</div>
|
||||
<table
|
||||
style={{ width: '100%', tableLayout: 'fixed', borderCollapse: 'collapse', fontFamily: 'M-Gothic', WebkitPrintColorAdjust: 'exact' }}
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th
|
||||
style={{
|
||||
padding: '10px',
|
||||
width: '126px',
|
||||
border: '1px solid #2E3A59',
|
||||
backgroundColor: '#F5F6FA',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#101010',
|
||||
textAlign: 'left',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
築年数
|
||||
</th>
|
||||
<td
|
||||
style={{
|
||||
padding: '10px',
|
||||
border: '1px solid #2E3A59',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#FF5656',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{surveyDetail?.detailInfo?.constructionYear === '1'
|
||||
? '新築'
|
||||
: surveyDetail?.detailInfo?.constructionYearEtc
|
||||
? `既築 (${surveyDetail?.detailInfo?.constructionYear}年)`
|
||||
: '-'}
|
||||
</td>
|
||||
<th
|
||||
style={{
|
||||
padding: '10px',
|
||||
width: '126px',
|
||||
border: '1px solid #2E3A59',
|
||||
backgroundColor: '#F5F6FA',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#101010',
|
||||
textAlign: 'left',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
至根材
|
||||
</th>
|
||||
<td
|
||||
style={{
|
||||
padding: '10px',
|
||||
border: '1px solid #2E3A59',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#FF5656',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{surveyDetail?.detailInfo?.roofMaterial === null && surveyDetail?.detailInfo?.roofMaterialEtc === null
|
||||
? '-'
|
||||
: roofMaterial
|
||||
.filter((material) => surveyDetail?.detailInfo?.roofMaterial?.includes(material.id.toString()))
|
||||
.map((material) => material.name)
|
||||
.join(', ')}
|
||||
{surveyDetail?.detailInfo?.roofMaterialEtc ? `, ${surveyDetail?.detailInfo?.roofMaterialEtc}` : ''}
|
||||
</td>
|
||||
<th
|
||||
style={{
|
||||
padding: '10px',
|
||||
width: '126px',
|
||||
border: '1px solid #2E3A59',
|
||||
backgroundColor: '#F5F6FA',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#101010',
|
||||
textAlign: 'left',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
座根形状
|
||||
</th>
|
||||
<td
|
||||
style={{
|
||||
padding: '10px',
|
||||
border: '1px solid #2E3A59',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#FF5656',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{selectBoxOptions.roofShape.find((shape) => shape.id.toString() === surveyDetail?.detailInfo?.roofShape)?.name ??
|
||||
(surveyDetail?.detailInfo?.roofShapeEtc ? ` ${surveyDetail?.detailInfo?.roofShapeEtc}` : '-')}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
style={{
|
||||
padding: '10px',
|
||||
width: '126px',
|
||||
border: '1px solid #2E3A59',
|
||||
backgroundColor: '#F5F6FA',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#101010',
|
||||
textAlign: 'left',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
座根勾配
|
||||
</th>
|
||||
<td
|
||||
style={{
|
||||
padding: '10px',
|
||||
border: '1px solid #2E3A59',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#FF5656',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{surveyDetail?.detailInfo?.roofSlope ? `${surveyDetail?.detailInfo?.roofSlope} 寸` : '-'}
|
||||
</td>
|
||||
<th
|
||||
style={{
|
||||
padding: '10px',
|
||||
width: '126px',
|
||||
border: '1px solid #2E3A59',
|
||||
backgroundColor: '#F5F6FA',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#101010',
|
||||
textAlign: 'left',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
住宅樠造
|
||||
</th>
|
||||
<td
|
||||
colSpan={3}
|
||||
style={{
|
||||
padding: '10px',
|
||||
border: '1px solid #2E3A59',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#FF5656',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{radioEtcData.houseStructure.find((structure) => structure.id.toString() === surveyDetail?.detailInfo?.houseStructure)?.label ??
|
||||
(surveyDetail?.detailInfo?.houseStructureEtc ? ` ${surveyDetail?.detailInfo?.houseStructureEtc}` : '-')}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
style={{
|
||||
padding: '10px',
|
||||
width: '126px',
|
||||
border: '1px solid #2E3A59',
|
||||
backgroundColor: '#F5F6FA',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#101010',
|
||||
textAlign: 'left',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
並木材質
|
||||
</th>
|
||||
<td
|
||||
style={{
|
||||
padding: '10px',
|
||||
border: '1px solid #2E3A59',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#FF5656',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{/* {surveyDetail?.detailInfo?.rafterMaterial === null && surveyDetail?.detailInfo?.rafterMaterialEtc === null
|
||||
? '-'
|
||||
: radioEtcData.rafterMaterial.find((material) => material.id.toString() === surveyDetail?.detailInfo?.rafterMaterial)?.label ??
|
||||
surveyDetail?.detailInfo?.rafterMaterialEtc} */}
|
||||
{radioEtcData.rafterMaterial.find((material) => material.id.toString() === surveyDetail?.detailInfo?.rafterMaterial)?.label ??
|
||||
(surveyDetail?.detailInfo?.rafterMaterialEtc ? ` ${surveyDetail?.detailInfo?.rafterMaterialEtc}` : '-')}
|
||||
</td>
|
||||
<th
|
||||
style={{
|
||||
padding: '10px',
|
||||
width: '126px',
|
||||
border: '1px solid #2E3A59',
|
||||
backgroundColor: '#F5F6FA',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#101010',
|
||||
textAlign: 'left',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
垂木サイズ
|
||||
</th>
|
||||
<td
|
||||
colSpan={3}
|
||||
style={{
|
||||
padding: '10px',
|
||||
border: '1px solid #2E3A59',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#FF5656',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{selectBoxOptions.rafterSize.find((size) => size.id.toString() === surveyDetail?.detailInfo?.rafterSize)?.name ??
|
||||
(surveyDetail?.detailInfo?.rafterSizeEtc ? ` ${surveyDetail?.detailInfo?.rafterSizeEtc}` : '-')}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
style={{
|
||||
padding: '10px',
|
||||
width: '126px',
|
||||
border: '1px solid #2E3A59',
|
||||
backgroundColor: '#F5F6FA',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#101010',
|
||||
textAlign: 'left',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
垂木ピッチ
|
||||
</th>
|
||||
<td
|
||||
style={{
|
||||
padding: '10px',
|
||||
border: '1px solid #2E3A59',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#FF5656',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{selectBoxOptions.rafterPitch.find((pitch) => pitch.id.toString() === surveyDetail?.detailInfo?.rafterPitch)?.name ??
|
||||
(surveyDetail?.detailInfo?.rafterPitchEtc ? ` ${surveyDetail?.detailInfo?.rafterPitchEtc}` : '-')}
|
||||
</td>
|
||||
<th
|
||||
style={{
|
||||
padding: '10px',
|
||||
width: '126px',
|
||||
border: '1px solid #2E3A59',
|
||||
backgroundColor: '#F5F6FA',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#101010',
|
||||
textAlign: 'left',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
垂木方向
|
||||
</th>
|
||||
<td
|
||||
colSpan={3}
|
||||
style={{
|
||||
padding: '10px',
|
||||
border: '1px solid #2E3A59',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#FF5656',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{radioEtcData.rafterDirection.find((direction) => direction.id.toString() === surveyDetail?.detailInfo?.rafterDirection)?.label ??
|
||||
'-'}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
style={{
|
||||
padding: '10px',
|
||||
width: '126px',
|
||||
border: '1px solid #2E3A59',
|
||||
backgroundColor: '#F5F6FA',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#101010',
|
||||
textAlign: 'left',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
野地板種類
|
||||
</th>
|
||||
<td
|
||||
style={{
|
||||
padding: '10px',
|
||||
border: '1px solid #2E3A59',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#FF5656',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{selectBoxOptions.openFieldPlateKind.find((kind) => kind.id.toString() === surveyDetail?.detailInfo?.openFieldPlateKind)?.name ??
|
||||
(surveyDetail?.detailInfo?.openFieldPlateKindEtc ? `${surveyDetail?.detailInfo?.openFieldPlateKindEtc}` : '-')}
|
||||
</td>
|
||||
<th
|
||||
style={{
|
||||
padding: '10px',
|
||||
width: '126px',
|
||||
border: '1px solid #2E3A59',
|
||||
backgroundColor: '#F5F6FA',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#101010',
|
||||
textAlign: 'left',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
野地板厚さ
|
||||
</th>
|
||||
<td
|
||||
colSpan={3}
|
||||
style={{
|
||||
padding: '10px',
|
||||
border: '1px solid #2E3A59',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#FF5656',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{surveyDetail?.detailInfo?.openFieldPlateThickness ? `${surveyDetail?.detailInfo?.openFieldPlateThickness}mm` : '-'}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
style={{
|
||||
padding: '10px',
|
||||
width: '126px',
|
||||
border: '1px solid #2E3A59',
|
||||
backgroundColor: '#F5F6FA',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#101010',
|
||||
textAlign: 'left',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
兩漏の形跡
|
||||
</th>
|
||||
<td
|
||||
colSpan={5}
|
||||
style={{
|
||||
padding: '10px',
|
||||
border: '1px solid #2E3A59',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#FF5656',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{surveyDetail?.detailInfo?.leakTrace ? 'あり' : 'なし'}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
style={{
|
||||
padding: '10px',
|
||||
width: '126px',
|
||||
border: '1px solid #2E3A59',
|
||||
backgroundColor: '#F5F6FA',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#101010',
|
||||
textAlign: 'left',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
ルーフィング種類
|
||||
</th>
|
||||
<td
|
||||
colSpan={5}
|
||||
style={{
|
||||
padding: '10px',
|
||||
border: '1px solid #2E3A59',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#FF5656',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{radioEtcData.waterproofMaterial.find((material) => material.id.toString() === surveyDetail?.detailInfo?.waterproofMaterial)
|
||||
?.label ?? (surveyDetail?.detailInfo?.waterproofMaterialEtc ? ` ${surveyDetail?.detailInfo?.waterproofMaterialEtc}` : '-')}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
style={{
|
||||
padding: '10px',
|
||||
width: '126px',
|
||||
border: '1px solid #2E3A59',
|
||||
backgroundColor: '#F5F6FA',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#101010',
|
||||
textAlign: 'left',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
断熱材の有無
|
||||
</th>
|
||||
<td
|
||||
colSpan={5}
|
||||
style={{
|
||||
padding: '10px',
|
||||
border: '1px solid #2E3A59',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#FF5656',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{
|
||||
radioEtcData.insulationPresence.find((presence) => presence.id.toString() === surveyDetail?.detailInfo?.insulationPresence)
|
||||
?.label
|
||||
}
|
||||
{surveyDetail?.detailInfo?.insulationPresenceEtc ? `, ${surveyDetail?.detailInfo?.insulationPresenceEtc}` : ''}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
style={{
|
||||
padding: '10px',
|
||||
width: '126px',
|
||||
border: '1px solid #2E3A59',
|
||||
backgroundColor: '#F5F6FA',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#101010',
|
||||
textAlign: 'left',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
屋根構造の順番
|
||||
</th>
|
||||
<td
|
||||
colSpan={5}
|
||||
style={{
|
||||
padding: '10px',
|
||||
border: '1px solid #2E3A59',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#FF5656',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{radioEtcData.structureOrder.find((order) => order.id.toString() === surveyDetail?.detailInfo?.structureOrder)?.label ??
|
||||
(surveyDetail?.detailInfo?.structureOrderEtc ? `${surveyDetail?.detailInfo?.structureOrderEtc}` : '-')}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div style={{ padding: '12px 20px' }}>
|
||||
<table
|
||||
style={{ width: '100%', tableLayout: 'fixed', borderCollapse: 'collapse', fontFamily: 'M-Gothic', WebkitPrintColorAdjust: 'exact' }}
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th
|
||||
style={{
|
||||
padding: '10px',
|
||||
width: '160px',
|
||||
border: '1px solid #2E3A59',
|
||||
backgroundColor: '#F5F6FA',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#101010',
|
||||
textAlign: 'left',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
区根製品名設置可否確認
|
||||
</th>
|
||||
<td
|
||||
colSpan={5}
|
||||
style={{
|
||||
padding: '10px',
|
||||
border: '1px solid #2E3A59',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
color: '#FF5656',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{surveyDetail?.detailInfo?.installationAvailability === null && surveyDetail.detailInfo?.installationAvailabilityEtc === null
|
||||
? '-'
|
||||
: selectBoxOptions.installationAvailability.find(
|
||||
(availability) => availability.id.toString() === surveyDetail?.detailInfo?.installationAvailability,
|
||||
)?.name}
|
||||
{surveyDetail?.detailInfo?.installationAvailabilityEtc ? `, ${surveyDetail?.detailInfo?.installationAvailabilityEtc}` : ''}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div style={{ padding: '12px 20px 12px' }}>
|
||||
<div style={{ fontSize: '14px', fontFamily: 'M-Gothic', color: '#101010', fontWeight: 500, marginBottom: '10px' }}>メモ</div>
|
||||
<div
|
||||
style={{
|
||||
boxSizing: 'border-box',
|
||||
padding: '10px',
|
||||
fontSize: '13px',
|
||||
fontWeight: 400,
|
||||
fontFamily: 'M-Gothic',
|
||||
color: '#FF5656',
|
||||
border: '1px solid #2E3A59',
|
||||
height: '150px',
|
||||
}}
|
||||
>
|
||||
{surveyDetail?.detailInfo?.memo ?? '-'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
330
src/components/pdf/SurveySalePdf.tsx
Normal file
330
src/components/pdf/SurveySalePdf.tsx
Normal file
@ -0,0 +1,330 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { Font, Page, Text, View, StyleSheet } from '@react-pdf/renderer'
|
||||
import { radioEtcData, selectBoxOptions, supplementaryFacilities, roofMaterial } from '@/types/Survey'
|
||||
import { SurveyBasicInfo } from '@/types/Survey'
|
||||
|
||||
Font.register({
|
||||
family: 'NotoSansJP',
|
||||
src: `data:font/ttf;base64,${fs.readFileSync(path.resolve(process.cwd(), 'src/components/pdf/NotoSansJP-Regular.ttf')).toString('base64')}`,
|
||||
})
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
page: {
|
||||
padding: 15,
|
||||
fontFamily: 'NotoSansJP',
|
||||
fontSize: 8,
|
||||
backgroundColor: '#fff',
|
||||
},
|
||||
header: {
|
||||
padding: '15px 15px 15px',
|
||||
borderBottom: '2px solid #2E3A59',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
},
|
||||
title: {
|
||||
fontSize: 14,
|
||||
color: '#101010',
|
||||
fontWeight: 'bold',
|
||||
fontFamily: 'NotoSansJP',
|
||||
},
|
||||
headerRight: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-start',
|
||||
},
|
||||
headerLeft: {
|
||||
marginRight: 15,
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
headerLabel: {
|
||||
fontSize: 9,
|
||||
color: '#101010',
|
||||
fontWeight: 'bold',
|
||||
fontFamily: 'NotoSansJP',
|
||||
textAlign: 'right',
|
||||
margin: 0,
|
||||
},
|
||||
headerValue: {
|
||||
fontSize: 9,
|
||||
color: '#FF5656',
|
||||
fontWeight: 400,
|
||||
fontFamily: 'NotoSansJP',
|
||||
margin: 0,
|
||||
},
|
||||
section: {
|
||||
padding: '20px 15px 8px',
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 10,
|
||||
fontFamily: 'NotoSansJP',
|
||||
color: '#101010',
|
||||
fontWeight: 'bold',
|
||||
marginBottom: 8,
|
||||
},
|
||||
table: {
|
||||
width: '100%',
|
||||
},
|
||||
tableRow: {
|
||||
flexDirection: 'row',
|
||||
minHeight: 28,
|
||||
},
|
||||
tableHeader: {
|
||||
padding: 6,
|
||||
backgroundColor: '#F5F6FA',
|
||||
fontSize: 9,
|
||||
fontWeight: 'bold',
|
||||
color: '#101010',
|
||||
border: '1px solid #2E3A59',
|
||||
fontFamily: 'NotoSansJP',
|
||||
justifyContent: 'flex-start',
|
||||
alignItems: 'center',
|
||||
},
|
||||
tableCell: {
|
||||
padding: 6,
|
||||
fontSize: 9,
|
||||
fontWeight: 500,
|
||||
color: '#FF5656',
|
||||
border: '1px solid #2E3A59',
|
||||
fontFamily: 'NotoSansJP',
|
||||
justifyContent: 'flex-start',
|
||||
alignItems: 'center',
|
||||
},
|
||||
tableHeaderSmall: {
|
||||
width: 50,
|
||||
},
|
||||
tableHeaderMedium: {
|
||||
width: 85,
|
||||
},
|
||||
tableHeaderLarge: {
|
||||
width: 110,
|
||||
},
|
||||
tableCellFlex1: {
|
||||
flex: 1,
|
||||
},
|
||||
tableCellFlex2: {
|
||||
flex: 2,
|
||||
},
|
||||
tableCellFlex07: {
|
||||
flex: 0.5745,
|
||||
},
|
||||
memoBox: {
|
||||
padding: 6,
|
||||
fontSize: 9,
|
||||
fontWeight: 400,
|
||||
fontFamily: 'NotoSansJP',
|
||||
color: '#FF5656',
|
||||
border: '1px solid #2E3A59',
|
||||
minHeight: 100,
|
||||
width: '100%',
|
||||
},
|
||||
sectionNoPadding: {
|
||||
padding: '10px 15px',
|
||||
},
|
||||
marginL: {
|
||||
marginLeft: -1,
|
||||
},
|
||||
marginT: {
|
||||
marginTop: -1,
|
||||
}
|
||||
})
|
||||
|
||||
export default function SurveySalePdf({ survey }: { survey: SurveyBasicInfo }) {
|
||||
return (
|
||||
<Page size="A4" style={styles.page}>
|
||||
{/* Header */}
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.title}>HWJ 現地調査シート1/2</Text>
|
||||
<View style={styles.headerRight}>
|
||||
<View style={styles.headerLeft}>
|
||||
<Text style={styles.headerLabel}>現地明登施工店名</Text>
|
||||
<Text style={styles.headerValue}>{survey?.store ?? '-'}</Text>
|
||||
</View>
|
||||
<View>
|
||||
<Text style={styles.headerLabel}>現地阴買日</Text>
|
||||
<Text style={styles.headerValue}>{survey?.investigationDate ?? '-'}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Customer Info */}
|
||||
<View style={styles.section}>
|
||||
<View style={styles.table}>
|
||||
<View style={styles.tableRow}>
|
||||
<Text style={[styles.tableHeader, styles.tableHeaderSmall]}>お客様名</Text>
|
||||
<Text style={[styles.tableCell, styles.tableCellFlex1, styles.marginL]}>{survey?.customerName ?? '-'}</Text>
|
||||
</View>
|
||||
<View style={styles.tableRow}>
|
||||
<Text style={[styles.tableHeader, styles.tableHeaderSmall, styles.marginT]}>ご住所</Text>
|
||||
<Text style={[styles.tableCell, styles.tableCellFlex1, styles.marginL, styles.marginT]}>
|
||||
{survey?.postCode ? `(${survey?.postCode}) ${survey?.address} ${survey?.addressDetail}` : '-'}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Electric Info */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>も気開係</Text>
|
||||
<View style={styles.table}>
|
||||
<View style={styles.tableRow}>
|
||||
<Text style={[styles.tableHeader, styles.tableHeaderMedium]}>雨気契约容国</Text>
|
||||
<Text style={[styles.tableCell, styles.tableCellFlex1, styles.marginL]}>{survey?.detailInfo?.contractCapacity ?? '-'}</Text>
|
||||
<Text style={[styles.tableHeader, styles.tableHeaderMedium, styles.marginL]}>電気契約会社</Text>
|
||||
<Text style={[styles.tableCell, styles.tableCellFlex1, styles.marginL]}>{survey?.detailInfo?.retailCompany ?? '-'}</Text>
|
||||
</View>
|
||||
<View style={styles.tableRow}>
|
||||
<Text style={[styles.tableHeader, styles.tableHeaderMedium, styles.marginT]}>電気付带設備</Text>
|
||||
<Text style={[styles.tableCell, styles.tableCellFlex1, styles.marginL, styles.marginT]}>
|
||||
{survey?.detailInfo?.supplementaryFacilities
|
||||
? supplementaryFacilities
|
||||
.filter((facility) => survey?.detailInfo?.supplementaryFacilities?.includes(facility.id.toString()))
|
||||
.map((facility) => facility.name)
|
||||
.join(', ') + (survey?.detailInfo?.supplementaryFacilitiesEtc ? `, ${survey?.detailInfo?.supplementaryFacilitiesEtc}` : '')
|
||||
: survey?.detailInfo?.supplementaryFacilitiesEtc
|
||||
? `${survey?.detailInfo?.supplementaryFacilitiesEtc}`
|
||||
: '-'}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.tableRow}>
|
||||
<Text style={[styles.tableHeader, styles.tableHeaderMedium, styles.marginT]}>設置希望システム</Text>
|
||||
<Text style={[styles.tableCell, styles.tableCellFlex1, styles.marginL, styles.marginT]}>
|
||||
{survey?.detailInfo?.installationSystem === null && survey?.detailInfo?.installationSystemEtc === null
|
||||
? '-'
|
||||
: survey?.detailInfo?.installationSystemEtc
|
||||
? `${survey?.detailInfo?.installationSystemEtc}`
|
||||
: selectBoxOptions.installationSystem.find((system) => system.id.toString() === survey?.detailInfo?.installationSystem)?.name}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Roof Info */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>屋根眀係</Text>
|
||||
<View style={styles.table}>
|
||||
<View style={styles.tableRow}>
|
||||
<Text style={[styles.tableHeader, styles.tableHeaderMedium]}>築年数</Text>
|
||||
<Text style={[styles.tableCell, styles.tableCellFlex1, styles.marginL]}>
|
||||
{survey?.detailInfo?.constructionYear === '1'
|
||||
? '新築'
|
||||
: survey?.detailInfo?.constructionYearEtc
|
||||
? `既築 (${survey?.detailInfo?.constructionYear}年)`
|
||||
: '-'}
|
||||
</Text>
|
||||
<Text style={[styles.tableHeader, styles.tableHeaderMedium, styles.marginL]}>至根材</Text>
|
||||
<Text style={[styles.tableCell, styles.tableCellFlex07, styles.marginL, styles.marginL]}>
|
||||
{survey?.detailInfo?.roofMaterial === null && survey?.detailInfo?.roofMaterialEtc === null
|
||||
? '-'
|
||||
: roofMaterial
|
||||
.filter((material) => survey?.detailInfo?.roofMaterial?.includes(material.id.toString()))
|
||||
.map((material) => material.name)
|
||||
.join(', ')}
|
||||
{survey?.detailInfo?.roofMaterialEtc ? `, ${survey?.detailInfo?.roofMaterialEtc}` : ''}
|
||||
</Text>
|
||||
<Text style={[styles.tableHeader, styles.tableHeaderMedium, styles.marginL]}>座根形状</Text>
|
||||
<Text style={[styles.tableCell, styles.tableCellFlex07, styles.marginL]}>
|
||||
{selectBoxOptions.roofShape.find((shape) => shape.id.toString() === survey?.detailInfo?.roofShape)?.name ??
|
||||
(survey?.detailInfo?.roofShapeEtc ? ` ${survey?.detailInfo?.roofShapeEtc}` : '-')}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.tableRow}>
|
||||
<Text style={[styles.tableHeader, styles.tableHeaderMedium, styles.marginT]}>座根勾配</Text>
|
||||
<Text style={[styles.tableCell, styles.tableCellFlex1, styles.marginL, styles.marginT, styles.marginL]}>
|
||||
{survey?.detailInfo?.roofSlope ? `${survey?.detailInfo?.roofSlope} 寸` : '-'}
|
||||
</Text>
|
||||
<Text style={[styles.tableHeader, styles.tableHeaderMedium, styles.marginL, styles.marginT]}>住宅樠造</Text>
|
||||
<Text style={[styles.tableCell, styles.tableCellFlex2, styles.marginL, styles.marginL, styles.marginT]}>
|
||||
{radioEtcData.houseStructure.find((structure) => structure.id.toString() === survey?.detailInfo?.houseStructure)?.label ??
|
||||
(survey?.detailInfo?.houseStructureEtc ? ` ${survey?.detailInfo?.houseStructureEtc}` : '-')}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.tableRow}>
|
||||
<Text style={[styles.tableHeader, styles.tableHeaderMedium, styles.marginT]}>並木材質</Text>
|
||||
<Text style={[styles.tableCell, styles.tableCellFlex1, styles.marginL, styles.marginT]}>
|
||||
{radioEtcData.rafterMaterial.find((material) => material.id.toString() === survey?.detailInfo?.rafterMaterial)?.label ??
|
||||
(survey?.detailInfo?.rafterMaterialEtc ? ` ${survey?.detailInfo?.rafterMaterialEtc}` : '-')}
|
||||
</Text>
|
||||
<Text style={[styles.tableHeader, styles.tableHeaderMedium, styles.marginL, styles.marginT]}>垂木サイズ</Text>
|
||||
<Text style={[styles.tableCell, styles.tableCellFlex2, styles.marginL, styles.marginL, styles.marginT]}>
|
||||
{selectBoxOptions.rafterSize.find((size) => size.id.toString() === survey?.detailInfo?.rafterSize)?.name ??
|
||||
(survey?.detailInfo?.rafterSizeEtc ? ` ${survey?.detailInfo?.rafterSizeEtc}` : '-')}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.tableRow}>
|
||||
<Text style={[styles.tableHeader, styles.tableHeaderMedium, styles.marginT]}>垂木ピッチ</Text>
|
||||
<Text style={[styles.tableCell, styles.tableCellFlex1, styles.marginL, styles.marginT]}>
|
||||
{selectBoxOptions.rafterPitch.find((pitch) => pitch.id.toString() === survey?.detailInfo?.rafterPitch)?.name ??
|
||||
(survey?.detailInfo?.rafterPitchEtc ? ` ${survey?.detailInfo?.rafterPitchEtc}` : '-')}
|
||||
</Text>
|
||||
<Text style={[styles.tableHeader, styles.tableHeaderMedium, styles.marginL, styles.marginT]}>垂木方向</Text>
|
||||
<Text style={[styles.tableCell, styles.tableCellFlex2, styles.marginL, styles.marginT]}>
|
||||
{radioEtcData.rafterDirection.find((direction) => direction.id.toString() === survey?.detailInfo?.rafterDirection)?.label ?? '-'}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.tableRow}>
|
||||
<Text style={[styles.tableHeader, styles.tableHeaderMedium, styles.marginT]}>野地板種類</Text>
|
||||
<Text style={[styles.tableCell, styles.tableCellFlex1, styles.marginL, styles.marginT]}>
|
||||
{selectBoxOptions.openFieldPlateKind.find((kind) => kind.id.toString() === survey?.detailInfo?.openFieldPlateKind)?.name ??
|
||||
(survey?.detailInfo?.openFieldPlateKindEtc ? `${survey?.detailInfo?.openFieldPlateKindEtc}` : '-')}
|
||||
</Text>
|
||||
<Text style={[styles.tableHeader, styles.tableHeaderMedium, styles.marginL, styles.marginT]}>野地板厚さ</Text>
|
||||
<Text style={[styles.tableCell, styles.tableCellFlex2, styles.marginL, styles.marginT]}>
|
||||
{survey?.detailInfo?.openFieldPlateThickness ? `${survey?.detailInfo?.openFieldPlateThickness}mm` : '-'}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.tableRow}>
|
||||
<Text style={[styles.tableHeader, styles.tableHeaderMedium, styles.marginT]}>兩漏の形跡</Text>
|
||||
<Text style={[styles.tableCell, styles.tableCellFlex1, styles.marginL, styles.marginT]}>{survey?.detailInfo?.leakTrace ? 'あり' : 'なし'}</Text>
|
||||
</View>
|
||||
<View style={styles.tableRow}>
|
||||
<Text style={[styles.tableHeader, styles.tableHeaderMedium, styles.marginT]}>ルーフィング種類</Text>
|
||||
<Text style={[styles.tableCell, styles.tableCellFlex1, styles.marginL, styles.marginT]}>
|
||||
{radioEtcData.waterproofMaterial.find((material) => material.id.toString() === survey?.detailInfo?.waterproofMaterial)?.label ??
|
||||
(survey?.detailInfo?.waterproofMaterialEtc ? ` ${survey?.detailInfo?.waterproofMaterialEtc}` : '-')}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.tableRow}>
|
||||
<Text style={[styles.tableHeader, styles.tableHeaderMedium, styles.marginT]}>断熱材の有無</Text>
|
||||
<Text style={[styles.tableCell, styles.tableCellFlex1, styles.marginL, styles.marginT]}>
|
||||
{radioEtcData.insulationPresence.find((presence) => presence.id.toString() === survey?.detailInfo?.insulationPresence)?.label}
|
||||
{survey?.detailInfo?.insulationPresenceEtc ? `, ${survey?.detailInfo?.insulationPresenceEtc}` : ''}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.tableRow}>
|
||||
<Text style={[styles.tableHeader, styles.tableHeaderMedium, styles.marginT]}>屋根構造の順番</Text>
|
||||
<Text style={[styles.tableCell, styles.tableCellFlex1, styles.marginL, styles.marginT]}>
|
||||
{radioEtcData.structureOrder.find((order) => order.id.toString() === survey?.detailInfo?.structureOrder)?.label ??
|
||||
(survey?.detailInfo?.structureOrderEtc ? `${survey?.detailInfo?.structureOrderEtc}` : '-')}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Installation Availability */}
|
||||
<View style={styles.sectionNoPadding}>
|
||||
<View style={styles.table}>
|
||||
<View style={styles.tableRow}>
|
||||
<Text style={[styles.tableHeader, styles.tableHeaderLarge]}>区根製品名設置可否確認</Text>
|
||||
<Text style={[styles.tableCell, styles.tableCellFlex1, styles.marginL]}>
|
||||
{survey?.detailInfo?.installationAvailability === null && survey.detailInfo?.installationAvailabilityEtc === null
|
||||
? '-'
|
||||
: selectBoxOptions.installationAvailability.find(
|
||||
(availability) => availability.id.toString() === survey?.detailInfo?.installationAvailability,
|
||||
)?.name}
|
||||
{survey?.detailInfo?.installationAvailabilityEtc ? `, ${survey?.detailInfo?.installationAvailabilityEtc}` : ''}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Memo */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>メモ</Text>
|
||||
<View style={styles.memoBox}>
|
||||
<Text>{survey?.detailInfo?.memo ?? '-'}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
@ -181,7 +181,7 @@ export default function SurveySaleSubmitPopup() {
|
||||
<p>
|
||||
<a
|
||||
style="font-size: 13px; font-weight: 400; color: #1259CB; margin-bottom: 5px; text-decoration: underline;"
|
||||
href="${process.env.NEXT_PUBLIC_API_URL}/pdf/survey-sale/${surveyDetail?.id}"
|
||||
href="${process.env.NEXT_PUBLIC_API_URL}/api/survey-sales/${surveyDetail?.id}?isPdf=true"
|
||||
target="_blank"
|
||||
>
|
||||
現地調査結果PDFダウンロード
|
||||
|
||||
@ -68,7 +68,7 @@ export default function ButtonForm({ mode, setMode, data }: ButtonFormProps) {
|
||||
const calculatePermissions = (session: any, basicData: SurveyBasicRequest): PermissionState => {
|
||||
const isSubmiter = calculateSubmitPermission(session, basicData)
|
||||
const isWriter = session.userId === basicData.representativeId
|
||||
const isReceiver = session?.storeId === basicData.submissionTargetId
|
||||
const isReceiver = session?.storeId === basicData.submissionTargetId || session?.storeNm === basicData.submissionTargetNm
|
||||
|
||||
return { isSubmiter, isWriter, isReceiver }
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { SurveyBasicInfo } from '@/types/Survey'
|
||||
import { useSurvey } from '@/hooks/useSurvey'
|
||||
|
||||
export default function DataTable({ surveyDetail }: { surveyDetail: SurveyBasicInfo }) {
|
||||
const router = useRouter()
|
||||
@ -9,21 +10,19 @@ export default function DataTable({ surveyDetail }: { surveyDetail: SurveyBasicI
|
||||
/** 제출 상태 처리 */
|
||||
const submitStatus = () => {
|
||||
const { submissionTargetNm, submissionTargetId } = surveyDetail ?? {}
|
||||
|
||||
if (!submissionTargetNm) {
|
||||
return null
|
||||
if (!submissionTargetId && !submissionTargetNm) {
|
||||
return <div>( Hanwha Japan )</div>
|
||||
}
|
||||
|
||||
if (!submissionTargetId) {
|
||||
return <div>{submissionTargetNm}</div>
|
||||
if (!submissionTargetId && submissionTargetNm) {
|
||||
return <div>( {submissionTargetNm} )</div>
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
({submissionTargetNm} - {submissionTargetId})
|
||||
</div>
|
||||
)
|
||||
}
|
||||
const { downloadSurveyPdf } = useSurvey()
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -68,7 +67,7 @@ export default function DataTable({ surveyDetail }: { surveyDetail: SurveyBasicI
|
||||
<tr>
|
||||
<th>ダウンロード</th>
|
||||
<td>
|
||||
<button className="data-down" onClick={() => router.push(`/pdf/survey-sale/${surveyDetail.id}`)}>
|
||||
<button className="data-down" onClick={() => downloadSurveyPdf(surveyDetail.id, `${surveyDetail.srlNo}.pdf`)}>
|
||||
HWJ現地調査票確認<i className="down-icon"></i>
|
||||
</button>
|
||||
</td>
|
||||
|
||||
@ -74,7 +74,7 @@ export default function DetailForm() {
|
||||
|
||||
const modeset = !Number.isNaN(Number(id)) ? 'READ' : 'CREATE'
|
||||
|
||||
const { surveyDetail, isLoadingSurveyDetail } = useSurvey(Number(id))
|
||||
const { surveyDetail, isLoadingSurveyDetail } = useSurvey(Number(id), false)
|
||||
const { session } = useSessionStore()
|
||||
const searchParams = useSearchParams()
|
||||
const popupController = usePopupController()
|
||||
|
||||
@ -1,239 +1,7 @@
|
||||
import { useState } from 'react'
|
||||
import type { Mode, SurveyDetailInfo, SurveyDetailRequest } from '@/types/Survey'
|
||||
import { useAlertMsg, WARNING_MESSAGE } from '@/hooks/useAlertMsg'
|
||||
|
||||
type RadioEtcKeys =
|
||||
| 'structureOrder'
|
||||
| 'houseStructure'
|
||||
| 'rafterMaterial'
|
||||
| 'waterproofMaterial'
|
||||
| 'insulationPresence'
|
||||
| 'rafterDirection'
|
||||
| 'leakTrace'
|
||||
type SelectBoxKeys =
|
||||
| 'installationSystem'
|
||||
| 'constructionYear'
|
||||
| 'roofShape'
|
||||
| 'rafterPitch'
|
||||
| 'rafterSize'
|
||||
| 'openFieldPlateKind'
|
||||
| 'installationAvailability'
|
||||
|
||||
export const supplementaryFacilities = [
|
||||
/** 에코큐트 */
|
||||
{ id: 1, name: 'エコキュート' },
|
||||
/** 에네팜 */
|
||||
{ id: 2, name: 'エネパーム' },
|
||||
/** 축전지시스템 */
|
||||
{ id: 3, name: '蓄電池システム' },
|
||||
/** 태양광발전 */
|
||||
{ id: 4, name: '太陽光発電' },
|
||||
]
|
||||
|
||||
export const roofMaterial = [
|
||||
/** 슬레이트 */
|
||||
{ id: 1, name: 'スレート' },
|
||||
/** 아스팔트 싱글 */
|
||||
{ id: 2, name: 'アスファルトシングル' },
|
||||
/** 기와 */
|
||||
{ id: 3, name: '瓦' },
|
||||
/** 금속지붕 */
|
||||
{ id: 4, name: '金属屋根' },
|
||||
]
|
||||
|
||||
export const selectBoxOptions: Record<SelectBoxKeys, { id: number; name: string }[]> = {
|
||||
installationSystem: [
|
||||
{
|
||||
/** 태양광발전 */
|
||||
id: 1,
|
||||
name: '太陽光発電',
|
||||
},
|
||||
{
|
||||
/** 하이브리드축전지시스템 */
|
||||
id: 2,
|
||||
name: 'ハイブリッド蓄電システム',
|
||||
},
|
||||
{
|
||||
/** 축전지시스템 */
|
||||
id: 3,
|
||||
name: '蓄電池システム',
|
||||
},
|
||||
],
|
||||
constructionYear: [
|
||||
{
|
||||
/** 신축 */
|
||||
id: 1,
|
||||
name: '新築',
|
||||
},
|
||||
{
|
||||
/** 기축 */
|
||||
id: 2,
|
||||
name: '既築',
|
||||
},
|
||||
],
|
||||
roofShape: [
|
||||
{
|
||||
/** 박공지붕 */
|
||||
id: 1,
|
||||
name: '切妻',
|
||||
},
|
||||
{
|
||||
/** 기동 */
|
||||
id: 2,
|
||||
name: '寄棟',
|
||||
},
|
||||
{
|
||||
/** 한쪽흐름 */
|
||||
id: 3,
|
||||
name: '片流れ',
|
||||
},
|
||||
],
|
||||
rafterSize: [
|
||||
{
|
||||
/** 35mm 이상×48mm 이상 */
|
||||
id: 1,
|
||||
name: '幅35mm以上×高さ48mm以上',
|
||||
},
|
||||
{
|
||||
/** 36mm 이상×46mm 이상 */
|
||||
id: 2,
|
||||
name: '幅36mm以上×高さ46mm以上',
|
||||
},
|
||||
{
|
||||
/** 37mm 이상×43mm 이상 */
|
||||
id: 3,
|
||||
name: '幅37mm以上×高さ43mm以上',
|
||||
},
|
||||
{
|
||||
/** 38mm 이상×40mm 이상 */
|
||||
id: 4,
|
||||
name: '幅38mm以上×高さ40mm以上',
|
||||
},
|
||||
],
|
||||
rafterPitch: [
|
||||
{
|
||||
/** 455mm 이하 */
|
||||
id: 1,
|
||||
name: '455mm以下',
|
||||
},
|
||||
{
|
||||
/** 500mm 이하 */
|
||||
id: 2,
|
||||
name: '500mm以下',
|
||||
},
|
||||
{
|
||||
/** 606mm 이하 */
|
||||
id: 3,
|
||||
name: '606mm以下',
|
||||
},
|
||||
],
|
||||
openFieldPlateKind: [
|
||||
{
|
||||
/** 구조용합판 */
|
||||
id: 1,
|
||||
name: '構造用合板',
|
||||
},
|
||||
{
|
||||
/** OSB */
|
||||
id: 2,
|
||||
name: 'OSB',
|
||||
},
|
||||
{
|
||||
/** 파티클보드 */
|
||||
id: 3,
|
||||
name: 'パーティクルボード',
|
||||
},
|
||||
{
|
||||
/** 소판 */
|
||||
id: 4,
|
||||
name: '小幅板',
|
||||
},
|
||||
],
|
||||
installationAvailability: [
|
||||
{
|
||||
/** 확인완료 */
|
||||
id: 1,
|
||||
name: '確認済み',
|
||||
},
|
||||
{
|
||||
/** 미확인 */
|
||||
id: 2,
|
||||
name: '未確認',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export const radioEtcData: Record<RadioEtcKeys, { id: number; label: string }[]> = {
|
||||
structureOrder: [
|
||||
{
|
||||
/** 지붕재 - 방수재 - 지붕의기초 - 서까래 */
|
||||
id: 1,
|
||||
label: '屋根材 > 防水材 > 屋根の基礎 > 垂木',
|
||||
},
|
||||
],
|
||||
houseStructure: [
|
||||
{
|
||||
/** 목재 */
|
||||
id: 1,
|
||||
label: '木製',
|
||||
},
|
||||
],
|
||||
rafterMaterial: [
|
||||
{
|
||||
/** 목재 */
|
||||
id: 1,
|
||||
label: '木製',
|
||||
},
|
||||
{
|
||||
/** 강재 */
|
||||
id: 2,
|
||||
label: '強制',
|
||||
},
|
||||
],
|
||||
waterproofMaterial: [
|
||||
{
|
||||
/** 아스팔트 지붕 940(22kg 이상) */
|
||||
id: 1,
|
||||
label: 'アスファルト屋根940(22kg以上)',
|
||||
},
|
||||
],
|
||||
insulationPresence: [
|
||||
{
|
||||
/** 없음 */
|
||||
id: 1,
|
||||
label: 'なし',
|
||||
},
|
||||
{
|
||||
/** 있음 */
|
||||
id: 2,
|
||||
label: 'あり',
|
||||
},
|
||||
],
|
||||
rafterDirection: [
|
||||
{
|
||||
/** 수직 */
|
||||
id: 1,
|
||||
label: '垂直垂木',
|
||||
},
|
||||
{
|
||||
/** 수평 */
|
||||
id: 2,
|
||||
label: '水平垂木',
|
||||
},
|
||||
],
|
||||
leakTrace: [
|
||||
{
|
||||
/** 있음 */
|
||||
id: 1,
|
||||
label: 'あり',
|
||||
},
|
||||
{
|
||||
/** 없음 */
|
||||
id: 2,
|
||||
label: 'なし',
|
||||
},
|
||||
],
|
||||
}
|
||||
import { radioEtcData, selectBoxOptions, supplementaryFacilities, roofMaterial } from '@/types/Survey'
|
||||
|
||||
const makeNumArr = (value: string) => {
|
||||
return value
|
||||
|
||||
@ -59,7 +59,6 @@ type ZipCode = {
|
||||
* @description 조사 매물 관련 기능을 제공하는 커스텀 훅
|
||||
*
|
||||
* @param {number} [id] 조사 매물 ID
|
||||
* @param {boolean} [isPdf] PDF 뷰 여부
|
||||
* @returns {Object} 조사 매물 관련 기능과 데이터
|
||||
* @returns {SurveyBasicInfo[]} surveyList - 조사 매물 목록 데이터
|
||||
* @returns {SurveyBasicInfo} surveyDetail - 조사 매물 상세 데이터
|
||||
@ -75,7 +74,7 @@ type ZipCode = {
|
||||
*/
|
||||
export function useSurvey(
|
||||
id?: number,
|
||||
isPdf?: boolean,
|
||||
isList?: boolean,
|
||||
): {
|
||||
surveyList: { data: SurveyBasicInfo[]; count: number } | {}
|
||||
surveyDetail: SurveyBasicInfo | null
|
||||
@ -94,6 +93,7 @@ export function useSurvey(
|
||||
refetchSurveyList: () => void
|
||||
refetchSurveyDetail: () => void
|
||||
getSubmitTarget: (params: { storeId: string; role: string }) => Promise<SubmitTargetResponse[] | null>
|
||||
downloadSurveyPdf: (id: number, filename: string) => Promise<Blob>
|
||||
} {
|
||||
const queryClient = useQueryClient()
|
||||
const { keyword, searchOption, isMySurvey, sort, offset } = useSurveyFilterStore()
|
||||
@ -148,11 +148,15 @@ export function useSurvey(
|
||||
* @param {boolean} isThrow 조사 매물 데이터 조회 에러 처리 여부
|
||||
* @returns {Promise<any>} API 응답 데이터
|
||||
*/
|
||||
const tryFunction = async (func: () => Promise<any>, isList?: boolean, isThrow?: boolean): Promise<any> => {
|
||||
const tryFunction = async (func: () => Promise<any>, isList?: boolean, isThrow?: boolean, isBlob?: boolean): Promise<any> => {
|
||||
try {
|
||||
const resp = await func()
|
||||
return resp.data
|
||||
return isBlob ? resp : resp.data
|
||||
} catch (error) {
|
||||
if (isBlob) {
|
||||
showErrorAlert(ERROR_MESSAGE.PDF_GENERATION_ERROR)
|
||||
return null
|
||||
}
|
||||
handleError(error, isThrow)
|
||||
if (isList) {
|
||||
return { data: [], count: 0 }
|
||||
@ -192,7 +196,7 @@ export function useSurvey(
|
||||
false,
|
||||
)
|
||||
},
|
||||
enabled: !isPdf,
|
||||
enabled: isList,
|
||||
})
|
||||
|
||||
/**
|
||||
@ -225,19 +229,47 @@ export function useSurvey(
|
||||
queryKey: ['survey', id],
|
||||
queryFn: async () => {
|
||||
if (Number.isNaN(id) || id === undefined || id === 0) return null
|
||||
return await tryFunction(
|
||||
return await tryFunction(() => axiosInstance(null).get<SurveyBasicInfo>(`/api/survey-sales/${id}`), false, false)
|
||||
},
|
||||
enabled: id !== 0 && id !== undefined && id !== null,
|
||||
})
|
||||
/**
|
||||
* @description 조사 매물 PDF 다운로드
|
||||
*
|
||||
* @param {number} id 조사 매물 ID
|
||||
* @param {string} filename 다운로드할 파일 이름
|
||||
* @returns {Promise<Blob>} PDF 파일 데이터
|
||||
*/
|
||||
const downloadSurveyPdf = async (id: number, filename: string) => {
|
||||
const resp = await tryFunction(
|
||||
() =>
|
||||
axiosInstance(null).get<SurveyBasicInfo>(`/api/survey-sales/${id}`, {
|
||||
params: {
|
||||
isPdf: isPdf,
|
||||
fetch(`/api/survey-sales/${id}?isPdf=true`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/pdf',
|
||||
},
|
||||
}),
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
)
|
||||
},
|
||||
enabled: id !== 0 && id !== undefined && id !== null,
|
||||
})
|
||||
console.log(resp)
|
||||
const blob = await resp.blob()
|
||||
|
||||
if (!blob || blob.size === 0) {
|
||||
showErrorAlert(ERROR_MESSAGE.PDF_GENERATION_ERROR)
|
||||
return null
|
||||
}
|
||||
|
||||
const url = window.URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = `${filename}.pdf`
|
||||
a.click()
|
||||
window.URL.revokeObjectURL(url)
|
||||
|
||||
return blob
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 조사 매물 생성
|
||||
@ -450,5 +482,6 @@ export function useSurvey(
|
||||
getSubmitTarget,
|
||||
refetchSurveyList,
|
||||
refetchSurveyDetail,
|
||||
downloadSurveyPdf,
|
||||
}
|
||||
}
|
||||
|
||||
@ -323,3 +323,237 @@ export type SurveySearchParams = {
|
||||
/** 시공점 ID */
|
||||
builderId?: string | null
|
||||
}
|
||||
|
||||
|
||||
type RadioEtcKeys =
|
||||
| 'structureOrder'
|
||||
| 'houseStructure'
|
||||
| 'rafterMaterial'
|
||||
| 'waterproofMaterial'
|
||||
| 'insulationPresence'
|
||||
| 'rafterDirection'
|
||||
| 'leakTrace'
|
||||
type SelectBoxKeys =
|
||||
| 'installationSystem'
|
||||
| 'constructionYear'
|
||||
| 'roofShape'
|
||||
| 'rafterPitch'
|
||||
| 'rafterSize'
|
||||
| 'openFieldPlateKind'
|
||||
| 'installationAvailability'
|
||||
|
||||
export const supplementaryFacilities = [
|
||||
/** 에코큐트 */
|
||||
{ id: 1, name: 'エコキュート' },
|
||||
/** 에네팜 */
|
||||
{ id: 2, name: 'エネパーム' },
|
||||
/** 축전지시스템 */
|
||||
{ id: 3, name: '蓄電池システム' },
|
||||
/** 태양광발전 */
|
||||
{ id: 4, name: '太陽光発電' },
|
||||
]
|
||||
|
||||
export const roofMaterial = [
|
||||
/** 슬레이트 */
|
||||
{ id: 1, name: 'スレート' },
|
||||
/** 아스팔트 싱글 */
|
||||
{ id: 2, name: 'アスファルトシングル' },
|
||||
/** 기와 */
|
||||
{ id: 3, name: '瓦' },
|
||||
/** 금속지붕 */
|
||||
{ id: 4, name: '金属屋根' },
|
||||
]
|
||||
|
||||
export const selectBoxOptions: Record<SelectBoxKeys, { id: number; name: string }[]> = {
|
||||
installationSystem: [
|
||||
{
|
||||
/** 태양광발전 */
|
||||
id: 1,
|
||||
name: '太陽光発電',
|
||||
},
|
||||
{
|
||||
/** 하이브리드축전지시스템 */
|
||||
id: 2,
|
||||
name: 'ハイブリッド蓄電システム',
|
||||
},
|
||||
{
|
||||
/** 축전지시스템 */
|
||||
id: 3,
|
||||
name: '蓄電池システム',
|
||||
},
|
||||
],
|
||||
constructionYear: [
|
||||
{
|
||||
/** 신축 */
|
||||
id: 1,
|
||||
name: '新築',
|
||||
},
|
||||
{
|
||||
/** 기축 */
|
||||
id: 2,
|
||||
name: '既築',
|
||||
},
|
||||
],
|
||||
roofShape: [
|
||||
{
|
||||
/** 박공지붕 */
|
||||
id: 1,
|
||||
name: '切妻',
|
||||
},
|
||||
{
|
||||
/** 기동 */
|
||||
id: 2,
|
||||
name: '寄棟',
|
||||
},
|
||||
{
|
||||
/** 한쪽흐름 */
|
||||
id: 3,
|
||||
name: '片流れ',
|
||||
},
|
||||
],
|
||||
rafterSize: [
|
||||
{
|
||||
/** 35mm 이상×48mm 이상 */
|
||||
id: 1,
|
||||
name: '幅35mm以上×高さ48mm以上',
|
||||
},
|
||||
{
|
||||
/** 36mm 이상×46mm 이상 */
|
||||
id: 2,
|
||||
name: '幅36mm以上×高さ46mm以上',
|
||||
},
|
||||
{
|
||||
/** 37mm 이상×43mm 이상 */
|
||||
id: 3,
|
||||
name: '幅37mm以上×高さ43mm以上',
|
||||
},
|
||||
{
|
||||
/** 38mm 이상×40mm 이상 */
|
||||
id: 4,
|
||||
name: '幅38mm以上×高さ40mm以上',
|
||||
},
|
||||
],
|
||||
rafterPitch: [
|
||||
{
|
||||
/** 455mm 이하 */
|
||||
id: 1,
|
||||
name: '455mm以下',
|
||||
},
|
||||
{
|
||||
/** 500mm 이하 */
|
||||
id: 2,
|
||||
name: '500mm以下',
|
||||
},
|
||||
{
|
||||
/** 606mm 이하 */
|
||||
id: 3,
|
||||
name: '606mm以下',
|
||||
},
|
||||
],
|
||||
openFieldPlateKind: [
|
||||
{
|
||||
/** 구조용합판 */
|
||||
id: 1,
|
||||
name: '構造用合板',
|
||||
},
|
||||
{
|
||||
/** OSB */
|
||||
id: 2,
|
||||
name: 'OSB',
|
||||
},
|
||||
{
|
||||
/** 파티클보드 */
|
||||
id: 3,
|
||||
name: 'パーティクルボード',
|
||||
},
|
||||
{
|
||||
/** 소판 */
|
||||
id: 4,
|
||||
name: '小幅板',
|
||||
},
|
||||
],
|
||||
installationAvailability: [
|
||||
{
|
||||
/** 확인완료 */
|
||||
id: 1,
|
||||
name: '確認済み',
|
||||
},
|
||||
{
|
||||
/** 미확인 */
|
||||
id: 2,
|
||||
name: '未確認',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export const radioEtcData: Record<RadioEtcKeys, { id: number; label: string }[]> = {
|
||||
structureOrder: [
|
||||
{
|
||||
/** 지붕재 - 방수재 - 지붕의기초 - 서까래 */
|
||||
id: 1,
|
||||
label: '屋根材 > 防水材 > 屋根の基礎 > 垂木',
|
||||
},
|
||||
],
|
||||
houseStructure: [
|
||||
{
|
||||
/** 목재 */
|
||||
id: 1,
|
||||
label: '木製',
|
||||
},
|
||||
],
|
||||
rafterMaterial: [
|
||||
{
|
||||
/** 목재 */
|
||||
id: 1,
|
||||
label: '木製',
|
||||
},
|
||||
{
|
||||
/** 강재 */
|
||||
id: 2,
|
||||
label: '強制',
|
||||
},
|
||||
],
|
||||
waterproofMaterial: [
|
||||
{
|
||||
/** 아스팔트 지붕 940(22kg 이상) */
|
||||
id: 1,
|
||||
label: 'アスファルト屋根940(22kg以上)',
|
||||
},
|
||||
],
|
||||
insulationPresence: [
|
||||
{
|
||||
/** 없음 */
|
||||
id: 1,
|
||||
label: 'なし',
|
||||
},
|
||||
{
|
||||
/** 있음 */
|
||||
id: 2,
|
||||
label: 'あり',
|
||||
},
|
||||
],
|
||||
rafterDirection: [
|
||||
{
|
||||
/** 수직 */
|
||||
id: 1,
|
||||
label: '垂直垂木',
|
||||
},
|
||||
{
|
||||
/** 수평 */
|
||||
id: 2,
|
||||
label: '水平垂木',
|
||||
},
|
||||
],
|
||||
leakTrace: [
|
||||
{
|
||||
/** 있음 */
|
||||
id: 1,
|
||||
label: 'あり',
|
||||
},
|
||||
{
|
||||
/** 없음 */
|
||||
id: 2,
|
||||
label: 'なし',
|
||||
},
|
||||
],
|
||||
}
|
||||
@ -209,3 +209,27 @@ export const convertToSnakeCase = (obj) => {
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
// 스네이크케이스를 카멜케이스로 변환하는 함수
|
||||
export const toCamelCase = (str) => {
|
||||
return str.replace(/_([a-z])/g, (match, letter) => letter.toUpperCase())
|
||||
}
|
||||
|
||||
// 객체의 키를 카멜케이스로 변환하는 함수
|
||||
export const convertToCamelCase = (obj) => {
|
||||
if (obj === null || obj === undefined) return obj
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map((item) => convertToCamelCase(item))
|
||||
}
|
||||
|
||||
if (typeof obj === 'object') {
|
||||
return Object.keys(obj).reduce((acc, key) => {
|
||||
const camelKey = toCamelCase(key.toLowerCase())
|
||||
acc[camelKey] = convertToCamelCase(obj[key])
|
||||
return acc
|
||||
}, {})
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user