diff --git a/src/App.js b/src/App.js
index 099b8fa..a0105fd 100644
--- a/src/App.js
+++ b/src/App.js
@@ -28,6 +28,7 @@ import CarManageAdd from "./pages/admin/car/CarManageAdd";
import CarManageDetail from "./pages/admin/car/CarManageDetail";
import OfficeManageAdd from "./pages/admin/office/OfficeManageAdd";
import EquipmentList from "./pages/basic/equipment/EquipmentList";
+import EquipmentAdd from "./pages/basic/equipment/EquipmentAdd";
function App() {
@@ -58,6 +59,8 @@ function App() {
} />
} />
} />
+ } />
+ } />
} />
} />
} />
diff --git a/src/components/capsule/DropBox.js b/src/components/capsule/DropBox.js
index c374607..bea8442 100644
--- a/src/components/capsule/DropBox.js
+++ b/src/components/capsule/DropBox.js
@@ -25,6 +25,7 @@ const Select = styled.select`
const ManagerSelect = styled(Select)`
margin-right: 10px;
+ border: ${props => props.color ? `2px solid ${props.color}` : '1px solid #717171'};
`
const NoBorderSelect = styled(Select)`
@@ -52,15 +53,7 @@ export function SelectToggleInModal(props) {
export function DropBox(props) {
return (
-
- );
-}
-
-export function ManagerDropBox(props) {
- return (
-
+
{props.items}
);
diff --git a/src/components/card/EquipmentInfo.js b/src/components/card/EquipmentInfo.js
index 64a5635..df373ec 100644
--- a/src/components/card/EquipmentInfo.js
+++ b/src/components/card/EquipmentInfo.js
@@ -11,13 +11,11 @@ import EmptyImg from "assets/images/EmptyImg.svg"
// 카드 박스
export const Card = styled.div`
height: 350px;
- width: calc(33.33% - 15px);
background: white;
border-radius: 8px;
border: 1px solid #E6E6E6;
box-sizing: border-box;
padding: 15px;
- margin: 0 0 15px 0;
`
// 상단줄 컨테이너
diff --git a/src/components/searchBar/ManageSearchBar.js b/src/components/searchBar/ManageSearchBar.js
index 6f01b38..97fa236 100644
--- a/src/components/searchBar/ManageSearchBar.js
+++ b/src/components/searchBar/ManageSearchBar.js
@@ -2,7 +2,7 @@ import React from "react";
import styled from "styled-components";
import SearchInputImage from "../../assets/images/SearchInput.svg"
import SearchButtonImage from "../../assets/images/SearchPlus.svg"
-import {ManagerDropBox} from "../capsule/DropBox";
+import {DropBox} from "../capsule/DropBox";
const Container = styled.div`
background: none;
@@ -74,7 +74,7 @@ function ManageSearchBar(props) {
let dropBoxes = [];
if (props.selectOptions !== null)
props.selectOptions.forEach((option, index) =>
- dropBoxes.push()
+ dropBoxes.push()
)
return dropBoxes
}
diff --git a/src/pages/admin/car/CarManage.js b/src/pages/admin/car/CarManage.js
index 96a96fc..2572547 100644
--- a/src/pages/admin/car/CarManage.js
+++ b/src/pages/admin/car/CarManage.js
@@ -17,8 +17,12 @@ function CarManage(props) {
Authorization: getToken()
}
})
- .then((Response) => { setCars(Response.data.data.content) })
- .catch((error) => {basicError(error)})
+ .then((Response) => {
+ setCars(Response.data.data.content)
+ })
+ .catch((error) => {
+ basicError(error)
+ })
};
const searchCars = (e) => {
@@ -29,16 +33,16 @@ function CarManage(props) {
getCars("");
}, [])
- const moveToAdd = () => {
+ const moveToAdd = () => {
window.location.href = `/admin/cars/add`
}
return (
-
+
차량 관리
-
+
@@ -52,7 +56,7 @@ function CarManage(props) {
- { cars.length === 0 ?
+ {cars.length === 0 ?
차량 내역이 없습니다. |
@@ -73,7 +77,7 @@ function CarManage(props) {
-
+
);
}
diff --git a/src/pages/admin/car/CarManageAdd.js b/src/pages/admin/car/CarManageAdd.js
index cce375f..98d1f43 100644
--- a/src/pages/admin/car/CarManageAdd.js
+++ b/src/pages/admin/car/CarManageAdd.js
@@ -217,7 +217,7 @@ function CarManageAdd(props) {
alert("책임자를 선택해주세요.");
return;
}
- if (imageFile !== null) { // 이미지 파일 선택했을 때
+ if (imageFile !== null && !isUpload) { // 이미지 파일 선택했을 때
ImageUrlAxios.get(`?ext=${imageFile.type.split("/", 2)[1]}&dir=car`)
.then((Response) => {
setImgUrl(Response.data);
diff --git a/src/pages/admin/office/OfficeManageAdd.js b/src/pages/admin/office/OfficeManageAdd.js
index 455526f..c05960c 100644
--- a/src/pages/admin/office/OfficeManageAdd.js
+++ b/src/pages/admin/office/OfficeManageAdd.js
@@ -217,7 +217,7 @@ function OfficeManageAdd(props) {
// 이미지 람다 호출
const getImageUrl = () => {
// todo: 검사 다 하기
- if (imageFile !== null) { // 이미지 파일 선택했을 때
+ if (imageFile !== null && !isUpload) { // 이미지 파일 선택했을 때 && 업로드 안했을 때
ImageUrlAxios.get(`?ext=${imageFile.type.split("/", 2)[1]}&dir=office`)
.then((Response) => {
setImgUrl(Response.data);
diff --git a/src/pages/admin/resource/ResourceManageAdd.js b/src/pages/admin/resource/ResourceManageAdd.js
index b120914..8134c74 100644
--- a/src/pages/admin/resource/ResourceManageAdd.js
+++ b/src/pages/admin/resource/ResourceManageAdd.js
@@ -217,7 +217,7 @@ function ResourceManageAdd(props) {
alert("책임자를 선택해주세요.");
return;
}
- if (imageFile !== null) { // 이미지 파일 선택했을 때
+ if (imageFile !== null && !isUpload) { // 이미지 파일 선택했을 때
ImageUrlAxios.get(`?ext=${imageFile.type.split("/", 2)[1]}&dir=resource`)
.then((Response) => {
setImgUrl(Response.data);
diff --git a/src/pages/admin/user/UserManage.js b/src/pages/admin/user/UserManage.js
index 7482af6..854bc93 100644
--- a/src/pages/admin/user/UserManage.js
+++ b/src/pages/admin/user/UserManage.js
@@ -25,7 +25,6 @@ function UserManage(props) {
const currentAffiliation = useRef("");
const currentDepartment = useRef("");
const currentSearchWord = useRef("");
- let departments;
// 유저 목록 조회
const getUserList = (word, affiliation, department) => {
@@ -51,7 +50,7 @@ function UserManage(props) {
}
})
.then((response) => {
- departments = response.data.data.departmentList
+ let departments = response.data.data.departmentList
if (departmentOptionList.length === 0) {
departmentOptionList.push()
departments.map((department) =>
diff --git a/src/pages/basic/equipment/EquipmentAdd.js b/src/pages/basic/equipment/EquipmentAdd.js
new file mode 100644
index 0000000..df7c9b9
--- /dev/null
+++ b/src/pages/basic/equipment/EquipmentAdd.js
@@ -0,0 +1,372 @@
+import React, {useEffect, useRef, useState} from "react";
+import styled from "styled-components";
+import {RightContainer, TitleText, WhiteContainer} from "components/rightContainer/RightContainer";
+import {ManageAddButton, ManageAddButtonImage} from "components/searchBar/ManageSearchBar";
+import {getToken} from "utils/IsLoginUtil";
+import {basicError} from "utils/ErrorHandlerUtil";
+import {EquipmentsAxios, ImageUrlAxios} from "api/AxiosApi";
+import SearchButtonImage from "assets/images/SearchPlus.svg"
+import EmptyImg from "assets/images/EmptyImg.svg"
+import {ExitBtn} from "components/modal/BigModal";
+import axios from "axios";
+import {useParams} from "react-router-dom";
+import {getImgKey} from "utils/ImageUtil";
+import {DropBox} from "components/capsule/DropBox";
+
+const MarginWhiteContainer = styled(WhiteContainer)`
+ padding: 40px;
+ box-sizing: border-box;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+`
+
+const ColumnContainer = styled.div`
+ height: 40px;
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ margin-bottom: 40px;
+`
+
+const ShortColumnContainer = styled(ColumnContainer)`
+ width: 50%;
+`
+
+const ImgColumnContainer = styled(ShortColumnContainer)`
+ margin-bottom: 0;
+ height: 150px;
+ width: 300px;
+`
+
+const TitleLabel = styled.label`
+ color: #8741CB;
+ font-size: 20px;
+ width: 100px;
+ min-width: 100px;
+ text-align: left;
+`
+
+const InfoInput = styled.input.attrs({type: 'text'})`
+ flex: 1;
+ height: 20px;
+ border-radius: 8px;
+ border: 2px solid #E6E6E6;
+ font-size: 20px;
+ padding: 10px;
+`
+
+const DescriptionContainer = styled(ColumnContainer)`
+ height: 60px;
+`
+
+const DescriptionInput = styled.textarea`
+ flex: 1;
+ height: 100%;
+ border-radius: 8px;
+ border: 2px solid #E6E6E6;
+ font-size: 20px;
+ padding: 10px;
+`
+
+const AddButtonContainer = styled.div`
+ width: 100%;
+ height: fit-content;
+ display: flex;
+ justify-content: flex-end;
+`
+
+const ImageAddContainer = styled.div`
+ width: 100px;
+ height: 40px;
+ margin-left: 10px;
+`
+
+const ImageAddButton = styled.button`
+ min-width: 100px;
+ height: 100%;
+ border-radius: 8px;
+ border: none;
+ filter: drop-shadow(0px 2px 2px rgba(0, 0, 0, 0.25));
+ font-size: 16px;
+`
+
+const ImageInfoContainer = styled.div`
+ width: 320px;
+ min-width: 320px;
+ height: 180px;
+ border-radius: 8px;
+ border: 2px solid #E6E6E6;
+ overflow: clip;
+ position: relative;
+`
+
+const AbExitBtn = styled(ExitBtn)`
+ position: absolute;
+ top: 0;
+ right: 0;
+ color: #8741CB;
+`
+
+const PreviewImage = styled.img`
+ width: 320px;
+ height: 180px;
+ object-fit: contain;
+`
+
+function EquipmentManageAdd(props) {
+ let {equipmentId} = useParams();
+
+ const initialValue = {
+ name: null,
+ quantity: null,
+ place: null,
+ description: null,
+ category: null
+ };
+ const [inputValues, setInputValues] = useState(initialValue);
+ const {name, quantity, place, description, category} = inputValues;
+ const [categoryOptionList, setCategoryOptionList] = useState([]);
+ const [imageSrc, setImgSrc] = useState(null);
+ const [imageFile, setImageFile] = useState(null);
+ const [imageUrl, setImgUrl] = useState(null);
+ const [isUpload, setIsUpload] = useState(false);
+ const [equipmentInfo, setEquipmentInfo] = useState(null)
+ const imageInput = useRef(null);
+
+ const onChangeInput = event => {
+ const {value, name: inputName} = event.target;
+ setInputValues({...inputValues, [inputName]: value});
+ }
+
+ const changeImageFile = () => {
+ imageInput.current.click();
+ };
+
+ const handleChange = (e) => {
+ setImageFile(e.target.files[0])
+ const reader = new FileReader();
+ reader.readAsDataURL(e.target.files[0]);
+ reader.onloadend = () => {
+ setImgSrc(reader.result);
+ };
+ };
+
+ // 비품 기존 정보 호출
+ const getEquipmentInfo = () => {
+ EquipmentsAxios.get(`/${equipmentId}`, {
+ headers: {
+ Authorization: getToken()
+ }
+ })
+ .then((Response) => {
+ setEquipmentInfo(Response.data.data);
+ setInputValues({
+ ...inputValues,
+ name: Response.data.data.name,
+ quantity: Response.data.data.quantity,
+ category: Response.data.data.category,
+ place: Response.data.data.location,
+ description: Response.data.data.description
+ });
+ setImgUrl(Response.data.data.imgUrl);
+ setImgSrc(Response.data.data.imgUrl);
+ })
+ .catch((Error) => {
+ basicError(Error)
+ window.history.back()
+ })
+ }
+ useEffect(() => {
+ getCategoryList();
+ if (equipmentId !== undefined) {
+ getEquipmentInfo();
+ }
+ }, [])
+
+ // 카테고리 리스트 검색
+ const getCategoryList = () => {
+ EquipmentsAxios.get(`categories`, {
+ headers: {
+ Authorization: getToken()
+ }
+ })
+ .then((Response) => {
+ let categories = Response.data.data.categoryNames
+ if (categoryOptionList.length === 0) {
+ setCategoryOptionList((prevList) => [...prevList, ])
+ categories.map((category) =>
+ setCategoryOptionList((prevList) => [...prevList,
+ ]))
+ }
+ })
+ .catch((error) => {
+ basicError(error)
+ });
+ };
+
+ const deleteImageFile = () => {
+ setImageFile(null);
+ setIsUpload(false);
+ imageInput.current.value = "";
+ setImgSrc(null)
+ setImgUrl(null)
+ };
+
+ // 이미지 람다 호출
+ const getImageUrl = () => {
+ // todo: 검사 다 하기
+ if (imageFile !== null && !isUpload) { // 이미지 파일 선택했을 때
+ ImageUrlAxios.get(`?ext=${imageFile.type.split("/", 2)[1]}&dir=equipment`)
+ .then((Response) => {
+ setImgUrl(Response.data);
+ })
+ .catch((error) => {
+ console.log(error)
+ });
+ } else {
+ if (equipmentInfo !== null) { // 수정일 때
+ editEquipment();
+ } else {
+ addEquipment();
+ }
+ }
+ }
+
+ // s3에 이미지 업로드
+ const uploadImage = () => {
+ axios.put(imageUrl.presignedUrl, imageFile, {
+ headers: {
+ 'Content-Type': 'multipart/form-data' // Content-Type 헤더 설정
+ }
+ })
+ .then(function (rep) {
+ setIsUpload(true);
+ })
+ .catch(function (err) {
+ console.log(err)
+ alert("이미지 등록에 실패했습니다. 다시 시도해주세요.");
+ });
+ }
+
+ useEffect(() => {
+ if (imageUrl !== null && imageFile !== null)
+ uploadImage();
+ }, [imageUrl]);
+
+ useEffect(() => {
+ if (isUpload) {
+ if (equipmentInfo !== null) editEquipment();
+ else addEquipment();
+ }
+ }, [isUpload]);
+
+ const addEquipment = () => {
+ EquipmentsAxios.post(``, {
+ category: category,
+ description: description,
+ quantity: quantity,
+ location: place,
+ name: name,
+ imgKey: imageFile === null ? null : `equipment/${imageUrl.imageKey}`,
+ },
+ {
+ headers: {
+ Authorization: getToken()
+ },
+ })
+ .then((Response) => {
+ alert("비품 등록이 완료되었습니다.");
+ window.location.href = `/equipments`
+ })
+ .catch((error) => {
+ basicError(error)
+ });
+ };
+
+ const editEquipment = () => {
+ EquipmentsAxios.patch(`/${equipmentId}`, {
+ category: category,
+ description: description,
+ quantity: quantity,
+ location: place,
+ name: name,
+ imgKey: imageFile === null ? getImgKey(imageUrl) : `equipment/${imageUrl.imageKey}`,
+ },
+ {
+ headers: {
+ Authorization: getToken()
+ },
+ })
+ .then((Response) => {
+ alert("비품 수정이 완료되었습니다.");
+ window.location.href = `/equipments`
+ })
+ .catch((error) => {
+ basicError(error)
+ });
+ }
+
+ return (
+
+ {equipmentInfo === null ? "비품 추가" : "비품 수정"}
+
+
+
+ 비품명
+
+
+
+
+ 수량
+
+
+
+
+ 보관장소
+
+
+
+
+ 카테고리
+
+
+
+
+ 설명
+
+
+
+
+ 첨부사진
+
+
+ {imageSrc !== null && ×}
+
+
+ 파일선택
+
+
+
+
+
+
+
+ {equipmentInfo === null ? "비품 추가" : "비품 수정"}
+
+
+
+
+
+ );
+}
+
+export default EquipmentManageAdd;
diff --git a/src/pages/basic/equipment/EquipmentList.js b/src/pages/basic/equipment/EquipmentList.js
index 7753c0a..c8aa113 100644
--- a/src/pages/basic/equipment/EquipmentList.js
+++ b/src/pages/basic/equipment/EquipmentList.js
@@ -11,10 +11,9 @@ import SearchButtonImage from "../../../assets/images/SearchPlus.svg";
import {ManageAddButton, ManageAddButtonImage} from "../../../components/searchBar/ManageSearchBar";
const CardList = styled.div`
- width: 100%;
- display: flex;
- flex-wrap: wrap;
- justify-content: space-between;
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(calc(33.33% - 15px), 1fr));
+ grid-gap: 15px;
`
const Container = styled(WhiteContainer)`
@@ -55,13 +54,17 @@ function EquipmentList(props) {
searchEquipment();
}, []);
+ const moveToAdd = () => {
+ window.location.href = `/equipments/add`
+ }
+
return (
비품 내역
-
+
신규 비품 추가