feature/comment-0624-ch
ch 2 years ago
parent 5864830b29
commit e78c41f6c2

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

@ -0,0 +1,55 @@
<!--
* @Author: ch
* @Date: 2022-06-23 10:40:04
* @LastEditors: ch
* @LastEditTime: 2022-06-24 16:21:52
* @Description: file content
-->
<template>
<div class="follow">
<b class="follow--title">{{day}}追评:</b>
<p class="follow--ctx">{{followComment.commentContent}}</p>
<!-- <view class="follow--img" v-if="imgs.length">
<image class="follow--img-item" v-for="(item, idx) in imgs" :src="item" :key="idx" @click="preview(idx)" mode="aspectFit"/>
</view> -->
</div>
</template>
<script>
export default {
props : {
followComment : {
type : Object,
default : () => ({})
},
commentTime : {
type : String,
default : ''
}
},
computed:{
day(){
const followTime = (new Date(this.followComment.createTime)).getTime();
const commentTime = (new Date(this.commentTime)).getTime();
const day = Math.floor((followTime - commentTime) / (24 * 60 * 60 * 1000));
return day > 0 ? `${day}天后` : `当天`;
},
imgs (){
let urls = this.followComment.pictureUrl || '';
return urls ? urls.split(',') : [];
}
}
}
</script>
<style lang="scss" scoped>
.follow{
margin-top: 30px;
&--title{
color: #FF6A19;
font-weight: normal;
}
&--ctx{
line-height: 24px;
}
}
</style>

@ -0,0 +1,290 @@
<!--
* @Author: ch
* @Date: 2022-06-24 11:43:04
* @LastEditors: ch
* @LastEditTime: 2022-06-27 10:35:22
* @Description: file content
-->
<template>
<div class="comment-info">
<div class="side">
<el-avatar :size="55" :src="commentDetail.userAvatar" />
<p>{{commentDetail.userName}}</p>
</div>
<main>
<div class="top">
<el-rate :value="commentDetail.commentScore" disabled/>
<span class="time">{{commentDetail.createTime}}</span>
</div>
<p class="sku">已购买{{commentDetail.skuName}}</p>
<div class="ctx">{{commentDetail.commentContent}}</div>
<UiImgs v-if="imgs.length" :list="imgs" class="imgs" />
<BsCommentFollowInfo v-if="commentDetail.followComment" :followComment="commentDetail.followComment" :commentTime="commentDetail.commentTime"/>
<div class="operation">
<div>
<span class="operation--chat" @click="answerVisible = !answerVisible">
<template v-if="answerCommentList.length">{{answerCount}}</template>
</span>
<span class="operation--show" v-if="answerCommentList.length" @click="answerVisible = !answerVisible">
{{answerVisible ? '收起' : '展开'}}
</span>
</div>
<span class="operation--thumb" :class="{'operation--thumb__active':isLike}" @click="handleUseful">{{usefulCount || ''}}</span>
</div>
<div class="answer" v-if="showAnswerBox">
<b class="answer--title">全部评论({{answerCount}})</b>
<ul>
<li class="answer--item" v-if="commentDetail.merchantComment">
<div class="answer--name"><b>{{commentDetail.merchantComment.userName}}</b><span>{{commentDetail.merchantComment.createTime}}</span></div>
<p class="answer--ctx">{{commentDetail.merchantComment.commentContent}}</p>
</li>
<li class="answer--item" v-for="(item, idx) in answerCommentList" :key="idx">
<div class="answer--name">
<b>{{item.userName}} {{item.parentId !== commentDetail.id ? ` 回复 ${item.parentUserName}` : ''}}</b>
<span>{{item.createTime}}</span>
</div>
<p class="answer--ctx">{{item.commentContent}}</p>
<span class="answer--answer" @click="handleAnswer(item)"></span>
</li>
</ul>
<div v-if="answerVisible" class="answer--form">
<input v-model="answerContent" class="answer--input" @keydown="handleClearAnswer" :placeholder="answerPlaceholder"/>
<UiButton :disabled="!answerContent" @click="handleSubmit"
radius="4px" class="answer--btn" type="red_panel">发表</UiButton>
</div>
</div>
<BsCommentSubmit v-if="!commentDetail.id" :commentDetail="commentDetail"/>
</main>
</div>
</template>
<script>
import BsCommentFollowInfo from './BsCommentFollowInfo.vue';
import {ApiPostComment, ApiPutCommentUseful} from '@/plugins/api/comment';
import {Debounce } from '@/plugins/utils';
import UiImgs from './UiImgs.vue';
import UiButton from './UiButton.vue';
import BsCommentSubmit from './BsCommentSubmit.vue';
export default {
components: { BsCommentFollowInfo, UiImgs, UiButton, BsCommentSubmit },
props:{
type:{
type : String,
default : 'detail' //edit detail
},
commentDetail : {
type : Object,
default : () => ({})
}
},
data(){
return {
answerCommentList : [],
answerVisible : false,
answerContent : '',
answer : null,
isLike : false,
usefulCount : 0
}
},
computed:{
showAnswerBox(){
return (this.commentDetail.merchantComment || this.answerVisible) ? true : false
},
answerCount(){
let count = this.answerCommentList.length;
if(this.commentDetail.merchantComment){
count += 1;
}
return count
},
answerPlaceholder (){
return this.answer ? `回复:${this.answer.userName}` : '说点什么吧?'
},
imgs (){
let imgs = this.commentDetail.pictureUrl;
return imgs ? imgs.split(',') : [];
}
},
watch:{
commentDetail(){
this.answerCommentList = this.commentDetail.answerCommentList || [];
this.isLike = this.commentDetail.isLike;
this.usefulCount = this.commentDetail.usefulCount;
}
},
mounted(){
this.answerCommentList = this.commentDetail.answerCommentList || [];
},
methods : {
handleAnswer (item){
this.answer = item;
},
handleClearAnswer(e){
if(e.code === 'Backspace' && !this.answerContent && this.answer){
this.answer = null;
}
},
async handleSubmit(){
let data = {
commentContent : this.answerContent,
commentType : 3,
originId : this.commentDetail.id,
parentId : this.answer ? this.answer.id : this.commentDetail.id
}
const {error, result} = await ApiPostComment(data);
if(error){
this.$message.error(error.message);
return false
}
this.answerCommentList.push({
...result,
userName : this.$store.state.userInfo.nickname,
parentName: this.answer ? this.answer.userName : ''
});
this.answerContent = '';
this.$message.success('评论成功!');
},
handleUseful(){
this.isLike = !this.isLike
if(this.isLike){
this.usefulCount++;
}else{
this.usefulCount--;
}
if(!this.debounce){
this.debounce = Debounce(this.updateUseFul, 500);
}
this.debounce();
},
async updateUseFul(){
if(this.isLike === this.commentDetail.isLike){
return false
}
const {error, result} = await ApiPutCommentUseful({
commentId : this.commentDetail.id,
isLike : this.isLike
});
this.commentDetail.isLike = this.isLike;
}
}
}
</script>
<style lang="scss" scoped>
.comment-info{
display: flex;
border-top: 1px solid #f2f2f2;
padding: 35px 20px 50px 0;
main{
flex: 1;
}
}
.side{
width: 170px;
text-align: center;
}
.top{
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
.time, .sku{
color: #999;
font-size: 12px;
}
.ctx{
word-break: break-all;
line-height: 24px;
margin-top: 8px;
}
.imgs{
margin-top: 10px;
}
.follow{
margin-top: 30px;
&--title{
color: #FF6A19;
font-weight: normal;
}
}
.operation{
color: #999;
display: flex;
justify-content: space-between;
margin-top: 30px;
&--show{
color: #3083FF;
margin-left: 28px;
cursor: pointer;
}
&--chat,&--thumb{
background: url('@/assets/img/comment/chat.png') no-repeat left center;
background-size: 16px;
padding-left: 24px;
cursor: pointer;
&__active,&:hover{
background-image: url('@/assets/img/comment/chat_active.png');
color: #FF6A19;
}
}
&--thumb{
background-image: url('@/assets/img/comment/thumb.png');
&__active,&:hover{
background-image: url('@/assets/img/comment/thumb_active.png');
}
}
}
.answer{
background: #F8F8F8;
margin-top: 14px;
padding: 0 24px 20px;
&--item{
border-top: 1px solid #eee;
padding: 20px 0;
}
&--title{
height: 54px;
line-height: 54px;
font-weight: normal;
color: #666;
}
&--name{
color: #999;
font-size: 12px;
display: flex;
justify-content: space-between;
}
&--ctx{
color: #666;
margin: 15px 0 0;
}
&--answer{
font-size: 12px;
color: #666;
text-align: right;
cursor: pointer;
display: block;
}
&--form{
display: flex;
}
&--input{
flex: 1;
height: 40px;
border: 1px solid #eee;
border-radius: 4px;
margin-right: 15px;
padding: 0 20px;
}
&--btn{
height: 40px;
}
}
</style>

@ -0,0 +1,169 @@
<!--
* @Author: ch
* @Date: 2022-06-25 15:29:43
* @LastEditors: ch
* @LastEditTime: 2022-06-27 09:50:29
* @Description: file content
-->
<template>
<div class="submit">
<p class="rate-box">
<b>满意度评分</b>
<el-rate v-model="rate"></el-rate>
<span>满意</span>
</p>
<el-input type="textarea" class="textarea" placeholder="从多个维度评价,可以帮助更多想买的人哦~"
v-model="commentContent" show-word-limit :maxlength="500" :rows="6"/>
<div class="operation">
<el-upload list-type="picture-card"
:on-remove="handleRemove" :limit="6"
:action="uploadAction" :data="uploadData"
:before-upload="handleBeforeUpload"
:on-exceed="handleUploadExceed"
:on-error="handleUploadError">
<i class="el-icon-plus"></i>
<p class="upload-txt">我要晒图</p>
</el-upload>
<UiButton class="upload-btn" @click="handleSubmit"></UiButton>
</div>
</div>
</template>
<script>
import {ApiPostComment} from '@/plugins/api/comment';
import {ApiPostGetOssConfig} from '@/plugins/api/oss';
import {COMMENT} from '@/constants'
export default {
props : {
type : {
type : String,
default : 1
},
commentDetail : {
type : Object,
default : () => ({})
}
},
data(){
return {
rate: 0,
commentContent : '',
uploadData : {},
uploadAction : '',
fileList : []
}
},
methods : {
async handleSubmit(){
let data = {
commentContent : this.commentContent,
commentType : this.type,
orderProductId : this.commentDetail.orderProductId,
pictureUrl : this.fileList.map(i => i.url).join(',')
}
console.log(this.commentDetail);
if(this.type === COMMENT.TYPE.COMMENT){
data.productId = this.commentDetail.productId;
data.commentScore = this.rate;
}else if(this.type === COMMENT.TYPE.FOLLOW_COMMENT){
data.originId = data.parentId = this.commentDetail.id;
}
const {error, result} = await ApiPostComment(data);
if(error){
this.$message.error(error.message);
return false;
}
this.$emit('submit',result);
},
/**
* 获取OSS鉴权信息
* configId 自定义文件夹 图片存储的文件夹名称
* serviceName 服务名
*/
async getOssCon(){
const {error, result} = await ApiPostGetOssConfig({
configId : 'account-comment/',
serviceName : 'comment'
});
if(error){
this.$message.error(error.message);
return false
}
return result
},
async handleBeforeUpload(file) {
let result = await this.getOssCon();
if(result){
this.uploadAction = result.host;
this.uploadData = {
...this.uploadData,
policy : result.policy,
OSSAccessKeyId: result.accessId,
success_action_status: 200,
signature: result.signature,
}
}
Object.assign(this.uploadData, {
key: `${result.dir}${"${filename}"}`,
name: file.name,
});
this.fileList.push({
url : `${result.host}/${result.dir}${file.name}`,
uid : file.uid
})
},
handleUploadError(error, file) {
this.handleRemove(file)
},
handleRemove(file) {
this.fileList = this.fileList.filter(i => i.uid != file.uid );
},
handleUploadExceed(){
this.$message.warning('最多只能上传6张照片哦~')
}
}
}
</script>
<style lang="scss" scoped>
.rate-box{
display: flex;
margin-top: 30px;
}
.textarea{
height: 138px;
margin-top: 30px;
}
.operation{
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 15px;
.upload-txt{
font-size: 12px;
color: #999;
}
.upload-btn{
height: 40px;
width: 100px;
border-radius: 4px;
font-size: 14px;
padding: 0;
}
}
/deep/{
.el-upload--picture-card,.el-upload-list__item{
height: 70px !important;
width: 70px !important;
line-height: 20px;
}
.el-upload--picture-card{
padding-top: 10px;
}
}
</style>

@ -0,0 +1,113 @@
<!--
* @Author: ch
* @Date: 2022-06-24 19:07:45
* @LastEditors: ch
* @LastEditTime: 2022-06-27 10:37:12
* @Description: file content
-->
<template>
<div class="preview-imgs">
{{imgs}}
<ul>
<li v-for="(i, idx) in list" :key="idx" :class="{'active' : curIndex == idx}" >
<img :src="i" @click="curIndex = idx"/>
</li>
</ul>
<p v-if="curIndex > -1">
<img :src="list[curIndex]" @click="curIndex = -1"/>
<span class="prev" @click="prev" v-if="curIndex > 0"></span>
<span class="next" @click="next" v-if="curIndex < list.length-1"></span>
</p>
</div>
</template>
<script>
export default {
props : {
list : {
type : Array,
default : () => ([])
}
},
data(){
return {
curIndex : -1,
// imgs : ['https://msb-edu-dev.oss-cn-beijing.aliyuncs.com/mall-product/product/cscs.png','https://img.alicdn.com/imgextra/i3/859515618/O1CN01Y1K5fp1rN5qfdxCtL_!!859515618.jpg']
}
},
methods:{
next(){
this.curIndex++;
},
prev(){
this.curIndex--;
}
}
}
</script>
<style lang="scss" scoped>
.preview-imgs{
ul{
display: flex;
}
li{
width: 46px;
height : 46px;
border: 1px solid #eee;
margin-right: 10px;
padding: 1px;
cursor: pointer;
img{
width: 42px;
height: 42px;
object-fit: contain;
}
&.active{
border-color: #FF512B;
position: relative;
&::after{
content: '';
height: 3px;
width: 3px;
bottom: -7px;
left: 17px;
display: block;
position: absolute;
// transform: rotate(45deg);
border: 3px solid #FF512B;
border-left-color: transparent;
border-right-color: transparent;
border-bottom-color: transparent;
}
}
}
p{
width: 300px;
margin-top: 20px;
position: relative;
img{
width: 300px;
height: 300px;
object-fit: contain;
cursor: zoom-out;
}
&:hover span{
display: block;
}
span{
display: none;
position: absolute;
width: 40px;
height: 40px;
background: rgba(0,0,0, .5);
top : 130px;
cursor: pointer;
&.prev{
left: 0;
}
&.next{
right: 0;
}
}
}
}
</style>

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-05-17 18:17:00
* @LastEditors: ch
* @LastEditTime: 2022-06-09 18:50:01
* @LastEditTime: 2022-06-27 09:45:38
* @Description: file content
*/
/**
@ -38,5 +38,16 @@ const SECKILL_STATUS = {
NOT_START: 1, // 未开始
GOING: 2, // 进行中
};
const COMMENT = {
TYPE: {
// 评价
COMMENT: 1,
// 追评
FOLLOW_COMMENT: 2,
// 回复
ANSWER: 3,
}
}
export { TOKEN_KEY, UUID_KEY, ORDER_STATUS, SEX_TYPE, CATEGROY_LEVEL, SECKILL_STATUS };
export { TOKEN_KEY, UUID_KEY, ORDER_STATUS, SEX_TYPE, CATEGROY_LEVEL, SECKILL_STATUS, COMMENT };

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-05-05 14:40:00
* @LastEditors: ch
* @LastEditTime: 2022-05-27 18:25:28
* @LastEditTime: 2022-06-24 14:21:20
* @Description: 根据git分支生成对应环境的环境变量
* 开发时如果环境变量换了可以不用重启服务直接运行node env.config.js即可
*/

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-05-04 17:56:39
* @LastEditors: ch
* @LastEditTime: 2022-05-31 16:52:40
* @LastEditTime: 2022-06-25 10:10:25
* @Description: file content
-->
<template>

@ -192,7 +192,6 @@ export default {
z-index: 10;
background: #ffffff;
box-shadow: 0px 4px 10px 1px rgba(0, 0, 0, 0.1);
z-index: 9999;
&--hide-shadow {
box-shadow: none;

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-05-03 22:14:16
* @LastEditors: ch
* @LastEditTime: 2022-06-12 14:31:52
* @LastEditTime: 2022-06-24 14:17:59
* @Description: file content
*/
export default {
@ -85,7 +85,7 @@ export default {
'/mall/': {
// target: 'http://114.55.64.39:3004', // 目标接口域名
target: 'https://you-gateway.mashibing.com/', // 目标接口域名
target: 'https://k8s-horse-gateway.mashibing.cn/', // 目标接口域名
// target: 'https://k8s-horse-gateway.mashibing.cn/', // 目标接口域名
pathRewrite: {
changeOrigin: true, // 表示是否跨域
},

@ -1,3 +1,10 @@
<!--
* @Author: ch
* @Date: 2022-05-20 09:59:05
* @LastEditors: ch
* @LastEditTime: 2022-06-25 15:40:05
* @Description: file content
-->
<!--
* @Author: ch
* @Date: 2022-05-04 17:52:50

@ -41,6 +41,7 @@
</main>
</div>
<div v-else>
<HeaderBar v-show="showHeaderBar" :tabKey="headerKey" @jump="handleJump" @addCart="addCart" />
<nav class="nav flex flex-middle flex-center">
<p class="nav__crumbs">
全部商品
@ -188,17 +189,15 @@
></UiGoodsItem>
</div>
<div class="section-details">
<p class="section-title">商品详情</p>
<div
class="rich"
v-html="detailData.detail"
v-if="detailData.detail"
></div>
<p class="section-title" ref="detailRef">商品详情</p>
<div class="rich" v-html="detailData.detail" v-if="detailData.detail" ></div>
<div class="section-details--none" v-else>
<img src="@/assets/img/goods/none.png" alt="" />
<p>暂无详情</p>
</div>
<Comment ref="commentRef" />
</div>
</section>
<BsChosen v-else></BsChosen>
@ -235,14 +234,16 @@ import UiMoney from "@/components/UiMoney.vue";
import UiButton from "@/components/UiButton.vue";
import UiGoodsItem from "@/components/UiGoodsItem.vue";
import BsChosen from "@/components/BsChosen.vue";
import Comment from './module/Comment.vue';
import { ApiPutAddCart } from "@/plugins/api/cart";
import {
ApiGetGoodsDetail,
ApiGetGoodsSkus,
ApiGetGoodsList,
} from "@/plugins/api/goods";
import HeaderBar from './module/HeaderBar.vue';
export default {
componetns: { UiMoney, UiButton, UiGoodsItem, BsChosen },
components: { UiMoney, UiButton, UiGoodsItem, BsChosen, Comment, HeaderBar },
data() {
return {
pageLoading: true,
@ -260,6 +261,8 @@ export default {
startTime: "",
endTime: "",
showService: false,
showHeaderBar : false,
headerKey: 'detail'
};
},
async created() {
@ -341,7 +344,41 @@ export default {
}
},
},
mounted(){
window.addEventListener("scroll", ()=>{
this.setHeaderBar()
});
this.setHeaderBar()
},
destroyed() {
window.removeEventListener("scroll", ()=>{
this.setHeaderBar()
});
},
methods: {
setHeaderBar(){
const y = window.scrollY
this.showHeaderBar = y > 700;
if(this.showHeaderBar){
const dY = this.$refs.detailRef.offsetTop;
const cY = this.$refs.commentRef.$el.offsetTop;
if(y >= cY){
this.headerKey = 'comment';
}else if(y > dY){
this.headerKey = 'detail';
}
}
},
handleJump(val){
if(val === 'detail'){
this.$refs.detailRef.scrollIntoView();
}else{
this.$refs.commentRef.$el.scrollIntoView();
}
this.headerKey = val;
},
onShowService() {
this.showService = true;
},
@ -526,6 +563,8 @@ export default {
this.$store.dispatch("getCartProducts");
// this.$Router.push('/cart');
},
},
};
</script>

@ -0,0 +1,273 @@
<!--
* @Author: ch
* @Date: 2022-06-24 14:39:38
* @LastEditors: ch
* @LastEditTime: 2022-06-27 11:01:07
* @Description: file content
-->
<template>
<div>
<div class="title">
<b>商品评价</b>
<div v-if="list.length">
<el-dropdown class="title--sort" @command="handleCommand">
<span>{{sortActive.label}}<i class="el-icon-arrow-down el-icon--right"></i></span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="item in sortData" :key="item.val" :command="item">{{item.label}}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-checkbox v-model="isContent" @change="handledContent"></el-checkbox>
</div>
</div>
<div class="ctx">
<UiEmpty v-if="!list.length" :icon="require('@/assets/img/comment/empty.png')" desc="暂时没有评论"/>
<template v-else>
<div class="ctx--top">
<div class="ctx--top-rate" v-if="productRate">
<b>商品满意度</b>
<p>{{productRate}}</p>
<el-rate :value="productRate" disabled></el-rate>
</div>
<div class="ctx--top-tabs" v-if="tabs.length > 1">
<span v-for="i in tabs" :key="i.labelType" @click="handleTabChanage(i)"
:class="{'active':i.labelType == tabActive}">
{{i.labelName}}({{i.commentCount}})
</span>
</div>
</div>
<BsCommentInfo v-for="item in list" :key="item.id" :commentDetail="item"/>
</template>
</div>
<el-pagination class="pagination flex flex-right" layout="prev, pager, next"
@current-change="handleCurrentChange" :current-page.sync="pageIndex"
:page-size="pageSize" :total="total"></el-pagination>
</div>
</template>
<script>
import {
ApiGetCommentList,
ApiGetCommentTabCount,
ApiGetProductSatisfaction,
ApiGetCommentCount
} from "@/plugins/api/comment";
import BsCommentInfo from '../../../../components/BsCommentInfo.vue';
export default {
components: { BsCommentInfo },
props : {
},
data(){
return {
productId : this.$route.params.id,
tabActive : -1,
sortData : [{
val : 1,
label : '默认排序'
},{
val : 2,
label : '按时间排序'
}],
sortActive : {
val : 1,
label : '默认排序'
},
productRate : 0,
isContent : true,
pageIndex : 1,
pageSize : 10,
total:0,
tabs : [
{
labelName : '全部',
labelType : -1,
commentCount : 0
}
],
pageSize : 10,
list : [],
loading : false
}
},
mounted(){
this.getList();
this.getTabCount();
this.getProductSatisfaction();
this.getCount();
},
methods:{
async getList(){
this.loading = true;
const {error, result} = await ApiGetCommentList({
pageIndex : this.pageIndex,
length : this.pageSize,
productId : this.productId,
commentLabel : this.tabActive == -1 ? null : this.tabActive,
sortType : this.sortActive.val,
isContent : this.isContent
});
this.loading = false
if(error){
return false;
}
this.list = result.records;
},
async getTabCount (){
const {error, result} = await ApiGetCommentTabCount({
productId : this.productId
});
if(error){
return false;
}
// this.list = result.records;
this.tabs = this.tabs.concat(result);
},
async getCount(){
const {error, result} = await ApiGetCommentCount({
productId : this.productId
});
if(error){
return false;
}
this.$set(this.tabs[0],'commentCount', result.allCommentCount)
},
async getProductSatisfaction (){
const {error, result} = await ApiGetProductSatisfaction({
productId : this.productId
});
if(error){
return false;
}
this.productRate = result.productSatisfaction;
},
handleCurrentChange(val) {
this.pageIndex = val;
this.getList();
},
handleTabChanage(i){
if(this.tabActive == i.labelType){
return false
}
this.tabActive = i.labelType;
this.getList();
},
handleCommand(val){
this.sortActive = val;
this.pageIndex = 1;
this.getList();
},
handledContent(){
this.pageIndex = 1;
this.getList();
}
}
}
</script>
<style lang="scss" scoped>
.title {
margin-top: 30px;
width: 100%;
height: 40px;
line-height: 40px;
background: #f7f7f7;
border: 1px solid #f2f2f2;
padding: 0 16px;
font-size: 14px;
font-family: Microsoft YaHei-Regular, Microsoft YaHei;
font-weight: 400;
color: #666666;
display: flex;
justify-content: space-between;
&--sort{
margin-right: 30px;
}
}
.ctx{
border: 1px solid #f2f2f2;
border-top: 0;
overflow: hidden;
&--top{
display: flex;
&-rate{
width: 170px;
height: 136px;
text-align: center;
padding-top: 26px;
color: #666;
position: relative;
b{
font-weight: normal;
}
p{
font-size: 40px;
height: 40px;
line-height: 40px;
font-weight: bold;
}
&::after{
content: '';
display: block;
height: 90px;
width: 1px;
background: #eee;
position: absolute;
right: 0;
top: 26px;
}
}
&-tabs{
margin: 34px 0;
padding-left: 40px;
span{
display: inline-block;
height: 24px;
line-height: 22px;
border: 1px solid #eee;
color: #999;
padding: 0 12px;
font-size: 12px;
border-radius: 4px;
margin-right: 16px;
cursor: pointer;
&.active{
background: #FF6A19;
border-color: #FF6A19;
color: #fff;
}
}
}
}
}
.pagination {
margin: 50px 0;
/deep/.el-pager {
margin-left: 8px;
}
/deep/button,
/deep/.number,
/deep/.btn-quicknext,
/deep/.btn-quickprev {
width: 32px;
height: 32px;
text-align: center;
line-height: 32px;
margin-left: 8px;
border-radius: 2px 2px 2px 2px;
border: 1px solid rgba(0, 0, 0, 0.15);
font-size: 14px;
font-family: Microsoft YaHei-Regular, Microsoft YaHei;
font-weight: 400;
color: rgba(0, 0, 0, 0.65);
}
/deep/.active {
background: #ff512b;
color: #fff;
}
}
</style>

@ -0,0 +1,83 @@
<!--
* @Author: ch
* @Date: 2022-06-25 07:24:32
* @LastEditors: ch
* @LastEditTime: 2022-06-25 12:02:54
* @Description: file content
-->
<template>
<div class="header">
<div class="header--layout">
<ul>
<li @click="handleJump('detail')" :class="{'active': tabKey =='detail'}">商品详情</li>
<li @click="handleJump('comment')" :class="{'active': tabKey =='comment'}">商品评价</li>
</ul>
<UiButton @click="handleAddCart"></UiButton>
</div>
</div>
</template>
<script>
import UiButton from '../../../../components/UiButton.vue'
export default {
components: { UiButton },
props:{
tabKey : {
type : String,
default : 'detail'
}
},
data(){
},
methods:{
handleJump(val){
this.$emit('jump', val)
},
handleAddCart(){
this.$emit('addCart')
}
}
}
</script>
<style lang="scss" scoped>
.header{
position: fixed;
top: 0;
left: 0;
right: 0;
height: 70px;
background: #fff;
z-index: 11;
&--layout{
@include layout-box;
padding-left: 256px;
display: flex;
justify-content: space-between;
align-items: center;
height: 100%;
ul{
display: flex;
font-size: 16px;
li{
margin-right: 50px;
height: 70px;
line-height: 70px;
&.active{
color: #FF6A19;
position: relative;
&::after{
display: block;
content: '';
position: absolute;
height: 2px;
width: 40px;
background: #FF6A19;
bottom: 0;
left: 50%;
transform: translateX(-50%);
}
}
}
}
}
}
</style>

@ -0,0 +1,68 @@
/*
* @Author: ch
* @Date: 2022-06-20 11:38:48
* @LastEditors: ch
* @LastEditTime: 2022-06-25 17:49:58
* @Description: file content
*/
import {axiosTk} from "../axiosTk";
import {axios} from "../axios";
import { ToAsyncAwait } from "../utils";
import ENV from '../config/env';
const BASE_URL = `${ENV.base_url}/mall/comment`;
/**
* 根据商品获取评论列表
* @param {*} param0
*/
export const ApiGetCommentList = (params) =>
ToAsyncAwait(axios.get(`${BASE_URL}/app/comment`, {params}));
/**
* 根据商品获取评论总数
* @param {*} param0
*/
export const ApiGetCommentCount = ({productId}) =>
ToAsyncAwait(axios.get(`${BASE_URL}/app/comment/getAllCommentCountByProductId/${productId}`));
/**
* 根据商品获取标签评论总数
* @param {*} param0
*/
export const ApiGetCommentTabCount = ({productId}) =>
ToAsyncAwait(axios.get(`${BASE_URL}/app/comment/listCommentLabel/${productId}`));
/**
* 获取订单评论详情
* @param {*} param0
*/
export const ApiGetOrderCommentDetail = ({orderId}) =>
ToAsyncAwait(axiosTk.get(`${BASE_URL}/app/comment/listOrderCommentByOrderId/${orderId}`));
/**
* 获取商品满意度
* @param {*} param0
*/
export const ApiGetProductSatisfaction = ({productId}) =>
ToAsyncAwait(axiosTk.get(`${BASE_URL}/app/comment/getProductSatisfaction/${productId}`));
/**
* 获取评论详情
* @param {*} param0
*/
export const ApiGetCommentDetail = ({commentId}) =>
ToAsyncAwait(axios.get(`${BASE_URL}/app/comment/getCommentDetail/${commentId}`));
/**
* 新增评论
* @param {*} param0
*/
export const ApiPostComment = (data) =>
ToAsyncAwait(axiosTk.post(`${BASE_URL}/app/comment`, data));
/**
* 更新评论有用数
* @param {*} param0
*/
export const ApiPutCommentUseful = (data) =>
ToAsyncAwait(axiosTk.put(`${BASE_URL}/app/comment/updateUsefulCount`, data));
Loading…
Cancel
Save