Merge branch 'main' into yoon

This commit is contained in:
yoon 2025-02-21 09:18:50 +09:00
commit 77af3859f2
23 changed files with 301 additions and 79 deletions

View File

@ -47,4 +47,7 @@ public class ApiResponse<T> {
public static <T> ApiResponse<T> error(HttpStatus status, String message) {
return new ApiResponse<>(status, message, null);
}
public static <T> ApiResponse<T> okMessage(String message) {
return new ApiResponse<>(HttpStatus.OK, message, null);
}
}

View File

@ -20,7 +20,11 @@ import org.springframework.util.ObjectUtils;
import java.io.Serial;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class MapDto extends ListOrderedMap {
@ -74,6 +78,32 @@ public class MapDto extends ListOrderedMap {
}
return null;
}
public <T> List<T> getList(String key, Class<T> clazz) {
Object value = this.get(key);
if (value == null) {
return Collections.emptyList();
}
if (!(value instanceof List<?>)) {
throw new IllegalArgumentException("Value for key " + key + " is not a List");
}
List<?> list = (List<?>) value;
List<T> result = new ArrayList<>();
for (Object item : list) {
if (item == null) {
continue; // null인 항목은 건너뜁니다.
}
if (clazz.isInstance(item)) {
result.add(clazz.cast(item));
} else if (clazz.equals(Long.class) && item instanceof Integer) {
result.add(clazz.cast(Long.valueOf((Integer) item)));
} else if (item instanceof Map && clazz.equals(MapDto.class)) {
result.add(clazz.cast(new MapDto((Map<String, Object>) item)));
} else {
throw new ClassCastException("Cannot cast " + item.getClass() + " to " + clazz);
}
}
return result;
}
}

View File

@ -165,17 +165,35 @@ public class BoardController {
}
/**
* 댓글/대댓글 조회
* 댓글 조회
* @ReqMap map 수정 데이터 (LOCBRDSEQ)
* @return 댓글 대댓글의 계층 구조 데이터
* @return 댓글
*/
@Member
@ParameterCheck
@GetMapping("/{boardId}/comments")
public ApiResponse<PageInfo<MapDto>> getComments(@ReqMap MapDto map) {
return ApiResponse.ok(boardService.selectComments(map));
}
public ApiResponse<PageInfo<MapDto>> selectComments(@ReqMap MapDto map) {
// 댓글조회
PageInfo<MapDto> comments = boardService.selectComments(map);
return ApiResponse.ok(comments);
}
/**
* 대댓글 조회
* @ReqMap map 수정 데이터 (LOCBRDSEQ)
* @return 대댓글
*/
@Member
@ParameterCheck
@GetMapping("/{boardId}/reply")
public ApiResponse<List<MapDto>> getComments(@ReqMap MapDto map) {
List<MapDto> replies = boardService.selectReply(map);
return ApiResponse.ok(replies);
}
/**
* 댓글/대댓글 작성
* @param boardId 게시물 ID

View File

@ -33,24 +33,52 @@ public class VacationController {
@Member
@ParameterCheck
@PostMapping
public ApiResponse<?> saveVacations(@RequestBody List<MapDto> map) {
Long user = AuthUtil.getUser().getId();
for (MapDto request : map) {
String date = request.getString("date");
String type = request.getString("type");
Object receiverId = request.get("receiverId");
if ( date == null || type == null) {
throw new IllegalArgumentException("요청 데이터에 누락된 값이 있습니다: " + request);
public ApiResponse<?> saveVacations(@RequestBody List<MapDto> list) {
Long user = AuthUtil.getUser().getId();
for (MapDto request : list) {
String date = request.getString("date");
String type = request.getString("type");
Object receiverId = request.get("receiverId");
request.put("employeeId", user);
if (date == null || type == null) {
throw new IllegalArgumentException("요청 데이터에 누락된 값이 있습니다: " + request);
}
// count 필드가 있으면, 해당 값만큼 반복해서 insert
Integer count = request.getInt("count");
if (count == null || count < 1) {
count = 1;
}
for (int i = 0; i < count; i++) {
localVacaService.insertVacation(request);
}
}
request.put("employeeId", user);
// 데이터 저장
localVacaService.insertVacation(request);
return ApiResponse.ok("모든 휴가가 성공적으로 저장되었습니다.");
}
return ApiResponse.ok("모든 휴가가 성공적으로 저장되었습니다.");
@Member
@ParameterCheck
@PostMapping("/batchUpdate")
public ApiResponse<?> batchUpdateVacations(@ReqMap MapDto map) {
Long user = AuthUtil.getUser().getId();
List<MapDto> addRequests = map.getList("add", MapDto.class);
List<Long> deleteIds = map.getList("delete", Long.class);
if (addRequests != null) {
for (MapDto addRequest : addRequests) {
addRequest.put("employeeId", user);
localVacaService.insertVacation(addRequest);
}
}
if (deleteIds != null) {
for (Long deleteId : deleteIds) {
localVacaService.deleteVacation(deleteId);
}
}
return ApiResponse.ok("휴가 변경이 성공적으로 처리되었습니다.");
}
/**
* 특정 연월에 대한 휴가 데이터 조회
*/

View File

@ -2,6 +2,7 @@ package io.company.localhost.controller.api;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@ -76,5 +77,19 @@ public class VoteBoardController {
return ApiResponse.ok(localvoteservice.insertCheckedNums(map));
}
/**
* 투표 종료
* @param endVoteId 투표번호
* @return
*/
@Member
@PatchMapping("updateEndData")
public ApiResponse<Long> updateEndData(@AuthenticationPrincipal MemberVo memberVo,@ReqMap MapDto map) {
Long userId = AuthUtil.getUser().getId();
map.put("userId", userId);
return ApiResponse.ok(localvoteservice.updateEndData(map));
}
}

View File

@ -14,6 +14,7 @@
*************************************************************/
package io.company.localhost.controller.api;
//import java.util.Arrays;
import java.util.List;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
@ -96,6 +97,9 @@ public class worddictController {
@PostMapping("insertCategory")
public ApiResponse<Long> insertCategory(@ReqMap MapDto map) {
Long result = commoncodservice.insertCategory(map);
if(result == -1) {
return ApiResponse.okMessage("이미 존재하는 카테고리명입니다.");
}
return ApiResponse.ok(result);
}
/**
@ -135,4 +139,16 @@ public class worddictController {
return ApiResponse.ok(result);
}
/**
* 용어 삭제
* @param idList 게시판 아이디 리스트
* @return
*/
@Member
@PatchMapping("deleteword")
public ApiResponse<Long> updateword(@AuthenticationPrincipal MemberVo memberVo,@ReqMap MapDto map) {
return ApiResponse.ok(worddictyservice.updateword(map));
}
}

View File

@ -40,4 +40,6 @@ public interface commoncodMapper {
List<MapDto> selectYearCategories();
List<MapDto> selectCategories();
Long selectcheckCategoryExists(MapDto map);
}

View File

@ -5,6 +5,7 @@ import java.util.Map;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.ResultType;
import io.company.localhost.common.dto.MapDto;
@ -43,8 +44,11 @@ public interface localbordMapper {
// 기존 반응 업데이트
void updateReaction(MapDto map);
// 댓글/대댓글 조회
// 댓글 조회
List<MapDto> selectComments(MapDto map);
//대댓글 조회
List<MapDto> selectReply(MapDto map);
// 댓글/대댓글 작성
void insertCommentOrReply(MapDto map);
@ -86,7 +90,7 @@ public interface localbordMapper {
MapDto selectCountBoardReactions(Long boardId);
// 댓글 좋아요/싫어요 개수
List<MapDto> selectCountCommentReactions(Long boardId);
MapDto selectCountCommentReactions(Long commentId);
// 첨부파일 가져오기
List<MapDto> selectAttachments(Long boardId);
@ -94,5 +98,6 @@ public interface localbordMapper {
//댓글id 확인
MapDto selectCommentById(int commentId);
}

View File

@ -12,6 +12,8 @@ import io.company.localhost.common.dto.MapDto;
public interface localvacaMapper {
void insertVacation(MapDto map);
void deleteVacation(Long vacationId);
List<MapDto> findVacations(@Param("year") int year, @Param("month") int month);
List<MapDto> getUsedVacations(@Param("userId") Long userId);

View File

@ -15,5 +15,7 @@ public interface localvoteMapper {
List<MapDto> getVoteList(MapDto map);
Long updateEndData(MapDto map);
}

View File

@ -33,6 +33,8 @@ public interface worddictyMapper {
int getTotal(MapDto map);
Long updateword(MapDto map);

View File

@ -19,6 +19,7 @@ import java.util.List;
import org.springframework.stereotype.Service;
import io.company.localhost.common.dto.MapDto;
import io.company.localhost.common.exception.NotFoundHandler;
import io.company.localhost.mapper.commoncodMapper;
import lombok.RequiredArgsConstructor;
@ -33,6 +34,10 @@ public class commoncodService {
}
public Long insertCategory(MapDto map) {
Long count = commoncodmapper.selectcheckCategoryExists(map);
if(count > 0) {
return -1L;
}
return commoncodmapper.insertCategory(map);
}

View File

@ -111,14 +111,19 @@ public class localbordService {
}
public PageInfo<MapDto> selectComments(MapDto map) {
int page = map.getString("page") != null ? Integer.parseInt(map.getString("page")) : 1;
int page = map.getString("page") != null ? Integer.parseInt(map.getString("page")) : 1;
int size = map.getString("size") != null ? Integer.parseInt(map.getString("size")) : 10;
PageHelper.startPage(page, size);
List<MapDto> result = boardMapper.selectComments(map);
enrichCommentsWithAdditionalData(result); // 댓글 데이터 보강
return PageUtil.redefineNavigation(new PageInfo<>(result, size));
}
public List<MapDto> selectReply(MapDto map) {
return boardMapper.selectReply(map);
}
public void insertCommentOrReply(MapDto map) {
if (map.get("LOCCMTPNT") == null) {
@ -172,7 +177,7 @@ public class localbordService {
return boardMapper.selectCountBoardReactions(boardId);
}
public List<MapDto> selectCountCommentReactions(Long boardId) {
public MapDto selectCountCommentReactions(Long boardId) {
return boardMapper.selectCountCommentReactions(boardId);
}
@ -301,4 +306,20 @@ public class localbordService {
}
}
private void enrichCommentsWithAdditionalData(List<MapDto> comments) {
for (MapDto comment : comments) {
Object idObject = comment.get("LOCCMTSEQ");
if (idObject instanceof Number) {
long commentId = ((Number) idObject).longValue();
MapDto reactions = boardMapper.selectCountCommentReactions(commentId);
comment.put("likeCount", reactions != null ? reactions.getOrDefault("likeCount", 0) : 0);
comment.put("dislikeCount", reactions != null ? reactions.getOrDefault("dislikeCount", 0) : 0);
Object content = comment.get("content");
comment.put("content", content);
}
}
}
}

View File

@ -34,8 +34,13 @@ public class localvacaService {
@Value("${api.public-holiday.key}")
private String serviceKey;
public void insertVacation(MapDto map) {
localvacaMapper.insertVacation(map);
public void insertVacation(MapDto vacation) {
// 필요한 경우 데이터 검증/전처리 매퍼 호출
localvacaMapper.insertVacation(vacation);
}
public void deleteVacation(Long vacationId) {
localvacaMapper.deleteVacation(vacationId);
}
public List<MapDto> getVacationList(int year, int month) {

View File

@ -31,7 +31,10 @@ public class localvoteService {
Long result = 0L;
int voteIdInt = (int) map.get("voteId");
int voteIdInt = 0 ;
if(map.get("voteId") != null) {
voteIdInt = (int) map.get("voteId");
}
if(voteIdInt != 0) {
result = votdetailmapper.insertdetail(map);
}else {
@ -87,5 +90,9 @@ public class localvoteService {
return result;
}
public Long updateEndData(MapDto map) {
return localvotemapper.updateEndData(map);
}
}

View File

@ -58,8 +58,6 @@ public class worddictyService {
return processedList;
}
public Long insertWord(MapDto map) {
return worddictymapper.insertWord(map);
}
@ -77,6 +75,11 @@ public class worddictyService {
}
public Long updateword(MapDto map) {
return worddictymapper.updateword(map);
}

View File

@ -12,11 +12,30 @@
</foreach>
</insert>
<select id="getVoteMember" parameterType="int" >
select
*
from
votdetail
SELECT
a.*,
n.*,
c.CMNCODNAM AS usercolor,
CASE
WHEN v.LOCVOTSEQ IS NOT NULL THEN 1
ELSE 0
END AS voted
FROM
votmember a
LEFT JOIN
netmember n
ON a.MEMBERSEQ = n.MEMBERSEQ
LEFT JOIN
commoncod c
ON
n.MEMBERCOL = c.CMNCODVAL
LEFT JOIN
votrecord v
ON
a.LOCVOTSEQ = v.LOCVOTSEQ
AND
a.MEMBERSEQ = v.VOTRECMEM
where
LOCVOTSEQ = #{LOCVOTSEQ}
a.locvotseq = #{LOCVOTSEQ}
</select>
</mapper>

View File

@ -23,20 +23,5 @@
,#{userId}
,now()
)
</insert>
<!-- <insert id="insertCheckedNums" parameterType="map">
INSERT INTO votrecord
(
LOCVOTSEQ
,VOTRECMEM
,VOTRECRDT
)
VALUES
<foreach collection="checkedList" item="item" separator=",">
(#{item.LOCVOTSEQ}, #{userId} ,now())
</foreach>
</insert>-->
</mapper>

View File

@ -112,5 +112,12 @@
AND
CMNCODODR != 0
</select>
<select id="selectcheckCategoryExists" parameterType="Map" resultType="Long">
select
count(*) checkCategory
from
commoncod
where
CMNCODNAM = #{CMNCODNAM}
</select>
</mapper>

View File

@ -132,7 +132,7 @@
VALUES (#{LOCBRDSEQ}, #{LOCCMTSEQ}, #{MEMBERSEQ}, #{LOCGOBGOD}, #{LOCGOBBAD})
</insert>
<!-- 댓글/대댓글 조회 -->
<!-- 댓글 조회 -->
<select id="selectComments" resultType="io.company.localhost.common.dto.MapDto">
SELECT
c.LOCCMTSEQ,c.LOCBRDSEQ,c.LOCCMTPNT,c.LOCCMTRPY,
@ -140,7 +140,19 @@
m.MEMBERNAM AS author
FROM localcomt c
LEFT JOIN netmember m ON c.MEMBERSEQ = m.MEMBERSEQ
WHERE LOCBRDSEQ = #{LOCBRDSEQ}
WHERE LOCBRDSEQ = #{LOCBRDSEQ} and LOCCMTPNT = 1
ORDER BY LOCCMTPNT ASC, LOCCMTUDT ASC
</select>
<!-- 대댓글 조회 -->
<select id="selectReply" resultType="io.company.localhost.common.dto.MapDto">
SELECT
c.LOCCMTSEQ,c.LOCBRDSEQ,c.LOCCMTPNT,c.LOCCMTRPY,
c.LOCCMTUDT,c.LOCCMTPWD,c.LOCCMTRDT,c.LOCCMTPNT,
m.MEMBERNAM AS author
FROM localcomt c
LEFT JOIN netmember m ON c.MEMBERSEQ = m.MEMBERSEQ
WHERE LOCCMTPNT = #{LOCCMTPNT} and LOCCMTPNT != 1
ORDER BY LOCCMTPNT ASC, LOCCMTUDT ASC
</select>
@ -240,14 +252,15 @@
</select>
<!-- 댓글별 좋아요/싫어요 개수 조회 -->
<select id="selectCountCommentReactions" resultType="io.company.localhost.common.dto.MapDto">
<select id="selectCountCommentReactions" parameterType="long" resultType="io.company.localhost.common.dto.MapDto">
SELECT
LOCCMTSEQ,
COALESCE(SUM(CASE WHEN LOCGOBGOD = 'T' THEN 1 ELSE 0 END), 0) AS likeCount,
COALESCE(SUM(CASE WHEN LOCGOBBAD = 'T' THEN 1 ELSE 0 END), 0) AS dislikeCount
FROM localgorb
WHERE LOCBRDSEQ = #{boardId}
GROUP BY LOCCMTSEQ
WHERE LOCCMTSEQ = #{commentId}
LIMIT 1
</select>
</mapper>

View File

@ -8,36 +8,45 @@
VALUES (#{employeeId}, #{date}, #{type}, NOW(), #{receiverId})
</insert>
<!-- 휴가 데이터 삭제 -->
<delete id="deleteVacation" parameterType="long">
DELETE FROM localvaca
WHERE LOCVACSEQ = #{vacationId}
</delete>
<!-- 휴가 정보 조회 -->
<select id="findVacations" parameterType="map" resultType="io.company.localhost.common.dto.MapDto">
SELECT MEMBERSEQ, LOCVACUDT, LOCVACTYP
SELECT LOCVACSEQ, MEMBERSEQ, LOCVACUDT, LOCVACTYP, LOCVACRMM
FROM localvaca
WHERE DATE_FORMAT(LOCVACUDT, '%Y-%m') = CONCAT(#{year}, '-', LPAD(#{month}, 2, '0'))
</select>
<!-- 사용자가 사용한 연차 목록 조회 -->
<select id="getUsedVacations" resultType="io.company.localhost.common.dto.MapDto">
SELECT LOCVACUDT AS date, LOCVACTYP AS type, COUNT(*) AS count, LOCVACRMM AS receiverId,
-- 반차(700101, 700102)는 0.5, 연차(700103)는 1로 계산
SUM(CASE
WHEN LOCVACTYP IN ('700101', '700102') THEN 0.5
WHEN LOCVACTYP = '700103' THEN 1
ELSE 0
END) AS used_quota
FROM localvaca
WHERE MEMBERSEQ = #{userId}
GROUP BY LOCVACUDT, LOCVACTYP, LOCVACRMM
ORDER BY LOCVACUDT DESC
</select>
<select id="getUsedVacations" resultType="io.company.localhost.common.dto.MapDto">
SELECT LOCVACUDT AS date, LOCVACTYP AS type, LOCVACRMM AS receiverId,
-- 반차(700101, 700102)는 0.5, 연차(700103)는 1로 계산
SUM(CASE
WHEN LOCVACTYP IN ('700101', '700102') THEN 0.5
WHEN LOCVACTYP = '700103' THEN 1
ELSE 0
END) AS used_quota
FROM localvaca
WHERE MEMBERSEQ = #{userId}
AND DATE_FORMAT(LOCVACUDT, '%Y') = DATE_FORMAT(CURDATE(), '%Y')
GROUP BY LOCVACUDT, LOCVACTYP, LOCVACRMM
ORDER BY LOCVACUDT DESC
</select>
<!-- 사용자가 받은 연차 목록 조회 -->
<select id="getReceivedVacations" resultType="io.company.localhost.common.dto.MapDto">
SELECT LOCVACUDT AS date, LOCVACTYP AS type, MEMBERSEQ AS senderId
FROM localvaca
WHERE LOCVACRMM = #{userId}
AND DATE_FORMAT(LOCVACUDT, '%Y') = DATE_FORMAT(CURDATE(), '%Y')
GROUP BY LOCVACUDT, LOCVACTYP, MEMBERSEQ
ORDER BY LOCVACUDT DESC
</select>
<!-- 사용자가 받은 연차 목록 조회 -->
<select id="getReceivedVacations" resultType="io.company.localhost.common.dto.MapDto">
SELECT LOCVACUDT AS date, LOCVACTYP AS type, COUNT(*) AS count, MEMBERSEQ AS senderId
FROM localvaca
WHERE LOCVACRMM = #{userId}
GROUP BY LOCVACUDT, LOCVACTYP, MEMBERSEQ
ORDER BY LOCVACUDT DESC
</select>
<!-- 전체 직원 남은 연차 조회 -->
<select id="getEmployeeRemainingVacation" resultType="io.company.localhost.common.dto.MapDto">
@ -110,7 +119,7 @@
</select>
<select id="countSentVacations" resultType="io.company.localhost.common.dto.MapDto">
SELECT COUNT(*) as count FROM localvaca WHERE MEMBERSEQ = #{userId} AND LOCVACRMM = #{receiverId} AND YEAR(LOCVACRDT) = YEAR(NOW())
SELECT COUNT(*) as count FROM localvaca WHERE MEMBERSEQ = #{userId} AND LOCVACRMM = #{receiverId}
</select>

View File

@ -28,11 +28,25 @@
,DATE_FORMAT(a.LOCVOTRDT, '%Y-%m-%d %H:%i') AS formatted_LOCVOTRDT
,DATE_FORMAT(a.LOCVOTEDT, '%Y-%m-%d %H:%i') AS formatted_LOCVOTEDT
,b.*
,c.CMNCODNAM usercolor
from
localvote a
LEFT JOIN
netmember b
on
a.LOCVOTREG = b.MEMBERSEQ
left join
commoncod c
on
b.MEMBERCOL = c.CMNCODVAL
order by
a.LOCVOTRDT desc
</select>
<update id="updateEndData" parameterType="map">
UPDATE
localvote
SET
LOCVOTDDT = now()
WHERE LOCVOTSEQ = #{endVoteId}
</update>
</mapper>

View File

@ -178,6 +178,7 @@
m2.MEMBERCOL = cu.CMNCODVAL -- 수정자 색상
where
1=1
and w.WRDDICEDT IS NULL
<include refid="searchConditions"/>
order by w.WRDDICRDT desc
</select>
@ -236,4 +237,14 @@
where
WRDDICSEQ = #{WRDDICSEQ}
</select>
<update id="updateword" parameterType="map">
UPDATE
worddicty
SET
WRDDICEDT = now()
WHERE WRDDICSEQ IN
<foreach item="id" collection="idList" open="(" separator="," close=")">
#{id}
</foreach>
</update>
</mapper>