homeReviews.vue 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. <template>
  2. <view class="home-reviews" :style="[bgRadius]" v-if="replyList.length > 0">
  3. <common-wrapper :config="configData">
  4. <view class="reviews-box">
  5. <!-- Header -->
  6. <view class="header acea-row row-between-wrapper">
  7. <view class="left acea-row row-middle">
  8. <text class="title" :style="{ color: titleColor }">{{
  9. $t("评价")
  10. }}</text>
  11. <text
  12. class="count"
  13. :style="{ color: countColor }"
  14. v-if="checkList.includes(0)"
  15. >({{ totalCount }})</text
  16. >
  17. </view>
  18. <navigator
  19. class="right acea-row row-middle"
  20. v-if="checkList.includes(1)"
  21. :url="
  22. productId
  23. ? '/pages/goods/goods_comment_list/index?product_id=' +
  24. productId
  25. : ''
  26. "
  27. hover-class="none"
  28. >
  29. <text class="rate" :style="{ color: rateColor }"
  30. >{{ replyChance }}% </text
  31. >{{ $t("好评率") }}
  32. <text class="iconfont icon-jiantou"></text>
  33. </navigator>
  34. </view>
  35. <!-- List -->
  36. <view class="list" v-if="!isSlide">
  37. <view class="item" v-for="(item, index) in showList" :key="index">
  38. <view class="user-info acea-row row-middle">
  39. <image
  40. :src="item.avatar"
  41. class="avatar"
  42. mode="aspectFill"
  43. ></image>
  44. <view class="info">
  45. <view class="name line1">{{ item.nickname }}</view>
  46. <view class="stars acea-row">
  47. <text
  48. class="iconfont icon-pingjia"
  49. v-for="i in 5"
  50. :key="i"
  51. :style="{ color: i <= item.star ? starColor : '#eee' }"
  52. ></text>
  53. </view>
  54. </view>
  55. </view>
  56. <view class="content line2">{{ item.comment }}</view>
  57. <view class="images acea-row" v-if="item.pics && item.pics.length">
  58. <view
  59. class="img-box"
  60. v-for="(img, imgIndex) in item.pics.slice(0, 3)"
  61. :key="imgIndex"
  62. >
  63. <image :src="img" class="img" mode="aspectFill"></image>
  64. <view class="more" v-if="imgIndex === 2 && item.pics.length > 3"
  65. >+{{ item.pics.length - 3 }}</view
  66. >
  67. </view>
  68. </view>
  69. </view>
  70. </view>
  71. <!-- Slide List -->
  72. <scroll-view scroll-x="true" class="slide-wrapper" v-else>
  73. <view
  74. class="slide-item"
  75. v-for="(item, index) in showList"
  76. :key="index"
  77. >
  78. <view class="user-info acea-row row-middle">
  79. <image
  80. :src="item.avatar"
  81. class="avatar"
  82. mode="aspectFill"
  83. ></image>
  84. <view class="info">
  85. <view class="name line1">{{ item.nickname }}</view>
  86. <view class="stars acea-row">
  87. <text
  88. class="iconfont icon-pingjia"
  89. v-for="i in 5"
  90. :key="i"
  91. :style="{ color: i <= item.star ? starColor : '#eee' }"
  92. ></text>
  93. </view>
  94. </view>
  95. </view>
  96. <view class="content line2">{{ item.comment }}</view>
  97. <view class="images acea-row" v-if="item.pics && item.pics.length">
  98. <view
  99. class="img-box"
  100. v-for="(img, imgIndex) in item.pics.slice(0, 3)"
  101. :key="imgIndex"
  102. >
  103. <image :src="img" class="img" mode="aspectFill"></image>
  104. <view class="more" v-if="imgIndex === 2 && item.pics.length > 3"
  105. >+{{ item.pics.length - 3 }}</view
  106. >
  107. </view>
  108. </view>
  109. </view>
  110. </scroll-view>
  111. </view>
  112. </common-wrapper>
  113. </view>
  114. </template>
  115. <script>
  116. import commonWrapper from "./commonWrapper.vue";
  117. import { getReplyList } from "@/api/store.js";
  118. export default {
  119. components: { commonWrapper },
  120. name: "homeReviews",
  121. props: {
  122. dataConfig: {
  123. type: Object,
  124. default: () => ({}),
  125. },
  126. productId: {
  127. type: [Number, String],
  128. default: 0,
  129. },
  130. reply: {
  131. type: Array,
  132. default: () => [],
  133. },
  134. replyCount: {
  135. type: [Number, String],
  136. default: 0,
  137. },
  138. replyChance: {
  139. type: [Number, String],
  140. default: 0,
  141. },
  142. },
  143. data() {
  144. return {
  145. replyList: [],
  146. };
  147. },
  148. watch: {
  149. productId: {
  150. handler(nVal) {
  151. if (nVal) {
  152. this.getReplyListFun();
  153. }
  154. },
  155. immediate: true,
  156. },
  157. dataConfig: {
  158. handler(nVal) {
  159. if (nVal && this.productId) {
  160. this.getReplyListFun();
  161. }
  162. },
  163. deep: true,
  164. },
  165. },
  166. computed: {
  167. configData() {
  168. return this.dataConfig;
  169. },
  170. bgRadius() {
  171. if (!this.dataConfig.fillet) return {};
  172. let borderRadius = `${this.dataConfig.fillet.val * 2}rpx`;
  173. if (this.dataConfig.fillet.type) {
  174. borderRadius = `${this.dataConfig.fillet.valList[0].val * 2}rpx ${
  175. this.dataConfig.fillet.valList[1].val * 2
  176. }rpx ${this.dataConfig.fillet.valList[3].val * 2}rpx ${
  177. this.dataConfig.fillet.valList[2].val * 2
  178. }rpx`;
  179. }
  180. return {
  181. borderRadius: borderRadius,
  182. overflow: "hidden",
  183. };
  184. },
  185. checkList() {
  186. return this.dataConfig.checkBoxConfig
  187. ? this.dataConfig.checkBoxConfig.type
  188. : [];
  189. },
  190. isSlide() {
  191. return this.dataConfig.layoutConfig
  192. ? this.dataConfig.layoutConfig.tabVal === 1
  193. : false;
  194. },
  195. showList() {
  196. return this.replyList;
  197. },
  198. titleColor() {
  199. return this.dataConfig.titleColor && this.dataConfig.titleColor.color[0]
  200. ? this.dataConfig.titleColor.color[0].item
  201. : "#333333";
  202. },
  203. countColor() {
  204. return this.dataConfig.countColor && this.dataConfig.countColor.color[0]
  205. ? this.dataConfig.countColor.color[0].item
  206. : "#999999";
  207. },
  208. rateColor() {
  209. if (
  210. this.dataConfig.toneConfig &&
  211. this.dataConfig.toneConfig.tabVal === 1
  212. ) {
  213. return this.dataConfig.rateColor && this.dataConfig.rateColor.color[0]
  214. ? this.dataConfig.rateColor.color[0].item
  215. : "#E93323";
  216. }
  217. return "var(--view-theme)";
  218. },
  219. starColor() {
  220. if (
  221. this.dataConfig.toneConfig &&
  222. this.dataConfig.toneConfig.tabVal === 1
  223. ) {
  224. return this.dataConfig.starColor && this.dataConfig.starColor.color[0]
  225. ? this.dataConfig.starColor.color[0].item
  226. : "#E93323";
  227. }
  228. return "var(--view-theme)";
  229. },
  230. totalCount() {
  231. return this.replyCount || "0";
  232. },
  233. },
  234. methods: {
  235. getReplyListFun() {
  236. let limit = this.dataConfig.numConfig ? this.dataConfig.numConfig.val : 2;
  237. getReplyList(this.productId, {
  238. page: 1,
  239. limit: limit,
  240. type: 0,
  241. }).then((res) => {
  242. this.replyList = res.data || [];
  243. });
  244. },
  245. },
  246. };
  247. </script>
  248. <style lang="scss" scoped>
  249. .header {
  250. margin-bottom: 24rpx;
  251. .title {
  252. font-size: 30rpx;
  253. font-weight: 600;
  254. }
  255. .icon-jiantou {
  256. color: #999;
  257. }
  258. .count {
  259. font-size: 24rpx;
  260. margin-left: 10rpx;
  261. }
  262. .right {
  263. font-size: 24rpx;
  264. }
  265. .iconfont {
  266. font-size: 24rpx;
  267. margin-left: 4rpx;
  268. }
  269. }
  270. .list {
  271. .item {
  272. background-color: #f9f9f9;
  273. border-radius: 12rpx;
  274. padding: 20rpx;
  275. margin-bottom: 20rpx;
  276. }
  277. }
  278. .slide-wrapper {
  279. white-space: nowrap;
  280. width: 100%;
  281. .slide-item {
  282. display: inline-block;
  283. background-color: #f9f9f9;
  284. border-radius: 12rpx;
  285. padding: 20rpx;
  286. margin-right: 20rpx;
  287. width: 600rpx;
  288. vertical-align: top;
  289. &:last-child {
  290. margin-right: 0;
  291. }
  292. }
  293. }
  294. .user-info {
  295. margin-bottom: 16rpx;
  296. .avatar {
  297. width: 64rpx;
  298. height: 64rpx;
  299. border-radius: 50%;
  300. }
  301. .info {
  302. margin-left: 16rpx;
  303. .name {
  304. font-size: 26rpx;
  305. color: #333;
  306. line-height: 36rpx;
  307. margin-bottom: 4rpx;
  308. max-width: 300rpx;
  309. }
  310. .stars {
  311. .iconfont {
  312. font-size: 20rpx;
  313. margin-right: 4rpx;
  314. }
  315. }
  316. }
  317. }
  318. .content {
  319. font-size: 26rpx;
  320. color: #333;
  321. line-height: 40rpx;
  322. margin-bottom: 16rpx;
  323. white-space: normal;
  324. }
  325. .images {
  326. .img-box {
  327. position: relative;
  328. margin-right: 12rpx;
  329. width: 120rpx;
  330. height: 120rpx;
  331. border-radius: 8rpx;
  332. overflow: hidden;
  333. .img {
  334. width: 100%;
  335. height: 100%;
  336. }
  337. .more {
  338. position: absolute;
  339. top: 0;
  340. left: 0;
  341. width: 100%;
  342. height: 100%;
  343. background-color: rgba(0, 0, 0, 0.4);
  344. display: flex;
  345. align-items: center;
  346. justify-content: center;
  347. color: #fff;
  348. font-size: 28rpx;
  349. }
  350. }
  351. }
  352. </style>