当前位置: 首页 > news >正文

汕头网站推广优化益阳市建设局网站

汕头网站推广优化,益阳市建设局网站,南宁手机平台网站建设,蓝莓直播视频文章目录 界面效果界面实现工具js页面日期格式化 后端收藏ControllerServicemapper 评论ControllerServiceMapper 商品Controller 阅读Service 界面效果 【说明】 界面中商品的图片来源于闲鱼,若侵权请联系删除 【商品详情】 【评论】 界面实现 工具js 该工…

文章目录

  • 界面效果
  • 界面实现
    • 工具js
    • 页面
      • 日期格式化
  • 后端
    • 收藏
      • Controller
      • Service
      • mapper
    • 评论
      • Controller
      • Service
      • Mapper
    • 商品
      • Controller
    • 阅读
      • Service

界面效果

【说明】

  • 界面中商品的图片来源于闲鱼,若侵权请联系删除

【商品详情】
在这里插入图片描述

【评论】
在这里插入图片描述

界面实现

工具js

该工具类的作用是,给定一个图片的url地址,计算出图片的高宽比,计算高宽比的作用是让图片可以按照正常比例显示

/*** 获取uuid*/
export default {/*** 获取高宽比 乘以 100%*/getAspectRatio(url) {uni.getImageInfo({src: url,success: function(res) {let aspectRatio = res.height * 100.0 / res.width;// console.log("aspectRatio:" + aspectRatio);return aspectRatio + "%";}});},
}
export default {/*** 日期格式化*/formatDateToString(date) {return new Date(date).toLocaleString();},
}

页面

<template><view class="container"><u-toast ref="uToast"></u-toast><view class="userItem"><view class="userProfile"><u--image :src="productVo.avatar" width="35" height="35" shape="circle"></u--image><view style="width: 10px;"></view><view><view class="nickname">{{productVo.nickname}}</view><view class="other">10分钟前来过 广东工业大学大学城校区</view></view></view><view class="follow" @click="follow" v-if="hadFollow==false"><view><u-icon name="plus" color="#ffffff" style="font-weight: bold;" size="15"></u-icon></view><view style="margin-left: 10rpx;font-size: 15px;">关 注</view></view><view class="followed" @click="cancelFollow" v-else><view style="font-size: 15px;color: #C2C2C2;">已 关 注</view></view></view><view class="productItem"><view class="top"><view class="price">¥<text class="number">{{productVo.price}}</text>/{{productVo.unit}}</view><view class="browseInformation">{{product.starNum}}人想要 | {{product.readNum}}个浏览</view></view><view class="productDetail">{{productVo.description}}</view><u--image :showLoading="true" v-for="(pic,index) in productVo.picList" :src="pic" width="100%":height="getAspectRatio(pic)" radius="10" mode="widthFix"></u--image></view><view class="commentView"><view style="color: #3D3D3D;">{{commentNum}}条评论</view><view v-for="(commentItem,index) in commentVoList"><view class="commentItem"><view style="display: flex;"><u--image :src="commentItem.userAvatar" width="30" height="30" shape="circle"></u--image><view style="width: 10px;"></view><view @click="clickShowBottomPopup(1, commentItem.id,commentItem.userNickName)"><view class="nickname">{{commentItem.userNickName}}</view><view class="content">{{commentItem.content}}</view><view class="dateAndPosition">{{formatDateToString(commentItem.createTime)}}</view></view></view><view style="display: inline-block;text-align: center;"><u-icon name="thumb-up" size="28" @click="likeComment(commentItem.id,commentItem)"v-if="commentItem.isLike==0"></u-icon><u-icon name="thumb-up-fill" color="#2B92FF" size="28"@click="cancelLikeComment(commentItem.id,commentItem)" v-else></u-icon><view style="font-size: 12px;color: #B9B9B9;">{{commentItem.likeNum}}</view></view></view><view class="sonCommentItem" v-for="(commentItem1,index1) in commentItem.children"><view style="display: flex;"><u--image :src="commentItem1.userAvatar" width="30" height="30" shape="circle"></u--image><view style="width: 10px;"></view><view @click="clickShowBottomPopup(1, commentItem1.id,commentItem1.userNickName)"><view class="nickname">{{commentItem1.userNickName}}</view><view class="content"><text style="font-size: 14px;">回复了<text style="color:#B9B9B9 ;">{{commentItem1.toUserNickName}}</text></text><text>{{ commentItem1.content }}</text></view><view class="dateAndPosition">{{formatDateToString(commentItem1.createTime)}}</view></view></view><view style="display: inline-block;text-align: center;"><u-icon name="thumb-up" size="28" @click="likeComment(commentItem1.id,commentItem1)"v-if="commentItem1.isLike==0"></u-icon><u-icon name="thumb-up-fill" color="#2B92FF" size="28"@click="cancelLikeComment(commentItem1.id, commentItem1)" v-else></u-icon><view style="font-size: 12px;color: #B9B9B9;">{{commentItem1.likeNum}}</view></view></view></view></view><view class="footer"><view><view class="item" @click="clickShowBottomPopup(0, productVo.id,)"><u-icon name="chat" size="28"></u-icon><view class="comment">评论</view></view><view class="item" @click="starProduct()" v-if="hadStar==false"><u-icon name="star" size="28"></u-icon><view class="comment">我想要</view></view><view class="item" @click="cancelStar()" v-if="hadStar==true"><u-icon name="star-fill" color="#2B92FF" size="28"></u-icon><view class="comment" style="color: #2B92FF">已收藏</view></view></view><view class="chat"><u-icon name="chat" color="#ffffff" size="18"></u-icon><view style="width: 5px;"></view>私 聊</view></view><!-- 底部弹出框:用于输入评论 --><!-- @close="this.showBottomPopup=false" 点击遮罩层关闭弹框  --><u-popup :show="showBottomPopup" mode="bottom" :round="10" @close="this.showBottomPopup=false"><view class="commentPopup"><u--textarea v-model="comment.content" :placeholder="commentPlaceHolder" autoHeight height="200"border="surround"></u--textarea><view class="commentButton" @click="commitComment()"><u-icon name="chat" color="#ffffff" size="18"></u-icon><view style="width: 5px;"></view>评 论</view></view></u-popup></view>
</template><script>import pictureApi from "@/utils/picture.js";import {addFollow,hadFollowSomeone,cancelFollowSomeone} from "@/api/market/follow.js";import {starProduct,cancelStar,hadStar} from "@/api/market/star.js";import {addComment,listCommentVoOfProduct} from "@/api/market/comment.js";import dateUtil from "@/utils/date.js";import {likeComment,cancelLikeComment} from "@/api/market/commentLike.js"import {getProduct} from "@/api/market/prodct.js"export default {data() {return {productVo: {},product: {},// 是否已经关注商品主人hadFollow: false,// 是否已经收藏商品hadStar: false,// 是否显示底部弹出框showBottomPopup: false,// 评论comment: {itemId: undefined,type: undefined,content: '',isTop: 0},// 存储商品对应的评论集合commentVoList: [],// 评论数量commentNum: undefined,commentPlaceHolder: "",}},methods: {/*** 获取高宽比 乘以 100%*/getAspectRatio(url) {// uni.getImageInfo({// 	src: url,// 	success: function(res) {// 		let aspectRatio = res.height * 100.0 / res.width;// 		// console.log("aspectRatio:" + aspectRatio);// 		return aspectRatio + "%";// 	}// });return pictureApi.getAspectRatio(url);},/*** 关注用户*/follow() {let data = {followedId: this.productVo.userId}addFollow(data).then(res => {this.hadFollow = true;this.$refs.uToast.show({type: 'success',message: "关注成功",duration: 300})}).catch(err => {this.$refs.uToast.show({type: 'error',message: err.msg,duration: 300})})},/*** 取消关注*/cancelFollow() {cancelFollowSomeone(this.productVo.userId).then(res => {this.hadFollow = false;this.$refs.uToast.show({type: 'success',message: "取消关注成功",duration: 300})})},/*** 查询是否已经关注了用户*/searchWhetherFollow() {hadFollowSomeone(this.productVo.userId).then(res => {// console.log("res:" + JSON.stringify(res));this.hadFollow = res.hadFollow;// console.log("this.hadFollow :" + this.hadFollow);})},/*** 收藏商品*/starProduct() {starProduct(this.productVo.id).then(res => {this.hadStar = true;this.getProduct();this.$refs.uToast.show({type: 'success',message: "收藏成功",duration: 300})})},/*** 取消收藏*/cancelStar() {cancelStar(this.productVo.id).then(res => {this.hadStar = false;this.getProduct();this.$refs.uToast.show({type: 'success',message: "取消收藏成功",duration: 300})})},/*** 点赞评论*/likeComment(commentId, comment) {// console.log("comment:" + JSON.stringify(comment))likeComment(commentId).then(res => {comment.isLike = 1;comment.likeNum += 1;this.$refs.uToast.show({type: 'success',message: "点赞成功",duration: 300})})},/*** 取消点赞评论*/cancelLikeComment(commentId, comment) {cancelLikeComment(commentId).then(res => {comment.isLike = 0;comment.likeNum -= 1;this.$refs.uToast.show({type: 'success',message: "取消点赞成功",duration: 300})})},/*** 查询是否已经关注了用户*/searchWhetherStar() {hadStar(this.productVo.id).then(res => {// console.log("res:" + JSON.stringify(res));this.hadStar = res.hadStar;// console.log("this.hadFollow :" + this.hadFollow);})},/*** 显示底部弹出框*/clickShowBottomPopup(type, itemId, username = undefined) {this.showBottomPopup = true;this.comment.type = type;this.comment.itemId = itemId;if (type == 0) {this.commentPlaceHolder = "想要了解更多信息,可以评论让商品主人看见哟";} else {this.commentPlaceHolder = "正在回复" + username + "";}},/*** 发表评论*/commitComment() {// console.log("发送评论,comment:" + JSON.stringify(this.comment))addComment(this.comment).then(res => {this.showBottomPopup = false;this.comment.content = '';this.listCommentVoOfProduct();this.$refs.uToast.show({type: 'success',message: "评论发送成功",duration: 300})})},/*** 获取商品对应的所有评论*/listCommentVoOfProduct() {listCommentVoOfProduct(this.productVo.id).then(res => {// console.log("listCommentVoOfProduct:" + JSON.stringify(res));this.commentVoList = res.tree;this.commentNum = res.commentNum;})},/*** 格式化日期* @param {Object} date*/formatDateToString(dateStr) {let date = new Date(dateStr);// 月份需要加一return date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();},/*** 获取商品详细信息,同时增加阅读量*/getProduct() {getProduct(this.productVo.id).then(res => {console.log("product:" + JSON.stringify(res.data));this.product = res.data;})}},onLoad(e) {this.productVo = JSON.parse(decodeURIComponent(e.productVo));this.searchWhetherFollow();this.searchWhetherStar();this.listCommentVoOfProduct();this.getProduct();// console.log("productVo:" + JSON.stringify(productVo));}}
</script><style lang="scss">.container {// padding: 20rpx;background: #F7F7F7;.userItem {display: flex;align-items: center;justify-content: space-between;background: #ffffff;padding: 20rpx;.userProfile {display: flex;.nickname {color: #202020;font-weight: bold;font-size: 14px;}.other {color: #A6A4A5;font-size: 11px;}}.follow {display: flex;align-items: center;font-weight: bold;color: #ffffff;background: #2B92FF;border-radius: 20px;padding: 4px 8px;}.followed {background: #F6F6F6;border-radius: 20px;padding: 4px 8px;}}.productItem {background: #ffffff;padding: 20rpx;.top {display: flex;align-items: center;justify-content: space-between;.price {color: #F84442;font-weight: bold;.number {font-size: 30px;}}.browseInformation {color: #A6A4A5;font-size: 14px;}}.productDetail {margin-top: 20rpx;margin-bottom: 10rpx;color: #4C4C4C;font-size: 15px;line-height: 30px;font-weight: bold;}}.commentView {margin-top: 10px;// 用来预留展示 footer 的高度,不然footer会挡住评论margin-bottom: calc(60px + 10rpx);background: #ffffff;padding: 30rpx 30rpx;.nickname {font-size: 14px;color: #B9B9B9;}.content {margin: 5px;// 解决英文字符串、数字不换行的问题word-break: break-all;word-wrap: break-word;}.dateAndPosition {font-size: 11px;color: #B9B9B9;}.commentItem {display: flex;margin: 10px;justify-content: space-between;}.sonCommentItem {display: flex;margin: 10px 10px 10px 50px;justify-content: space-between;}}.footer {padding: 20rpx;position: fixed;// right: 20rpx;bottom: 0rpx;background: #ffffff;height: 60px;width: 710rpx;padding-top: 2px;display: flex;align-items: center;justify-content: space-between;.item {display: inline-block;text-align: center;margin-right: 10px;.comment {font-size: 10px;}}.chat {display: flex;align-items: center;background-color: #2B92FF;border-radius: 20px;padding: 7px;color: #ffffff;// margin-right: 20px;font-size: 12px;}}.commentPopup {display: flex;padding: 10px;min-height: 200rpx;.commentButton {background-color: #2B92FF;border-radius: 5px;padding: 7px;color: #ffffff;font-size: 12px;height: 20px;display: flex;align-items: center;}}}
</style>

日期格式化

有时候后端传递过来的日期格式直接在前端页面中展示不太美观或简洁,那就可以自己写一个日期格式化方法,将日期转化为我们需要的格式来显示

/*** 格式化日期* @param {Object} date*/
formatDateToString(dateStr) {let date = new Date(dateStr);// 月份需要加一return date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
},

后端

收藏

Controller

为了便于商品数据的查询,我在数据库设计的时候给商品表增加了收藏数的冗余字段,因此每次收藏商品或者取消商品的收藏的同时,需要更新商品表的收藏数

在这里插入图片描述

/*** 收藏商品*/
@PreAuthorize("@ss.hasPermi('market:star:star')")
@GetMapping("/starProduct/{productId}")
public AjaxResult starProduct(@PathVariable("productId") Long productId) {Star star = new Star();star.setUserId(getLoginUser().getUserId());star.setProductId(productId);boolean isStar = starService.addStar(star);if (isStar){// 需要将商品的收藏量+1productService.starNumPlusOne(productId);}return AjaxResult.success();
}

Service

package com.shm.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.domain.entity.Star;
import com.shm.mapper.StarMapper;
import com.shm.service.IStarService;
import org.springframework.stereotype.Service;/**
* @author dam
* @description 针对表【collection(收藏表)】的数据库操作Service实现
* @createDate 2023-08-09 19:41:23
*/
@Service
public class IStarServiceImpl extends ServiceImpl<StarMapper, Star>implements IStarService {@Overridepublic boolean addStar(Star star) {return baseMapper.addStar(star);}
}

mapper

public interface StarMapper extends BaseMapper<Star> {boolean addStar(@Param("star") Star star);
}

将商品添加收藏的时候,需要先判断同样的收藏数据不存在于数据库中才执行插入操作,否则如果用户网络卡顿并多次发送收藏请求,数据库会出现冗余的脏数据

<insert id="addStar">INSERT INTO `star` (`user_id`, `product_id`)SELECT #{star.userId},#{star.productId} FROM DUALWHERE NOT EXISTS (SELECT 1 FROM `star`WHERE `user_id` = #{star.productId} AND `product_id` = #{star.productId} limit 1);
</insert>

评论

Controller

/*** 获取商品对应的所有评论** @param productId* @return*/
@PreAuthorize("@ss.hasPermi('market:comment:list')")
@GetMapping("/listCommentVoOfProduct/{productId}")
public AjaxResult listCommentVoOfProduct(@PathVariable("productId") Long productId) {// 查询出商品对应的所有评论数据List<CommentVo> commentVoList = commentService.listCommentVoOfProduct(productId, getLoginUser().getUserId());int commentNum = commentVoList.size();// 将评论数据封装成树形结构List<CommentVo> tree = commentService.buildTree(commentVoList);return AjaxResult.success().put("tree", tree).put("commentNum", commentNum);
}

Service

需要注意的是,这里的树形结构只有两层数据(针对商品的评论为一层,针对评论的所有评论为一层),因为小程序不方便显示太多层数据,否则宽度会非常大,用户需要反复滑动来查看完整的评论
在这里插入图片描述

在这里插入图片描述

@Override
public List<CommentVo> listCommentVoOfProduct(Long productId, Long userId) {return commentMapper.listCommentVoOfProduct(productId, userId);
}/*** 将评论数据封装成树形结构** @param commentVoList* @return*/
@Override
public List<CommentVo> buildTree(List<CommentVo> commentVoList) {// 将所有父级评论过滤出来List<CommentVo> fatherList = commentVoList.stream().filter((item) -> {return item.getType() == 0;}).collect(Collectors.toList());commentVoList.removeAll(fatherList);// 为所有父级评论寻找孩子for (CommentVo father : fatherList) {father.setChildren(new ArrayList<>());this.searchSon(father.getId(), father.getUserNickName(), father.getChildren(), commentVoList);}return fatherList;
}/*** 寻找孩子** @param fatherId* @param children* @param commentVoList*/
private void searchSon(Long fatherId, String fatherNickName, List<CommentVo> children, List<CommentVo> commentVoList) {for (CommentVo commentVo : commentVoList) {if (commentVo.getItemId().equals(fatherId)) {commentVo.setToUserNickName(fatherNickName);children.add(commentVo);this.searchSon(commentVo.getId(), commentVo.getUserNickName(), children, commentVoList);}}
}

Mapper

这段sql非常复杂,一次性将评论的主人昵称、头像、评论的点赞数量查出来了,同时还使用递归查询来不断查询出评论的子评论。我目前不能保证这段sql的效率,只是实现了功能,后面如果性能不足,我再想办法优化

<select id="listCommentVoOfProduct" resultType="com.ruoyi.common.core.domain.vo.CommentVo">SELECTct.id,ct.user_id,ct.item_id,ct.type,ct.content,ct.create_time,u.nick_name AS userNickName,u.avatar AS userAvatar,CASEWHEN cl.user_id IS NULL THEN0 ELSE 1END AS isLike,ct.LEVEL,COALESCE ( likeNum, 0 ) AS likeNumFROM(WITH RECURSIVE comment_tree AS (SELECTid,user_id,item_id,type,content,create_time,0 AS LEVELFROMCOMMENTWHEREitem_id = #{productId} and type=0UNION ALLSELECTc.id,c.user_id,c.item_id,c.type,c.content,c.create_time,ct.LEVEL + 1 AS LEVELFROMCOMMENT cINNER JOIN comment_tree ct ON c.item_id = ct.idWHEREc.type = 1) SELECT*FROMcomment_tree) ctLEFT JOIN ( SELECT comment_id, COUNT(*) AS likeNum FROM comment_like WHERE is_deleted = 0 GROUP BY comment_id ) pc ON ct.id = pc.comment_idLEFT JOIN sys_user AS u ON ct.user_id = u.user_idLEFT JOIN comment_like cl ON ct.id = cl.comment_idAND cl.user_id = #{userId} and cl.is_deleted =0</select>

商品

Controller

/*** 获取商品详细信息*/
@PreAuthorize("@ss.hasPermi('market:product:query')")
@GetMapping(value = "/{id}")
@Transactional // 同时处理多个表,添加事务
public AjaxResult getInfo(@PathVariable("id") Long id) {// 首先判断用户有没有阅读该商品boolean isAdd = productReadService.addRead(new ProductRead(getLoginUser().getUserId(), id));if (isAdd) {// 需要将商品的阅读量+1productService.readNumPlusOne(id);}return success(productService.getById(id));
}

阅读

Service

<insert id="addRead">INSERT INTO `product_read` (`user_id`, `product_id`)SELECT #{productRead.userId},#{productRead.productId} FROM DUALWHERE NOT EXISTS (SELECT 1 FROM `product_read`WHERE `user_id` = #{productRead.userId} AND `product_id` = #{productRead.productId} limit 1);</insert>
http://www.yayakq.cn/news/967903/

相关文章:

  • 河南天元建设公司网站新兴街做网站公司
  • 广西住房建设厅网站wordpress站群seo
  • 学校网站做等级保护个人做百度云下载网站吗
  • 怎么制作网站上传婚庆公司包含哪些项目
  • 佛山网站策划哪家专业软文广告案例分析
  • 做英语四级题的网站厦门seo网站建设费用
  • 网站开发华企云商阿里云服务器 做网站
  • 站长工具 seo查询医院seo是什么
  • 知名网站建设推广wordpress jitpecj插件
  • 简易购物网站前端模板1天学会搭建营销网站
  • 广州网站设计服务商免费创意字体设计
  • 大连中小网站建设公司做任务 网站
  • 局域网网站凡客科技有限公司
  • c语言网站建设南昌定制网站开发
  • 个人网站备案icp餐馆网站怎么做
  • 重庆市建设厅网站东营招标建设信息网
  • 怎样建设营销型网站课堂网站开发
  • 龙岩网站制作教程在线教育网站有什么程序做
  • 网站与云平台区别吗青岛的网站设计
  • 哈尔滨门户网站制作哪家好织梦与wordpress seo哪个好
  • 福建建设执业注册管理中心网站江西省城乡建设厅网站证件查询
  • 上海大型网站品牌网站建设 1蝌蚪小
  • dede修改网站密码在百度上做网站推广怎么弄
  • 长春网站推广优化深圳建设工程信息网站
  • 山东企业网站建设报价国家企业信息管理系统
  • 自己网站做短链接wordpress 主题详解
  • 如何判断一个网站是php还是asp自己的电脑做服务器搭建网站
  • 网站新闻详细页面设计网站建设的价值体现在哪
  • 福建省建设工程资格中心网站wordpress 按标题搜索
  • 网站建设作业教程收费网站方案