사용자 최근 작성 글 조회 기능 추가:
- 최근 3건 조회 서비스/페이사드/리포지토리 구현 - HTML 아코디언 UI 및 스타일 추가
This commit is contained in:
+1
@@ -40,6 +40,7 @@ public class PartnershipApplicationController {
|
|||||||
|
|
||||||
model.addAttribute("partnership", new PartnershipApplicationDTO());
|
model.addAttribute("partnership", new PartnershipApplicationDTO());
|
||||||
model.addAttribute("isInternalUser", UserTypeUtil.isCurrentUserInternal());
|
model.addAttribute("isInternalUser", UserTypeUtil.isCurrentUserInternal());
|
||||||
|
model.addAttribute("recentApplications", partnershipApplicationFacade.getMyRecentApplications());
|
||||||
return "apps/community/mainPartnershipForm";
|
return "apps/community/mainPartnershipForm";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
@@ -2,8 +2,10 @@ package com.eactive.apim.portal.apps.community.partnership.mapper;
|
|||||||
|
|
||||||
|
|
||||||
import com.eactive.apim.portal.apps.community.partnership.dto.PartnershipApplicationDTO;
|
import com.eactive.apim.portal.apps.community.partnership.dto.PartnershipApplicationDTO;
|
||||||
|
import com.eactive.apim.portal.apps.community.partnership.dto.PartnershipApplicationSummaryDTO;
|
||||||
import com.eactive.apim.portal.common.mapper.CommonMapper;
|
import com.eactive.apim.portal.common.mapper.CommonMapper;
|
||||||
import com.eactive.apim.portal.partnershipapplication.entity.PartnershipApplication;
|
import com.eactive.apim.portal.partnershipapplication.entity.PartnershipApplication;
|
||||||
|
import java.util.List;
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.ReportingPolicy;
|
import org.mapstruct.ReportingPolicy;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -16,4 +18,8 @@ import org.springframework.stereotype.Component;
|
|||||||
public interface PartnershipApplicationMapper {
|
public interface PartnershipApplicationMapper {
|
||||||
|
|
||||||
PartnershipApplication toEntity(PartnershipApplicationDTO dto);
|
PartnershipApplication toEntity(PartnershipApplicationDTO dto);
|
||||||
|
|
||||||
|
PartnershipApplicationSummaryDTO toSummaryDto(PartnershipApplication entity);
|
||||||
|
|
||||||
|
List<PartnershipApplicationSummaryDTO> toSummaryDtoList(List<PartnershipApplication> entities);
|
||||||
}
|
}
|
||||||
|
|||||||
+7
@@ -2,6 +2,7 @@ package com.eactive.apim.portal.apps.community.partnership.repository;
|
|||||||
|
|
||||||
import com.eactive.apim.portal.partnershipapplication.entity.PartnershipApplication;
|
import com.eactive.apim.portal.partnershipapplication.entity.PartnershipApplication;
|
||||||
import com.eactive.eai.rms.data.EMSDataSource;
|
import com.eactive.eai.rms.data.EMSDataSource;
|
||||||
|
import java.util.List;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
@@ -9,4 +10,10 @@ import org.springframework.stereotype.Repository;
|
|||||||
@Repository
|
@Repository
|
||||||
@EMSDataSource
|
@EMSDataSource
|
||||||
public interface PartnershipApplicationRepository extends JpaRepository<PartnershipApplication, String>, JpaSpecificationExecutor<PartnershipApplication> {
|
public interface PartnershipApplicationRepository extends JpaRepository<PartnershipApplication, String>, JpaSpecificationExecutor<PartnershipApplication> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 특정 작성자(createdBy)가 등록한 최근 3건을 최신순으로 조회한다.
|
||||||
|
* createdBy 는 PersonalDataEncryptConverter 로 결정적 암호화되므로 평문 사용자 id 로 등가 조회가 가능하다.
|
||||||
|
*/
|
||||||
|
List<PartnershipApplication> findTop3ByCreatedByOrderByCreatedDateDesc(String createdBy);
|
||||||
}
|
}
|
||||||
|
|||||||
+7
@@ -1,9 +1,16 @@
|
|||||||
package com.eactive.apim.portal.apps.community.partnership.service;
|
package com.eactive.apim.portal.apps.community.partnership.service;
|
||||||
|
|
||||||
import com.eactive.apim.portal.apps.community.partnership.dto.PartnershipApplicationDTO;
|
import com.eactive.apim.portal.apps.community.partnership.dto.PartnershipApplicationDTO;
|
||||||
|
import com.eactive.apim.portal.apps.community.partnership.dto.PartnershipApplicationSummaryDTO;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public interface PartnershipApplicationFacade {
|
public interface PartnershipApplicationFacade {
|
||||||
|
|
||||||
void createPartnershipApplication(PartnershipApplicationDTO partnershipApplicationDTO) throws IOException;
|
void createPartnershipApplication(PartnershipApplicationDTO partnershipApplicationDTO) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 현재 로그인 사용자가 작성한 최근 3건을 조회한다. 미인증이면 빈 목록.
|
||||||
|
*/
|
||||||
|
List<PartnershipApplicationSummaryDTO> getMyRecentApplications();
|
||||||
}
|
}
|
||||||
|
|||||||
+13
@@ -1,6 +1,7 @@
|
|||||||
package com.eactive.apim.portal.apps.community.partnership.service;
|
package com.eactive.apim.portal.apps.community.partnership.service;
|
||||||
|
|
||||||
import com.eactive.apim.portal.apps.community.partnership.dto.PartnershipApplicationDTO;
|
import com.eactive.apim.portal.apps.community.partnership.dto.PartnershipApplicationDTO;
|
||||||
|
import com.eactive.apim.portal.apps.community.partnership.dto.PartnershipApplicationSummaryDTO;
|
||||||
import com.eactive.apim.portal.apps.community.partnership.mapper.PartnershipApplicationMapper;
|
import com.eactive.apim.portal.apps.community.partnership.mapper.PartnershipApplicationMapper;
|
||||||
import com.eactive.apim.portal.common.user.PortalAuthenticatedUser;
|
import com.eactive.apim.portal.common.user.PortalAuthenticatedUser;
|
||||||
import com.eactive.apim.portal.common.util.SecurityUtil;
|
import com.eactive.apim.portal.common.util.SecurityUtil;
|
||||||
@@ -15,7 +16,9 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@@ -60,4 +63,14 @@ public class PartnershipApplicationFacadeImpl implements PartnershipApplicationF
|
|||||||
}
|
}
|
||||||
portalAdminNotifier.notifyPortalAdmins(MessageCode.PARTNERSHIP_CREATED, params);
|
portalAdminNotifier.notifyPortalAdmins(MessageCode.PARTNERSHIP_CREATED, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PartnershipApplicationSummaryDTO> getMyRecentApplications() {
|
||||||
|
PortalAuthenticatedUser user = SecurityUtil.getPortalAuthenticatedUser();
|
||||||
|
if (user == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
List<PartnershipApplication> recent = partnershipApplicationService.findRecentByCreatedBy(user.getId());
|
||||||
|
return partnershipApplicationMapper.toSummaryDtoList(recent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
@@ -2,6 +2,7 @@ package com.eactive.apim.portal.apps.community.partnership.service;
|
|||||||
|
|
||||||
import com.eactive.apim.portal.apps.community.partnership.repository.PartnershipApplicationRepository;
|
import com.eactive.apim.portal.apps.community.partnership.repository.PartnershipApplicationRepository;
|
||||||
import com.eactive.apim.portal.partnershipapplication.entity.PartnershipApplication;
|
import com.eactive.apim.portal.partnershipapplication.entity.PartnershipApplication;
|
||||||
|
import java.util.List;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@@ -21,4 +22,12 @@ public class PartnershipApplicationService {
|
|||||||
public void createPartnershipApplication(PartnershipApplication partnershipApplication) {
|
public void createPartnershipApplication(PartnershipApplication partnershipApplication) {
|
||||||
partnershipApplicationRepository.save(partnershipApplication);
|
partnershipApplicationRepository.save(partnershipApplication);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 작성자 id 로 최근 등록 3건 조회(최신순).
|
||||||
|
*/
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public List<PartnershipApplication> findRecentByCreatedBy(String createdBy) {
|
||||||
|
return partnershipApplicationRepository.findTop3ByCreatedByOrderByCreatedDateDesc(createdBy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,23 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<th:block layout:fragment="contentFragment">
|
<th:block layout:fragment="contentFragment">
|
||||||
|
<style>
|
||||||
|
.recent-apps { margin: 0 0 24px; }
|
||||||
|
.recent-apps-title { font-size: 15px; font-weight: 600; color: #334155; margin: 0 0 10px; }
|
||||||
|
.recent-apps-list { list-style: none; margin: 0; padding: 0; border: 1px solid #E2E8F0; border-radius: 8px; overflow: hidden; }
|
||||||
|
.recent-apps-item + .recent-apps-item { border-top: 1px solid #E2E8F0; }
|
||||||
|
.recent-apps-head { display: flex; align-items: center; gap: 12px; width: 100%; padding: 14px 16px;
|
||||||
|
background: #F8FAFC; border: 0; cursor: pointer; text-align: left; font: inherit; }
|
||||||
|
.recent-apps-head:hover { background: #F1F5F9; }
|
||||||
|
.recent-apps-subject { flex: 1; min-width: 0; font-size: 14px; font-weight: 500; color: #1E293B;
|
||||||
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
|
.recent-apps-date { flex-shrink: 0; font-size: 12px; color: #94A3B8; }
|
||||||
|
.recent-apps-arrow { flex-shrink: 0; color: #94A3B8; transition: transform .2s ease; }
|
||||||
|
.recent-apps-item.is-open .recent-apps-arrow { transform: rotate(180deg); }
|
||||||
|
.recent-apps-body { display: none; padding: 14px 16px; background: #fff; }
|
||||||
|
.recent-apps-item.is-open .recent-apps-body { display: block; }
|
||||||
|
.recent-apps-detail { margin: 0; font-size: 13px; line-height: 1.6; color: #475569; white-space: pre-wrap; word-break: break-word; }
|
||||||
|
</style>
|
||||||
<section class="inquiry-form-container">
|
<section class="inquiry-form-container">
|
||||||
|
|
||||||
<!-- Title Bar -->
|
<!-- Title Bar -->
|
||||||
@@ -19,6 +36,27 @@
|
|||||||
<span class="register-subtitle">DJBank은 온라인 비즈니스 혁신을 위한 피드백/개선요청을 환영합니다.</span>
|
<span class="register-subtitle">DJBank은 온라인 비즈니스 혁신을 위한 피드백/개선요청을 환영합니다.</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 내가 작성한 최근 글(최대 3건) 아코디언 -->
|
||||||
|
<div class="recent-apps" th:if="${recentApplications != null and !recentApplications.isEmpty()}">
|
||||||
|
<p class="recent-apps-title">내가 작성한 최근 글</p>
|
||||||
|
<ul class="recent-apps-list">
|
||||||
|
<li class="recent-apps-item" th:each="item : ${recentApplications}">
|
||||||
|
<button type="button" class="recent-apps-head">
|
||||||
|
<span class="recent-apps-subject" th:text="${item.bizSubject}">제목</span>
|
||||||
|
<span class="recent-apps-date"
|
||||||
|
th:text="${item.createdDate != null ? #temporals.format(item.createdDate, 'yyyy.MM.dd') : ''}">2026.07.13</span>
|
||||||
|
<svg class="recent-apps-arrow" width="18" height="18" viewBox="0 0 24 24" fill="none"
|
||||||
|
stroke="currentColor" stroke-width="2" aria-hidden="true">
|
||||||
|
<polyline points="6 9 12 15 18 9"></polyline>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div class="recent-apps-body">
|
||||||
|
<p class="recent-apps-detail" th:text="${item.bizDetail}">내용</p>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Form Content -->
|
<!-- Form Content -->
|
||||||
<div class="register-form-container">
|
<div class="register-form-container">
|
||||||
<form name="partnershipForm" id="partnershipForm" th:action="@{/partnership}" th:object="${partnership}"
|
<form name="partnershipForm" id="partnershipForm" th:action="@{/partnership}" th:object="${partnership}"
|
||||||
@@ -131,6 +169,13 @@
|
|||||||
</script>
|
</script>
|
||||||
<script th:inline="javascript">
|
<script th:inline="javascript">
|
||||||
$(function () {
|
$(function () {
|
||||||
|
// 최근 글 아코디언 토글
|
||||||
|
document.querySelectorAll('.recent-apps-head').forEach(function (head) {
|
||||||
|
head.addEventListener('click', function () {
|
||||||
|
head.closest('.recent-apps-item').classList.toggle('is-open');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const btnSubmit = document.querySelector('.btn-submit-form');
|
const btnSubmit = document.querySelector('.btn-submit-form');
|
||||||
const fileInput = document.getElementById('file');
|
const fileInput = document.getElementById('file');
|
||||||
const fileDisplayText = document.getElementById('fileDisplayText');
|
const fileDisplayText = document.getElementById('fileDisplayText');
|
||||||
|
|||||||
Reference in New Issue
Block a user