From 2ba72f1142a3512367ec69863c532e66e7c8e5b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=B0=BD=EC=88=98?= Date: Thu, 5 Jun 2025 18:04:53 +0900 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20suitablepdf=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/pdf/SuitablePdf.tsx | 170 +++++++++++++++++++++-------- 1 file changed, 126 insertions(+), 44 deletions(-) diff --git a/src/components/pdf/SuitablePdf.tsx b/src/components/pdf/SuitablePdf.tsx index e27a31f..e82c1e9 100644 --- a/src/components/pdf/SuitablePdf.tsx +++ b/src/components/pdf/SuitablePdf.tsx @@ -10,45 +10,127 @@ Font.register({ const styles = StyleSheet.create({ page: { - padding: 30, - fontSize: 10, + maxWidth: 840, + minWidth: 840, + margin: '0 auto', + padding: 20, fontFamily: 'NotoSansJP', }, - text: { + introPage: { + height: 550, + padding: '60 20', + }, + introTitWrap: { + textAlign: 'center', + marginBottom: 70, + }, + introTit: { + fontSize: 18, + fontWeight: 500, + color: '#101010', fontFamily: 'NotoSansJP', + marginBottom: 20, + }, + introDate: { + fontSize: 16, + fontWeight: 400, + color: '#101010', + fontFamily: 'NotoSansJP', + }, + introContText: { + fontSize: 13, + fontWeight: 400, + color: '#101010', + fontFamily: 'NotoSansJP', + }, + tableGridWrap: { + display: 'flex', + flexWrap: 'wrap', + flexDirection: 'row', + gap: 20 + }, + tableCard:{ + width: '48.7%', + }, + tableTitWrap: { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + marginBottom: 5, + }, + tableTit:{ + fontSize: 8, + fontWeight: 500, + fontFamily: 'NotoSansJP', + color: '#101010', + }, + tableTit01: { + paddingRight: 6, + borderRight: '1px solid #101010' + }, + tableTit02: { + padding: '0 6', + borderRight: '1px solid #101010' + }, + tableTit03: { + paddingLeft: 6, }, table: { display: 'flex', - width: 'auto', - borderStyle: 'solid', - borderWidth: 1, - borderColor: '#000', + width: '100%', }, tableRow: { flexDirection: 'row', }, - tableColHeader: { - width: '25%', - borderStyle: 'solid', - borderWidth: 1, - backgroundColor: '#f0f0f0', - padding: 2, + tableCol01: { + width: '18%', }, - tableCol: { - width: '25%', - borderStyle: 'solid', - borderWidth: 1, - padding: 2, + tableCol02: { + width: '23%', + }, + tableCol03: { + width: '18%', + }, + tableCol04: { + width: '41%', + }, + tableTh: { + fontSize: 5, + fontWeight: 500, + color: '#fff', + backgroundColor: '#18B490', + border: '1px solid #18B490', + textAlign: 'center' + }, + tableTd: { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + fontSize: 5, + fontWeight: 300, + color: '#101010', + backgroundColor: '#fff', + border: '1px solid #CBCBCB', + padding: 3, + }, + marginL:{ + marginLeft: -1, + }, + marginT:{ + marginTop: -1, }, footer: { position: 'absolute', - bottom: 30, + bottom: 5, left: 30, right: 30, }, footerDate: { - fontSize: 10, + fontSize: 7, textAlign: 'right', + fontFamily: 'NotoSansJP', + fontWeight: 400, + color: '#101010', }, }) @@ -70,52 +152,52 @@ export default function SuitablePdf({ data, fileTitle, firstPage }: { data: Suit {/* Intro Section */} {firstPage && ( - - - ハンファジャパン株式会社 - {fileTitle} - {createTime} + + + ハンファジャパン株式会社 + {fileTitle} + {createTime} - 本適合表は参考資料としてご使用下さい。 - 屋根材製品の形状・仕様はメーカーより変更される場合が御座います。 - + 本適合表は参考資料としてご使用下さい。 + 屋根材製品の形状・仕様はメーカーより変更される場合が御座います。 + 又、現場環境(働き、勾配、瓦桟木条件等)により本適合表と異なる適合結果となる場合が御座います。予めご了承下さい。 - 屋根材以外の設置条件(垂木、野地板等の設置基準)も必ずご確認下さい。 + 屋根材以外の設置条件(垂木、野地板等の設置基準)も必ずご確認下さい。 )} - + {/* Cards Section */} {data?.map((item: Suitable) => ( - + {/* Table Title */} - - {item.productName} - {item.manuFtCd} - {item.roofMtCd} + + {item.productName} + {item.manuFtCd} + {item.roofMtCd} {/* Table */} {/* Table Header */} - 金具タイプ - 金具名 - 設置可否 - 備考 + 金具タイプ + 金具名 + 設置可否 + 備考 {/* Table Body */} {JSON.parse(item.detail)?.map((subItem: SuitableDetail) => ( - {item.roofShCd} - {subItem.trestleMfpcCd} - {subItem.trestleManufacturerProductName} - {subItem.memo} + {item.roofShCd} + {subItem.trestleMfpcCd} + {subItem.trestleManufacturerProductName} + {subItem.memo} ))} @@ -126,7 +208,7 @@ export default function SuitablePdf({ data, fileTitle, firstPage }: { data: Suit {/* Footer */} - {createTime} + {createTime} ) From 5cd9eb6ca26fc61e5090defee67ccd1edf220fd7 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Thu, 5 Jun 2025 18:16:22 +0900 Subject: [PATCH 2/2] remove: delete unused API files for auth, suitable, surveySales, and user --- README.md | 12 +++- src/api/auth.ts | 22 ------- src/api/suitable.ts | 107 ---------------------------------- src/api/surveySales.ts | 127 ----------------------------------------- src/api/user.ts | 37 ------------ 5 files changed, 10 insertions(+), 295 deletions(-) delete mode 100644 src/api/auth.ts delete mode 100644 src/api/suitable.ts delete mode 100644 src/api/surveySales.ts delete mode 100644 src/api/user.ts diff --git a/README.md b/README.md index fda8464..f1e889e 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Next.js와 TypeScript로 구축된 현장 조사용 모바일 애플리케이션 ### 필수 요구사항 -- Node.js (LTS 버전) +- Node.js (LTS 버전) 22.16.0 권장 - npm 또는 yarn 또는 pnpm 또는 burn - Prisma CLI @@ -52,7 +52,9 @@ npm start ## 프로젝트 구조 -[프로젝트 구조 Diagram](./diagram/mermaid.md) +[컴포넌트 간 관계 Diagram](./diagram/mermaid.md) + +[페이지 컴포넌트 간 관례 Diagram](./diagram/mermaid3.md) ``` ├── app/ # Next.js 앱 디렉토리 @@ -63,6 +65,12 @@ npm start └── public/ # 정적 자산 ``` +## 로그인 + +[로그인 Sequence Diagram](./diagram/mermaid2.md) + +[로그인 컴포넌트 Diagram](./diagram/Login.md) + ## 참고 ### prisma 연결 diff --git a/src/api/auth.ts b/src/api/auth.ts deleted file mode 100644 index 00a415e..0000000 --- a/src/api/auth.ts +++ /dev/null @@ -1,22 +0,0 @@ -'use server' - -import { sessionOptions } from '@/libs/session' -import type { SessionData } from '@/types/Auth' -import { getIronSession } from 'iron-session' -import { cookies } from 'next/headers' -import { redirect } from 'next/navigation' - -export const logout = async () => { - const cookieStore = await cookies() - const session = await getIronSession(cookieStore, sessionOptions) - - session.destroy() - return redirect('/login') -} - -export const getSession = async () => { - const cookieStore = await cookies() - const session = await getIronSession(cookieStore, sessionOptions) - - return session -} diff --git a/src/api/suitable.ts b/src/api/suitable.ts deleted file mode 100644 index 952f956..0000000 --- a/src/api/suitable.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { database } from '@/data' -import { axiosInstance } from '@/libs/axios' - -export interface Suitable { - id?: number - product_name: string - manufacturer: string - roof_material: string - shape: string - support_roof_tile: string - support_roof_tile_memo: string - support_roof_bracket: string - support_roof_bracket_memo: string - yg_anchor: string - yg_anchor_memo: string - rg_roof_tile_part: string - rg_roof_tile_part_memo: string - dido_hunt_support_tile_2: string - dido_hunt_support_tile_2_memo: string - takashima_power_base: string - takashima_power_base_memo: string - takashima_tile_bracket: string - takashima_tile_bracket_memo: string - slate_bracket_4: string - slate_bracket_4_memo: string - slate_single_metal_bracket: string - slate_single_metal_bracket_memo: string - dido_hunt_short_rack_4: string - dido_hunt_short_rack_4_memo: string - takashima_slate_bracket_slate_single: string - takashima_slate_bracket_slate_single_memo: string - df_metal_bracket: string - df_metal_bracket_memo: string - slate_metal_bracket: string - slate_metal_bracket_memo: string - takashima_slate_bracket_metal_roof: string - takashima_slate_bracket_metal_roof_memo: string -} - -export const suitableApi = { - // 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(null).get('/api/suitable/list', { params: condition }) - // console.log('🚀 ~ getList: ~ response:', response) - // return response.data - // }, - // getCategory: async (): Promise => { - // const response = await axiosInstance(null).get('/api/suitable/category') - // console.log('🚀 ~ getCategory: ~ response:', response) - // return response.data - // }, - // getDetails: async (roofMaterial: string): Promise => { - // const response = await axiosInstance(null).get(`/api/suitable/details?roof-material=${roofMaterial}`) - // console.log('🚀 ~ getDetails: ~ response:', response) - // return response.data - // }, - // create: async () => { - // const suitableData: Suitable[] = [] - // database.forEach((item) => { - // suitableData.push({ - // product_name: item[0], - // manufacturer: item[1], - // roof_material: item[2], - // shape: item[3], - // support_roof_tile: item[4], - // support_roof_tile_memo: item[5], - // support_roof_bracket: item[6], - // support_roof_bracket_memo: item[7], - // yg_anchor: item[8], - // yg_anchor_memo: item[9], - // rg_roof_tile_part: item[10], - // rg_roof_tile_part_memo: item[11], - // dido_hunt_support_tile_2: item[12], - // dido_hunt_support_tile_2_memo: item[13], - // takashima_power_base: item[14], - // takashima_power_base_memo: item[15], - // takashima_tile_bracket: item[16], - // takashima_tile_bracket_memo: item[17], - // slate_bracket_4: item[18], - // slate_bracket_4_memo: item[19], - // slate_single_metal_bracket: item[20], - // slate_single_metal_bracket_memo: item[21], - // dido_hunt_short_rack_4: item[22], - // dido_hunt_short_rack_4_memo: item[23], - // takashima_slate_bracket_slate_single: item[24], - // takashima_slate_bracket_slate_single_memo: item[25], - // df_metal_bracket: item[26], - // df_metal_bracket_memo: item[27], - // slate_metal_bracket: item[28], - // slate_metal_bracket_memo: item[29], - // takashima_slate_bracket_metal_roof: item[30], - // takashima_slate_bracket_metal_roof_memo: item[31], - // }) - // }) - // const response = await axiosInstance(null).post('/api/suitable', suitableData) - // return response.data - // }, -} diff --git a/src/api/surveySales.ts b/src/api/surveySales.ts deleted file mode 100644 index b17f053..0000000 --- a/src/api/surveySales.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { axiosInstance } from '@/libs/axios' - -export interface SurveySalesBasicInfo { - id?: number - representative: string - store: string | null - construction_point: string | null - investigation_date: string | null - building_name: string | null - customer_name: string | null - post_code: string | null - address: string | null - address_detail: string | null - submission_status: boolean - submission_date?: string | null - detail_info?: SurveySalesDetailInfo | null -} - -export interface SurveySalesDetailInfo { - id?: number - contract_capacity: string | null - retail_company: string | null - supplementary_facilities: number | null - supplementary_facilities_etc: string | null - installation_system: number | null - installation_system_etc: string | null - construction_year: number | null - construction_year_etc: string | null - roof_material: number | null - roof_material_etc: string | null - roof_shape: number | null - roof_shape_etc: string | null - roof_slope: string | null - house_structure: number | null - house_structure_etc: string | null - rafter_material: number | null - rafter_material_etc: string | null - rafter_size: number | null - rafter_size_etc: string | null - rafter_pitch: number | null - rafter_pitch_etc: string | null - rafter_direction: number | null - open_field_plate_kind: number | null - open_field_plate_kind_etc: string | null - open_field_plate_thickness: string | null - leak_trace: boolean | null - waterproof_material: number | null - waterproof_material_etc: string | null - insulation_presence: number | null - insulation_presence_etc: string | null - structure_order: number | null - structure_order_etc: string | null - installation_availability: number | null - installation_availability_etc: string | null - memo: string | null -} - -export const surveySalesApi = { - create: async (data: SurveySalesBasicInfo): Promise => { - try { - const response = await axiosInstance(null).post('/api/survey-sales', data) - return response.data.id ?? 0 - } catch (error) { - console.error(error) - return 0 - } - }, - getList: async (): Promise => { - try { - const response = await axiosInstance(null).get('/api/survey-sales') - return response.data - } catch (error) { - console.error(error) - return [] - } - }, - getDetail: async (id: number): Promise => { - try { - const response = await axiosInstance(null).get(`/api/survey-sales/${id}`) - return response.data - } catch (error) { - console.error(error) - return null - } - }, - update: async (id: number, data: SurveySalesBasicInfo): Promise => { - try { - const response = await axiosInstance(null).put(`/api/survey-sales/${id}`, data) - return response.data - } catch (error) { - console.error(error) - return null - } - }, - delete: async (id: number, isDetail: boolean = false): Promise => { - try { - await axiosInstance(null).delete(`/api/survey-sales/${id}`, { - params: { - detail_id: isDetail ? id : undefined, - }, - }) - return true - } catch (error) { - throw error - } - }, - createDetail: async (surveyId: number, data: SurveySalesDetailInfo): Promise => { - try { - await axiosInstance(null).post(`/api/survey-sales/${surveyId}`, data) - return true - } catch (error) { - throw error - } - }, - confirm: async (id: number): Promise => { - try { - await axiosInstance(null).patch(`/api/survey-sales/${id}`) - return true - } catch (error) { - throw error - } - }, - // update: async (data: SurveySalesBasicInfo): Promise => { - // const response = await axiosInstance.put(`/api/survey-sales`, data) - // return response.data - // }, -} diff --git a/src/api/user.ts b/src/api/user.ts deleted file mode 100644 index 6b39cf0..0000000 --- a/src/api/user.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { axiosInstance } from '@/libs/axios' - -export interface UserData { - username: string - email: string - password: string -} - -export interface User { - id: number - username: string - email: string - created_at: string - updated_at: string -} - -export interface LoginData { - username: string - password: string -} - -export const userApi = { - create: async (data: UserData): Promise => { - const response = await axiosInstance(null).post('/api/user/create', data) - return response.data - }, - - getList: async (): Promise => { - const response = await axiosInstance(null).get('/api/user/list') - return response.data - }, - - getUser: async (data: LoginData): Promise => { - const response = await axiosInstance(null).post(`/api/user`, data) - return response.data - }, -}