diff --git a/.env.development b/.env.development index 47cfa78..8e6fead 100644 --- a/.env.development +++ b/.env.development @@ -2,13 +2,13 @@ NEXT_PUBLIC_RUN_MODE=development # 모바일 디바이스로 로컬 서버 확인하려면 자신 IP 주소로 변경 # 다시 로컬에서 개발할때는 localhost로 변경 #route handler -NEXT_PUBLIC_API_URL=http://localhost:3000 +NEXT_PUBLIC_API_URL=http://172.30.1.65:3000 #qsp 로그인 api NEXT_PUBLIC_QSP_API_URL=http://1.248.227.176:8120 #1:1문의 api -NEXT_PUBLIC_INQUIRY_API_URL=http://1.248.227.176:38080 +NEXT_PUBLIC_INQUIRY_API_URL=http://172.23.4.129:8110 #QPARTNER 로그인 api DB_HOST=202.218.61.226 diff --git a/.env.localhost b/.env.localhost index 966e366..29cb5c2 100644 --- a/.env.localhost +++ b/.env.localhost @@ -2,13 +2,13 @@ NEXT_PUBLIC_RUN_MODE=local # 모바일 디바이스로 로컬 서버 확인하려면 자신 IP 주소로 변경 # 다시 로컬에서 개발할때는 localhost로 변경 #route handler -NEXT_PUBLIC_API_URL=http://localhost:3000 +NEXT_PUBLIC_API_URL=http://172.30.1.65:3000 #qsp 로그인 api NEXT_PUBLIC_QSP_API_URL=http://1.248.227.176:8120 #1:1문의 api -NEXT_PUBLIC_INQUIRY_API_URL=http://1.248.227.176:38080 +NEXT_PUBLIC_INQUIRY_API_URL=http://172.23.4.129:8110 #QPARTNER 로그인 api DB_HOST=202.218.61.226 diff --git a/.env.production b/.env.production index ce56225..ce308e8 100644 --- a/.env.production +++ b/.env.production @@ -6,7 +6,7 @@ NEXT_PUBLIC_API_URL=http://1.248.227.176:3000 NEXT_PUBLIC_QSP_API_URL=http://1.248.227.176:8120 #1:1문의 api -NEXT_PUBLIC_INQUIRY_API_URL=http://1.248.227.176:38080 +NEXT_PUBLIC_INQUIRY_API_URL=http://172.23.4.129:8110 #QPARTNER 로그인 api DB_HOST=202.218.61.226 diff --git a/src/app/api/survey-sales/[id]/route.ts b/src/app/api/survey-sales/[id]/route.ts index db5c9df..eb718f4 100644 --- a/src/app/api/survey-sales/[id]/route.ts +++ b/src/app/api/survey-sales/[id]/route.ts @@ -19,15 +19,16 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{ } } -const getNewSrlNo = async (srlNo: string, storeId: string) => { +const getNewSrlNo = async (srlNo: string, storeId: string, role: string) => { + const srlRole = role === 'T01' || role === 'Admin' ? 'HO' : role === 'Admin_Sub' || role === 'Builder' ? 'HM' : '' + let newSrlNo = srlNo - console.log('srlNo:: ', srlNo) if (srlNo.startsWith('一時保存')) { //@ts-ignore const lastSurvey = await prisma.SD_SURVEY_SALES_BASIC_INFO.findFirst({ where: { SRL_NO: { - startsWith: storeId, + startsWith: srlRole + storeId, }, }, orderBy: { @@ -35,7 +36,9 @@ const getNewSrlNo = async (srlNo: string, storeId: string) => { }, }) const lastNo = lastSurvey ? parseInt(lastSurvey.SRL_NO.slice(-3)) : 0 + newSrlNo = + srlRole + storeId + new Date().getFullYear().toString().slice(-2) + (new Date().getMonth() + 1).toString().padStart(2, '0') + @@ -52,7 +55,7 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{ const { detailInfo, ...basicInfo } = body.survey // PUT 요청 시 임시저장 여부 확인 후 임시저장 시 기존 SRL_NO 사용, 기본 저장 시 새로운 SRL_NO 생성 - const newSrlNo = body.isTemporary ? body.survey.srlNo : await getNewSrlNo(body.survey.srlNo, body.storeId) + const newSrlNo = body.isTemporary ? body.survey.srlNo : await getNewSrlNo(body.survey.srlNo, body.storeId, body.role) // @ts-ignore const survey = await prisma.SD_SURVEY_SALES_BASIC_INFO.update({ where: { ID: Number(id) }, @@ -113,9 +116,6 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise< const { id } = await params const body = await request.json() - // 제출 시 기존 SRL_NO 확인 후 '임시저장'으로 시작하면 새로운 SRL_NO 생성 - const newSrlNo = await getNewSrlNo(body.srlNo, body.storeId) - if (body.targetId) { // @ts-ignore const survey = await prisma.SD_SURVEY_SALES_BASIC_INFO.update({ @@ -125,11 +125,9 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise< SUBMISSION_DATE: new Date(), SUBMISSION_TARGET_ID: body.targetId, UPT_DT: new Date(), - SRL_NO: newSrlNo, }, }) - console.log(survey) - return NextResponse.json({ message: 'Survey confirmed successfully' }) + return NextResponse.json({ message: 'Survey confirmed successfully', data: survey }) } } catch (error) { console.error('Error updating survey:', error) diff --git a/src/app/api/survey-sales/route.ts b/src/app/api/survey-sales/route.ts index 7d51802..a5d60c8 100644 --- a/src/app/api/survey-sales/route.ts +++ b/src/app/api/survey-sales/route.ts @@ -1,7 +1,6 @@ import { NextResponse } from 'next/server' import { prisma } from '@/libs/prisma' import { convertToSnakeCase } from '@/utils/common-utils' -import { equal } from 'assert' /** * 검색 파라미터 */ @@ -32,6 +31,7 @@ const SEARCH_OPTIONS = [ 'POST_CODE', // 우편번호 'ADDRESS', // 주소 'ADDRESS_DETAIL', // 상세주소 + 'SRL_NO', // 등록번호 ] as const // 페이지당 항목 수 @@ -50,13 +50,6 @@ const createKeywordSearchCondition = (keyword: string, searchOption: string): Wh // 모든 필드 검색 시 OR 조건 사용 where.OR = [] - // ID가 숫자인 경우 ID 검색 조건 추가 - if (keyword.match(/^\d+$/) || !isNaN(Number(keyword))) { - where.OR.push({ - ID: { equals: Number(keyword) }, - }) - } - where.OR.push( ...SEARCH_OPTIONS.map((field) => ({ [field]: { contains: keyword }, @@ -65,15 +58,6 @@ const createKeywordSearchCondition = (keyword: string, searchOption: string): Wh } else if (SEARCH_OPTIONS.includes(searchOption.toUpperCase() as any)) { // 특정 필드 검색 where[searchOption.toUpperCase()] = { contains: keyword } - } else if (searchOption === 'id') { - // ID 검색 (숫자 변환 필요) - const number = Number(keyword) - if (!isNaN(number)) { - where.ID = { equals: number } - } else { - // 유효하지 않은 ID 검색 시 빈 결과 반환 - where.ID = { equals: null } - } } return where } @@ -91,7 +75,7 @@ const createMemberRoleCondition = (params: SearchParams): WhereCondition => { where.OR = [ { // 같은 판매점에서 작성한 제출/제출되지 않은 매물 - AND: [{ STORE: { equals: params.store } }], + AND: [{ STORE_ID: { equals: params.store } }], }, { // MUSUBI (시공권한 X) 가 ORDER 에 제출한 매물 @@ -105,7 +89,7 @@ const createMemberRoleCondition = (params: SearchParams): WhereCondition => { { // MUSUBI (시공권한 X) 같은 판매점에서 작성한 제출/제출되지 않은 매물 AND: [ - { STORE: { equals: params.store } }, + { STORE_ID: { equals: params.store } }, { OR: [{ CONSTRUCTION_POINT: { equals: null } }, { CONSTRUCTION_POINT: { equals: '' } }], }, @@ -125,9 +109,10 @@ const createMemberRoleCondition = (params: SearchParams): WhereCondition => { case 'Builder': // MUSUBI (시공권한 O) case 'Partner': // PARTNER - // 같은 시공ID에서 작성된 매물 + // 시공점이 있고 STORE_ID가 시공ID와 같은 매물 where.AND?.push({ - CONSTRUCTION_POINT: { equals: params.builderNo }, + CONSTRUCTION_POINT: { not: null }, + STORE_ID: { equals: params.builderNo }, }) break @@ -141,7 +126,7 @@ const createMemberRoleCondition = (params: SearchParams): WhereCondition => { }, }, { - STORE: { + STORE_ID: { equals: params.store, }, }, @@ -165,11 +150,11 @@ export async function GET(request: Request) { const params: SearchParams = { keyword: searchParams.get('keyword'), searchOption: searchParams.get('searchOption'), - isMySurvey: searchParams.get('isMySurvey'), + isMySurvey: searchParams.get('isMySurvey'), //representativeId sort: searchParams.get('sort'), offset: searchParams.get('offset'), role: searchParams.get('role'), - store: searchParams.get('store'), + store: searchParams.get('store'), //storeId builderNo: searchParams.get('builderNo'), } @@ -178,7 +163,7 @@ export async function GET(request: Request) { // 내가 작성한 매물 조건 적용 if (params.isMySurvey) { - where.AND.push({ REPRESENTATIVE: params.isMySurvey }) + where.AND.push({ REPRESENTATIVE_ID: params.isMySurvey }) } // 키워드 검색 조건 적용 @@ -242,11 +227,21 @@ export async function POST(request: Request) { try { const body = await request.json() - // 임시 저장 시 임시저장 + 000 으로 저장 - // 기본 저장 시 판매점ID + yyMMdd + 000 으로 저장 + 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 ?? - body.storeId + + role + + body.storeId + new Date().getFullYear().toString().slice(-2) + (new Date().getMonth() + 1).toString().padStart(2, '0') + new Date().getDate().toString().padStart(2, '0') @@ -255,7 +250,7 @@ export async function POST(request: Request) { const lastSurvey = await prisma.SD_SURVEY_SALES_BASIC_INFO.findFirst({ where: { SRL_NO: { - startsWith: body.storeId, + startsWith: role + body.storeId, }, }, orderBy: { diff --git a/src/components/popup/SurveySaleSubmitPopup.tsx b/src/components/popup/SurveySaleSubmitPopup.tsx new file mode 100644 index 0000000..1d61da1 --- /dev/null +++ b/src/components/popup/SurveySaleSubmitPopup.tsx @@ -0,0 +1,151 @@ +import Image from 'next/image' +import { usePopupController } from '@/store/popupController' +import { useParams } from 'next/navigation' +import { useServey } from '@/hooks/useSurvey' +import { useState } from 'react' +import { useSessionStore } from '@/store/session' + +interface SubmitFormData { + store: string + sender: string + receiver: string + reference: string + title: string + contents: string +} + +interface FormField { + id: keyof SubmitFormData + name: string + required: boolean +} + +const FORM_FIELDS: FormField[] = [ + { id: 'store', name: '提出販売店', required: true }, + { id: 'sender', name: '発送者', required: true }, + { id: 'receiver', name: '受信者', required: true }, + { id: 'reference', name: '参考', required: false }, + { id: 'title', name: 'タイトル', required: true }, + { id: 'contents', name: '内容', required: true }, +] + +export default function SurveySaleSubmitPopup() { + const popupController = usePopupController() + const { session } = useSessionStore() + const params = useParams() + const routeId = params.id + + const [submitData, setSubmitData] = useState({ + store: '', + sender: session?.email ?? '', + receiver: '', + reference: '', + title: '[HANASYS現地調査] 調査物件が提出.', + contents: '', + }) + + const { submitSurvey, isSubmittingSurvey } = useServey(Number(routeId)) + + const handleInputChange = (field: keyof SubmitFormData, value: string) => { + setSubmitData((prev) => ({ ...prev, [field]: value })) + } + + const validateData = (data: SubmitFormData): boolean => { + const requiredFields = FORM_FIELDS.filter((field) => field.required) + + for (const field of requiredFields) { + if (!data[field.id].trim()) { + const element = document.getElementById(field.id) + if (element) { + element.focus() + } + alert(`${field.name}は必須入力項目です。`) + return false + } + } + + return true + } + + const handleSubmit = () => { + if (validateData(submitData)) { + window.neoConfirm('送信しますか? 送信後は変更・修正することはできません。', () => { + submitSurvey({ targetId: submitData.store }) + if (!isSubmittingSurvey) { + popupController.setSurveySaleSubmitPopup(false) + } + }) + } + } + + const handleClose = () => { + popupController.setSurveySaleSubmitPopup(false) + } + + const renderFormField = (field: FormField) => { + // const isReadOnly = (field.id === 'store' && session?.role !== 'Partner') || (field.id === 'receiver' && session?.role !== 'Partner') + const isReadOnly = false + + return ( +
+
+ {field.name} {field.required && *} +
+
+ {field.id === 'contents' ? ( +