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

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;
@Column(name = "CATEGORY_NAME", nullable = false)
private String categoryName;
@Column(name = "SORT_CNT")
private Integer sortCnt;
@Transient
private List<BoardCategory> childCategoryList;
@Transient

View File

@ -7,6 +7,6 @@ import java.util.List;
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);
}

View File

@ -3,6 +3,8 @@ package com.dbnt.kcgfilemanager.repository;
import com.dbnt.kcgfilemanager.model.Board;
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;
import com.dbnt.kcgfilemanager.model.Board;
import com.dbnt.kcgfilemanager.model.BoardCategory;
import com.dbnt.kcgfilemanager.model.CategoryRole;
import com.dbnt.kcgfilemanager.model.ContentPosition;
import com.dbnt.kcgfilemanager.repository.BoardCategoryRepository;
import com.dbnt.kcgfilemanager.repository.BoardRepository;
import com.dbnt.kcgfilemanager.repository.CategoryRoleRepository;
import com.dbnt.kcgfilemanager.repository.ContentPositionRepository;
import lombok.RequiredArgsConstructor;
@ -18,17 +20,20 @@ import java.util.Objects;
@RequiredArgsConstructor
public class BoardCategoryService {
private final FileInfoService fileInfoService;
private final BoardRepository boardRepository;
private final BoardCategoryRepository boardCategoryRepository;
private final CategoryRoleRepository categoryRoleRepository;
private final ContentPositionRepository contentPositionRepository;
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){
List<BoardCategory> categoryList = boardCategoryRepository.findByParentSeqAndDepth(parentSeq, depth);
List<BoardCategory> categoryList = boardCategoryRepository.findByParentSeqAndDepthOrderBySortCntDesc(parentSeq, depth);
for(BoardCategory category: categoryList){
category.setChildCategoryList(selectBoardCategoryAll(category.getCategorySeq(), depth+1));
}
@ -96,6 +101,8 @@ public class BoardCategoryService {
for(BoardCategory category: categoryList){
switch (category.getStatus()){
case "deleted":
/*게시물 삭제 로직 필요.*/
deleteContentToCategorySeq(category.getCategorySeq());
boardCategoryRepository.delete(category);
break;
case "modified":
@ -104,9 +111,12 @@ public class BoardCategoryService {
case "added":
category.setTempSeq(category.getCategorySeq());
category.setCategorySeq(null);
if(category.getDepth()!=1){
for(BoardCategory temp : categoryList){
if(Objects.equals(temp.getTempSeq(), category.getParentSeq())){
category.setParentSeq(temp.getCategorySeq());
break;
}
}
}
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
public class BoardService {
private final BoardMapper boardMapper;
private final BoardRepository boardRepository;
private final BoardCategoryRepository boardCategoryRepository;
private final FileInfoService fileInfoService;
private final BoardCategoryService boardCategoryService;
private final BoardMapper boardMapper;
private final BoardRepository boardRepository;
private final BoardCategoryRepository boardCategoryRepository;
private final BoardLogRepository boardLogRepository;
private final FileInfoRepository fileInfoRepository;
private final HashTagRepository hashTagRepository;
@ -221,7 +222,7 @@ public class BoardService {
content.setStatus("D");
saveBoardLog(contentSeq, LogStatus.DELETE, null, user.getUserId());
deleteHashTagLink(contentSeq);
deleteFileInfoAll(contentSeq);
fileInfoService.deleteFileInfoAll(contentSeq);
return contentSeq;
}
@ -254,29 +255,18 @@ public class BoardService {
List<HashTagLink> tagLinkList = hashTagLinkRepository.findByContentSeq(contentSeq);
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){
List<FileInfo> fileInfoList = fileInfoRepository.findByContentSeqOrderByFileSeqAsc(contentSeq);
for(FileInfo fileInfo: fileInfoList){
if(fileSeqList.contains(fileInfo.getFileSeq())){
deleteStoredFile(fileInfo.getSavePath(), fileInfo.getConversionName());
fileInfoService.deleteStoredFile(fileInfo.getSavePath(), fileInfo.getConversionName());
saveBoardLog(contentSeq, LogStatus.FILE_REMOVE, fileInfo.getFullName(), userId);
fileInfoRepository.delete(fileInfo);
}
}
}
private void deleteStoredFile(String savePath, String conversionName){
File deleteFile = new File(savePath, conversionName);
deleteFile.delete();
}
private String calculationSize(double fileSize){
String[] units = {"bytes", "KB", "MB", "GB", "TB", "PB"};
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 maxSeq = 0;
let maxSeq = 1;
$(function (){
getCategoryList();
})
@ -9,17 +9,21 @@ $(document).on('click', '.categoryTr', function (){
chooseTr.find(".trCheckBox").prop("checked", true);
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 changedName = this.value;
if(changedName !== categoryInfo.attr("data-categoryname")){
const changedValue = this.value;
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){
if(category.categorySeq === Number(categoryInfo.attr("data-categoryseq"))){
category.categoryName = changedName;
if(category.status !== "added"){
if(categoryNameFlag)
category.categoryName = changedValue;
if(sortCntFlag)
category.sortCnt = changedValue;
if(category.status !== "added")
category.status = "modified";
}
}
})
categoryInfo[0].className += "bg-warning bg-opacity-25";
}
@ -27,7 +31,9 @@ $(document).on('change', '.categoryName', function (){
$(document).on('click', '.addCategoryBtn', function (){
const depth = Number($(this).attr("data-depth"));
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("삭제될 상위 분류에는 추가할 수 없습니다.");
}else{
const parentSeq = parentCategory.attr("data-categoryseq");
@ -35,6 +41,7 @@ $(document).on('click', '.addCategoryBtn', function (){
categorySeq: maxSeq++,
parentSeq: depth===1?null:Number(parentSeq),
categoryName: "신규",
sortCnt: 0,
depth: depth,
status: "added"
})
@ -52,6 +59,7 @@ $(document).on('click', '.copyCategory', function (){
parentSeq: depth===1?null:Number(parentSeq),
categoryName: "복사된 분류",
depth: depth,
sortCnt: 0,
status: "added"
}];
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 categorySeq = categoryInfo.attr("data-categoryseq");
if(categoryInfo.attr("data-status") !== "deleted"){
if(confirm("선택된 분류와 하위 분류를 삭제하시겠습니까?")){
if(confirm("선택된 분류와 하위 분류를 삭제하시겠습니까?\n등록된 자료가 모두 삭제됩니다.")){
statusChange("deleted", Number(categorySeq));
}
}else{
@ -122,6 +130,7 @@ function getCategoryList(){
categoryName: category.categoryName,
originalName: category.categoryName,
depth: category.depth,
sortCnt: category.sortCnt,
status: "saved",
})
if(maxSeq<=category.categorySeq){
@ -147,10 +156,11 @@ function setCategoryTable(depth, parentSeq){
case "deleted": statusColor = "bg-danger bg-opacity-25"; break;
}
tbody += "<tr class='categoryTr "+statusColor+"' data-categoryseq='"+data.categorySeq+"'" +
" data-parentseq='"+data.parentSeq+"' data-depth='"+data.depth+"'" +
" data-categoryname='"+data.categoryName+"' data-status='"+data.status+"'>";
" data-parentseq='"+data.parentSeq+"' data-categoryname='"+data.categoryName+"'" +
" data-depth='"+data.depth+"' data-sortcnt='"+data.sortCnt+"' data-status='"+data.status+"'>";
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='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='deleteCategory'><i class='bi bi-x-square text-danger'></i></a></td>";
tbody += "</tr>";
@ -163,15 +173,11 @@ function getCopyData(depth, parentSeq, lastSeq){
let copyList = getTableData(categoryList, depth, parentSeq);
let childList = [];
copyList.forEach(function (category){
const tempList = getCopyData(category.depth+1, category.categorySeq)
category.categorySeq = maxSeq++;
const tempSeq = maxSeq++;
const tempList = getCopyData(category.depth+1, category.categorySeq, tempSeq)
category.categorySeq = tempSeq;
category.parentSeq = lastSeq;
category.status = "added";
tempList.forEach(function (child){
child.parentSeq = category.categorySeq;
child.categorySeq = maxSeq++;
child.status = "added";
})
childList = childList.concat(tempList);
})
copyList = copyList.concat(childList);
@ -184,9 +190,10 @@ function getTableData(categoryList, depth, parentSeq){
if(category.depth===depth && category.parentSeq===parentSeq){
targetList.push({
categorySeq: category.categorySeq,
categoryName: category.categoryName,
parentSeq: category.parentSeq,
categoryName: category.categoryName,
depth: category.depth,
sortCnt: category.sortCnt,
status: category.status
})
}

View File

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