Day4谷粒学院评论、创建订单、查询订单总结
1、评论
需求:在课程详细下面写好评论,可以完成分页,增加评论等。
解决方案以及思路:
0、创建表和代码生成
①后端接口要包括分页查询评论,只需要传入courseI就可以了。第二个接口就是添加评论,需要用到用户信息,所以需要远程调用根据用户id获取用户信息。
②然后就是前端加入评论组件,写好comment的api也就是js。然后就是页面调用初始化评论,展示分页评论。
③最后就是写添加方法。这里的token会通过拦截器传入到后端,只需要用JWTUtils解析就能获取用户id。然后就能够远程调用获取用户信息并且添加评论。
CommentController
@RestController
@RequestMapping("/eduservice/comment")
@CrossOrigin
@Slf4j
public class EduCommentController {
@Autowired
EduCommentService commentService;
@Autowired
UcenterClient ucenterClient;
@ApiOperation("添加对应的评论")
@PostMapping("addComment")
public R addComment(HttpServletRequest request, @RequestBody EduComment comment){
//1.因为Header上面本来就有这个token,解析token获取id
String memberId = JwtUtils.getMemberIdByJwtToken(request);
//2.放入comment
comment.setMemberId(memberId);
//3.根据id获取对应的member信息
UcenterMemberVo ucenterMemberVo =ucenterClient.getMemberInfoById(memberId);
//4.设置值进comment
comment.setAvatar(ucenterMemberVo.getAvatar());
comment.setNickname(ucenterMemberVo.getNickname());
commentService.save(comment);
return R.ok();
}
@ApiOperation("根据课程id分页查询")
@GetMapping("getComment/{page}/{limit}/{courseId}")
public R getCommentByCourseId(
@PathVariable("limit")long limit,
@PathVariable("page")long page,
@PathVariable("courseId")String courseId
){
log.info(courseId);
log.info("查询comment");
//1.设置查询条件
Page<EduComment> commentPage=new Page<>(page,limit);
QueryWrapper<EduComment> queryWrapper=new QueryWrapper<>();
queryWrapper.eq("course_id",courseId);
commentService.page(commentPage, queryWrapper);
//获取所有属性放到map上面
Map<String,Object> map=new HashMap<>();
List<EduComment> commentList = commentPage.getRecords();
long current = commentPage.getCurrent();//当前页
long size = commentPage.getSize();//一页记录数
long total = commentPage.getTotal();//总记录数
long pages = commentPage.getPages();//总页数
boolean hasPrevious = commentPage.hasPrevious();//是否有上页
boolean hasNext = commentPage.hasNext();//是否有下页
//把属性put进去
map.put("current",current);
map.put("size",size);
map.put("total",total);
map.put("pages",pages);
map.put("hasPrevious",hasPrevious);
map.put("hasNext",hasNext);
map.put("list",commentList);
log.info(String.valueOf(commentList));
return R.ok().data(map);
}
}
UcenterClient
@Component
@FeignClient(name = "service-ucenter")
public interface UcenterClient {
@ApiOperation("根据id获取member")
@GetMapping("/educenter/member/getMemberInfoById/{memberId}")
UcenterMemberVo getMemberInfoById(@PathVariable("memberId")String memberId);
}
UcenterController
//4.根据id获取对应的member
@ApiOperation("根据id获取member")
@GetMapping("getMemberInfoById/{memberId}")
public UcenterMemberVo getMemberInfoById(@PathVariable("memberId")String memberId){
UcenterMember byId = ucenterMemberService.getById(memberId);
UcenterMemberVo ucenterMemberVo=new UcenterMemberVo();
BeanUtils.copyProperties(byId,ucenterMemberVo);
return ucenterMemberVo;
}
放在common下的通用类UcenterMemberVo
@Data
public class UcenterMemberVo implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "会员id")
@TableId(value = "id", type = IdType.ID_WORKER_STR)
private String id;
@ApiModelProperty(value = "微信openid")
private String openid;
@ApiModelProperty(value = "手机号")
private String mobile;
@ApiModelProperty(value = "密码")
private String password;
@ApiModelProperty(value = "昵称")
private String nickname;
@ApiModelProperty(value = "性别 1 女,2 男")
private Integer sex;
@ApiModelProperty(value = "年龄")
private Integer age;
@ApiModelProperty(value = "用户头像")
private String avatar;
@ApiModelProperty(value = "用户签名")
private String sign;
@ApiModelProperty(value = "是否禁用 1(true)已禁用, 0(false)未禁用")
private Boolean isDisabled;
@ApiModelProperty(value = "逻辑删除 1(true)已删除, 0(false)未删除")
private Boolean isDeleted;
@ApiModelProperty(value = "创建时间")
@TableField(fill = FieldFill.INSERT)
private Date gmtCreate;
@ApiModelProperty(value = "更新时间")
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date gmtModified;
}
课程详细页面的方法和组件(js文件也就是api就不提供)
data(){
return {
courseId:"",
data:{},//分页查询的结果
comment:{
courseId:"",
teacherId:"",
content:""//内容
},
course:{
courseId:"",
},
chapterVideoList:[]
}
},
methods:{
addComment(){
this.course.courseId=this.$route.params.id
this.comment.courseId = this.course.courseId;
this.comment.teacherId=this.course.teacherId
commentApi.addComment(this.comment)
.then(response=>{
alert(this.course.courseId);
this.$message({
type:"succuss",
message:"添加成功"
})
this.gotoPage(1);
})
}
,
initComment(){
commentApi.getCommentByCourseId(1,5,this.course.courseId)
.then(response=>{
this.data=response.data.data;
})
}
}
组件
<div class="mt50 commentHtml">
<div>
<h6 class="c-c-content c-infor-title" id="i-art-comment">
<span class="commentTitle">课程评论</span>
</h6>
<section class="lh-bj-list pr mt20 replyhtml">
<ul>
<li class="unBr">
<aside class="noter-pic">
<img
width="50"
height="50"
class="picImg"
src="~/assets/img/avatar-boy.gif"
/>
</aside>
<div class="of">
<section class="n-reply-wrap">
<fieldset>
<textarea
name=""
v-model="comment.content"
placeholder="输入您要评论的文字"
id="commentContent"
></textarea>
</fieldset>
<p class="of mt5 tar pl10 pr10">
<span class="fl"
><tt
class="c-red commentContentmeg"
style="display: none"
></tt
></span>
<input
type="button"
@click="addComment()"
value="回复"
class="lh-reply-btn"
/>
</p>
</section>
</div>
</li>
</ul>
</section>
<section class="">
<section class="question-list lh-bj-list pr">
<ul class="pr10">
<li v-for="comment in data.list" :key="comment.id">
<aside class="noter-pic">
<img
width="50"
height="50"
class="picImg"
:src="comment.avatar"
/>
</aside>
<div class="of">
<span class="fl">
<font class="fsize12 c-blue">{{ comment.nickname }}</font>
<font class="fsize12 c-999 ml5">评论:</font></span
>
</div>
<div class="noter-txt mt5">
<p>{{ comment.content }}</p>
</div>
<div class="of mt5">
<span class="fr"
><font class="fsize12 c-999ml5">{{
comment.gmtCreate
}}</font></span
>
</div>
</li>
</ul>
</section>
</section>
<!-- 公共分页 开始 -->
<div class="paging">
<!-- undisable这个class是否存在,取决于数据属性hasPrevious -->
<a
:class="{ undisable: !data.hasPrevious }"
href="#"
title="首页"
@click.prevent="gotoPage(1)"
>首</a
>
<a
:class="{ undisable: !data.hasPrevious }"
href="#"
title="前一页"
@click.prevent="gotoPage(data.current - 1)"
><</a
>
<a
v-for="page in data.pages"
:key="page"
:class="{
current: data.current == page,
undisable: data.current == page,
}"
:title="'第' + page + '页'"
href="#"
@click.prevent="gotoPage(page)"
>{{ page }}</a
>
<a
:class="{ undisable: !data.hasNext }"
href="#"
title="后一页"
@click.prevent="gotoPage(data.current + 1)"
>></a
>
<a
:class="{ undisable: !data.hasNext }"
href="#"
title="末页"
@click.prevent="gotoPage(data.pages)"
>末</a
>
<div class="clear" />
</div>
<!-- 公共分页 结束 -->
</div>
</div>
2、创建订单和查询订单。
其实就是课程详细中,点击购买之后跳转到订单页面。
思路以及解决方案:
①后端接口包括(1)订单信息添加,订单信息还需要通过用户id获取用户信息和根据课程id获取课程信息。然后就是要(2)查询订单信息。
②前端只需要在页面点击购买之后调用添加订单方法,路由跳转到对应页面,并且调用查询订单信息方法回显信息
OrderController
@RestController
@RequestMapping("/eduorder/order")
@CrossOrigin
public class OrderController {
@Autowired
OrderService orderService;
@PostMapping("createOrder/{courseId}")
public R createOrder(@PathVariable("courseId")String courseId, HttpServletRequest request){
//1.获取memberId
String memberId = JwtUtils.getMemberIdByJwtToken(request);
//2.创建订单,获取订单号
String orderNo=orderService.createOrder(courseId,memberId);
return R.ok().data("orderId",orderNo);
}
@GetMapping("getOrderInfo/{orderId}")
public R getOrderInfo(@PathVariable("orderId")String orderId){
QueryWrapper<Order> queryWrapper=new QueryWrapper<>();
queryWrapper.eq("order_no",orderId);
Order order = orderService.getOne(queryWrapper);
return R.ok().data("item",order);
}
}
前端课程详细
<section class="c-attr-mt">
<a
@click="createOrders()"
href="#"
title="立即观看"
class="comm-btn c-btn-3"
>立即购买</a
>
</section>
methods:
createOrders() {
orderApi.createOrder(this.courseId).then((response) => {
//生成订单并且跳转到订单页面
this.$router.push({ path: "/orders/" + response.data.data.orderId });
});
},
订单页面orders/_oid.vue
<template>
<div class="Page Confirm">
<div class="Title">
<h1 class="fl f18">订单确认</h1>
<img src="~/assets/img/cart_setp2.png" class="fr" />
<div class="clear"></div>
</div>
<form name="flowForm" id="flowForm" method="post" action="">
<table class="GoodList">
<tbody>
<tr>
<th class="name">商品</th>
<th class="price">原价</th>
<th class="priceNew">价格</th>
</tr>
</tbody>
<tbody>
<!-- <tr>
<td colspan="3" class="Title red f18 fb"><p>限时折扣</p></td>
</tr> -->
<tr>
<td colspan="3" class="teacher">讲师:{{ order.teacherName }}</td>
</tr>
<tr class="good">
<td class="name First">
<a
target="_blank"
:href="'https://localhost:3000/course/' + order.courseId"
>
<img :src="order.courseCover"
/></a>
<div class="goodInfo">
<input type="hidden" class="ids ids_14502" value="14502" />
<a
target="_blank"
:href="'https://localhost:3000/course/' + order.courseId"
>{{ order.courseTitle }}</a
>
</div>
</td>
<td class="price">
<p>
¥<strong>{{ order.totalFee }}</strong>
</p>
<!-- <span class="discName red">限时8折</span> -->
</td>
<td class="red priceNew Last">
¥<strong>{{ order.totalFee }}</strong>
</td>
</tr>
<tr>
<td class="Billing tr" colspan="3">
<div class="tr">
<p>
共 <strong class="red">1</strong> 件商品,合计<span
class="red f20"
>¥<strong>{{ order.totalFee }}</strong></span
>
</p>
</div>
</td>
</tr>
</tbody>
</table>
<div class="Finish">
<div class="fr" id="AgreeDiv">
<label for="Agree"
><p class="on">
<input type="checkbox" checked="checked" />我已阅读并同意<a
href="javascript:"
target="_blank"
>《谷粒学院购买 协议》</a
>
</p></label
>
</div>
<div class="clear"></div>
<div class="Main fl">
<div class="fl">
<a :href="'/course/' + order.courseId">返回课程详情页</a>
</div>
<div class="fr">
<p>
共 <strong class="red">1</strong> 件商品,合计<span
class="red f20"
>¥<strong id="AllPrice">{{ order.totalFee }}</strong></span
>
</p>
</div>
</div>
<input name="score" value="0" type="hidden" id="usedScore" />
<button class="fr redb" type="button" id="submitPay" @click="toPay()">
去支 付
</button>
<div class="clear"></div>
</div>
</form>
</div>
</template>
<script>
import orderApi from "@/api/order"
export default {
asyncData({params,error}){
return orderApi.getOrderInfo(params.oid)
.then(response=>{
return {
order:response.data.data.item,
}
})
}
}
</script>