Explorar el Código

:satisfied: 商品评论功能

nnkwrik hace 6 años
padre
commit
c25c84e1f2

+ 1 - 0
common/src/main/java/io/github/nnkwrik/common/dto/Response.java

@@ -18,6 +18,7 @@ public class Response<T> {
 
     //goods
     public static final int OPEN_ID_IS_EMPTY = 4001;
+    public static final int COMMENT_INFO_INCOMPLETE = 4002;
 
     //user
     public static final int USER_IS_NOT_EXIST = 3001;

+ 1 - 1
common/src/main/java/io/github/nnkwrik/common/token/injection/JWTResolver.java

@@ -47,7 +47,7 @@ public class JWTResolver implements HandlerMethodArgumentResolver {
         if (token == null && parameter.getParameterAnnotation(JWT.class).required()) {
             log.info("用户的Authorization头为空,无法获取jwt");
             throw new JWTException(JWTException.TOKEN_IS_EMPTY, "用户的Authorization头为空,无法获取jwt");
-        } else if ((user = cache.getIfPresent(token)) == null) {   //试图从缓存获取
+        } else if (token != null && (user = cache.getIfPresent(token)) == null) {   //试图从缓存获取
 
             try {
                 user = tokenSolver.solve(token);

+ 23 - 4
goods-service/src/main/java/io/github/nnkwrik/goodsservice/controller/IndexController.java

@@ -5,13 +5,12 @@ import io.github.nnkwrik.common.dto.Response;
 import io.github.nnkwrik.common.token.injection.JWT;
 import io.github.nnkwrik.goodsservice.model.vo.CatalogVo;
 import io.github.nnkwrik.goodsservice.model.vo.IndexVO;
+import io.github.nnkwrik.goodsservice.model.vo.inner.CommentVo;
 import io.github.nnkwrik.goodsservice.service.IndexService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
 
 /**
  * @author nnkwrik
@@ -60,4 +59,24 @@ public class IndexController {
         return Response.ok();
 
     }
+
+    @PostMapping("/comment/post/{goodsId}")
+    public Response postComment(@PathVariable("goodsId") int goodsId,
+                                @RequestBody CommentVo comment,
+                                @JWT(required = true) JWTUser user) {
+        if (StringUtils.isEmpty(user.getOpenId()) ||
+                StringUtils.isEmpty(comment.getReply_user_id()) ||
+                StringUtils.isEmpty(comment.getContent()) ||
+                comment.getReply_comment_id() == null) {
+            String msg = "用户发表评论失败,信息不完整";
+            log.info(msg);
+            return Response.fail(Response.COMMENT_INFO_INCOMPLETE,msg);
+        }
+
+        indexService.addComment(goodsId, user.getOpenId(), comment.getReply_comment_id(), comment.getReply_user_id(), comment.getContent());
+
+        log.info("用户添加评论:用户id=【{}】,回复评论id=【{}】,回复内容=【{}】", user.getOpenId(),comment.getReply_comment_id(),comment.getReply_user_name());
+        return Response.ok();
+
+    }
 }

+ 4 - 2
goods-service/src/main/java/io/github/nnkwrik/goodsservice/controller/SearchController.java

@@ -36,13 +36,15 @@ public class SearchController {
     @GetMapping("/index")
     public Response<SearchIndexPageVo> searchIndex(@JWT JWTUser jwtUser) {
         List<String> historyKeyword = null;
+        String openId = null;
         if (jwtUser != null) {
-            historyKeyword = searchService.getUserHistory(jwtUser.getOpenId());
+            openId = jwtUser.getOpenId();
+            historyKeyword = searchService.getUserHistory(openId);
         }
 
         List<String> hotKeyword = searchCache.getHot(10);
         SearchIndexPageVo vo = new SearchIndexPageVo(historyKeyword, hotKeyword);
-        log.info("用户openId= 【{}】获取搜索历史和热门关键词,搜索历史 = 【{}】,热门关键词 = 【{}】", jwtUser.getOpenId(), historyKeyword, hotKeyword);
+        log.info("用户openId= 【{}】获取搜索历史和热门关键词,搜索历史 = 【{}】,热门关键词 = 【{}】", openId, historyKeyword, hotKeyword);
 
         return Response.ok(vo);
     }

+ 9 - 1
goods-service/src/main/java/io/github/nnkwrik/goodsservice/dao/OtherMapper.java

@@ -39,7 +39,6 @@ public interface OtherMapper {
     void deleteUserCollect(@Param("user_id") String userId, @Param("goods_id") int goodsId);
 
 
-
     @Select("SELECT EXISTS(SELECT 1 FROM user_preference WHERE type = 2 and user_id = #{user_id} and goods_id = #{goods_id})")
     Boolean userHasWant(@Param("user_id") String userId, @Param("goods_id") int goodsId);
 
@@ -54,4 +53,13 @@ public interface OtherMapper {
             "  and type = 2;")
     void deleteUserWant(@Param("user_id") String userId, @Param("goods_id") int goodsId);
 
+
+    @Insert("insert into goods_comment (goods_id, user_id, reply_comment_id, reply_user_id, content)\n" +
+            "values (#{goods_id}, #{user_id}, #{reply_comment_id}, #{reply_user_id}, #{content});")
+    void addComment(@Param("goods_id") int goodsId,
+                    @Param("user_id") String userId,
+                    @Param("reply_comment_id") int replyCommentId,
+                    @Param("reply_user_id") String replyUserId,
+                    @Param("content") String content);
+
 }

+ 1 - 0
goods-service/src/main/java/io/github/nnkwrik/goodsservice/service/IndexService.java

@@ -17,5 +17,6 @@ public interface IndexService {
 
     void collectAddOrDelete(int goodsId, String userId, boolean hasCollect);
 
+    void addComment(int goodsId, String userId, int replyCommentId, String replyUserId, String content);
 
 }

+ 6 - 4
goods-service/src/main/java/io/github/nnkwrik/goodsservice/service/impl/IndexServiceImpl.java

@@ -4,10 +4,7 @@ import com.github.pagehelper.PageHelper;
 import io.github.nnkwrik.goodsservice.dao.CategoryMapper;
 import io.github.nnkwrik.goodsservice.dao.GoodsMapper;
 import io.github.nnkwrik.goodsservice.dao.OtherMapper;
-import io.github.nnkwrik.goodsservice.model.po.Ad;
-import io.github.nnkwrik.goodsservice.model.po.Category;
-import io.github.nnkwrik.goodsservice.model.po.Channel;
-import io.github.nnkwrik.goodsservice.model.po.Goods;
+import io.github.nnkwrik.goodsservice.model.po.*;
 import io.github.nnkwrik.goodsservice.model.vo.CatalogVo;
 import io.github.nnkwrik.goodsservice.model.vo.IndexVO;
 import io.github.nnkwrik.goodsservice.model.vo.inner.BannerVo;
@@ -89,5 +86,10 @@ public class IndexServiceImpl implements IndexService {
         }
     }
 
+    @Override
+    public void addComment(int goodsId, String userId, int replyCommentId, String replyUserId, String content) {
+        otherMapper.addComment(goodsId,userId,replyCommentId,replyUserId,content);
+    }
+
 
 }

+ 84 - 26
wx-front/pages/goods/goods.js

@@ -2,6 +2,7 @@ var app = getApp();
 var WxParse = require('../../lib/wxParse/wxParse.js');
 var util = require('../../utils/util.js');
 var api = require('../../config/api.js');
+var user = require('../../services/user.js');
 
 Page({
   data: {
@@ -20,13 +21,19 @@ Page({
     number: 1,
     checkedSpecText: '请选择规格数量',
     openAttr: false,
+    openComment: false,
+    replyId: '',
+    replyUserId: '',
+    replyUserName: '',
+    commentContent:'',
+    onLoadOption: {},
     noCollectImage: "/static/images/detail_star.png",
     hasCollectImage: "/static/images/detail_star_checked.png",
     collectBackImage: "/static/images/detail_star.png"
   },
-  getGoodsInfo: function () {
+  getGoodsInfo: function() {
     let that = this;
-    util.request(api.GoodsDetail + '/' + that.data.id).then(function (res) {
+    util.request(api.GoodsDetail + '/' + that.data.id).then(function(res) {
       if (res.errno === 0) {
         that.setData({
           goods: res.data.info,
@@ -57,9 +64,9 @@ Page({
     });
 
   },
-  getGoodsRelated: function () {
+  getGoodsRelated: function() {
     let that = this;
-    util.request(api.GoodsRelated + '/' + that.data.id,).then(function (res) {
+    util.request(api.GoodsRelated + '/' + that.data.id, ).then(function(res) {
       if (res.errno === 0) {
         that.setData({
           relatedGoods: res.data.goodsList,
@@ -176,10 +183,13 @@ Page({
   //     }
   //   });
   // },
-  onLoad: function (options) {
+  onLoad: function(options) {
     // 页面初始化 options为页面跳转所带来的参数
     this.setData({
-      id: parseInt(options.id)
+      onLoadOption: options,
+      id: parseInt(options.id),
+      commentContent:''
+      
       // id: 1181000
     });
 
@@ -194,46 +204,94 @@ Page({
     //   }
     // });
   },
-  onReady: function () {
+  onReady: function() {
     // 页面渲染完成
 
   },
-  onShow: function () {
+  onShow: function() {
     // 页面显示
 
   },
-  onHide: function () {
+  onHide: function() {
     // 页面隐藏
 
   },
-  onUnload: function () {
+  onUnload: function() {
     // 页面关闭
 
   },
-  // switchAttrPop: function () {
-  //   if (this.data.openAttr == false) {
-  //     this.setData({
-  //       openAttr: !this.data.openAttr
-  //     });
-  //   }
-  // },
-  // closeAttr: function () {
-  //   this.setData({
-  //     openAttr: false,
-  //   });
-  // },
-  addCannelCollect: function () {
+
+  switchCommentPop: function(event) {
+    let that = this
+
+    this.setData({
+      replyId: event.currentTarget.dataset.replyId,
+      replyUserId: event.currentTarget.dataset.replyUserId,
+      replyUserName: event.currentTarget.dataset.replyUserName
+
+    })
+
+    user.checkLoginAndNav().then(() => {
+      if (this.data.openComment == false) {
+        this.setData({
+          openComment: !this.data.openComment
+        });
+      }
+    })
+
+  },
+
+
+  closeComment: function() {
+    this.setData({
+
+      openComment: false,
+    });
+  },
+
+  postComment: function(event) {
+    let that = this
+    if (!event.detail.value) {
+      util.showErrorToast('请填写内容')
+      return false;
+    }
+    util.request(api.CommentPost + '/' + this.data.id, {
+      reply_comment_id: this.data.replyId,
+      reply_user_id: this.data.replyUserId,
+      reply_user_name: this.data.replyUserName,
+      content: event.detail.value
+    }, "POST").then(function(res) {
+      if (res.errno === 0) {
+        that.setData({
+          commentContent:''
+        })
+        
+        wx.showToast({
+          title: '留言成功'
+        })
+        //刷新
+        that.onLoad(that.data.onLoadOption);
+        
+
+      }
+      console.log(res)
+    });
+
+  },
+
+  addCannelCollect: function() {
     let that = this;
+    that.checkLogin();
     //添加或是取消收藏
-    util.request(api.CollectAddOrDelete + '/' + this.data.id + '/' + this.data.userHasCollect,{}, "POST")
-      .then(function (res) {
+    util.request(api.CollectAddOrDelete + '/' + this.data.id + '/' + this.data.userHasCollect, {}, "POST")
+      .then(function(res) {
         let _res = res;
         let collectState = !that.data.userHasCollect;
         if (_res.errno == 0) {
           that.setData({
             userHasCollect: collectState
           });
-          
+
           if (that.data.userHasCollect) {
             that.setData({
               'collectBackImage': that.data.hasCollectImage

+ 32 - 4
wx-front/pages/goods/goods.wxml

@@ -87,12 +87,13 @@
 
   <view class="comments" wx:if="{{comment.length > 0}}">
     <view class="h">
-      <text class="t">留言 ({{comment.length > 999 ? '999+' : comment.length}})</text>
+      <text class="t">留言</text>
     </view>
     <view class="b">
-      <view wx:for="{{comment}}" wx:for-index="index" wx:for-item="item" wx:key="{{item.id}}">
+      <view wx:for="{{comment}}"  wx:for-index="index" wx:for-item="item" wx:key="{{item.id}}">
         <!-- comment -->
         <view class="item">
+        <view bindtap="switchCommentPop" data-reply-id="{{item.id}}" data-reply-user-id="{{item.simpleUser.openId}}" data-reply-user-name='{{item.simpleUser.nickName}}'>
           <view class="info">
             <view class="user">
               <image src="{{item.simpleUser.avatarUrl}}"></image>
@@ -103,8 +104,9 @@
           <view class="content">
             {{item.content}}
           </view>
+          </view>
           <!-- reply -->
-          <view wx:for="{{item.replyList}}" wx:for-index="iindex" wx:for-item="iitem" wx:key="{{iitem.id}}">
+          <view wx:for="{{item.replyList}}" wx:for-index="iindex" wx:for-item="iitem" wx:key="{{iitem.id}}" bindtap="switchCommentPop" data-reply-id="{{iitem.id}}" data-reply-user-id="{{iitem.simpleUser.openId}}" data-reply-user-name='{{iitem.simpleUser.nickName}}' >
             <view class="reply-info">
               <view class="reply-user">
                 <image src="{{iitem.simpleUser.avatarUrl}}"></image>
@@ -222,15 +224,41 @@
   </view>
 </view> -->
 
+<view class="attr-pop-box" hidden="{{!openComment}}">
+  <view class="attr-pop">
+    <!-- <view class="close" bindtap="closeComment">
+      <image class="icon" src="/static/images/clear_input.png"></image>
+    </view> -->
+    <view class="post-comment">
+      <view class="title" wx:if="{{replyUserName}}">
+      回复@{{replyUserName}}:
+      </view>
+      <view class="title" wx:else>
+      发表留言:
+      </view>
+
+      <view class="content">
+        <input id='comment-input' class='' focus='{{openComment}}' placeholder="输入文本" maxlength='100' bindblur='closeComment' bindconfirm='postComment' value='{{commentContent}}' />
+      </view>
+
+    </view>
+  </view>
+</view>
+
+
 <view class="bottom-btn">
   <view class="l" bindtap="addCannelCollect">
     <image class="icon" src="{{ collectBackImage }}"></image>
     收藏
   </view>
-  <view class="l" bindtap="addCannelCollect">
+  <view class="l" bindtap="switchCommentPop" data-reply-id="0" data-reply-user-name='' data-reply-user-id="0">
     <image class="icon" src="/static/images/ic_menu_chat_nor.png"></image>
     留言
   </view>
+  <!-- <view class="l" >
+    <image class="icon" src="/static/images/ic_menu_chat_nor.png"></image>
+    留言
+  </view> -->
   <!-- <view class="l l-cart">
     <view class="box">
       <text class="cart-count">{{cartGoodsCount}}</text>

+ 50 - 10
wx-front/pages/goods/goods.wxss

@@ -235,7 +235,7 @@
   height: 67rpx;
   line-height: 67rpx;
   font-size: 0;
-  overflow:hidden;
+  overflow: hidden;
 }
 
 .comments .reply-user {
@@ -245,7 +245,7 @@
   line-height: 67rpx;
   font-size: 0;
   margin-left: 50rpx;
-  overflow:hidden;
+  overflow: hidden;
 }
 
 .comments .reply-user  image {
@@ -256,14 +256,15 @@
   margin-top: 5rpx;
   border-radius: 50%;
 }
+
 .comments .reply-user text {
-  display:inline-block;
-width:auto;
-height:66rpx;
-overflow:hidden;
-font-size:29rpx;
-line-height:66rpx;
-font-weight:bold;
+  display: inline-block;
+  width: auto;
+  height: 66rpx;
+  overflow: hidden;
+  font-size: 29rpx;
+  line-height: 66rpx;
+  font-weight: bold;
 }
 
 .comments .user  image {
@@ -652,7 +653,7 @@ font-weight:bold;
   width: 100%;
   height: auto;
   max-height: 780rpx;
-  padding: 31.25rpx;
+  padding: 10rpx;
   background: #fff;
   position: fixed;
   z-index: 9;
@@ -876,3 +877,42 @@ font-weight:bold;
   line-height: 30rpx;
   font-size: 27rpx;
 }
+
+.attr-pop-box .attr-pop .post-comment {
+  display: block;
+  background: #fff;
+  font-size: 29rpx;
+  color: #333;
+  height: auto;
+  /* width: 650rpx; */
+  padding: 20rpx;
+  /* margin:10px; */
+  overflow: hidden;
+}
+
+.attr-pop-box .attr-pop .title {
+  margin-bottom: 10rpx;
+}
+
+.attr-pop-box .attr-pop .content {
+  
+  border: 1rpx solid #eee;
+  border-radius: 20rpx;
+  padding: 10rpx;
+  background: #eee;
+  overflow:hidden;
+  height:65rpx;
+
+}
+.attr-pop-box .attr-pop input {
+display:block;
+height:1.4rem;
+text-overflow:clip;
+overflow:hidden;
+white-space:nowrap;
+font-family:UICTFontTextStyleBody;
+min-height:1.4rem;
+margin-bottom: 40rpx;
+
+
+}

+ 1 - 1
wx-front/pages/search/search.wxml

@@ -4,7 +4,7 @@
       <image class="icon" src="http://nos.netease.com/mailpub/hxm/yanxuan-wap/p/20150730/style/img/icon-normal/search2-2fb94833aa.png"></image>
       <!-- TODO 输入辅助 -->
       <!-- <input name="input" class="keywrod" focus="true" value="{{keyword}}" confirm-type="search" bindinput="inputChange" bindfocus="inputFocus" bindconfirm="onKeywordConfirm" confirm-type="search" placeholder="{{defaultKeyword}}" /> -->
-            <input name="input" class="keywrod" focus="true" value="{{keyword}}" confirm-type="search" bindfocus="inputFocus" bindconfirm="onKeywordConfirm" confirm-type="search" placeholder="{{defaultKeyword}}" />
+            <input name="input" class="keywrod" focus="true" value="{{keyword}}"  bindfocus="inputFocus" bindconfirm="onKeywordConfirm" confirm-type="search" placeholder="{{defaultKeyword}}" />
       <image class="del" wx:if="{{keyword}}" bindtap="clearKeyword" src="http://nos.netease.com/mailpub/hxm/yanxuan-wap/p/20150730/style/img/icon-normal/clearIpt-f71b83e3c2.png"></image>
     </view>
     <view class="right" bindtap="closeSearch">取消</view>

+ 15 - 1
wx-front/services/user.js

@@ -62,6 +62,19 @@ function checkLogin() {
   });
 }
 
+function checkLoginAndNav() {
+  return new Promise(function(resolve, reject) {
+    if (wx.getStorageSync('userInfo') && wx.getStorageSync('token')) {
+      resolve(true);
+    } else {
+      wx.navigateTo({
+        url: '/pages/auth/auth'
+      })
+      reject(false); //没有登陆过
+    }
+  });
+}
+
 /**
  * 判断用户是否已授权获取userInfo
  */
@@ -72,7 +85,7 @@ function checkUserAuth() {
         if (res.authSetting['scope.userInfo']) {
           // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
           resolve(true);
-        }else{
+        } else {
           reject(false);
         }
       }
@@ -85,4 +98,5 @@ module.exports = {
   loginByWeixin,
   checkLogin,
   checkUserAuth,
+  checkLoginAndNav,
 };

+ 1 - 2
wx-front/utils/util.js

@@ -38,7 +38,6 @@ function request(url, data = {}, method = "GET") {
         console.log("success");
 
         if (res.statusCode == 200) {
-
           if (res.data.errno == 3003 || res.data.errno == 3004 || res.data.errno == 3005) {
             console.log(res.data.errmsg)
             //TOKEN_IS_EMPTY
@@ -118,7 +117,7 @@ function backendLogin(detail) {
 
             resolve(res.data.userInfo);
           } else {
-            reject(res.data.userInfo);
+            reject(res);
           }
       }).catch((err) => { //request
         reject(err);

+ 5 - 0
zuul/src/main/resources/application.yml

@@ -43,6 +43,11 @@ zuul:
       serviceId: goods-service
       strip-prefix: false
       sensitiveHeaders:
+    comment:
+      path: /comment/**
+      serviceId: goods-service
+      strip-prefix: false
+      sensitiveHeaders: