게시판 분류 관리 편의성 개선 작업 종료

master
강석 최 2022-01-11 15:39:34 +09:00
parent 4fe795a343
commit 83aab6fb11
8 changed files with 109 additions and 47 deletions

View File

@ -28,6 +28,8 @@ public class BoardCategory {
private Integer parentSeq; private Integer parentSeq;
@Column(name = "CATEGORY_NAME", nullable = false) @Column(name = "CATEGORY_NAME", nullable = false)
private String categoryName; private String categoryName;
@Column(name = "SORT_CNT")
private Integer sortCnt;
@Transient @Transient
private List<BoardCategory> childCategoryList; private List<BoardCategory> childCategoryList;
@Transient @Transient

View File

@ -7,6 +7,6 @@ import java.util.List;
public interface BoardCategoryRepository extends JpaRepository<BoardCategory, Integer> { public interface BoardCategoryRepository extends JpaRepository<BoardCategory, Integer> {
List<BoardCategory> findByParentSeqAndDepth(Integer parentSeq, Integer depth); List<BoardCategory> findByParentSeqAndDepthOrderBySortCntDesc(Integer parentSeq, Integer depth);
List<BoardCategory> findByParentSeq(Integer parentSeq); List<BoardCategory> findByParentSeq(Integer parentSeq);
} }

View File

@ -3,6 +3,8 @@ package com.dbnt.kcgfilemanager.repository;
import com.dbnt.kcgfilemanager.model.Board; import com.dbnt.kcgfilemanager.model.Board;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
public interface BoardRepository extends JpaRepository<Board, Integer> { import java.util.List;
public interface BoardRepository extends JpaRepository<Board, Integer> {
List<Board> findByCategorySeq(int categorySeq);
} }

View File

@ -1,9 +1,11 @@
package com.dbnt.kcgfilemanager.service; package com.dbnt.kcgfilemanager.service;
import com.dbnt.kcgfilemanager.model.Board;
import com.dbnt.kcgfilemanager.model.BoardCategory; import com.dbnt.kcgfilemanager.model.BoardCategory;
import com.dbnt.kcgfilemanager.model.CategoryRole; import com.dbnt.kcgfilemanager.model.CategoryRole;
import com.dbnt.kcgfilemanager.model.ContentPosition; import com.dbnt.kcgfilemanager.model.ContentPosition;
import com.dbnt.kcgfilemanager.repository.BoardCategoryRepository; import com.dbnt.kcgfilemanager.repository.BoardCategoryRepository;
import com.dbnt.kcgfilemanager.repository.BoardRepository;
import com.dbnt.kcgfilemanager.repository.CategoryRoleRepository; import com.dbnt.kcgfilemanager.repository.CategoryRoleRepository;
import com.dbnt.kcgfilemanager.repository.ContentPositionRepository; import com.dbnt.kcgfilemanager.repository.ContentPositionRepository;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -18,17 +20,20 @@ import java.util.Objects;
@RequiredArgsConstructor @RequiredArgsConstructor
public class BoardCategoryService { public class BoardCategoryService {
private final FileInfoService fileInfoService;
private final BoardRepository boardRepository;
private final BoardCategoryRepository boardCategoryRepository; private final BoardCategoryRepository boardCategoryRepository;
private final CategoryRoleRepository categoryRoleRepository; private final CategoryRoleRepository categoryRoleRepository;
private final ContentPositionRepository contentPositionRepository; private final ContentPositionRepository contentPositionRepository;
public List<BoardCategory> selectBoardCategory(Integer parentSeq, Integer depth) { public List<BoardCategory> selectBoardCategory(Integer parentSeq, Integer depth) {
return boardCategoryRepository.findByParentSeqAndDepth(parentSeq, depth); return boardCategoryRepository.findByParentSeqAndDepthOrderBySortCntDesc(parentSeq, depth);
} }
public List<BoardCategory> selectBoardCategoryAll(Integer parentSeq, Integer depth){ public List<BoardCategory> selectBoardCategoryAll(Integer parentSeq, Integer depth){
List<BoardCategory> categoryList = boardCategoryRepository.findByParentSeqAndDepth(parentSeq, depth); List<BoardCategory> categoryList = boardCategoryRepository.findByParentSeqAndDepthOrderBySortCntDesc(parentSeq, depth);
for(BoardCategory category: categoryList){ for(BoardCategory category: categoryList){
category.setChildCategoryList(selectBoardCategoryAll(category.getCategorySeq(), depth+1)); category.setChildCategoryList(selectBoardCategoryAll(category.getCategorySeq(), depth+1));
} }
@ -96,6 +101,8 @@ public class BoardCategoryService {
for(BoardCategory category: categoryList){ for(BoardCategory category: categoryList){
switch (category.getStatus()){ switch (category.getStatus()){
case "deleted": case "deleted":
/*게시물 삭제 로직 필요.*/
deleteContentToCategorySeq(category.getCategorySeq());
boardCategoryRepository.delete(category); boardCategoryRepository.delete(category);
break; break;
case "modified": case "modified":
@ -104,9 +111,12 @@ public class BoardCategoryService {
case "added": case "added":
category.setTempSeq(category.getCategorySeq()); category.setTempSeq(category.getCategorySeq());
category.setCategorySeq(null); category.setCategorySeq(null);
for(BoardCategory temp : categoryList){ if(category.getDepth()!=1){
if(Objects.equals(temp.getTempSeq(), category.getParentSeq())){ for(BoardCategory temp : categoryList){
category.setParentSeq(temp.getCategorySeq()); if(Objects.equals(temp.getTempSeq(), category.getParentSeq())){
category.setParentSeq(temp.getCategorySeq());
break;
}
} }
} }
boardCategoryRepository.saveAndFlush(category); boardCategoryRepository.saveAndFlush(category);
@ -114,4 +124,12 @@ public class BoardCategoryService {
} }
} }
} }
private void deleteContentToCategorySeq(Integer categorySeq) {
List<Board> deleteContentList = boardRepository.findByCategorySeq(categorySeq);
for(Board deleteContent: deleteContentList){
fileInfoService.deleteFileInfoAll(deleteContent.getContentSeq());
boardRepository.delete(deleteContent);
}
}
} }

View File

@ -17,12 +17,13 @@ import java.util.*;
@RequiredArgsConstructor @RequiredArgsConstructor
public class BoardService { public class BoardService {
private final BoardMapper boardMapper; private final FileInfoService fileInfoService;
private final BoardRepository boardRepository;
private final BoardCategoryRepository boardCategoryRepository;
private final BoardCategoryService boardCategoryService; private final BoardCategoryService boardCategoryService;
private final BoardMapper boardMapper;
private final BoardRepository boardRepository;
private final BoardCategoryRepository boardCategoryRepository;
private final BoardLogRepository boardLogRepository; private final BoardLogRepository boardLogRepository;
private final FileInfoRepository fileInfoRepository; private final FileInfoRepository fileInfoRepository;
private final HashTagRepository hashTagRepository; private final HashTagRepository hashTagRepository;
@ -221,7 +222,7 @@ public class BoardService {
content.setStatus("D"); content.setStatus("D");
saveBoardLog(contentSeq, LogStatus.DELETE, null, user.getUserId()); saveBoardLog(contentSeq, LogStatus.DELETE, null, user.getUserId());
deleteHashTagLink(contentSeq); deleteHashTagLink(contentSeq);
deleteFileInfoAll(contentSeq); fileInfoService.deleteFileInfoAll(contentSeq);
return contentSeq; return contentSeq;
} }
@ -254,29 +255,18 @@ public class BoardService {
List<HashTagLink> tagLinkList = hashTagLinkRepository.findByContentSeq(contentSeq); List<HashTagLink> tagLinkList = hashTagLinkRepository.findByContentSeq(contentSeq);
hashTagLinkRepository.deleteAll(tagLinkList); hashTagLinkRepository.deleteAll(tagLinkList);
} }
private void deleteFileInfoAll(int contentSeq){
List<FileInfo> fileInfoList = fileInfoRepository.findByContentSeqOrderByFileSeqAsc(contentSeq);
for(FileInfo fileInfo: fileInfoList){
deleteStoredFile(fileInfo.getSavePath(), fileInfo.getConversionName());
}
fileInfoRepository.deleteAll(fileInfoList);
}
private void deleteFileInfo(Integer contentSeq, List<Integer> fileSeqList, String userId){ private void deleteFileInfo(Integer contentSeq, List<Integer> fileSeqList, String userId){
List<FileInfo> fileInfoList = fileInfoRepository.findByContentSeqOrderByFileSeqAsc(contentSeq); List<FileInfo> fileInfoList = fileInfoRepository.findByContentSeqOrderByFileSeqAsc(contentSeq);
for(FileInfo fileInfo: fileInfoList){ for(FileInfo fileInfo: fileInfoList){
if(fileSeqList.contains(fileInfo.getFileSeq())){ if(fileSeqList.contains(fileInfo.getFileSeq())){
deleteStoredFile(fileInfo.getSavePath(), fileInfo.getConversionName()); fileInfoService.deleteStoredFile(fileInfo.getSavePath(), fileInfo.getConversionName());
saveBoardLog(contentSeq, LogStatus.FILE_REMOVE, fileInfo.getFullName(), userId); saveBoardLog(contentSeq, LogStatus.FILE_REMOVE, fileInfo.getFullName(), userId);
fileInfoRepository.delete(fileInfo); fileInfoRepository.delete(fileInfo);
} }
} }
} }
private void deleteStoredFile(String savePath, String conversionName){
File deleteFile = new File(savePath, conversionName);
deleteFile.delete();
}
private String calculationSize(double fileSize){ private String calculationSize(double fileSize){
String[] units = {"bytes", "KB", "MB", "GB", "TB", "PB"}; String[] units = {"bytes", "KB", "MB", "GB", "TB", "PB"};
double unitSelector = Math.floor(Math.log(fileSize)/Math.log(1024)); double unitSelector = Math.floor(Math.log(fileSize)/Math.log(1024));

View File

@ -0,0 +1,29 @@
package com.dbnt.kcgfilemanager.service;
import com.dbnt.kcgfilemanager.config.LogStatus;
import com.dbnt.kcgfilemanager.model.FileInfo;
import com.dbnt.kcgfilemanager.repository.FileInfoRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.io.File;
import java.util.List;
@Service
@RequiredArgsConstructor
public class FileInfoService {
private final FileInfoRepository fileInfoRepository;
public void deleteFileInfoAll(int contentSeq){
List<FileInfo> fileInfoList = fileInfoRepository.findByContentSeqOrderByFileSeqAsc(contentSeq);
for(FileInfo fileInfo: fileInfoList){
deleteStoredFile(fileInfo.getSavePath(), fileInfo.getConversionName());
}
fileInfoRepository.deleteAll(fileInfoList);
}
public void deleteStoredFile(String savePath, String conversionName){
File deleteFile = new File(savePath, conversionName);
deleteFile.delete();
}
}

View File

@ -1,5 +1,5 @@
let categoryList = [] let categoryList = []
let maxSeq = 0; let maxSeq = 1;
$(function (){ $(function (){
getCategoryList(); getCategoryList();
}) })
@ -9,16 +9,20 @@ $(document).on('click', '.categoryTr', function (){
chooseTr.find(".trCheckBox").prop("checked", true); chooseTr.find(".trCheckBox").prop("checked", true);
setCategoryTable(Number(chooseTr.attr("data-depth"))+1, Number(chooseTr.attr("data-categoryseq"))); setCategoryTable(Number(chooseTr.attr("data-depth"))+1, Number(chooseTr.attr("data-categoryseq")));
}) })
$(document).on('change', '.categoryName', function (){ $(document).on('change', '.categoryName, .sortCnt', function (){
const categoryInfo = $(this).parents("tr"); const categoryInfo = $(this).parents("tr");
const changedName = this.value; const changedValue = this.value;
if(changedName !== categoryInfo.attr("data-categoryname")){ let sortCntFlag = this.className.includes("sortCnt")&&(changedValue !== categoryInfo.attr("data-sortcnt"));
let categoryNameFlag = this.className.includes("categoryName")&&(changedValue !== categoryInfo.attr("data-categoryname"));
if(sortCntFlag || categoryNameFlag){
categoryList.forEach(function (category){ categoryList.forEach(function (category){
if(category.categorySeq === Number(categoryInfo.attr("data-categoryseq"))){ if(category.categorySeq === Number(categoryInfo.attr("data-categoryseq"))){
category.categoryName = changedName; if(categoryNameFlag)
if(category.status !== "added"){ category.categoryName = changedValue;
if(sortCntFlag)
category.sortCnt = changedValue;
if(category.status !== "added")
category.status = "modified"; category.status = "modified";
}
} }
}) })
categoryInfo[0].className += "bg-warning bg-opacity-25"; categoryInfo[0].className += "bg-warning bg-opacity-25";
@ -27,7 +31,9 @@ $(document).on('change', '.categoryName', function (){
$(document).on('click', '.addCategoryBtn', function (){ $(document).on('click', '.addCategoryBtn', function (){
const depth = Number($(this).attr("data-depth")); const depth = Number($(this).attr("data-depth"));
const parentCategory = $("#depth"+(depth-1)+"Tbody").find(".trCheckBox:checked").parents("tr"); const parentCategory = $("#depth"+(depth-1)+"Tbody").find(".trCheckBox:checked").parents("tr");
if(parentCategory.attr("data-status")==="deleted"){ if(depth!==1 && parentCategory.length===0){
alert("상위 분류를 선택해 주세요.");
}else if(parentCategory.attr("data-status")==="deleted"){
alert("삭제될 상위 분류에는 추가할 수 없습니다."); alert("삭제될 상위 분류에는 추가할 수 없습니다.");
}else{ }else{
const parentSeq = parentCategory.attr("data-categoryseq"); const parentSeq = parentCategory.attr("data-categoryseq");
@ -35,6 +41,7 @@ $(document).on('click', '.addCategoryBtn', function (){
categorySeq: maxSeq++, categorySeq: maxSeq++,
parentSeq: depth===1?null:Number(parentSeq), parentSeq: depth===1?null:Number(parentSeq),
categoryName: "신규", categoryName: "신규",
sortCnt: 0,
depth: depth, depth: depth,
status: "added" status: "added"
}) })
@ -52,6 +59,7 @@ $(document).on('click', '.copyCategory', function (){
parentSeq: depth===1?null:Number(parentSeq), parentSeq: depth===1?null:Number(parentSeq),
categoryName: "복사된 분류", categoryName: "복사된 분류",
depth: depth, depth: depth,
sortCnt: 0,
status: "added" status: "added"
}]; }];
copyList = copyList.concat(getCopyData(depth+1, Number(copyInfo.attr("data-categoryseq")), lastSeq)); copyList = copyList.concat(getCopyData(depth+1, Number(copyInfo.attr("data-categoryseq")), lastSeq));
@ -64,7 +72,7 @@ $(document).on('click', '.deleteCategory', function (){
const categoryInfo = $(this).parents("tr"); const categoryInfo = $(this).parents("tr");
const categorySeq = categoryInfo.attr("data-categoryseq"); const categorySeq = categoryInfo.attr("data-categoryseq");
if(categoryInfo.attr("data-status") !== "deleted"){ if(categoryInfo.attr("data-status") !== "deleted"){
if(confirm("선택된 분류와 하위 분류를 삭제하시겠습니까?")){ if(confirm("선택된 분류와 하위 분류를 삭제하시겠습니까?\n등록된 자료가 모두 삭제됩니다.")){
statusChange("deleted", Number(categorySeq)); statusChange("deleted", Number(categorySeq));
} }
}else{ }else{
@ -122,6 +130,7 @@ function getCategoryList(){
categoryName: category.categoryName, categoryName: category.categoryName,
originalName: category.categoryName, originalName: category.categoryName,
depth: category.depth, depth: category.depth,
sortCnt: category.sortCnt,
status: "saved", status: "saved",
}) })
if(maxSeq<=category.categorySeq){ if(maxSeq<=category.categorySeq){
@ -147,10 +156,11 @@ function setCategoryTable(depth, parentSeq){
case "deleted": statusColor = "bg-danger bg-opacity-25"; break; case "deleted": statusColor = "bg-danger bg-opacity-25"; break;
} }
tbody += "<tr class='categoryTr "+statusColor+"' data-categoryseq='"+data.categorySeq+"'" + tbody += "<tr class='categoryTr "+statusColor+"' data-categoryseq='"+data.categorySeq+"'" +
" data-parentseq='"+data.parentSeq+"' data-depth='"+data.depth+"'" + " data-parentseq='"+data.parentSeq+"' data-categoryname='"+data.categoryName+"'" +
" data-categoryname='"+data.categoryName+"' data-status='"+data.status+"'>"; " data-depth='"+data.depth+"' data-sortcnt='"+data.sortCnt+"' data-status='"+data.status+"'>";
tbody += "<td><input type='checkbox' class='trCheckBox'></td>" tbody += "<td><input type='checkbox' class='trCheckBox'></td>"
tbody += "<td><input type='text' class='form-control form-control-sm categoryName' value='"+data.categoryName+"' "+(data.status==="deleted"?"readonly":"")+"></td>" tbody += "<td><input type='text' class='form-control form-control-sm categoryName' value='"+data.categoryName+"' "+(data.status==="deleted"?"readonly":"")+"></td>"
tbody += "<td><input type='number' class='form-control form-control-sm sortCnt' value='"+data.sortCnt+"' "+(data.status==="deleted"?"readonly":"")+"></td>"
tbody += "<td><a href='#' class='copyCategory'><i class='bi bi-journals text-success'></i></a></td>"; tbody += "<td><a href='#' class='copyCategory'><i class='bi bi-journals text-success'></i></a></td>";
tbody += "<td><a href='#' class='deleteCategory'><i class='bi bi-x-square text-danger'></i></a></td>"; tbody += "<td><a href='#' class='deleteCategory'><i class='bi bi-x-square text-danger'></i></a></td>";
tbody += "</tr>"; tbody += "</tr>";
@ -163,15 +173,11 @@ function getCopyData(depth, parentSeq, lastSeq){
let copyList = getTableData(categoryList, depth, parentSeq); let copyList = getTableData(categoryList, depth, parentSeq);
let childList = []; let childList = [];
copyList.forEach(function (category){ copyList.forEach(function (category){
const tempList = getCopyData(category.depth+1, category.categorySeq) const tempSeq = maxSeq++;
category.categorySeq = maxSeq++; const tempList = getCopyData(category.depth+1, category.categorySeq, tempSeq)
category.categorySeq = tempSeq;
category.parentSeq = lastSeq; category.parentSeq = lastSeq;
category.status = "added"; category.status = "added";
tempList.forEach(function (child){
child.parentSeq = category.categorySeq;
child.categorySeq = maxSeq++;
child.status = "added";
})
childList = childList.concat(tempList); childList = childList.concat(tempList);
}) })
copyList = copyList.concat(childList); copyList = copyList.concat(childList);
@ -184,9 +190,10 @@ function getTableData(categoryList, depth, parentSeq){
if(category.depth===depth && category.parentSeq===parentSeq){ if(category.depth===depth && category.parentSeq===parentSeq){
targetList.push({ targetList.push({
categorySeq: category.categorySeq, categorySeq: category.categorySeq,
categoryName: category.categoryName,
parentSeq: category.parentSeq, parentSeq: category.parentSeq,
categoryName: category.categoryName,
depth: category.depth, depth: category.depth,
sortCnt: category.sortCnt,
status: category.status status: category.status
}) })
} }

View File

@ -2,6 +2,16 @@
<html lang="ko" xmlns:th="http://www.thymeleaf.org" <html lang="ko" xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout/layout}"> layout:decorate="~{layout/layout}">
<th:block layout:fragment="css">
<style>
.categoryName{
width: 130px;
}
.sortCnt{
width: 60px;
}
</style>
</th:block>
<th:block layout:fragment="script"> <th:block layout:fragment="script">
<script type="text/javascript" th:src="@{/js/admin/categoryMgt2.js}"></script> <script type="text/javascript" th:src="@{/js/admin/categoryMgt2.js}"></script>
</th:block> </th:block>
@ -23,7 +33,8 @@
<thead data-depth="1"> <thead data-depth="1">
<tr> <tr>
<th></th> <th></th>
<th>대분류</th> <th class="categoryName">대분류</th>
<th class="sortCnt">순서</th>
<th></th> <th></th>
<th></th> <th></th>
</tr> </tr>
@ -44,7 +55,8 @@
<thead> <thead>
<tr> <tr>
<th></th> <th></th>
<th>연도</th> <th class="categoryName">연도</th>
<th class="sortCnt">순서</th>
<th></th> <th></th>
<th></th> <th></th>
</tr> </tr>
@ -65,7 +77,8 @@
<thead> <thead>
<tr> <tr>
<th></th> <th></th>
<th>중분류</th> <th class="categoryName">중분류</th>
<th class="sortCnt">순서</th>
<th></th> <th></th>
<th></th> <th></th>
</tr> </tr>
@ -86,7 +99,8 @@
<thead> <thead>
<tr> <tr>
<th></th> <th></th>
<th>소분류</th> <th class="categoryName">소분류</th>
<th class="sortCnt">순서</th>
<th></th> <th></th>
<th></th> <th></th>
</tr> </tr>