Front-End(리액트)와 Back-End
SI(시스템 통합 연동 실습)
Work에
07_SI 폴더 만들고
다운 받아서 압축풀고
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"
/>
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;
'SI' 카테고리의 다른 글
[SI] 벡엔드 (02_SimpleDMS_Page) 반응형 게시판 (0) | 2023.10.31 |
---|---|
[SI] 프론트엔드 (02_SimpleDMS_Page) 반응형 게시판 (0) | 2023.10.27 |
[SI] 벡엔드 (02_SimpleDMS_Page) 페이지 기능 추가 (0) | 2023.10.23 |
[SI] 프론트엔드 (02_SimpleDMS_Page) 페이지 기능 추가 (0) | 2023.10.20 |
[SI] 벡엔드 (01_SimpleDMS) (0) | 2023.10.19 |