【UniApp开发小程序】商品详情展示+评论、评论展示、评论点赞+商品收藏【后端基于若依管理系统开发】

news2024/12/29 11:01:45

文章目录

  • 界面效果
  • 界面实现
    • 工具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){
        // 需要将商品的收藏量+1
        productService.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 {

    @Override
    public 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 DUAL
    WHERE 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">
      SELECT
          ct.id,
          ct.user_id,
          ct.item_id,
          ct.type,
          ct.content,
          ct.create_time,
          u.nick_name AS userNickName,
          u.avatar AS userAvatar,
          CASE
              WHEN cl.user_id IS NULL THEN
                  0 ELSE 1
              END AS isLike,
          ct.LEVEL,
          COALESCE ( likeNum, 0 ) AS likeNum
      FROM
          (
              WITH RECURSIVE comment_tree AS (
                  SELECT
                      id,
                      user_id,
                      item_id,
                      type,
                      content,
                      create_time,
                      0 AS LEVEL
                  FROM
                      COMMENT
                  WHERE
                      item_id = #{productId} and type=0
                  UNION ALL
                  SELECT
                      c.id,
                      c.user_id,
                      c.item_id,
                      c.type,
                      c.content,
                      c.create_time,
                      ct.LEVEL + 1 AS LEVEL
                  FROM
                      COMMENT c
                          INNER JOIN comment_tree ct ON c.item_id = ct.id
                  WHERE
                      c.type = 1
              ) SELECT
                  *
              FROM
                  comment_tree
          ) ct
              LEFT JOIN ( SELECT comment_id, COUNT(*) AS likeNum FROM comment_like WHERE is_deleted = 0 GROUP BY comment_id ) pc ON ct.id = pc.comment_id
              LEFT JOIN sys_user AS u ON ct.user_id = u.user_id
              LEFT JOIN comment_like cl ON ct.id = cl.comment_id
              AND 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) {
        // 需要将商品的阅读量+1
        productService.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 DUAL
    WHERE NOT EXISTS (
            SELECT 1 FROM `product_read`
            WHERE `user_id` = #{productRead.userId} AND `product_id` = #{productRead.productId} limit 1
        );

</insert>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/890478.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

即拼七人拼团模式怎么玩?如何留存消费者?

如今&#xff0c;流量稀缺&#xff0c;任何流量都需要付出一定的成本&#xff0c;商家做私域亦是如此。我们能做的就是降低预算&#xff0c;探索属于自己的方法。如何进行私域引流&#xff1f; 现阶段&#xff0c;新消费品牌提升品牌力的关键就在于构建品牌与消费者之间的信任关…

大家gobigger连接后不能调亮度(亮度不能保存)解决办法

关于gobigger连接后不能调亮度&#xff0c;会不会感觉是gobigger很爽的一点&#xff1f;其实不是&#xff0c;可以通过以下方法解决。如果解决你的问题给记得点赞&#xff0c;感谢支持。 现象&#xff1a; 数据线连接后&#xff0c;用滚轮调节亮度到最高点&#xff0c;当时是很…

JavaWeb+JSP+SQL server学生学籍管理系统设计与实现(源代码+论文+开题报告+外文翻译+答辩PPT)

需求分析 本系统主要是针对各个高校的学生学籍进行管理&#xff0c;系统满足以下几点要求&#xff1a; 系统安全性。由于此系统中的操作都是由用户操作的&#xff0c;所以对于用户的权限设置比较严格。对于数据库&#xff0c;设置了不同用户的权限&#xff0c;不同权限进入不…

前端下载文件的几种方式使用Blob下载文件

前端下载文件的几种方式 使用Blob下载文件 在前端下载文件是个很通用的需求&#xff0c;一般后端会提供下载的方式有两种&#xff1a; 1.直接返回文件的网络地址&#xff08;一般用在静态文件上&#xff0c;比如图片以及各种音视频资源等&#xff09; 2.返回文件流&#xff08;…

UE5.2 LyraDemo源码阅读笔记(五)输入系统

Lyra里使用了增强输入系统&#xff0c;首先知道增强输入系统里的三个类型配置。 一、Input Actions (IA)&#xff1a; 输入操作带来的变量&#xff0c;与玩家的输入组件绑定&#xff0c;回调里驱动玩家行为。 二、InputMappingContext&#xff08;IMC&#xff09;&#xff1a…

批量删除文件名中特定文字的方法

怎么批量删除文件名中特定文字&#xff1f;作为一个上班族&#xff0c;在电脑上进行批量文件名称的修改是一个非常常见的事情。如果你有大量的图片、视频、音乐和其他文件&#xff0c;希望批量删除文件名中的特定文字&#xff0c;那么不妨看看下面的介绍&#xff0c;并尝试使用…

制定设备维护管理计划时需要考虑的不同维护策略

在现代企业运营中&#xff0c;保障关键资产的稳定运行对于实现高效生产和客户满意度至关重要。然而&#xff0c;如何制定适合企业的设备维护管理计划却是一个需要深入思考和策划的重要问题。不同类型的维护策略可以满足不同的运营需求和预算限制。在本文中&#xff0c;我们将探…

142亿亿次/秒?长安汽车与百度达成战略合作,推动智能低碳出行

8月17日&#xff0c;重庆长安汽车股份有限公司与百度正式达成战略合作协议&#xff0c;双方将在多个领域展开深度合作&#xff0c;包括云计算、人工智能、大数据和物联网。这一合作旨在推动长安汽车向智能低碳的出行科技公司转型。 据悉&#xff0c;双方还共同建立了长安汽车智…

时序数据库influxdb笔记

官方资料 https://docs.influxdata.com/influxdb/v2.7/install/?tLinux https://www.influxdata.com/influxdb/ 安装 1、linux平台下 1&#xff09;下载 2&#xff09;解压 3&#xff09;添加账户&#xff08; adduser influx&#xff09; 4&#xff09;设置目录权限 5…

NodeJs导出PDF

&#xff08;优于别人&#xff0c;并不高贵&#xff0c;真正的高贵应该是优于过去的自己。——海明威&#xff09; 场景 根据订单参数生成账单PDF 结果 示例代码 /* eslint-disable no-unused-vars */ /* eslint-disable no-undef */ /* eslint-disable complexity */ const…

忘记LockSupport怎么用了?那我们举个有趣的小例子,永远记住它!

概述 LockSupport是一个非常方便实用的线程阻塞工具&#xff0c;它可以在线程内任意位置让线程阻塞。和Thread.suspend()相比&#xff0c;它弥补了由于resume()在前发生&#xff0c;导致线程无法继续执行的情况。和Object.wait()方法相比&#xff0c;它不需要先获得某个对象的…

用easyui DataGrid编辑树形资料

easyui显示编辑树形资料有TreeGrid元件&#xff0c;但是这个元件的vue版本和react版本没有分页功能。virtual scroll功能也表现不佳。 我用DataGrid来处理。要解决的问题点&#xff1a; &#xff08;1&#xff09;如何显示成树形。即&#xff0c;子节点如何有缩进。 先计算好…

精准无误的公文材料:感谢爱校对软件

在公文处理的过程中&#xff0c;无论是机构还是企业&#xff0c;我们都追求精准无误的结果。在这个信息化、智能化不断发展的时代&#xff0c;爱校对软件以其卓越的性能和优质的服务&#xff0c;赢得了大家的广泛好评。 首先&#xff0c;爱校对软件采用了最新的自然语言处理和…

深入了解msfconsole功能详解

一、前言 正如上篇文章所述&#xff0c;刚开始接触msf&#xff0c;单纯是为了分析某些漏洞&#xff0c;然后在msf中查找相应漏洞软件版本&#xff0c;系统版本的exp便于漏洞分析&#xff0c;同时进行偶尔的exp修改&#xff0c;这就是初期对于msf的使用&#xff0c;以至于我认为…

ai写真制作让你的照片焕发异彩

最近&#xff0c;越来越多的人开始使用ai写真应用程序来美化他们的照片。这些应用程序使用人工智能技术来将人们的照片变成更有艺术感的写真照&#xff0c;是人们的照片看起来更加生动、自然。今天&#xff0c;我将通过几幅生动的ai写真照片&#xff0c;来带你深入探索ai写真ap…

高等数学教材重难点题型总结(三)微分中值定理和导数的应用

第三章&#xff0c;微分中值定理的证明题等&#xff0c;非常重要&#xff0c;需要牢牢掌握 1.证明中值定理对某函数在给定区间上的正确性 2.与中值定理有关的证明题 3.微分中值定理应用于求证不等式 4.洛必达法则求极限 5.洛必达的经典错误反例 6.按某项实现多项式幂展开 7.求带…

外卖订餐系统源码:数字化餐饮新篇章

在当今数字化时代&#xff0c;外卖订餐系统源码成为餐饮行业的一颗明星&#xff0c;为餐厅和顾客提供了无与伦比的便捷体验。在本文中&#xff0c;我们将一起探索一个简单的外卖订餐系统源码示例&#xff0c;了解它是如何将美食带到您的门口的。 # 导入所需模块 import time#…

影响力再度提升,Smartbi多次蝉联Gartner、IDC等权威认可

近期&#xff0c;思迈特软件捷报频传&#xff0c;Smartbi凭借技术创新实力和产品能力&#xff0c;成功入选Gartner中国增强数据分析代表厂商及自助分析代表厂商&#xff0c;同时&#xff0c;连续三年蝉联“IDC中国FinTech 50”榜单。 Part.1 再次被Gartner提名 Smartbi深度融…

实现动画的连续展示 JAVA

目录 1、前言&#xff1a;2、图片的展示以及自动关闭&#xff1a;3、动画的连续展示&#xff1a; 1、前言&#xff1a; 要实现动画的流畅展示需要在能展示图片的基础上对图片进行关闭&#xff0c;再切换下一张图片&#xff0c;这要关闭窗口&#xff0c;与延时函数以及while函数…

FreeModbus——移植(三)

参考自&#xff1a;手把手教你移植FreeModbus到STM32【看评论区引导&#xff0c;领取全套资料包】_freemodbus移植_HQYJ520的博客-CSDN博客 1.准备源码 1.这里用到串口进行传输&#xff0c;所以我没拷贝一个正常的串口工程&#xff08;我用的是正点原子f4库函数版本&#xff…