From cc8ef6a7d3f0f813819a20b8742dee9617b371df Mon Sep 17 00:00:00 2001 From: Daseul Kim Date: Mon, 28 Apr 2025 16:51:01 +0900 Subject: [PATCH 01/12] =?UTF-8?q?feat:=20=EC=A7=80=EB=B6=95=EC=9E=AC=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/suitable.ts | 21 ++++++- src/app/api/suitable/category/route.ts | 16 +++++ src/app/api/suitable/list/route.ts | 37 ++++++++++-- src/components/Suitable.tsx | 35 ++++++++--- src/components/SuitableSearch.tsx | 82 +++++++++++++++++++++++--- src/hooks/useSuitable.ts | 30 ++++++++++ src/store/useSuitableStore.ts | 68 +++++++++++++++++++++ 7 files changed, 266 insertions(+), 23 deletions(-) create mode 100644 src/app/api/suitable/category/route.ts create mode 100644 src/hooks/useSuitable.ts create mode 100644 src/store/useSuitableStore.ts diff --git a/src/api/suitable.ts b/src/api/suitable.ts index e8458c4..277bc7e 100644 --- a/src/api/suitable.ts +++ b/src/api/suitable.ts @@ -38,14 +38,31 @@ export interface Suitable { } export const suitableApi = { - getList: async (): Promise => { - const response = await axiosInstance.get('/api/suitable/list') + getList: async (category?: string, keyword?: string): Promise => { + let condition: any = {} + if (category) { + condition['category'] = category + } + if (keyword) { + condition['keyword'] = { + contains: keyword, + } + } + console.log('๐Ÿš€ ~ getList: ~ condition:', condition) + const response = await axiosInstance.get('/api/suitable/list', { params: condition }) console.log('๐Ÿš€ ~ getList: ~ response:', response) return response.data }, + getCategory: async (): Promise => { + const response = await axiosInstance.get('/api/suitable/category') + console.log('๐Ÿš€ ~ getCategory: ~ response:', response) + return response.data + }, + getDetails: async (roofMaterial: string): Promise => { const response = await axiosInstance.get(`/api/suitable/details?roof-material=${roofMaterial}`) + console.log('๐Ÿš€ ~ getDetails: ~ response:', response) return response.data }, diff --git a/src/app/api/suitable/category/route.ts b/src/app/api/suitable/category/route.ts new file mode 100644 index 0000000..288a74a --- /dev/null +++ b/src/app/api/suitable/category/route.ts @@ -0,0 +1,16 @@ +import { NextResponse } from 'next/server' +import { prisma } from '@/libs/prisma' + +export async function GET() { + // @ts-ignore + const roofMaterialCategory = await prisma.MS_SUITABLE.findMany({ + select: { + roof_material: true, + }, + distinct: ['roof_material'], + orderBy: { + roof_material: 'asc', + }, + }) + return NextResponse.json(roofMaterialCategory) +} diff --git a/src/app/api/suitable/list/route.ts b/src/app/api/suitable/list/route.ts index e1a44cb..22c3d8a 100644 --- a/src/app/api/suitable/list/route.ts +++ b/src/app/api/suitable/list/route.ts @@ -1,8 +1,35 @@ -import { NextResponse } from 'next/server' +import { NextRequest, NextResponse } from 'next/server' import { prisma } from '@/libs/prisma' -export async function GET() { - // @ts-ignore - const suitables = await prisma.MS_SUITABLE.findMany() - return NextResponse.json(suitables) + +export async function GET(request: NextRequest) { + try { + const searchParams = request.nextUrl.searchParams + const category = searchParams.get('category') + const keyword = searchParams.get('keyword') + + let whereCondition: any = {} + if (category) { + whereCondition['roof_material'] = category + } + if (keyword) { + whereCondition['product_name'] = { + contains: keyword, + } + } + console.log('๐Ÿš€ ~ /api/suitable/list: ~ prisma where condition:', whereCondition) + + // @ts-ignore + const suitables = await prisma.MS_SUITABLE.findMany({ + where: whereCondition, + orderBy: { + product_name: 'asc', + }, + }) + + return NextResponse.json(suitables) + } catch (error) { + console.error('โŒ ๋ฐ์ดํ„ฐ ์กฐํšŒ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค:', error) + return NextResponse.json({ error: '๋ฐ์ดํ„ฐ ์กฐํšŒ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค' }, { status: 500 }) + } } diff --git a/src/components/Suitable.tsx b/src/components/Suitable.tsx index f5766f1..1af6d86 100644 --- a/src/components/Suitable.tsx +++ b/src/components/Suitable.tsx @@ -1,16 +1,23 @@ 'use client' -import { suitableApi } from '@/api/suitable' +import { useSuitableStore } from '@/store/useSuitableStore' import { useQuery } from '@tanstack/react-query' import { useRouter } from 'next/navigation' +import type { Suitable as SuitableType } from '@/api/suitable' export default function Suitable() { const router = useRouter() - const { data, error, isPending } = useQuery({ - queryKey: ['suitable-list'], - queryFn: suitableApi.getList, + const { selectedItems, addSelectedItem } = useSuitableStore() + + const { data: suitableList, isLoading } = useQuery({ + queryKey: ['suitables', 'search'], + enabled: false, }) + if (isLoading || !suitableList) { + return
Loading...
+ } + return ( <>

Suitable

@@ -22,9 +29,23 @@ export default function Suitable() { > HOME - {error &&
Error: {error.message}
} - {isPending &&
Loading...
} - {data && data.map((item) =>
{item.product_name}
)} +
+

์„ ํƒ๋œ ์•„์ดํ…œ

+ {selectedItems.length > 0 ? selectedItems.map((item) =>
{item.product_name}
) :
์„ ํƒ๋œ ์•„์ดํ…œ์ด ์—†์Šต๋‹ˆ๋‹ค.
} +
+
+
+

๋ฐ์ดํ„ฐ ๋ชฉ๋ก

+ {suitableList ? ( + suitableList.map((item: SuitableType) => ( +
addSelectedItem(item)}> + {item.product_name} +
+ )) + ) : ( +
๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
+ )} +
) } diff --git a/src/components/SuitableSearch.tsx b/src/components/SuitableSearch.tsx index 9583ede..e339f80 100644 --- a/src/components/SuitableSearch.tsx +++ b/src/components/SuitableSearch.tsx @@ -1,21 +1,85 @@ 'use client' -import { useState } from 'react' +import { useEffect, useState } from 'react' import { useRouter } from 'next/navigation' +import { useQuery } from '@tanstack/react-query' +import { useSuitable } from '@/hooks/useSuitable' export default function SuitableSearch() { const router = useRouter() - const [selectedValue, setSelectedValue] = useState('') + const [selectedCategory, setSelectedCategory] = useState('') + const [searchValue, setSearchValue] = useState('') + const { getCategories, getSuitables } = useSuitable() + + const { data: categories } = useQuery({ + queryKey: ['categories'], + queryFn: getCategories, + staleTime: 1000 * 60 * 60, // 60๋ถ„ + }) + + const { data: suitableList } = useQuery({ + queryKey: ['suitables', 'list'], + queryFn: async () => await getSuitables(), + staleTime: 1000 * 60 * 10, // 10๋ถ„ + gcTime: 1000 * 60 * 10, // 10๋ถ„ + }) + + const { data: suitableSearch, refetch: refetchBySearch } = useQuery({ + queryKey: ['suitables', 'search'], + queryFn: async () => { + // api๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒ€์ƒ‰ ๋ฐฉ๋ฒ• + // return await updateSearchResults(selectedCategory || undefined, searchValue || undefined) + // useQuery ์บ์‹œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒ€์ƒ‰ ๋ฐฉ๋ฒ• + return ( + suitableList?.filter((item) => { + const categoryMatch = !selectedCategory || item.roof_material === selectedCategory + const searchMatch = !searchValue || item.product_name.includes(searchValue) + return categoryMatch && searchMatch + }) ?? [] + ) + }, + staleTime: 1000 * 60 * 10, + gcTime: 1000 * 60 * 10, + enabled: false, + }) + + // ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ๋œ ํ›„ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์—†์œผ๋ฉด ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ๋กœ๋”ฉ + useEffect(() => { + if (suitableList && (!suitableSearch || suitableSearch.length === 0)) { + refetchBySearch() + } + }, [suitableList, suitableSearch]) + + // ์นดํ…Œ๊ณ ๋ฆฌ ์„ ํƒ ์‹œ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ๋กœ๋”ฉ + useEffect(() => { + refetchBySearch() + }, [selectedCategory]) + + const handleSearch = async () => { + if (!searchValue.trim()) { + alert('๊ฒ€์ƒ‰์–ด๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”.') + return + } + refetchBySearch() + } return ( <> - - +
+ + +
+
+ setSearchValue(e.target.value)} /> + +
) } diff --git a/src/hooks/useSuitable.ts b/src/hooks/useSuitable.ts new file mode 100644 index 0000000..62f00e2 --- /dev/null +++ b/src/hooks/useSuitable.ts @@ -0,0 +1,30 @@ +import { suitableApi } from '@/api/suitable' + +export function useSuitable() { + const getCategories = async () => { + try { + return await suitableApi.getCategory() + } catch (error) { + console.error('์นดํ…Œ๊ณ ๋ฆฌ ๋ฐ์ดํ„ฐ ๋กœ๋“œ ์‹คํŒจ:', error) + return [] + } + } + + const getSuitables = async () => { + try { + return await suitableApi.getList() + } catch (error) { + console.error('์ง€๋ถ•์žฌ ๋ฐ์ดํ„ฐ ๋กœ๋“œ ์‹คํŒจ:', error) + } + } + + const updateSearchResults = async (selectedCategory: string | undefined, searchValue: string | undefined) => { + try { + return await suitableApi.getList(selectedCategory, searchValue) + } catch (error) { + console.error('์ง€๋ถ•์žฌ ๋ฐ์ดํ„ฐ ๊ฒ€์ƒ‰ ์‹คํŒจ:', error) + } + } + + return { getCategories, getSuitables, updateSearchResults } +} diff --git a/src/store/useSuitableStore.ts b/src/store/useSuitableStore.ts new file mode 100644 index 0000000..17b88c5 --- /dev/null +++ b/src/store/useSuitableStore.ts @@ -0,0 +1,68 @@ +import { create } from 'zustand' +import { Suitable, suitableApi } from '@/api/suitable' + +interface SuitableState { + // // ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ๋ฆฌ์ŠคํŠธ + // searchResults: Suitable[] + // // ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ ๋กœ๋“œ + // fetchInitializeData: () => Promise + // // ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์„ค์ • + // setSearchResults: (results: Suitable[]) => void + // // ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์ดˆ๊ธฐํ™” + // resetSearchResults: () => void + + // ์„ ํƒ๋œ ์•„์ดํ…œ ๋ฆฌ์ŠคํŠธ + selectedItems: Suitable[] + // ์„ ํƒ๋œ ์•„์ดํ…œ ์ถ”๊ฐ€ + addSelectedItem: (item: Suitable) => void + // ์„ ํƒ๋œ ์•„์ดํ…œ ์ œ๊ฑฐ + removeSelectedItem: (itemId: number) => void + // ์„ ํƒ๋œ ์•„์ดํ…œ ๋ชจ๋‘ ์ œ๊ฑฐ + clearSelectedItems: () => void +} + +export const useSuitableStore = create((set) => ({ + // // ์ดˆ๊ธฐ ์ƒํƒœ + // searchResults: [], + + // // ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ ๋กœ๋“œ + // fetchInitializeData: async () => { + // const suitables = await fetchInitialSuitablee() + // set({ searchResults: suitables }) + // }, + + // // ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์„ค์ • + // setSearchResults: (results) => set({ searchResults: results }), + + // // ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์ดˆ๊ธฐํ™” + // resetSearchResults: () => set({ searchResults: [] }), + + // ์ดˆ๊ธฐ ์ƒํƒœ + selectedItems: [], + + // ์„ ํƒ๋œ ์•„์ดํ…œ ์ถ”๊ฐ€ (์ค‘๋ณต ๋ฐฉ์ง€) + addSelectedItem: (item) => + set((state) => ({ + selectedItems: state.selectedItems.some((i) => i.id === item.id) ? state.selectedItems : [...state.selectedItems, item], + })), + + // ์„ ํƒ๋œ ์•„์ดํ…œ ์ œ๊ฑฐ + removeSelectedItem: (itemId) => + set((state) => ({ + selectedItems: state.selectedItems.filter((item) => item.id !== itemId), + })), + + // ์„ ํƒ๋œ ์•„์ดํ…œ ๋ชจ๋‘ ์ œ๊ฑฐ + clearSelectedItems: () => set({ selectedItems: [] }), +})) + +// // ์ „์ฒด ๋ฐ์ดํ„ฐ ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜ +// async function fetchInitialSuitablee() { +// try { +// const suitable = await suitableApi.getList() +// return suitable +// } catch (error) { +// console.error('์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ ๋กœ๋“œ ์‹คํŒจ:', error) +// return [] +// } +// } From bfbbdc01b8dce44375f7516cf9ed6ff358e5b63f Mon Sep 17 00:00:00 2001 From: Daseul Kim Date: Tue, 29 Apr 2025 10:49:58 +0900 Subject: [PATCH 02/12] =?UTF-8?q?feat:=20=EC=A7=80=EB=B6=95=EC=9E=AC=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=84=A0=ED=83=9D=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Suitable.tsx | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/components/Suitable.tsx b/src/components/Suitable.tsx index 1af6d86..eb725a2 100644 --- a/src/components/Suitable.tsx +++ b/src/components/Suitable.tsx @@ -1,16 +1,25 @@ 'use client' import { useSuitableStore } from '@/store/useSuitableStore' -import { useQuery } from '@tanstack/react-query' +import { useQuery, useQueryClient } from '@tanstack/react-query' import { useRouter } from 'next/navigation' import type { Suitable as SuitableType } from '@/api/suitable' export default function Suitable() { const router = useRouter() - const { selectedItems, addSelectedItem } = useSuitableStore() + const queryClient = useQueryClient() + const { selectedItems, addSelectedItem, removeSelectedItem } = useSuitableStore() + const handleItemClick = (item: SuitableType) => { + if (!item.id) return // ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ import ๋•Œ๋ฌธ์— Suitable.id๊ฐ€ optional ํƒ€์ž…์ด๋ผ์„œ ๋ฐฉ์–ด ์ฒ˜๋ฆฌ ์ถ”๊ฐ€ + selectedItems.some((selected) => selected.id === item.id) ? removeSelectedItem(item.id) : addSelectedItem(item) + } const { data: suitableList, isLoading } = useQuery({ queryKey: ['suitables', 'search'], + queryFn: async () => { + const data = queryClient.getQueryData(['suitables', 'search']) as SuitableType[] + return data ?? [] + }, enabled: false, }) @@ -31,14 +40,22 @@ export default function Suitable() {

์„ ํƒ๋œ ์•„์ดํ…œ

- {selectedItems.length > 0 ? selectedItems.map((item) =>
{item.product_name}
) :
์„ ํƒ๋œ ์•„์ดํ…œ์ด ์—†์Šต๋‹ˆ๋‹ค.
} + {selectedItems.length > 0 ? ( + selectedItems.map((item) => ( +
handleItemClick(item)}> + {item.product_name} +
+ )) + ) : ( +
์„ ํƒ๋œ ์•„์ดํ…œ์ด ์—†์Šต๋‹ˆ๋‹ค.
+ )}

๋ฐ์ดํ„ฐ ๋ชฉ๋ก

{suitableList ? ( suitableList.map((item: SuitableType) => ( -
addSelectedItem(item)}> +
handleItemClick(item)}> {item.product_name}
)) From adfe6d7a3281f476adf7f3fcf37b9e94cccacd87 Mon Sep 17 00:00:00 2001 From: Daseul Kim Date: Wed, 30 Apr 2025 16:20:36 +0900 Subject: [PATCH 03/12] =?UTF-8?q?feat:=20=EC=A7=80=EB=B6=95=EC=9E=AC=20?= =?UTF-8?q?=EC=A0=81=ED=95=A9=EC=84=B1=20pdf=20=EA=B8=B0=EB=B3=B8=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/api/suitable/details/route.ts | 1 + src/components/Suitable.tsx | 3 +- src/components/SuitableDetails.tsx | 74 +++++++++++++--- src/components/SuitablePdf.tsx | 116 ++++++++++++++++++++++++++ src/components/SuitableSearch.tsx | 5 +- 5 files changed, 184 insertions(+), 15 deletions(-) create mode 100644 src/components/SuitablePdf.tsx diff --git a/src/app/api/suitable/details/route.ts b/src/app/api/suitable/details/route.ts index 2645411..d29f666 100644 --- a/src/app/api/suitable/details/route.ts +++ b/src/app/api/suitable/details/route.ts @@ -1,4 +1,5 @@ import { NextResponse } from 'next/server' +import { prisma } from '@/libs/prisma' export async function GET(request: Request) { const { searchParams } = new URL(request.url) diff --git a/src/components/Suitable.tsx b/src/components/Suitable.tsx index eb725a2..e21b4d4 100644 --- a/src/components/Suitable.tsx +++ b/src/components/Suitable.tsx @@ -9,6 +9,7 @@ export default function Suitable() { const router = useRouter() const queryClient = useQueryClient() const { selectedItems, addSelectedItem, removeSelectedItem } = useSuitableStore() + const handleItemClick = (item: SuitableType) => { if (!item.id) return // ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ import ๋•Œ๋ฌธ์— Suitable.id๊ฐ€ optional ํƒ€์ž…์ด๋ผ์„œ ๋ฐฉ์–ด ์ฒ˜๋ฆฌ ์ถ”๊ฐ€ selectedItems.some((selected) => selected.id === item.id) ? removeSelectedItem(item.id) : addSelectedItem(item) @@ -23,7 +24,7 @@ export default function Suitable() { enabled: false, }) - if (isLoading || !suitableList) { + if (isLoading || !suitableList || suitableList.length === 0) { return
Loading...
} diff --git a/src/components/SuitableDetails.tsx b/src/components/SuitableDetails.tsx index 795fcdc..748c28f 100644 --- a/src/components/SuitableDetails.tsx +++ b/src/components/SuitableDetails.tsx @@ -1,23 +1,71 @@ 'use client' -import { Suitable, suitableApi } from '@/api/suitable' -import { useQuery, useQueryClient } from '@tanstack/react-query' +import { suitableApi } from '@/api/suitable' +import { useQuery } from '@tanstack/react-query' +import generatePDF, { usePDF, Options } from 'react-to-pdf' +import PDFContent from './SuitablePdf' + +const pdfOptions: Options = { + filename: 'page.pdf', + method: 'save', + page: { format: 'a4', margin: 10 }, + overrides: { + pdf: { + compress: true, + }, + }, +} export default function SuitableDetails({ roofMaterial }: { roofMaterial: string }) { - console.log('๐Ÿš€ ~ SuitableDetails ~ roofMaterial:', roofMaterial) - // const { data, error, isPending } = useQuery({ - // queryKey: ['suitable-details'], - // queryFn: () => suitableApi.getDetails(roofMaterial), - // staleTime: 0, - // }) - const cache = useQueryClient() - const listData = cache.getQueryData(['suitable-list']) as Suitable[] - const data = listData.filter((item) => item.roof_material === roofMaterial) + const { data, isLoading } = useQuery({ + queryKey: ['suitable-details'], + queryFn: () => suitableApi.getDetails(roofMaterial), + staleTime: 0, + enabled: !!roofMaterial, + }) + + const { toPDF, targetRef } = usePDF({ ...pdfOptions, method: 'open' }) + + if (isLoading) { + return
Loading...
+ } return ( <> -

Searched Roof Material: {roofMaterial}

- {data && data.map((item) =>
{item.product_name}
)} + + + {/* */} + {/*
*/} +
+

Searched Roof Material: {decodeURIComponent(roofMaterial as string)}

+ {data && + data.map((item) => ( +
+
+
product_name: {item.product_name}
+
manufacturer: {item.manufacturer}
+
roof_material: {item.roof_material}
+
shape: {item.shape}
+
support_roof_tile: {item.support_roof_tile}
+
support_roof_bracket: {item.support_roof_bracket}
+
yg_anchor: {item.yg_anchor}
+
+ ))} +
+ {/*
*/} +
+
+

PDF ๋‚ด์šฉ ๋‚˜์™€๋ผ

+ +
+
) } diff --git a/src/components/SuitablePdf.tsx b/src/components/SuitablePdf.tsx new file mode 100644 index 0000000..f059744 --- /dev/null +++ b/src/components/SuitablePdf.tsx @@ -0,0 +1,116 @@ +import { Suitable } from '@/api/suitable' + +interface StatusInfo { + statusIcon: string + statusText: string +} + +interface FittingItem { + name: string + value: string + memo: string +} + +function getStatusInfo(value: string): StatusInfo | null { + const val = value?.trim()?.replace(/ใƒผ|๏ผ/g, '-') || '' + + if (['โ—‹', 'ใ€‡'].includes(val)) { + return { + statusIcon: 'โœ…', + statusText: '่จญ็ฝฎๅฏ', + } + } + + if (['ร—', 'โœ•'].includes(val)) { + return { + statusIcon: 'โŒ', + statusText: '่จญ็ฝฎไธๅฏ', + } + } + + if (['-', '๏ผ', 'ใƒผ'].includes(val)) { + return { + statusIcon: 'โ“', + statusText: 'ใŠๅ•ใ„ๅˆใ‚ใ›ใใ ใ•ใ„', + } + } + + if (val === '') return null + + return { + statusIcon: 'โœ…', + statusText: `${val} ใง่จญ็ฝฎๅฏ`, + } +} + +function getFittingItems(item: Suitable): FittingItem[] { + return [ + { name: 'ๅฑ‹ๆ น็“ฆ็”จๆ”ฏๆŒ้‡‘ๅ…ท', value: item.support_roof_tile, memo: item.support_roof_tile_memo }, + { name: 'ๅฑ‹ๆ นใƒ–ใƒฉใ‚ฑใƒƒใƒˆ็”จๆ”ฏๆŒ้‡‘ๅ…ท', value: item.support_roof_bracket, memo: item.support_roof_bracket_memo }, + { name: 'YGใ‚ขใƒณใ‚ซใƒผ', value: item.yg_anchor, memo: item.yg_anchor_memo }, + { name: 'RGๅฑ‹ๆ น็“ฆใƒ‘ใƒผใƒ„', value: item.rg_roof_tile_part, memo: item.rg_roof_tile_part_memo }, + { name: 'DIDOใƒใƒณใƒˆๆ”ฏๆŒ็“ฆ2', value: item.dido_hunt_support_tile_2, memo: item.dido_hunt_support_tile_2_memo }, + { name: '้ซ˜ๅณถใƒ‘ใƒฏใƒผใƒ™ใƒผใ‚น', value: item.takashima_power_base, memo: item.takashima_power_base_memo }, + { name: '้ซ˜ๅณถ็“ฆใƒ–ใƒฉใ‚ฑใƒƒใƒˆ', value: item.takashima_tile_bracket, memo: item.takashima_tile_bracket_memo }, + { name: 'ใ‚นใƒฌใƒผใƒˆใƒ–ใƒฉใ‚ฑใƒƒใƒˆ4', value: item.slate_bracket_4, memo: item.slate_bracket_4_memo }, + { name: 'ใ‚นใƒฌใƒผใƒˆใ‚ทใƒณใ‚ฐใƒซใƒกใ‚ฟใƒซใƒ–ใƒฉใ‚ฑใƒƒใƒˆ', value: item.slate_single_metal_bracket, memo: item.slate_single_metal_bracket_memo }, + { name: 'DIDOใƒใƒณใƒˆใ‚ทใƒงใƒผใƒˆใƒฉใƒƒใ‚ฏ4', value: item.dido_hunt_short_rack_4, memo: item.dido_hunt_short_rack_4_memo }, + { + name: '้ซ˜ๅณถใ‚นใƒฌใƒผใƒˆใƒ–ใƒฉใ‚ฑใƒƒใƒˆใ‚นใƒฌใƒผใƒˆใ‚ทใƒณใ‚ฐใƒซ', + value: item.takashima_slate_bracket_slate_single, + memo: item.takashima_slate_bracket_slate_single_memo, + }, + { name: 'DFใƒกใ‚ฟใƒซใƒ–ใƒฉใ‚ฑใƒƒใƒˆ', value: item.df_metal_bracket, memo: item.df_metal_bracket_memo }, + { name: 'ใ‚นใƒฌใƒผใƒˆใƒกใ‚ฟใƒซใƒ–ใƒฉใ‚ฑใƒƒใƒˆ', value: item.slate_metal_bracket, memo: item.slate_metal_bracket_memo }, + { name: '้ซ˜ๅณถใ‚นใƒฌใƒผใƒˆใƒ–ใƒฉใ‚ฑใƒƒใƒˆใƒกใ‚ฟใƒซๅฑ‹ๆ น', value: item.takashima_slate_bracket_metal_roof, memo: item.takashima_slate_bracket_metal_roof_memo }, + ] +} + +function FittingItem({ fitting }: { fitting: FittingItem }) { + const statusInfo = getStatusInfo(fitting.value) + if (!statusInfo) return null + + return ( +
  • + {statusInfo.statusIcon} + + {fitting.name}๏ผš{statusInfo.statusText} + + {fitting.memo && ( + + ๅ‚™่€ƒ๏ผš + {fitting.memo} + + )} +
  • + ) +} + +export default function PDFContent({ data }: { data: Suitable[] }) { + return ( +
    + +

    ้ฉๅˆ็ตๆžœ (์ ํ•ฉ๊ฒฐ๊ณผ)

    + {data.map((item) => ( +
    +
    +

    + {item.product_name}๏ผˆ{item.manufacturer} / {item.roof_material} / {item.shape}๏ผ‰ +

    +
      + {getFittingItems(item).map((fitting, index) => ( + + ))} +
    +
    + ))} +
    + ) +} diff --git a/src/components/SuitableSearch.tsx b/src/components/SuitableSearch.tsx index e339f80..4e3aa13 100644 --- a/src/components/SuitableSearch.tsx +++ b/src/components/SuitableSearch.tsx @@ -4,6 +4,7 @@ import { useEffect, useState } from 'react' import { useRouter } from 'next/navigation' import { useQuery } from '@tanstack/react-query' import { useSuitable } from '@/hooks/useSuitable' +import Link from 'next/link' export default function SuitableSearch() { const router = useRouter() @@ -74,7 +75,9 @@ export default function SuitableSearch() { ))} - + + ์ง€๋ถ•์žฌ ์ข…๋ฅ˜ ์ƒ์„ธ๋ณด๊ธฐ ํŽ˜์ด์ง€ ์ด๋™ +
    setSearchValue(e.target.value)} /> From e84ef1b7a02d9ecd368525f63b23f91296212888 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Mon, 12 May 2025 11:24:32 +0900 Subject: [PATCH 04/12] fix: update session data handling in RootLayout to conditionally stringify session based on login status --- src/app/layout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/layout.tsx b/src/app/layout.tsx index cc67df2..093dbec 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -28,7 +28,7 @@ export default async function RootLayout({ children, header, footer, floatBtn }: const cookieStore = await cookies() const session = await getIronSession(cookieStore, sessionOptions) - const sessionData = JSON.stringify(session) + const sessionData = session.isLoggedIn ? JSON.stringify(session) : '' return ( From 69d81d892dea416bb426518222675a921f473c85 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Mon, 12 May 2025 13:34:14 +0900 Subject: [PATCH 05/12] fix: conditionally update session state in EdgeProvider based on presence of sessionData --- src/providers/EdgeProvider.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/providers/EdgeProvider.tsx b/src/providers/EdgeProvider.tsx index 4d789f3..9caa71d 100644 --- a/src/providers/EdgeProvider.tsx +++ b/src/providers/EdgeProvider.tsx @@ -63,10 +63,12 @@ export default function EdgeProvider({ children, sessionData }: EdgeProviderProp ) return false } - setSession({ - ...session, - ...JSON.parse(sessionData), - }) + if (sessionData && sessionData !== '') { + setSession({ + ...session, + ...JSON.parse(sessionData), + }) + } }, []) /** From b4e009cb8e89ae8ae00029608dfc0a8ff72ab697 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Mon, 12 May 2025 18:24:11 +0900 Subject: [PATCH 06/12] chore: add inquiry API URL to development and production environment files --- .env.development | 5 ++++- .env.production | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.env.development b/.env.development index c8a3ab5..9d7881a 100644 --- a/.env.development +++ b/.env.development @@ -4,4 +4,7 @@ NEXT_PUBLIC_API_URL=http://localhost:3000 #qsp ๋กœ๊ทธ์ธ api -NEXT_PUBLIC_QSP_API_URL=http://1.248.227.176:8120 \ No newline at end of file +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 \ No newline at end of file diff --git a/.env.production b/.env.production index 1d169db..3d04f51 100644 --- a/.env.production +++ b/.env.production @@ -2,4 +2,7 @@ NEXT_PUBLIC_API_URL=http://172.30.1.35:3000 #qsp ๋กœ๊ทธ์ธ api -NEXT_PUBLIC_QSP_API_URL=http://1.248.227.176:8120 \ No newline at end of file +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 \ No newline at end of file From 778d3b6be8adb6fb883bb1f2477733f99ec2975a Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Mon, 12 May 2025 18:24:18 +0900 Subject: [PATCH 07/12] refactor: enhance DoubleBtnAlert and Header components with improved button handling and confirm dialog integration --- src/components/ui/common/DoubleBtnAlert.tsx | 17 ++++++++++---- src/components/ui/common/Header.tsx | 19 +++++++++++++++- src/providers/EdgeProvider.tsx | 25 ++++++++++----------- src/utils/window.ts | 7 ++++++ 4 files changed, 50 insertions(+), 18 deletions(-) create mode 100644 src/utils/window.ts diff --git a/src/components/ui/common/DoubleBtnAlert.tsx b/src/components/ui/common/DoubleBtnAlert.tsx index 43129b7..fed3be5 100644 --- a/src/components/ui/common/DoubleBtnAlert.tsx +++ b/src/components/ui/common/DoubleBtnAlert.tsx @@ -1,10 +1,19 @@ 'use client' import { usePopupController } from '@/store/popupController' -import React from 'react' export default function DoubleBtnAlert() { - const { alertMsg, alert2BtnYes, alert2BtnNo } = usePopupController() + const { alertMsg, alert2BtnYes, alert2BtnNo, setAlert2 } = usePopupController() + + const handleAlert2BtnYes = () => { + alert2BtnYes() + setAlert2(false) + } + + const handleAlert2BtnNo = () => { + alert2BtnNo() + setAlert2(false) + } return (
    @@ -13,12 +22,12 @@ export default function DoubleBtnAlert() {
    {alertMsg}
    -
    -
    diff --git a/src/components/ui/common/Header.tsx b/src/components/ui/common/Header.tsx index 6630e1a..30e646f 100644 --- a/src/components/ui/common/Header.tsx +++ b/src/components/ui/common/Header.tsx @@ -14,6 +14,7 @@ import { useTitle } from '@/hooks/useTitle' import { axiosInstance } from '@/libs/axios' import 'swiper/css' +import { confirmParamsSerialize } from '@/utils/window' export default function Header() { const router = useRouter() @@ -38,6 +39,22 @@ export default function Header() { } } + const handleYes = () => { + console.log('yes') + } + + const handleNo = () => { + console.log('no') + } + + const handleCofirm = () => { + window.neoConfirm( + 'ใ‚ˆใ‚ใ—ใ„ใงใ™ใ‹๏ผŸ', + () => console.log('yes'), + () => console.log('no'), + ) + } + return ( <>
    @@ -45,7 +62,7 @@ export default function Header() {
    {backBtn && (
    - +
    )}

    diff --git a/src/providers/EdgeProvider.tsx b/src/providers/EdgeProvider.tsx index 9caa71d..424ab2d 100644 --- a/src/providers/EdgeProvider.tsx +++ b/src/providers/EdgeProvider.tsx @@ -7,6 +7,12 @@ import { usePathname } from 'next/navigation' import { useEffect } from 'react' import { useSessionStore } from '@/store/session' +declare global { + interface Window { + neoConfirm: (msg?: string, alertBtn2Yes?: Function, alertBtn2No?: Function) => boolean + } +} + interface EdgeProviderProps { children: React.ReactNode sessionData: string @@ -44,25 +50,18 @@ export default function EdgeProvider({ children, sessionData }: EdgeProviderProp setAlert2(true) } - //alert ํ•จ์ˆ˜ ๋ณ€๊ฒฝํ•ด์„œ ๋ฐ”์ธ๋”ฉ useEffect(() => { + //alert ํ•จ์ˆ˜ ๋ณ€๊ฒฝํ•ด์„œ ๋ฐ”์ธ๋”ฉ window.alert = function (msg, alertBtn = () => setAlert(false)) { alertFunc(msg, alertBtn) } - window.confirm = function (msg = '', alert2BtnYes = () => setAlert2(false), alert2BtnNo = () => setAlert2(false)) { - alertFunc2( - msg, - () => { - alert2BtnYes() - return true - }, - () => { - alert2BtnNo() - return false - }, - ) + // confirm ํ•จ์ˆ˜ ๋ณ€๊ฒฝํ•ด์„œ ๋ฐ”์ธ๋”ฉ + window.neoConfirm = function (msg: string | undefined, alertBtn2Yes?: Function, alertBtn2No?: Function) { + if (!msg) return false + alertFunc2(msg, alertBtn2Yes || (() => {}), alertBtn2No || (() => {})) return false } + // ์„œ๋ฒ„ ์„ธ์…˜์ด ์žˆ์œผ๋ฉด zuatand ์„ธ์…˜ ๋ฐ์ดํ„ฐ ๊ฐฑ์‹  if (sessionData && sessionData !== '') { setSession({ ...session, diff --git a/src/utils/window.ts b/src/utils/window.ts new file mode 100644 index 0000000..bb20dae --- /dev/null +++ b/src/utils/window.ts @@ -0,0 +1,7 @@ +export const confirmParamsSerialize = ({ msg, yes, no }: { msg: string; yes: () => void; no: () => void }) => { + return JSON.stringify({ msg, yes, no }) +} + +export const confirmParamsDeserialize = (params: string) => { + return JSON.parse(params) +} From bc1c1579ccddb925b5360bba41e5c75a0c42e987 Mon Sep 17 00:00:00 2001 From: Daseul Kim Date: Tue, 13 May 2025 09:35:21 +0900 Subject: [PATCH 08/12] =?UTF-8?q?feat:=20=EC=A7=80=EB=B6=95=EC=9E=AC=20?= =?UTF-8?q?=EC=A0=81=ED=95=A9=EC=84=B1=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=ED=85=8C=EC=9D=B4=EB=B8=94=20=EB=AA=A8?= =?UTF-8?q?=EB=8D=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- prisma/schema.prisma | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 3a511a3..4efd2aa 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -79,13 +79,13 @@ model SD_SERVEY_SALES_DETAIL_INFO { id Int @id @default(autoincrement()) contract_capacity String? @db.VarChar(20) retail_company String? @db.VarChar(100) - supplementary_facilities Int? + supplementary_facilities String? @db.VarChar(20) supplementary_facilities_etc String? @db.VarChar(200) installation_system Int? installation_system_etc String? @db.VarChar(200) construction_year Int? construction_year_etc String? @db.VarChar(200) - roof_material Int? + roof_material String? @db.VarChar(20) roof_material_etc String? @db.VarChar(200) roof_shape Int? roof_shape_etc String? @db.VarChar(200) @@ -177,3 +177,33 @@ model BC_COMM_L { @@id([HEAD_CD, CODE], map: "PK_BC_COMM_L") } + +model MS_SUITABLE_ROOF_MATERIAL_GROUP { + id Int @id @default(autoincrement()) + roof_material_group String @db.VarChar(200) + roof_material String @db.VarChar(200) + created_at DateTime @default(now(), map: "DF__MS_SUITAB__creat__4F7CD00D") + updated_at DateTime +} + +model MS_SUITABLE_DETAIL { + id Int @id @default(autoincrement()) + main_id Int + trestle_manufacturer_product_code String? @db.VarChar(200) + trestle_manufacturer_product_name String? @db.VarChar(200) + memo String? @db.VarChar(500) + created_at DateTime @default(now(), map: "DF__MS_SUITAB__creat__571DF1D5") + updated_at DateTime? + MS_SUITABLE_MAIN MS_SUITABLE_MAIN @relation(fields: [main_id], references: [id], onUpdate: NoAction, map: "MS_SUITABLE_DETAIL_MS_SUITABLE_MAIN_FK") +} + +model MS_SUITABLE_MAIN { + id Int @id @default(autoincrement()) + product_name String @db.VarChar(200) + manufacturer String? @db.VarChar(200) + roof_material String? @db.VarChar(100) + shape String? @db.VarChar(200) + created_at DateTime @default(now(), map: "DF__MS_SUITAB__creat__5441852A") + updated_at DateTime? @updatedAt + details MS_SUITABLE_DETAIL[] +} From 186843e1548ed5c4d61844c9b7100e2aa5f7b384 Mon Sep 17 00:00:00 2001 From: Daseul Kim Date: Tue, 13 May 2025 09:40:08 +0900 Subject: [PATCH 09/12] =?UTF-8?q?remove:=20=EB=AF=B8=EC=82=AC=EC=9A=A9=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=ED=8C=8C=EC=9D=BC=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/SuitablePdf.tsx | 116 --------------------------------- 1 file changed, 116 deletions(-) delete mode 100644 src/components/SuitablePdf.tsx diff --git a/src/components/SuitablePdf.tsx b/src/components/SuitablePdf.tsx deleted file mode 100644 index f059744..0000000 --- a/src/components/SuitablePdf.tsx +++ /dev/null @@ -1,116 +0,0 @@ -import { Suitable } from '@/api/suitable' - -interface StatusInfo { - statusIcon: string - statusText: string -} - -interface FittingItem { - name: string - value: string - memo: string -} - -function getStatusInfo(value: string): StatusInfo | null { - const val = value?.trim()?.replace(/ใƒผ|๏ผ/g, '-') || '' - - if (['โ—‹', 'ใ€‡'].includes(val)) { - return { - statusIcon: 'โœ…', - statusText: '่จญ็ฝฎๅฏ', - } - } - - if (['ร—', 'โœ•'].includes(val)) { - return { - statusIcon: 'โŒ', - statusText: '่จญ็ฝฎไธๅฏ', - } - } - - if (['-', '๏ผ', 'ใƒผ'].includes(val)) { - return { - statusIcon: 'โ“', - statusText: 'ใŠๅ•ใ„ๅˆใ‚ใ›ใใ ใ•ใ„', - } - } - - if (val === '') return null - - return { - statusIcon: 'โœ…', - statusText: `${val} ใง่จญ็ฝฎๅฏ`, - } -} - -function getFittingItems(item: Suitable): FittingItem[] { - return [ - { name: 'ๅฑ‹ๆ น็“ฆ็”จๆ”ฏๆŒ้‡‘ๅ…ท', value: item.support_roof_tile, memo: item.support_roof_tile_memo }, - { name: 'ๅฑ‹ๆ นใƒ–ใƒฉใ‚ฑใƒƒใƒˆ็”จๆ”ฏๆŒ้‡‘ๅ…ท', value: item.support_roof_bracket, memo: item.support_roof_bracket_memo }, - { name: 'YGใ‚ขใƒณใ‚ซใƒผ', value: item.yg_anchor, memo: item.yg_anchor_memo }, - { name: 'RGๅฑ‹ๆ น็“ฆใƒ‘ใƒผใƒ„', value: item.rg_roof_tile_part, memo: item.rg_roof_tile_part_memo }, - { name: 'DIDOใƒใƒณใƒˆๆ”ฏๆŒ็“ฆ2', value: item.dido_hunt_support_tile_2, memo: item.dido_hunt_support_tile_2_memo }, - { name: '้ซ˜ๅณถใƒ‘ใƒฏใƒผใƒ™ใƒผใ‚น', value: item.takashima_power_base, memo: item.takashima_power_base_memo }, - { name: '้ซ˜ๅณถ็“ฆใƒ–ใƒฉใ‚ฑใƒƒใƒˆ', value: item.takashima_tile_bracket, memo: item.takashima_tile_bracket_memo }, - { name: 'ใ‚นใƒฌใƒผใƒˆใƒ–ใƒฉใ‚ฑใƒƒใƒˆ4', value: item.slate_bracket_4, memo: item.slate_bracket_4_memo }, - { name: 'ใ‚นใƒฌใƒผใƒˆใ‚ทใƒณใ‚ฐใƒซใƒกใ‚ฟใƒซใƒ–ใƒฉใ‚ฑใƒƒใƒˆ', value: item.slate_single_metal_bracket, memo: item.slate_single_metal_bracket_memo }, - { name: 'DIDOใƒใƒณใƒˆใ‚ทใƒงใƒผใƒˆใƒฉใƒƒใ‚ฏ4', value: item.dido_hunt_short_rack_4, memo: item.dido_hunt_short_rack_4_memo }, - { - name: '้ซ˜ๅณถใ‚นใƒฌใƒผใƒˆใƒ–ใƒฉใ‚ฑใƒƒใƒˆใ‚นใƒฌใƒผใƒˆใ‚ทใƒณใ‚ฐใƒซ', - value: item.takashima_slate_bracket_slate_single, - memo: item.takashima_slate_bracket_slate_single_memo, - }, - { name: 'DFใƒกใ‚ฟใƒซใƒ–ใƒฉใ‚ฑใƒƒใƒˆ', value: item.df_metal_bracket, memo: item.df_metal_bracket_memo }, - { name: 'ใ‚นใƒฌใƒผใƒˆใƒกใ‚ฟใƒซใƒ–ใƒฉใ‚ฑใƒƒใƒˆ', value: item.slate_metal_bracket, memo: item.slate_metal_bracket_memo }, - { name: '้ซ˜ๅณถใ‚นใƒฌใƒผใƒˆใƒ–ใƒฉใ‚ฑใƒƒใƒˆใƒกใ‚ฟใƒซๅฑ‹ๆ น', value: item.takashima_slate_bracket_metal_roof, memo: item.takashima_slate_bracket_metal_roof_memo }, - ] -} - -function FittingItem({ fitting }: { fitting: FittingItem }) { - const statusInfo = getStatusInfo(fitting.value) - if (!statusInfo) return null - - return ( -
  • - {statusInfo.statusIcon} - - {fitting.name}๏ผš{statusInfo.statusText} - - {fitting.memo && ( - - ๅ‚™่€ƒ๏ผš - {fitting.memo} - - )} -
  • - ) -} - -export default function PDFContent({ data }: { data: Suitable[] }) { - return ( -
    - -

    ้ฉๅˆ็ตๆžœ (์ ํ•ฉ๊ฒฐ๊ณผ)

    - {data.map((item) => ( -
    -
    -

    - {item.product_name}๏ผˆ{item.manufacturer} / {item.roof_material} / {item.shape}๏ผ‰ -

    -
      - {getFittingItems(item).map((fitting, index) => ( - - ))} -
    -
    - ))} -
    - ) -} From 2c75a6b416a4d7b6d8131b2a8c1550efb36d4d2c Mon Sep 17 00:00:00 2001 From: Daseul Kim Date: Tue, 13 May 2025 10:51:17 +0900 Subject: [PATCH 10/12] =?UTF-8?q?refactor:=20=EC=A7=80=EB=B6=95=EC=9E=AC?= =?UTF-8?q?=20=EC=A0=81=ED=95=A9=EC=84=B1=20=ED=85=8C=EC=9D=B4=EB=B8=94=20?= =?UTF-8?q?=EC=BB=AC=EB=9F=BC=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- prisma/schema.prisma | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 4efd2aa..3cc1c4c 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -179,31 +179,31 @@ model BC_COMM_L { } model MS_SUITABLE_ROOF_MATERIAL_GROUP { - id Int @id @default(autoincrement()) - roof_material_group String @db.VarChar(200) - roof_material String @db.VarChar(200) - created_at DateTime @default(now(), map: "DF__MS_SUITAB__creat__4F7CD00D") - updated_at DateTime + ID Int @id @default(autoincrement()) + ROOF_MATERIAL_GROUP String @db.VarChar(200) + ROOF_MATERIAL String @db.VarChar(200) + REG_DT DateTime @default(now(), map: "DF__MS_SUITAB__creat__4F7CD00D") + UPT_DT DateTime } model MS_SUITABLE_DETAIL { - id Int @id @default(autoincrement()) - main_id Int - trestle_manufacturer_product_code String? @db.VarChar(200) - trestle_manufacturer_product_name String? @db.VarChar(200) - memo String? @db.VarChar(500) - created_at DateTime @default(now(), map: "DF__MS_SUITAB__creat__571DF1D5") - updated_at DateTime? - MS_SUITABLE_MAIN MS_SUITABLE_MAIN @relation(fields: [main_id], references: [id], onUpdate: NoAction, map: "MS_SUITABLE_DETAIL_MS_SUITABLE_MAIN_FK") + ID Int @id @default(autoincrement()) + MAIN_ID Int + TRESTLE_MANUFACTURER_PRODUCT_CODE String? @db.VarChar(200) + TRESTLE_MANUFACTURER_PRODUCT_NAME String? @db.VarChar(200) + MEMO String? @db.VarChar(500) + REG_DT DateTime @default(now(), map: "DF__MS_SUITAB__creat__571DF1D5") + UPT_DT DateTime? + MS_SUITABLE_MAIN MS_SUITABLE_MAIN @relation(fields: [MAIN_ID], references: [ID], onUpdate: NoAction, map: "MS_SUITABLE_DETAIL_MS_SUITABLE_MAIN_FK") } model MS_SUITABLE_MAIN { - id Int @id @default(autoincrement()) - product_name String @db.VarChar(200) - manufacturer String? @db.VarChar(200) - roof_material String? @db.VarChar(100) - shape String? @db.VarChar(200) - created_at DateTime @default(now(), map: "DF__MS_SUITAB__creat__5441852A") - updated_at DateTime? @updatedAt - details MS_SUITABLE_DETAIL[] + ID Int @id @default(autoincrement()) + PRODUCT_NAME String @db.VarChar(200) + MANUFACTURER String? @db.VarChar(200) + ROOT_MATERIAL String? @db.VarChar(100) + SHAPE String? @db.VarChar(200) + REG_DT DateTime @default(now(), map: "DF__MS_SUITAB__creat__5441852A") + UPT_DT DateTime? + MS_SUITABLE_DETAIL MS_SUITABLE_DETAIL[] } From 9f4c3de2cf16f8e563b983b77bc27605cab1bef9 Mon Sep 17 00:00:00 2001 From: Daseul Kim Date: Tue, 13 May 2025 11:00:20 +0900 Subject: [PATCH 11/12] =?UTF-8?q?refactor:=20=EC=A7=80=EB=B6=95=EC=9E=AC?= =?UTF-8?q?=20=EC=A0=81=ED=95=A9=EC=84=B1=20=ED=85=8C=EC=9D=B4=EB=B8=94=20?= =?UTF-8?q?=EC=BB=AC=EB=9F=BC=EB=AA=85=20=EA=B3=B5=ED=86=B5=EC=BD=94?= =?UTF-8?q?=EB=93=9C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- prisma/schema.prisma | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 3cc1c4c..296042d 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -181,7 +181,7 @@ model BC_COMM_L { model MS_SUITABLE_ROOF_MATERIAL_GROUP { ID Int @id @default(autoincrement()) ROOF_MATERIAL_GROUP String @db.VarChar(200) - ROOF_MATERIAL String @db.VarChar(200) + ROOF_MT_CD String @db.VarChar(200) REG_DT DateTime @default(now(), map: "DF__MS_SUITAB__creat__4F7CD00D") UPT_DT DateTime } @@ -189,7 +189,7 @@ model MS_SUITABLE_ROOF_MATERIAL_GROUP { model MS_SUITABLE_DETAIL { ID Int @id @default(autoincrement()) MAIN_ID Int - TRESTLE_MANUFACTURER_PRODUCT_CODE String? @db.VarChar(200) + TRESTLE_MFPC_CD String? @db.VarChar(200) TRESTLE_MANUFACTURER_PRODUCT_NAME String? @db.VarChar(200) MEMO String? @db.VarChar(500) REG_DT DateTime @default(now(), map: "DF__MS_SUITAB__creat__571DF1D5") @@ -200,9 +200,9 @@ model MS_SUITABLE_DETAIL { model MS_SUITABLE_MAIN { ID Int @id @default(autoincrement()) PRODUCT_NAME String @db.VarChar(200) - MANUFACTURER String? @db.VarChar(200) - ROOT_MATERIAL String? @db.VarChar(100) - SHAPE String? @db.VarChar(200) + MANU_FT_CD String? @db.VarChar(200) + ROOF_MT_CD String? @db.VarChar(100) + ROOF_SH_CD String? @db.VarChar(200) REG_DT DateTime @default(now(), map: "DF__MS_SUITAB__creat__5441852A") UPT_DT DateTime? MS_SUITABLE_DETAIL MS_SUITABLE_DETAIL[] From e5affe0df5853f65b860263cafc64ae63fe6c13d Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Tue, 13 May 2025 13:28:46 +0900 Subject: [PATCH 12/12] chore: update environment variables and dependencies; add database configuration for QPARTNER login --- .env.development | 9 +++- .env.production | 9 +++- package.json | 4 +- pnpm-lock.yaml | 78 ++++++++++++++--------------- prisma/schema.prisma | 114 +++++++++++++++++++++---------------------- 5 files changed, 114 insertions(+), 100 deletions(-) diff --git a/.env.development b/.env.development index 9d7881a..75df0fa 100644 --- a/.env.development +++ b/.env.development @@ -7,4 +7,11 @@ NEXT_PUBLIC_API_URL=http://localhost: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 \ No newline at end of file +NEXT_PUBLIC_INQUIRY_API_URL=http://1.248.227.176:38080 + +#QPARTNER ๋กœ๊ทธ์ธ api +DB_HOST=asdf +DB_USER=asdf +DB_PASSWORD=asdf +DB_DATABASE=asdf +DB_PORT=3306 \ No newline at end of file diff --git a/.env.production b/.env.production index 3d04f51..e1a6d43 100644 --- a/.env.production +++ b/.env.production @@ -5,4 +5,11 @@ NEXT_PUBLIC_API_URL=http://172.30.1.35: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 \ No newline at end of file +NEXT_PUBLIC_INQUIRY_API_URL=http://1.248.227.176:38080 + +#QPARTNER ๋กœ๊ทธ์ธ api +DB_HOST=asdf +DB_USER=asdf +DB_PASSWORD=asdf +DB_DATABASE=asdf +DB_PORT=3306 \ No newline at end of file diff --git a/package.json b/package.json index 61c7e67..7d5da52 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "lint": "next lint" }, "dependencies": { - "@prisma/client": "^6.5.0", + "@prisma/client": "^6.7.0", "@tanstack/react-query": "^5.71.0", "@tanstack/react-query-devtools": "^5.71.0", "axios": "^1.8.4", @@ -28,7 +28,7 @@ "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", - "prisma": "^6.5.0", + "prisma": "^6.7.0", "tailwindcss": "^4", "typescript": "^5" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 08d920f..9ebc4c8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@prisma/client': - specifier: ^6.5.0 - version: 6.5.0(prisma@6.5.0(typescript@5.8.2))(typescript@5.8.2) + specifier: ^6.7.0 + version: 6.7.0(prisma@6.7.0(typescript@5.8.2))(typescript@5.8.2) '@tanstack/react-query': specifier: ^5.71.0 version: 5.71.0(react@19.1.0) @@ -61,8 +61,8 @@ importers: specifier: ^19 version: 19.0.4(@types/react@19.0.12) prisma: - specifier: ^6.5.0 - version: 6.5.0(typescript@5.8.2) + specifier: ^6.7.0 + version: 6.7.0(typescript@5.8.2) tailwindcss: specifier: ^4 version: 4.0.17 @@ -538,8 +538,8 @@ packages: resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} engines: {node: '>= 10.0.0'} - '@prisma/client@6.5.0': - resolution: {integrity: sha512-M6w1Ql/BeiGoZmhMdAZUXHu5sz5HubyVcKukbLs3l0ELcQb8hTUJxtGEChhv4SVJ0QJlwtLnwOLgIRQhpsm9dw==} + '@prisma/client@6.7.0': + resolution: {integrity: sha512-+k61zZn1XHjbZul8q6TdQLpuI/cvyfil87zqK2zpreNIXyXtpUv3+H/oM69hcsFcZXaokHJIzPAt5Z8C8eK2QA==} engines: {node: '>=18.18'} peerDependencies: prisma: '*' @@ -550,23 +550,23 @@ packages: typescript: optional: true - '@prisma/config@6.5.0': - resolution: {integrity: sha512-sOH/2Go9Zer67DNFLZk6pYOHj+rumSb0VILgltkoxOjYnlLqUpHPAN826vnx8HigqnOCxj9LRhT6U7uLiIIWgw==} + '@prisma/config@6.7.0': + resolution: {integrity: sha512-di8QDdvSz7DLUi3OOcCHSwxRNeW7jtGRUD2+Z3SdNE3A+pPiNT8WgUJoUyOwJmUr5t+JA2W15P78C/N+8RXrOA==} - '@prisma/debug@6.5.0': - resolution: {integrity: sha512-fc/nusYBlJMzDmDepdUtH9aBsJrda2JNErP9AzuHbgUEQY0/9zQYZdNlXmKoIWENtio+qarPNe/+DQtrX5kMcQ==} + '@prisma/debug@6.7.0': + resolution: {integrity: sha512-RabHn9emKoYFsv99RLxvfG2GHzWk2ZI1BuVzqYtmMSIcuGboHY5uFt3Q3boOREM9de6z5s3bQoyKeWnq8Fz22w==} - '@prisma/engines-version@6.5.0-73.173f8d54f8d52e692c7e27e72a88314ec7aeff60': - resolution: {integrity: sha512-iK3EmiVGFDCmXjSpdsKGNqy9hOdLnvYBrJB61far/oP03hlIxrb04OWmDjNTwtmZ3UZdA5MCvI+f+3k2jPTflQ==} + '@prisma/engines-version@6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed': + resolution: {integrity: sha512-EvpOFEWf1KkJpDsBCrih0kg3HdHuaCnXmMn7XFPObpFTzagK1N0Q0FMnYPsEhvARfANP5Ok11QyoTIRA2hgJTA==} - '@prisma/engines@6.5.0': - resolution: {integrity: sha512-FVPQYHgOllJklN9DUyujXvh3hFJCY0NX86sDmBErLvoZjy2OXGiZ5FNf3J/C4/RZZmCypZBYpBKEhx7b7rEsdw==} + '@prisma/engines@6.7.0': + resolution: {integrity: sha512-3wDMesnOxPrOsq++e5oKV9LmIiEazFTRFZrlULDQ8fxdub5w4NgRBoxtWbvXmj2nJVCnzuz6eFix3OhIqsZ1jw==} - '@prisma/fetch-engine@6.5.0': - resolution: {integrity: sha512-3LhYA+FXP6pqY8FLHCjewyE8pGXXJ7BxZw2rhPq+CZAhvflVzq4K8Qly3OrmOkn6wGlz79nyLQdknyCG2HBTuA==} + '@prisma/fetch-engine@6.7.0': + resolution: {integrity: sha512-zLlAGnrkmioPKJR4Yf7NfW3hftcvqeNNEHleMZK9yX7RZSkhmxacAYyfGsCcqRt47jiZ7RKdgE0Wh2fWnm7WsQ==} - '@prisma/get-platform@6.5.0': - resolution: {integrity: sha512-xYcvyJwNMg2eDptBYFqFLUCfgi+wZLcj6HDMsj0Qw0irvauG4IKmkbywnqwok0B+k+W+p+jThM2DKTSmoPCkzw==} + '@prisma/get-platform@6.7.0': + resolution: {integrity: sha512-i9IH5lO4fQwnMLvQLYNdgVh9TK3PuWBfQd7QLk/YurnAIg+VeADcZDbmhAi4XBBDD+hDif9hrKyASu0hbjwabw==} '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} @@ -1181,8 +1181,8 @@ packages: resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} engines: {node: ^10 || ^12 || >=14} - prisma@6.5.0: - resolution: {integrity: sha512-yUGXmWqv5F4PByMSNbYFxke/WbnyTLjnJ5bKr8fLkcnY7U5rU9rUTh/+Fja+gOrRxEgtCbCtca94IeITj4j/pg==} + prisma@6.7.0: + resolution: {integrity: sha512-vArg+4UqnQ13CVhc2WUosemwh6hr6cr6FY2uzDvCIFwH8pu8BXVv38PktoMLVjtX7sbYThxbnZF5YiR8sN2clw==} engines: {node: '>=18.18'} hasBin: true peerDependencies: @@ -1754,38 +1754,38 @@ snapshots: '@parcel/watcher-win32-x64': 2.5.1 optional: true - '@prisma/client@6.5.0(prisma@6.5.0(typescript@5.8.2))(typescript@5.8.2)': + '@prisma/client@6.7.0(prisma@6.7.0(typescript@5.8.2))(typescript@5.8.2)': optionalDependencies: - prisma: 6.5.0(typescript@5.8.2) + prisma: 6.7.0(typescript@5.8.2) typescript: 5.8.2 - '@prisma/config@6.5.0': + '@prisma/config@6.7.0': dependencies: esbuild: 0.25.2 esbuild-register: 3.6.0(esbuild@0.25.2) transitivePeerDependencies: - supports-color - '@prisma/debug@6.5.0': {} + '@prisma/debug@6.7.0': {} - '@prisma/engines-version@6.5.0-73.173f8d54f8d52e692c7e27e72a88314ec7aeff60': {} + '@prisma/engines-version@6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed': {} - '@prisma/engines@6.5.0': + '@prisma/engines@6.7.0': dependencies: - '@prisma/debug': 6.5.0 - '@prisma/engines-version': 6.5.0-73.173f8d54f8d52e692c7e27e72a88314ec7aeff60 - '@prisma/fetch-engine': 6.5.0 - '@prisma/get-platform': 6.5.0 + '@prisma/debug': 6.7.0 + '@prisma/engines-version': 6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed + '@prisma/fetch-engine': 6.7.0 + '@prisma/get-platform': 6.7.0 - '@prisma/fetch-engine@6.5.0': + '@prisma/fetch-engine@6.7.0': dependencies: - '@prisma/debug': 6.5.0 - '@prisma/engines-version': 6.5.0-73.173f8d54f8d52e692c7e27e72a88314ec7aeff60 - '@prisma/get-platform': 6.5.0 + '@prisma/debug': 6.7.0 + '@prisma/engines-version': 6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed + '@prisma/get-platform': 6.7.0 - '@prisma/get-platform@6.5.0': + '@prisma/get-platform@6.7.0': dependencies: - '@prisma/debug': 6.5.0 + '@prisma/debug': 6.7.0 '@swc/counter@0.1.3': {} @@ -2413,10 +2413,10 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - prisma@6.5.0(typescript@5.8.2): + prisma@6.7.0(typescript@5.8.2): dependencies: - '@prisma/config': 6.5.0 - '@prisma/engines': 6.5.0 + '@prisma/config': 6.7.0 + '@prisma/engines': 6.7.0 optionalDependencies: fsevents: 2.3.3 typescript: 5.8.2 diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 296042d..7996ce0 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -57,65 +57,65 @@ model MS_SUITABLE { updated_at DateTime @updatedAt } -model SD_SERVEY_SALES_BASIC_INFO { - id Int @id @default(autoincrement()) - representative String @db.VarChar(200) - store String? @db.VarChar(200) - construction_point String? @db.VarChar(200) - investigation_date String? @db.VarChar(10) - building_name String? @db.VarChar(200) - customer_name String? @db.VarChar(200) - post_code String? @db.VarChar(10) - address String? @db.VarChar(200) - address_detail String? @db.VarChar(300) - submission_status Boolean @default(false) - submission_date DateTime? @db.Date - created_at DateTime @default(now()) - updated_at DateTime @updatedAt - detail_info SD_SERVEY_SALES_DETAIL_INFO? +model SD_SURVEY_SALES_BASIC_INFO { + ID Int @id @default(autoincrement()) + REPRESENTATIVE String @db.VarChar(200) + STORE String? @db.VarChar(200) + CONSTRUCTION_POINT String? @db.VarChar(200) + INVESTIGATION_DATE String? @db.VarChar(10) + BUILDING_NAME String? @db.VarChar(200) + CUSTOMER_NAME String? @db.VarChar(200) + POST_CODE String? @db.VarChar(10) + ADDRESS String? @db.VarChar(200) + ADDRESS_DETAIL String? @db.VarChar(300) + SUBMISSION_STATUS Boolean @default(false) + SUBMISSION_DATE DateTime? @db.Date + REG_DT DateTime @default(now()) + UPT_DT DateTime @updatedAt + DETAIL_INFO SD_SURVEY_SALES_DETAIL_INFO? } -model SD_SERVEY_SALES_DETAIL_INFO { - id Int @id @default(autoincrement()) - contract_capacity String? @db.VarChar(20) - retail_company String? @db.VarChar(100) - supplementary_facilities String? @db.VarChar(20) - supplementary_facilities_etc String? @db.VarChar(200) - installation_system Int? - installation_system_etc String? @db.VarChar(200) - construction_year Int? - construction_year_etc String? @db.VarChar(200) - roof_material String? @db.VarChar(20) - roof_material_etc String? @db.VarChar(200) - roof_shape Int? - roof_shape_etc String? @db.VarChar(200) - roof_slope String? @db.VarChar(5) - house_structure Int? - house_structure_etc String? @db.VarChar(200) - rafter_material Int? - rafter_material_etc String? @db.VarChar(200) - rafter_size Int? - rafter_size_etc String? @db.VarChar(200) - rafter_pitch Int? - rafter_pitch_etc String? @db.VarChar(200) - rafter_direction Int? - open_field_plate_kind Int? - open_field_plate_kind_etc String? @db.VarChar(200) - open_field_plate_thickness String? @db.VarChar(5) - leak_trace Boolean? @default(false) - waterproof_material Int? - waterproof_material_etc String? @db.VarChar(200) - insulation_presence Int? - insulation_presence_etc String? @db.VarChar(200) - structure_order Int? - structure_order_etc String? @db.VarChar(200) - installation_availability Int? - installation_availability_etc String? @db.VarChar(200) - memo String? @db.VarChar(500) - created_at DateTime @default(now()) - updated_at DateTime @updatedAt - basic_info_id Int @unique - basic_info SD_SERVEY_SALES_BASIC_INFO @relation(fields: [basic_info_id], references: [id]) +model SD_SURVEY_SALES_DETAIL_INFO { + ID Int @id @default(autoincrement()) + CONTRACT_CAPACITY String? @db.VarChar(20) + RETAIL_COMPANY String? @db.VarChar(100) + SUPPLEMENTARY_FACILITIES String? @db.VarChar(20) + SUPPLEMENTARY_FACILITIES_ETC String? @db.VarChar(200) + INSTALLATION_SYSTEM String? @db.VarChar(20) + INSTALLATION_SYSTEM_ETC String? @db.VarChar(200) + CONSTRUCTION_YEAR String? @db.VarChar(200) + CONSTRUCTION_YEAR_ETC String? @db.VarChar(200) + ROOF_MATERIAL String? @db.VarChar(20) + ROOF_MATERIAL_ETC String? @db.VarChar(200) + ROOF_SHAPE String? @db.VarChar(20) + ROOF_SHAPE_ETC String? @db.VarChar(200) + ROOF_SLOPE String? @db.VarChar(5) + HOUSE_STRUCTURE String? @db.VarChar(20) + HOUSE_STRUCTURE_ETC String? @db.VarChar(200) + RAFTER_MATERIAL String? @db.VarChar(20) + RAFTER_MATERIAL_ETC String? @db.VarChar(200) + RAFTER_SIZE String? @db.VarChar(20) + RAFTER_SIZE_ETC String? @db.VarChar(200) + RAFTER_PITCH String? @db.VarChar(20) + RAFTER_PITCH_ETC String? @db.VarChar(200) + RAFTER_DIRECTION String? @db.VarChar(20) + OPEN_FIELD_PLATE_KIND String? @db.VarChar(20) + OPEN_FIELD_PLATE_KIND_ETC String? @db.VarChar(200) + OPEN_FIELD_PLATE_THICKNESS String? @db.VarChar(5) + LEAK_TRACE Boolean? @default(false) + WATERPROOF_MATERIAL String? @db.VarChar(20) + WATERPROOF_MATERIAL_ETC String? @db.VarChar(200) + INSULATION_PRESENCE String? @db.VarChar(20) + INSULATION_PRESENCE_ETC String? @db.VarChar(200) + STRUCTURE_ORDER String? @db.VarChar(20) + STRUCTURE_ORDER_ETC String? @db.VarChar(200) + INSTALLATION_AVAILABILITY String? @db.VarChar(20) + INSTALLATION_AVAILABILITY_ETC String? @db.VarChar(200) + MEMO String? @db.VarChar(500) + REG_DT DateTime @default(now()) + UPT_DT DateTime @updatedAt + BASIC_INFO_ID Int @unique + BASIC_INFO SD_SURVEY_SALES_BASIC_INFO @relation(fields: [BASIC_INFO_ID], references: [ID]) } model BC_COMM_H {