반응형
프론트 ( 리액트 )
달력
const [selectedDate, setSelectedDate] = useState(null);
onClick={() => handleDateClick(day)}
// 날짜를 클릭했을 때 실행되는 함수
const handleDateClick = (date) => {
setSelectedDate(date); // 선택된 날짜 상태 업데이트
onDateSelect(date); // 부모 컴포넌트로 선택된 날짜 전달
};
클릭이벤트로 일자 선택시 가져오는 이벤트 만듬
메인페이지 ( 달력 일자 선택 시 해당하는 데이터 조회 )
<Calendar onDateSelect={handleDateSelect} />
const handleDateSelect = (selectedDate) => {
// 날짜가 어떤 형식으로 들어오는지 검증
const formattedDate = format(selectedDate, 'yyyy-MM-dd');
console.log("Formatted date for API:", formattedDate);
axios.get(`http://localhost:8090/traders/stock?date=${formattedDate}`)
// axios.get(`http://localhost:8090/traders/stock?date=${format(selectedDate, 'yyyy-MM-dd')}`)
.then(response => {
//data가 들어오는지 검증
console.log("API:", response.data);
// 선택된 날짜로부터 7일 이내에 유통기한이 끝나는 상품만 필터링
const expiringProducts = response.data.filter(stock => {
// console.log("date변환전 : " + JSON.stringify(stock));
// stock을 콘솔로 찍었을때 object라고만 떠서 JSON.stringify로 문자열로 변환후 데이터를 확인
console.log("date변환전 : " + stock.expdate);
// stock에 날짜가 expdate로 들어오고 있었음
//날짜 변환
const expirationDate = new Date(stock.expdate);
console.log("test:" + expirationDate);
const daysDifference = (expirationDate - selectedDate) / (1000 * 60 * 60 * 24);
//1000밀리초, 60초, 60분, 24시간 = 86,400,000 (날짜간의 차이를 계산할때 정확하게하기 위해)
return daysDifference >= -7 && daysDifference <= 1;
});
setStock(expiringProducts);
console.log(expiringProducts);
console.log(response.data);
})
.catch(error => {
console.error('There was an error fetching the stock!', error);
});
};
---------------------------------------------------------------------------------------------------------------------------------------------------------
달력 전체코드
import React, { useState } from 'react';
import { format, addMonths, subMonths, startOfMonth, endOfMonth, startOfWeek, addDays, getDay, getWeek, isSameMonth } from 'date-fns';
import '../components/Calendar.css';
const Calendar = ({ onDateSelect }) => {
const [currentDate, setCurrentDate] = useState(new Date()); // 현재 날짜를 저장하는 상태
const [selectedDate, setSelectedDate] = useState(null); // 선택된 날짜를 저장하는 상태
// 한국어로 된 월 이름을 반환하는 함수
const getKoreanMonth = (date) => {
const months = ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'];
return months[date.getMonth()];
};
// 해당 월의 날짜들을 반환하는 함수
const getDaysInMonth = (date) => {
const start = startOfWeek(startOfMonth(date), { weekStartsOn: 1 });
let days = [];
for (let i = 0; i < 35; i++) { // 5주(7일*5=35일)를 표현하기 위해 35일을 계산
days.push(addDays(start, i));
}
return days;
};
// 특정 날짜가 공휴일인지 확인하는 함수
const isHoliday = (date) => {
const dayOfWeek = getDay(date); // 요일을 가져옴 (0: 일요일, 1: 월요일, ...)
const weekOfMonth = getWeek(date) - getWeek(startOfMonth(date)); // 해당 월의 몇 번째 주인지 계산
return dayOfWeek === 0 && (weekOfMonth === 2 || weekOfMonth === 4); // 둘째 주, 넷째 주 일요일을 공휴일로 간주
};
const days = getDaysInMonth(currentDate); // 현재 월의 날짜들 가져오기
// 이전 달로 이동하는 함수
const onPrevMonth = () => setCurrentDate(subMonths(currentDate, 1));
// 다음 달로 이동하는 함수
const onNextMonth = () => setCurrentDate(addMonths(currentDate, 1));
// 날짜를 클릭했을 때 실행되는 함수
const handleDateClick = (date) => {
setSelectedDate(date); // 선택된 날짜 상태 업데이트
onDateSelect(date); // 부모 컴포넌트로 선택된 날짜 전달
};
return (
<div className="calendar">
<div className="calendar-header">
<button onClick={onPrevMonth} className='cal_btnP'><</button> {/* 이전 달 버튼 */}
<h2>{getKoreanMonth(currentDate)} {format(currentDate, 'yyyy')}</h2> {/* 현재 월과 연도 표시 */}
<button onClick={onNextMonth} className='cal_btnN'>></button> {/* 다음 달 버튼 */}
</div>
<div className="calendar-body">
<div className="calendar-week-days">
{['월', '화', '수', '목', '금', '토', '일'].map(day => (
<div key={day} className="week-day">{day}</div> // 요일 표시
))}
</div>
<div className="calendar-days">
{days.map(day => (
<div
key={day.toString()}
className={`calendar-day
${!isSameMonth(day, currentDate) ? 'other-month' : ''} // 다른 달의 날짜 표시
${isHoliday(day) ? 'holiday' : ''} // 공휴일 표시
${selectedDate && day.toDateString() === selectedDate.toDateString() ? 'selected' : ''}` // 선택된 날짜 표시
}
onClick={() => handleDateClick(day)}
>
{format(day, 'd')} {/* 날짜 숫자 표시 */}
</div>
))}
</div>
</div>
</div>
);
};
export default Calendar;
메인 페이지 전체코드
import React, { useState, useEffect, useRef } from 'react';
import main from '../pages/Main.module.css';
import Calendar from '../components/Calendar';
import axios from 'axios';
import { format } from 'date-fns';
function Main() {
const [goods, setGoods] = useState([]);
const [searchGoods, setSearchGoods] = useState('');
const [stock, setStock] = useState([]);
const [stockk, setStockk] = useState([]); // 재고부족 상품 상태
const [selectedGoods, setSelectedGoods] = useState([]);
const prevSelectedDate = useRef(null); // 이전에 선택한 날짜를 추적하는 ref
const [expiringMessage, setExpiringMessage] = useState(''); // 메시지를 저장할 상태 추가
useEffect(() => {
axios.get('http://localhost:8090/traders/home')
.then(response => {
setGoods(response.data);
})
.catch(error => {
console.error('goods상품 조회 불가', error);
});
// 재고부족 상품 리스트 조회
axios.get('http://localhost:8090/traders/stock')
.then(response => {
const shortage = response.data.filter(stock => stock.stockquantity <= 10).sort((a, b) => a.stockquantity - b.stockquantity);
setStockk(shortage);
})
.catch(error => {
console.error('There was an error fetching the goods!', error);
});
}, []);
const handleSearch = (event) => {
event.preventDefault();
axios.get(`http://localhost:8090/traders/home/${searchGoods}`)
.then(response => {
setGoods(response.data);
})
.catch(error => {
console.error('goods상품 검색 불가', error);
});
};
const handleDateSelect = (selectedDate) => {
// 선택한 날짜가 이전에 선택한 날짜와 다른 경우에만 실행
if (prevSelectedDate.current && prevSelectedDate.current.getTime() === selectedDate.getTime()) {
return;
}
prevSelectedDate.current = selectedDate;
// 날짜가 어떤 형식으로 들어오는지 검증
const formattedDate = format(selectedDate, 'yyyy-MM-dd');
axios.get(`http://localhost:8090/traders/stock?date=${formattedDate}`)
.then(response => {
//data가 들어오는지 검증
console.log("API:", response.data);
// 선택된 날짜로부터 7일 이내에 유통기한이 끝나는 상품만 필터링
const expiringProducts = response.data.filter(stock => {
// console.log("date변환전 : " + JSON.stringify(stock));
// stock을 콘솔로 찍었을때 object라고만 떠서 JSON.stringify로 문자열로 변환후 데이터를 확인
console.log("date변환전 : " + stock.expdate);
//stock에 날짜가 expdate로 들어오고 있었음
const expirationDate = new Date(stock.expdate); //유통기한
console.log("test:" + expirationDate);
const daysDifference = (expirationDate - selectedDate) / (1000 * 60 * 60 * 24);
//1000밀리초, 60초, 60분, 24시간 = 86,400,000 (날짜간의 차이를 계산할때 정확하게하기 위해)
console.log("tt:" + daysDifference);
return daysDifference >= 0 && daysDifference <= 7;
});
if (expiringProducts.length > 0) {
setStock(expiringProducts);
console.log(expiringProducts);
setExpiringMessage('');
} else {
setStock([]);
setExpiringMessage('7일 이내에 유통기한이 임박한 상품이 없습니다.');
}
})
.catch(error => {
console.error('There was an error fetching the stock!', error);
});
};
// 개별 선택 체크
const handleSelect = (gcode) => {
setSelectedGoods(prevSelectedGoods =>
prevSelectedGoods.includes(gcode)
? prevSelectedGoods.filter(code => code !== gcode)
: [...prevSelectedGoods, gcode]
);
};
//전체 선택 체크
const handleSelectAll = (event) => {
if (event.target.checked) {
setSelectedGoods(goods.map(item => item.gcode));
} else {
setSelectedGoods([]);
}
};
return (
<div className={main.Main}>
<div className={main.goods_page}>
<div className={main.leftSection}>
<form onSubmit={handleSearch} id='goods-form'>
<input type='search'
name='goods_search'
placeholder='제품코드, 카테고리명, 상품명 검색'
className={main.inputGoodsSearch}
value={searchGoods}
onChange={(e) => setSearchGoods(e.target.value)} />
<button type="submit" className={main.btnGoodsSearch}>검색</button>
</form>
<div className={main.goodsList}>
<table className={main.goodsTable}>
<thead>
<tr>
<th style={{ width: '50px' }}>
<input type="checkbox"
onChange={handleSelectAll}
checked={selectedGoods.length === goods.length} /></th>
<th style={{ width: '65px' }}>제품번호</th>
<th>제품코드</th>
<th>카테고리</th>
<th>상품명(단위)</th>
<th>가격</th>
</tr>
</thead>
<tbody>
{goods.map((goods, index) => (
<tr key={index} className={main.goodsItem}>
<td><input type="checkbox"
checked={selectedGoods.includes(goods.gcode)}
onChange={() => handleSelect(goods.gcode)} /></td>
<td>{index + 1}</td>
<td>{goods.gcode}</td>
<td>{goods.gcategory}</td>
<td>{goods.gname}</td>
<td>{goods.gcostprice.toLocaleString('ko-KR')}</td>
</tr>
))}
</tbody>
</table>
</div>
<button className={main.orBtn} onClick={handleOrder}>발주하기</button>
<div className={main.events}>
이벤트 슬라이드
</div>
</div>
</div>
<div className={main.rightsection}>
<div className={main.locCalender}>
<Calendar onDateSelect={handleDateSelect} />
</div>
<div className={main.tableLabel}>
<div className={main.tableLabel2}>유통기한 임박 상품 리스트</div>
<div className={main.tableLabel3}>재고 부족 상품 리스트</div>
</div>
<div className={main.rightSectionBox}>
<div className={main.disuseList}>
<table className={main.disuseTable}>
<thead>
<tr>
<th style={{ width: '12%' }}>번호</th>
<th style={{ width: '28%' }}>제품코드</th>
<th style={{ width: '35%' }}>상품명</th>
<th style={{ width: '25%' }}>유통기한</th>
</tr>
</thead>
<tbody>
{stock.length > 0 ? (
stock.map((stock, index) => (
<tr key={index} className={main.stockItem}>
<td>{index + 1}</td>
<td>{stock.goods.gcode}</td>
<td>{stock.goods.gname}</td>
<td>{stock.expdate}</td>
</tr>
))
) : (
<tr>
<td colSpan="4">{expiringMessage}</td>
</tr>
)}
</tbody>
</table>
</div>
<div className={main.stockList}>
<table className={main.stockTable}>
<thead>
<tr>
<th style={{ width: '12%' }}>번호</th>
<th style={{ width: '28%' }}>제품코드</th>
<th style={{ width: '35%' }}>상품명</th>
<th style={{ width: '12%' }}>수량</th>
</tr>
</thead>
<tbody>
{stockk.map((stock, index) => (
<tr key={index} className={main.stockItem}>
<td>{index + 1}</td>
<td>{stock.goods.gcode}</td>
<td>{stock.goods.gname}</td>
<td>{stock.stockquantity}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
</div>
);
}
export default Main;
결과
728x90
반응형
'Final Project 신세계아이앤씨' 카테고리의 다른 글
결제하기 ( 토스페이먼츠 ) (0) | 2024.08.07 |
---|---|
홈페이지 들어가면 달력에 오늘 날짜 보이게하기 (0) | 2024.07.31 |
재고관리 페이지 ( 리액트, 스프링부트 ) (0) | 2024.07.24 |
캘린더 (react, npm, 커스텀) (0) | 2024.07.23 |
Final 기획 (1) | 2024.07.20 |