From 5f0bed4df0823a24d3d4cff5657f8b1dddfa91d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=BC=ED=98=95?= Date: Tue, 26 Mar 2024 18:00:33 +0900 Subject: [PATCH] =?UTF-8?q?=EA=B4=80=EB=A0=A8=EC=82=AC=EC=9D=B4=ED=8A=B8?= =?UTF-8?q?=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EB=93=9C=EB=9E=98=EA=B7=B8?= =?UTF-8?q?=EC=95=A4=EB=93=9C=EB=A1=AD=20=EC=97=85=EB=A1=9C=EB=93=9C,=20?= =?UTF-8?q?=EC=A7=81=EC=A0=91=EC=84=A0=ED=83=9D=20=EC=97=85=EB=A1=9C?= =?UTF-8?q?=EB=93=9C,=20=EB=AF=B8=EB=A6=AC=EB=B3=B4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/css/component.css | 75 ++++++++++ .../config/aboutSiteMgt/AboutSiteModal.jsx | 138 +++++++++++++++--- .../admin/config/AdminConfigController.java | 11 +- .../config/service/AdminConfigService.java | 42 +++++- 4 files changed, 242 insertions(+), 24 deletions(-) diff --git a/egovframe-template-simple-react-contribution/src/css/component.css b/egovframe-template-simple-react-contribution/src/css/component.css index 1dc342c..23837cf 100644 --- a/egovframe-template-simple-react-contribution/src/css/component.css +++ b/egovframe-template-simple-react-contribution/src/css/component.css @@ -332,4 +332,79 @@ select::-ms-expand {display:none;} .recharts-legend-item-text { font-size: 11px; +} + +.uploadIcon { + width: 100px; + height: 100px; + pointer-events: none; +} + +.file { + display: none; +} + +.file::file-selector-button { + font-size: 14px; + background: #fff; + border: 1px solid #111; + border-radius: 12px; + padding: 4px 32px; + cursor: pointer; +} + +.preview { + width: 400px; + height: 350px; + margin: auto; + background-color: #fff; + border-radius: 5px; + border: 3px dashed #eee; + padding: 70px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + cursor: pointer; +} + +.preview_image { + max-width: 100%; + max-height: 100%; + object-fit: contain; +} + +.preview:hover { + border-color: #111; +} + +.preview_msg { + font-weight: 500; + font-size: 18px; + margin: 20px 0 10px; +} + +.preview_desc { + margin: 0; + font-size: 14px; +} + +.preview_info { + width: 100%; + list-style: none; + padding: 0; + gap: 16px; + display: flex; + flex-direction: column; +} + +.preview_info .info_key { + display: block; + font-weight: 500; + font-size: 12px; + margin-bottom: 4px; +} + +.preview_info .info_value { + font-size: 14px; } \ No newline at end of file diff --git a/egovframe-template-simple-react-contribution/src/pages/admin/config/aboutSiteMgt/AboutSiteModal.jsx b/egovframe-template-simple-react-contribution/src/pages/admin/config/aboutSiteMgt/AboutSiteModal.jsx index 371d331..3a0044e 100644 --- a/egovframe-template-simple-react-contribution/src/pages/admin/config/aboutSiteMgt/AboutSiteModal.jsx +++ b/egovframe-template-simple-react-contribution/src/pages/admin/config/aboutSiteMgt/AboutSiteModal.jsx @@ -19,6 +19,7 @@ function AboutSiteModal({props, reloadFunction}) { const navigate = useNavigate(); const location = useLocation(); const checkRef = useRef([]); + const fileInputRef = useRef(null); console.log("AboutSiteModal [location] : ", location); @@ -32,7 +33,18 @@ function AboutSiteModal({props, reloadFunction}) { useEffect(() => { initMode(); - // eslint-disable-next-line react-hooks/exhaustive-deps + const fileDOM = document.querySelector('#file'); + const preview = document.querySelector('.preview'); + + if(fileDOM) { + fileDOM.addEventListener('change', () => { + const reader = new FileReader(); + reader.onload = ({target}) => { + preview.src = target.result; + }; + reader.readAsDataURL(fileDOM.files[0]); + }); + } }, []); const initMode = () => { @@ -45,24 +57,22 @@ function AboutSiteModal({props, reloadFunction}) { e.preventDefault(); e.stopPropagation(); const form = e.target; - const info = { - siteTitle: form.siteTitle.value, - siteUrl: form.siteUrl.value, - fileGrpId: form.fileGrpId.value, - siteOrder: form.siteOrder.value, - useYn: form.useYn.value - } + const formData = new FormData(form); // 새 FormData 객체 생성 + + // FormData 객체에 파일 데이터 추가 + console.log("@@@ current : " + fileInputRef.current); + console.log("@@@ file : " + fileInputRef.current.files[0]); + formData.append('file', currentFile); + formData.append('fileGrpId', props.fileGrpId); + if (modeInfo.mode === CODE.MODE_MODIFY) { - info.siteSeq = props.siteSeq; + formData.append('siteSeq', props.siteSeq); // 수정 모드일 때 필요한 추가 정보 추가 } EgovNet.requestFetch( '/admin/config/partner-site-mgt', { method: "PUT", - headers: { - 'Content-type': 'application/json' - }, - body: JSON.stringify(info) + body: formData }, (resp) => { if (Number(resp.resultCode) === Number(CODE.RCV_SUCCESS)) { @@ -102,6 +112,100 @@ function AboutSiteModal({props, reloadFunction}) { } } + const Logo = () => ( + + + + + ) + + const [currentFile, setCurrentFile] = useState(null); + const [uploadedInfo, setUploadedInfo] = useState(null); + const [previewImage, setPreviewImage] = useState(null); + + const UploadBox = () => { + const [isActive, setActive] = useState(false); + + const onDragEnter = (e: React.DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + }; + const onDragLeave = (e: React.DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + }; + const onDragOver = (e: React.DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + }; + + const setFileInfo = (file) => { + const { name, size: byteSize, type } = file; + const isImage = type.includes('image'); + const size = (byteSize / (1024 * 1024)).toFixed(2) + 'mb'; + setUploadedInfo({ name, size, type }); // name, size, type 정보를 uploadedInfo에 저장 + + if (!isImage) { + setUploadedInfo({ name, size, type }); + return; + } + const reader = new FileReader(); + reader.onload = () => { + setPreviewImage(reader.result); + setUploadedInfo({ name, size, type, imageUrl: String(reader.result) }); + }; + reader.readAsDataURL(file); + }; + + const onDrop = (e: React.DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + setActive(false); + + const droppedFile = e.dataTransfer.files[0]; + console.log("@@@ handleDrop file : " + droppedFile); + if (droppedFile.type.startsWith('image/')) { + setCurrentFile(droppedFile); + setFileInfo(droppedFile); + } else { + // 이미지 파일이 아닌 경우에 대한 처리 + alert('이미지 파일만 업로드할 수 있습니다.'); + } + }; + + const handleUpload = (e: ChangeEvent) => { + const file = e.target.files[0]; + console.log("@@@ handleUpload file : " + file); + if (file.type.startsWith('image/')) { + setCurrentFile(file); + setFileInfo(file); + } else { + // 이미지 파일이 아닌 경우에 대한 처리 + alert('이미지 파일만 업로드할 수 있습니다.'); + } + }; + + return ( + + ); + }; + console.log("------------------------------AboutSiteModal [End]"); console.groupEnd("AboutSiteModal"); @@ -118,6 +222,7 @@ function AboutSiteModal({props, reloadFunction}) { +
{editPartnerSite(e)}} noValidate>
@@ -134,13 +239,6 @@ function AboutSiteModal({props, reloadFunction}) { defaultValue={props?.siteUrl}/>
-
-
필수
-
- -
-
필수
diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/AdminConfigController.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/AdminConfigController.java index 92412e5..5ff7f7f 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/AdminConfigController.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/AdminConfigController.java @@ -24,6 +24,7 @@ import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.validation.Errors; import org.springframework.validation.FieldError; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; @@ -516,7 +517,12 @@ public class AdminConfigController extends BaseController { @ApiResponse(responseCode = "403", description = "인가된 사용자가 아님") }) @RequestMapping(method = RequestMethod.PUT, value = "/partner-site-mgt") - public ResultVO savePartnerSite(@RequestBody @Valid TnPartnerSite tnPartnerSite, Errors errors, @AuthenticationPrincipal LoginVO user) { + public ResultVO savePartnerSite( + @Valid TnPartnerSite tnPartnerSite, + HttpServletRequest request, + Errors errors, + @RequestParam(required = false) MultipartFile[] file, + @AuthenticationPrincipal LoginVO user) throws Exception { ResultVO resultVO = new ResultVO(); if (user == null) { resultVO.setResultCode(ResponseCode.TOKEN_EXPIRED.getCode()); @@ -531,7 +537,8 @@ public class AdminConfigController extends BaseController { resultVO.setResultMessage(msg.toString()); } else { System.out.println("@@@ bbs.getBbsSeq() : " + tnPartnerSite.getSiteSeq()); - adminConfigService.savePartnerSite(tnPartnerSite, user.getId()); + System.out.println("@@@ file : " + file); + adminConfigService.savePartnerSite(tnPartnerSite, request, user, file); resultVO.setResultCode(ResponseCode.SUCCESS.getCode()); } } diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/service/AdminConfigService.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/service/AdminConfigService.java index ba9a1a8..bc1ed0f 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/service/AdminConfigService.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/config/service/AdminConfigService.java @@ -8,17 +8,24 @@ import com.dbnt.kcscbackend.admin.config.mapper.TcMenuMapper; import com.dbnt.kcscbackend.admin.config.repository.TbMenuRoleRepository; import com.dbnt.kcscbackend.admin.config.repository.TcMenuRepository; import com.dbnt.kcscbackend.admin.config.repository.TnPartnerSiteRepository; +import com.dbnt.kcscbackend.auth.entity.LoginVO; import com.dbnt.kcscbackend.commonCode.entity.TcCodeGrp; import com.dbnt.kcscbackend.commonCode.entity.TcCodeItem; import com.dbnt.kcscbackend.commonCode.repository.TcCodeGrpRepository; import com.dbnt.kcscbackend.commonCode.repository.TcCodeItemRepository; +import com.dbnt.kcscbackend.file.entity.TnAttachFile; +import com.dbnt.kcscbackend.file.service.FileService; import lombok.RequiredArgsConstructor; import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletRequest; +import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.Optional; @@ -32,6 +39,7 @@ public class AdminConfigService extends EgovAbstractServiceImpl { private final TbMenuRoleRepository menuRoleRepository; private final TcMenuMapper menuMapper; private final TnPartnerSiteRepository tnPartnerSiteRepository; + private final FileService fileService; public List selectCodeGrpList(){ return codeGrpRepository.findByUseYn("Y"); @@ -175,17 +183,47 @@ public class AdminConfigService extends EgovAbstractServiceImpl { return tnPartnerSiteRepository.findAllByOrderBySiteOrder(); } - @Transactional - public void savePartnerSite(TnPartnerSite tnPartnerSite, String userId) { + /** + * 파일이 저장될 중간 경로를 생성한다. + * D:/kcscUploadFiles/XXXX/abc.jpg XXXX에 해당하는 경로다. + * + * @return 중간 경로 + */ + private String getMiddlePath() { + //파일이 저장될 경로를 생성한다. + String domainPath = "partnerSite"; + Date nowDate = new Date(); + String strNowYyyy = new SimpleDateFormat("yyyy").format(nowDate); + String strNowYyyyMmdd = new SimpleDateFormat("yyyyMMdd").format(nowDate); + String middlePath = domainPath + "/" + strNowYyyy + "/" + strNowYyyyMmdd + "/"; + + return middlePath; + } + + public void savePartnerSite(TnPartnerSite tnPartnerSite, HttpServletRequest request, LoginVO user, MultipartFile[] file) throws Exception { if (tnPartnerSite.getSiteSeq() == null) { + String fileGrpId = fileService.addTnAttachFile(request, user, file, this.getMiddlePath()); + tnPartnerSite.setFileGrpId(fileGrpId); tnPartnerSiteRepository.save(tnPartnerSite); } else { + String fileGrpId = tnPartnerSite.getFileGrpId(); + System.out.println("@@@ fileGrpId : " + fileGrpId); + if (file != null && file.length > 0) { + List tnAttachFileList = fileService.findByFileGrpId(fileGrpId); + if (tnAttachFileList != null) { + for (TnAttachFile item : tnAttachFileList) { + fileService.deleteTnAttachFile(request, user, item.getFileSeq().longValue()); + } + } + fileGrpId = fileService.addTnAttachFile(request, user, file, this.getMiddlePath()); + } TnPartnerSite savedPartnerSite = tnPartnerSiteRepository.findById(tnPartnerSite.getSiteSeq()).orElse(null); savedPartnerSite.setSiteTitle(tnPartnerSite.getSiteTitle()); savedPartnerSite.setSiteUrl(tnPartnerSite.getSiteUrl()); savedPartnerSite.setFileGrpId(tnPartnerSite.getFileGrpId()); savedPartnerSite.setSiteOrder(tnPartnerSite.getSiteOrder()); savedPartnerSite.setUseYn(tnPartnerSite.getUseYn()); + savedPartnerSite.setFileGrpId(fileGrpId); tnPartnerSiteRepository.save(savedPartnerSite); } }