【UniApp开发小程序】小程序首页(展示商品、商品搜索、商品分类搜索)【后端基于若依管理系统开发】

文章目录

  • 界面效果
  • 界面实现
    • 工具js
    • 页面
      • 首页
        • 让文字只显示两行
        • 路由跳转传递对象
        • 将商品分为两列显示
        • 使用中划线划掉原价
  • 后端
    • 商品
      • controller
      • service
      • mapper
      • sql

界面效果

【说明】

  • 界面中商品的图片来源于闲鱼,若侵权请联系删除
  • 关于商品分类页面的实现,请在我的Uniapp系列文章中寻找来查看
  • 关于页面中悬浮按钮的实现,请在我的Uniapp系列文章中寻找来查看

在这里插入图片描述

在这里插入图片描述

界面实现

工具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 + "%";
			}
		});
	},
}

页面

首页

<template>
	<view class="content">
		<view style="display: flex;align-items: center;">
			<u-search placeholder="请输入商品名称" v-model="searchForm.keyword" @search="listProductVo" :showAction="false"
				:clearabled="true"></u-search>
			<text class="iconfont" style="font-size: 35px;" @click="selectCategory()">&#xe622;</text>
		</view>

		<u-row customStyle="margin-top: 10px" gutter="10" align="start" v-if="productList[0].length>0&&loadData==false">
			<u-col span="6" class="col" v-for="(data,index) in productList" :key="index">
				<view class="productVoItem" v-for="(productVo,index1) in data" :key="index1"
					@click="seeProductDetail(productVo)">
					<u--image v-if="productVo.picList!=null&&productVo.picList.length>0" :showLoading="true"
						:src="productVo.picList[0]" width="100%" :height="getAspectRatio(productVo.picList[0])"
						radius="10" mode="widthFix"></u--image>
					<!-- <u--image v-else :showLoading="true" :src="src" @click="click"></u--image> -->
					<view class="productMes">
						<text class="productName">【{{productVo.name}}】</text>
						<text>
							{{productVo.description==null?'':productVo.description}}
						</text>
					</view>
					<view style="display: flex;align-items: center;">
						<!-- 现价 -->
						<view class="price">¥<text class="number">{{productVo.price}}</text>/{{productVo.unit}}</view>
						<view style="width: 10px;"></view>
						<!-- 原价 -->
						<view class="originPrice">¥{{productVo.originalPrice}}/{{productVo.unit}}
						</view>
					</view>
					<view style="display: flex;align-items: center;">
						<u--image :src="productVo.avatar" width="20" height="20" shape="circle"></u--image>
						<view style="width: 10px;"></view>
						<view> {{productVo.nickname}}</view>
					</view>
				</view>
			</u-col>
		</u-row>
		<u-empty v-if="productList[0].length==0&&loadData==false" mode="data" texColor="#ffffff" iconSize="180"
			iconColor="#D7DEEB" text="所选择的分类没有对应的商品,请重新选择" textColor="#D7DEEB" textSize="18" marginTop="30">
		</u-empty>
		<view style="margin-top: 20px;" v-if="loadData==true">
			<u-skeleton :loading="true" :animate="true" rows="10"></u-skeleton>
		</view>

		<!-- 浮动按钮 -->
		<FloatButton @click="cellMyProduct()">
			<u--image :src="floatButtonPic" shape="circle" width="60px" height="60px"></u--image>
		</FloatButton>
	</view>
</template>

<script>
	import FloatButton from "@/components/FloatButton/FloatButton.vue";
	import {
		listProductVo
	} from "@/api/market/prodct.js";
	import pictureApi from "@/utils/picture.js";

	export default {
		components: {
			FloatButton
		},
		onShow: function() {
			let categoryNameList = uni.getStorageSync("categoryNameList");
			if (categoryNameList) {
				this.categoryNameList = categoryNameList;
				this.searchForm.productCategoryId = uni.getStorageSync("productCategoryId");
				this.searchForm.keyword = this.getCategoryLayerName(this.categoryNameList);
				uni.removeStorageSync("categoryNameList");
				uni.removeStorageSync("productCategoryId");
				this.listProductVo();
			}
		},
		data() {
			return {
				title: 'Hello',
				// 浮动按钮的图片
				floatButtonPic: require("@/static/cellLeaveUnused.png"),
				searchForm: {
					// 商品搜索关键词
					keyword: "",
					productCategoryId: undefined
				},
				productList: [
					[],
					[]
				],
				loadData: false,

			}
		},
		onLoad() {

		},
		created() {
			this.listProductVo();
		},
		methods: {
			/**
			 * 查询商品vo集合
			 */
			listProductVo() {
				this.loadData = true;
				listProductVo(this.searchForm).then(res => {
					this.loadData = false;
					// console.log("listProductVo:" + JSON.stringify(res))
					let productVoList = res.rows;
					this.productList = [
						[],
						[]
					];
					for (var i = 0; i < productVoList.length; i++) {
						if (i % 2 == 0) {
							// 第一列数据
							this.productList[0].push(productVoList[i]);
						} else {
							// 第二列数据
							this.productList[1].push(productVoList[i]);
						}
					}
				})
			},
			/**
			 * 跳转到卖闲置页面
			 */
			cellMyProduct() {
				console.log("我要卖闲置");
				uni.navigateTo({
					url: "/pages/sellMyProduct/sellMyProduct"
				})
			},
			/**
			 * 获取高宽比 乘以 100%
			 */
			getAspectRatio(url) {
				return pictureApi.getAspectRatio(url);
			},
			/**
			 * 选择分类
			 */
			selectCategory() {
				uni.navigateTo({
					url: "/pages/sellMyProduct/selectCategory"
				})
			},
			/**
			 * 获取商品名称
			 */
			getCategoryLayerName() {
				let str = '';
				for (let i = 0; i < this.categoryNameList.length - 1; i++) {
					str += this.categoryNameList[i] + '/';
				}
				return str + this.categoryNameList[this.categoryNameList.length - 1];
			},
			/**
			 * 查看商品的详情
			 */
			seeProductDetail(productVo) {
				// console.log("productVo:"+JSON.stringify(productVo))
				uni.navigateTo({
					url: "/pages/product/detail?productVo=" + encodeURIComponent(JSON.stringify(productVo))
				})
			}
		}
	}
</script>

<style lang="scss">
	.content {
		padding: 20rpx;

		.col {
			width: 50%;
		}

		.productVoItem {
			margin-bottom: 20px;

			.productMes {
				overflow: hidden;
				text-overflow: ellipsis;
				display: -webkit-box;
				/* 显示2行 */
				-webkit-line-clamp: 2;
				-webkit-box-orient: vertical;

				.productName {
					font-weight: bold;
				}
			}

			.price {
				color: #ff0000;
				font-weight: bold;

				.number {
					font-size: 22px;
				}
			}

			.originPrice {
				color: #A2A2A2;
				font-size: 15px;
				// 给文字添加中划线
				text-decoration: line-through;
			}
		}
	}
</style>

让文字只显示两行

overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
/* 显示2行 */
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;

在这里插入图片描述

路由跳转传递对象

因为首页已经查询到商品的很多信息了,点击查看商品详情的时候,很多信息不需要再查询一遍了,可以直接将商品的已知信息通过路由传递到新的页面去,需要注意的时候,将对象作为参数传递之前,需要先将对象进行编码

uni.navigateTo({
	url: "/pages/product/detail?productVo=" + encodeURIComponent(JSON.stringify(productVo))
})

将商品分为两列显示

首先将查询到的商品分为两组

let productVoList = res.rows;
this.productList = [
	[],
	[]
];
for (var i = 0; i < productVoList.length; i++) {
	if (i % 2 == 0) {
		// 第一列数据
		this.productList[0].push(productVoList[i]);
	} else {
		// 第二列数据
		this.productList[1].push(productVoList[i]);
	}
}

然后在布局中使用行列布局即可,即使用一行两列的方式来显示商品信息
在这里插入图片描述

使用中划线划掉原价

在这里插入图片描述

// 给文字添加中划线
text-decoration: line-through;

后端

商品

controller

 /**
  * 查询商品Vo列表
  */
 @PreAuthorize("@ss.hasPermi('market:product:list')")
 @PostMapping("/listProductVo")
 @ApiOperation("获取商品列表")
 public TableDataInfo listProductVo(@RequestBody ProductVo productVo) {
     startPage();
     if (productVo.getProductCategoryId() != null) {
         // --if-- 当分类不为空的时候,只按照分类来搜索
         productVo.setKeyword(null);
     }
     List<ProductVo> list = productService.selectProductVoList(productVo);
     return getDataTable(list);
 }

service

/**
 * 查询商品Vo列表
 *
 * @param productVo
 * @return
 */
@Override
public List<ProductVo> selectProductVoList(ProductVo productVo) {
//        List<ProductVo> productVoList = new ArrayList<>();
    List<ProductVo> productVoList = baseMapper.selectProductVoList(productVo);
    ///设置每个商品的图片
    // 获取所有商品的id
    List<Long> productIdList = productVoList.stream().map(item -> {
        return item.getId();
    }).collect(Collectors.toList());
    // 查询出所有商品的图片
    if (productIdList.size() > 0) {
        List<Picture> pictureList = pictureService.selectPictureListByItemIdListAndType(productIdList, PictureType.PRODUCT.getType());
        Map<Long, List<String>> itemIdAndPicList = new HashMap<>();
        for (Picture picture : pictureList) {
            if (!itemIdAndPicList.containsKey(picture.getItemId())) {
                List<String> picList = new ArrayList<>();
                picList.add(picture.getAddress());
                itemIdAndPicList.put(picture.getItemId(), picList);
            } else {
                itemIdAndPicList.get(picture.getItemId()).add(picture.getAddress());
            }
        }
        // 给每个商品设置图片
        for (ProductVo vo : productVoList) {
            vo.setPicList(itemIdAndPicList.get(vo.getId()));
        }
    }
    return productVoList;
}

mapper

void starNumDiffOne(@Param("productId") Long productId);

sql

  <select id="selectProductVoList" parameterType="ProductVo" resultMap="ProductVoResult">
      SELECT
      p.id,
      p.NAME,
      p.description,
      p.original_price,
      p.price,
      p.product_category_id,
      pc.NAME AS productCategoryName,
      p.user_id,
      u.user_name as username,
      u.nick_name as nickname,
      u.avatar as avatar,
      p.reviewer_id,
      u1.user_name as reviewerUserName,
      p.fineness,
      p.unit,
      p.STATUS,
      p.is_contribute,
      p.functional_status,
      p.brand_id,
      b.NAME AS brandName
      FROM
      product AS p
      LEFT JOIN product_category AS pc ON p.product_category_id = pc.id
      LEFT JOIN brand AS b ON p.brand_id = b.id
      LEFT JOIN sys_user AS u ON p.user_id = u.user_id
      LEFT JOIN sys_user AS u1 ON p.reviewer_id = u1.user_id
      <where>
          <if test="keyword != null  and keyword != ''">and p.name like concat('%', #{keyword}, '%')</if>
          <if test="keyword != null  and keyword != ''">or p.description like concat('%', #{keyword}, '%')</if>
          <if test="productCategoryId != null  and productCategoryId != ''">and p.product_category_id =
              #{productCategoryId}
          </if>
      </where>
  </select>

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于 ObjectOutputStream 实现 对象与二进制数据 的序列化和反序列化

目录 为什么要进行序列化呢&#xff1f; 如何实现 对象与二进制数据 的序列化和反序列化&#xff1f; 为什么要进行序列化呢&#xff1f; 主要是为了把一个对象&#xff08;结构化的数据&#xff09;转化成一个 字符串 / 字节数组&#xff0c;方便我们存储&#xff08;有时候需…

AWS——03篇(AWS之Amazon S3(云中可扩展存储)-01入门)

AWS——03篇&#xff08;AWS之Amazon S3&#xff08;云中可扩展存储&#xff09;-01入门&#xff09; 1. 前言2. 关于 Amazon S32.1 介绍2.1.1 简述2.1.2 详细介绍 2.2 Amazon S3 好处和功能2.3 3. 创建S3存储桶3.1 创建存储桶3.2 修改访问权限 4. 简单实用4.1 上传图片文件4.2…

海量数据迁移,亚马逊云科技云数据库服务为大库治理提供新思路

1.背景 目前&#xff0c;文档型数据库由于灵活的schema和接近关系型数据库的访问特点&#xff0c;被广泛应用&#xff0c;尤其是游戏、互联网金融等行业的客户使用MongoDB构建了大量应用程序&#xff0c;比如游戏客户用来处理玩家的属性信息&#xff1b;又如股票APP用来存储与时…

SpringBoot复习:(44)MyBatisAutoConfiguration

可以看到MyBatisAutoConfiguration引入了MyBatisProperties这个属性&#xff1a; MyBatisAutoConfiguration中配置了一个SqlSessionFactoryBean,代码如下&#xff1a; 可以配置mybatis-config.xml,需要配置文件里指定&#xff1a; mybatis.config-locationclasspath:/mybat…

【环境配置】Windows 10 安装 PyTorch 开发环境,以及验证 YOLOv8

Windows 10 安装 PyTorch 开发环境&#xff0c;以及验证 YOLOv8 最近搞了一台Windows机器&#xff0c;准备在上面安装深度学习的开发环境&#xff0c;并搭建部署YOLOv8做训练和测试使用&#xff1b; 环境&#xff1a; OS&#xff1a; Windows 10 显卡&#xff1a; RTX 3090 安…

笔记04:全局内存

一、CUDA内存模型概述 寄存器、共享内存、本地内存、常量内存、纹理内存和全局内存 一个核函数中的线程都有自己私有的本地内存。 一个线程块有自己的共享内存&#xff0c;对同一个线程块中所有的线程都可见&#xff0c;其内容持续线程块的整个生命周期。 所有线程都可以访问…

【LeetCode动态规划#】完全背包问题实战(单词拆分,涉及集合处理字符串)

单词拆分 给定一个非空字符串 s 和一个包含非空单词的列表 wordDict&#xff0c;判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。 说明&#xff1a; 拆分时可以重复使用字典中的单词。 你可以假设字典中没有重复的单词。 示例 1&#xff1a; 输入: s "l…

手把手教你 Vue3 + vite + Echarts 5 +TS 绘制中国地图,看完就会

废话不多说&#xff0c;看图&#xff01; 本篇文章介绍 Vue3 vite TS 项目内使用 Echarts 5 绘制中国地图&#xff0c;标记分布点&#xff01;之前没有接触过 Echarts 的&#xff0c;可以先去官方示例看看&#xff0c;里面图形特别齐全。但是官方文档看着费劲的&#xff0c;太…

铁是地球科学争论的核心

一项新的研究调查了地球内部铁的形态。这些发现对理解内核的结构产生了影响。 一项新的研究探索了地球内核的铁结构&#xff0c;如图中的黄色和白色所示。 资料来源&#xff1a;地球物理研究快报 地球内核以铁为主&#xff0c;铁可以多种晶体形式作为固体材料存在。&#xff08…

html css实现爱心

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><style>/* 爱心 */.lo…

JVM 内存结构快速入门

文章目录 一、简介二、JVM内存区域2.1 方法区2.3.2 永久代和元空间 2.2 堆2.1.2 对象的创建和销毁 2.2 栈内存2.2.1 栈帧的组成和作用2.2.2 栈的特点 2.4 程序计数器2.4.1 程序计数器的作用和使用场景 一、简介 Java 内存模型&#xff08;Java Memory Model&#xff0c;JMM&…

docker发展历史

docker 一、docker发展历史很久以前2013年2014年2015年2016年2017年2018年2019年及未来 二、 docker概述定义&#xff1a;docker底层运行原理:docker简述核心概念容器特点Docker与虚拟机的区别: 三、容器在内核中支持两种重要技术四、namespace的六项隔离五、虚拟化产品有哪些1…

CTFshow 限时活动 红包挑战7、红包挑战8

CTFshow红包挑战7 写不出来一点&#xff0c;还是等了官方wp之后才复现。 直接给了源码 <?php highlight_file(__FILE__); error_reporting(2);extract($_GET); ini_set($name,$value);system("ls ".filter($_GET[1])."" );function filter($cmd){$cmd…

《C语言深度解剖》.pdf

&#x1f407; &#x1f525;博客主页&#xff1a; 云曦 &#x1f4cb;系列专栏&#xff1a;深入理解C语言 &#x1f4a8;吾生也有涯&#xff0c;而知也无涯 &#x1f49b; 感谢大家&#x1f44d;点赞 &#x1f60b;关注&#x1f4dd;评论 C语言深度解剖.pdf 提取码:yunx

收银一体化-亿发2023智慧门店新零售营销策略,实现全渠道运营

伴随着互联网电商行业的兴起&#xff0c;以及用户理念的改变&#xff0c;大量用户从线下涌入线上&#xff0c;传统的线下门店人流量急剧收缩&#xff0c;门店升级几乎成为了每一个零售企业的发展之路。智慧门店新零售收银解决方案是针对传统零售企业面临的诸多挑战和问题&#…

S7-200 Smart 的多种端口及通讯方式

每个S7-200 SMART CPU都提供一个以太网端口和一个RS485端口(端口0)&#xff0c;标准型CPU额外支持SB CM01信号板(端口1)&#xff0c;信号板可通过STEP 7-Micro/WIN SMART软件组态为RS232通信端口或RS485通信端口。 CPU 通信端口引脚分配 1.S7-200 SMART CPU 集成的 RS485 通信…

vant金额输入框

1.在components中新建文件夹currency&#xff0c;新建index.js import Currency from ./src/currency.vueCurrency.install function (Vue) {Vue.component(Currency.name, Currency) }export default Currency 2.在currency中新建文件夹src&#xff0c;在src中间currency.v…

接口测试及接口抓包常用的测试工具

接口 接口测试是测试系统组件间接口的一种测试。接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。测试的重点是要检查数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及系统间的相互逻辑依赖关系等。 接口测试的重要性 是节省时间前后端不…

SpringCloud微服务之间如何进行用户信息传递(涉及:Gateway、OpenFeign组件)

目录 1、想达到的效果2、用户信息在微服务之间传递的两种途径3、用RuoYi-Cloud为例进行演示说明&#xff08;1&#xff09;网关将用户信息写在请求头中&#xff08;2&#xff09;业务微服务之间通过OpenFeign进行调用&#xff0c;并且将用户信息写在OpenFeign准备的请求头中&am…

Python 基础教程,Python 是什么?

Python 的诞生是极具戏曲性的&#xff0c;据 Guido 自述记载&#xff0c;Python 语言是在圣诞节期间为了打发无聊的时间而开发的&#xff0c;之所以会选择 Python 作为该编程语言的名字&#xff0c;是因为 Guido 是 Monty Python 戏剧团的忠实粉丝。 Python 语言是在 ABC 语言的…