Compare commits

..

4 Commits

Author SHA1 Message Date
thkim 52cfa4a257 fix: K) 위원회 일정관리 날짜형식 변경 2024-03-18 17:56:38 +09:00
thkim 964b0ebf34 fix: K) 위원회 일정관리 날짜형식 변경 2024-03-18 17:56:07 +09:00
thkim 72e996193a fix: K) 첨부파일 - 기능 오류
관리자 - 팝업 관리 > 특정 글 수정 시, file download 적용 건.
2024-03-18 17:42:25 +09:00
thkim 3075d39606 feat: 관리자 - 팝업 관리 > 특정 글 수정 시, 특정 file 삭제하는 API 추가 건 2024-03-18 15:28:38 +09:00
11 changed files with 351 additions and 95 deletions

View File

@ -1,9 +1,11 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import Button from '@mui/material/Button';
import AttachFileIcon from '@mui/icons-material/AttachFile'; import AttachFileIcon from '@mui/icons-material/AttachFile';
import IconButton from '@mui/material/IconButton'; import IconButton from '@mui/material/IconButton';
import DeleteIcon from '@mui/icons-material/Delete'; import DeleteIcon from '@mui/icons-material/Delete';
import styled from "styled-components"; import styled from "styled-components";
import FileDragDrop from "./FileDragDrop"; import FileDragDrop from "./FileDragDrop";
import * as File from "utils/file";
const StyledDiv = styled.div` const StyledDiv = styled.div`
label { label {
@ -14,7 +16,7 @@ const StyledDiv = styled.div`
border-radius: 6px; border-radius: 6px;
& > div { & > div {
height: 100%; height: 100%;
line-height: 37px; line-height: auto;
padding: 20px; padding: 20px;
color: #999999; color: #999999;
} }
@ -31,7 +33,6 @@ function AttachFile(props) {
useEffect(function () { useEffect(function () {
const labelEle = document.querySelectorAll("label[for='preDataFile']")[0]; const labelEle = document.querySelectorAll("label[for='preDataFile']")[0];
console.log(labelEle); // NodeList(3) [li, li, li]
// event // event
const onClickLabel = (e) => { const onClickLabel = (e) => {
@ -43,15 +44,16 @@ function AttachFile(props) {
e.preventDefault(); e.preventDefault();
return false; return false;
} else { } else {
if( if(
oldTagName === 'path' || oldTagName === 'path' ||
oldTagName === 'svg' || oldTagName === 'svg' ||
oldTagName === 'button' oldTagName === 'button'
) { ) {
oldTagName = undefined; oldTagName = undefined;
e.preventDefault(); e.preventDefault();
return false; return false;
} }
} }
} }
@ -129,14 +131,12 @@ function AttachFile(props) {
} }
Object.keys(files).forEach(function(key, index) { Object.keys(files).forEach(function(key, index) {
//console.log(key, props.files[key]);
if( typeof files[key].name === 'undefined' ) { if( typeof files[key].name === 'undefined' ) {
return; return;
} }
files[key].index=nNewIndex++; files[key].index=nNewIndex++;
items.push( files[key] ); items.push( files[key] );
}); });
console.log('%o\n%o', files, items);
setFileItem(items); setFileItem(items);
props.setFiles(items); props.setFiles(items);
}; };
@ -144,6 +144,7 @@ function AttachFile(props) {
const onClickDeleteItem = (e, targetEle) => { const onClickDeleteItem = (e, targetEle) => {
const dataIndex = Number(targetEle.getAttribute('data-index')); const dataIndex = Number(targetEle.getAttribute('data-index'));
let items = []; let items = [];
@ -157,7 +158,39 @@ function AttachFile(props) {
setFileItem(items); setFileItem(items);
props.setFiles(items); props.setFiles(items);
} };
const onClickFile = (e, item) => {
e = e || window.event;
const target = e.target || e.srcElement;
const dataSeq = target.getAttribute('data-seq');
if( dataSeq ) {
// server download
const fileSeq = Number(dataSeq);
File.download(fileSeq);
} else {
// file
const file = item;
let fr = new FileReader();
fr.readAsDataURL(file);
var blob = new Blob([file], { type: "application/pdf" });
var objectURL = window.URL.createObjectURL(blob);
if (navigator.appVersion.toString().indexOf('.NET') > 0) {
window.navigator.msSaveOrOpenBlob(blob, item.name);
} else {
var link = document.createElement('a');
link.href = objectURL;
link.download = item.name;
document.body.appendChild(link);
link.click();
link.remove();
}
}
};
return ( return (
<StyledDiv> <StyledDiv>
@ -179,11 +212,11 @@ function AttachFile(props) {
fileItem.map((item) => ( fileItem.map((item) => (
<span key={item.index} data-index={item.index}> <span key={item.index} data-index={item.index}>
<IconButton aria-label="delete" size="small" <IconButton aria-label="delete" size="small"
sx={{color: '#094c72', padding: '2px 4px'}}
onClick={(e)=> { onClick={(e)=> {
e = e || window.event; e = e || window.event;
const target = e.target || e.srcElement; const target = e.target || e.srcElement;
console.log('%o', target);
const tagName = String(target.tagName).toLowerCase(); const tagName = String(target.tagName).toLowerCase();
// target // target
@ -199,11 +232,20 @@ function AttachFile(props) {
> >
<DeleteIcon fontSize="small" /> <DeleteIcon fontSize="small" />
</IconButton> </IconButton>
{item.name}<br /> <Button
variant="text"
sx={{textTransform: 'none', color: '#032b77', fontSize: '14px', padding: '2px 5px 4px 5px'}}
onClick={(e)=> {
onClickFile(e, item);
}}
key={item.index}
data-seq={item.seq}
>{item.name}</Button>
<br />
</span> </span>
)) ))
: :
<span><AttachFileIcon /> 파일을 마우스로 끌어놓으세요.</span> <span>여기를 누르시거나 파일을 마우스로 끌어놓으세요.</span>
} }
</div> </div>
</FileDragDrop> </FileDragDrop>

View File

@ -3,6 +3,8 @@ import React, { useState, useEffect, useCallback } from 'react';
import { Link, useLocation } from 'react-router-dom'; import { Link, useLocation } from 'react-router-dom';
import styled from "styled-components"; import styled from "styled-components";
import CircularProgress from '@mui/material/CircularProgress';
import Box from '@mui/material/Box';
import * as EgovNet from 'api/egovFetch'; import * as EgovNet from 'api/egovFetch';
@ -62,7 +64,7 @@ function Schedules(props) {
const [searchCondition, setSearchCondition] = useState(location.state?.searchCondition || { schdulSe: '', year: TODAY.getFullYear(), month: TODAY.getMonth(), date: TODAY.getDate() }); const [searchCondition, setSearchCondition] = useState(location.state?.searchCondition || { schdulSe: '', year: TODAY.getFullYear(), month: TODAY.getMonth(), date: TODAY.getDate() });
const [calendarTag, setCalendarTag] = useState([]); const [calendarTag, setCalendarTag] = useState([]);
const [scheduleList, setScheduleList] = useState([]); const [scheduleList, setScheduleList] = useState();
const innerConsole = (...args) => { const innerConsole = (...args) => {
console.log(...args); console.log(...args);
@ -189,7 +191,7 @@ function Schedules(props) {
if (day !== 0) {// if (day !== 0) {//
let sDate = day.toString().length === 1 ? "0" + day.toString() : day.toString(); let sDate = day.toString().length === 1 ? "0" + day.toString() : day.toString();
let iUseDate = Number(mutsUseYearMonth + sDate); let iUseDate = Number(mutsUseYearMonth + sDate);
if (scheduleList.length > 0) {// if (scheduleList && scheduleList.length > 0) {//
return ( return (
<td key={keyIdx++}> <td key={keyIdx++}>
<Link to={{pathname: URL.ADMIN__COMMITTEE__SCHEDULES__CREATE}} state={{ iUseDate: mutsUseYearMonth + sDate + "000000"}} className="day" <Link to={{pathname: URL.ADMIN__COMMITTEE__SCHEDULES__CREATE}} state={{ iUseDate: mutsUseYearMonth + sDate + "000000"}} className="day"
@ -346,10 +348,24 @@ function Schedules(props) {
<th></th> <th></th>
<th></th> <th></th>
</tr> </tr>
</thead> </thead>
<tbody> {
{true && calendarTag} typeof scheduleList === 'undefined'
</tbody> ?
<tbody>
<tr>
<td colSpan="7">
<Box sx={{ display: 'flex', width: '100%', padding: '250px 0px' }}>
<CircularProgress sx={{ margin: '0px auto', }}/>
</Box>
</td>
</tr>
</tbody>
:
<tbody>
{calendarTag}
</tbody>
}
</table> </table>
</div> </div>
</StyledDiv> </StyledDiv>

View File

@ -36,6 +36,25 @@ function SchedulesDetail(props) {
} }
const convertDate = (str) => {
if( !str ) {
return null;
}
let year = str.substring(0, 4);
let month = str.substring(5, 7);
let date = str.substring(8, 10);
let hour = str.substring(11, 13);
let minute = str.substring(14, 16);
return {
year: year,
month: month,
date: date,
hour: hour,
minute: minute,
dateForm: year + "-" + month + "-" + date + " " + hour + ":" + minute + ""
}
}
const onClickDeleteSchedule = (schdulId) => { const onClickDeleteSchedule = (schdulId) => {
const deleteBoardURL = `/schedule/${schdulId}`; const deleteBoardURL = `/schedule/${schdulId}`;
@ -115,8 +134,8 @@ function SchedulesDetail(props) {
<dd>{scheduleDetail.location}</dd> <dd>{scheduleDetail.location}</dd>
</dl> </dl>
<dl> <dl>
<dt>날짜/시간</dt> <dt>날짜/시간 </dt>
<dd> {scheduleDetail.startDate} ~ {scheduleDetail.endDate}</dd> <dd> { convertDate(scheduleDetail?.startDate)?.dateForm} ~ {convertDate(scheduleDetail?.endDate)?.dateForm} </dd>
</dl> </dl>
<dl> <dl>
<dt>내용</dt> <dt>내용</dt>

View File

@ -1,6 +1,7 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { Link, useLocation, useNavigate } from 'react-router-dom'; import { Link, useLocation, useNavigate } from 'react-router-dom';
import Switch from '@mui/material/Switch'; import Switch from '@mui/material/Switch';
import LinearProgress from '@mui/material/LinearProgress';
import * as EgovNet from 'api/egovFetch'; import * as EgovNet from 'api/egovFetch';
import URL from 'constants/url'; import URL from 'constants/url';
@ -54,7 +55,7 @@ function PopUp(props) {
const location = useLocation(); const location = useLocation();
const navigate = useNavigate(); const navigate = useNavigate();
const [listPopup, setListPopup] = useState([]); const [listPopup, setListPopup] = useState();
const [searchCondition, setSearchCondition] = useState(location.state?.searchCondition || { pageIndex: 1, searchCnd: '0', searchWrd: '' }); const [searchCondition, setSearchCondition] = useState(location.state?.searchCondition || { pageIndex: 1, searchCnd: '0', searchWrd: '' });
const [paginationInfo, setPaginationInfo] = useState({}); const [paginationInfo, setPaginationInfo] = useState({});
@ -152,10 +153,13 @@ function PopUp(props) {
</div> </div>
<div className="result"> <div className="result">
{/* <!-- case : 데이터 없을때 --> */} {/* <!-- case : 데이터 없을때 --> */}
{listPopup.length === 0 && {typeof listPopup === 'undefined' &&
<p className="no_data" key="0"><LinearProgress /></p>
}
{listPopup && listPopup.length === 0 &&
<p className="no_data" key="0">검색된 결과가 없습니다.</p> <p className="no_data" key="0">검색된 결과가 없습니다.</p>
} }
{listPopup.map((it)=>( {listPopup && listPopup.map((it)=>(
<div className='list_item' key={it.seq}> <div className='list_item' key={it.seq}>
<div>{it.number}</div> <div>{it.number}</div>
<div className="al"><Link to={URL.ADMIN__CONTENTS__POP_UP__MODIFY} state={{popupId: it.seq} } key={it.seq}>{it.popupTitle}</Link></div> <div className="al"><Link to={URL.ADMIN__CONTENTS__POP_UP__MODIFY} state={{popupId: it.seq} } key={it.seq}>{it.popupTitle}</Link></div>

View File

@ -1,6 +1,7 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { Link, useLocation, useNavigate } from 'react-router-dom'; import { Link, useLocation, useNavigate } from 'react-router-dom';
import DatePicker from "react-datepicker"; import DatePicker from "react-datepicker";
import LinearProgress from '@mui/material/LinearProgress';
import AttachFile from "../../../../components/file/AttachFile"; import AttachFile from "../../../../components/file/AttachFile";
import RichTextEditor from "../../../../components/editor/RichTextEditor"; import RichTextEditor from "../../../../components/editor/RichTextEditor";
import AlertDialogSlide from "../../../../components/alert/AlertDialogSlide"; import AlertDialogSlide from "../../../../components/alert/AlertDialogSlide";
@ -164,15 +165,17 @@ function PopupEditor(props) {
formData.append("contents", text); formData.append("contents", text);
// //
//formData.append("files", files); if( files ) {
for(let i=0; i<files.length; i++) { for(let i=0; i<files.length; i++) {
// seq server upload file continue if( files[i].seq ) {
if( files[i].seq ) { // file seq .
continue; formData.append("survivingFiles", files[i].seq);
} continue;
formData.append("files", files[i]); }
formData.append("files", files[i]);
}
} }
if (formValidator(formData)) { if (formValidator(formData)) {
const requestOptions = { const requestOptions = {
method: modeInfo.method, method: modeInfo.method,
@ -207,7 +210,7 @@ function PopupEditor(props) {
} }
} }
const onClickDelete = (popupId) => { const onClickDelete = (popupId) => {
const deleteBoardURL = `/contents/api/popup-manage/${popupId}`; const deleteBoardURL = `/contents/api/popup-manage/${popupId}`;
@ -235,6 +238,27 @@ function PopupEditor(props) {
setConfirm({...confirm, open: true, body: "삭제하시겠습니까?", yesCallback: requestTask}); setConfirm({...confirm, open: true, body: "삭제하시겠습니까?", yesCallback: requestTask});
} }
// file
const deleteFile = (fileSeq) => {
const deleteFileURL = `/contents/api/popup-manage/file/${fileSeq}`;
const requestOptions = {
method: "DELETE",
headers: {
'Content-type': 'application/json',
}
}
EgovNet.requestFetch(deleteFileURL,
requestOptions,
(resp) => {
}
);
}
const onClickList = (e) => { const onClickList = (e) => {
const requestTask = () => { const requestTask = () => {
@ -315,6 +339,7 @@ function PopupEditor(props) {
<dl> <dl>
<dt><label htmlFor="title">제목</label><span className="req">필수</span></dt> <dt><label htmlFor="title">제목</label><span className="req">필수</span></dt>
<dd> <dd>
{modeInfo.mode === CODE.MODE_MODIFY && typeof popupDetail.title === 'undefined' && <LinearProgress /> }
<input className="f_input2 w_full" type="text" name="title" title="제목" id="title" placeholder="제목을 입력하세요." <input className="f_input2 w_full" type="text" name="title" title="제목" id="title" placeholder="제목을 입력하세요."
value={popupDetail.title} value={popupDetail.title}
onChange={(e) => setPopupDetail({ ...popupDetail, title: e.target.value })} onChange={(e) => setPopupDetail({ ...popupDetail, title: e.target.value })}
@ -364,7 +389,7 @@ function PopupEditor(props) {
<dl className="file-attach-wrapper"> <dl className="file-attach-wrapper">
<dt>첨부파일</dt> <dt>첨부파일</dt>
<dd> <dd>
<AttachFile name="preDataFile" multiple={true} files={files} setFiles={setFiles} serverFiles={serverFiles} fileTypes={fileTypes} /> <AttachFile name="preDataFile" multiple={true} files={files} setFiles={setFiles} serverFiles={serverFiles} fileTypes={fileTypes} deleteFile={deleteFile} />
</dd> </dd>
</dl> </dl>
@ -372,7 +397,13 @@ function PopupEditor(props) {
{/* <!--// 상단 입력 form --> */} {/* <!--// 상단 입력 form --> */}
{/* <!-- 게시판 --> */} {/* <!-- 게시판 --> */}
<RichTextEditor item={text} setText={setText}/> {modeInfo.mode === CODE.MODE_MODIFY && typeof text === 'undefined'
?
<LinearProgress />
:
<RichTextEditor item={text} setText={setText}/>
}
{/* <!--// 게시판 --> */} {/* <!--// 게시판 --> */}
{/* <!-- 버튼영역 --> */} {/* <!-- 버튼영역 --> */}

View File

@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { Link, useLocation, useNavigate } from 'react-router-dom'; import { Link, useLocation, useNavigate } from 'react-router-dom';
import Switch from '@mui/material/Switch'; import LinearProgress from '@mui/material/LinearProgress';
import * as EgovNet from 'api/egovFetch'; import * as EgovNet from 'api/egovFetch';
import URL from 'constants/url'; import URL from 'constants/url';
@ -67,7 +67,7 @@ function StandardResearch(props) {
const location = useLocation(); const location = useLocation();
const navigate = useNavigate(); const navigate = useNavigate();
const [list, setList] = useState([]); const [list, setList] = useState();
const [searchCondition, setSearchCondition] = useState(location.state?.searchCondition || { pageIndex: 1, searchCnd: '0', searchWrd: '' }); const [searchCondition, setSearchCondition] = useState(location.state?.searchCondition || { pageIndex: 1, searchCnd: '0', searchWrd: '' });
const [paginationInfo, setPaginationInfo] = useState({}); const [paginationInfo, setPaginationInfo] = useState({});
@ -167,10 +167,13 @@ function StandardResearch(props) {
</div> </div>
<div className="result"> <div className="result">
{/* <!-- case : 데이터 없을때 --> */} {/* <!-- case : 데이터 없을때 --> */}
{list.length === 0 && {typeof list === 'undefined' &&
<p className="no_data" key="0"><LinearProgress /></p>
}
{list && list.length === 0 &&
<p className="no_data" key="0">검색된 결과가 없습니다.</p> <p className="no_data" key="0">검색된 결과가 없습니다.</p>
} }
{list.map((it)=>( {list && list.map((it)=>(
<div className='list_item' key={it.id}> <div className='list_item' key={it.id}>
<div>{it.number}</div> <div>{it.number}</div>
<div className="al"><Link to={URL.ADMIN__CONTENTS__STANDARDS_RESEARCH__MODIFY} state={{rsId: it.id} } key={it.id}>{it.title}</Link></div> <div className="al"><Link to={URL.ADMIN__CONTENTS__STANDARDS_RESEARCH__MODIFY} state={{rsId: it.id} } key={it.id}>{it.title}</Link></div>

View File

@ -1,6 +1,7 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { Link, useLocation, useNavigate } from 'react-router-dom'; import { Link, useLocation, useNavigate } from 'react-router-dom';
import DatePicker from "react-datepicker"; import DatePicker from "react-datepicker";
import LinearProgress from '@mui/material/LinearProgress';
import EgovAttachFile from 'components/EgovAttachFile'; import EgovAttachFile from 'components/EgovAttachFile';
import RichTextEditor from "../../../../components/editor/RichTextEditor"; import RichTextEditor from "../../../../components/editor/RichTextEditor";
@ -45,12 +46,12 @@ function StandardResearchEditor(props) {
const location = useLocation(); const location = useLocation();
const [modeInfo, setModeInfo] = useState({ mode: props.mode }); const [modeInfo, setModeInfo] = useState({ mode: props.mode });
const [purpose, setPurpose] = useState(""); const [purpose, setPurpose] = useState();
const [purposeOriginal, setPurposeOriginal] = useState(""); const [purposeOriginal, setPurposeOriginal] = useState();
const [content, setContent] = useState(""); const [content, setContent] = useState("");
const [contentOriginal, setContentOriginal] = useState(""); const [contentOriginal, setContentOriginal] = useState();
const [effectContent, setEffectContent] = useState(""); const [effectContent, setEffectContent] = useState("");
const [effectContentOriginal, setEffectContentOriginal] = useState(""); const [effectContentOriginal, setEffectContentOriginal] = useState();
@ -319,6 +320,7 @@ function StandardResearchEditor(props) {
<dl> <dl>
<dt><label htmlFor="title">연구명</label><span className="req">필수</span></dt> <dt><label htmlFor="title">연구명</label><span className="req">필수</span></dt>
<dd> <dd>
{modeInfo.mode === CODE.MODE_MODIFY && typeof standardResearchDetail.title === 'undefined' && <LinearProgress /> }
<input className="f_input2 w_full" type="text" name="title" title="연구명" id="title" placeholder="연구명을 입력하세요." <input className="f_input2 w_full" type="text" name="title" title="연구명" id="title" placeholder="연구명을 입력하세요."
value={standardResearchDetail.title} value={standardResearchDetail.title}
onChange={(e) => setStandardResearchDetail({ ...standardResearchDetail, title: e.target.value })} onChange={(e) => setStandardResearchDetail({ ...standardResearchDetail, title: e.target.value })}
@ -358,6 +360,7 @@ function StandardResearchEditor(props) {
<dl> <dl>
<dt><label htmlFor="director">연구 책임자</label><span className="req">필수</span></dt> <dt><label htmlFor="director">연구 책임자</label><span className="req">필수</span></dt>
<dd> <dd>
{modeInfo.mode === CODE.MODE_MODIFY && typeof standardResearchDetail.director === 'undefined' && <LinearProgress /> }
<input className="f_input2 w_full" type="text" name="director" title="연구 책임자" id="director" placeholder="연구 책임자를 입력하세요." <input className="f_input2 w_full" type="text" name="director" title="연구 책임자" id="director" placeholder="연구 책임자를 입력하세요."
value={standardResearchDetail.director} value={standardResearchDetail.director}
onChange={(e) => setStandardResearchDetail({ ...standardResearchDetail, director: e.target.value })} onChange={(e) => setStandardResearchDetail({ ...standardResearchDetail, director: e.target.value })}
@ -369,13 +372,34 @@ function StandardResearchEditor(props) {
{/* <!-- 게시판 --> */} {/* <!-- 게시판 --> */}
<label className="label-text-editor">연구 목적<span className="req">필수</span></label> <label className="label-text-editor">연구 목적<span className="req">필수</span></label>
<RichTextEditor item={purpose} setText={setPurpose}/> {
modeInfo.mode === CODE.MODE_MODIFY && typeof purpose === 'undefined'
?
<LinearProgress />
:
<RichTextEditor item={purpose} setText={setPurpose}/>
}
<label className="label-text-editor">연구 내용<span className="req">필수</span></label> <label className="label-text-editor">연구 내용<span className="req">필수</span></label>
<RichTextEditor item={content} setText={setContent}/> {
modeInfo.mode === CODE.MODE_MODIFY && typeof content === 'undefined'
?
<LinearProgress />
:
<RichTextEditor item={content} setText={setContent}/>
}
<label className="label-text-editor">기대 효과<span className="req">필수</span></label> <label className="label-text-editor">기대 효과<span className="req">필수</span></label>
<RichTextEditor item={effectContent} setText={setEffectContent}/> {
modeInfo.mode === CODE.MODE_MODIFY && typeof effectContent === 'undefined'
?
<LinearProgress />
:
<RichTextEditor item={effectContent} setText={setEffectContent}/>
}
{/* <!--// 게시판 --> */} {/* <!--// 게시판 --> */}
{/* <!-- 버튼영역 --> */} {/* <!-- 버튼영역 --> */}

View File

@ -129,6 +129,7 @@ public class PopUpApiController {
HttpServletRequest request, HttpServletRequest request,
@AuthenticationPrincipal LoginVO loginVO, @AuthenticationPrincipal LoginVO loginVO,
UpdatePopupVO updatePopupVO, UpdatePopupVO updatePopupVO,
@RequestParam(required = false) long[] survivingFiles,
@RequestParam(required = false) MultipartFile[] files, @RequestParam(required = false) MultipartFile[] files,
@PathVariable("popupId") Long popupId @PathVariable("popupId") Long popupId
) throws Exception { ) throws Exception {
@ -136,7 +137,7 @@ public class PopUpApiController {
ResultVO resultVO = new ResultVO(); ResultVO resultVO = new ResultVO();
try { try {
resultVO = popUpApiService.contentsApiPopUpManageUpdate(resultVO, request, loginVO, updatePopupVO, files, popupId); resultVO = popUpApiService.contentsApiPopUpManageUpdate(resultVO, request, loginVO, updatePopupVO, files, survivingFiles, popupId);
} catch (Exception e) { } catch (Exception e) {
resultVO.setResultCode(ResponseCode.FAILED.getCode()); resultVO.setResultCode(ResponseCode.FAILED.getCode());
resultVO.setResultMessage(e.getMessage()); resultVO.setResultMessage(e.getMessage());
@ -233,7 +234,6 @@ public class PopUpApiController {
); );
return resultVO; return resultVO;
} }
@Operation( @Operation(
@ -273,6 +273,43 @@ public class PopUpApiController {
return resultVO; return resultVO;
} }
@Operation(
summary = "팝업 관리에서 특정 첨부 파일을 삭제하는 API",
description = "관리자 단에서 '컨텐츠 관리' > '팝업 관리' 페이지에서 특정 팝업 수정 후 첨부된 file 삭제하는 API.",
tags = {"PopUpApiController"}
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "등록 성공"),
@ApiResponse(responseCode = "403", description = "인가된 사용자가 아님"),
})
@DeleteMapping(value = "/contents/api/popup-manage/file/{fileSeq}")
public ResultVO deleteFileContentsApiPopUpManage
(
@AuthenticationPrincipal LoginVO user,
HttpServletRequest request,
@PathVariable("fileSeq") Long fileSeq
) throws Exception {
ResultVO resultVO = new ResultVO();
try {
resultVO = popUpApiService.deleteFileContentsApiPopUpManage(resultVO, request, user, fileSeq);
} catch (Exception e) {
resultVO.setResultCode(ResponseCode.FAILED.getCode());
resultVO.setResultMessage(e.getMessage());
}
System.out.println(
"\n--------------------------------------------------------------\n" +
request.getRequestURI() + " OUT:" +
"\n--------------------------------------------------------------\n" +
"resultVO.toString():" + "\n" +
resultVO.toString() + "\n" +
"\n--------------------------------------------------------------\n"
);
return resultVO;
}

View File

@ -18,8 +18,8 @@ public interface PopUpApiService {
public ResultVO contentsApiPopUpManageList(ResultVO resultVO, HttpServletRequest request, LoginVO user, Pageable pageable) throws Exception; public ResultVO contentsApiPopUpManageList(ResultVO resultVO, HttpServletRequest request, LoginVO user, Pageable pageable) throws Exception;
public ResultVO contentsApiPopUpManageCreate(ResultVO resultVO, HttpServletRequest request, LoginVO user, final MultipartHttpServletRequest multiRequest, CreatePopupVO createPopupVO, MultipartFile[] files) throws Exception; public ResultVO contentsApiPopUpManageCreate(ResultVO resultVO, HttpServletRequest request, LoginVO user, final MultipartHttpServletRequest multiRequest, CreatePopupVO createPopupVO, MultipartFile[] files) throws Exception;
public ResultVO contentsApiPopUpManageRead(ResultVO resultVO, HttpServletRequest request, LoginVO user, Long popupSeq) throws Exception; public ResultVO contentsApiPopUpManageRead(ResultVO resultVO, HttpServletRequest request, LoginVO user, Long popupSeq) throws Exception;
public ResultVO contentsApiPopUpManageUpdate(ResultVO resultVO, HttpServletRequest request, LoginVO user, UpdatePopupVO updatePopupVO, MultipartFile[] files, Long popupSeq) throws Exception; public ResultVO contentsApiPopUpManageUpdate(ResultVO resultVO, HttpServletRequest request, LoginVO user, UpdatePopupVO updatePopupVO, MultipartFile[] files, long[] survivingFiles, Long popupSeq) throws Exception;
public ResultVO contentsApiPopUpManageDelete(ResultVO resultVO, HttpServletRequest request, LoginVO user, Long popupSeq) throws Exception; public ResultVO contentsApiPopUpManageDelete(ResultVO resultVO, HttpServletRequest request, LoginVO user, Long popupSeq) throws Exception;
public ResultVO contentsApiPopUpManageUpdateActivationSwitch(ResultVO resultVO, HttpServletRequest request, LoginVO user, String checked, Long popupSeq) throws Exception; public ResultVO contentsApiPopUpManageUpdateActivationSwitch(ResultVO resultVO, HttpServletRequest request, LoginVO user, String checked, Long popupSeq) throws Exception;
public ResultVO deleteFileContentsApiPopUpManage(ResultVO resultVO, HttpServletRequest request, LoginVO user, Long fileSeq) throws Exception;
} }

View File

@ -40,8 +40,6 @@ public class PopUpApiServiceImpl extends EgovAbstractServiceImpl implements PopU
private final TnPopupMngRepository tnPopupMngRepository; private final TnPopupMngRepository tnPopupMngRepository;
private final TnPopupMngRepositoryWithoutPopupContents tnPopupMngRepositoryWithoutPopupContents; private final TnPopupMngRepositoryWithoutPopupContents tnPopupMngRepositoryWithoutPopupContents;
private final TnAttachFileRepository tnAttachFileRepository;
private final FileService fileService; private final FileService fileService;
@ -173,7 +171,7 @@ public class PopUpApiServiceImpl extends EgovAbstractServiceImpl implements PopU
dto.put("schdulEndde", tnPopupMng.getPopupEndDate().plusHours(9).format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); // 날짜/시간의 종료 일시 - yyyyMMddHHmmss dto.put("schdulEndde", tnPopupMng.getPopupEndDate().plusHours(9).format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); // 날짜/시간의 종료 일시 - yyyyMMddHHmmss
//첨부파일명을 가져온다. //첨부파일명을 가져온다.
List<TnAttachFile> tnAttachFileList = tnAttachFileRepository.findByFileGrpId(tnPopupMng.getFileGrpId()).orElse(null); List<TnAttachFile> tnAttachFileList = fileService.findByFileGrpId(tnPopupMng.getFileGrpId());
if( tnAttachFileList != null ) { if( tnAttachFileList != null ) {
List<Map<String, Object>> files = new ArrayList<Map<String, Object>>(); List<Map<String, Object>> files = new ArrayList<Map<String, Object>>();
@ -200,7 +198,7 @@ public class PopUpApiServiceImpl extends EgovAbstractServiceImpl implements PopU
} }
@Override @Override
public ResultVO contentsApiPopUpManageUpdate(ResultVO resultVO, HttpServletRequest request, LoginVO user, UpdatePopupVO updatePopupVO, MultipartFile[] files, Long popupSeq) throws Exception { public ResultVO contentsApiPopUpManageUpdate(ResultVO resultVO, HttpServletRequest request, LoginVO user, UpdatePopupVO updatePopupVO, MultipartFile[] files, long[] survivingFiles, Long popupSeq) throws Exception {
System.out.println( System.out.println(
"\n--------------------------------------------------------------\n" + "\n--------------------------------------------------------------\n" +
request.getRequestURI() + " IN:" + request.getRequestURI() + " IN:" +
@ -223,12 +221,46 @@ public class PopUpApiServiceImpl extends EgovAbstractServiceImpl implements PopU
throw new Exception("종료일시는 시작일시보다 앞 설 수 없습니다."); throw new Exception("종료일시는 시작일시보다 앞 설 수 없습니다.");
} }
// 기존 첨부된 file이 있다면 기존 fileGrpId을 활용한다. // 기존 첨부된 file이 있다면 기존 fileGrpId을 활용한다.
TnPopupMng tnPopupMng = tnPopupMngRepository.findByPopupSeq(popupSeq); TnPopupMng tnPopupMng = tnPopupMngRepository.findByPopupSeq(popupSeq);
String fileGrpId = tnPopupMng.getFileGrpId(); String fileGrpId = tnPopupMng.getFileGrpId();
List<TnAttachFile> tnAttachFileList = fileService.findByFileGrpId(tnPopupMng.getFileGrpId());
if( survivingFiles == null ) {
//기존 file을 모두 삭제한다.
if( fileGrpId != null ) {
if( tnAttachFileList != null ) {
for (TnAttachFile item : tnAttachFileList) {
fileService.deleteTnAttachFile(request, user, item.getFileSeq().longValue());
}
}
fileGrpId = null;
}
} else {
// 살아남은 file을 제외한 나머지 file을 삭제한다.
if( tnAttachFileList != null ) {
boolean isFound = false;
for (TnAttachFile item : tnAttachFileList) {
for( long oldFileSeq : survivingFiles) {
if( oldFileSeq == item.getFileSeq() ) {
isFound = true;
break;
}
}
if( !isFound ) {
fileService.deleteTnAttachFile(request, user, item.getFileSeq().longValue());
}
isFound = false;
}
}
}
fileGrpId = fileService.addTnAttachFile(request, user, files, this.getMiddlePath(), fileGrpId); fileGrpId = fileService.addTnAttachFile(request, user, files, this.getMiddlePath(), fileGrpId);
Map<String, Object> response = tnPopupMngRepository.spUpdateTnPopupMng( Map<String, Object> response = tnPopupMngRepository.spUpdateTnPopupMng(
popupSeq.intValue(), popupSeq.intValue(),
updatePopupVO.getTitle(), updatePopupVO.getTitle(),
@ -258,12 +290,12 @@ public class PopUpApiServiceImpl extends EgovAbstractServiceImpl implements PopU
@Override @Override
public ResultVO contentsApiPopUpManageDelete(ResultVO resultVO, HttpServletRequest request, LoginVO user, Long popupId) throws Exception { public ResultVO contentsApiPopUpManageDelete(ResultVO resultVO, HttpServletRequest request, LoginVO user, Long popupId) throws Exception {
System.out.println( System.out.println(
"\n--------------------------------------------------------------\n" + "\n--------------------------------------------------------------\n" +
request.getRequestURI() + " IN:" + request.getRequestURI() + " IN:" +
"\n--------------------------------------------------------------\n" + "\n--------------------------------------------------------------\n" +
"popupId:" + "\n" + "popupId:" + "\n" +
popupId + "\n" + popupId + "\n" +
"\n--------------------------------------------------------------\n" "\n--------------------------------------------------------------\n"
); );
@ -338,6 +370,28 @@ public class PopUpApiServiceImpl extends EgovAbstractServiceImpl implements PopU
return resultVO; return resultVO;
} }
@Override
public ResultVO deleteFileContentsApiPopUpManage(ResultVO resultVO, HttpServletRequest request, LoginVO user, Long fileSeq) throws Exception {
System.out.println(
"\n--------------------------------------------------------------\n" +
request.getRequestURI() + " IN:" +
"\n--------------------------------------------------------------\n" +
"fileSeq:" + "\n" +
fileSeq + "\n" +
"\n--------------------------------------------------------------\n"
);
Map<String, Object> dto = new HashMap<String, Object>();
fileService.deleteTnAttachFile(request, user, fileSeq);
resultVO.setResult(dto);
resultVO.setResultCode(ResponseCode.SUCCESS.getCode());
resultVO.setResultMessage(ResponseCode.SUCCESS.getMessage());
return resultVO;
}
/** /**
* . * .

View File

@ -42,18 +42,6 @@ public class FileService {
/**
* TN_ATTACH_FILE table insert , ID return .
* TN_ATTACH_FILE .
* @param request
* @param user
* @param files
* @param middlePath .
* D:/kcscUploadFiles/XXXX/abc.jpg XXXX .
* D:/kcscUploadFiles application-xxx.properties Globals.fileStorePath .
* @return ID
* @throws Exception
*/
public String addTnAttachFile(HttpServletRequest request, LoginVO user, MultipartFile[] files, String middlePath) throws Exception { public String addTnAttachFile(HttpServletRequest request, LoginVO user, MultipartFile[] files, String middlePath) throws Exception {
return this.addTnAttachFile(request, user, files, middlePath, null); return this.addTnAttachFile(request, user, files, middlePath, null);
} }
@ -76,6 +64,10 @@ public class FileService {
* @throws Exception * @throws Exception
*/ */
public String addTnAttachFile(HttpServletRequest request, LoginVO user, MultipartFile[] files, String middlePath, String fileGrpId) throws Exception { public String addTnAttachFile(HttpServletRequest request, LoginVO user, MultipartFile[] files, String middlePath, String fileGrpId) throws Exception {
if( files == null ) {
return fileGrpId;
}
String ipAddress = NetworkUtil.getClientIpAddress(request); String ipAddress = NetworkUtil.getClientIpAddress(request);
@ -85,41 +77,75 @@ public class FileService {
} }
for (MultipartFile file : files) {if( file != null && !file.isEmpty()) { for (MultipartFile file : files) {
if( file != null && !file.isEmpty()) {
Map<String, MultipartFile> filesMap = new HashMap<String, MultipartFile>(); Map<String, MultipartFile> filesMap = new HashMap<String, MultipartFile>();
filesMap.put("file", file); filesMap.put("file", file);
List<FileVO> fileVoList = fileUtil.parseFileInf(filesMap, "", 0, middlePath, null); List<FileVO> fileVoList = fileUtil.parseFileInf(filesMap, "", 0, middlePath, null);
int nCount = 1; int nCount = 1;
// 업로드된 file을 tnAttachFile에 insert한다. // 업로드된 file을 tnAttachFile에 insert한다.
for (Iterator<FileVO> iter = fileVoList.iterator(); iter.hasNext(); nCount++) { for (Iterator<FileVO> iter = fileVoList.iterator(); iter.hasNext(); nCount++) {
FileVO item = iter.next(); FileVO item = iter.next();
tnAttachFileRepository.spAddTnAttachFile( String fileNewName = item.getStreFileNm() + "." + item.getFileExtsn();
fileGrpId, String filePath = (item.getFileStreCours() + File.separator + item.getAtchFileId()).replaceAll("\\\\", "/") + fileNewName;
nCount, tnAttachFileRepository.spAddTnAttachFile(
item.getOrignlFileNm(), fileGrpId,
item.getStreFileNm() + "." + item.getFileExtsn(), nCount,
(item.getFileStreCours() + File.separator + item.getAtchFileId()).replaceAll("\\\\", "/"), item.getOrignlFileNm(),
Long.parseLong(item.getFileMg()), fileNewName,
item.getFileExtsn(), filePath,
ipAddress, Long.parseLong(item.getFileMg()),
user.getId(), item.getFileExtsn(),
null, ipAddress,
null, user.getId(),
null null,
); null,
null
);
}
} }
} }
}
return fileGrpId; return fileGrpId;
} }
/**
* .
* @param request
* @param user
* @param fileSeq
* @return , true. ,
* @throws Exception
*/
public boolean deleteTnAttachFile(HttpServletRequest request, LoginVO user, Long fileSeq) throws Exception {
//파일을 삭제한다.
TnAttachFile tnAttachFile = tnAttachFileRepository.findById(fileSeq.intValue()).orElse(null);
if( tnAttachFile == null ) {
throw new Exception("대상이 존재하지 않습니다.");
}
String fileFullPath = tnAttachFile.getFilePath();
File file = new File(fileFullPath);
file.delete();
tnAttachFileRepository.deleteById(fileSeq.intValue());
return true;
}
public List<TnAttachFile> findByFileGrpId(String fileGrpId) throws Exception {
return tnAttachFileRepository.findByFileGrpId(fileGrpId).orElse(null);
}
} }