index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. <template>
  2. <view>
  3. <u-sticky bgColor="#fff" class="tabs-wrap">
  4. <u-tabs
  5. class="tabs"
  6. :list="tabs"
  7. :itemStyle="itemStyle"
  8. :is-scroll="false"
  9. :current="params.active"
  10. @change="handTabhange">
  11. </u-tabs>
  12. </u-sticky>
  13. <view class="content-wrap" v-if="params.active == 0" style="padding-top: 20rpx;">
  14. <scroll-view scroll-y class="evaluation-info-wrap" @scrolltolower="scrolltolower">
  15. <view class="evaluation-list">
  16. <view class="item" v-for="item in evaluationList" :key="item.evaluateId">
  17. <view class="user-info">
  18. <view class="user">
  19. <image class="avatr" :src="item.headimgurl || ''"/>
  20. <view class="user-wrap">
  21. <view class="top">
  22. <view class="user-name">{{ item.memberName || '会员' }}</view>
  23. <view class="date">{{ item.evaDateStr }}</view>
  24. </view>
  25. <!-- <view class="evaluation-rate">
  26. <text class="label" style="white-space: nowrap;">商品:</text>
  27. <view class="goods-name" style="margin-left: 8rpx;">{{ item.goodsName || '' }}</view>
  28. </view> -->
  29. <view class="evaluation-rate">
  30. <text class="label" style="white-space: nowrap;">评分</text>
  31. <u-rate size="20" readonly active-color="#F57119" v-model="item.goodsScore"></u-rate>
  32. </view>
  33. </view>
  34. </view>
  35. </view>
  36. <view class="evaluation-text">
  37. {{ item.content || '' }}
  38. </view>
  39. <view class="evaluation-image" v-if="item.pictureUrl">
  40. <image :src="item.pictureUrl" />
  41. </view>
  42. <view style="margin-top: 10rpx;margin-left: 80rpx;">
  43. <button type="primary" size="mini" @click="reply(item)">回复</button>
  44. </view>
  45. </view>
  46. </view>
  47. </scroll-view>
  48. </view>
  49. <view class="content-wrap" v-if="params.active == 1" style="padding-top: 20rpx;">
  50. <scroll-view scroll-y class="evaluation-info-wrap" @scrolltolower="scrolltolower">
  51. <view class="evaluation-list">
  52. <view class="item" v-for="item in evaluationList" :key="item.evaluateId">
  53. <view class="user-info">
  54. <view class="user">
  55. <image class="avatr" :src="item.headimgurl || ''"/>
  56. <view class="user-wrap">
  57. <view class="top">
  58. <view class="user-name">{{ item.memberName || '会员' }}</view>
  59. <view class="date">{{ item.evaDateStr }}</view>
  60. </view>
  61. <!-- <view class="evaluation-rate">
  62. <text class="label" style="white-space: nowrap;">商品:</text>
  63. <view class="goods-name" style="margin-left: 8rpx;">{{ item.goodsName || '' }}</view>
  64. </view> -->
  65. <view class="evaluation-rate">
  66. <text class="label" style="white-space: nowrap;">评分</text>
  67. <u-rate size="20" readonly active-color="#F57119" v-model="item.goodsScore"></u-rate>
  68. </view>
  69. </view>
  70. </view>
  71. </view>
  72. <view class="evaluation-text">
  73. {{ item.content }}
  74. </view>
  75. <view class="evaluation-image" v-if="item.pictureUrl">
  76. <image :src="item.pictureUrl" />
  77. </view>
  78. <view class="sotre-recover" v-if="item.reply && item.reply.length">
  79. <view class="name">商家回复:</view>
  80. <view>
  81. {{ item.reply }}
  82. </view>
  83. </view>
  84. </view>
  85. </view>
  86. </scroll-view>
  87. </view>
  88. <uni-popup ref="popup" :maskClick="true" @change="closePopup">
  89. <view style="background-color: #FFF;">
  90. <view class="reply-title">回复内容</view>
  91. <textarea :value="content" maxlength="45" class="reply-content" @input="inputChange"></textarea>
  92. <button @click="sumbit">提交</button>
  93. </view>
  94. </uni-popup>
  95. </view>
  96. </template>
  97. <script>
  98. import {mapState} from 'vuex';
  99. export default {
  100. data() {
  101. return {
  102. evaUrl: '/storeEvaluationApi/getEvaluateList',
  103. replyUrl: '/storeEvaluationApi/replyEvaluation',
  104. params: {
  105. active: 0
  106. },
  107. itemStyle: {
  108. width: '50vw',
  109. height: '80rpx'
  110. },
  111. tabs: [
  112. {
  113. name: '待回复',
  114. value: 0,
  115. badge: {
  116. value: 0,
  117. }
  118. },
  119. {
  120. name: '已回复',
  121. value: 10,
  122. badge: {
  123. value: 0,
  124. }
  125. },
  126. ],
  127. evaluationList:[],
  128. page: 1,
  129. content: '',
  130. currentItem: null,
  131. loadingType: 0,
  132. }
  133. },
  134. computed: {
  135. ...mapState(['storeInfo'])
  136. },
  137. methods: {
  138. closePopup () {
  139. this.content = ''
  140. },
  141. handTabhange (e) {
  142. this.params.active = e.index
  143. this.loadData()
  144. },
  145. reply(item) {
  146. this.currentItem = item;
  147. this.$refs.popup.open();
  148. },
  149. inputChange(e) {
  150. this.content = e.detail.value
  151. },
  152. sumbit() {
  153. uni.showLoading({
  154. title: '回复中'
  155. });
  156. var dateStr = (new Date()).getTime();
  157. var sign = this.getSign(dateStr);
  158. this.requst({
  159. url: this.replyUrl,
  160. data: {
  161. timestamp: dateStr,
  162. sign: sign,
  163. evaluationId: this.currentItem.evaluateId,
  164. content: this.content
  165. },
  166. success: res => {
  167. uni.showToast({
  168. title: '回复成功',
  169. icon: 'none'
  170. })
  171. this.loadData();
  172. this.$refs.popup.close();
  173. uni.hideLoading();
  174. },
  175. fail: (e) => {
  176. console.log("接口调用失败:" + JSON.stringify(e));
  177. uni.hideLoading();
  178. }
  179. })
  180. },
  181. loadData() {
  182. uni.showLoading({
  183. title: '加载中'
  184. });
  185. var dateStr = (new Date()).getTime();
  186. var sign = this.getSign(dateStr);
  187. this.requst({
  188. url: this.evaUrl,
  189. data: {
  190. timestamp: dateStr,
  191. sign: sign,
  192. currentPage: this.page,
  193. storeId: this.storeInfo.storeId,
  194. status: (this.params.active + 1)
  195. },
  196. success: res => {
  197. if (res.data.rtnBean.rtnCode != undefined) {
  198. if (res.data.rtnBean.rtnCode == 0) {
  199. if (res.data.list != null && res.data.list.length > 0) {
  200. if (res.data.list != null && res.data.list.length > 0 && res.data.list
  201. .length <= 20) {
  202. this.evaluationList = res.data.list;
  203. if (res.data.page.pageCount == 1) {
  204. this.isShow = false
  205. this.loadingType = 2;
  206. } else {
  207. this.isShow = false
  208. this.loadingType = 0;
  209. }
  210. } else {
  211. this.isShow = true
  212. this.loadingType = 2;
  213. }
  214. } else {
  215. this.isShow = true
  216. this.evaluationList = [];
  217. }
  218. } else {
  219. this.isShow = true
  220. this.evaluationList = [];
  221. }
  222. }
  223. uni.hideLoading();
  224. },
  225. fail: (e) => {
  226. console.log("接口调用失败:" + JSON.stringify(e));
  227. uni.hideLoading();
  228. }
  229. })
  230. },
  231. scrolltolower() {
  232. if (this.loadingType != 0) { // loadingType!=0;直接返回
  233. return false
  234. }
  235. // this.loadingType_status = 'loading';
  236. this.page = this.page + 1;
  237. this.loadingType = 1;
  238. uni.showLoading({
  239. title: '加载中'
  240. });
  241. var dateStr = (new Date()).getTime();
  242. var sign = this.getSign(dateStr);
  243. this.requst({
  244. url: this.evaUrl,
  245. data: {
  246. timestamp: dateStr,
  247. sign: sign,
  248. currentPage: this.page,
  249. storeId: this.storeInfo.storeId,
  250. status: (this.params.active + 1)
  251. },
  252. success: res => {
  253. if (res.data.rtnBean.rtnCode == 0) {
  254. uni.hideLoading();
  255. if (res.data.list != "" && res.data.list != null && res.data.list.length > 0) {
  256. for (var i = 0; i < res.data.list.length; i++) {
  257. this.evaluationList.push(res.data.list[i]);
  258. }
  259. if (res.data.page.currentPage == res.data.page.pageCount) {
  260. this.loadingType = 2;
  261. }else {
  262. this.isShow = false
  263. this.loadingType = 0;
  264. }
  265. } else {
  266. this.loadingType = 2;
  267. }
  268. } else {
  269. uni.hideLoading();
  270. if (res.data.rtnBean.rtnMsg != '') {
  271. this.$api.msg(res.data.rtnBean.rtnMsg);
  272. }
  273. }
  274. },
  275. fail: (e) => {
  276. console.log("接口调用失败:" + JSON.stringify(e));
  277. uni.hideLoading();
  278. },
  279. });
  280. },
  281. },
  282. onLoad() {
  283. this.loadData()
  284. }
  285. }
  286. </script>
  287. <style lang="scss" scoped>
  288. .content-wrap {
  289. height: calc(100vh - 80rpx);
  290. }
  291. .evaluation-info-wrap {
  292. width: 100%;
  293. max-height: 100%;
  294. height: 100%;
  295. overflow-y: auto;
  296. background-color: #f5f5f5;
  297. }
  298. .evaluation-wrap {
  299. width: 100%;
  300. height: 246rpx;
  301. @include between;
  302. margin: 20rpx 0;
  303. background-color: #fff;
  304. .left, .right {
  305. flex: 1;
  306. text-align: center;
  307. .count {
  308. font-size: 56rpx;
  309. font-weight: bold;
  310. color: $light-color;
  311. }
  312. .name {
  313. font-size: $font-lg;
  314. }
  315. }
  316. .center {
  317. flex: 2;
  318. display: flex;
  319. flex-direction: column;
  320. .item {
  321. @include flexStart;
  322. }
  323. }
  324. .right {
  325. }
  326. }
  327. .evaluation-list {
  328. padding: 20rpx 0 0;
  329. box-sizing: border-box;
  330. background-color: #fff;
  331. .item {
  332. margin-bottom: 20rpx;
  333. border-bottom: 2px solid #f5f5f5;
  334. padding: 0 40rpx 20rpx;
  335. box-sizing: border-box;
  336. }
  337. .item:last-child {
  338. margin-bottom: 0;
  339. border-bottom: none;
  340. }
  341. .user-info {
  342. width: 100%;
  343. @include between;
  344. }
  345. .user {
  346. width: 100%;
  347. @include flexStart;
  348. }
  349. .avatr {
  350. width: 60rpx;
  351. min-width: 60rpx;
  352. height: 60rpx;
  353. border-radius: 60rpx;
  354. overflow: hidden;
  355. margin-right: 20rpx;
  356. }
  357. .user-wrap {
  358. width: calc(100% - 80rpx);
  359. margin-bottom: 20rpx;
  360. .top {
  361. width: 100%;
  362. @include between;
  363. }
  364. .date {
  365. font-size: $font-base;
  366. }
  367. .evaluation-rate {
  368. @include flexStart;
  369. font-size: $font-base;
  370. }
  371. }
  372. .evaluation-text, .evaluation-image, .sotre-recover {
  373. margin-left: 80rpx;
  374. font-size: 26rpx;
  375. }
  376. .evaluation-image {
  377. margin-top: 20rpx;
  378. image {
  379. width: 200rpx;
  380. height: 200rpx;
  381. margin-right: 20rpx;
  382. margin-bottom: 20rpx;
  383. }
  384. }
  385. .sotre-recover {
  386. background-color: #f5f5f5;
  387. padding: 20rpx;
  388. margin-top: 20rpx;
  389. box-sizing: border-box;
  390. font-size: $font-base;
  391. color: $icon-color;
  392. }
  393. }
  394. .reply-title {
  395. padding: 16rpx;
  396. border-bottom: 2rpx solid #E6E6E6;
  397. }
  398. .reply-content {
  399. border-bottom: 2rpx solid #E6E6E6;
  400. padding: 20rpx;
  401. }
  402. .user-name {
  403. white-space: nowrap;
  404. overflow: hidden;
  405. text-overflow: ellipsis;
  406. display: inline-block;
  407. max-width: 6em;
  408. }
  409. </style>