[SI] 프론트엔드 (01_SimpleDMS)

Front-End(리액트)와 Back-End
SI(시스템 통합 연동 실습)

 

Work에

07_SI 폴더 만들고

 

frontend-react-new.zip
3.24MB

다운 받아서 압축풀고

00_NEWUi_React_Template

01_SimpleDMS

폴더에 넣기

Vscode로 실행

src 통합 터미널 열고

(ReadMe.md 파일 따라서 실행)

 

# 설치 패키지 
# 1) 메뉴 라이브러리 설치
npm i react-router-dom

# 2) 벡엔드 연동 라이브러리 설치
npm i axios

# 3) pre css 컴파일러 : node-sass -> 더이상 안씀 : sass 설치할것
<!-- npm i node-sass -->
npm install sass
# 4) Material Page component 업그레이드 
# 과거 v4 -> v5 변경 설치
npm i @mui/material @emotion/react @emotion/styled

# 4-1) 소스에서 임포트 사용법 : <Pagination />
import Pagination from '@mui/material/Pagination';

# 5) typescript jquery, jqueryui type 넣기
# 5-1) typescript jquery 사용
npm i --save-dev @types/jquery

통합터미널

npm start

순서

http-common.ts -> IDept.ts -> App.tsx -> DeptService -> HeaderCom(dept-nop 수정)  -> DeptListNop -> AddDeptNop.tsx -> DeptNop.tsx

http-common.ts

import axios from "axios";

// todo: baseURL: "http://스프링ip주소:스프링포트번호/공통url"
export default axios.create({
  baseURL: "http://localhost:8000/api",
  headers: {
    "Content-Type": "application/json"
  }
});

IDept.ts

// 인터페이스 : == 자바 모델 유사
// => 목적 : 각 속성에 자료형(type) 을 강제하는 것
export default interface IDept {
    dno?: any | null,
    dname: string,
    loc: string,
}

 App.tsx 수정

밑에코드 추가

          {/* dept */}
          <Route path="/dept-nop" element={<DeptListNop />} />
          <Route path="/add-dept-nop" element={<AddDeptNop />} />
          <Route path="/dept-nop/:dno" element={<DeptNop />} />
          {/* emp */}
          <Route path="/emp-nop" element={<EmpListNop />} />
          <Route path="/add-emp-nop" element={<AddEmpNop />} />
          <Route path="/emp-nop/:eno" element={<EmpNop />} />
import React from "react";
// app css import
import "./assets/css/app.css";

import HeaderCom from "./components/common/HeaderCom";
import { Route, Routes } from "react-router-dom";
import Home from "./pages/Home";
import Login from "./pages/auth/Login";
import Register from "./pages/auth/Register";
import ForgotPassword from "./pages/auth/ForgotPassword";
import NotFound from "./pages/common/NotFound";
import DeptListNop from "./pages/dept-nop/DeptListNop";
import EmpListNop from "./pages/emp-nop/EmpListNop";
import AddDeptNop from "./pages/dept-nop/AddDeptNop";
import AddEmpNop from "./pages/emp-nop/AddEmpNop";
import DeptNop from "./pages/dept-nop/DeptNop";
import EmpNop from "./pages/emp-nop/EmpNop";

function App() {
  return (
    <div className="App">
      <HeaderCom />

      {/* <!-- 구분 막대 시작 --> */}
      <div className="gutter text-center text-muted fade-in-box">
        <div>클론 코딩 예제 사이트에 오신 것을 환영합니다.</div>
      </div>
      {/* <!-- 구분 막대 끝 --> */}

      <div id="content-wrapper">
        {/* 라우터 정의 시작 */}
        <Routes>
          {/* login */}
          <Route path="/" element={<Home />} />
          <Route path="/login" element={<Login />} />
          <Route path="/register" element={<Register />} />
          <Route path="/forgot-password" element={<ForgotPassword />} />

          {/* dept */}
          <Route path="/dept-nop" element={<DeptListNop />} />
          <Route path="/add-dept-nop" element={<AddDeptNop />} />
          <Route path="/dept-nop/:dno" element={<DeptNop />} />
          {/* emp */}
          <Route path="/emp-nop" element={<EmpListNop />} />
          <Route path="/add-emp-nop" element={<AddEmpNop />} />
          <Route path="/emp-nop/:eno" element={<EmpNop />} />
         
          {/* TODO: 사원 전체 조회 페이지를 만들고 (/emp-nop) 화면에 출력하세요(부서)
          1) types/IEmp.ts
          2) services/EmpService.ts (axios 공통함수들)
          3) pages/emp-nop/EmpListNop.tsx (전체조회 페이지)
          4) Route 메뉴 달기
          */}

          {/* NotFound */}
          <Route path="*" element={<NotFound />} />
        </Routes>
        {/* 라우터 정의 끝 */}
      </div>
    </div>
  );
}

export default App;

DeptService

// DeptService.ts
import http from "../utils/http-common"; // axios 통신
import IDept from "../types/IDept";      // IDept 임포트

// 화살표함수 단축키 : nfn
/** 전체 조회 요청 */
const getAll = () => {
    // 조회요청 : .get("/url")
    // 사용법 : http.get<리턴타입>("url")
    return http.get<Array<IDept>>("/dept");
 }

 /** 상세조회(1건조회) 요청 : 기본키 */
 const get = (dno:any) => {
    return http.get<IDept>(`/dept/${dno}`);
  }

/** 저장요청 */
const create = (data:IDept) => {
    return http.post<IDept>("/dept", data);
 }

/** 수정요청 : 기본키, 객체 */
const update = (dno:any, data:IDept) => {
    return http.put<any>(`/dept/${dno}`, data);
 }

/** 삭제요청 : 기본키 */
const remove = (dno:any) => {
    return http.delete<any>(`/dept/deletion/${dno}`);
 }

/** 부서명 검색 함수 */
const findByDname = (dname:string) => {
    return http.get<Array<IDept>>(`/dept?dname=${dname}`);
 }

const DeptService = {
    getAll,
    get,
    create,
    update,
    remove,
    findByDname
}

export default DeptService;

HeaderCom

수정 (dept-nop 수정)

 

import React, { useEffect } from "react";
import initMain from "../../assets/js/scripts";

function HeaderCom() {
  useEffect(() => {
    initMain();
  });

  return (
    <div>
      {/* nav 메뉴 시작 */}
      <div className="nav-wrapper bg-light">
        <nav className="navbar navbar-expand-lg p-2">
          <div className="container-fluid">
            <a className="navbar-brand" href="*">
              <img
                src={require("../../assets/img/simple-coding2.png")}
                alt=""
                width="24"
                height="24"
              />
              &nbsp;&nbsp;Simple Coding
            </a>
            <button
              className="navbar-toggler"
              type="button"
              data-bs-toggle="collapse"
              data-bs-target="#navbarSupportedContent"
              aria-controls="navbarSupportedContent"
              aria-expanded="false"
              aria-label="Toggle navigation"
            >
              <span className="navbar-toggler-icon"></span>
            </button>
            <div
              className="collapse navbar-collapse"
              id="navbarSupportedContent"
            >
              {/* <!-- me-auto : 왼쪽 정렬(여백이 오른쪽에 자동으로 만들어짐) --> */}
              <ul className="navbar-nav me-auto mb-2 mb-lg-0">
                {/* home 시작 */}
                <li className="nav-item me-2">
                  <a className="nav-link active" href="/">
                    Home
                  </a>
                </li>
                {/* home 끝 */}

                {/* 기초메뉴 시작 */}
                <li className="nav-item menu-toggle dropdown me-2">
                  <a
                    className="sidebar-subject nav-link active"
                    data-bs-toggle="dropdown"
                    href="#"
                  >
                    기초
                  </a>
                  <div className="sidebar-wrapper">
                    <ul className="sidebar-nav row">
                      {/* <!-- 메뉴:제목 --> */}
                      <li className="dropdown-item col-12 ms-5 mb-2 fw-bolder fs-5">
                        맛보기 예제
                      </li>
                      {/* <!-- 1행 시작--> */}
                      <li className="sidebar-nav-item col-3">
                        <a href="/dept-nop" className="nav-link active ms-2">
                          Dept
                        </a>
                      </li>
                      <li className="sidebar-nav-item col-3">
                        <a href="/add-dept-nop" className="nav-link active ms-2">
                          Add Dept
                        </a>
                      </li>
                      {/* <!-- 줄바꿈 : w-100 --> */}
                      <li className="sidebar-nav-item w-100"></li>
                      {/* <!-- 1행 끝--> */}

                      {/* <!-- 2행 시작--> */}
                      <li className="sidebar-nav-item col-3">
                        <a href="/emp-nop" className="nav-link active ms-2">
                          Emp(연습)
                        </a>
                      </li>
                      <li className="sidebar-nav-item col-3">
                        <a href="/add-emp-nop" className="nav-link active ms-2">
                          Add Emp(연습)
                        </a>
                      </li>
                      {/* <!-- 줄바꿈 : w-100 --> */}
                      <li className="sidebar-nav-item w-100"></li>
                      {/* <!-- 2행 끝--> */}

                      {/* <!-- 3행 시작--> */}
                      <li className="sidebar-nav-item col-3">
                        <a href="/qna" className="nav-link active ms-2">
                          Qna(다양한검색))
                        </a>
                      </li>
                      <li className="sidebar-nav-item col-3">
                        <a href="/add-qna" className="nav-link active ms-2">
                          AddQna(다양한검색)
                        </a>
                      </li>
                      {/* <!-- 줄바꿈 : w-100 --> */}
                      <li className="sidebar-nav-item w-100"></li>
                      {/* <!-- 3행 끝 --> */}

                      {/* <!-- 4행 시작--> */}
                      <li className="sidebar-nav-item col-3">
                        <a href="/customer" className="nav-link active ms-2">
                          Customer(연습)
                        </a>
                      </li>
                      <li className="sidebar-nav-item col-3">
                        <a
                          href="/add-customer"
                          className="nav-link active ms-2"
                        >
                          Customer(연습)
                        </a>
                      </li>
                      {/* <!-- 줄바꿈 : w-100 --> */}
                      <li className="sidebar-nav-item w-100"></li>
                      {/* <!-- 4행 끝 --> */}
                    </ul>
                  </div>
                </li>
                {/* 기초메뉴 끝 */}

                {/* 보통메뉴 시작 */}
                <li className="nav-item menu-toggle dropdown me-2">
                  <a
                    className="sidebar-subject nav-link active"
                    data-bs-toggle="dropdown"
                    href="#"
                  >
                    보통
                  </a>
                  <div className="sidebar-wrapper">
                    <ul className="sidebar-nav row">
                      {/* <!-- 메뉴:제목 --> */}
                      <li className="dropdown-item col-12 ms-5 mb-2 fw-bolder fs-5">
                        다양한 메뉴
                      </li>
                      {/* <!-- 1행 시작--> */}
                      <li className="sidebar-nav-item col-3">
                        <a href="/faq" className="nav-link active ms-2">
                          Faq(아코디언)
                        </a>
                      </li>
                      <li className="sidebar-nav-item col-3">
                        <a href="/add-faq" className="nav-link active ms-2">
                          Add Faq
                        </a>
                      </li>
                      {/* <!-- 줄바꿈 : w-100 --> */}
                      <li className="sidebar-nav-item w-100"></li>
                      {/* <!-- 1행 끝--> */}

                      {/* <!-- 2행 시작--> */}
                      <li className="sidebar-nav-item col-3">
                        <a href="/cinema-faq" className="nav-link active ms-2">
                          Cinema faq(연습)
                        </a>
                      </li>
                      <li className="sidebar-nav-item col-3">
                        <a
                          href="/add-cinema-faq"
                          className="nav-link active ms-2"
                        >
                          Add Cinema(연습)
                        </a>
                      </li>
                      {/* <!-- 줄바꿈 : w-100 --> */}
                      <li className="sidebar-nav-item w-100"></li>
                      {/* <!-- 2행 끝--> */}

                      {/* <!-- 3행 시작--> */}
                      <li className="sidebar-nav-item col-3">
                        <a href="reply-board" className="nav-link active ms-2">
                          Reply List
                        </a>
                      </li>
                      <li className="sidebar-nav-item col-3">
                        <a
                          href="add-reply-board"
                          className="nav-link active ms-2"
                        >
                          Add Reply
                        </a>
                      </li>
                      {/* <!-- 줄바꿈 : w-100 --> */}
                      <li className="sidebar-nav-item w-100"></li>
                      {/* <!-- 3행 끝 --> */}

                      {/* <!-- 4행 시작--> */}
                      <li className="sidebar-nav-item col-3">
                        <a
                          href="/thread-board"
                          className="nav-link active ms-2"
                        >
                          Thread List(연습)
                        </a>
                      </li>
                      <li className="sidebar-nav-item col-3">
                        <a
                          href="/add-thread-board"
                          className="nav-link active ms-2"
                        >
                          Add Thread(연습)
                        </a>
                      </li>
                      {/* <!-- 줄바꿈 : w-100 --> */}
                      <li className="sidebar-nav-item w-100"></li>
                      {/* <!-- 4행 끝 --> */}
                    </ul>
                  </div>
                </li>
                {/* 보통메뉴 끝 */}

                {/* 쇼핑몰 시작 */}
                <li className="nav-item menu-toggle dropdown me-2">
                  <a
                    className="sidebar-subject nav-link active"
                    data-bs-toggle="dropdown"
                    href="#"
                  >
                    쇼핑몰
                  </a>
                  <div className="sidebar-wrapper">
                    <ul className="sidebar-nav row">
                      {/* <!-- 메뉴:제목 --> */}
                      <li className="dropdown-item col-12 ms-5 mb-2 fw-bolder fs-5">
                        쇼핑몰 핵심 메뉴
                      </li>
                      {/* <!-- 1행 시작--> */}
                      <li className="sidebar-nav-item col-3">
                        <a
                          href="/simple-product"
                          className="nav-link active ms-2"
                        >
                          Sim. Prod. List
                        </a>
                      </li>
                      <li className="sidebar-nav-item col-3">
                        <a
                          href="/add-simple-product"
                          className="nav-link active ms-2"
                        >
                          Add Sim. Prod.(adm)
                        </a>
                      </li>
                      {/* <!-- 줄바꿈 : w-100 --> */}
                      <li className="sidebar-nav-item w-100"></li>
                      {/* <!-- 1행 끝--> */}

                      {/* <!-- 2행 시작--> */}
                      <li className="sidebar-nav-item col-3">
                        <a href="/product" className="nav-link active ms-2">
                          Product List(연습)
                        </a>
                      </li>
                      <li className="sidebar-nav-item col-3">
                        <a href="/add-product" className="nav-link active ms-2">
                          Add Product(연습)
                        </a>
                      </li>
                      {/* <!-- 줄바꿈 : w-100 --> */}
                      <li className="sidebar-nav-item w-100"></li>
                      {/* <!-- 2행 끝--> */}

                      {/* <!-- 3행 시작--> */}
                      <li className="sidebar-nav-item col-3">
                        <a href="/cinema" className="nav-link active ms-2">
                          Daily Cinema(공공)
                        </a>
                      </li>
                      <li className="sidebar-nav-item col-3">
                        <a
                          href="/weekend-box-office"
                          className="nav-link active ms-2"
                        >
                          Week. Cinema(연습)
                        </a>
                      </li>
                      {/* <!-- 줄바꿈 : w-100 --> */}
                      <li className="sidebar-nav-item w-100"></li>
                      {/* <!-- 3행 끝 --> */}

                      {/* <!-- 4행 시작--> */}
                      <li className="sidebar-nav-item col-3">
                        <a href="/thema-load" className="nav-link active ms-2">
                          Thema Load(공공)
                        </a>
                      </li>
                      <li className="sidebar-nav-item col-3">
                        <a href="/thema-basic" className="nav-link active ms-2">
                          Thema Basic(연습)
                        </a>
                      </li>
                      {/* <!-- 줄바꿈 : w-100 --> */}
                      <li className="sidebar-nav-item w-100"></li>
                      {/* <!-- 4행 끝 --> */}
                    </ul>
                  </div>
                </li>
                {/* 쇼핑몰 끝 */}

                {/* 고급메뉴 시작 */}
                <li className="nav-item menu-toggle dropdown me-2">
                  <a
                    className="sidebar-subject nav-link active"
                    data-bs-toggle="dropdown"
                    href="#"
                  >
                    고급
                  </a>
                  <div className="sidebar-wrapper">
                    <ul className="sidebar-nav row">
                      {/* <!-- 메뉴:제목 --> */}
                      <li className="dropdown-item col-12 ms-5 mb-2 fw-bolder fs-5">
                        파일 업로드 메뉴
                      </li>
                      {/* <!-- 1행 시작--> */}
                      <li className="sidebar-nav-item col-3">
                        <a
                          href="/fileDb"
                          className="nav-link active ms-2"
                        >
                          File Upload List
                        </a>
                      </li>
                      <li className="sidebar-nav-item col-3">
                        <a
                          href="/add-fileDb"
                          className="nav-link active ms-2"
                        >
                          Add File Upload(admin)
                        </a>
                      </li>
                      {/* <!-- 줄바꿈 : w-100 --> */}
                      <li className="sidebar-nav-item w-100"></li>
                      {/* <!-- 1행 끝--> */}

                      {/* <!-- 2행 시작--> */}
                      <li className="sidebar-nav-item col-3">
                        <a href="/gallery" className="nav-link active ms-2">
                          Gallery List(연습)
                        </a>
                      </li>
                      <li className="sidebar-nav-item col-3">
                        <a href="/add-gallery" className="nav-link active ms-2">
                          Add Gallery(연습)
                        </a>
                      </li>
                      {/* <!-- 줄바꿈 : w-100 --> */}
                      <li className="sidebar-nav-item w-100"></li>
                      {/* <!-- 2행 끝--> */}

                      {/* <!-- 3행 시작--> */}
                      <li className="sidebar-nav-item col-3">
                        <a href="#" className="nav-link active ms-2">
                        </a>
                      </li>
                      <li className="sidebar-nav-item col-3">
                        <a
                          href="#"
                          className="nav-link active ms-2"
                        >
                        </a>
                      </li>
                      {/* <!-- 줄바꿈 : w-100 --> */}
                      <li className="sidebar-nav-item w-100"></li>
                      {/* <!-- 3행 끝 --> */}

                      {/* <!-- 4행 시작--> */}
                      <li className="sidebar-nav-item col-3">
                        <a href="#" className="nav-link active ms-2">
                        </a>
                      </li>
                      <li className="sidebar-nav-item col-3">
                        <a href="#" className="nav-link active ms-2">
                        </a>
                      </li>
                      {/* <!-- 줄바꿈 : w-100 --> */}
                      <li className="sidebar-nav-item w-100"></li>
                      {/* <!-- 4행 끝 --> */}
                    </ul>
                  </div>
                </li>
                {/* 고급메뉴 끝 */}
              </ul>
              <ul className="navbar-nav">
                {/* 어드민 시작 */}
                <li className="nav-item menu-toggle dropdown me-2">
                  <a
                    className="sidebar-subject nav-link active"
                    data-bs-toggle="dropdown"
                    href="#"
                  >
                    어드민 예제
                  </a>
                  <div className="sidebar-wrapper">
                    <ul className="sidebar-nav row">
                      {/* <!-- 메뉴:제목 --> */}
                      <li className="dropdown-item col-12 ms-5 mb-2 fw-bolder fs-5">
                        코드 / 관리자 메뉴
                      </li>
                      {/* <!-- 1행 시작--> */}
                      <li className="sidebar-nav-item col-3">
                        <a
                          href="/code-category"
                          className="nav-link active ms-2"
                        >
                          Code Category List
                        </a>
                      </li>
                      <li className="sidebar-nav-item col-3">
                        <a
                          href="/add-code-category"
                          className="nav-link active ms-2"
                        >
                          Add Code Category
                        </a>
                      </li>
                      {/* <!-- 줄바꿈 : w-100 --> */}
                      <li className="sidebar-nav-item w-100"></li>
                      {/* <!-- 1행 끝--> */}

                      {/* <!-- 2행 시작--> */}
                      <li className="sidebar-nav-item col-3">
                        <a href="/code" className="nav-link active ms-2">
                          Code
                        </a>
                      </li>
                      <li className="sidebar-nav-item col-3">
                        <a href="/add-code" className="nav-link active ms-2">
                          Add Code
                        </a>
                      </li>
                      {/* <!-- 줄바꿈 : w-100 --> */}
                      <li className="sidebar-nav-item w-100"></li>
                      {/* <!-- 2행 끝--> */}

                      {/* <!-- 3행 시작--> */}
                      <li className="sidebar-nav-item col-3">
                        <a href="#" className="nav-link active ms-2"></a>
                      </li>
                      <li className="sidebar-nav-item col-3">
                        <a href="#" className="nav-link active ms-2"></a>
                      </li>
                      {/* <!-- 줄바꿈 : w-100 --> */}
                      <li className="sidebar-nav-item w-100"></li>
                      {/* <!-- 3행 끝 --> */}

                      {/* <!-- 4행 시작--> */}
                      <li className="sidebar-nav-item col-3">
                        <a href="#" className="nav-link active ms-2"></a>
                      </li>
                      <li className="sidebar-nav-item col-3">
                        <a href="#" className="nav-link active ms-2"></a>
                      </li>
                      {/* <!-- 줄바꿈 : w-100 --> */}
                      <li className="sidebar-nav-item w-100"></li>
                      {/* <!-- 4행 끝 --> */}
                    </ul>
                  </div>
                </li>
                {/* 어드민 끝 */}

                {/* 로그인 시작 */}
                <li className="nav-item">
                  <a className="nav-link active" href="/register">
                    회원가입
                  </a>
                </li>
                <li className="nav-item">
                  <a className="nav-link active" href="/login">
                    로그인
                  </a>
                </li>
                {/* 로그인 끝 */}
              </ul>
            </div>
          </div>
        </nav>
      </div>
      {/* nav 메뉴 끝 */}
    </div>
  );
}

export default HeaderCom;

DeptListNop

// DeptListNop.tsx
// react 단축키 : rfce
import React, { useEffect, useState } from "react";
import TitleCom from "../../components/common/TitleCom";
import { Link } from "react-router-dom";
import IDept from "../../types/IDept";
import DeptService from "../../services/DeptService";

function DeptListNop() {
  // 변수 정의
  // todo: 부서배열 변수
  const [dept, setDept] = useState<Array<IDept>>([]);
  // todo: 검색어 변수
  const [searchDname, setSearchDname] = useState<string>("");

  // 함수 정의
  // todo: 화면이 뜨자마자 실행되는 이벤트함수(1번)
  //  사용법 : useEffect(()=>{실행문},[])
  useEffect(() => {
    // 전체 조회 실행
    retrieveDept();
  }, []);

  // todo: 검색어 수동 바인딩 함수
  const onChangeSearchDname = (e: React.ChangeEvent<HTMLInputElement>) => {
    // todo: event.target : input 태그에 현재 걸린 이벤트
    //  => e.target.value : 현재 조작하는 태그의 value 값
    setSearchDname(e.target.value);
  };

  // todo: 전체 조회 함수
  const retrieveDept = () => {
    DeptService.getAll() // backend 요청
      .then((response: any) => {
        // todo: 성공 처리
        setDept(response.data);
        // 로그
        console.log("response", response.data);
      })
      .catch((e: Error) => {
        // todo: 실패 처리
        console.log(e);
      });
  };

  // todo: 검색어 조회 함수
  const findByDname = () => {
    DeptService.findByDname(searchDname) // backend 요청
      .then((response: any) => {
        // todo: 성공 처리
        setDept(response.data);
        // 로그
        console.log("response", response.data);
      })
      .catch((e: Error) => {
        // todo: 실패 처리
        console.log(e);
      });
  };

  return (
    // 여기
    <>
      {/* 제목 start */}
      <TitleCom title="Dept List No Page" />
      {/* 제목 end */}

      {/* dname start(검색창) */}
      <div className="row mb-5 justify-content-center">
        {/* w-50 : 크기 조정, mx-auto : 중앙정렬(margin: 0 auto), justify-content-center */}
        <div className="col-12 w-50 input-group mb-3">
          {/* 입력창 시작 */}
          <input
            type="text"
            className="form-control"
            placeholder="Search by dname"
            value={searchDname}
            onChange={onChangeSearchDname}
          />
          {/* 입력창 끝 */}

          {/* 검색버튼 시작 */}
          <div className="input-group-append">
            <button
              className="btn btn-outline-secondary"
              type="button"
              onClick={findByDname}
            >
              Search
            </button>
          </div>
          {/* 검색버튼 끝 */}
        </div>
      </div>
      {/* dname end */}

      {/* table start(본문) */}
      <div className="col-md-12">
        {/* table start */}
        <table className="table">
          {/* 테이블 제목 시작 */}
          <thead className="table-light">
            <tr>
              <th scope="col">Dname</th>
              <th scope="col">Loc</th>
              <th scope="col">Actions</th>
            </tr>
          </thead>
          {/* 테이블 제목 끝 */}

          {/* TODO: 테이블 데이터 시작 */}
          <tbody>
            {dept &&
              dept.map((data) => (
                <tr key={data.dno}>
                  <td>{data.dname}</td>
                  <td>{data.loc}</td>
                  <td>
                    <Link to={"/dept-nop/" + data.dno}>
                      <span className="badge bg-success">Edit</span>
                    </Link>
                  </td>
                </tr>
              ))}
          </tbody>
          {/* 테이블 데이터 끝 */}
        </table>
        {/* table end */}
      </div>
      {/* table end */}
    </>
  );
}

export default DeptListNop;

AddDeptNop.tsx

// AddDeptNop.tsx : rfce
import React,{useState} from "react";
import TitleCom from "../../components/common/TitleCom";
import IDept from "../../types/IDept";
import DeptService from "../../services/DeptService";

// todo: 새 부서(객체:1개) 저장 페이지
function AddDeptNop() {

    // 변수 정의
    // todo : 초기화 객체
    const initialDept = {
        dno: null,
        dname: "",
        loc: "",
    }

    // todo: 새부서 객체 변수
    const [dept, setDept] = useState<IDept>(initialDept);
    // todo: 저장하면 true, 아니면 false 인 변수(값에따라 화면바뀜)
    const [submitted, setSubmitted] = useState<boolean>(false);

    // 함수 정의
    // todo: 새로운 폼(form)을 보여주는 함수
    const newDept = () => {
        // 새폼 == 객체초기화, submitted 변수 초기화(false)
        setDept(initialDept); // 객체초기화
        setSubmitted(false);  
     }

    // todo: 각각의 입력창 수동바인딩 공통함수
    const handleInputChange = (event:any) => {
        const { name, value } = event.target; // 화면값[이름]
        // 화면값 -> Dept 객체의 속성에 저장
        setDept({...dept, [name]: value});
     }

    // todo: 저장 함수
    const saveDept = () => {
        // 임시 부서 변수(저장될 객체)
        var data = {
            dname: dept.dname,
            loc: dept.loc
        }
        // 저장 함수 호출
        DeptService.create(data) // 벡엔드로 저장 요청
        .then((response:any)=>{
            // 저장 성공 유무 -> submitted 변수 : true 변경
            setSubmitted(true); // 화면 변경
            console.log(response.data);
        })
        .catch((e:Error)=>{
            console.log(e);
        })
     }

  return (
    // 여기
    <div className="row">
      {submitted ? (
        // 저장 버튼 클릭하면 아래 화면이 보임
        <div className="col-6 mx-auto">
          <h4>You submitted successfully!</h4>
          {/* Add 버튼 클릭하면 다시 새로운 부서저장 페이지로 이동(새폼 보이기) */}
          <button className="btn btn-success" onClick={newDept}>
            Add
          </button>
        </div>
      ) : (
        <>
          {/* 제목 start */}
          <TitleCom title="Add Dept No Page" />
          {/* 제목 end */}

          <div className="col-6 mx-auto">
            {/* 부서명 입력창 시작 */}
            <div className="row g-3 align-items-center mb-3">
              <div className="col-3">
                <label htmlFor="dname" className="col-form-label">
                  Dname
                </label>
              </div>

              <div className="col-9">
                <input
                  type="text"
                  id="dname"
                  required
                  className="form-control"
                  value={dept.dname}
                  onChange={handleInputChange}
                  placeholder="dname"
                  name="dname"
                />
              </div>
            </div>
            {/* 부서명 입력창 끝 */}

            {/* 부서위치 입력창 시작 */}
            <div className="row g-3 align-items-center mb-3">
              <div className="col-3">
                <label htmlFor="loc" className="col-form-label">
                  Loc
                </label>
              </div>
              <div className="col-9">
                <input
                  type="text"
                  id="loc"
                  required
                  className="form-control"
                  value={dept.loc}
                  onChange={handleInputChange}
                  placeholder="loc"
                  name="loc"
                />
              </div>
            </div>
            {/* 부서위치 입력창 끝 */}

            {/* 저장버튼 시작 */}
            <div className="row g-3 mt-3 mb-3">
              <button
                onClick={saveDept}
                className="btn btn-outline-primary ms-2 col"
              >
                Submit
              </button>
            </div>
            {/* 저장버튼 끝 */}
          </div>
        </>
      )}
    </div>
  );
}

export default AddDeptNop;

DeptNop.tsx

// DeptNop.tsx : rfce
// 상세조회 + 수정/삭제
import React from "react";
import TitleCom from "../../components/common/TitleCom";
import { useNavigate, useParams } from "react-router-dom";
import { useState } from "react";
import IDept from "../../types/IDept";
import { useEffect } from "react";
import DeptService from "../../services/DeptService";

function DeptNop() {
  // 전체조회페이지 보내준 기본키 정보 받기
  // todo: useParams() -> url/기본키(dno) 정보를 받게하는 함수
  const { dno } = useParams();
  // todo: 강제 페이지 이동 함수
  let navigate = useNavigate();

  // 변수 정의
  // todo: 객체 초기화
  const initialDept = {
    dno: "",
    dname: "",
    loc: "",
  };
  // todo: 수정될 부서객체 변수
  const [dept, setDept] = useState<IDept>(initialDept);
  // todo: 화면에서 수정 성공/실패 메세지 변수
  const [message, setMessage] = useState<string>("");

  // 함수 정의
  // todo: 화면이 뜰때 실행되는 이벤트 함수 + dno 값 감시
  // 사용법 : useEffect(()=>{실행문},[변수명])
  useEffect(() => {
    // dno(기본키) 있으면 상세조회 실행
    if (dno) getDept(dno);
  }, [dno]);

  // todo: 상세조회
  const getDept = (dno: string) => {
    DeptService.get(dno) // 벡엔드에 상세조회 요청
      .then((response: any) => {
        // 벡엔드 결과(response.data) -> 부서객체 저장
        setDept(response.data);
        console.log(response.data);
      })
      .catch((e: Error) => {
        console.log(e);
      });
  };

  // todo: 입력창 수동 바인딩 공통함수
  const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = event.target; // 화면값[이름]
    // 화면값 -> Dept 객체의 속성에 저장
    setDept({ ...dept, [name]: value });
  };

  //  todo: 수정 함수
  const updateDept = () => {
    DeptService.update(dept.dno, dept) // 벡엔드 수정요청
    .then((response)=>{
      console.log(response.data); // 벡엔드 결과 로그
      // 화면에 성공메세지 출력
      setMessage("부서정보가 수정되었습니다.");
    })
    .catch((e:Error)=>{
      console.log(e);
    })
  };

  // todo: 삭제함수
  const deleteDept = () => {
    DeptService.remove(dept.dno) // 삭제 요청
    .then((response)=>{
      console.log(response.data); // 벡엔드 결과(response.data)
      // 강제 전체조회 페이지로 이동
      // todo: navigate("/이동할url");
      navigate("/dept-nop");
    })
    .catch((e:Error)=>{
      console.log(e);
    })
  };

  return (
    // 여기
    <>
      {/* 제목 start */}
      <TitleCom title="DeptNop Detail No Page" />
      {/* 제목 end */}

      <>
        {dept ? (
          <div className="col-6 mx-auto">
            {/* 입력창 */}
            <form>
              {/* 부서명 입력창 시작 */}
              <div className="row g-3 align-items-center mb-3">
                <div className="col-3">
                  <label htmlFor="dname" className="col-form-label">
                    Dname
                  </label>
                </div>

                <div className="col-9">
                  <input
                    type="text"
                    id="dname"
                    required
                    className="form-control"
                    value={dept.dname}
                    onChange={handleInputChange}
                    placeholder="dname"
                    name="dname"
                  />
                </div>
              </div>
              {/* 부서명 입력창 끝 */}

              {/* 부서위치 입력창 시작 */}
              <div className="row g-3 align-items-center mb-3">
                <div className="col-3">
                  <label htmlFor="loc" className="col-form-label">
                    Loc
                  </label>
                </div>

                <div className="col-9">
                  <input
                    type="text"
                    id="loc"
                    required
                    className="form-control"
                    value={dept.loc}
                    onChange={handleInputChange}
                    placeholder="loc"
                    name="loc"
                  />
                </div>
              </div>
              {/* 부서위치 입력창 끝 */}
            </form>

            {/* 삭제/수정 버튼 시작 */}
            <div className="row g-3 mt-3 mb-3">
              <button
                onClick={deleteDept}
                className="btn btn-outline-danger ms-3 col"
              >
                Delete
              </button>

              <button
                type="submit"
                onClick={updateDept}
                className="btn btn-outline-success ms-2 col"
              >
                Update
              </button>
            </div>
            {/* 삭제/수정 버튼 끝 */}

            {/* 수정버튼 성공메세지 출력  */}
            <p>{message}</p>
          </div>
        ) : (
          <div className="col-6 mx-auto">
            <br />
            <p>Please click on a DeptNop...</p>
          </div>
        )}
      </>
    </>
  );
}

export default DeptNop;