284 lines
7.9 KiB
TypeScript
284 lines
7.9 KiB
TypeScript
import { NextResponse } from 'next/server'
|
|
import { prisma } from '@/libs/prisma'
|
|
import { convertToSnakeCase } from '@/utils/common-utils'
|
|
/**
|
|
* 검색 파라미터
|
|
*/
|
|
type SearchParams = {
|
|
keyword?: string | null // 검색어
|
|
searchOption?: string | null // 검색 옵션 (select 옵션)
|
|
isMySurvey?: string | null // 내가 작성한 매물
|
|
sort?: string | null // 정렬 방식
|
|
offset?: string | null
|
|
role?: string | null // 회원권한한
|
|
store?: string | null // 판매점ID
|
|
builderNo?: string | null // 시공ID
|
|
}
|
|
|
|
type WhereCondition = {
|
|
AND: any[]
|
|
OR?: any[]
|
|
[key: string]: any
|
|
}
|
|
|
|
// 검색 가능한 필드 옵션
|
|
const SEARCH_OPTIONS = [
|
|
'BUILDING_NAME', // 건물명
|
|
'REPRESENTATIVE', // 담당자
|
|
'STORE', // 판매점
|
|
'CONSTRUCTION_POINT', // 시공점
|
|
'CUSTOMER_NAME', // 고객명
|
|
'POST_CODE', // 우편번호
|
|
'ADDRESS', // 주소
|
|
'ADDRESS_DETAIL', // 상세주소
|
|
'SRL_NO', // 등록번호
|
|
] as const
|
|
|
|
// 페이지당 항목 수
|
|
const ITEMS_PER_PAGE = 10
|
|
|
|
/**
|
|
* 키워드 검색 조건 생성 함수
|
|
* @param keyword 검색 키워드
|
|
* @param searchOption 검색 옵션
|
|
* @returns 검색 조건 객체
|
|
*/
|
|
const createKeywordSearchCondition = (keyword: string, searchOption: string): WhereCondition => {
|
|
const where: WhereCondition = { AND: [] }
|
|
|
|
if (searchOption === 'all') {
|
|
// 모든 필드 검색 시 OR 조건 사용
|
|
where.OR = []
|
|
|
|
where.OR.push(
|
|
...SEARCH_OPTIONS.map((field) => ({
|
|
[field]: { contains: keyword },
|
|
})),
|
|
)
|
|
} else if (SEARCH_OPTIONS.includes(searchOption.toUpperCase() as any)) {
|
|
// 특정 필드 검색
|
|
where[searchOption.toUpperCase()] = { contains: keyword }
|
|
}
|
|
return where
|
|
}
|
|
|
|
/**
|
|
* 회원 역할별 검색 조건 생성 함수
|
|
* @param params 검색 파라미터
|
|
* @returns 검색 조건 객체
|
|
*/
|
|
const createMemberRoleCondition = (params: SearchParams): WhereCondition => {
|
|
const where: WhereCondition = { AND: [] }
|
|
|
|
switch (params.role) {
|
|
case 'Admin': // 1차점
|
|
where.OR = [
|
|
{
|
|
// 같은 판매점에서 작성한 제출/제출되지 않은 매물
|
|
AND: [{ STORE_ID: { equals: params.store } }],
|
|
},
|
|
{
|
|
// MUSUBI (시공권한 X) 가 ORDER 에 제출한 매물
|
|
AND: [{ SUBMISSION_TARGET_ID: { equals: params.store } }, { SUBMISSION_STATUS: { equals: true } }],
|
|
},
|
|
]
|
|
break
|
|
|
|
case 'Admin_Sub': // 2차점
|
|
where.OR = [
|
|
{
|
|
// MUSUBI (시공권한 X) 같은 판매점에서 작성한 제출/제출되지 않은 매물
|
|
AND: [
|
|
{ STORE_ID: { equals: params.store } },
|
|
// {
|
|
// OR: [{ CONSTRUCTION_POINT: { equals: null } }, { CONSTRUCTION_POINT: { equals: '' } }],
|
|
// },
|
|
],
|
|
},
|
|
{
|
|
// MUSUBI (시공권한 O) 가 MUSUBI 에 제출한 매물 + PARTNER 가 제출한 매물
|
|
AND: [
|
|
{ SUBMISSION_TARGET_ID: { equals: params.store } },
|
|
{ CONSTRUCTION_POINT: { not: null } },
|
|
{ CONSTRUCTION_POINT: { not: '' } },
|
|
{ SUBMISSION_STATUS: { equals: true } },
|
|
],
|
|
},
|
|
]
|
|
break
|
|
|
|
case 'Builder': // MUSUBI (시공권한 O)
|
|
case 'Partner': // PARTNER
|
|
// 시공점이 있고 STORE_ID 가 시공ID와 같은 매물
|
|
where.AND?.push({
|
|
// CONSTRUCTION_POINT: { not: null },
|
|
CONSTRUCTION_POINT: { equals: params.builderNo },
|
|
})
|
|
break
|
|
|
|
case 'T01':
|
|
where.OR = [
|
|
{
|
|
NOT: {
|
|
SRL_NO: {
|
|
startsWith: '一時保存',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
STORE_ID: {
|
|
equals: params.store,
|
|
},
|
|
},
|
|
]
|
|
break
|
|
case 'User':
|
|
// 모든 매물 조회 가능 (추가 조건 없음)
|
|
break
|
|
}
|
|
|
|
return where
|
|
}
|
|
|
|
/**
|
|
* GET 핸들러 - 설문 목록 조회
|
|
*/
|
|
export async function GET(request: Request) {
|
|
try {
|
|
// URL 파라미터 파싱
|
|
const { searchParams } = new URL(request.url)
|
|
const params: SearchParams = {
|
|
keyword: searchParams.get('keyword'),
|
|
searchOption: searchParams.get('searchOption'),
|
|
isMySurvey: searchParams.get('isMySurvey'), //representativeId
|
|
sort: searchParams.get('sort'),
|
|
offset: searchParams.get('offset'),
|
|
role: searchParams.get('role'),
|
|
store: searchParams.get('store'), //storeId
|
|
builderNo: searchParams.get('builderNo'),
|
|
}
|
|
|
|
// 검색 조건 구성
|
|
const where: WhereCondition = { AND: [] }
|
|
|
|
// 내가 작성한 매물 조건 적용
|
|
if (params.isMySurvey) {
|
|
where.AND.push({ REPRESENTATIVE_ID: params.isMySurvey })
|
|
}
|
|
|
|
// 키워드 검색 조건 적용
|
|
if (params.keyword && params.searchOption) {
|
|
where.AND.push(createKeywordSearchCondition(params.keyword, params.searchOption))
|
|
}
|
|
|
|
// 회원 유형 조건 적용
|
|
const roleCondition = createMemberRoleCondition(params)
|
|
if (Object.keys(roleCondition).length > 0) {
|
|
where.AND.push(roleCondition)
|
|
}
|
|
|
|
// 페이지네이션 데이터 조회
|
|
//@ts-ignore
|
|
const surveys = await prisma.SD_SURVEY_SALES_BASIC_INFO.findMany({
|
|
where,
|
|
orderBy: params.sort === 'created' ? { REG_DT: 'desc' } : { UPT_DT: 'desc' },
|
|
skip: Number(params.offset),
|
|
take: ITEMS_PER_PAGE,
|
|
})
|
|
// 전체 개수만 조회
|
|
//@ts-ignore
|
|
const count = await prisma.SD_SURVEY_SALES_BASIC_INFO.count({ where })
|
|
return NextResponse.json({ data: { data: surveys, count: count } })
|
|
} catch (error) {
|
|
console.error(error)
|
|
return NextResponse.json({ error: 'Fail Read Survey' }, { status: 500 })
|
|
}
|
|
}
|
|
|
|
/**
|
|
* PUT 핸들러 - 상세 정보 추가
|
|
*/
|
|
export async function PUT(request: Request) {
|
|
try {
|
|
const body = await request.json()
|
|
|
|
// 상세 정보 생성을 위한 데이터 구성
|
|
const detailInfo = {
|
|
...body.detail_info,
|
|
BASIC_INFO_ID: body.id,
|
|
}
|
|
|
|
// 상세 정보 생성
|
|
//@ts-ignore
|
|
await prisma.SD_SURVEY_SALES_DETAIL_INFO.create({
|
|
data: detailInfo,
|
|
})
|
|
|
|
return NextResponse.json({
|
|
message: 'Success Update Survey',
|
|
})
|
|
} catch (error) {
|
|
console.error(error)
|
|
return NextResponse.json({ error: 'Fail Update Survey' }, { status: 500 })
|
|
}
|
|
}
|
|
|
|
export async function POST(request: Request) {
|
|
try {
|
|
const body = await request.json()
|
|
|
|
const role =
|
|
body.role === 'T01' || body.role === 'Admin'
|
|
? 'HO'
|
|
: body.role === 'Admin_Sub' || body.role === 'Builder'
|
|
? 'HM'
|
|
: body.role === 'Partner'
|
|
? ''
|
|
: null
|
|
|
|
// 임시 저장 시 임시저장으로 저장
|
|
// 기본 저장 시 (HO/HM) + 판매점ID + yyMMdd + 000 으로 저장
|
|
const baseSrlNo =
|
|
body.survey.srlNo ??
|
|
role +
|
|
body.storeId +
|
|
new Date().getFullYear().toString().slice(-2) +
|
|
(new Date().getMonth() + 1).toString().padStart(2, '0') +
|
|
new Date().getDate().toString().padStart(2, '0')
|
|
|
|
// @ts-ignore
|
|
const lastSurvey = await prisma.SD_SURVEY_SALES_BASIC_INFO.findFirst({
|
|
where: {
|
|
SRL_NO: {
|
|
startsWith: role + body.storeId,
|
|
},
|
|
},
|
|
orderBy: {
|
|
SRL_NO: 'desc',
|
|
},
|
|
})
|
|
|
|
// 마지막 번호 추출
|
|
const lastNumber = lastSurvey ? parseInt(lastSurvey.SRL_NO.slice(-3)) : 0
|
|
|
|
// 새로운 srlNo 생성 - 임시저장일 경우 '임시저장' 으로 저장
|
|
const newSrlNo = baseSrlNo.startsWith('一時保存') ? baseSrlNo : baseSrlNo + (lastNumber + 1).toString().padStart(3, '0')
|
|
|
|
const { detailInfo, ...basicInfo } = body.survey
|
|
// @ts-ignore
|
|
const result = await prisma.SD_SURVEY_SALES_BASIC_INFO.create({
|
|
data: {
|
|
...convertToSnakeCase(basicInfo),
|
|
SRL_NO: newSrlNo,
|
|
DETAIL_INFO: {
|
|
create: convertToSnakeCase(detailInfo),
|
|
},
|
|
},
|
|
})
|
|
return NextResponse.json(result)
|
|
} catch (error) {
|
|
console.error(error)
|
|
return NextResponse.json({ error: 'Fail Create Survey' }, { status: 500 })
|
|
}
|
|
}
|