欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 文化 > 帝可得-商品管理

帝可得-商品管理

2025/6/6 18:46:57 来源:https://blog.csdn.net/m0_45253972/article/details/144303594  浏览:    关键词:帝可得-商品管理

商品管理

需求说明

商品管理主要涉及到三个功能模块,业务流程如下:

  1. 新增商品类型: 定义商品的不同分类,如饮料、零食、日用品等。
  2. 新增商品: 添加新的商品信息,包括名称、规格、价格、类型等。
  3. 设备货道管理: 将商品与售货机的货道关联,管理每个货道的商品信息。
登录系统
新增商品类型
新增商品
货道关联商品

对于商品和其他管理数据,下面是示意图:

  • 关系字段:class_id、sku_id、vm_id

在这里插入图片描述

生成基础代码

需求

使用若依代码生成器,生成商品类型、商品管理前后端基础代码,并导入到项目中:
在这里插入图片描述

步骤

创建目录菜单

创建商品管理目录菜单

在这里插入图片描述

配置代码生成信息

导入二张表

在这里插入图片描述

配置商品类型表(参考原型)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

配置商品表(参考原型)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

下载代码并导入项目

选中商品表和商品类型表生成下载

在这里插入图片描述

解压ruoyi.zip得到前后端代码和动态菜单sql

在这里插入图片描述

代码导入

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

商品类型改造

基础页面

需求

参考页面原型,完成基础布局展示改造

在这里插入图片描述

列表显示改造

在skuClass/index.vue视图组件中修改

<el-table v-loading="loading" :data="skuClassList" @selection-change="handleSelectionChange"><!-- <el-table-column type="selection" width="55" align="center" /> --><el-table-column label="序号" align="center" prop="classId" /><el-table-column label="商品类型" align="center" prop="className" /><!-- 创建日期 --><el-table-column label="创建日期" align="center" prop="createTime" width="180" /><el-table-column label="操作" align="center" class-name="small-padding fixed-width"><template #default="scope"><el-button link type="primary" @click="handleUpdate(scope.row)" v-hasPermi="['manage:skuClass:edit']">修改</el-button><el-button link type="primary" @click="handleDelete(scope.row)" v-hasPermi="['manage:skuClass:remove']">删除</el-button></template></el-table-column></el-table>

原来的商品类型表中没有create_time和update_time字段需要手动添加,并在xml中返回查询创建时间。

SkuClassMapper.xml

    <sql id="selectSkuClassVo">select class_id, class_name, parent_id,create_time, update_time from tb_sku_class</sql><select id="selectSkuClassList" parameterType="SkuClass" resultMap="SkuClassResult"><include refid="selectSkuClassVo"/><where>  <if test="className != null  and className != ''"> and class_name like concat('%', #{className}, '%')</if></where></select>

在这里插入图片描述

对话框改造

在这里插入图片描述

商品管理中的商品与商品类型存在外键约束,不能删除有关联的商品类型,所以要设置一个全局异常处理器,拦截这些异常并返回前端能理解的提示。同时当添加已存在的数据时,返回的是违反数据完整性约束,需要指定该异常信息为无法保存名称已存在

在这里插入图片描述

修改全局异常处理器,添加以下内容

在这里插入图片描述

/*** 数据完整性异常*/
@ExceptionHandler(DataIntegrityViolationException.class)
public AjaxResult handelDataIntegrityViolationException(DataIntegrityViolationException e) {if (e.getMessage().contains("foreign")) {return AjaxResult.error("无法删除,有其他数据引用");}if(e.getMessage().contains("Duplicate")){return AjaxResult.error("无法保存,名称已存在");}return AjaxResult.error("数据完整性异常,请联系管理员");
}

在这里插入图片描述

在这里插入图片描述

商品管理改造

基础页面

需求

参考页面原型,完成基础布局展示改造

在这里插入图片描述

搜索区域改造

代码实现
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px"><el-form-item label="商品搜索" prop="skuName"><el-inputv-model="queryParams.skuName"placeholder="请输入"clearable@keyup.enter="handleQuery"/></el-form-item><el-form-item><el-button type="primary" @click="handleQuery">查询</el-button><!-- <el-button icon="Refresh" @click="resetQuery">重置</el-button> --></el-form-item></el-form><el-row :gutter="10" class="mb8"><el-col :span="1.5"><el-buttontype="primary"@click="handleAdd"v-hasPermi="['manage:sku:add']">新增</el-button></el-col><!-- 后续修改实现方法 --><el-col :span="1.5"><el-buttontype="primary"@click="handleExport"v-hasPermi="['manage:sku:export']">导入</el-button></el-col><right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar></el-row>

在这里插入图片描述

列表显示改造

在sku/index.vue视图组件中修改

代码实现

商品类型展示的应该是商品的类型名,而不是商品类型id。

    <el-table v-loading="loading" :data="skuList" @selection-change="handleSelectionChange"><el-table-column label="商品编号" align="center" prop="skuId" /><el-table-column label="商品名称" align="center" prop="skuName" /><el-table-column label="商品图片" align="center" prop="skuImage" width="100"><template #default="scope"><image-preview :src="scope.row.skuImage" :width="50" :height="50"/></template></el-table-column><el-table-column label="品牌" align="center" prop="brandName" /><el-table-column label="规格" align="center" prop="unit" /><el-table-column label="商品价格" align="center" prop="price" /></el-table-column><el-table-column label="商品类型" align="center" prop="classId" ><template #default="scope"><div v-for="item in skuClassList" :key="item.classId"><span v-if="item.classId == scope.row.classId">{{ item.className }}</span></div></template></el-table-column><el-table-column label="创建日期" align="center" prop="createTime" width="180"><template #default="scope"><span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span></template></el-table-column><el-table-column label="操作" align="center" class-name="small-padding fixed-width"><template #default="scope"><el-button link type="primary" @click="handleUpdate(scope.row)" v-hasPermi="['manage:sku:edit']">修改</el-button><el-button link type="primary" @click="handleDelete(scope.row)" v-hasPermi="['manage:sku:remove']">删除</el-button></template></el-table-column></el-table>import { listSkuClass } from "@/api/manage/skuClass";
import { loadAllParams } from "@/api/page";// 查询商品类型列表
const skuClassList = ref([]);
function getSkuClassList() {listSkuClass(loadAllParams).then(response => {skuClassList.value = response.rows;});
}
getSkuClassList();

在这里插入图片描述

将前端分改为元,为了突出这一列的可读性,可以通过增加tag标签对这一列进行高亮。

<el-table-column label="商品价格" align="center" prop="price"><template #default="scope"><el-tag >{{ scope.row.price/100 }} 元</el-tag></template></el-table-column>

在这里插入图片描述

添加或修改对话框改造

页面原型

在这里插入图片描述

代码实现

商品价格需要改为数字输入框,并且通过precision属性保留两位小数,并且通过step属性将增加减小的步径金额从1元改为0.5元。

   <!-- 添加或修改商品管理对话框 --><el-dialog :title="title" v-model="open" width="500px" append-to-body><el-form ref="skuRef" :model="form" :rules="rules" label-width="80px"><el-form-item label="商品名称" prop="skuName"><el-input v-model="form.skuName" placeholder="请输入" /></el-form-item><el-form-item label="品牌" prop="brandName"><el-input v-model="form.brandName" placeholder="请输入" /></el-form-item> <el-form-item label="商品价格" prop="price"><el-input-number :min="0.01" :max="999.99" :precision="2" :step="0.5" v-model="form.price" placeholder="请输入" style="width: 140px" /> &nbsp;&nbsp;<span>{{ '元' }}</span></el-form-item><el-form-item label="商品类型" prop="classId"><el-select v-model="form.classId" placeholder="请选择" style="width: 140px"><el-option v-for="item in skuClassList" :key="item.classId" :label="item.className" :value="item.classId" /></el-select></el-form-item><el-form-item label="规格" prop="unit"><el-input v-model="form.unit" placeholder="请输入规格" style="width: 140px" /> </el-form-item><el-form-item label="商品图片" prop="skuImage"><image-upload v-model="form.skuImage"/></el-form-item>  </el-form><template #footer><div class="dialog-footer"><el-button type="primary" @click="submitForm">确 定</el-button><el-button @click="cancel">取 消</el-button></div></template></el-dialog>

在这里插入图片描述

但是在修改对话框中回显的数据是分,原因是数据库中存储的数据是整形,也就是分。所以在回显之前将单位的分转换为元回显,同时提交修改的时候需要将元转换为分。

在这里插入图片描述

在这里插入图片描述

/** 修改按钮操作 */
function handleUpdate(row) {reset();const _skuId = row.skuId || ids.valuegetSku(_skuId).then(response => {form.value = response.data;// 回显价格时,需要将分转为元。form.value.price /= 100;open.value = true;title.value = "修改商品管理";});
}

在这里插入图片描述

但是在新增是商品后,价格除了100。原因就是在提交的时候提交的单位是,在数据库存储的应该是,所以在新增修改在提交数据前需要将元转换为分。

在这里插入图片描述

代码:

/** 提交按钮 */
function submitForm() {proxy.$refs["skuRef"].validate(valid => {// 将价格单位从元转换为分form.value.price *= 100;if (valid) {if (form.value.skuId != null) {updateSku(form.value).then(response => {proxy.$modal.msgSuccess("修改成功");open.value = false;getList();});} else {addSku(form.value).then(response => {proxy.$modal.msgSuccess("新增成功");open.value = false;getList();});}}});
}

再次添加数据:

在这里插入图片描述

商品删除

需求

在删除商品时,需要判断此商品是否被售货机的货道关联,如果关联则无法删除

  • 物理外键约束:通过在子表中添加一个外键列和约束,该列与父表的主键列相关联,由数据库维护数据的一致性和完整性

  • 逻辑外键约束:在不使用数据库外键约束的情况下,通常在应用程序中通过代码来检查和维护数据的一致性和完整性

使用逻辑外键约束的原因:我们在新增售货机货道记录时暂不指定商品,货道表中的SKU_ID有默认值0,而这个值在商品表中并不存在,那么物理外键约束会阻止货道表的插入,因为0并不指向任何有效的商品记录

在这里插入图片描述
在这里插入图片描述

代码实现

SkuServiceImpl

@Autowired
private IChannelService channelService;/*** 批量删除商品管理** @param skuIds 需要删除的商品管理主键* @return 结果*/
@Override
public int deleteSkuBySkuIds(Long[] skuIds)
{   //1. 判断商品的id集合是否有关联货道int count = channelService.countChannelBySkuIds(skuIds);if(count>0){throw new ServiceException("此商品被货道关联,无法删除");}//2. 没有关联货道才能删除return skuMapper.deleteSkuBySkuIds(skuIds);
}

IChannelService

/*** 根据商品id集合统计货道数量* @param skuIds* @return 统计结果*/
int countChannelBySkuIds(Long[] skuIds);

ChannelServiceImpl

/*** 根据商品id集合统计货道数量* @param skuIds* @return 统计结果*/
@Override
public int countChannelBySkuIds(Long[] skuIds) {return channelMapper.countChannelBySkuIds(skuIds);
}

ChannelMapper接口和xml

/*** 根据商品id集合统计货道数量* @param skuIds* @return 统计结果*/
int countChannelBySkuIds(Long[] skuIds);
<select id="countChannelBySkuIds" resultType="java.lang.Integer">select count(1) from tb_channel where sku_id in<foreach item="id" collection="array" open="(" separator="," close=")">#{id}</foreach>
</select>

当删除被货道关联的商品时

在这里插入图片描述

导出功能详解

在若依中已经默认将商品的导出功能实现了,主要是基于后端实现的。

在这里插入图片描述

Excel工具类底层是若依封装的,底层是基于apache的poi,原生apache的poi代码写起来非常繁琐,若依就将poi的基础功能封装和抽取,实现了文件的上传和下载功能。

在这里插入图片描述

主要包括文件的导入解析和文件的导出操作。

在这里插入图片描述

代码生成器默认生成好了文件的导出功能

批量导入

接口文档分析

在这里插入图片描述

两个请求投,Content-Type的作用告诉后端是一个表单文件提交,Authorization是告诉后端前端的身份令牌信息,只有登录以后前端具有了令牌才能上传,非则就会被拦截器拦截。返回结果就是标准的ajax result,有提示信息和业务状态码。

前端

需求

点击导入数据弹出导入数据弹窗,实现商品的批量导入

在这里插入图片描述

代码实现

打开导入按钮的对话框:

      <el-col :span="1.5"><el-buttontype="warning"icon="Upload"@click="handleImport"v-hasPermi="['manage:sku:add']">导入</el-button></el-col><!-- 新增导入对话框 --><el-dialog title="数据导入" v-model="openImport" width="500px" append-to-body></el-dialog>// 打开导入按钮
const openImport = ref(false);
function handleImport() {openImport.value = true;
}

在这里插入图片描述

完善上传对话框:

使用element-plus官网的上传按钮的方法

在这里插入图片描述

<!-- 新增导入对话框 --><el-dialogtitle="数据导入"v-model="openImport"width="500px"append-to-body><!-- 上传文件组件 --><el-uploadref="uploadRef"class="upload-demo"action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15":auto-upload="false"><template #trigger><el-button type="primary">上传文件</el-button></template><el-button class="ml-3" type="success" @click="submitUpload">上传</el-button><template #tip><div class="el-upload__tip">上传文件仅支持,xls/xlsx格式,文件大小不得超过1M</div></template></el-upload></el-dialog>// 上传excel文件
const uploadRef = ref({});
function submitUpload() {uploadRef.value.submit();
}

在这里插入图片描述

请求地址是element官网提供的,需要将请求地址改为帝可得商品的批量导入路径,可以参考图片上传的组件。

在这里插入图片描述

/* 上传地址 */
const uploadExcelUrl = ref(import.meta.env.VITE_APP_BASE_API + "/manage/sku/import"); // 上传excel文件地址
/* 上传请求头 */
const headers = ref({ Authorization: "Bearer " + getToken() });

在这里插入图片描述

上传失败提供失败信息,上传成功以后关闭对话框,并提示上传成功的信息。

在这里插入图片描述


// 上传成功回调
function handleUploadSuccess(res, file) {if (res.code === 200) {proxy.$modal.msgSuccess(`上传excel文件成功`);// 关闭导入对话框openImport.value = false;// 刷新列表getList();} else {proxy.$modal.msgError(res.msg);}// 清理上传文件uploadRef.value.clearFiles();}// 上传失败回调
function handleUploadError(err, file) {proxy.$modal.msgError("上传excel文件失败");// 清理上传文件uploadRef.value.clearFiles();
}

限制文件上传的大小,在上传前loading加载中添加相应的方法。

在这里插入图片描述

// 上传前的校验
const props = defineProps({modelValue: [String, Object, Array],// 大小限制(MB)fileSize: {type: Number,default: 1,},// 文件类型, 例如['xls', 'xlsx']fileType: {type: Array,default: () => ["xls", "xlsx"],},});
// 上传前loading加载
function handleBeforeUpload(file) {let isExcel = false;if (props.fileType.length) {let fileExtension = "";if (file.name.lastIndexOf(".") > -1) {fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);}isExcel = props.fileType.some(type => {if (file.type.indexOf(type) > -1) return true;if (fileExtension && fileExtension.indexOf(type) > -1) return true;return false;});}if (!isExcel) {proxy.$modal.msgError(`文件格式不正确, 请上传${props.fileType.join("/")}格式文件!`);return false;}if (props.fileSize) {const isLt = file.size / 1024 / 1024 < props.fileSize;if (!isLt) {proxy.$modal.msgError(`上传excel文件大小不能超过 ${props.fileSize} MB!`);return false;}}proxy.$modal.loading("正在上传excel文件,请稍候...");
}

在这里插入图片描述

在这里插入图片描述

上传成功或者失败之后关闭loading加载状态。

// 上传成功回调
function handleUploadSuccess(res, file) {if (res.code === 200) {proxy.$modal.msgSuccess(`上传excel文件成功`);// 关闭导入对话框openImport.value = false;// 刷新列表getList();} else {proxy.$modal.msgError(res.msg);}// 清理上传文件uploadRef.value.clearFiles();// 关闭加载状态proxy.$modal.closeLoading();
}// 上传失败回调
function handleUploadError(err, file) {proxy.$modal.msgError("上传excel文件失败");// 清理上传文件uploadRef.value.clearFiles();// 关闭加载状态proxy.$modal.closeLoading();
}

上传前的loading方法已经取消了多个文件上传,所以需要添加支持单个文件上传的属性limit。

<!-- 上传文件组件 --><el-uploadref="uploadRef"class="upload-demo":action="uploadExcelUrl":headers="headers":auto-upload="false":before-upload="handleBeforeUpload":on-success="handleUploadSuccess":on-error="handleUploadError":limit="1"><template #trigger><el-button type="primary">上传文件</el-button></template><el-button class="ml-3" type="success" @click="submitUpload">上传</el-button><template #tip><div class="el-upload__tip">上传文件仅支持,xls/xlsx格式,文件大小不得超过1M</div></template></el-upload>

后端

需求

请求路径和接收参数

在这里插入图片描述

在这里插入图片描述

代码实现

SkuController:

    /*** 导出商品管理列表*/@PreAuthorize("@ss.hasPermi('manage:sku:export')")@Log(title = "商品管理", businessType = BusinessType.EXPORT)@PostMapping("/export")// 接收前端的请求条件skupublic void export(HttpServletResponse response, Sku sku){// 1. 调用service实现商品列表的查询List<Sku> list = skuService.selectSkuList(sku);// 2. 将查询的结果list集合,交给一个excel工具类,实现文件的下载和导出功能。在创建excel工具类的同时需要指定商品类型的字节码对象,因为它底层是一道反射来解析实体属性获取数据。ExcelUtil<Sku> util = new ExcelUtil<Sku>(Sku.class);// 3. 创建好工具类之后,通过exportExcel方法,实现excel文件的生成和下载功能。util.exportExcel(response, list, "商品管理数据");}

如何将商品名称封装到对应的skuName属性中,图片封装到image中?

实体类中每个属性的上方都有一个Excel注解,这个注解的作用就是将当前的列标题与属性建立关系,导出数据每列的标题也是由Excel注解提供的。

在这里插入图片描述

ISkuService:

/*** 批量新增商品管理* @param skuList* @return 结果*/
public int insertSkus(List<Sku> skuList);
/*** 批量新增商品管理* @param skuList* @return 结果*/
@Override
public int insertSkus(List<Sku> skuList) {return skuMapper.insertSkus(skuList);
}

SKuMapper:

/*** 批量新增商品管理* @param skuList* @return 结果*/
public int insertSkus(List<Sku> skuList);

根据通义灵码将单个商品添加xml改造为批量添加:

假如你是一名软件开发工程师,请把下面的xml改为批量新增,不需要动态sql
    <insert id="insertSkus" parameterType="java.util.List">insert into tb_sku (sku_name,sku_image,brand_Name,unit,price,class_id,is_discount,create_time,update_time)values<foreach collection="list" item="sku" separator=",">(#{sku.skuName},#{sku.skuImage},#{sku.brandName},#{sku.unit},#{sku.price},#{sku.classId},#{sku.isDiscount},#{sku.createTime},#{sku.updateTime})</foreach></insert>

在这里插入图片描述

发现添加的数据没有创建日期,因为传入的excel文件并没有创建时间和更新时间的数据,在插入的时候会添加null。创建时间和更新时间在插入数据的时候会自动添加当前系统时间。是否打折不应该由商品决定,而是由商品所关联的售货机的策略模式判断的。在xml中去掉这些字段

<insert id="insertSkus" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="skuId">insert into tb_sku (sku_name, sku_image, brand_Name, unit, price, class_id)values<foreach item="item" index="index" collection="list" separator=",">(#{item.skuName}, #{item.skuImage}, #{item.brandName}, #{item.unit}, #{item.price}, #{item.classId})</foreach>
</insert>

添加成功:

在这里插入图片描述

EasyExcel

介绍

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

官方地址:https://easyexcel.alibaba.com/

Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。
easyexcel重写了poi对07版Excel的解析,一个3M的excel用POI sax解析依然需要100M左右内存,改用easyexcel可以降低到几M,并且再大的excel也不会出现内存溢出;03版依赖POI的sax模式,在上层做了模型转换的封装,让使用者更加简单方便

项目集成

文档地址

1、dkd-common\pom.xml模块添加整合依赖

<!--  excel处理工具-->
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>4.0.1</version>
</dependency>

2、在dkd-common\模块的ExcelUtil.java新增easyexcel导出导入方法

/*** 对excel表单默认第一个索引名转换成list(EasyExcel)* * @param is 输入流* @return 转换后集合*/
public List<T> importEasyExcel(InputStream is) throws Exception
{return EasyExcel.read(is).head(clazz).sheet().doReadSync();
}/*** 对list数据源将其里面的数据导入到excel表单(EasyExcel)* * @param list 导出数据集合* @param sheetName 工作表的名称* @return 结果*/
public void exportEasyExcel(HttpServletResponse response, List<T> list, String sheetName)
{try{EasyExcel.write(response.getOutputStream(), clazz).sheet(sheetName).doWrite(list);}catch (IOException e){log.error("导出EasyExcel异常{}", e.getMessage());}
}

3、Sku.java修改为@ExcelProperty注解

package com.dkd.manage.domain;import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.HeadFontStyle;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import com.dkd.common.annotation.Excel;
import com.dkd.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;/*** 商品管理对象 tb_sku** @author itheima* @date 2024-07-15*/
@ExcelIgnoreUnannotated// 注解表示在导出Excel时,忽略没有被任何注解标记的字段
@ColumnWidth(16)// 注解用于设置列的宽度
@HeadRowHeight(14)// 注解用于设置表头行的高度
@HeadFontStyle(fontHeightInPoints = 11)// 注解用于设置表头的字体样式
public class Sku extends BaseEntity
{private static final long serialVersionUID = 1L;/** 主键 */private Long skuId;/** 商品名称 */@Excel(name = "商品名称")@ExcelProperty("商品名称")private String skuName;/** 商品图片 */@Excel(name = "商品图片")@ExcelProperty("商品图片")private String skuImage;/** 品牌 */@Excel(name = "品牌")@ExcelProperty("品牌")private String brandName;/** 规格(净含量) */@Excel(name = "规格(净含量)")@ExcelProperty("规格(净含量)")private String unit;/** 商品价格 */@Excel(name = "商品价格")@ExcelProperty("商品价格")private Long price;/** 商品类型Id */@Excel(name = "商品类型Id")@ExcelProperty("商品类型Id")private Long classId;/** 是否打折促销 */private Integer isDiscount;// 其他略...
}

4、SkuController.java中将importExcel改为importEasyExcel

/*** 导入商品管理列表*/
@PreAuthorize("@ss.hasPermi('manage:sku:add')")
@Log(title = "商品管理", businessType = BusinessType.IMPORT)
@PostMapping("/import")
public AjaxResult excelImport(MultipartFile file) throws Exception {ExcelUtil<Sku> util = new ExcelUtil<Sku>(Sku.class);List<Sku> skuList = util.importEasyExcel(file.getInputStream());return toAjax(skuService.insertSkus(skuList));
}

5、SkuController.java中将exportExcel改为exportEasyExcel

/*** 导出商品管理列表*/
@PreAuthorize("@ss.hasPermi('manage:sku:export')")
@Log(title = "商品管理", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, Sku sku) {List<Sku> list = skuService.selectSkuList(sku);ExcelUtil<Sku> util = new ExcelUtil<Sku>(Sku.class);util.exportEasyExcel(response, list, "商品管理数据");
}

会出现easyexcelpoi版本不匹配的情况,在parent得xml中修改poi的版本号为5.2.3即可。

货道关联商品

需求

在设备管理的操作中点击货道,会弹出一个货道设置的对话框。点击添加按钮会弹出商品的对话框,可以选择关联的商品。点击智能排货,会弹出智能排货的对话框。

在这里插入图片描述

对智能售货机内部的货道进行商品摆放的管理

在这里插入图片描述

在这里插入图片描述

此功能涉及四个后端接口

  • 查询设备类型(已完成)
  • 查询货道列表(待完成)
  • 查询商品列表(已完成)
  • 货道关联商品(待完成)

货道对话框

从资料中复制货道api请求js文件到api/manage目录下

在这里插入图片描述

从资料中复制货道的视图组件components到views/manage/vm目录下

在这里插入图片描述

修改index.vue视图,并引入css样式

<el-button link type="primary" @click="handleGoods(scope.row)" v-hasPermi="['manage:vm:edit']">货道</el-button><!-- 货道组件对话框 -->
<ChannelDialog :goodVisible="goodVisible" :goodData="goodData" @handleCloseGood="handleCloseGood"></ChannelDialog>
<!-- end --><script setup name="Vm">// ********************货道********************// 货道组件import ChannelDialog from './components/ChannelDialog.vue';const goodVisible = ref(false); //货道弹层显示隐藏const goodData = ref({}); //货道信息用来拿取 vmTypeId和innerCode// 打开货道弹层const handleGoods = (row) => {goodVisible.value = true;goodData.value = row;};// 关闭货道弹层const handleCloseGood = () => {goodVisible.value = false;};// ********************货道end********************
</script>
<style lang="scss" scoped src="./index.scss"></style>

查询货道列表

前端向后端发送的请求是list/售货机编号,返回的信息不仅有货道的信息还有货道对应的商品信息。

在这里插入图片描述

需要先根据售货机编号inner_code货道表中查询货道信息,再根据货道信息中的sku_id商品表嵌套查询商品信息。将货道信息和商品信息封装到channelVo中返回。

ChannelVo

@Data
public class ChannelVo extends Channel {// 商品信息private Sku sku;
}

ChannelMapper和xml

/*** 根据售货机编号查询货道列表** @param innerCode* @return ChannelVo集合*/
List<ChannelVo> selectChannelVoListByInnerCode(String innerCode);
<resultMap type="ChannelVo" id="ChannelVoResult"><result property="id"    column="id"    /><result property="channelCode"    column="channel_code"    /><result property="skuId"    column="sku_id"    /><result property="vmId"    column="vm_id"    /><result property="innerCode"    column="inner_code"    /><result property="maxCapacity"    column="max_capacity"    /><result property="currentCapacity"    column="current_capacity"    /><result property="lastSupplyTime"    column="last_supply_time"    /><result property="createTime"    column="create_time"    /><result property="updateTime"    column="update_time"    /><association property="sku" javaType="Sku" column="sku_id" select="com.dkd.manage.mapper.SkuMapper.selectSkuBySkuId"/>
</resultMap><select id="selectChannelVoListByInnerCode" resultMap="ChannelVoResult"><include refid="selectChannelVo"/>where inner_code = #{innerCode}
</select>

IChannelService接口和实现

/*** 根据售货机编号查询货道列表** @param innerCode* @return ChannelVo集合*/
List<ChannelVo> selectChannelVoListByInnerCode(String innerCode);
/*** 根据售货机编号查询货道列表** @param innerCode* @return ChannelVo集合*/
@Override
public List<ChannelVo> selectChannelVoListByInnerCode(String innerCode) {return channelMapper.selectChannelVoListByInnerCode(innerCode);
}

ChannelController

/*** 根据售货机编号查询货道列表*/
@PreAuthorize("@ss.hasPermi('manage:channel:list')")
@GetMapping("/list/{innerCode}")
public AjaxResult lisetByInnerCode(@PathVariable("innerCode") String innerCode) {List<ChannelVo> voList = channelService.selectChannelVoListByInnerCode(innerCode);return success(voList);
}

货道关联商品

完成货道的配置,实现货道关联商品,并通过点击按钮向后端发送请求更新数据库。根据channel_code和inner_code可以确定货道的唯一标识,然后可以更新货道中的sku_id。主要关注的是前端的请求参数,接口返回的数据就是一个标准的AjaxResult

在这里插入图片描述

DTO对象不能直接更新数据库货道表的,需要将DTO转换为与数据库对应的PO对象,也就是持久化对象,实体的属性名与货道的属性名做到一一对应。在转换的过程中需要对前端的数据进行校验,确保当前货道是存在的,所以需要根据售货机的编号和货道的编号来查询当前货道的信息。如果查到了就给当前的货道实体类设置skuId,这是其中一个货道的设置,需要遍历查询转换设置sku_id。

在这里插入图片描述

ChannelSkuDto

设计一个数据传输对象专门接收innerCode和channelCode,因为目前数据库对应的实体类没有这样的属性与前端的参数所对应,channelList用于接收每个货道的信息,也需要设计一个数据传输对象。

// 某个货道对应的sku信息
@Data
public class ChannelSkuDto {private String innerCode; // 售货机编号private String channelCode; // 货道编号private Long skuId; // 商品ID
}

ChannelConfigDto

// 售货机货道配置,接收前端传输的整体数据
@Data
public class ChannelConfigDto {// 售货机编号private String innerCode;// 货道配置private List<ChannelSkuDto> channelList;
}

根据innerCode和channelCode查询对应的货道信息

ChannelMapper和xml

/*** 根据售货机编号和货道编号查询货道信息* @param innerCode* @param channelCode* @return 售货机货道*/
@Select("select * from tb_channel where inner_code =#{innerCode} and channel_code=#{channelCode}")
Channel getChannelInfo(@Param("innerCode") String innerCode, @Param("channelCode") String channelCode);/*** 批量修改货道* @param list* @return 结果*/
int batchUpdateChannel(List<Channel> list);
<update id="batchUpdateChannel" parameterType="java.util.List"><foreach item="channel" collection="list" separator=";">UPDATE tb_channel<set><if test="channel.channelCode != null and channel.channelCode != ''">channel_code = #{channel.channelCode},</if><if test="channel.skuId != null">sku_id = #{channel.skuId},</if><if test="channel.vmId != null">vm_id = #{channel.vmId},</if><if test="channel.innerCode != null and channel.innerCode != ''">inner_code = #{channel.innerCode},</if><if test="channel.maxCapacity != null">max_capacity = #{channel.maxCapacity},</if><if test="channel.currentCapacity != null">current_capacity = #{channel.currentCapacity},</if><if test="channel.lastSupplyTime != null">last_supply_time = #{channel.lastSupplyTime},</if><if test="channel.createTime != null">create_time = #{channel.createTime},</if><if test="channel.updateTime != null">update_time = #{channel.updateTime},</if></set>WHERE id = #{channel.id}</foreach>
</update>

mybatis在连接数据库的时候,默认情况下一个请求只能执行一条sql语句。之前的批量新增是insert into values()();而生成的动态更新是update xxx;update xxx;这就包含多个更新语句了。

application-druid.yml

允许mybatis框架在单个请求中发送多个sql语句

在这里插入图片描述

IChannelService接口和实现

/*** 货道关联商品* @param channelConfigDto* @return 结果*/
int setChannel(ChannelConfigDto channelConfigDto);
/*** 货道关联商品* @param channelConfigDto* @return 结果*/
@Override
public int setChannel(ChannelConfigDto channelConfigDto) {//1. dto转poList<Channel> list = channelConfigDto.getChannelList().stream().map(c -> {// 根据售货机编号和货道编号查询货道Channel channel = channelMapper.getChannelInfo(c.getInnerCode(), c.getChannelCode());if (channel != null) {// 货道更新skuIdchannel.setSkuId(c.getSkuId());// 货道更新时间channel.setUpdateTime(DateUtils.getNowDate());}return channel;}).collect(Collectors.toList());//2. 批量修改货道return channelMapper.batchUpdateChannel(list);
}

ChannelController

/*** 货道关联商品*/
@PreAuthorize("@ss.hasPermi('manage:channel:edit')")
@Log(title = "售货机货道", businessType = BusinessType.UPDATE)
@PutMapping("/config")
public AjaxResult setChannel(@RequestBody ChannelConfigDto channelConfigDto) {return toAjax(channelService.setChannel(channelConfigDto));
}

在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词