Jelajahi Sumber

✨ 商品详情:评论列表

YunaiV 1 tahun lalu
induk
melakukan
0e189711a8

+ 159 - 162
pages/goods/comment/list.vue

@@ -1,170 +1,167 @@
-<!-- 页 -->
+<!-- 商品评论的分页 -->
 <template>
-	<s-layout title="全部评价">
-		<su-tabs :list="state.type" :scrollable="false" @change="onTabsChange" :current="state.currentTab"></su-tabs>
-		<view class="ss-m-t-20">
-			<view class="list-item" v-for="item in state.pagination.data" :key="item">
-				<comment-item :item="item"></comment-item>
-			</view>
-		</view>
-		<s-empty v-if="state.pagination.total === 0" text="暂无数据" icon="/static/data-empty.png" />
-		<uni-load-more v-if="state.pagination.total > 0" :status="state.loadStatus" :content-text="{
+  <s-layout title="全部评价">
+    <su-tabs
+      :list="state.type"
+      :scrollable="false"
+      @change="onTabsChange"
+      :current="state.currentTab"
+    />
+    <!-- 评论列表 -->
+    <view class="ss-m-t-20">
+      <view class="list-item" v-for="item in state.pagination.list" :key="item">
+        <comment-item :item="item" />
+      </view>
+    </view>
+    <s-empty v-if="state.pagination.total === 0" text="暂无数据" icon="/static/data-empty.png" />
+    <!-- 下拉 -->
+    <uni-load-more
+      v-if="state.pagination.total > 0"
+      :status="state.loadStatus"
+      :content-text="{
         contentdown: '上拉加载更多',
-      }" @tap="loadmore" />
-	</s-layout>
+      }"
+      @tap="loadMore"
+    />
+  </s-layout>
 </template>
 
 <script setup>
-	import sheep from '@/sheep';
-	import {
-		onLoad,
-		onReachBottom
-	} from '@dcloudio/uni-app';
-	import {
-		computed,
-		reactive
-	} from 'vue';
-	import _ from 'lodash';
-	import commentItem from '../components/detail/comment-item.vue';
-
-	const pagination = {
-		data: [],
-		current_page: 1,
-		total: 1,
-		last_page: 1,
-	};
-	const state = reactive({
-		list: [],
-		type: [],
-		currentTab: 0,
-		pagination: {
-			data: [],
-			current_page: 1,
-			total: 1,
-			last_page: 1,
-		},
-		commentId: 0,
-		code: 0,
-	});
-	// 切换选项卡
-	function onTabsChange(e) {
-		state.pagination = pagination
-		state.currentTab = e.index;
-		state.code = e.code;
-		getList(state.commentId, e.code);
-	}
-	async function getType(id) {
-		const {
-			error,
-			data
-		} = await sheep.$api.goods.getType(id);
-		if (error === 0) {
-			console.log(data)
-			// state.type = data;
-			state.type = [{code:0,name:'全部'},{code:1,name:'好评'},{code:2,name:'中评'},{code:3,name:'差评'}];
-		}
-	}
-	async function getList(id, code=0, page = 1, list_rows = 6) {
-		state.loadStatus = 'loading';
-		let res = await sheep.$api.goods.comment2(id, {
-			type: code,
-			pageSize: list_rows,
-			pageNo: page,
-		});
-		console.log(res);
-		if (res.code === 0) {
-			let orderList = _.concat(state.pagination.data, res.data.list);
-			state.pagination = {
-				...res.data,
-				data: orderList,
-			};
-			if (state.pagination.current_page < state.pagination.last_page) {
-				state.loadStatus = 'more';
-			} else {
-				state.loadStatus = 'noMore';
-			}
-		}
-	}
-	// 加载更多
-	function loadmore() {
-		if (state.loadStatus !== 'noMore') {
-			getList(state.commentId, state.code, state.pagination.current_page + 1);
-		}
-	}
-	onLoad((options) => {
-		state.commentId = options.id;
-		getType(state.commentId);
-		getList(state.commentId);
-	});
-	// 上拉加载更多
-	onReachBottom(() => {
-		loadmore();
-	});
+  import CommentApi from '@/sheep/api/product/comment';
+  import { onLoad, onReachBottom } from '@dcloudio/uni-app';
+  import { reactive } from 'vue';
+  import _ from 'lodash';
+  import commentItem from '../components/detail/comment-item.vue';
+
+  const state = reactive({
+    id: 0, // 商品 SPU 编号
+    type: [
+      { type: 0, name: '全部' },
+      { type: 1, name: '好评' },
+      { type: 2, name: '中评' },
+      { type: 3, name: '差评' },
+    ],
+    currentTab: 0, // 选中的 TAB
+    loadStatus: '',
+    pagination: {
+      list: [],
+      total: 0,
+      pageNo: 1,
+      pageSize: 1,
+    },
+  });
+
+  // 切换选项卡
+  function onTabsChange(e) {
+    state.currentTab = e.index;
+    // 加载列表
+    state.pagination.pageNo = 1;
+    state.pagination.list = [];
+    state.pagination.total = 0;
+    getList();
+  }
+
+  async function getList() {
+    // 加载列表
+    state.loadStatus = 'loading';
+    let res = await CommentApi.getCommentPage(
+      state.id,
+      state.pagination.pageNo,
+      state.pagination.pageSize,
+      state.type[state.currentTab].type,
+    );
+    if (res.code !== 0) {
+      return;
+    }
+    // 合并列表
+    state.pagination.list = _.concat(state.pagination.list, res.data.list);
+    state.pagination.total = res.data.total;
+    state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
+  }
+
+  // 加载更多
+  function loadMore() {
+    if (state.loadStatus === 'noMore') {
+      return;
+    }
+    state.pagination.pageNo++;
+    getList();
+  }
+
+  onLoad((options) => {
+    state.id = options.id;
+    getList();
+  });
+
+  // 上拉加载更多
+  onReachBottom(() => {
+    loadMore();
+  });
 </script>
 
 <style lang="scss" scoped>
-	.list-item {
-		padding: 32rpx 30rpx 20rpx 20rpx;
-		background: #fff;
-
-		.avatar {
-			width: 52rpx;
-			height: 52rpx;
-			border-radius: 50%;
-		}
-
-		.nickname {
-			font-size: 26rpx;
-			font-weight: 500;
-			color: #999999;
-		}
-
-		.create-time {
-			font-size: 24rpx;
-			font-weight: 500;
-			color: #c4c4c4;
-		}
-
-		.content-title {
-			font-size: 26rpx;
-			font-weight: 400;
-			color: #666666;
-			line-height: 42rpx;
-		}
-
-		.content-img {
-			width: 174rpx;
-			height: 174rpx;
-		}
-
-		.cicon-info-o {
-			font-size: 26rpx;
-			color: #c4c4c4;
-		}
-
-		.foot-title {
-			font-size: 24rpx;
-			font-weight: 500;
-			color: #999999;
-		}
-	}
-
-	.btn-box {
-		width: 100%;
-		height: 120rpx;
-		background: #fff;
-		border-top: 2rpx solid #eee;
-	}
-
-	.tab-btn {
-		width: 130rpx;
-		height: 62rpx;
-		background: #eeeeee;
-		border-radius: 31rpx;
-		font-size: 28rpx;
-		font-weight: 400;
-		color: #999999;
-		border: 1px solid #e5e5e5;
-		margin-right: 10rpx;
-	}
-</style>
+  .list-item {
+    padding: 32rpx 30rpx 20rpx 20rpx;
+    background: #fff;
+
+    .avatar {
+      width: 52rpx;
+      height: 52rpx;
+      border-radius: 50%;
+    }
+
+    .nickname {
+      font-size: 26rpx;
+      font-weight: 500;
+      color: #999999;
+    }
+
+    .create-time {
+      font-size: 24rpx;
+      font-weight: 500;
+      color: #c4c4c4;
+    }
+
+    .content-title {
+      font-size: 26rpx;
+      font-weight: 400;
+      color: #666666;
+      line-height: 42rpx;
+    }
+
+    .content-img {
+      width: 174rpx;
+      height: 174rpx;
+    }
+
+    .cicon-info-o {
+      font-size: 26rpx;
+      color: #c4c4c4;
+    }
+
+    .foot-title {
+      font-size: 24rpx;
+      font-weight: 500;
+      color: #999999;
+    }
+  }
+
+  .btn-box {
+    width: 100%;
+    height: 120rpx;
+    background: #fff;
+    border-top: 2rpx solid #eee;
+  }
+
+  .tab-btn {
+    width: 130rpx;
+    height: 62rpx;
+    background: #eeeeee;
+    border-radius: 31rpx;
+    font-size: 28rpx;
+    font-weight: 400;
+    color: #999999;
+    border: 1px solid #e5e5e5;
+    margin-right: 10rpx;
+  }
+</style>

+ 63 - 64
pages/goods/components/detail/comment-item.vue

@@ -1,95 +1,94 @@
+<!-- 商品评论项 -->
 <template>
   <view>
+    <!-- 用户评论 -->
     <view class="user ss-flex ss-m-b-14">
       <view class="ss-m-r-20 ss-flex">
-        <image class="avatar" :src="sheep.$url.cdn(item.user_avatar)"></image>
-      </view>
-      <view class="nickname ss-m-r-20">
-        {{ item.userNickname }}
+        <image class="avatar" :src="item.userAvatar"></image>
       </view>
+      <view class="nickname ss-m-r-20">{{ item.userNickname }}</view>
       <view class="">
         <uni-rate :readonly="true" v-model="item.scores" size="18" />
       </view>
     </view>
-    <view class="content">
-      {{ item.content }}
-    </view>
+    <view class="content"> {{ item.content }} </view>
     <view class="ss-m-t-24" v-if="item.picUrls?.length">
       <scroll-view class="scroll-box" scroll-x scroll-anchoring>
         <view class="ss-flex">
-          <view v-for="(item, index) in item.picUrls" :key="item" class="ss-m-r-10">
-            <su-image class="content-img" isPreview :previewList="state.commentImages" :current="index" :src="item"
-              :height="120" :width="120" mode="aspectFill"></su-image>
+          <view v-for="(picUrl, index) in item.picUrls" :key="picUrl" class="ss-m-r-10">
+            <su-image
+              class="content-img"
+              isPreview
+              :previewList="item.picUrls"
+              :current="index"
+              :src="picUrl"
+              :height="120"
+              :width="120"
+              mode="aspectFill"
+            />
           </view>
         </view>
       </scroll-view>
     </view>
-    <view class="ss-m-t-20 reply-box" v-if="item.reply_time">
+    <!-- 商家回复 -->
+    <view class="ss-m-t-20 reply-box" v-if="item.replyTime">
       <view class="reply-title">商家回复:</view>
-      <view class="reply-content">{{ item.reply_content }}</view>
+      <view class="reply-content">{{ item.replyContent }}</view>
     </view>
   </view>
 </template>
 
 <script setup>
-import sheep from '@/sheep';
-import { reactive } from 'vue';
-const props = defineProps({
-  item: {
-    type: Object,
-    default() { },
-  },
-});
-const state = reactive({
-  commentImages: [],
-});
-props.item.images?.forEach((i) => {
-  state.commentImages.push(sheep.$url.cdn(i));
-});
+  const props = defineProps({
+    item: {
+      type: Object,
+      default() {},
+    },
+  });
 </script>
 
 <style lang="scss" scoped>
-.avatar {
-  width: 52rpx;
-  height: 52rpx;
-  border-radius: 50%;
-}
+  .avatar {
+    width: 52rpx;
+    height: 52rpx;
+    border-radius: 50%;
+  }
 
-.nickname {
-  font-size: 26rpx;
-  font-weight: 500;
-  color: #999999;
-}
+  .nickname {
+    font-size: 26rpx;
+    font-weight: 500;
+    color: #999999;
+  }
 
-.content {
-  width: 636rpx;
-  font-size: 26rpx;
-  font-weight: 400;
-  color: #333333;
-}
+  .content {
+    width: 636rpx;
+    font-size: 26rpx;
+    font-weight: 400;
+    color: #333333;
+  }
 
-.reply-box {
-  position: relative;
-  background: #f8f8f8;
-  border-radius: 8rpx;
-  padding: 16rpx;
-}
+  .reply-box {
+    position: relative;
+    background: #f8f8f8;
+    border-radius: 8rpx;
+    padding: 16rpx;
+  }
 
-.reply-title {
-  position: absolute;
-  left: 16rpx;
-  top: 16rpx;
-  font-weight: 400;
-  font-size: 26rpx;
-  line-height: 40rpx;
-  color: #333333;
-}
+  .reply-title {
+    position: absolute;
+    left: 16rpx;
+    top: 16rpx;
+    font-weight: 400;
+    font-size: 26rpx;
+    line-height: 40rpx;
+    color: #333333;
+  }
 
-.reply-content {
-  text-indent: 128rpx;
-  font-weight: 400;
-  font-size: 26rpx;
-  line-height: 40rpx;
-  color: #333333;
-}
+  .reply-content {
+    text-indent: 128rpx;
+    font-weight: 400;
+    font-size: 26rpx;
+    line-height: 40rpx;
+    color: #333333;
+  }
 </style>

+ 15 - 11
pages/goods/components/detail/detail-comment-card.vue

@@ -1,3 +1,4 @@
+<!-- 商品评论的卡片 -->
 <template>
   <view class="detail-comment-card bg-white">
     <view class="card-header ss-flex ss-col-center ss-row-between ss-p-b-30">
@@ -12,19 +13,20 @@
         v-if="state.commentList.length > 0"
       >
         <button class="ss-reset-button more-btn">查看全部</button>
-        <text class="cicon-forward"></text>
+        <text class="cicon-forward" />
       </view>
     </view>
+    <!-- 评论列表 -->
     <view class="card-content">
       <view class="comment-box ss-p-y-30" v-for="item in state.commentList" :key="item.id">
-        <comment-item :item="item"></comment-item>
+        <comment-item :item="item" />
       </view>
       <s-empty
         v-if="state.commentList.length === 0"
         paddingTop="0"
         icon="/static/comment-empty.png"
         text="期待您的第一个评价"
-      ></s-empty>
+      />
     </view>
   </view>
 </template>
@@ -32,25 +34,27 @@
 <script setup>
   import { reactive, onBeforeMount } from 'vue';
   import sheep from '@/sheep';
+  import CommentApi from '@/sheep/api/product/comment';
   import commentItem from './comment-item.vue';
+
   const props = defineProps({
     goodsId: {
       type: [Number, String],
       default: 0,
     },
   });
+
   const state = reactive({
-    commentList: [],
-    total: 0,
+    commentList: [], // 评论列表,只展示最近的 3 条
+    total: 0, // 总评论数
   });
+
   async function getComment(id) {
-    const { data } = await sheep.$api.goods.comment(id, {
-      list_rows: 3,
-    });  
-	 const {data:datas} = await sheep.$api.goods.comment2(id);
-    state.commentList = data;
-    state.total = datas.total;
+    const { data } = await CommentApi.getCommentPage(id, 1, 3, 0);
+    state.commentList = data.list;
+    state.total = data.total;
   }
+
   onBeforeMount(() => {
     getComment(props.goodsId);
   });

+ 4 - 5
pages/goods/index.vue

@@ -34,8 +34,7 @@
 						<view class="discounts-box ss-flex ss-row-between ss-m-b-28">
 							<div class="tag-content">
 								<view class="tag-box ss-flex">
-									<view class="tag ss-m-r-10" v-for="promos in state.goodsInfo.promos"
-										:key="promos.id" @tap="onActivity">
+									<view class="tag ss-m-r-10" v-for="promos in state.goodsInfo.promos" :key="promos.id" @tap="onActivity">
 										{{ promos.title }}
 									</view>
 								</view>
@@ -71,10 +70,10 @@
 				<!-- 详情 -->
 				<detail-content-card class="detail-content-selector" :content="state.goodsInfo.description" />
 
-				<!-- 活动跳转 -->
-				<detail-activity-tip v-if="state.goodsInfo.activities" :data="state.goodsInfo"></detail-activity-tip>
+				<!-- TODO 芋艿:活动跳转 -->
+				<detail-activity-tip v-if="state.goodsInfo.activities" :data="state.goodsInfo" />
 
-				<!-- 详情tabbar -->
+				<!-- 详情 tabbar -->
 				<detail-tabbar v-model="state.goodsInfo">
 					<view class="buy-box ss-flex ss-col-center ss-p-r-20" v-if="state.goodsInfo.stock > 0">
 						<button class="ss-reset-button add-btn ui-Shadow-Main" @tap="state.showSelectSku = true">

+ 0 - 10
sheep/api/goods.js

@@ -49,16 +49,6 @@ export default {
         showError: false,
       },
     }),
-  comment2: (id, params = {pageNo:1,pageSize:10,type:0}) =>
-    request2({
-      url: 'product/comment/page?spuId='+id,
-      method: 'GET',
-      params,
-      custom: {
-        showLoading: false,
-        showError: false,
-      },
-    }),
   // 商品评价类型
   getType: (id) =>
     request({

+ 18 - 0
sheep/api/product/comment.js

@@ -0,0 +1,18 @@
+import request from '@/sheep/request';
+
+const CommentApi = {
+  // 获得商品评价分页
+  getCommentPage: (spuId, pageNo, pageSize, type) => {
+    return request({
+      url: '/app-api/product/comment/page',
+      method: 'GET',
+      params: {
+        spuId,
+        pageNo,
+        pageSize,
+        type
+      },
+    });
+  },
+};
+export default CommentApi;

+ 10 - 0
sheep/hooks/useGoods.js

@@ -157,6 +157,16 @@ function getDayjsTime(time) {
   }
 }
 
+/**
+ * 将分转成元
+ *
+ * @param price 分,例如说 100 分
+ * @returns {string} 元,例如说 1.00 元
+ */
+export function fen2yuan(price) {
+  return (price / 100.0).toFixed(2)
+}
+
 /**
  * 从商品 SKU 数组中,转换出商品属性的数组
  *