增加下载台码功能

This commit is contained in:
GYJ
2024-06-13 12:00:06 +08:00
parent 737d38d0a6
commit d693e8afd5
14 changed files with 653 additions and 3 deletions

View File

@@ -113,6 +113,21 @@
<artifactId>mybatis-plus-boot-starter</artifactId> <artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version> <version>3.5.3.1</version>
</dependency> </dependency>
<!-- zxing生成二维码 -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.5.3</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.5.3</version>
</dependency>
</dependencies> </dependencies>
<profiles> <profiles>
<profile> <profile>
@@ -145,5 +160,12 @@
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
<repositories>
<repository>
<id>maven_central</id>
<name>Maven Central</name>
<url>https://repo.maven.apache.org/maven2/</url>
</repository>
</repositories>
</project> </project>

View File

@@ -0,0 +1,121 @@
package cn.ysk.cashier.controller.shop;
import cn.hutool.core.util.ZipUtil;
import cn.ysk.cashier.dto.shop.TbDeviceStockDownloadDto;
import cn.ysk.cashier.dto.shop.TbShopInfoDto;
import cn.ysk.cashier.pojo.TbDeviceStock;
import cn.ysk.cashier.pojo.shop.TbShopTable;
import cn.ysk.cashier.service.shop.TbDeviceStockService;
import cn.ysk.cashier.service.shop.TbShopInfoService;
import cn.ysk.cashier.service.shop.TbShopTableService;
import cn.ysk.cashier.utils.FileUtil;
import cn.ysk.cashier.utils.QrCodeUtils;
import cn.ysk.cashier.utils.ZipUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* @author GYJ
*/
@RestController
@RequiredArgsConstructor
@Api(tags = "/device/台桌码管理")
@RequestMapping("/api/deviceStock")
public class TbDeviceStockController {
private final TbDeviceStockService tbDeviceStockService;
private final TbShopTableService shopTableService;
private final TbShopInfoService shopInfoService;
@ApiOperation("批量下载二维码")
@PostMapping(value = "/batchDownload")
public void batchDownload(HttpServletRequest request, HttpServletResponse response, @RequestBody TbDeviceStockDownloadDto downloadDto) {
TbShopInfoDto shop = shopInfoService.findById(Integer.valueOf(downloadDto.getShopId()));
if (shop == null) {
throw new RuntimeException("店铺不存在");
}
// 查询shop下面有多少台桌
List<TbShopTable> shopTables = shopTableService.queryListByShopId(Integer.valueOf(downloadDto.getShopId()));
if (shopTables.isEmpty()) {
throw new RuntimeException("请先添加台桌");
}
if (downloadDto.getCount() > (shopTables.size() * 2)) {
throw new RuntimeException("最多可获取台桌数量的2倍");
}
TbDeviceStock lastRecord = tbDeviceStockService.findLastRecord();
long startCode = 4000000000L;
if (lastRecord != null) {
startCode = Long.parseLong(lastRecord.getSnNo()) + 1;
}
List<TbDeviceStock> list = new ArrayList<>();
for (int i = 0; i < downloadDto.getCount(); i++) {
TbDeviceStock stock = new TbDeviceStock();
stock.setCreateTime(new Date());
stock.setSnNo(String.valueOf(startCode + i));
stock.setPrice(BigDecimal.ZERO);
stock.setStatus("1");
stock.setCode("zm");
stock.setType("1张");
stock.setGroupNo("111");
stock.setDelFlag("1");
list.add(stock);
}
try {
tbDeviceStockService.saveBatch(list);
} catch (Exception e) {
throw new RuntimeException("设备编号重复");
}
// 根据code拼接前缀生成二维码存在本地
// 二维码存放路径
String basePath = "/usr/local/tmp/qrCode/" + shop.getShopName();
String baseUrl = "https://kysh.sxczgkj.cn/codeplate?code=";
File codeImgFileSaveDir = new File(basePath);
if (codeImgFileSaveDir.exists()) {
// 先删除内部的文件
File[] files = codeImgFileSaveDir.listFiles();
for (File file : files) {
file.delete();
}
// 删除文件夹
codeImgFileSaveDir.delete();
}
for (TbDeviceStock stock : list) {
// 生成二维码
QrCodeUtils.createCodeToFile(baseUrl + stock.getSnNo(), codeImgFileSaveDir, stock.getSnNo() + ".png");
}
try {
String zipPath = basePath + ".zip";
File zipFile = new File(zipPath);
if (zipFile.exists()) {
zipFile.delete();
}
ZipUtils.zipDirectory(codeImgFileSaveDir, zipFile);
System.out.println(basePath + ".zip");
FileUtil.downloadFile(request, response, zipFile, true);
} catch (Exception e) {
throw new RuntimeException("压缩文件失败");
}
}
}

View File

@@ -0,0 +1,12 @@
package cn.ysk.cashier.dto.shop;
import lombok.Data;
/**
* @author GYJ
*/
@Data
public class TbDeviceStockDownloadDto {
private String shopId;
private Integer count;
}

View File

@@ -0,0 +1,35 @@
package cn.ysk.cashier.dto.shop;
import lombok.Data;
import java.io.Serializable;
@Data
public class TbDeviceStockDto implements Serializable {
private Integer id;
private String name;
private Integer shopId;
private Integer maxCapacity;
private Integer sort;
private Integer areaId;
private Integer isPredate;
private String status;
private Integer type;
private String view;
private Long createdAt;
private Long updatedAt;
private String qrcode;
}

View File

@@ -0,0 +1,14 @@
package cn.ysk.cashier.mapper.shop;
import cn.ysk.cashier.base.BaseMapper;
import cn.ysk.cashier.dto.shop.TbDeviceStockDto;
import cn.ysk.cashier.pojo.TbDeviceStock;
import org.mapstruct.Mapper;
import org.mapstruct.ReportingPolicy;
/**
* @author GYJ
*/
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface TbDeviceStockMapper extends BaseMapper<TbDeviceStockDto, TbDeviceStock> {
}

View File

@@ -0,0 +1,205 @@
package cn.ysk.cashier.pojo;
import com.alibaba.fastjson.annotation.JSONField;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.SqlCondition;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import javax.persistence.*;
import java.math.BigDecimal;
import java.util.Date;
/**
* @author GYJ
*/
@Entity
@Data
@Table(name="tb_device_stock")
public class TbDeviceStock {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "`id`")
@ApiModelProperty(value = "自增id")
private Integer id;
/**
* code
*/
@TableField(value = "code", whereStrategy = FieldStrategy.NOT_EMPTY)
@Column(name = "`code`")
private String code;
/**
* 设备唯一编码,码牌即为二维码编号
*/
@TableField(value = "sn_no",whereStrategy = FieldStrategy.NOT_EMPTY)
@Column(name = "`sn_no`")
private String snNo;
/**
* 设备购买单号
*/
@TableField(value = "order_no",whereStrategy = FieldStrategy.NOT_EMPTY)
@Column(name = "`order_no`")
private String orderNo;
/**
* 设备购买价格
*/
@TableField("price")
@Column(name = "`price`")
private BigDecimal price;
/**
* 设备版本
*/
@TableField(value = "type",whereStrategy = FieldStrategy.NOT_EMPTY)
@Column(name = "`type`")
private String type;
/**
* 库存分组
*/
@TableField(value = "group_no",whereStrategy = FieldStrategy.NOT_EMPTY)
@Column(name = "`group_no`")
private String groupNo;
/**
* 购买商家名称
*/
@TableField(value = "buy_merc_name",whereStrategy = FieldStrategy.NOT_EMPTY,condition = SqlCondition.LIKE)
@Column(name = "`buy_merc_name`")
private String buyMercName;
/**
* 购买商家ID
*/
@TableField(value = "buy_merc_id",whereStrategy = FieldStrategy.NOT_EMPTY)
@Column(name = "`buy_merc_id`")
private String buyMercId;
/**
* 激活商家名称
*/
@TableField(value = "act_merc_ame",whereStrategy = FieldStrategy.NOT_EMPTY,condition = SqlCondition.LIKE)
@Column(name = "`act_merc_ame`")
private String actMercName;
/**
* 激活商家ID
*/
@TableField(value = "act_merc_d",whereStrategy = FieldStrategy.NOT_EMPTY)
@Column(name = "act_merc_d")
private String actMercId;
/**
* 二维码状态1未出售2已出售 3:已激活
*/
@TableField(value = "status",whereStrategy = FieldStrategy.NOT_EMPTY)
@Column(name = "`status`")
private String status;
/**
* 创建时间
*/
@TableField(value = "create_time", fill = FieldFill.INSERT)
@Column(name = "`create_time`")
private Date createTime;
/**
* 创建人
*/
@TableField("create_by")
@Column(name = "`create_by`")
private String createBy;
/**
* 删除标记1正常2删除
*/
@TableField("del_flag")
@Column(name = "`del_flag`")
private String delFlag;
/**
* 备注
*/
@TableField("remarks")
@Column(name = "`remarks`")
private String remarks;
/**
* 更新时间
*/
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
@Column(name = "`update_time`")
private Date updateTime;
/**
* 厂家设备编号,音箱播报需要
*/
@TableField(value = "device_no")
@Column(name = "`device_no`")
private String deviceNo;
/**
* 归属用户ID 如果是商户直接从设备商城购买的问题
* 就显示当前使用用户ID
* 如果是直营团队那边的 就归属于上级ID
*/
@TableField("belong_user_id")
@Column(name = "`belong_user_id`")
private Long belongUserId;
/**
* 提货人用户ID
*/
@TableField("extract_user_id")
@Column(name = "`extract_user_id`")
private Long extractUserId;
/**
* 所属角色
*/
@TableField("role_code")
@Column(name = "`role_code`")
private String roleCode;
/**
* 入库时间
*/
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
@TableField("in_stock_time")
@Column(name = "`in_stock_time`")
private Date inStockTime;
/**
* 划拨状态 划拨状态 01待接收 其他表示已接收
*/
@TableField("transfer_status")
@Column(name = "`transfer_status`")
private String transferStatus;
/**
* 绑定时间
*/
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
@TableField("bind_time")
@Column(name = "`bind_time`")
private Date bindTime;
}

View File

@@ -0,0 +1,12 @@
package cn.ysk.cashier.repository.shop;
import cn.ysk.cashier.pojo.TbDeviceStock;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
/**
* @author GYJ
*/
public interface TbDeviceStockRepository extends JpaRepository<TbDeviceStock, Integer>, JpaSpecificationExecutor<TbDeviceStock> {
}

View File

@@ -21,6 +21,8 @@ import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import java.util.List;
/** /**
* @website https://eladmin.vip * @website https://eladmin.vip
* @author lyf * @author lyf
@@ -33,4 +35,7 @@ public interface TbShopTableRepository extends JpaRepository<TbShopTable, Intege
// @Query("select table from TbShopTable table where table.shopId = :qrcode") // @Query("select table from TbShopTable table where table.shopId = :qrcode")
// List<TbShopTable> findByQrcode(@Param("qrcode") Integer shopId); // List<TbShopTable> findByQrcode(@Param("qrcode") Integer shopId);
}
@Query("select table from TbShopTable table where table.shopId = :shopId")
List<TbShopTable> findByShopId(@Param("shopId") Integer shopId);
}

View File

@@ -0,0 +1,38 @@
package cn.ysk.cashier.service.impl.shopimpl;
import cn.ysk.cashier.pojo.TbDeviceStock;
import cn.ysk.cashier.repository.shop.TbDeviceStockRepository;
import cn.ysk.cashier.service.shop.TbDeviceStockService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author GYJ
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class TbDeviceStockServiceImpl implements TbDeviceStockService {
private final TbDeviceStockRepository deviceStockRepository;
@Override
public TbDeviceStock findLastRecord() {
List<TbDeviceStock> list = deviceStockRepository.findAll(PageRequest.of(0, 1, Sort.by(Sort.Direction.DESC, "id"))).getContent();
if (list.isEmpty()) {
return null;
}
return list.get(0);
}
@Override
public void saveBatch(List<TbDeviceStock> list) {
deviceStockRepository.saveAll(list);
}
}

View File

@@ -94,6 +94,11 @@ public class TbShopTableServiceImpl implements TbShopTableService {
return tbShopTableMapper.toDto(tbShopTableRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder))); return tbShopTableMapper.toDto(tbShopTableRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
} }
@Override
public List<TbShopTable> queryListByShopId(Integer shopId) {
return tbShopTableRepository.findByShopId(shopId);
}
@Override @Override
@Transactional @Transactional
public TbShopTableDto findById(Integer id) { public TbShopTableDto findById(Integer id) {
@@ -167,4 +172,4 @@ public class TbShopTableServiceImpl implements TbShopTableService {
} }
FileUtil.downloadExcel(list, response); FileUtil.downloadExcel(list, response);
} }
} }

View File

@@ -0,0 +1,14 @@
package cn.ysk.cashier.service.shop;
import cn.ysk.cashier.pojo.TbDeviceStock;
import java.util.List;
/**
* @author GYJ
*/
public interface TbDeviceStockService {
TbDeviceStock findLastRecord();
void saveBatch(List<TbDeviceStock> list);
}

View File

@@ -49,6 +49,13 @@ public interface TbShopTableService {
*/ */
List<TbShopTableDto> queryAll(TbShopTableQueryCriteria criteria); List<TbShopTableDto> queryAll(TbShopTableQueryCriteria criteria);
/**
* 根据shopId查询台桌列表
* @param shopId 店铺id
* @return 台桌列表
*/
List<TbShopTable> queryListByShopId(Integer shopId);
/** /**
* 根据ID查询 * 根据ID查询
* @param id ID * @param id ID
@@ -85,4 +92,4 @@ public interface TbShopTableService {
* @throws IOException / * @throws IOException /
*/ */
void download(List<TbShopTableDto> all, HttpServletResponse response) throws IOException; void download(List<TbShopTableDto> all, HttpServletResponse response) throws IOException;
} }

View File

@@ -0,0 +1,114 @@
package cn.ysk.cashier.utils;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import javax.imageio.ImageIO;
import javax.swing.filechooser.FileSystemView;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
/**
* 二维码工具类
*
* @author GYJ
*/
public class QrCodeUtils {
//CODE_WIDTH二维码宽度单位像素
private static final int CODE_WIDTH = 400;
//CODE_HEIGHT二维码高度单位像素
private static final int CODE_HEIGHT = 400;
//FRONT_COLOR二维码前景色0x000000 表示黑色
private static final int FRONT_COLOR = 0x000000;
//BACKGROUND_COLOR二维码背景色0xFFFFFF 表示白色
//演示用 16 进制表示,和前端页面 CSS 的取色是一样的,注意前后景颜色应该对比明显,如常见的黑白
private static final int BACKGROUND_COLOR = 0xFFFFFF;
public static void createCodeToFile(String content, File codeImgFileSaveDir, String fileName) {
try {
if (StringUtils.isBlank(content) || StringUtils.isBlank(fileName)) {
return;
}
content = content.trim();
if (codeImgFileSaveDir==null || codeImgFileSaveDir.isFile()) {
//二维码图片存在目录为空,默认放在桌面...
codeImgFileSaveDir = FileSystemView.getFileSystemView().getHomeDirectory();
}
if (!codeImgFileSaveDir.exists()) {
//二维码图片存在目录不存在,开始创建...
codeImgFileSaveDir.mkdirs();
}
//核心代码-生成二维码
BufferedImage bufferedImage = getBufferedImage(content);
File codeImgFile = new File(codeImgFileSaveDir, fileName);
ImageIO.write(bufferedImage, "png", codeImgFile);
System.out.println("二维码图片生成成功:" + codeImgFile.getPath());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 生成二维码并输出到输出流, 通常用于输出到网页上进行显示,输出到网页与输出到磁盘上的文件中,区别在于最后一句 ImageIO.write
* write(RenderedImage im,String formatName,File output):写到文件中
* write(RenderedImage im,String formatName,OutputStream output):输出到输出流中
* @param content :二维码内容
* @param outputStream :输出流,比如 HttpServletResponse 的 getOutputStream
*/
public static void createCodeToOutputStream(String content, OutputStream outputStream) {
try {
if (StringUtils.isBlank(content)) {
return;
}
content = content.trim();
//核心代码-生成二维码
BufferedImage bufferedImage = getBufferedImage(content);
//区别就是这一句,输出到输出流中,如果第三个参数是 File则输出到文件中
ImageIO.write(bufferedImage, "png", outputStream);
System.out.println("二维码图片生成到输出流成功...");
} catch (Exception e) {
e.printStackTrace();
}
}
//核心代码-生成二维码
private static BufferedImage getBufferedImage(String content) throws WriterException {
//com.google.zxing.EncodeHintType编码提示类型,枚举类型
Map<EncodeHintType, Object> hints = new HashMap();
//EncodeHintType.CHARACTER_SET设置字符编码类型
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
//EncodeHintType.ERROR_CORRECTION设置误差校正
//ErrorCorrectionLevel误差校正等级L = ~7% correction、M = ~15% correction、Q = ~25% correction、H = ~30% correction
//不设置时,默认为 L 等级,等级不一样,生成的图案不同,但扫描的结果是一样的
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
//EncodeHintType.MARGIN设置二维码边距单位像素值越小二维码距离四周越近
hints.put(EncodeHintType.MARGIN, 1);
MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
BitMatrix bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, CODE_WIDTH, CODE_HEIGHT, hints);
BufferedImage bufferedImage = new BufferedImage(CODE_WIDTH, CODE_HEIGHT, BufferedImage.TYPE_INT_BGR);
for (int x = 0; x < CODE_WIDTH; x++) {
for (int y = 0; y < CODE_HEIGHT; y++) {
bufferedImage.setRGB(x, y, bitMatrix.get(x, y) ? FRONT_COLOR : BACKGROUND_COLOR);
}
}
return bufferedImage;
}
}

View File

@@ -0,0 +1,46 @@
package cn.ysk.cashier.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* zip工具类
*
* @author GYJ
*/
public class ZipUtils {
public static void zipDirectory(File directoryToZip, File zipFile) throws IOException {
FileOutputStream fos = new FileOutputStream(zipFile);
ZipOutputStream zos = new ZipOutputStream(fos);
compressDirectoryToZipfile(directoryToZip, directoryToZip, zos);
zos.close();
fos.close();
}
private static void compressDirectoryToZipfile(File rootDir, File currentDir, ZipOutputStream zos) throws IOException {
File[] files = currentDir.listFiles();
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
compressDirectoryToZipfile(rootDir, file, zos);
} else {
ZipEntry zipEntry = new ZipEntry(rootDir.toURI().relativize(file.toURI()).getPath());
zos.putNextEntry(zipEntry);
FileInputStream fis = new FileInputStream(file);
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) > 0) {
zos.write(buffer, 0, len);
}
fis.close();
zos.closeEntry();
}
}
}
}
}