# Conflicts:
#	src/main/java/com/dbnt/faisp/controller/TranslatorController.java
#	src/main/java/com/dbnt/faisp/translator/TranslatorService.java
TaehunPark 2022-09-13 15:52:08 +09:00
commit 90a20960ff
34 changed files with 1125 additions and 246 deletions

View File

@ -33,10 +33,4 @@ dependencies {
runtimeOnly 'org.postgresql:postgresql:42.3.6'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor:2.7.2'
annotationProcessor 'org.projectlombok:lombok:1.18.24'
testImplementation 'org.springframework.boot:spring-boot-starter-test:2.7.2'
testImplementation 'org.springframework.security:spring-security-test:5.7.2'
}
tasks.named('test') {
useJUnitPlatform()
}

View File

@ -1,18 +1,13 @@
package com.dbnt.faisp.controller;
package com.dbnt.faisp.authMgt;
import com.dbnt.faisp.authMgt.AuthMgtService;
import com.dbnt.faisp.authMgt.model.AccessConfig;
import com.dbnt.faisp.authMgt.model.ApprovalConfig;
import com.dbnt.faisp.authMgt.service.AuthMgtService;
import com.dbnt.faisp.authMgt.model.AuthMgt;
import com.dbnt.faisp.menuMgt.MenuMgtService;
import com.dbnt.faisp.userInfo.UserInfoService;
import com.dbnt.faisp.userInfo.service.UserInfoService;
import com.dbnt.faisp.userInfo.model.UserInfo;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import java.util.List;
@RestController
@RequiredArgsConstructor

View File

@ -1,4 +1,4 @@
package com.dbnt.faisp.authMgt;
package com.dbnt.faisp.authMgt.service;
import com.dbnt.faisp.authMgt.mapper.AuthMgtMapper;
import com.dbnt.faisp.authMgt.model.AccessConfig;

View File

@ -1,7 +1,7 @@
package com.dbnt.faisp.controller;
package com.dbnt.faisp.codeMgt;
import com.dbnt.faisp.codeMgt.model.CodeCatg;
import com.dbnt.faisp.codeMgt.CodeMgtService;
import com.dbnt.faisp.codeMgt.service.CodeMgtService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

View File

@ -1,4 +1,4 @@
package com.dbnt.faisp.codeMgt;
package com.dbnt.faisp.codeMgt.service;
import com.dbnt.faisp.codeMgt.model.CodeCatg;
import com.dbnt.faisp.codeMgt.model.CodeMgt;

View File

@ -1,13 +1,9 @@
package com.dbnt.faisp.controller;
package com.dbnt.faisp.config;
import com.dbnt.faisp.authMgt.AuthMgtService;
import com.dbnt.faisp.menuMgt.MenuMgtService;
import com.dbnt.faisp.menuMgt.model.MenuMgt;
import com.dbnt.faisp.organMgt.OrganConfigService;
import com.dbnt.faisp.menuMgt.service.MenuMgtService;
import com.dbnt.faisp.organMgt.service.OrganConfigService;
import com.dbnt.faisp.userInfo.model.UserInfo;
import com.dbnt.faisp.codeMgt.CodeMgtService;
import com.dbnt.faisp.codeMgt.model.CodeCatg;
import com.dbnt.faisp.codeMgt.model.CodeMgt;
import com.dbnt.faisp.codeMgt.service.CodeMgtService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
@ -15,9 +11,6 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpSession;
@RestController

View File

@ -0,0 +1,29 @@
package com.dbnt.faisp.config;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.File;
@Service
@RequiredArgsConstructor
public class BaseService {
@Value("${spring.servlet.multipart.location}")
protected String locationPath;
protected String calculationSize(double fileSize){
String[] units = {"bytes", "KB", "MB", "GB", "TB", "PB"};
double unitSelector = Math.floor(Math.log(fileSize)/Math.log(1024));
if(fileSize>0){
return Math.round((fileSize/Math.pow(1024, unitSelector))*100)/100d+" "+units[(int)unitSelector];
}else{
return "";
}
}
public void deleteStoredFile(File deleteFile){
deleteFile.delete();
}
}

View File

@ -0,0 +1,100 @@
package com.dbnt.faisp.config;
import com.dbnt.faisp.fpiMgt.monthPlan.service.MonthPlanService;
import com.dbnt.faisp.userInfo.model.UserInfo;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
@RestController
@RequiredArgsConstructor
public class FileController {
private final MonthPlanService monthPlanService;
@GetMapping("/file/fileDownload")
public void fileDownload(HttpServletRequest request,
HttpServletResponse response,
String board,
Integer parentKey,
Integer fileSeq) {
FileInfo downloadFile = null;
switch (board){
case "monthPlan":
downloadFile = monthPlanService.selectPlanFile(parentKey, fileSeq);
break;
}
BufferedInputStream in;
BufferedOutputStream out;
try {
File file = new File(downloadFile.getSavePath(), downloadFile.getConvNm());
setDisposition(downloadFile.getFullName(), request, response);
in = new BufferedInputStream(new FileInputStream(file));
out = new BufferedOutputStream(response.getOutputStream());
FileCopyUtils.copy(in, out);
out.flush();
if(out!=null) out.close();
if(in!=null )in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private void setDisposition(String filename, HttpServletRequest request, HttpServletResponse response) throws IOException {
String browser = getBrowser(request);
String dispositionPrefix = "attachment; filename=";
String encodedFilename = null;
if (browser.equals("MSIE")) {
encodedFilename = URLEncoder.encode(filename, "UTF-8").replaceAll("\\+", "%20");
} else if (browser.equals("Trident")) { // IE11 문자열 깨짐 방지
encodedFilename = URLEncoder.encode(filename, "UTF-8").replaceAll("\\+", "%20");
} else if (browser.equals("Firefox")) {
encodedFilename = "\"" + new String(filename.getBytes("UTF-8"), "8859_1") + "\"";
} else if (browser.equals("Opera")) {
encodedFilename = "\"" + new String(filename.getBytes("UTF-8"), "8859_1") + "\"";
} else if (browser.equals("Chrome")) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < filename.length(); i++) {
char c = filename.charAt(i);
if (c > '~') {
sb.append(URLEncoder.encode("" + c, "UTF-8"));
} else {
sb.append(c);
}
}
encodedFilename = sb.toString();
} else {
throw new IOException("Not supported browser");
}
response.setHeader("Content-Disposition", dispositionPrefix + encodedFilename);
if ("Opera".equals(browser)) {
response.setContentType("application/octet-stream;charset=UTF-8");
}
}
private String getBrowser(HttpServletRequest request) {
String header = request.getHeader("User-Agent");
if (header.indexOf("MSIE") > -1) {
return "MSIE";
} else if (header.indexOf("Trident") > -1) { // IE11 문자열 깨짐 방지
return "Trident";
} else if (header.indexOf("Chrome") > -1) {
return "Chrome";
} else if (header.indexOf("Opera") > -1) {
return "Opera";
}
return "Firefox";
}
}

View File

@ -0,0 +1,25 @@
package com.dbnt.faisp.config;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.Column;
import javax.persistence.Transient;
import java.util.List;
@Getter
@Setter
@NoArgsConstructor
public class FileInfo {
private String origNm;
private String convNm;
private String fileExtn;
private String fileSize;
private String savePath;
public String getFullName(){
return getOrigNm()+"."+getFileExtn();
}
}

View File

@ -1,15 +1,15 @@
package com.dbnt.faisp.controller;
package com.dbnt.faisp.fpiMgt;
import com.dbnt.faisp.fpiMgt.monthPlan.MonthPlanService;
import com.dbnt.faisp.fpiMgt.monthPlan.service.MonthPlanService;
import com.dbnt.faisp.fpiMgt.monthPlan.model.BoardPlan;
import com.dbnt.faisp.userInfo.model.UserInfo;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@RestController
@ -45,10 +45,21 @@ public class FpiMgtController { // 외사경찰견문관리
return mav;
}
@GetMapping("/planViewModal")
public ModelAndView planViewModal(BoardPlan boardPlan){
ModelAndView mav = new ModelAndView("igActivities/fpiMgt/monthPlan/planViewModal");
boardPlan = monthPlanService.selectBoardPlan(boardPlan.getPlanKey());
mav.addObject("plan", boardPlan);
return mav;
}
@PostMapping("/savePlan")
public Integer savePlan(BoardPlan boardPlan,
@RequestParam(value = "planInfos", required = false) List<String> planInfos,
@RequestParam(value = "detailPlanInfos", required = false)List<String> detailPlanInfos){
return monthPlanService.saveBoardPlan(boardPlan, planInfos, detailPlanInfos);
@RequestParam(value = "detailPlanInfos", required = false)List<String> detailPlanInfos,
MultipartHttpServletRequest request,
@RequestParam(value = "fileSeq", required = false) List<Integer> deleteFileSeq){
boardPlan.setMultipartFileList(request.getMultiFileMap().get("uploadFiles"));
return monthPlanService.saveBoardPlan(boardPlan, planInfos, detailPlanInfos, deleteFileSeq);
}
}

View File

@ -1,60 +0,0 @@
package com.dbnt.faisp.fpiMgt.monthPlan;
import com.dbnt.faisp.fpiMgt.monthPlan.mapper.MonthPlanMapper;
import com.dbnt.faisp.fpiMgt.monthPlan.model.BoardPlan;
import com.dbnt.faisp.fpiMgt.monthPlan.model.PlanFile;
import com.dbnt.faisp.fpiMgt.monthPlan.model.PlanMainInfo;
import com.dbnt.faisp.fpiMgt.monthPlan.repository.BoardPlanRepository;
import com.dbnt.faisp.fpiMgt.monthPlan.repository.PlanFileRepository;
import com.dbnt.faisp.fpiMgt.monthPlan.repository.PlanMainInfoRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.Transient;
import java.util.List;
@Service
@RequiredArgsConstructor
public class MonthPlanService {
private final BoardPlanRepository boardPlanRepository;
private final PlanFileRepository planFileRepository;
private final PlanMainInfoRepository planMainInfoRepository;
private final MonthPlanMapper monthPlanMapper;
public BoardPlan selectBoardPlan(Integer planKey) {
BoardPlan savedPlan = boardPlanRepository.findById(planKey).orElse(null);
savedPlan.setFileList(planFileRepository.findByPlanKey(planKey));
savedPlan.setMainInfoList(planMainInfoRepository.findByPlanKey(planKey));
return savedPlan;
}
@Transactional
public Integer saveBoardPlan(BoardPlan boardPlan, List<String> planInfos, List<String> detailPlanInfos) {
Integer planKey = boardPlanRepository.save(boardPlan).getPlanKey();
Integer infoSeq = savePlanMainInfos(planKey,0, "S", planInfos);//요약 summery
savePlanMainInfos(planKey, infoSeq, "D", detailPlanInfos);//상세 detail
return planKey;
}
private Integer savePlanMainInfos(Integer planKey, Integer planSeq, String infoType, List<String> infoList){
for(String info: infoList){
PlanMainInfo planMainInfo = new PlanMainInfo();
planMainInfo.setPlanKey(planKey);
planMainInfo.setPlanSeq(++planSeq);
planMainInfo.setPlanType(infoType);
planMainInfo.setPlanInfo(info);
planMainInfoRepository.save(planMainInfo);
}
return planSeq;
}
public List<BoardPlan> selectBoardPlanList(BoardPlan boardPlan) {
return monthPlanMapper.selectBoardPlanList(boardPlan);
}
public Integer selectBoardPlanListCnt(BoardPlan boardPlan) {
return monthPlanMapper.selectBoardPlanListCnt(boardPlan);
}
}

View File

@ -7,6 +7,7 @@ import lombok.Setter;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.multipart.MultipartFile;
import javax.persistence.*;
import java.time.LocalDate;
@ -52,9 +53,13 @@ public class BoardPlan extends BaseModel {
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm")
private LocalDateTime wrtDt;
@Transient
private Integer fileCnt;
@Transient
private List<PlanMainInfo> mainInfoList;
@Transient
private List<PlanFile> fileList;
@Transient
private List<MultipartFile> multipartFileList;
}

View File

@ -1,5 +1,6 @@
package com.dbnt.faisp.fpiMgt.monthPlan.model;
import com.dbnt.faisp.config.FileInfo;
import lombok.*;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
@ -15,7 +16,7 @@ import java.io.Serializable;
@DynamicUpdate
@Table(name = "plan_file")
@IdClass(PlanFile.PlanFileId.class)
public class PlanFile{
public class PlanFile extends FileInfo {
@Id
@Column(name = "plan_key")
private Integer planKey;
@ -29,7 +30,7 @@ public class PlanFile{
@Column(name = "file_extn")
private String fileExtn;
@Column(name = "file_size")
private Integer fileSize;
private String fileSize;
@Column(name = "save_path")
private String savePath;

View File

@ -4,8 +4,10 @@ import com.dbnt.faisp.fpiMgt.monthPlan.model.PlanFile;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
import java.util.Optional;
public interface PlanFileRepository extends JpaRepository<PlanFile, PlanFile.PlanFileId> {
List<PlanFile> findByPlanKey(Integer planKey);
Optional<PlanFile> findByPlanKeyOrderByFileSeqDesc(Integer planKey);
}

View File

@ -0,0 +1,128 @@
package com.dbnt.faisp.fpiMgt.monthPlan.service;
import com.dbnt.faisp.config.BaseService;
import com.dbnt.faisp.config.FileInfo;
import com.dbnt.faisp.fpiMgt.monthPlan.mapper.MonthPlanMapper;
import com.dbnt.faisp.fpiMgt.monthPlan.model.BoardPlan;
import com.dbnt.faisp.fpiMgt.monthPlan.model.PlanFile;
import com.dbnt.faisp.fpiMgt.monthPlan.model.PlanMainInfo;
import com.dbnt.faisp.fpiMgt.monthPlan.repository.BoardPlanRepository;
import com.dbnt.faisp.fpiMgt.monthPlan.repository.PlanFileRepository;
import com.dbnt.faisp.fpiMgt.monthPlan.repository.PlanMainInfoRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.persistence.Transient;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
@Service
@RequiredArgsConstructor
public class MonthPlanService extends BaseService {
private final BoardPlanRepository boardPlanRepository;
private final PlanFileRepository planFileRepository;
private final PlanMainInfoRepository planMainInfoRepository;
private final MonthPlanMapper monthPlanMapper;
public BoardPlan selectBoardPlan(Integer planKey) {
BoardPlan savedPlan = boardPlanRepository.findById(planKey).orElse(null);
if (savedPlan != null) {
savedPlan.setFileList(planFileRepository.findByPlanKey(planKey));
savedPlan.setMainInfoList(planMainInfoRepository.findByPlanKey(planKey));
}
return savedPlan;
}
@Transactional
public Integer saveBoardPlan(BoardPlan boardPlan, List<String> planInfos, List<String> detailPlanInfos, List<Integer> deleteFileSeq) {
Integer planKey = boardPlanRepository.save(boardPlan).getPlanKey();
Integer infoSeq = savePlanMainInfos(planKey,0, "S", planInfos);//요약 summery
savePlanMainInfos(planKey, infoSeq, "D", detailPlanInfos);//상세 detail
if(deleteFileSeq.size()>0){
deletePlanFile(planKey, deleteFileSeq);
}
if(boardPlan.getMultipartFileList()!=null){
saveUploadFiles(planKey, boardPlan.getMultipartFileList());
}
return planKey;
}
private Integer savePlanMainInfos(Integer planKey, Integer planSeq, String infoType, List<String> infoList){
for(String info: infoList){
PlanMainInfo planMainInfo = new PlanMainInfo();
planMainInfo.setPlanKey(planKey);
planMainInfo.setPlanSeq(++planSeq);
planMainInfo.setPlanType(infoType);
planMainInfo.setPlanInfo(info);
planMainInfoRepository.save(planMainInfo);
}
return planSeq;
}
public List<BoardPlan> selectBoardPlanList(BoardPlan boardPlan) {
return monthPlanMapper.selectBoardPlanList(boardPlan);
}
public Integer selectBoardPlanListCnt(BoardPlan boardPlan) {
return monthPlanMapper.selectBoardPlanListCnt(boardPlan);
}
private void saveUploadFiles(Integer planKey, List<MultipartFile> multipartFileList){
PlanFile lastFileInfo = planFileRepository.findByPlanKeyOrderByFileSeqDesc(planKey).orElse(null);
int fileSeq = lastFileInfo==null?1:(lastFileInfo.getFileSeq()+1);
for(MultipartFile file : multipartFileList){
String saveName = UUID.randomUUID().toString();
String path = locationPath+File.separator+"monthPlan"+File.separator;
File saveFile = new File(path+File.separator+saveName);
if(file.getSize()!=0){ // 저장될 파일 확인
if(!saveFile.exists()){ // 저장될 경로 확인
if(saveFile.getParentFile().mkdirs()){
try{
saveFile.createNewFile();
}catch (IOException e){
e.printStackTrace();
}
}
}
try {
file.transferTo(saveFile);
}catch (IllegalStateException | IOException e){
e.printStackTrace();
}
}
String originalFilename = file.getOriginalFilename();
int extnIdx = originalFilename.lastIndexOf(".");
PlanFile fileInfo = new PlanFile();
fileInfo.setPlanKey(planKey);
fileInfo.setFileSeq(fileSeq++);
fileInfo.setOrigNm(originalFilename.substring(0, extnIdx));
fileInfo.setFileExtn(originalFilename.substring(extnIdx+1));
fileInfo.setConvNm(saveName);
fileInfo.setFileSize(calculationSize(file.getSize()));
fileInfo.setSavePath(path);
planFileRepository.save(fileInfo);
}
}
public void deletePlanFile(Integer planKey, List<Integer> deleteFileSeq) {
List<PlanFile> planFileList = planFileRepository.findByPlanKey(planKey);
for(PlanFile file: planFileList){
if(deleteFileSeq.contains(file.getFileSeq())){
deleteStoredFile(new File(file.getSavePath(), file.getConvNm()));
planFileRepository.delete(file);
}
}
}
public FileInfo selectPlanFile(Integer parentKey, Integer fileSeq) {
return planFileRepository.findById(new PlanFile.PlanFileId(parentKey, fileSeq)).orElse(null);
}
}

View File

@ -1,7 +1,7 @@
package com.dbnt.faisp.controller;
package com.dbnt.faisp.menuMgt;
import com.dbnt.faisp.codeMgt.CodeMgtService;
import com.dbnt.faisp.menuMgt.MenuMgtService;
import com.dbnt.faisp.codeMgt.service.CodeMgtService;
import com.dbnt.faisp.menuMgt.service.MenuMgtService;
import com.dbnt.faisp.menuMgt.model.MenuMgt;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

View File

@ -1,4 +1,4 @@
package com.dbnt.faisp.menuMgt;
package com.dbnt.faisp.menuMgt.service;
import com.dbnt.faisp.menuMgt.mapper.MenuMgtMapper;
import com.dbnt.faisp.menuMgt.model.MenuMgt;

View File

@ -1,8 +1,8 @@
package com.dbnt.faisp.controller;
package com.dbnt.faisp.organMgt;
import com.dbnt.faisp.codeMgt.CodeMgtService;
import com.dbnt.faisp.codeMgt.service.CodeMgtService;
import com.dbnt.faisp.codeMgt.model.CodeMgt;
import com.dbnt.faisp.organMgt.OrganConfigService;
import com.dbnt.faisp.organMgt.service.OrganConfigService;
import com.dbnt.faisp.organMgt.model.OrganConfig;
import com.dbnt.faisp.userInfo.model.UserInfo;
import lombok.RequiredArgsConstructor;

View File

@ -1,4 +1,4 @@
package com.dbnt.faisp.organMgt;
package com.dbnt.faisp.organMgt.service;
import com.dbnt.faisp.organMgt.mapper.OrganConfigMapper;
import com.dbnt.faisp.organMgt.model.OrganConfig;

View File

@ -1,19 +1,15 @@
package com.dbnt.faisp.controller;
package com.dbnt.faisp.translator;
import com.dbnt.faisp.authMgt.AuthMgtService;
import com.dbnt.faisp.codeMgt.CodeMgtService;
import com.dbnt.faisp.menuMgt.MenuMgtService;
import com.dbnt.faisp.menuMgt.model.MenuMgt;
import com.dbnt.faisp.organMgt.OrganConfigService;
import com.dbnt.faisp.translator.TranslatorService;
import com.dbnt.faisp.authMgt.service.AuthMgtService;
import com.dbnt.faisp.codeMgt.service.CodeMgtService;
import com.dbnt.faisp.menuMgt.service.MenuMgtService;
import com.dbnt.faisp.organMgt.service.OrganConfigService;
import com.dbnt.faisp.translator.model.Translator;
import com.dbnt.faisp.translator.model.TranslatorCrr;
import com.dbnt.faisp.userInfo.UserInfoService;
import com.dbnt.faisp.translator.service.TranslatorService;
import com.dbnt.faisp.userInfo.service.UserInfoService;
import com.dbnt.faisp.userInfo.model.UserInfo;
import lombok.RequiredArgsConstructor;
import java.util.List;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
@ -45,11 +41,9 @@ public class TranslatorController {
}
@PostMapping("/insertTranslatorInfo")
@ResponseBody
public String insertTranslatorInfo(@AuthenticationPrincipal UserInfo loginUser,Translator translator, @RequestParam List<TranslatorCrr> tCrr) {
public String insertTranslatorInfo(@AuthenticationPrincipal UserInfo loginUser,Translator translator) {
translator.setWrtNm(loginUser.getUserId());
translator.setWrtOrgan(loginUser.getOgCd());
System.out.println("@@="+tCrr);
return translatorSevice.insertTranslatorInfo(translator);
}

View File

@ -0,0 +1,92 @@
package com.dbnt.faisp.translator.service;
import com.dbnt.faisp.menuMgt.mapper.MenuMgtMapper;
import com.dbnt.faisp.menuMgt.model.MenuMgt;
import com.dbnt.faisp.menuMgt.repository.MenuMgtRepository;
import com.dbnt.faisp.translator.mapper.TranslatorMapper;
import com.dbnt.faisp.translator.model.Translator;
import com.dbnt.faisp.translator.model.Translator.TranslatorId;
import com.dbnt.faisp.translator.repository.TranslatorRepository;
import com.dbnt.faisp.userInfo.model.UserInfo;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.Transient;
import java.time.LocalDateTime;
import java.util.*;
@Service
@RequiredArgsConstructor
public class TranslatorService {
private final TranslatorRepository translatorRepository;
private final TranslatorMapper translatorMapper;
public String insertTranslatorInfo(Translator translator) {
Translator dbTranslator = translatorRepository.findFirstByOrderByTranslatorKeyDesc();
translator.setWrtDt(LocalDateTime.now());
if (dbTranslator == null) {
translator.setTranslatorKey(1);
translator.setVersionNo(1);
translatorRepository.save(translator);
return translatorRepository.save(translator).getTrName();
} else {
translator.setTranslatorKey(dbTranslator.getTranslatorKey() + 1);
translator.setVersionNo(1);
return translatorRepository.save(translator).getTrName();
}
}
public List<Translator> selectTranslatorList(Translator translator) {
return translatorMapper.selectTranslatorList(translator);
}
public Integer selectTranslatorListCnt(Translator translator) {
return translatorMapper.selectTranslatorListCnt(translator);
}
public Translator selectTranslatorView(Translator translator) {
return translatorRepository.findById(new TranslatorId(translator.getTranslatorKey(), translator.getVersionNo()))
.orElse(null);
}
@Transactional
public void updatetranslatorInfo(Translator translator) {
Translator dbTranslator = translatorRepository
.findById(new TranslatorId(translator.getTranslatorKey(), translator.getVersionNo())).orElse(null);
Translator translatorTmp = new Translator();
translatorTmp.setTranslatorKey(dbTranslator.getTranslatorKey());
translatorTmp.setVersionNo(dbTranslator.getVersionNo() + 1);
translatorTmp.setOgdp1(translator.getOgdp1());
translatorTmp.setTrLang(translator.getTrLang());
translatorTmp.setTrCareer(translator.getTrCareer());
translatorTmp.setTrName(translator.getTrName());
translatorTmp.setTrSex(translator.getTrSex());
translatorTmp.setTrPhone(translator.getTrPhone());
translatorTmp.setTrNny(translator.getTrNny());
translatorTmp.setTrAge(translator.getTrAge());
translatorTmp.setTrEdu(translator.getTrEdu());
translatorTmp.setTrCft(translator.getTrCft());
translatorTmp.setTrVisa(translator.getTrVisa());
translatorTmp.setAptDt(translator.getAptDt());
translatorTmp.setDmlYn(translator.getDmlYn());
translatorTmp.setRemark(translator.getRemark());
translatorTmp.setWrtNm(translator.getWrtNm());
translatorTmp.setWrtDt(LocalDateTime.now());
translatorTmp.setWrtOrgan(translator.getWrtOrgan());
translatorRepository.save(translatorTmp);
}
public List<Translator> selectHistoryList(Translator translator) {
return translatorMapper.selectHistoryList(translator);
}
public Translator HistoryView(Translator translator) {
return translatorMapper.HistoryView(translator);
}
}

View File

@ -1,7 +1,7 @@
package com.dbnt.faisp.controller;
package com.dbnt.faisp.userInfo;
import com.dbnt.faisp.userInfo.model.UserInfo;
import com.dbnt.faisp.userInfo.UserInfoService;
import com.dbnt.faisp.userInfo.service.UserInfoService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

View File

@ -1,4 +1,4 @@
package com.dbnt.faisp.userInfo;
package com.dbnt.faisp.userInfo.service;
import com.dbnt.faisp.config.Role;
import com.dbnt.faisp.userInfo.mapper.UserInfoMapper;

View File

@ -1,10 +1,9 @@
package com.dbnt.faisp.controller;
package com.dbnt.faisp.userInfo;
import com.dbnt.faisp.authMgt.AuthMgtService;
import com.dbnt.faisp.codeMgt.CodeMgtService;
import com.dbnt.faisp.menuMgt.MenuMgtService;
import com.dbnt.faisp.menuMgt.model.MenuMgt;
import com.dbnt.faisp.userInfo.UserInfoService;
import com.dbnt.faisp.authMgt.service.AuthMgtService;
import com.dbnt.faisp.codeMgt.service.CodeMgtService;
import com.dbnt.faisp.menuMgt.service.MenuMgtService;
import com.dbnt.faisp.userInfo.service.UserInfoService;
import com.dbnt.faisp.userInfo.model.UserInfo;
import lombok.RequiredArgsConstructor;
@ -37,7 +36,7 @@ public class userMgtController {
mav.addObject("searchParams", userInfo);
return mav;
}
@GetMapping("/userEditModal")
public ModelAndView menuEditModal(UserInfo userInfo){
ModelAndView mav = new ModelAndView("adminPage/userMgt/userEditModal");

View File

@ -14,10 +14,10 @@
a.wrt_organ,
a.wrt_nm,
a.wrt_dt,
b.file_seq
b.fileCnt
from board_plan a
left outer join (select plan_key,
max(file_seq) as file_seq
count(file_seq) as fileCnt
from plan_file
group by plan_key) b
on a.plan_key = b.plan_key

View File

@ -45,4 +45,47 @@ $(document).on('mouseenter', '.secondMenuLink', function (event){
$(document).on('mouseleave', '.menuDiv', function (){
$(".secondMenu").hide();
$(".thirdMenu").hide();
})
$(document).on('change', '#fileInputer', function (){
for(const file of this.files){
setFileDiv(file, files.push(file));
}
this.value = null;
})
function byteCalculation(size) {
const bytes = parseInt(size);
const s = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB'];
const e = Math.floor(Math.log(bytes)/Math.log(1024));
if(e === "-Infinity") return "0 "+s[0];
else return (bytes/Math.pow(1024, Math.floor(e))).toFixed(2)+" "+s[e];
}
$(document).on('click', '.fileDelete', function (){
const target = $(this);
files[Number(target.attr("data-fileidx"))].isDelete = true;
target.parent().remove();
const uploadDiv = $("#uploadDiv");
if(uploadDiv.children().length === 0){
uploadDiv.append("<br>파일을 업로드 해주세요.");
}
})
$(document).on('click', '.uploadedFileDelete', function (){
const target = $(this).parent().find("span")[0];
if(target.className===""){
target.className = "text-decoration-line-through";
}else{
target.className = "";
}
})
$(document).on('click', '.fileDownLink', function (){
let url = "/file/fileDownload?"
url += "board="+$(this).attr("data-board");
url += "&parentKey="+Number($("#viewModalPlanKey").val());
url += "&fileSeq="+$(this).attr("data-fileseq");
window.open(encodeURI(url));
})

View File

@ -1,72 +1,184 @@
let files = [];
$(document).on('click', '#addPlanBtn', function (){
$.ajax({
url: '/fpiMgt/planEditModal',
data: {planKey: null},
type: 'GET',
dataType:"html",
success: function(html){
$("#planEditBody").empty().append(html)
$("#planEditModal").modal('show');
$("#planDt").datepicker({
format: "yyyy-mm-dd",
language: "ko"
});
},
error:function(){
getEditModal(null)
})
}
});
$(document).on('click', '.planTr', function (){
getViewModal(Number($(this).find(".planKey").val()));
})
$(document).on('click', '#editPlanBtn', function (){
$("#planViewModal").modal('hide');
getEditModal(Number($("#planViewBody").find("[name='planKey']").val()));
})
$(document).on('click', '#planAddBtn', function (){
$("#planDiv").append("<input type='text' class='form-control' name='planInfos'>")
$("#planDiv").append("<input type='text' class='form-control' name='planInfos'>")
})
$(document).on('click', '#detailPlanAddBtn', function (){
const detailPlanDiv = $("#detailPlanDiv");
detailPlanDiv.append("<textarea type='text' name='detailPlanInfos'></textarea>");
const lastAppendTextarea = detailPlanDiv.children()[detailPlanDiv.children().length-1];
$(lastAppendTextarea).summernote({
const detailPlanDiv = $("#detailPlanDiv");
detailPlanDiv.append("<textarea type='text' name='detailPlanInfos'></textarea>");
const lastAppendTextarea = detailPlanDiv.children()[detailPlanDiv.children().length-1];
$(lastAppendTextarea).summernote({
lang:'ko-KR',
height: 120,
disableDragAndDrop: true,
toolbar: [
['style', ['style']],
['font', ['bold', 'underline', 'clear']],
['color', ['color']],
['para', ['ul', 'ol', 'paragraph']],
['table', ['table']]
]
});
})
$(document).on('click', '#savePlanBtn', function (){
savePlan('S')
})
$(document).on('click', '#saveTempBtn', function (){
savePlan('T')
})
function getViewModal(planKey){
$.ajax({
url: '/fpiMgt/planViewModal',
data: {planKey: planKey},
type: 'GET',
dataType:"html",
success: function(html){
$("#planViewBody").empty().append(html)
$("#planViewModal").modal('show');
},
error:function(){
}
});
}
function getEditModal(planKey){
$.ajax({
url: '/fpiMgt/planEditModal',
data: {planKey: planKey},
type: 'GET',
dataType:"html",
success: function(html){
$("#planEditModalContent").empty().append(html)
$("#planEditModal").modal('show');
$("#planDt").datepicker({
format: "yyyy-mm-dd",
language: "ko"
});
$("[name='detailPlanInfos']").summernote({
lang:'ko-KR',
height: 120,
disableDragAndDrop: true,
toolbar: [
['style', ['style']],
['font', ['bold', 'underline', 'clear']],
['color', ['color']],
['para', ['ul', 'ol', 'paragraph']],
['table', ['table']]
['style', ['style']],
['font', ['bold', 'underline', 'clear']],
['color', ['color']],
['para', ['ul', 'ol', 'paragraph']],
['table', ['table']]
]
});
})
});
setUploadDiv();
},
error:function(){
$(document).on('click', '#savePlanBtn', function (){
savePlan('S')
})
$(document).on('click', '#saveTempBtn', function (){
savePlan('T')
})
function savePlan(planState){
if(confirm("저장하시겠습니까?")){
$("#planState").val(planState);
contentFade("in");
const formData = new FormData($("#planEditForm")[0]);
$.ajax({
type : 'POST',
data : formData,
url : "/fpiMgt/savePlan",
processData: false,
contentType: false,
success : function(result) {
debugger
contentFade("out");
},
error : function(xhr, status) {
alert("저장에 실패하였습니다.")
contentFade("out");
}
})
}
});
}
function setUploadDiv(){
files = [];
$("#uploadDiv").on("dragenter", function(e) {
// $(this).addClass('drag-over');
}).on("dragleave", function(e) {
// $(this).removeClass('drag-over');
}).on("dragover", function(e) {
e.stopPropagation();
e.preventDefault();
}).on('drop', function(e) {
e.preventDefault();
// $(this).removeClass('drag-over');
for(const file of e.originalEvent.dataTransfer.files){
setFileDiv(file, files.push(file));
}
}).on('click', function (e){
if(e.target.className.indexOf("ileDelete")<0){
$("#fileInputer").click();
}
});
}
function savePlan(planState){
if(contentCheck()){
if(confirm("저장하시겠습니까?")){
$("#planState").val(planState);
contentFade("in");
const formData = new FormData($("#planEditForm")[0]);
for(const file of files) {
if(!file.isDelete)
formData.append('uploadFiles', file, file.name);
}
$(".text-decoration-line-through").each(function (idx, el){
formData.append('fileSeq', $(el).attr("data-fileseq"));
})
$.ajax({
type : 'POST',
data : formData,
url : "/fpiMgt/savePlan",
processData: false,
contentType: false,
success : function(result) {
alert("저장되었습니다.");
contentFade("out");
$("#planEditModal").modal('hide');
getViewModal(result);
},
error : function(xhr, status) {
alert("저장에 실패하였습니다.")
contentFade("out");
}
})
}
}
}
function setFileDiv(file, idx){
const uploadDiv = $("#uploadDiv");
if($(".uploadedFileDelete").length===0 && $(".fileDelete").length === 0){
uploadDiv.empty();
}
let fileInfo = "<div class='row-col-6'>";
fileInfo += file.name+" "+byteCalculation(file.size)+" ";
fileInfo += "<a href='#' class='fileDelete text-danger text-decoration-none' data-fileidx='"+(idx-1)+"'>삭제</a>";
fileInfo += "</div>";
uploadDiv.append(fileInfo);
}
function contentCheck(){
let flag = true;
if(!$("#contentTitle").val()){
alert("제목을 입력해주세요.")
flag = false;
}
if(!$("#planDt").val()){
alert("시행일자를 입력해주세요.")
flag = false;
}
let totalSize = 0;
for(const file of files) {
if(!file.isDelete){
totalSize+=file.size;
if(file.size>209715200){
alert("파일당 사이즈는 200MB을 넘길 수 없습니다.")
flag = false;
}
}
}
if(totalSize>524288000){
alert("첨부파일의 용량 합은 500MB를 넘길 수 없습니다.")
flag = false;
}
return flag;
}

View File

@ -0,0 +1,94 @@
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<form method="get" th:action="@{/fpiMgt/monthPlanPage}">
<input type="hidden" name="pageIndex" id="pageIndex" th:value="${searchParams.pageIndex}">
<div class="row justify-content-between pe-3 py-1">
<div class="col-auto">
<select class="form-select" name="rowCnt" id="rowCnt">
<th:block th:each="num : ${#numbers.sequence(1,5)}">
<option th:value="${num*10}" th:text="${num*10}" th:selected="${searchParams.rowCnt eq num*10}"></option>
</th:block>
</select>
</div>
<div class="col-auto">
<div class="row justify-content-end">
<div class="col-auto">
<input type="text" class="form-control form-control-sm">
</div>
<input type="submit" class="btn btn-sm btn-primary col-auto" id="searchBtn" value="검색">
</div>
</div>
</div>
</form>
<div class="row justify-content-start">
<div class="col-12">
<div class="card">
<div class="card-body">
<div class="row">
<table class="table table-hover">
<thead>
<tr>
<th></th>
<th>제목</th>
<th>시행일자</th>
<th>작성자</th>
<th>작성일시</th>
<th>첨부파일</th>
<th>상태</th>
</tr>
</thead>
<tbody>
<tr class="planTr" th:each="plan:${planList}">
<input type="hidden" class="planKey" th:value="${plan.planKey}">
<td><input type="checkbox"></td>
<td th:text="${plan.contentTitle}"></td>
<td th:text="${#temporals.format(plan.planDt, 'yyyy-MM-dd')}"></td>
<td th:text="${plan.wrtNm}"></td>
<td th:text="${#temporals.format(plan.wrtDt, 'yyyy-MM-dd HH:mm')}"></td>
<td></td>
<td th:if="${plan.sectionApprv eq 'T'}">계장결재</td>
<td th:if="${plan.sectionApprv eq 'F'}">계장반려</td>
<td th:if="${plan.headApprv eq 'T'}">부장결재</td>
<td th:if="${plan.headApprv eq 'F'}">부장반려</td>
<td th:if="${plan.planState eq 'T'}">임시저장</td>
<td th:if="${#strings.isEmpty(plan.sectionApprv) and #strings.isEmpty(plan.headApprv) and plan.planState eq 'S'}">결재대기</td>
</tr>
</tbody>
</table>
</div>
<div class="row justify-content-between">
<div class="col-auto"></div>
<div class="col-auto">
<nav aria-label="Page navigation">
<ul class="pagination">
<th:block th:if="${searchParams.pageIndex>3}">
<li class="page-item" th:data-pageindex="${(searchParams.pageIndex)-3}">
<a class="page-link" href="#" aria-label="Previous">
<span aria-hidden="true">&laquo;</span>
</a>
</li>
</th:block>
<th:block th:each="num : ${#numbers.sequence(searchParams.startNum, searchParams.endNum)}">
<li class="page-item" th:data-pageindex="${num}" th:classappend="${searchParams.pageIndex eq num?'active':''}">
<a class="page-link" href="#" th:text="${num}"></a>
</li>
</th:block>
<th:block th:if="${searchParams.maxNum>searchParams.endNum+2}">
<li class="page-item" th:data-pageindex="${(searchParams.pageIndex)+3}">
<a class="page-link" href="#" aria-label="Next">
<span aria-hidden="true">&raquo;</span>
</a>
</li>
</th:block>
</ul>
</nav>
</div>
<div class="col-auto">
<input type="button" class="btn btn-success" value="등록" id="addPlanBtn">
</div>
</div>
</div>
</div>
</div>
</div>
</html>

View File

@ -0,0 +1,94 @@
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<form method="get" th:action="@{/fpiMgt/monthPlanPage}">
<input type="hidden" name="pageIndex" id="pageIndex" th:value="${searchParams.pageIndex}">
<div class="row justify-content-between pe-3 py-1">
<div class="col-auto">
<select class="form-select" name="rowCnt" id="rowCnt">
<th:block th:each="num : ${#numbers.sequence(1,5)}">
<option th:value="${num*10}" th:text="${num*10}" th:selected="${searchParams.rowCnt eq num*10}"></option>
</th:block>
</select>
</div>
<div class="col-auto">
<div class="row justify-content-end">
<div class="col-auto">
<input type="text" class="form-control form-control-sm">
</div>
<input type="submit" class="btn btn-sm btn-primary col-auto" id="searchBtn" value="검색">
</div>
</div>
</div>
</form>
<div class="row justify-content-start">
<div class="col-12">
<div class="card">
<div class="card-body">
<div class="row">
<table class="table table-hover">
<thead>
<tr>
<th></th>
<th>제목</th>
<th>시행일자</th>
<th>작성자</th>
<th>작성일시</th>
<th>첨부파일</th>
<th>상태</th>
</tr>
</thead>
<tbody>
<tr class="planTr" th:each="plan:${planList}">
<input type="hidden" class="planKey" th:value="${plan.planKey}">
<td><input type="checkbox"></td>
<td th:text="${plan.contentTitle}"></td>
<td th:text="${#temporals.format(plan.planDt, 'yyyy-MM-dd')}"></td>
<td th:text="${plan.wrtNm}"></td>
<td th:text="${#temporals.format(plan.wrtDt, 'yyyy-MM-dd HH:mm')}"></td>
<td></td>
<td th:if="${plan.sectionApprv eq 'T'}">계장결재</td>
<td th:if="${plan.sectionApprv eq 'F'}">계장반려</td>
<td th:if="${plan.headApprv eq 'T'}">부장결재</td>
<td th:if="${plan.headApprv eq 'F'}">부장반려</td>
<td th:if="${plan.planState eq 'T'}">임시저장</td>
<td th:if="${#strings.isEmpty(plan.sectionApprv) and #strings.isEmpty(plan.headApprv) and plan.planState eq 'S'}">결재대기</td>
</tr>
</tbody>
</table>
</div>
<div class="row justify-content-between">
<div class="col-auto"></div>
<div class="col-auto">
<nav aria-label="Page navigation">
<ul class="pagination">
<th:block th:if="${searchParams.pageIndex>3}">
<li class="page-item" th:data-pageindex="${(searchParams.pageIndex)-3}">
<a class="page-link" href="#" aria-label="Previous">
<span aria-hidden="true">&laquo;</span>
</a>
</li>
</th:block>
<th:block th:each="num : ${#numbers.sequence(searchParams.startNum, searchParams.endNum)}">
<li class="page-item" th:data-pageindex="${num}" th:classappend="${searchParams.pageIndex eq num?'active':''}">
<a class="page-link" href="#" th:text="${num}"></a>
</li>
</th:block>
<th:block th:if="${searchParams.maxNum>searchParams.endNum+2}">
<li class="page-item" th:data-pageindex="${(searchParams.pageIndex)+3}">
<a class="page-link" href="#" aria-label="Next">
<span aria-hidden="true">&raquo;</span>
</a>
</li>
</th:block>
</ul>
</nav>
</div>
<div class="col-auto">
<input type="button" class="btn btn-success" value="등록" id="addPlanBtn">
</div>
</div>
</div>
</div>
</div>
</div>
</html>

View File

@ -25,7 +25,7 @@
</li>
</ul>
<div class="tab-content border border-top-0 p-2" id="planContent">
<form method="get" th:action="@{/menuMgt/menuMgtPage}">
<form method="get" th:action="@{/fpiMgt/monthPlanPage}">
<input type="hidden" name="pageIndex" id="pageIndex" th:value="${searchParams.pageIndex}">
<div class="row justify-content-between pe-3 py-1">
<div class="col-auto">
@ -63,13 +63,14 @@
</tr>
</thead>
<tbody>
<tr th:each="plan:${planList}">
<tr class="planTr" th:each="plan:${planList}">
<input type="hidden" class="planKey" th:value="${plan.planKey}">
<td><input type="checkbox"></td>
<td th:text="${plan.contentTitle}"></td>
<td th:text="${#temporals.format(plan.planDt, 'yyyy-MM-dd')}"></td>
<td th:text="${plan.wrtNm}"></td>
<td th:text="${#temporals.format(plan.wrtDt, 'yyyy-MM-dd HH:mm')}"></td>
<td></td>
<td th:text="${plan.fileCnt eq null?'파일 없음':#strings.concat(plan.fileCnt,' 건')}"></td>
<td th:if="${plan.sectionApprv eq 'T'}">계장결재</td>
<td th:if="${plan.sectionApprv eq 'F'}">계장반려</td>
<td th:if="${plan.headApprv eq 'T'}">부장결재</td>
@ -122,19 +123,25 @@
</main>
<div class="modal fade" id="planEditModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="planEditModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl">
<div class="modal-dialog modal-xl modal-dialog-scrollable">
<div class="modal-content" id="planEditModalContent">
</div>
</div>
</div>
<div class="modal fade" id="planViewModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="planViewModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="planEditModalLabel">월간 계획 작성</h5>
<h5 class="modal-title" id="planViewModalLabel">월간 계획 열람</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body" id="planEditBody">
<div class="modal-body" id="planViewBody">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">닫기</button>
<button type="button" class="btn btn-warning" id="saveTempBtn">임시저장</button>
<button type="button" class="btn btn-primary" id="savePlanBtn">저장</button>
<button type="button" class="btn btn-warning" id="editPlanBtn">수정</button>
</div>
</div>
</div>

View File

@ -0,0 +1,94 @@
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<form method="get" th:action="@{/fpiMgt/monthPlanPage}">
<input type="hidden" name="pageIndex" id="pageIndex" th:value="${searchParams.pageIndex}">
<div class="row justify-content-between pe-3 py-1">
<div class="col-auto">
<select class="form-select" name="rowCnt" id="rowCnt">
<th:block th:each="num : ${#numbers.sequence(1,5)}">
<option th:value="${num*10}" th:text="${num*10}" th:selected="${searchParams.rowCnt eq num*10}"></option>
</th:block>
</select>
</div>
<div class="col-auto">
<div class="row justify-content-end">
<div class="col-auto">
<input type="text" class="form-control form-control-sm">
</div>
<input type="submit" class="btn btn-sm btn-primary col-auto" id="searchBtn" value="검색">
</div>
</div>
</div>
</form>
<div class="row justify-content-start">
<div class="col-12">
<div class="card">
<div class="card-body">
<div class="row">
<table class="table table-hover">
<thead>
<tr>
<th></th>
<th>제목</th>
<th>시행일자</th>
<th>작성자</th>
<th>작성일시</th>
<th>첨부파일</th>
<th>상태</th>
</tr>
</thead>
<tbody>
<tr class="planTr" th:each="plan:${planList}">
<input type="hidden" class="planKey" th:value="${plan.planKey}">
<td><input type="checkbox"></td>
<td th:text="${plan.contentTitle}"></td>
<td th:text="${#temporals.format(plan.planDt, 'yyyy-MM-dd')}"></td>
<td th:text="${plan.wrtNm}"></td>
<td th:text="${#temporals.format(plan.wrtDt, 'yyyy-MM-dd HH:mm')}"></td>
<td></td>
<td th:if="${plan.sectionApprv eq 'T'}">계장결재</td>
<td th:if="${plan.sectionApprv eq 'F'}">계장반려</td>
<td th:if="${plan.headApprv eq 'T'}">부장결재</td>
<td th:if="${plan.headApprv eq 'F'}">부장반려</td>
<td th:if="${plan.planState eq 'T'}">임시저장</td>
<td th:if="${#strings.isEmpty(plan.sectionApprv) and #strings.isEmpty(plan.headApprv) and plan.planState eq 'S'}">결재대기</td>
</tr>
</tbody>
</table>
</div>
<div class="row justify-content-between">
<div class="col-auto"></div>
<div class="col-auto">
<nav aria-label="Page navigation">
<ul class="pagination">
<th:block th:if="${searchParams.pageIndex>3}">
<li class="page-item" th:data-pageindex="${(searchParams.pageIndex)-3}">
<a class="page-link" href="#" aria-label="Previous">
<span aria-hidden="true">&laquo;</span>
</a>
</li>
</th:block>
<th:block th:each="num : ${#numbers.sequence(searchParams.startNum, searchParams.endNum)}">
<li class="page-item" th:data-pageindex="${num}" th:classappend="${searchParams.pageIndex eq num?'active':''}">
<a class="page-link" href="#" th:text="${num}"></a>
</li>
</th:block>
<th:block th:if="${searchParams.maxNum>searchParams.endNum+2}">
<li class="page-item" th:data-pageindex="${(searchParams.pageIndex)+3}">
<a class="page-link" href="#" aria-label="Next">
<span aria-hidden="true">&raquo;</span>
</a>
</li>
</th:block>
</ul>
</nav>
</div>
<div class="col-auto">
<input type="button" class="btn btn-success" value="등록" id="addPlanBtn">
</div>
</div>
</div>
</div>
</div>
</div>
</html>

View File

@ -1,47 +1,89 @@
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<form action="#" method="post" id="planEditForm">
<input type="hidden" name="_csrf_header" th:value="${_csrf.headerName}"/>
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
<input type="hidden" name="planKey" th:value="${plan.planKey}">
<input type="hidden" name="wrtOrgan" th:value="${plan.wrtOrgan}">
<input type="hidden" name="planState" id="planState" th:value="${plan.planState}">
<div class="mb-3 row">
<label for="wrtNm" class="col-sm-2 col-form-label text-center">작성자</label>
<div class="col-sm-2">
<input type="text" class="form-control" id="wrtNm" name="wrtNm" th:value="${plan.wrtNm}" readonly>
<div class="modal-header">
<h5 class="modal-title" id="planEditModalLabel" th:text="${plan.planKey eq null?'월간 계획 작성':'월간 계획 수정'}"></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body" id="planEditBody">
<form action="#" method="post" id="planEditForm">
<input type="hidden" name="_csrf_header" th:value="${_csrf.headerName}"/>
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
<input type="hidden" name="planKey" th:value="${plan.planKey}">
<input type="hidden" name="wrtOrgan" th:value="${plan.wrtOrgan}">
<input type="hidden" name="planState" id="planState" th:value="${plan.planState}">
<div class="mb-3 row">
<label for="wrtNm" class="col-sm-2 col-form-label text-center">작성자</label>
<div class="col-sm-2">
<input type="text" class="form-control" id="wrtNm" name="wrtNm" th:value="${plan.wrtNm}" readonly>
</div>
<label for="wrtDt" class="col-sm-2 col-form-label text-center">작성일시</label>
<div class="col-sm-2">
<input type="text" class="form-control" id="wrtDt" name="wrtDt" th:value="${#temporals.format(plan.wrtDt, 'yyyy-MM-dd HH:mm')}" readonly>
</div>
<label for="planDt" class="col-sm-2 col-form-label text-center">시행일자</label>
<div class="col-sm-2">
<input type="text" class="form-control" id="planDt" name="planDt" th:value="${#temporals.format(plan.planDt, 'yyyy-MM-dd')}" autocomplete="off">
</div>
</div>
<label for="wrtDt" class="col-sm-2 col-form-label text-center">작성일시</label>
<div class="col-sm-2">
<input type="text" class="form-control" id="wrtDt" name="wrtDt" th:value="${#temporals.format(plan.wrtDt, 'yyyy-MM-dd HH:mm')}" readonly>
<div class="mb-3 row">
<label for="contentTitle" class="col-sm-2 col-form-label text-center">제목</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="contentTitle" name="contentTitle" th:value="${plan.contentTitle}">
</div>
</div>
<label for="planDt" class="col-sm-2 col-form-label text-center">시행일자</label>
<div class="col-sm-2">
<input type="text" class="form-control" id="planDt" name="planDt" th:value="${#temporals.format(plan.planDt, 'yyyy-MM-dd')}" autocomplete="off">
<div class="mb-3 row justify-content-center">
<label for="planDiv" class="col-sm-2 col-form-label text-center">주요 사업계획</label>
<div class="col-sm-10" id="planDiv">
<th:block th:if="${plan.planKey eq null}">
<input type='text' class='form-control' name='planInfos'>
</th:block>
<th:block th:each="infoList:${plan.mainInfoList}">
<th:block th:if="${infoList.planType eq 'S'}">
<input type="text" class="form-control" name="planInfos" th:value="${infoList.planInfo}">
</th:block>
</th:block>
</div>
<div class="col-sm-auto">
<button type="button" class="btn btn-sm btn-outline-primary" id="planAddBtn"><i class="bi bi-plus-lg"></i></button>
</div>
</div>
</div>
<div class="mb-3 row">
<label for="contentTitle" class="col-sm-2 col-form-label text-center">제목</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="contentTitle" name="contentTitle" th:value="${plan.contentTitle}">
<div class="mb-3 row justify-content-center">
<label for="detailPlanDiv" class="col-sm-2 col-form-label text-center">사업개요 및 추진계획</label>
<div class="col-sm-10" id="detailPlanDiv">
<th:block th:if="${plan.planKey eq null}">
<textarea type='text' name='detailPlanInfos'></textarea>
</th:block>
<th:block th:each="infoList:${plan.mainInfoList}">
<th:block th:if="${infoList.planType eq 'D'}">
<textarea type='text' name='detailPlanInfos' th:utext="${infoList.planInfo}"></textarea>
</th:block>
</th:block>
</div>
<div class="col-sm-auto">
<button type="button" class="btn btn-sm btn-outline-primary" id="detailPlanAddBtn"><i class="bi bi-plus-lg"></i></button>
</div>
</div>
</div>
<div class="mb-3 row justify-content-center">
<label for="planAddBtn" class="col-sm-2 col-form-label text-center">주요 사업계획</label>
<div class="col-sm-10" id="planDiv">
<!--<input type="text" class="form-control" name="planInfo">-->
<div class="row mb-3">
<label for="fileInputer" class="col-sm-2 col-form-label text-center">업로드 자료</label>
<div class="col-sm-10" style="min-height: 70px;">
<div class="w-100 h-100 border border-info rounded text-center" id="uploadDiv">
<th:block th:if="${#arrays.isEmpty(plan.fileList)}">
<br>파일을 업로드 해주세요.
</th:block>
<th:block th:unless="${#arrays.isEmpty(plan.fileList)}">
<div class='row-col-6' th:each="planFile:${plan.fileList}">
<span th:data-fileseq="${planFile.fileSeq}" th:text="|${planFile.origNm}.${planFile.fileExtn} ${planFile.fileSize}|"></span>
<a href='#' class='uploadedFileDelete text-danger text-decoration-none'>삭제</a>
</div>
</th:block>
</div>
</div>
<input type="file" class="d-none" id="fileInputer" multiple>
</div>
<div class="col-sm-auto">
<button type="button" class="btn btn-sm btn-outline-primary" id="planAddBtn"><i class="bi bi-plus-lg"></i></button>
</div>
</div>
<div class="mb-3 row justify-content-center">
<label for="detailPlanAddBtn" class="col-sm-2 col-form-label text-center">사업개요 및 추진계획</label>
<div class="col-sm-10" id="detailPlanDiv">
<!--<textarea id="detailPlanInfo"></textarea>-->
</div>
<div class="col-sm-auto">
<button type="button" class="btn btn-sm btn-outline-primary" id="detailPlanAddBtn"><i class="bi bi-plus-lg"></i></button>
</div>
</div>
</form>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">닫기</button>
<button type="button" class="btn btn-warning" id="saveTempBtn">임시저장</button>
<button type="button" class="btn btn-primary" id="savePlanBtn">저장</button>
</div>

View File

@ -0,0 +1,98 @@
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<input type="hidden" name="planKey" id="viewModalPlanKey" th:value="${plan.planKey}">
<input type="hidden" name="wrtOrgan" th:value="${plan.wrtOrgan}">
<input type="hidden" name="planState" id="planState" th:value="${plan.planState}">
<div class="mb-3 row">
<label for="wrtNm" class="col-sm-1 col-form-label text-center">작성자</label>
<div class="col-sm-2">
<input type="text" class="form-control border-0" id="wrtNm" name="wrtNm" th:value="${plan.wrtNm}" readonly>
</div>
<label for="wrtDt" class="col-sm-1 col-form-label text-center">작성일시</label>
<div class="col-sm-2">
<input type="text" class="form-control border-0" id="wrtDt" name="wrtDt" th:value="${#temporals.format(plan.wrtDt, 'yyyy-MM-dd HH:mm')}" readonly>
</div>
<label for="planDt" class="col-sm-1 col-form-label text-center">시행일자</label>
<div class="col-sm-2">
<input type="text" class="form-control border-0" id="planDt" name="planDt" th:value="${#temporals.format(plan.planDt, 'yyyy-MM-dd')}" readonly>
</div>
<label for="planState" class="col-sm-1 col-form-label text-center">상태</label>
<div class="col-sm-2">
<th:block th:if="${plan.sectionApprv eq 'T'}">
<input type="text" class="form-control border-0" value="계장결재" readonly>
</th:block>
<th:block th:if="${plan.sectionApprv eq 'F'}">
<input type="text" class="form-control border-0" value="계장반려" readonly>
</th:block>
<th:block th:if="${plan.headApprv eq 'T'}">
<input type="text" class="form-control border-0" value="부장결재" readonly>
</th:block>
<th:block th:if="${plan.headApprv eq 'F'}">
<input type="text" class="form-control border-0" value="부장반려" readonly>
</th:block>
<th:block th:if="${plan.planState eq 'T'}">
<input type="text" class="form-control border-0" value="임시저장" readonly>
</th:block>
<th:block th:if="${#strings.isEmpty(plan.sectionApprv) and #strings.isEmpty(plan.headApprv) and plan.planState eq 'S'}">
<input type="text" class="form-control border-0" value="결재대기" readonly>
</th:block>
</div>
</div>
<hr>
<div class="row">
<div class="col-8">
<div class="mb-3 row">
<label for="contentTitle" class="col-sm-2 col-form-label text-center">제목</label>
<div class="col-sm-10">
<input type="text" class="form-control border-0" id="contentTitle" name="contentTitle" th:value="${plan.contentTitle}" readonly>
</div>
</div>
<hr>
<div class="mb-3 row">
<label for="planDiv" class="col-sm-2 col-form-label text-center">주요<br>사업계획</label>
<div class="col-sm-10" id="planDiv">
<th:block th:each="infoList:${plan.mainInfoList}">
<th:block th:if="${infoList.planType eq 'S'}">
<input type="text" class="form-control border-0" name="planInfo" th:value="${infoList.planInfo}" readonly>
</th:block>
</th:block>
</div>
</div>
<hr>
<div class="mb-3 row">
<label for="detailPlanDiv" class="col-sm-2 col-form-label text-center">사업개요<br><br>추진계획</label>
<div class="col-sm-10" id="detailPlanDiv">
<th:block th:each="infoList:${plan.mainInfoList}">
<th:block th:if="${infoList.planType eq 'D'}">
<div th:utext="${infoList.planInfo}"></div>
</th:block>
</th:block>
</div>
</div>
</div>
<div class="col-4">
<table class="table">
<thead>
<tr>
<th>파일명</th>
<th>사이즈</th>
</tr>
</thead>
<tbody>
<th:block th:if="${#arrays.isEmpty(plan.fileList)}">
<tr>
<td colspan="2">파일이 없습니다.</td>
</tr>
</th:block>
<th:block th:unless="${#arrays.isEmpty(plan.fileList)}">
<th:block th:each="file:${plan.fileList}">
<tr class="fileInfoTr">
<td><a href="#" class="fileDownLink" data-board="monthPlan" th:data-fileseq="${file.fileSeq}" th:text="|${file.origNm}.${file.fileExtn}|"></a></td>
<td th:text="${file.fileSize}"></td>
</tr>
</th:block>
</th:block>
</tbody>
</table>
</div>
</div>

View File

@ -1,13 +0,0 @@
package com.dbnt.faisp;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class FaispApplicationTests {
@Test
void contextLoads() {
}
}