미리미리 정리해뒀어야 했는데... 도서 사이트를 완성하고 이제서야 작성한다
책 상세보기에는 아래 사진과 같이
1. 책 정보
2. 책 소개, 목차, 출간자 서평
3. 해당 책 댓글
4. 우측 네비게이션
5. 하단 책 추천
으로 나눌 수 있다.
(책 상세보기의 Vue - script코드)
<script>
import CommentComponent from "@/views/book/bookComponents/CommentComponent";
import Recommend from "@/views/book/bookComponents/Recommend"
export default {
name: "BookDetailComponent",
components: {Recommend, CommentComponent},
data: function (){
return{
...
}
},
watch:{
$route(){
this.bid = this.$route.query.bid;
this.getBookDetail()
this.$vuetify.goTo(0)
}
},
computed:{
// 컴포넌트에서 페이지 변경
component() {
const wishTab = this.wishTab;
return () => import(`@/views/wishlist/${wishTab}`);
}
},
methods: {
getBookDetail(){
this.$axios.get('book/'+this.bid)
.then(response=>{
this.bookData = response.data
this.keyword = (response.data.bookKeyword.split(','))
//받아온 내용 줄바꿈 적용
this.bookData.bookContent = response.data.bookContent.replace(/(?:\r\n|\r|\n)/g, '<br />')
this.bookData.bookIndex = response.data.bookIndex.replace(/(?:\r\n|\r|\n)/g, '<br />')
this.bookData.bookPreview = response.data.bookPreview.replace(/(?:\r\n|\r|\n)/g, '<br />')
//detail item data set
//page
this.$set(this.detailItem[0],'data',response.data.bookPage +' page' )
//치수 & 무게
this.$set(this.detailItem[1],'data',response.data.bookSize.split('/')[0] )
this.$set(this.detailItem[2],'data',response.data.bookSize.split('/')[1] )
//Isbn - 10 & 13
this.$set(this.detailItem[3],'data',response.data.bookIsbn.split(/[()]/)[0] )
this.$set(this.detailItem[4],'data',response.data.bookIsbn.split(/[()]/)[1] )
//data
this.$set(this.detailItem[5],'data',response.data.bookPublishedDate)
})
.catch(error =>{
console.log(error.response);
})
},
//cart에 담기
addCart(){
this.$axios.get("cart/add/"+this.bid
).then(response=>{
console.log(response.data.message);
this.cartDialogMsg = "성공적으로 장바구니에 추가했습니다"
this.cartDialog = true
}).catch(error =>{
console.log(error.response);
this.cartDialogMsg = "장바구니 추가에 실패했습니다"
this.cartDialog = true
})
},
/*
* 컴포넌트 관련 메소드
*
* */
setComponentData(){
this.dialog =true;
this.setWishTab("WishList") // 디폴트 페이지는 항상 WishList
this.updateComponentKey() // 컴포넌트를 리로드 하기위해
},
updateComponentKey(){
this.componentKey +=1 //컴포넌트 리로드
},
setWishTab(data){
this.wishTab = data
},
//긑
pushLink(){
let cartArr = []
cartArr.push( {bid:this.bookData.bid, bookCount:1})
this.$store.dispatch('getOrderByDetail', cartArr)
.then(()=>
this.$router.push({path: '/order'}).catch(()=>console.log('잘못된 접근입니다'))
)
},
moveScroll(data){
let div = document.getElementById(data)
let abTop = window.pageYOffset + div.getBoundingClientRect().top;
this.$vuetify.goTo(abTop)
},
},
mounted() {
this.getBookDetail()
window.scrollTo(0, 0);
}
}
</script>
1 ,2 책 정보
위 코드는 책 세부정보의 Vue - 스크립트 부분이다
mounted로 책 정보를 불러온 후 정보들을 가공한다.
불러온 정보가 책 정보, 목차, 서평, 세부정보가 된다
3. 책 댓글 컴포넌트
(댓글 컴포넌트의 Vue - script코드 코드)
export default {
name: "CommentComponent",
props : ["selectBid"],
data: function (){
return{
...
}
},
watch: {
writeComment(val) {
this.commitBtn = val.length < 10;
}
},
methods: {
//정렬 설정 후 불러오기
//설정 안하고 바로 불러오면 다시 불러올때 (페이지 넘기거나할때) 초기화돼서
setSelectSort(index){
this.selectSort = index
this.getBookComment();
},
getBookComment() {
let data = {}
data.bid = this.selectBid
data.sortType = this.selectSort
data.page = this.page -1
data.size = this.size
this.$axios.post("comment/", JSON.stringify(data) ,{
headers: {
"Content-Type": `application/json`,
},
}).then(response=>{
this.commentData = response.data.content;
this.totalPages = response.data.totalPages;
if(response.data.content.length === 0){
this.noComments = true;
}
})
.catch(error =>{
console.log(error.response);
})
},
postComment(){
if(this.writeRating<1){
alert("별점을 입력해주세요")
}
else if(this.writeComment<11) {
alert("내용을 입력해주세요")
}else {
let data = {}
data.bid = this.selectBid;
data.mid = this.$store.state.member.userData.mid;
data.ratings = this.writeRating;
data.content = this.writeComment;
this.$axios.post("comment/user/write", JSON.stringify(data), {
headers: {
"Content-Type": `application/json`,
},
}).then(response => {
console.log(response.data)
this.$emit('childKey')
})
.catch(error => {
console.log(error.response);
})
}
},
//추천하기
setPopularity(data,cid){
console.log("popularity "+ data +" and "+ cid)
let comment = {}
comment.update = data
comment.cid = cid
this.$axios.post("comment/user/pop/", JSON.stringify(comment),{
headers: {
"Content-Type": `application/json`,
},
}).then(response=>{
console.log(response.data);
this.getBookComment();
}).catch(error =>{
console.log(error.response);
})
},
//종합 추천도 불러오기
getTotalRating() {
//clearInterval(this.interval)
this.$axios.get("comment/" + this.selectBid)
.then(response=>{
let totalCount = 0;
let sumMulti = 0;
for(let i = 0; i< response.data.length; i++) {
totalCount = totalCount + response.data[i].count
}
for(let i = 0; i<4; i++) {
//역순으로 리스트에 데이터 넣기
//별이 4개면 -> 0번째 리스트에 , 3개면 -> 1번째
if(response.data[i]==null){
continue;
}
this.ratingList[(this.ratingList.length - 1) - (response.data[i].ratings - 1)].count = response.data[i].count
this.ratingList[(this.ratingList.length - 1) - (response.data[i].ratings - 1)].per = Math.round(response.data[i].count / totalCount * 100);
//전체 별점 구하기
sumMulti = sumMulti + ( response.data[i].ratings * response.data[i].count )
}
this.totalRating = Math.round((sumMulti / totalCount) * 10) / 10;
this.totalCount = totalCount;
this.startBuffer()
}).catch(error =>{
console.log(error.response);
})
},
//그래프 동작
startBuffer(){
for(let i = 0 ; i<4; i++) {
this.interval = setInterval(() => {
if (this.ratingList[i].value === this.ratingList[i].per) {
return (this.ratingList[i].per)
}
this.ratingList[i].value += 1
}, 25)
}
},
},
mounted() {
this.getBookComment()
this.getTotalRating()
}
댓글 컴포넌트는 책 상세보기의 자식 컴포넌트이다.
댓글을 새로 불러오거나 해야하면 $emit을 사용하여 부모 컴포넌트에게 값을 보내 댓글 목록을 업데이트한다.
(추천과 댓글 작성에 사용)
3-1. 댓글 정렬
getComment() 부분을 보면 정렬부분이 있는걸 볼 수 있다.
정렬버튼은 최신순 추천순 별점순을 제공하고 클릭시 getComment() 의 sortType 에 0, 1, 2의 값을 넣어 보낸다
(0: 최신순, 1: 추천순, 2: 별점순)
java의 Comment Service
public Page<CommentBookMapping> getMyCommentList(SortDTO sortDTO) {
PageRequest pageRequest = PageRequest.of(sortDTO.getPage() , sortDTO.getSize());
//최신순
if(sortDTO.getSortType() == 0) {
return commentBookRepository.findAllByBidAndIsDel(getMemberIdByEmail(), "N", pageRequest);
}
//추천순
if(sortDTO.getSortType() == 1) {
return commentBookRepository.findByPopularity(getMemberIdByEmail(), "N", pageRequest);
}
//별점순
if(sortDTO.getSortType() == 2) {
return commentBookRepository.findByRatings(getMemberIdByEmail(), "N", pageRequest);
}
return null;
}
받은 sortType에 따라 각각의 JPA쿼리로 처리한다.
3-2. 별점과 댓글수
(추천도 불러오기 js부분)
//종합 추천도 불러오기
getTotalRating() {
//clearInterval(this.interval)
this.$axios.get("comment/" + this.selectBid)
.then(response=>{
let totalCount = 0;
let sumMulti = 0;
for(let i = 0; i< response.data.length; i++) {
totalCount = totalCount + response.data[i].count
}
for(let i = 0; i<4; i++) {
//역순으로 리스트에 데이터 넣기
//별이 4개면 -> 0번째 리스트에 , 3개면 -> 1번째
if(response.data[i]==null){
continue;
}
this.ratingList[(this.ratingList.length - 1) - (response.data[i].ratings - 1)].count = response.data[i].count
this.ratingList[(this.ratingList.length - 1) - (response.data[i].ratings - 1)].per = Math.round(response.data[i].count / totalCount * 100);
//전체 별점 구하기
sumMulti = sumMulti + ( response.data[i].ratings * response.data[i].count )
}
this.totalRating = Math.round((sumMulti / totalCount) * 10) / 10;
this.totalCount = totalCount;
this.startBuffer()
}).catch(error =>{
console.log(error.response);
})
},
페이지가 실행되면 댓글 불러오기와 같이 전체 별점을 가져오는 getTotalRatings() 함수가 mounted된다
가져온 데이터를 가공해 그래프 값에 넣어주고 각 별점을 보기쉽게 그래프로 나타낸다.
4. 우측 네비게이션
moveScroll(data){
let div = document.getElementById(data)
let abTop = window.pageYOffset + div.getBoundingClientRect().top;
this.$vuetify.goTo(abTop)
},
우측 네비게이션의 각 목차를 클릭하면 위 함수가 실행되면서 해당 목차 구역으로 이동한다.
각 목차의 최상단에 id를 지정해 높이를 구하고 $vuetify.goTo로 부드럽게 이동한다 (영상참고)
5. 하단 책 추천 컴포넌트
public List<BookMainInterface> getRecommend(Long bid) {
Optional<Book> bookData = bookRepository.findBookByBid(bid);
Book data = bookData.orElseThrow(() -> new RuntimeException("no data"));
String keyword = data.getBookKeyword().replace(',','|');
return bookRepository.getRecommendRand(keyword, bid, "N");
}
해당 book id로 키워드를 가져와 RegEXP로 해당 키워드를 포함하는 모든 책 중 rand쿼리와 limit를 사용하여
조건에 맞는 랜덤 4가지의 책을 가져온다.
jpa nativeQuery
@Query(value = "select b.bid, b.bookThumb ,b.bookTitle ,b.bookKeyword, b.bookAuthor, b.bookPublisher FROM Book b where (b.bookKeyword regexp :keyword) and not b.bid=:bid and b.isDel=:isDel order by rand() limit 4", nativeQuery = true)
List<BookMainInterface> getRecommendRand(@Param("keyword") String keyword, @Param("bid") Long bid, @Param("isDel") String isDel);
'ETC' 카테고리의 다른 글
13. 마이페이지-1 (장바구니, 위시 리스트, 주문목록) (0) | 2022.07.11 |
---|---|
12. Vuex Store ( 로그인 회원정보와 주문정보 Store ) (0) | 2022.07.11 |
book Store (Spring boot + Vue.js ) (1) | 2022.07.07 |
20210802 오후 (0) | 2021.08.02 |
20210802 오전 (0) | 2021.08.02 |