From d18c97c992212ef7f1b8ccb9451440637ac7ff79 Mon Sep 17 00:00:00 2001
From: chpark <chpark@gdnsi.com>
Date: Mon, 6 Jan 2025 14:31:54 +0900
Subject: [PATCH] =?UTF-8?q?=EA=B3=B5=ED=86=B5=20=EC=85=80=EB=A0=89?=
 =?UTF-8?q?=ED=8A=B8=20=EB=B0=95=EC=8A=A4=20=EB=B0=98=EC=98=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../app/common/common.controller.js           | 11 +++
 plm-api/src/services/common.service.js        | 31 +++++--
 .../common/product/components/ProductForm.tsx | 80 +++++++++++++++++--
 .../src/app/(admin)/common/product/page.tsx   | 20 ++++-
 4 files changed, 127 insertions(+), 15 deletions(-)

diff --git a/plm-api/src/controllers/app/common/common.controller.js b/plm-api/src/controllers/app/common/common.controller.js
index 73898c4..ee51309 100644
--- a/plm-api/src/controllers/app/common/common.controller.js
+++ b/plm-api/src/controllers/app/common/common.controller.js
@@ -137,5 +137,16 @@ router.patch("/codes/:id/active", async (req, res, next) => {
 });
 //////========================================공통코드==============================================//////
 
+// 공통 셀렉트 박스 데이터를 가져오기 위한 엔드포인트
+router.get("/select-options", async (req, res, next) => {
+  try {
+    const { modelName, orderField } = req.query;
+    //가져올 모델명(테이블) 과 sorting 할 필드를 전달 
+    const options = await CommonService.getSelectOptions(modelName, orderField);
+    res.json(options);
+  } catch (error) {
+    next(error);
+  }
+});
 
 module.exports = router;
\ No newline at end of file
diff --git a/plm-api/src/services/common.service.js b/plm-api/src/services/common.service.js
index 4b43891..0b3cdfa 100644
--- a/plm-api/src/services/common.service.js
+++ b/plm-api/src/services/common.service.js
@@ -1,7 +1,4 @@
-const {
-  MenuInfo,
-  CommCode,
-} = require("../models");
+const { MenuInfo, CommCode, ProductGroup, sequelize } = require("../models"); // sequelize 임포트 추가
 const { Op } = require("sequelize");
 
 
@@ -218,6 +215,28 @@ const toggleCodeActive = async (id, isActive) => {
     throw error;
   }
 };
+
+// 공통 셀렉트 박스 데이터를 가져오기 위한 함수
+const getSelectOptions = async (modelName, orderField = 'name') => {
+  try {
+    const model = sequelize.models[modelName]; // 동적으로 모델 참조
+    if (!model) {
+      throw new Error('Invalid model name');
+    }
+
+    const options = await model.findAll({
+      order: [[orderField, 'ASC']],
+      raw: true,
+    });
+
+    return {
+      success: true,
+      data: options,
+    };
+  } catch (error) {
+    throw error;
+  }
+};
 //////========================================공통코드==============================================//////
 
 module.exports = {
@@ -228,5 +247,7 @@ module.exports = {
   getCodes,
   saveCode, 
   deleteCode,
-  toggleCodeActive
+  toggleCodeActive,
+  getProductGroups,
+  getSelectOptions, // getSelectOptions 함수 추가
 };
\ No newline at end of file
diff --git a/plm-app/src/app/(admin)/common/product/components/ProductForm.tsx b/plm-app/src/app/(admin)/common/product/components/ProductForm.tsx
index 2da0729..9947266 100644
--- a/plm-app/src/app/(admin)/common/product/components/ProductForm.tsx
+++ b/plm-app/src/app/(admin)/common/product/components/ProductForm.tsx
@@ -1,9 +1,9 @@
-import React from "react";
+import React, { useEffect, useState } from "react";
 import { useForm } from "react-hook-form";
 import { Button } from "@/components/ui/button";
 import { Input } from "@/components/ui/input";
 import { Switch } from "@/components/ui/switch";
-import { product} from "@/types/common/product/product";
+import { product } from "@/types/common/product/product";
 import {
   Form,
   FormControl,
@@ -12,6 +12,8 @@ import {
   FormLabel,
   FormMessage,
 } from "@/components/ui/form";
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; // Select 컴포넌트 임포트 추가
+import { api } from "@/lib/api"; // API 호출을 위한 임포트 추가
 
 interface ProductFormProps {
   initialData?: Partial<product>;
@@ -26,6 +28,7 @@ export const ProductForm: React.FC<ProductFormProps> = ({
 }) => {
   const form = useForm({
     defaultValues: {
+      product_group_id: initialData?.product_group_id || "",
       product_code: initialData?.product_code || "",
       product_name: initialData?.product_name || "",
       product_desc: initialData?.product_desc || "",
@@ -33,21 +36,49 @@ export const ProductForm: React.FC<ProductFormProps> = ({
     },
   });
 
+  const [productGroups, setProductGroups] = useState([]);
+
+  useEffect(() => {
+    const fetchSelectOptions = async (modelName, orderField) => {
+      try {
+        const response = await api.get("/api/v1/app/common/select-options", {
+          params: { modelName, orderField },
+        });
+        console.log("Fetched select options:", response.data.data); // 디버깅 로그 추가
+        setProductGroups(response.data.data);
+      } catch (error) {
+        console.error("Failed to fetch select options:", error);
+      }
+    };
+
+    fetchSelectOptions("ProductGroup", "product_group_name");
+  }, []);
+
   return (
     <Form {...form}>
       <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
         <FormField
           control={form.control}
-          name="product_name"
+          name="product_group_id"
           validation={{
             required: "제품군은 필수 입력값입니다",
-            maxLength: { value: 100, message: "최대 100자까지 입력 가능합니다" }
           }}
           render={({ field }) => (
             <FormItem>
               <FormLabel>제품군</FormLabel>
               <FormControl>
-                <Input {...field} />
+                <Select onValueChange={field.onChange} value={field.value}>
+                  <SelectTrigger>
+                    <SelectValue placeholder="제품군을 선택하세요" />
+                  </SelectTrigger>
+                  <SelectContent>
+                    {productGroups.map((group) => (
+                      <SelectItem key={group.id} value={group.id}>
+                        {group.product_group_name}
+                      </SelectItem>
+                    ))}
+                  </SelectContent>
+                </Select>
               </FormControl>
               <FormMessage />
             </FormItem>
@@ -56,10 +87,44 @@ export const ProductForm: React.FC<ProductFormProps> = ({
         
         <FormField
           control={form.control}
-          name="description"
+          name="product_code"
+          validation={{
+            required: "제품코드는 필수 입력값입니다",
+            maxLength: { value: 50, message: "최대 50자까지 입력 가능합니다" }
+          }}
           render={({ field }) => (
             <FormItem>
-              <FormLabel>설명</FormLabel>
+              <FormLabel>제품코드</FormLabel>
+              <FormControl>
+                <Input {...field} />
+              </FormControl>
+              <FormMessage />
+            </FormItem>
+          )}
+        />
+        <FormField
+          control={form.control}
+          name="product_name"
+          validation={{
+            required: "제품명은 필수 입력값입니다",
+            maxLength: { value: 50, message: "최대 50자까지 입력 가능합니다" }
+          }}
+          render={({ field }) => (
+            <FormItem>
+              <FormLabel>제품명</FormLabel>
+              <FormControl>
+                <Input {...field} />
+              </FormControl>
+              <FormMessage />
+            </FormItem>
+          )}
+        />
+        <FormField
+          control={form.control}
+          name="product_desc"
+          render={({ field }) => (
+            <FormItem>
+              <FormLabel>제품내용</FormLabel>
               <FormControl>
                 <Input {...field} />
               </FormControl>
@@ -85,7 +150,6 @@ export const ProductForm: React.FC<ProductFormProps> = ({
             </FormItem>
           )}
         />
-
         <div className="flex justify-end gap-2">
           <Button type="button" variant="outline" onClick={onCancel}>
             취소
diff --git a/plm-app/src/app/(admin)/common/product/page.tsx b/plm-app/src/app/(admin)/common/product/page.tsx
index 6fe2e66..2ad9482 100644
--- a/plm-app/src/app/(admin)/common/product/page.tsx
+++ b/plm-app/src/app/(admin)/common/product/page.tsx
@@ -160,6 +160,22 @@ const ProductPage = () => {
         textAlign: "center",
       },
     },
+    {
+      accessorKey: "ProductGroup.product_group_name",
+      header: "제품군명",
+      meta: {
+        width: "120px",
+        textAlign: "center",
+      },
+    },
+    {
+      accessorKey: "product_code",
+      header: "제품코드",
+      meta: {
+        width: "120px",
+        textAlign: "center",
+      },
+    },
     {
       accessorKey: "product_name",
       header: "제품명",
@@ -169,8 +185,8 @@ const ProductPage = () => {
       },
     },
     {
-      accessorKey: "description",
-      header: "내용",
+      accessorKey: "product_desc",
+      header: "제품내용",
       meta: {
         width: "200px",
         textAlign: "center",