10 minute read

사용자 화면

image

유스케이스

image

📍 해당 코드는 PayManagementSystemManagement 라는 React 컴포넌트를 정의하고 있으며, 급여 관리 시스템의 웹 페이지를 나타낸다.
이 컴포넌트에서 제공하는 주요 기능을 간략하게 요약하면 다음과 같다. 👇🏻
### **1. 급여 데이터 표시 및 관리**
API를 호출하여 **`/api/timeManagement`** 에서 직원 정보를 가져와서 테이블 형태로 화면에 표시합니다. 각 직원에 대한 정보로는 사원번호, 이름, 무급휴가일수, 유급휴가일수, 실제근로일수, 실제근로시간, 이메일, 지급 여부 등이 포함된다. 이 테이블은 **`@coreui/react`** 라이브러리를 사용하여 구성되어 있다. ### **2. 급여 지급 여부 관리**
테이블의 각 행에는 급여 지급 버튼이 있습니다. 버튼을 클릭하면 사용자에게 확인 메시지가 표시되고, "확인"을 선택하면 해당 직원의 급여 지급 상태가 "yes"로 변경된다. 이 변경은 테이블의 해당 행에 즉시 반영된다.
### **3. 개별 직원 급여 정보 PDF 다운로드**
테이블의 각 행 마지막에는 PDF 다운로드 버튼이 있다. 이 버튼을 클릭하면 해당 직원의 급여 정보가 PDF 형식으로 다운로드 된다. 이 기능은 **`Pdf`** 컴포넌트를 통해 제공되고 있다.
**요약하자면, 이 컴포넌트는 직원의 급여 정보를 테이블 형태로 표시하고, 각 직원의 급여 지급 여부를 관리하며, 각 직원의 급여 정보를 PDF 형식으로 다운로드할 수 있는 기능을 제공하고 있다.**

front-end

1. 서버에서 데이터 받아오기

useEffect(() => {
  fetch("/api/timeManagement")
    .then((response) => response.json())
    .then((data) => {
      setUsers(data);
    });
}, []);

useEffect(() => {
  setRows(
    users.map((user) => [
      user.empNum, //사원번호
      user.empName, //사원이름
      user.unpaid, //무급휴가
      user.vacation, //유급휴가
      user.actualWorkDays, //실제근로일수
      user.workingHours, //실제근로시간
      user.email, //이메일
      "no", //지급여부 초깃값
    ])
  );
}, [users]);

React에서 사용되는 useEffect 훅을 활용하여 데이터를 가져오고 가공한다.

1-1. 첫 번째 useEffect

useEffect(() => {
  fetch("/api/timeManagement")
    .then((response) => response.json())
    .then((data) => {
      setUsers(data);
    });
}, []);

해당 훅은 컴포넌트가 처음 마운트 될 때 ([] 빈 종속성 배열 때문에) /api/timeManagement URL에서 데이터를 가져온다. →

가져온 데이터를 JSON 형태로 변환한 후, setUsers 를 통해 users 상태를 설정한다.

1-2. 두 번째 useEffect

useEffect(() => {
  setRows(
    users.map((user) => [
      user.empNum, //사원번호
      user.empName, //사원이름
      user.unpaid, //무급휴가
      user.vacation, //유급휴가
      user.actualWorkDays, //실제근로일수
      user.workingHours, //실제근로시간
      user.email, //이메일
      "no", //지급여부 초깃값
    ])
  );
}, [users]);

이 훅은 users 상태가 변경될 때마다 실행된다. users 배열의 각 사용자에 대해 배열 형태로 데이터를 재구성하고, 이를 setRows를 사용하여 rows 상태를 업데이트한다.

💡 결론적으로, 이 코드는 API를 호출하여 사용자 데이터를 가져온 후, 그 데이터를 다른 형태로 재구성하여 `rows` 상태에 저장한다.

2. 급여 지급 여부 관리

const handlePayClick = (index) => {
  const confirmed = window.confirm("결제 완료 하시겠습니까?");
  if (confirmed) {
    alert("결제 완료되었습니다!");
    const newRows = [...rows];
    newRows[index][7] = "yes";
    setRows(newRows);
  } else {
    alert("취소 되었습니다.");
  }
};

handlePayClick 함수는 사용자의 인터랙션에 따라 데이터를 실시간으로 업데이트하는 중요한 역할을 한다! 사용자가 급여를 지급하도록 선택할 경우, 해당 데이터가 즉시 업데이트되어 사용자에게 피드백을 제공한다.

2-1. 함수 인자 ‘index’

const handlePayClick = (index) => { ... }

이 함수는 index 라는 인자를 받습니다. index 는 현재 클릭한 직원의 테이블 행 번호를 나타낸다. 이를 통해 특정 직원의 데이터를 업데이트할 수 있다.

2-2. 사용자에게 급여 지급 여부 확인

const confirmed = window.confirm("결제 완료 하시겠습니까?");

window.confirm 함수는 사용자에게 확인 대화상자를 표시하고, “확인” 또는 “취소” 버튼을 통해 사용자의 응답을 받는다. 사용자가 “확인”을 클릭하면 true 를 반환하고, “취소”를 클릭하면 false 를 반환한다.

2-3. 급여 지급 상태 업데이트

javascriptCopy code
if (confirmed) {
    alert("결제 완료되었습니다!");
    const newRows = [...rows];
    newRows[index][7] = "yes";
    setRows(newRows);
}

...rows 를 사용하는 것은 현재의 rows 배열을 복사하는 것이다. 이를 “spread operator“라고 부르며, 배열 또는 객체의 내용을 새 배열 또는 객체로 복사한다.
→ 이렇게 하는 이유는 상태를 직접 수정하는 것이 아니라 새로운 배열을 생성하여 상태를 수정하는 것이 React의 권장 사항이기 때문이다.

newRows[index][7] = "yes"; 에서 index 는 현재 클릭한 직원의 행 번호를 나타다. [7] 은 해당 직원의 “지급 여부” 데이터가 저장된 열(column) 번호를 나타낸다. 즉, 선택된 컬럼의 급여 “지급 여부”를 “yes”로 변경할 수 있게 된다.

setRows(newRows);setRows 라는 상태 업데이트 함수를 호출하여 rows 상태를 newRows 로 업데이트한다. 이렇게 함으로써 UI에 급여가 지급이 된 상태의 (변경 된) 내용이 반영된다.

2-4. 지급 취소

else {
    alert("취소 되었습니다.");
}

서비스 이용 시 실수로 눌렀을 경우를 고려하여 취소도 가능하도록 구현했다. 만약 사용자가 급여 지급을 취소하면 “취소 되었습니다.”라는 알림이 표시된다.

💡 요약하면, **`handlePayClick`** 함수는 사용자가 특정 직원의 급여를 지급하려고 할 때 해당 직원의 "지급 여부" 데이터를 "yes"로 업데이트하거나 지급을 취소하는 역할을 한다.

3. 개별 직원 급여 정보, QR코드가 담긴 PDF 다운로드

사용 라이브러리 보러가기 JsPDF 기술 정의서

image

image

3-1. PDF 생성 함수

const generatePdf = async () => {
  const doc = new jsPDF();
  // ... 중략 ...
  doc.save("급여명세.pdf");
};

해당 코드는 급여명세서를 생성하는 함수이다.

  1. jsPDF를 사용하여 PDF를 생성하고 설정한 정보와 표를 PDF에 추가한 뒤, doc.save("급여명세.pdf") 를 호출하여 PDF를 다운로드 한다.
  2. jsPDF 라이브러리를 이용하여 간단하게 PDF를 생성한다.

3-2. QR코드 생성 함수

const generateQrCode = async (pdfUrl) => {
  try {
    const url = await QRCode.toDataURL(pdfUrl);
    setQrCodeURL(url);
    return url;
  } catch (err) {
    console.error(err);
    return "";
  }
};

이 함수는 PDF 문서의 URL을 입력으로 받아 QR코드 이미지의 Data URL을 생성하고, 상태 변수 qrCodeURL에 저장하는 역할을 한다.

여기에 대한 설명은 다음과 같다 👇🏻

  • QRCode.toDataURL(pdfUrl)pdfUrl을 이용하여 QR코드를 생성하고, 그 결과를 Data URL 형식으로 반환한다.
  • await를 사용하여 비동기로 QR코드 생성을 기다립니다. QR코드 생성이 완료되면 결과 URL을 url 변수에 저장한다.
  • setQrCodeURL(url)을 사용하여 qrCodeURL 상태를 업데이트하고, 나중에 컴포넌트에서 호출하여 사용할 수 있도록 한다.
  • 오류가 발생하면 try-catch 블록에서 오류를 처리하고 빈 문자열을 반환한다.
💡 QR코드와 PDF 생성 원리: - QR코드 생성: `QRCode.toDataURL(pdfUrl)` 함수를 사용하여 PDF 문서의 URL을 입력으로 받아 QR코드를 생성한다.
- QR코드는 데이터를 특별한 방식으로 인코딩하여 텍스트 또는 URL로 표현하는 2차원 매트릭스 바코드이다.
- PDF 생성: `jsPDF` 라이브러리를 사용하여 빈 PDF 문서를 생성하고, `doc.text()` 및 `doc.autoTable()` 함수를 사용하여 문서에 텍스트와 표를 추가합니다. 이렇게 추가한 정보는 PDF 파일로 저장하거나 브라우저에서 렌더링할 수 있다 !
→ 즉, 부트스트랩 처럼 하나의 라이브러리로 사용하는 방식 또는 문법이 있어 사용하면 된다.


![image](https://github.com/solfany/Spring-board-project/assets/123814718/0f672f93-93fa-45ac-b7c3-2b6d4b0d488b)

3-3. 부모 컴포넌트(급여 정산)에서 데이터를 받아오기

function Pdf({ userData }) {
  //부모 컴포넌트에서 porp를 통해 전달 받는다.
  // ...

  // 데이터를 받아오는 함수
  const generatePdf = async () => {
    const doc = new jsPDF();

    // userData를 사용하여 PDF 생성
    const headers = [
      ["이름", "생년월일", "사원번호", "부서명", "직급", "주소", "이메일"],
    ];
    const data = [
      [
        userData.empName,
        userData.birthDate,
        userData.empNum,
        userData.dept,
        userData.position,
        userData.address,
        userData.email,
      ],
    ];

    doc.autoTable({
      head: headers,
      body: data,
      startY: 50,
      // ...
    });

    // 나머지 PDF 생성 부분

    doc.save("급여명세.pdf");
  };

  return (
    <div>
      <CButton onClick={generatePdf} size="sm">
        <CIcon icon={cilCloudDownload} />
      </CButton>
    </div>
  );
}

위의 코드에서 데이터를 받아오는 부분은 Pdf 컴포넌트의 userData prop을 통해 이루어진다. PDF에 들어가는 데이터는 컴포넌트가 부모 컴포넌트로부터 전달 받게 된다. 이 데이터는 사용자 정보를 포함하고 있으며, 이 정보를 활용하여 PDF 문서를 생성한다.

데이터를 받아올 때 주요한 부분은 generatePdf 함수 내부에서 사용자 정보를 PDF로 출력하는 부분이다. userData 객체 내의 필드들을 이용하여 테이블 데이터를 생성하고, 생성된 데이터를 PDF로 변환하고 저장하는 역할을 하게된다.

이 부분은 userData 객체의 속성을 접근하여 데이터를 추출하고, 그 데이터를 PDF로 포맷하여 출력하는 것으로, 사용자 정보를 기반으로 동적인 PDF를 생성하는 역할을 하게된다!

해당 코드는 PayManagementSystemManagement라는 React 컴포넌트를 정의하고 있으며, 주요 기능들은 급여 정보의 테이블 뷰, 급여 지급 및 취소, PDF 다운로드 등으로 나누어져 있습니다.

아래는 코드 내에서 주요 기능을 설명하며 주석을 추가하는 방식으로 구성되어 있습니다:

import React, { useState, useEffect } from "react";
// 필요한 UI 컴포넌트들을 가져옵니다.
import { Table, Container, Row, Col, Button } from "reactstrap";
import GetThisMonth from "../TimeManagementSystem/CountWeekdays";
import Pdf from "./Pdf";
import { Pagination, message } from "antd";
import Cookies from "js-cookie";
import {
  CContainer,
  CTable,
  CTableBody,
  CTableHead,
  CTableHeaderCell,
  CTableRow,
  CTableDataCell,
} from "@coreui/react";

function PayManagementSystemManagement() {
  // 각종 상태값들을 정의합니다.
  const [rows, setRows] = useState([]);
  const [users, setUsers] = useState([]);
  const [selectedRowIndex, setSelectedRowIndex] = useState(null);
  const staffInfo = JSON.parse(Cookies.get("staffInfo")); // 쿠키에서 staff 정보를 가져옵니다.

  // 컴포넌트 마운트 시점에 서버로부터 사용자(직원) 정보를 가져옵니다.
  useEffect(() => {
    fetch("/api/timeManagement")
      .then((response) => response.json())
      .then((data) => {
        setUsers(data);
      });
  }, []);

  // users 상태값이 변경될 때마다 rows 상태를 업데이트합니다.
  useEffect(() => {
    setRows(
      users.map((user) => [
        user.empNum,
        user.empName,
        0,
        user.vacation,
        user.actualWorkDays,
        user.workingHours,
        user.email,
        "no",
      ])
    );
  }, [users]);

  // 테이블의 컬럼 이름을 정의합니다.
  const tableColumns = [
    // ... (이전 코드를 유지합니다.)
  ];

  // 급여 지급 버튼을 클릭했을 때의 로직입니다.
  const handlePayClick = (index) => {
    // ... (이전 코드를 유지합니다.)
  };

  // 무작위 문자열 생성 로직입니다.
  const randum = (max) => Math.floor(Math.random() * max);
  // ... (이전 코드를 유지합니다.)

  // 지급 완료 버튼을 클릭했을 때의 알림 로직입니다.
  const clickTobtn = () => {
    // ... (이전 코드를 유지합니다.)
  };

  // 테이블의 특정 행을 클릭했을 때의 로직입니다.
  const handleRowClick = (index) => {
    setSelectedRowIndex(index);
  };
  const someData = selectedRowIndex !== null ? users[selectedRowIndex] : null;

  return (
    <>
      <CContainer className="d-flex justify-content-around ">
        // ... (이전 코드를 유지합니다.) // 급여 정보를 나타내는 테이블 뷰를
        렌더링합니다.
        <CTable striped bordered hover style=>
          // ... (이전 코드를 유지합니다.)
        </CTable>
        <Pagination />
      </CContainer>
    </>
  );
}

export default PayManagementSystemManagement;

이 코드는 전체적으로 React의 useStateuseEffect 훅을 활용하여 급여 관리 시스템의 기능을 구현합니다. 테이블에는 각 직원의 급여 정보가 나타나며, 직원별로 급여 지급 및 취소, PDF 다운로드 기능이 제공됩니다.

1. 상태값 정의 및 초기화

javascriptCopy code
const [rows, setRows] = useState([]);
const [users, setUsers] = useState([]);
const [selectedRowIndex, setSelectedRowIndex] = useState(null);
const staffInfo = JSON.parse(Cookies.get("staffInfo")); // 쿠키에서 staff 정보를 가져옵니다.

2. 사용자(직원) 정보 로딩

데이터는 “/api/timeManagement” 엔드포인트에서 가져옵니다.

// 컴포넌트가 처음 렌더링될 때 사용자 정보를 가져옵니다.
useEffect(() => {
  fetch("/api/timeManagement")
    .then((response) => response.json())
    .then((data) => {
      setUsers(data); // 사용자 정보를 users 상태값에 저장합니다.
    });
}, []);

3. 사용자 정보를 테이블 행 데이터로 변환

javascriptCopy code
// users 상태값이 변경될 때마다 rows 상태를 업데이트합니다.
useEffect(() => {
    setRows(
      users.map((user) => [
        user.empNum,
        user.empName,
        0,
        user.vacation,
        user.actualWorkDays,
        user.workingHours,
        user.email,
        "no",
      ])
    );
}, [users]);

4. 급여 지급 확인 및 취소

javascriptCopy code
// 급여 지급 버튼을 클릭했을 때의 액션입니다.
const handlePayClick = (index) => {
    const confirmed = window.confirm("결제 완료 하시겠습니까?");
    if (confirmed) {
      alert("결제 완료되었습니다!");
      const newRows = [...rows];
      newRows[index][7] = "yes";
      setRows(newRows);
    } else {
      alert("취소 되었습니다.");
    }
};

5. 무작위 문자열 생성

급여 지급 후, 관리자 코드를 생성하기 위한 로직입니다.

const randum = (max) => Math.floor(Math.random() * max);
const numbers = "0123456789";
const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

let ran = "";
for (let i = 0; i < 4; i++) {
  ran += numbers[randum(numbers.length)] + letters[randum(letters.length)];
}

6. 지급 완료 버튼 클릭 이벤트

급여가 지급되면 관리자에게 결제 정보를 보여줍니다.

const clickTobtn = () => {
  alert(`
    결제자: ${staffInfo.empName}
    결제 일시 : ${new Date()}
    관리자 코드: ${staffInfo.empNum}${ran}`);
};

7. 특정 행 클릭 이벤트

javascriptCopy code
// 테이블의 특정 행을 클릭하면 해당 행의 인덱스를 저장합니다.
const handleRowClick = (index) => {
    setSelectedRowIndex(index);
};

8. UI 렌더링

컴포넌트의 반환 부분에서 UI가 구성되어 있습니다. 이곳에는 직원의 급여 정보를 나타내는 테이블, 급여 지급 및 취소 버튼, PDF 다운로드 버튼 등의 UI 요소가 포함되어 있습니다.

코드는 주로 “@coreui/react” 및 “reactstrap” 라이브러리를 활용하여 구현되었습니다.

9. PDF 다운로드

테이블의 각 행마다 PDF 다운로드 버튼이 있으며, 해당 버튼을 클릭하면 Pdf 컴포넌트가 실행됩니다.

<Pdf userData={users[rowIndex]} />

위의 코드로 각 사용자의 데이터를 PDF 컴포넌트로 전달하여, 해당 사용자의 정보를 포함한 PDF 파일을 다운로드할 수 있습니다.


전체적으로 이 컴포넌트는 React 훅을 활용하여 서버에서 직원의 급여 정보를 가져와 테이블 형태로 보여주고, 급여 지급 및 취소, PDF 다운로드 등의 기능을 제공합니다.


급여 정산 페이지

image

CountWeekdays 컴포넌트 코드 분석:

1. 상태(State) 설정:

javascriptCopy code
const [year, setYear] = useState(new Date().getFullYear());
const [month, setMonth] = useState(new Date().getMonth() + 1);
const [weekdays, setWeekdays] = useState(0);
const [workHours, setWorkHours] = useState(0);
  • year, setYear: 현재 연도를 기본 값으로 가지는 상태입니다.
  • month, setMonth: 현재 월을 기본 값으로 가지는 상태입니다.
  • weekdays, setWeekdays: 해당 월의 평일 수를 표시하는 상태입니다.
  • workHours, setWorkHours: 소정 근로 시간을 표시하는 상태입니다.

2. 함수:

const countWeekdaysInMonth = (year, month) => {...}
  • 이 함수는 주어진 연도와 월에 대해 해당 월의 평일 수를 계산합니다.
  • date.getDay()를 사용하여 해당 날짜가 일요일(0) 또는 토요일(6)인지 확인합니다. 주말이 아닐 경우 평일 수를 증가시킵니다.
const calculateWorkHours = (weekdays) => {...}
  • 평일 수를 인자로 받아 소정 근로 시간을 계산합니다. 여기서는 하루의 근무 시간을 8시간으로 가정하고 있습니다.
const handleSubmit = () => {...}
  • ‘Calculate Weekdays’ 버튼을 클릭하면 실행되는 함수입니다.
  • 위의 두 함수를 호출하여 평일 수와 소정 근로 시간을 계산하고, 그 값을 상태에 저장합니다.

3. UI 요소:

  1. 연도 및 월 입력:
    • 사용자는 연도와 월을 숫자로 입력할 수 있습니다.
    • 월 입력에 변경이 발생하면 범위를 검사하여 1보다 작거나 12보다 큰 값을 처리합니다.
<CFormInput
  type="number"
  value={year}
  onChange={(e) => setYear(e.target.value)}
/>
  1. ‘Calculate Weekdays’ 버튼:
    • 이 버튼을 클릭하면 handleSubmit 함수가 호출됩니다.
<CButton onClick={handleSubmit}>Calculate Weekdays</CButton>
  1. 결과 출력:
<CCallout color="primary" className="zzzz">
  <CRow>
    <CCol md={3}>
      {year}{month}월의 평일 수: <b>{weekdays}</b></CCol>
    <CCol md={2}>
      소정근로일수: <b>{weekdays}</b></CCol>
    <CCol md={2}>
      소정근로시간: <b>{workHours}</b>시간
    </CCol>
  </CRow>
</CCallout>
  • 계산된 평일 수와 소정 근로 시간을 보여줍니다.

맨 위로 이동하기

Leave a comment