Q&A 게시판 댓글 작성 기능
This commit is contained in:
@@ -37,6 +37,13 @@
|
|||||||
border-bottom: 2px solid #e0e0e0; /* 제목 아래 줄 긋기 */
|
border-bottom: 2px solid #e0e0e0; /* 제목 아래 줄 긋기 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.comment-section {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
border: 1px solid #e0e0e0; /* 동일한 박스 스타일 */
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.info-row {
|
.info-row {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -58,6 +65,15 @@
|
|||||||
min-height: 200px;
|
min-height: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#commentDetail {
|
||||||
|
min-height: 100px;
|
||||||
|
border: 1px solid #00000032;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 10px;
|
||||||
|
flex: 1;
|
||||||
|
font-family: '맑은고딕'
|
||||||
|
}
|
||||||
|
|
||||||
.required-mark {
|
.required-mark {
|
||||||
color: red;
|
color: red;
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
@@ -94,6 +110,8 @@
|
|||||||
var decodedContent = decodeHTMLEntities(data.responseDetail);
|
var decodedContent = decodeHTMLEntities(data.responseDetail);
|
||||||
$("#responseDetail").summernote('code', decodedContent || '');
|
$("#responseDetail").summernote('code', decodedContent || '');
|
||||||
|
|
||||||
|
// 댓글 표시
|
||||||
|
listComment(key);
|
||||||
|
|
||||||
// 첨부 파일 표시
|
// 첨부 파일 표시
|
||||||
displayAttachFiles(data.fileInfo);
|
displayAttachFiles(data.fileInfo);
|
||||||
@@ -105,6 +123,55 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function listComment(inquiryId) {
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
url: url,
|
||||||
|
dataType: "json",
|
||||||
|
data: {cmd: 'LIST_COMMENT', id: inquiryId},
|
||||||
|
success: function (data) {
|
||||||
|
var $commentList = $('#commentList');
|
||||||
|
$commentList.empty();
|
||||||
|
if (!data || data.length === 0) return;
|
||||||
|
$.each(data, function (i, comment) {
|
||||||
|
var date = comment.createdDate ? timeStampFormat(comment.createdDate) : '';
|
||||||
|
var row = $('<div>').addClass('info-row');
|
||||||
|
$('<div>').addClass('info-label').css('color', '#555').text(comment.writerName || '').appendTo(row);
|
||||||
|
var content = $('<div>').addClass('info-content');
|
||||||
|
$('<div>').css('white-space', 'pre-wrap').text(comment.commentDetail).appendTo(content);
|
||||||
|
var meta = $('<div>').css({'font-size': '0.9em', 'color': '#999', 'margin-top': '2px'});
|
||||||
|
$('<span>').text(date).appendTo(meta);
|
||||||
|
$('<button>').attr('type', 'button').addClass('cssbtn smallBtn2').css({'margin-left': '8px', 'font-size': '0.85em', 'padding': '1px 6px'})
|
||||||
|
.text('delete').on('click', (function(id, inquiryId) {
|
||||||
|
return function() { deleteComment(id, inquiryId); };
|
||||||
|
})(comment.id, comment.inquiryId))
|
||||||
|
.appendTo(meta);
|
||||||
|
meta.appendTo(content);
|
||||||
|
content.appendTo(row);
|
||||||
|
row.appendTo($commentList);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
error: function (e) {
|
||||||
|
alert(e.responseText);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteComment(commentId, inquiryId) {
|
||||||
|
if (!confirm("댓글을 삭제하시겠습니까?")) return;
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
url: url,
|
||||||
|
data: {cmd: 'DELETE_COMMENT', id: commentId},
|
||||||
|
success: function () {
|
||||||
|
listComment(inquiryId);
|
||||||
|
},
|
||||||
|
error: function (e) {
|
||||||
|
alert(e.responseText);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
var returnUrl = getReturnUrlForReturn();
|
var returnUrl = getReturnUrlForReturn();
|
||||||
var key = "${param.id}";
|
var key = "${param.id}";
|
||||||
@@ -115,6 +182,7 @@
|
|||||||
height: 200
|
height: 200
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
if (key) {
|
if (key) {
|
||||||
detail(key);
|
detail(key);
|
||||||
}
|
}
|
||||||
@@ -140,6 +208,29 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#btn_comment").click(function () {
|
||||||
|
|
||||||
|
if (!confirm("<%= localeMessage.getString("common.checkSave")%>")) return;
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
url: url,
|
||||||
|
data: {
|
||||||
|
cmd: "INSERT_COMMENT",
|
||||||
|
inquiryId: $('#id').val(),
|
||||||
|
commentDetail: $('#commentDetail').val(),
|
||||||
|
},
|
||||||
|
success: function (json) {
|
||||||
|
alert("<%= localeMessage.getString("common.saveMsg") %>");
|
||||||
|
$('#commentDetail').val('');
|
||||||
|
listComment(key);
|
||||||
|
},
|
||||||
|
error: function (e) {
|
||||||
|
alert(e.responseText);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
$("#btn_previous").click(function () {
|
$("#btn_previous").click(function () {
|
||||||
goNav(returnUrl);
|
goNav(returnUrl);
|
||||||
});
|
});
|
||||||
@@ -221,6 +312,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 댓글 작성 부분 -->
|
||||||
|
<div class="comment-section">
|
||||||
|
<div id="commentList"></div>
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-label">${sessionScope.login.userName}</div>
|
||||||
|
<div style="flex:1; display: flex; gap: 8px; align-items: stretch;">
|
||||||
|
<textarea id="commentDetail" name="commentDetail" data-required data-warning="댓글 내용을 입력하여 주십시오."></textarea>
|
||||||
|
<button type="button" class="cssbtn" id="btn_comment" level="W" style="width:100px; height: 100px; text-align:center; ">댓글등록</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<input type="hidden" name="id" id="id">
|
<input type="hidden" name="id" id="id">
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
package com.eactive.eai.rms.data.entity.onl.apim.portalinquiry;
|
||||||
|
|
||||||
|
import com.eactive.apim.portal.qna.entity.InquiryComment;
|
||||||
|
import com.eactive.eai.data.jpa.BaseRepository;
|
||||||
|
import com.eactive.eai.rms.data.EMSDataSource;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@EMSDataSource
|
||||||
|
public interface InquiryCommentRepository extends BaseRepository<InquiryComment, String> {
|
||||||
|
|
||||||
|
long countByInquiry_Id(String inquiryId);
|
||||||
|
|
||||||
|
List<InquiryComment> findByInquiry_IdAndDelYnOrderBySeqAsc(String inquiryId, String delYn);
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
package com.eactive.eai.rms.data.entity.onl.apim.portalinquiry;
|
||||||
|
|
||||||
|
import com.eactive.apim.portal.qna.entity.InquiryComment;
|
||||||
|
import com.eactive.eai.rms.data.jpa.AbstractEMSDataSerivce;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional(transactionManager = "transactionManagerForEMS")
|
||||||
|
public class PortalInquiryCommentService extends AbstractEMSDataSerivce<InquiryComment, String, InquiryCommentRepository> {
|
||||||
|
|
||||||
|
// AbstractEMSDataSerivce의 repository 필드가 BaseRepository<T,I>로 고정되어
|
||||||
|
// 커스텀 메서드를 호출할 수 없으므로 별도 필드로 직접 주입
|
||||||
|
@Autowired
|
||||||
|
private InquiryCommentRepository inquiryCommentRepository;
|
||||||
|
|
||||||
|
public long countByInquiryId(String inquiryId) {
|
||||||
|
return inquiryCommentRepository.countByInquiry_Id(inquiryId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<InquiryComment> findByInquiryId(String inquiryId) {
|
||||||
|
return inquiryCommentRepository.findByInquiry_IdAndDelYnOrderBySeqAsc(inquiryId, "N");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.eactive.eai.rms.onl.apim.portalInquiry;
|
||||||
|
|
||||||
|
import com.eactive.apim.portal.file.entity.FileInfo;
|
||||||
|
import com.eactive.eai.data.converter.LocalDateTimeFormatters;
|
||||||
|
import com.eactive.eai.rms.onl.apim.portaluser.PortalUserUI;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class PortalInquiryCommentUI {
|
||||||
|
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
private String inquiryId;
|
||||||
|
|
||||||
|
private String commentDetail;
|
||||||
|
|
||||||
|
private int seq;
|
||||||
|
|
||||||
|
private String delYn;
|
||||||
|
|
||||||
|
private String createdBy;
|
||||||
|
|
||||||
|
private String writerName;
|
||||||
|
|
||||||
|
private String lastModifiedBy;
|
||||||
|
|
||||||
|
@JsonFormat(pattern = LocalDateTimeFormatters.FORMAT_YYYYMMDDHHMMSS_14)
|
||||||
|
@DateTimeFormat(pattern = "yyyyMMddHHmmss")
|
||||||
|
private LocalDateTime createdDate;
|
||||||
|
|
||||||
|
@JsonFormat(pattern = LocalDateTimeFormatters.FORMAT_YYYYMMDDHHMMSS_14)
|
||||||
|
@DateTimeFormat(pattern = "yyyyMMddHHmmss")
|
||||||
|
private LocalDateTime lastModifiedDate;
|
||||||
|
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
package com.eactive.eai.rms.onl.apim.portalInquiry;
|
||||||
|
|
||||||
|
import com.eactive.apim.portal.qna.entity.InquiryComment;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.ReportingPolicy;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
|
||||||
|
public interface PortalInquiryCommentUIMapper {
|
||||||
|
|
||||||
|
@Mapping(target = "inquiryId", source = "inquiry.id")
|
||||||
|
PortalInquiryCommentUI toVo(InquiryComment entity);
|
||||||
|
|
||||||
|
List<PortalInquiryCommentUI> toVoList(List<InquiryComment> entities);
|
||||||
|
}
|
||||||
+18
@@ -74,4 +74,22 @@ public class PortalInquiryManController extends BaseAnnotationController {
|
|||||||
return ResponseEntity.ok().build();
|
return ResponseEntity.ok().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "/onl/apim/portalinquiry/portalInquiryMan.json", params = "cmd=LIST_COMMENT")
|
||||||
|
public ResponseEntity<List<PortalInquiryCommentUI>> selectCommentList(String id) {
|
||||||
|
return ResponseEntity.ok(portalInquiryManService.selectCommentList(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "/onl/apim/portalinquiry/portalInquiryMan.json", params = "cmd=INSERT_COMMENT")
|
||||||
|
public ResponseEntity<String> insertComment(HttpServletRequest request, PortalInquiryCommentUI portalInquiryCommentUI) {
|
||||||
|
String userid = SessionManager.getUserId(request);
|
||||||
|
portalInquiryManService.insertComment(portalInquiryCommentUI, userid);
|
||||||
|
return ResponseEntity.ok().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "/onl/apim/portalinquiry/portalInquiryMan.json", params = "cmd=DELETE_COMMENT")
|
||||||
|
public ResponseEntity<Void> deleteComment(String id) {
|
||||||
|
portalInquiryManService.deleteComment(id);
|
||||||
|
return ResponseEntity.ok().build();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,13 @@ import com.eactive.apim.portal.file.entity.FileInfo;
|
|||||||
import com.eactive.apim.portal.file.service.FileService;
|
import com.eactive.apim.portal.file.service.FileService;
|
||||||
import com.eactive.apim.portal.portaluser.entity.PortalUser;
|
import com.eactive.apim.portal.portaluser.entity.PortalUser;
|
||||||
import com.eactive.apim.portal.portaluser.entity.PortalUserEnums;
|
import com.eactive.apim.portal.portaluser.entity.PortalUserEnums;
|
||||||
|
import com.eactive.apim.portal.portaluser.repository.PortalUserRepository;
|
||||||
import com.eactive.apim.portal.qna.entity.Inquiry;
|
import com.eactive.apim.portal.qna.entity.Inquiry;
|
||||||
|
import com.eactive.apim.portal.qna.entity.InquiryComment;
|
||||||
import com.eactive.apim.portal.user.entity.UserInfo;
|
import com.eactive.apim.portal.user.entity.UserInfo;
|
||||||
import com.eactive.eai.rms.common.base.BaseService;
|
import com.eactive.eai.rms.common.base.BaseService;
|
||||||
import com.eactive.eai.rms.data.entity.man.user.UserInfoService;
|
import com.eactive.eai.rms.data.entity.man.user.UserInfoService;
|
||||||
|
import com.eactive.eai.rms.data.entity.onl.apim.portalinquiry.PortalInquiryCommentService;
|
||||||
import com.eactive.eai.rms.data.entity.onl.apim.portalinquiry.PortalInquirySearch;
|
import com.eactive.eai.rms.data.entity.onl.apim.portalinquiry.PortalInquirySearch;
|
||||||
import com.eactive.eai.rms.data.entity.onl.apim.portalinquiry.PortalInquiryService;
|
import com.eactive.eai.rms.data.entity.onl.apim.portalinquiry.PortalInquiryService;
|
||||||
import com.eactive.eai.rms.onl.apim.masking.MaskingUtils;
|
import com.eactive.eai.rms.onl.apim.masking.MaskingUtils;
|
||||||
@@ -22,14 +25,18 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Transactional(transactionManager = "transactionManagerForEMS")
|
@Transactional(transactionManager = "transactionManagerForEMS")
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class PortalInquiryManService extends BaseService {
|
public class PortalInquiryManService extends BaseService {
|
||||||
private final PortalInquiryService portalInquiryService;
|
private final PortalInquiryService portalInquiryService;
|
||||||
|
private final PortalInquiryCommentService portalInquiryCommentService;
|
||||||
private final PortalInquiryUIMapper portalInquiryUIMapper;
|
private final PortalInquiryUIMapper portalInquiryUIMapper;
|
||||||
|
private final PortalInquiryCommentUIMapper portalInquiryCommentUIMapper;
|
||||||
private final UserInfoService userInfoService;
|
private final UserInfoService userInfoService;
|
||||||
|
private final PortalUserRepository portalUserRepository;
|
||||||
private final FileService fileService;
|
private final FileService fileService;
|
||||||
|
|
||||||
public static final String PENDING = "PENDING";
|
public static final String PENDING = "PENDING";
|
||||||
@@ -37,12 +44,18 @@ public class PortalInquiryManService extends BaseService {
|
|||||||
|
|
||||||
|
|
||||||
public PortalInquiryManService(PortalInquiryService portalInquiryService,
|
public PortalInquiryManService(PortalInquiryService portalInquiryService,
|
||||||
|
PortalInquiryCommentService portalInquiryCommentService,
|
||||||
PortalInquiryUIMapper portalInquiryUIMapper,
|
PortalInquiryUIMapper portalInquiryUIMapper,
|
||||||
|
PortalInquiryCommentUIMapper portalInquiryCommentUIMapper,
|
||||||
UserInfoService userInfoService,
|
UserInfoService userInfoService,
|
||||||
|
PortalUserRepository portalUserRepository,
|
||||||
FileService fileService){
|
FileService fileService){
|
||||||
this.portalInquiryService = portalInquiryService;
|
this.portalInquiryService = portalInquiryService;
|
||||||
|
this.portalInquiryCommentService = portalInquiryCommentService;
|
||||||
this.portalInquiryUIMapper = portalInquiryUIMapper;
|
this.portalInquiryUIMapper = portalInquiryUIMapper;
|
||||||
|
this.portalInquiryCommentUIMapper = portalInquiryCommentUIMapper;
|
||||||
this.userInfoService = userInfoService;
|
this.userInfoService = userInfoService;
|
||||||
|
this.portalUserRepository = portalUserRepository;
|
||||||
this.fileService = fileService;
|
this.fileService = fileService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,4 +175,45 @@ public class PortalInquiryManService extends BaseService {
|
|||||||
portalInquiryService.deleteByIds(idList);
|
portalInquiryService.deleteByIds(idList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<PortalInquiryCommentUI> selectCommentList(String inquiryId) {
|
||||||
|
List<InquiryComment> comments = portalInquiryCommentService.findByInquiryId(inquiryId);
|
||||||
|
List<PortalInquiryCommentUI> result = portalInquiryCommentUIMapper.toVoList(comments);
|
||||||
|
result.forEach(ui -> ui.setWriterName(resolveWriterName(ui.getCreatedBy())));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveWriterName(String userId) {
|
||||||
|
if (StringUtils.isBlank(userId)) return "";
|
||||||
|
// 직원(내부 사용자) 여부 먼저 확인 → 이름 그대로 반환
|
||||||
|
Optional<UserInfo> staff = userInfoService.findById(userId);
|
||||||
|
if (staff.isPresent()) {
|
||||||
|
return staff.get().getUsername();
|
||||||
|
}
|
||||||
|
// 포털 회원이면 이름 마스킹 처리 (김수민 → 김수*)
|
||||||
|
Optional<PortalUser> portalUser = portalUserRepository.findById(userId);
|
||||||
|
if (portalUser.isPresent()) {
|
||||||
|
return MaskingUtils.maskName(portalUser.get().getUserName());
|
||||||
|
}
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void insertComment(PortalInquiryCommentUI commentUI, String userId) {
|
||||||
|
Inquiry inquiry = portalInquiryService.getById(commentUI.getInquiryId());
|
||||||
|
|
||||||
|
InquiryComment comment = new InquiryComment();
|
||||||
|
comment.setInquiry(inquiry);
|
||||||
|
comment.setCommentDetail(commentUI.getCommentDetail());
|
||||||
|
comment.setDelYn("N");
|
||||||
|
int nextSeq = (int) portalInquiryCommentService.countByInquiryId(commentUI.getInquiryId()) + 1;
|
||||||
|
comment.setSeq(nextSeq);
|
||||||
|
|
||||||
|
portalInquiryCommentService.save(comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteComment(String commentId) {
|
||||||
|
InquiryComment comment = portalInquiryCommentService.getById(commentId);
|
||||||
|
comment.setDelYn("Y");
|
||||||
|
portalInquiryCommentService.save(comment);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user