-
쇼핑몰 프로젝트 --별 기능(화면구현)쇼핑몰 프로젝트 2024. 6. 26. 19:02
아이템 전체 리스트, 카테고리 별 아이템 리스트에 별 표시되게 하는 거 추가
item/itemList (itemCategoryList 도 동일하게 추가해서 따로 안적음)
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" lang="en"> <head th:replace="frame/header :: head"> <title>Zay Shop - Product Listing Page</title> </head> <style> .fixed-size-img { width: 300px; /* 원하는 너비로 설정 */ height: 300px; /* 원하는 높이로 설정 */ object-fit: cover; /* 이미지를 크기에 맞게 조정 */ } </style> <body> <!--header--> <header th:replace="frame/header :: header"></header> <!-- Start Content --> <div class="container py-5"> <div class="row"> <div class="container-fluid mt-3"> <div class="row"> <div class="col-md-12"> <ul class="list-inline shop-top-menu pb-3 pt-1"> <li class="list-inline-item"> <a class="h3 text-dark text-decoration-none mr-3" th:href="@{/ypjs/item/post}">상품 등록</a> </li> <li class="list-inline-item"> <a class="h3 text-dark text-decoration-none mr-3" th:href="@{/ypjs/category/post}">카테고리 등록</a> </li> <li class="list-inline-item"> <a class="h3 text-dark text-decoration-none mr-3" th:href="@{/ypjs/category/get}">카테고리 보기</a> </li> </ul> </div> </div> </div> <div class="col-lg-3"> <h1 class="h2 pb-4">Categories</h1> <ul class="list-unstyled templatemo-accordion"> <li class="pb-3"> <a class="collapsed d-flex justify-content-between h3 text-decoration-none" href="#"> Women <i class="fa fa-fw fa-chevron-circle-down mt-1"></i> </a> <ul class="collapse show list-unstyled pl-3"> <li><a class="text-decoration-none" th:href="@{/ypjs/categoryItem/get/{categoryId}(categoryId=3)}">Outer</a></li> <li><a class="text-decoration-none" th:href="@{/ypjs/categoryItem/get/{categoryId}(categoryId=4)}">Top</a></li> <li><a class="text-decoration-none" th:href="@{/ypjs/categoryItem/get/{categoryId}(categoryId=5)}">Bottom</a></li> </ul> </li> <li class="pb-3"> <a class="collapsed d-flex justify-content-between h3 text-decoration-none" href="#"> Man <i class="pull-right fa fa-fw fa-chevron-circle-down mt-1"></i> </a> <ul id="collapseTwo" class="collapse list-unstyled pl-3"> <li><a class="text-decoration-none" th:href="@{/ypjs/categoryItem/get/{categoryId}(categoryId=6)}">Outer</a></li> <li><a class="text-decoration-none" th:href="@{/ypjs/categoryItem/get/{categoryId}(categoryId=7)}">Top</a></li> <li><a class="text-decoration-none" th:href="@{/ypjs/categoryItem/get/{categoryId}(categoryId=8)}">Bottom</a></li> </ul> </li> </ul> </div> <div class="col-lg-9"> <div class="row"> <div class="col-md-6"> <ul class="list-inline shop-top-menu pb-3 pt-1"> <li class="list-inline-item"> <a class="h3 text-dark text-decoration-none mr-3" th:href="@{/ypjs/item/get}">All Items</a> </li> </ul> </div> <!-- <div class="col-md-6">--> <!-- <form action="#" th:action="@{/ypjs/item/get}" method="get">--> <!-- <div class="col-md-6 pb-4">--> <!-- <div class="d-flex">--> <!-- <select class="form-control" name="sortBy" id="sortBy" onchange="this.form.submit()">--> <!-- <option value="itemId" th:selected="${sortBy == 'itemId'}">최신순</option>--> <!-- <option value="itemRatings" th:selected="${sortBy == 'itemRatings'}">별점 높은 순</option>--> <!-- <option value="likeCount" th:selected="${sortBy == 'likeCount'}">찜많은순</option>--> <!-- </select>--> <!-- </div>--> <!-- </div>--> <!-- </form>--> <!-- </div>--> <!-- <div class="container">--> <!-- <div class="row">--> <!-- <div class="col-lg-9">--> <!-- <!– 검색 폼 –>--> <!-- <form th:action="@{/ypjs/item/get}" method="get">--> <!-- <div class="form-row align-items-center mb-3">--> <!-- <div class="col-auto">--> <!-- <label for="keyword" class="sr-only">Keyword</label>--> <!-- <input type="text" id="keyword" name="keyword" class="form-control"--> <!-- placeholder="Search by item name" th:value="${keyword}">--> <!-- </div>--> <!-- <div class="col-auto">--> <!-- <button type="submit" class="btn btn-primary">Search</button>--> <!-- </div>--> <!-- </div>--> <!-- </form>--> <!-- </div>--> <!-- </div>--> <div class="col-lg-6"> <!-- 검색 폼 및 정렬 폼 통합 --> <form th:action="@{/ypjs/item/get}" method="get" class="input-group"> <input type="text" id="keyword" name="keyword" class="form-control" placeholder="제목으로 검색하기" th:value="${keyword}"> <div class="input-group-append"> <button type="submit" class="btn btn-link text-dark"> <i class="fa fa-search"></i> </button> </div> <div class="col-auto"> <select class="form-control" name="sortBy" id="sortBy" onchange="this.form.submit()"> <option value="itemId" th:selected="${sortBy == 'itemId'}">최신순</option> <option value="itemRatings" th:selected="${sortBy == 'itemRatings'}">별점 높은 순</option> <option value="likeCount" th:selected="${sortBy == 'likeCount'}">찜많은순</option> </select> </div> </form> </div> <!-- 반별 추가--> <!-- <div class="container-fluid mt-3">--> <!-- <div class="row">--> <!-- <!– items 리스트의 각 항목을 반복 –>--> <!-- <div th:each="item : ${items}" class="col-md-4">--> <!-- <div class="card mb-4 product-wap rounded-0">--> <!-- <!– 제품 이미지 –>--> <!-- <div class="card rounded-0">--> <!-- <a th:href="@{/ypjs/item/get/{itemId}(itemId=${item.itemId})}">--> <!-- <img class="card-img rounded-0 img-fluid fixed-size-img" th:src="${item.itemFilePath}" alt="product-item">--> <!-- <!– 필요한 경우 오버레이나 추가 요소를 여기에 추가할 수 있습니다 –>--> <!-- <div class="card-img-overlay rounded-0 product-overlay d-flex align-items-center justify-content-center">--> <!-- <!– 추가적인 콘텐츠가 필요하다면 여기에 추가할 수 있습니다 –>--> <!-- <ul class="list-unstyled">--> <!-- <!– 리스트의 다른 요소들 –>--> <!-- </ul>--> <!-- </div>--> <!-- </a>--> <!-- </div>--> <!-- <!– 제품 정보 –>--> <!-- <div class="card-body">--> <!-- <!– 제품 링크 –>--> <!-- <a th:href="@{/ypjs/item/get/{itemId}(itemId=${item.itemId})}" id="itemName" class="font-weight-bold" th:text="${item.itemName}"></a>--> <!-- <!– 별점 및 평점 표시 –>--> <!-- <div class="d-flex justify-content-center mb-1 align-items-center">--> <!-- <ul class="list-unstyled d-flex mb-0" id="starRating" th:attr="data-rating=${item.itemRatings}">--> <!-- <!– 별 아이콘은 JavaScript로 생성됩니다 –>--> <!-- </ul> --> <!-- <span id="itemRatings" class="font-weight-bold ml-2" th:text="${item.itemRatings}"></span>--> <!-- </div>--> <!-- <!– 가격 표시 –>--> <!-- <span id="itemPrice" class="font-weight-bold" th:text="${item.itemPrice}"></span>--> <!-- <span class="font-weight-bold">원</span>--> <!-- </div>--> <!-- </div>--> <!-- </div>--> <!-- </div>--> <!-- </div>--> <!-- <script>--> <!-- document.addEventListener("DOMContentLoaded", function() {--> <!-- var starRatingContainers = document.querySelectorAll("#starRating");--> <!-- starRatingContainers.forEach(function(starRatingContainer) {--> <!-- var rating = parseFloat(starRatingContainer.getAttribute("data-rating"));--> <!-- starRatingContainer.innerHTML = generateStarRating(rating);--> <!-- });--> <!-- });--> <!-- function generateStarRating(rating) {--> <!-- var starsHTML = '';--> <!-- var fullStars = Math.floor(rating); // 정수 부분의 별 개수--> <!-- var halfStar = (rating % 1 >= 0.1 && rating % 1 <= 0.9) ? 1 : 0; // 반 별 조건--> <!-- // 정수 부분의 별 추가--> <!-- for (var i = 0; i < fullStars; i++) {--> <!-- starsHTML += '<i class="text-warning fa fa-star"></i>';--> <!-- }--> <!-- // 반 별 추가--> <!-- if (halfStar) {--> <!-- starsHTML += '<i class="text-warning fa fa-star-half-alt"></i>';--> <!-- }--> <!-- // 남은 빈 별 추가--> <!-- var emptyStars = 5 - fullStars - halfStar;--> <!-- for (var i = 0; i < emptyStars; i++) {--> <!-- starsHTML += '<i class="text-muted fa fa-star"></i>';--> <!-- }--> <!-- return starsHTML;--> <!-- }--> <!-- </script>--> <!-- 꽉찬 별만--> <div class="container-fluid mt-3"> <div class="row"> <!-- items 리스트의 각 항목을 반복 --> <div th:each="item : ${items}" class="col-md-4"> <div class="card mb-4 product-wap rounded-0"> <!-- 제품 이미지 --> <div class="card rounded-0"> <a th:href="@{/ypjs/item/get/{itemId}(itemId=${item.itemId})}"> <img class="card-img rounded-0 img-fluid fixed-size-img" th:src="${item.itemFilePath}" alt="product-item"> <!-- 필요한 경우 오버레이나 추가 요소를 여기에 추가할 수 있습니다 --> <div class="card-img-overlay rounded-0 product-overlay d-flex align-items-center justify-content-center"> <!-- 추가적인 콘텐츠가 필요하다면 여기에 추가할 수 있습니다 --> <ul class="list-unstyled"> <!-- 리스트의 다른 요소들 --> </ul> </div> </a> </div> <!-- 제품 정보 --> <div class="card-body"> <!-- 제품 링크 --> <a th:href="@{/ypjs/item/get/{itemId}(itemId=${item.itemId})}" id="itemName" class="font-weight-bold" th:text="${item.itemName}"></a> <!-- 별점 및 평점 표시 --> <div class="d-flex justify-content-center mb-1 align-items-center"> <ul class="list-unstyled d-flex mb-0" id="starRating" th:attr="data-rating=${item.itemRatings}"> <!-- 별 아이콘은 JavaScript로 생성됩니다 --> </ul> <span id="itemRatings" class="font-weight-bold ml-2" th:text="${item.itemRatings}"></span> </div> <!-- 가격 표시 --> <span id="itemPrice" class="font-weight-bold" th:text="${item.itemPrice}"></span> <span class="font-weight-bold">원</span> </div> </div> </div> </div> </div> <script> document.addEventListener("DOMContentLoaded", function() { var starRatingContainers = document.querySelectorAll("#starRating"); starRatingContainers.forEach(function(starRatingContainer) { var rating = parseFloat(starRatingContainer.getAttribute("data-rating")); starRatingContainer.innerHTML = generateStarRating(rating); }); }); function generateStarRating(rating) { var starsHTML = ''; var numStars; if (rating >= 0 && rating < 1) { numStars = 0; } else if (rating >= 1 && rating < 2) { numStars = 1; } else if (rating >= 2 && rating < 3) { numStars = 2; } else if (rating >= 3 && rating < 4) { numStars = 3; } else if (rating >= 4 && rating < 5) { numStars = 4; } else if (rating == 5) { numStars = 5; } for (var i = 0; i < numStars; i++) { starsHTML += '<i class="text-warning fa fa-star"></i>'; } for (var i = numStars; i < 5; i++) { starsHTML += '<i class="text-muted fa fa-star"></i>'; } return starsHTML; } </script> </div> </div> </div> </div> <!-- End Content --> <!-- Start Brands --> <section class="bg-light py-5"> <div class="container my-4"> <div class="row text-center py-3"> <div class="col-lg-6 m-auto"> <h1 class="h1">Our Brands</h1> <p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod Lorem ipsum dolor sit amet. </p> </div> <div class="col-lg-9 m-auto tempaltemo-carousel"> <div class="row d-flex flex-row"> <!--Controls--> <div class="col-1 align-self-center"> <a class="h1" href="#multi-item-example" role="button" data-bs-slide="prev"> <i class="text-light fas fa-chevron-left"></i> </a> </div> <!--End Controls--> <!--Carousel Wrapper--> <div class="col"> <div class="carousel slide carousel-multi-item pt-2 pt-md-0" id="multi-item-example" data-bs-ride="carousel"> <!--Slides--> <div class="carousel-inner product-links-wap" role="listbox"> <!--First slide--> <div class="carousel-item active"> <div class="row"> <div class="col-3 p-md-5"> <a href="#"><img class="img-fluid brand-img" src="/img/brand_01.png" alt="Brand Logo"></a> </div> <div class="col-3 p-md-5"> <a href="#"><img class="img-fluid brand-img" src="/img/brand_02.png" alt="Brand Logo"></a> </div> <div class="col-3 p-md-5"> <a href="#"><img class="img-fluid brand-img" src="/img/brand_03.png" alt="Brand Logo"></a> </div> <div class="col-3 p-md-5"> <a href="#"><img class="img-fluid brand-img" src="/img/brand_04.png" alt="Brand Logo"></a> </div> </div> </div> <!--End First slide--> <!--Second slide--> <div class="carousel-item"> <div class="row"> <div class="col-3 p-md-5"> <a href="#"><img class="img-fluid brand-img" src="/img/brand_01.png" alt="Brand Logo"></a> </div> <div class="col-3 p-md-5"> <a href="#"><img class="img-fluid brand-img" src="/img/brand_02.png" alt="Brand Logo"></a> </div> <div class="col-3 p-md-5"> <a href="#"><img class="img-fluid brand-img" src="/img/brand_03.png" alt="Brand Logo"></a> </div> <div class="col-3 p-md-5"> <a href="#"><img class="img-fluid brand-img" src="/img/brand_04.png" alt="Brand Logo"></a> </div> </div> </div> <!--End Second slide--> <!--Third slide--> <div class="carousel-item"> <div class="row"> <div class="col-3 p-md-5"> <a href="#"><img class="img-fluid brand-img" src="/img/brand_01.png" alt="Brand Logo"></a> </div> <div class="col-3 p-md-5"> <a href="#"><img class="img-fluid brand-img" src="/img/brand_02.png" alt="Brand Logo"></a> </div> <div class="col-3 p-md-5"> <a href="#"><img class="img-fluid brand-img" src="/img/brand_03.png" alt="Brand Logo"></a> </div> <div class="col-3 p-md-5"> <a href="#"><img class="img-fluid brand-img" src="/img/brand_04.png" alt="Brand Logo"></a> </div> </div> </div> <!--End Third slide--> </div> <!--End Slides--> </div> </div> <!--End Carousel Wrapper--> <!--Controls--> <div class="col-1 align-self-center"> <a class="h1" href="#multi-item-example" role="button" data-bs-slide="next"> <i class="text-light fas fa-chevron-right"></i> </a> </div> <!--End Controls--> </div> </div> </div> </div> </section> <!--End Brands--> <footer th:replace="frame/footer :: footer"></footer> </body> </html>
아이템 당 리뷰도 구현
item/itemGet
리뷰쓰기에서 별점 구현
itemReview/itemReviewPost
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" lang="en"> <head th:replace="frame/header :: head"> <title>Zay Shop - Product Listing Page</title> </head> <body> <!--header--> <header th:replace="frame/header :: header"></header> <!-- Start Content --> <div class="container py-5"> 리뷰등록 </div> <!-- End Content --> <!-- jQuery --> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <!-- Summernote 스타일 및 스크립트 --> <link href="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.18/summernote-bs4.min.css" rel="stylesheet"> <script src="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.18/summernote-bs4.min.js"></script> <!-- JS 파일 포함 --> <script src="/js/jquery-1.11.0.min.js"></script> <script src="/js/summernote-lite.js"></script> <script src="/js/summernote-ko-KR.js"></script> <script src="/js/item/itemReview.js"></script> <script src="/js/item/itemRatings.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.18/summernote.min.js"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"> <style> .rating-stars { font-size: 24px; /* 별 아이콘 크기 */ color: #ccc; /* 비어 있는 별 색상 */ cursor: pointer; /* 포인터 커서 추가 */ } .filled-star { color: gold; /* 채워진 별 색상 */ } </style> <!-- Start Contact --> <div class="container py-5"> <div class="row justify-content-center py-5"> <!-- 폼 요소들 --> <div class="col-lg-8"> <div class="row"> <input type="hidden" id="itemId" th:value="${item.itemId}" > <!-- Thymeleaf의 value 속성 사용 --> <input type="hidden" id="memberId" value="1"> <!-- memberId 값 받아와야 됨 --> <div class="form-group mb-3"> <label for="itemReviewName">제목</label> <input type="text" class="form-control mt-1" id="itemReviewName" name="itemReviewName" placeholder="제목"> </div> <br><br><br><br> <div class="container"> <label for="itemScore">별점을 입력하세요</label> <div id="starRating" class="mt-3"> <!-- 별 아이콘이 동적으로 추가될 위치 --> </div> <input type="hidden" id="itemScore" name="itemScore" value="0"> </div> <BR><br><br><br> <div class="form-group mb-3"> <label for="itemReviewContent">내용</label> <textarea class="form-control" id="itemReviewContent" name="itemReviewContent" rows="10"></textarea> </div> <!-- Summernote 초기화 스크립트 --> <script th:inline="javascript"> $(document).ready(function() { $("#itemReviewContent").summernote({ height: 300, // 높이 설정 placeholder: '내용을 입력하세요...', // 플레이스홀더 설정 callbacks: { onChange: function(contents, $editable) { // 내용이 변경될 때 처리할 로직 추가 가능 } } }); }); </script> <!-- 글 등록 버튼 --> <div class="row"> <div class="col text-end mt-2"> <button type="button" id="btn-itemReviewPost" class="btn btn-success btn-lg px-3">리뷰등록</button> </div> </div> </div> </div> </div> </div> <!-- End Contact --> <footer th:replace="frame/footer :: footer"></footer> </body> </html>
itemRatings.js
$(document).ready(function() { var initialScore = $('#itemScore').val(); // 기존의 itemScore 값 가져오기 $('#starRating').html(generateStarRating(initialScore)); // 초기화: 기존의 별점으로 별 아이콘 표시 // 별 아이콘 클릭 이벤트 리스너 추가 $('#starRating').on('click', '.fa-star', function() { var score = $(this).data('score'); $('#itemScore').val(score); // hidden 필드에 새로운 점수 설정 $('#starRating').html(generateStarRating(score)); // 별 아이콘 업데이트 }); // 별 아이콘을 생성하여 HTML 문자열 반환하는 함수 function generateStarRating(score) { var starsHTML = ''; for (var i = 1; i <= 5; i++) { if (i <= score) { starsHTML += '<i class="fas fa-star rating-stars filled-star" data-score="' + i + '"></i>'; } else { starsHTML += '<i class="fas fa-star rating-stars" data-score="' + i + '"></i>'; } } return starsHTML; } });
itemReview.js
let itemBoardObject = { init: function() { let _this = this; $("#btn-itemReviewPost").on("click", function() { _this.insert(); }), $("#btn-itemReviewUpdate").on("click", function() { _this.update(); }), $(document).on("click", ".btn-delete-itemReview", function() { // 클릭된 버튼의 데이터 속성에서 itemReviewId를 가져옴 let itemReviewId = $(this).data("itemreviewid"); // 아이템 리뷰 삭제 함수 호출 _this.deleteItemReview(itemReviewId); }); }, insert: function() { let itemId = $("#itemId").val(); // URL에 사용할 itemId를 가져옴 let itemScore = $("#itemScore").val(); // 별점 가져오기 let itemReviewName = $("#itemReviewName").val(); // 제목 가져오기 // 별점을 선택하지 않은 경우 처리 if (itemScore === "0") { alert("별점을 선택하세요."); return; // 리뷰 등록 중단 } // 제목이 비어 있는지 확인 if (!itemReviewName || itemReviewName.trim().length === 0) { alert("제목을 입력하세요."); return; // 리뷰 등록 중단 } let data = { itemId: itemId, // itemId를 데이터에 포함 memberId: $("#memberId").val(), // 멤버 ID 추가 itemReviewName: $("#itemReviewName").val(), itemScore: $("#itemScore").val(), itemReviewContent: $("#itemReviewContent").val(), }; $.ajax({ type: "POST", url: "/ypjs/itemReview/post/" + itemId, // URL에 itemId를 추가 data: JSON.stringify(data), contentType: "application/json; charset=utf-8", success: function(response) { alert("리뷰가 등록되었습니다."); window.location.href = "/ypjs/itemReview/get/" + itemId; // 성공 후 리디렉션 }, error: function(error) { alert("에러 발생: " + JSON.stringify(error)); } }); }, update: function() { let itemReviewId = $("#itemReviewId").val(); let itemScore = $("#itemScore").val(); // 별점 가져오기 // 별점을 선택하지 않은 경우 처리 if (itemScore === "0") { alert("별점을 선택하세요."); return; // 리뷰 등록 중단 } let updateData = { itemReviewName: $("#itemReviewName").val(), itemScore: $("#itemScore").val(), itemReviewContent: $("#itemReviewContent").val(), }; $.ajax({ type: "PUT", url: "/ypjs/itemReview/update/" + itemReviewId, data: JSON.stringify(updateData), contentType: "application/json; charset=utf-8", success: function(response) { alert("리뷰가 수정되었습니다."); window.location.href = "/ypjs/itemReview/get/" + response ; }, error: function(error) { alert("에러 발생: " + JSON.stringify(error)); // 에러 발생 시 적절히 처리하도록 수정이 필요할 수 있습니다. } }); }, deleteItemReview: function(itemReviewId) { let itemId = $("#itemId").val(); $.ajax({ type: "DELETE", url: "/ypjs/itemReview/delete/" + itemReviewId, success: function(response) { alert("리뷰가 삭제되었습니다."); window.location.href = "/ypjs/itemReview/get/" + itemId; }, error: function(xhr, status, error) { alert("에러 발생: " + error); } }); } }; $(document).ready(function() { itemBoardObject.init(); });
별점 유효성검사 추가
itemreview/itemReviewUpdate
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" lang="en"> <head th:replace="frame/header :: head"> <title>Zay Shop - Product Listing Page</title> </head> <body> <!--header--> <header th:replace="frame/header :: header"></header> <!-- Start Content --> <div class="container py-5"> 리뷰수정 </div> <!-- End Content --> <!-- jQuery --> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <!-- Summernote 스타일 및 스크립트 --> <link href="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.18/summernote-bs4.min.css" rel="stylesheet"> <script src="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.18/summernote-bs4.min.js"></script> <!-- JS 파일 포함 --> <script src="/js/jquery-1.11.0.min.js"></script> <script src="/js/summernote-lite.js"></script> <script src="/js/summernote-ko-KR.js"></script> <script src="/js/item/itemReview.js"></script> <script src="/js/item/itemRatings.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.18/summernote.min.js"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"> <style> .rating-stars { font-size: 24px; /* 별 아이콘 크기 */ color: #ccc; /* 비어 있는 별 색상 */ cursor: pointer; /* 포인터 커서 추가 */ } .filled-star { color: gold; /* 채워진 별 색상 */ } </style> <!-- Start Contact --> <div class="container py-5"> <div class="row justify-content-center py-5"> <!-- 폼 요소들 --> <div class="col-lg-8"> <div class="row"> <input type="hidden" id="itemReviewId" th:value="${itemReview.itemReviewId}"> <div class="form-group mb-3"> <label for="itemReviewName">제목</label> <input type="text" class="form-control mt-1" id="itemReviewName" name="itemReviewName" th:value="${itemReview.itemReviewName}" placeholder="제목"> </div> <div class="container"> <div id="starRating" class="mt-3" data-rating="${itemReview.itemScore}"> <!-- 별 아이콘이 동적으로 추가될 위치 --> </div> <input type="hidden" id="itemScore" name="itemScore" th:value="${itemReview.itemScore}" value="0"> </div> </div> <div class="mb-3"> <label for="itemReviewContent">내용</label> <textarea class="form-control" id="itemReviewContent" name="itemReviewContent" th:text="${itemReview.itemReviewContent}" rows="10"></textarea> </div> <!-- Summernote 초기화 스크립트 --> <script th:inline="javascript"> $(document).ready(function() { $("#itemReviewContent").summernote({ height: 300, // 높이 설정 placeholder: '내용을 입력하세요...', // 플레이스홀더 설정 callbacks: { onChange: function(contents, $editable) { // 내용이 변경될 때 처리할 로직 추가 가능 } } }); }); </script> <!-- 글 등록 버튼 --> <div class="row"> <div class="col text-end mt-2"> <button type="button" id="btn-itemReviewUpdate" class="btn btn-success btn-lg px-3">리뷰수정</button> </div> </div> </div> </div> </div> <!-- End Contact --> <footer th:replace="frame/footer :: footer"></footer> </body> </html>
별점 받아오기 itemRatings.js에
var initialScore = $('#itemScore').val();
$('#starRating').html(generateStarRating(initialScore));
이거 추가 위에 올라간 js는 이미 추가 된 js
아이템 리뷰 목록
itemreview/itemReviewGet
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" lang="en"> <head th:replace="frame/header :: head"> <title>Zay Shop - Product Listing Page</title> </head> <body> <!--header--> <header th:replace="frame/header :: header"></header> <!-- Start Content --> <div class="container py-5"> 아이템 리뷰 </div> <!-- End Content --> <!-- jQuery --> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <!-- JS 파일 포함 --> <script src="/js/jquery-1.11.0.min.js"></script> <script src="/js/summernote-lite.js"></script> <script src="/js/summernote-ko-KR.js"></script> <script src="/js/item/itemReview.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.18/summernote.min.js"></script> <!-- Start Contact --> <div class="container py-5"> <div class="row py-5"> <form class="col-md-9 m-auto" method="post" > <!-- 폼 요소들 --> <div class="row"> <style> .category-box { border: 1px solid #ccc; padding: 10px; margin-bottom: 10px; } .category-label { font-weight: bold; } .item-box { border: 1px solid #ccc; padding: 10px; margin-bottom: 10px; } .item-info { /* Optional: Add additional styles for item information */ } .category-label { font-weight: bold; } </style> <div th:if="${not #lists.isEmpty(itemReviews)}"> <br><br><br> <h3>리뷰 목록</h3> <br> <div th:each="itemReview : ${itemReviews}" class="item-box"> <div class="item-info"> <div> <span class="category-label">아이템 이름 : </span> <span th:text="${itemReview.itemReviewName}"></span> </div> <!-- 별점 및 평점 표시 --> <div class="d-flex justify-content-left mb-1 align-items-left"> <span class="category-label">별점 : </span> <ul class="list-unstyled d-flex mb-0" id="starRating" th:attr="data-rating=${itemReview.itemScore}"> <!-- 별 아이콘은 JavaScript로 생성됩니다 --> </ul> </div> <script> document.addEventListener("DOMContentLoaded", function() { var starRatingContainers = document.querySelectorAll("#starRating"); starRatingContainers.forEach(function(starRatingContainer) { var rating = parseFloat(starRatingContainer.getAttribute("data-rating")); starRatingContainer.innerHTML = generateStarRating(rating); }); }); function generateStarRating(rating) { var starsHTML = ''; var numStars; if (rating >= 0 && rating < 1) { numStars = 0; } else if (rating >= 1 && rating < 2) { numStars = 1; } else if (rating >= 2 && rating < 3) { numStars = 2; } else if (rating >= 3 && rating < 4) { numStars = 3; } else if (rating >= 4 && rating < 5) { numStars = 4; } else if (rating == 5) { numStars = 5; } for (var i = 0; i < numStars; i++) { starsHTML += '<i class="text-warning fa fa-star"></i>'; } for (var i = numStars; i < 5; i++) { starsHTML += '<i class="text-muted fa fa-star"></i>'; } return starsHTML; } </script> <div> <span class="category-label">리뷰 내용 : </span> <div style="text-align: left;"> <!-- 썸머노트에서 입력한 리뷰 내용 --> <div id="reviewContent" th:utext="${itemReview.itemReviewContent}"> <!-- 썸머노트에서 삽입된 이미지의 스타일 --> <style> #reviewContent img { display: block; /* 이미지가 한 줄에 나타나도록 설정 */ margin: auto; /* 가운데 정렬 */ max-width: 100%; /* 최대 너비 설정 */ height: auto; /* 높이 자동으로 조정 */ margin-bottom: 10px; /* 이미지 아래 여백 추가 */ } </style> </div> </div> </div> <input type="hidden" id="itemId" th:value="${itemReview.itemId}"> <!-- 수정 및 삭제 버튼 --> <div class="container"> <div class="row justify-content-end"> <div class="col-auto"> <a th:href="@{/ypjs/itemReview/update/{itemReviewId}(itemReviewId=${itemReview.itemReviewId})}" class="btn btn-warning">수정하기</a> </div> <div class="col-auto"> <button type="button" class="btn btn-danger btn-sm btn-delete-itemReview" th:data-itemReviewId="${itemReview.itemReviewId}" style="padding: 2px 10px; font-size: 16px; width: 90px; height: 40px;"> 삭제하기 </button> </div> </div> </div> </div> </div> </div> <!-- End Contact --> </div> </form> </div> </div> <footer th:replace="frame/footer :: footer"></footer> </body> </html>
썸네일 유효성 검사
// 폼 제출 전 유효성 검사 $('form').submit(function(event) { var fileInput = document.getElementById('file'); if (fileInput.files.length === 0) { alert('썸네일 파일을 선택하세요.'); event.preventDefault(); // 폼 제출 방지 } });
이부분 itme/itemPost, item/itemUpdate에 추가
예) item/itemPost
<!-- Summernote 초기화 스크립트 --> <script th:inline="javascript"> $(document).ready(function() { $("#itemContent").summernote({ height: 600, // 높이 설정 placeholder: '상품 내용을 입력하세요...', // 플레이스홀더 설정 callbacks: { onChange: function(contents, $editable) { // 내용이 변경될 때 처리할 로직 추가 가능 } } }); }); // 파일명을 표시하는 함수 function displayFileName(input) { if (input.files.length > 0) { var fileName = input.files[0].name; document.getElementById('file-name-display').innerText = '선택된 파일: ' + fileName; } else { document.getElementById('file-name-display').innerText = ''; } } // 폼 제출 전 유효성 검사 $('form').submit(function(event) { var fileInput = document.getElementById('file'); if (fileInput.files.length === 0) { alert('썸네일 파일을 선택하세요.'); event.preventDefault(); // 폼 제출 방지 } }); </script>
여기에 추가 그러면
이렇게 뜸
'쇼핑몰 프로젝트' 카테고리의 다른 글
쇼핑몰 프로젝트 --카테고리 링크수정, 컨트롤러분리,유효성검사(화면구현) (0) 2024.07.02 쇼핑몰 프로젝트 --페이지네이션, 유효성검사, 리뷰 정렬(화면구현) (0) 2024.06.28 쇼핑몰 프로젝트 --리뷰 수정, 삭제, 아이템 검색, 정렬(화면구현) (0) 2024.06.26 쇼핑몰 프로젝트 -- 카테고리, 리뷰(화면구현) (0) 2024.06.20 쇼핑몰 프로젝트 --아이템조회, 삭제, 아이템전체리스트조회 (화면구현) (0) 2024.06.19