liding
昨天 d75958896efd4c8a6daee9c56d048641b99cacf6
1.二维码巡检记录以及文件上传记录 2.部分优化
已修改11个文件
已添加16个文件
746 ■■■■■ 文件已修改
main-business/src/main/java/com/ruoyi/business/controller/QrCodeController.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/controller/QrCodeScanRecordController.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/dto/QrCodeDto.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/dto/QrCodeScanRecordDto.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/entity/OfficialInventory.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/entity/PendingInventory.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/entity/PurchaseRegistration.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/entity/QrCode.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/entity/QrCodeScanRecord.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/mapper/QrCodeMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/mapper/QrCodeScanRecordMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/service/QrCodeScanRecordService.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/service/QrCodeService.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/service/impl/ArchiveServiceImpl.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/service/impl/PurchaseRegistrationServiceImpl.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/service/impl/QrCodeScanRecordServiceImpl.java 189 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/service/impl/QrCodeServiceImpl.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/service/impl/SalesRecordServiceImpl.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/resources/db/migration/postgresql/V20250604104500__create_table_pending_inventory.sql 42 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/resources/db/migration/postgresql/V20250604111200__create_table_official_inventory.sql 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/resources/db/migration/postgresql/V20250624092100__create_table_qr_code.sql 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/resources/db/migration/postgresql/V20250624092400__create_table_qr_code_scan_record.sql 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/resources/mapper/PendingInventoryMapper.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/resources/mapper/PurchaseRegistrationMapper.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/resources/mapper/QrCodeMapper.xml 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/resources/mapper/QrCodeScanRecordMapper.xml 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/enums/StorageAttachmentRecordType.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/controller/QrCodeController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,55 @@
package com.ruoyi.business.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.business.dto.ProductionDto;
import com.ruoyi.business.dto.QrCodeDto;
import com.ruoyi.business.entity.Production;
import com.ruoyi.business.entity.QrCode;
import com.ruoyi.business.service.QrCodeService;
import com.ruoyi.common.core.domain.R;
import org.springframework.web.bind.annotation.*;
import lombok.AllArgsConstructor;
/**
 * <p>
 * äºŒç»´ç ç®¡ç†è¡¨ å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author ld
 * @since 2025-06-24
 */
@RestController
@AllArgsConstructor
@RequestMapping("/qrCode")
public class QrCodeController {
    private QrCodeService qrCodeService;
    /**
     * äºŒç»´ç ç®¡ç†è¡¨æŸ¥è¯¢
     */
    @GetMapping("/list")
    public R<IPage<QrCode>> list(Page page, QrCodeDto qrCodeDto) {
        IPage<QrCode> list = qrCodeService.selectQrCodeList(page, qrCodeDto);
        return R.ok(list);
    }
    /**
     * äºŒç»´ç ç®¡ç†è¡¨æ–°å¢žä¿®æ”¹
     */
    @PostMapping("/addOrEditQrCode")
    public R<Long> addOrEditQrCode(@RequestBody QrCodeDto qrCodeDto) {
        return R.ok(qrCodeService.addOrEditQrCode(qrCodeDto));
    }
    /**
     * äºŒç»´ç ç®¡ç†è¡¨åˆ é™¤
     */
    @DeleteMapping("/delQrCode")
    public R remove(@RequestBody Long[] ids) {
        return R.ok(qrCodeService.delByIds(ids));
    }
}
main-business/src/main/java/com/ruoyi/business/controller/QrCodeScanRecordController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,56 @@
package com.ruoyi.business.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.business.dto.QrCodeDto;
import com.ruoyi.business.dto.QrCodeScanRecordDto;
import com.ruoyi.business.entity.QrCode;
import com.ruoyi.business.entity.QrCodeScanRecord;
import com.ruoyi.business.service.QrCodeScanRecordService;
import com.ruoyi.business.service.QrCodeService;
import com.ruoyi.common.core.domain.R;
import org.springframework.web.bind.annotation.*;
import lombok.AllArgsConstructor;
/**
 * <p>
 * äºŒç»´ç æ‰«ç è®°å½•表 å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author ld
 * @since 2025-06-24
 */
@RestController
@AllArgsConstructor
@RequestMapping("/qrCodeScanRecord")
public class QrCodeScanRecordController {
    private final QrCodeScanRecordService qrCodeScanRecordService;
    /**
     * äºŒç»´ç æ‰«ç è®°å½•表查询
     */
    @GetMapping("/list")
    public R<IPage<QrCodeScanRecordDto>> list(Page<QrCodeScanRecord> page, QrCodeScanRecordDto qrCodeScanRecordDto) {
        IPage<QrCodeScanRecordDto> list = qrCodeScanRecordService.selectQrCodeScanRecordList(page, qrCodeScanRecordDto);
        return R.ok(list);
    }
    /**
     * äºŒç»´ç æ‰«ç è®°å½•表新增修改
     */
    @PostMapping("/addOrEditQrCodeRecord")
    public R addOrEditQrCodeRecord(@RequestBody QrCodeScanRecordDto qrCodeScanRecordDto) {
        return R.ok(qrCodeScanRecordService.addOrEditQrCodeRecord(qrCodeScanRecordDto));
    }
    /**
     * äºŒç»´ç æ‰«ç è®°å½•表删除
     */
    @DeleteMapping("/delSalesRecord")
    public R remove(@RequestBody Long[] ids) {
        return R.ok(qrCodeScanRecordService.delByIds(ids));
    }
}
main-business/src/main/java/com/ruoyi/business/dto/QrCodeDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
package com.ruoyi.business.dto;
import com.ruoyi.business.entity.QrCode;
import lombok.Data;
@Data
public class QrCodeDto extends QrCode {
}
main-business/src/main/java/com/ruoyi/business/dto/QrCodeScanRecordDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,19 @@
package com.ruoyi.business.dto;
import com.ruoyi.basic.entity.dto.StorageBlobDTO;
import com.ruoyi.business.entity.QrCode;
import com.ruoyi.business.entity.QrCodeScanRecord;
import lombok.Data;
import java.util.List;
@Data
public class QrCodeScanRecordDto extends QrCodeScanRecord {
    private QrCode qrCode;
    private String scanner;
    private List<StorageBlobDTO> storageBlobDTO;
}
main-business/src/main/java/com/ruoyi/business/entity/OfficialInventory.java
@@ -40,8 +40,8 @@
    /**
     * ç…¤ç§
     */
    @TableField(value = "coal")
    private String coal;
    @TableField(value = "coal_id")
    private Long coalId;
    /**
     * å•位
     */
main-business/src/main/java/com/ruoyi/business/entity/PendingInventory.java
@@ -38,6 +38,11 @@
    @TableField(value = "supplier_name")
    private String supplierName;
    /**
     * ä¾›è´§å•†åç§°
     */
    @TableField(value = "supplier_id")
    private Long supplierId;
    /**
     * ç…¤ç§
     */
    @TableField(value = "coal_id")
main-business/src/main/java/com/ruoyi/business/entity/PurchaseRegistration.java
@@ -47,11 +47,7 @@
     */
    @TableField(value = "coal_id")
    private Long coalId;
    /**
     * ç…¤ç§ç±»åž‹
     */
    @TableField(value = "coal")
    private String coal;
    /**
     * é‡‡è´­æ•°é‡
     */
main-business/src/main/java/com/ruoyi/business/entity/QrCode.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,34 @@
package com.ruoyi.business.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import com.ruoyi.common.core.domain.MyBaseEntity;
/**
 * äºŒç»´ç ç®¡ç†è¡¨ å®žä½“ç±»
 *
 * @author ld
 * @date 2025-06-24
 */
@Data
@TableName("qr_code")
public class QrCode extends MyBaseEntity {
    private static final long serialVersionUID = 1L;
    /**
     * äºŒç»´ç å”¯ä¸€æ ‡è¯†
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * è®¾å¤‡åç§°
     */
    @TableField(value = "device_name")
    private String deviceName;
    /**
     * æ‰€åœ¨ä½ç½®æè¿°
     */
    @TableField(value = "location")
    private String location;
}
main-business/src/main/java/com/ruoyi/business/entity/QrCodeScanRecord.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
package com.ruoyi.business.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import com.ruoyi.common.core.domain.MyBaseEntity;
import java.time.LocalDateTime;
/**
 * äºŒç»´ç æ‰«ç è®°å½•表 å®žä½“ç±»
 *
 * @author ld
 * @date 2025-06-24
 */
@Data
@TableName("qr_code_scan_record")
public class QrCodeScanRecord extends MyBaseEntity {
    private static final long serialVersionUID = 1L;
    /**
     * æ‰«ç è®°å½•唯一标识
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * å…³è”的二维码ID
     */
    @TableField(value = "qr_code_id")
    private Long qrCodeId;
    /**
     * æ‰«ç äººç”¨æˆ·ID
     */
    @TableField(value = "scanner_id")
    private Long scannerId;
    /**
     * å®žé™…扫码时间
     */
    @TableField(value = "scan_time")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime scanTime;
}
main-business/src/main/java/com/ruoyi/business/mapper/QrCodeMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.ruoyi.business.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.business.entity.QrCode;
import org.apache.ibatis.annotations.Mapper;
/**
 * <p>
 * äºŒç»´ç ç®¡ç†è¡¨ Mapper æŽ¥å£
 * </p>
 *
 * @author ld
 * @since 2025-06-24
 */
@Mapper
public interface QrCodeMapper extends BaseMapper<QrCode> {
}
main-business/src/main/java/com/ruoyi/business/mapper/QrCodeScanRecordMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.ruoyi.business.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.business.entity.QrCodeScanRecord;
import org.apache.ibatis.annotations.Mapper;
/**
 * <p>
 * äºŒç»´ç æ‰«ç è®°å½•表 Mapper æŽ¥å£
 * </p>
 *
 * @author ld
 * @since 2025-06-24
 */
@Mapper
public interface QrCodeScanRecordMapper extends BaseMapper<QrCodeScanRecord> {
}
main-business/src/main/java/com/ruoyi/business/service/QrCodeScanRecordService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
package com.ruoyi.business.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.business.dto.QrCodeScanRecordDto;
import com.ruoyi.business.entity.QrCodeScanRecord;
import com.baomidou.mybatisplus.extension.service.IService;
/**
 * <p>
 * äºŒç»´ç æ‰«ç è®°å½•表 æœåŠ¡ç±»
 * </p>
 *
 * @author ld
 * @since 2025-06-24
 */
public interface QrCodeScanRecordService extends IService<QrCodeScanRecord> {
    IPage<QrCodeScanRecordDto> selectQrCodeScanRecordList(Page<QrCodeScanRecord> page, QrCodeScanRecordDto qrCodeScanRecordDto);
    int addOrEditQrCodeRecord(QrCodeScanRecordDto qrCodeScanRecordDto);
    int delByIds(Long[] ids);
}
main-business/src/main/java/com/ruoyi/business/service/QrCodeService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
package com.ruoyi.business.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.business.dto.QrCodeDto;
import com.ruoyi.business.entity.QrCode;
import com.baomidou.mybatisplus.extension.service.IService;
/**
 * <p>
 * äºŒç»´ç ç®¡ç†è¡¨ æœåŠ¡ç±»
 * </p>
 *
 * @author ld
 * @since 2025-06-24
 */
public interface QrCodeService extends IService<QrCode> {
    IPage<QrCode> selectQrCodeList(Page page, QrCodeDto qrCodeDto);
    Long addOrEditQrCode(QrCodeDto qrCodeDto);
    int delByIds(Long[] ids);
}
main-business/src/main/java/com/ruoyi/business/service/impl/ArchiveServiceImpl.java
@@ -48,6 +48,7 @@
    private final StorageBlobMapper storageBlobMapper;
    private final StorageAttachmentMapper storageAttachmentMapper;
    private final MinioUtils minioUtils;
main-business/src/main/java/com/ruoyi/business/service/impl/PurchaseRegistrationServiceImpl.java
@@ -52,7 +52,7 @@
        LambdaQueryWrapper<PurchaseRegistration> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(purchaseRegistrationDto.getSearchAll())){
            queryWrapper.and(wrapper -> wrapper
                    .like(PurchaseRegistration::getCoal, purchaseRegistrationDto.getSearchAll())
                    .like(PurchaseRegistration::getCoalId, purchaseRegistrationDto.getSearchAll())
                    .or()
                    .like(PurchaseRegistration::getSupplierName, purchaseRegistrationDto.getSearchAll())
            );
@@ -74,7 +74,7 @@
        if (coalInfo == null) {
            throw new BaseException("煤种信息不存在");
        }
        purchaseRegistration.setCoal(coalInfo.getCoal());
//        purchaseRegistration.setCoal(coalInfo.getCoal());
        Supply supply = supplyMapper.selectById(purchaseRegistrationDto.getSupplierId());
        if (supply == null) {
            throw new BaseException("供应商信息不存在");
@@ -109,6 +109,7 @@
        BeanUtils.copyProperties(purchaseRegistration, pendingInventory);
        // è®¾ç½®å¾…入库记录特有的属性(如果有)
        pendingInventory.setCoalId(purchaseRegistration.getCoalId());
        pendingInventory.setInventoryQuantity(purchaseRegistration.getPurchaseQuantity());
        return pendingInventory;
    }
main-business/src/main/java/com/ruoyi/business/service/impl/QrCodeScanRecordServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,189 @@
package com.ruoyi.business.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.basic.entity.StorageAttachment;
import com.ruoyi.basic.entity.StorageBlob;
import com.ruoyi.basic.entity.dto.StorageBlobDTO;
import com.ruoyi.basic.mapper.StorageAttachmentMapper;
import com.ruoyi.basic.mapper.StorageBlobMapper;
import com.ruoyi.basic.service.StorageAttachmentService;
import com.ruoyi.business.dto.QrCodeDto;
import com.ruoyi.business.dto.QrCodeScanRecordDto;
import com.ruoyi.business.entity.Archive;
import com.ruoyi.business.entity.QrCode;
import com.ruoyi.business.entity.QrCodeScanRecord;
import com.ruoyi.business.mapper.QrCodeMapper;
import com.ruoyi.business.mapper.QrCodeScanRecordMapper;
import com.ruoyi.business.service.QrCodeScanRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.file.MinioUtils;
import com.ruoyi.system.mapper.SysUserMapper;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.ruoyi.common.constant.StorageAttachmentConstants.StorageAttachmentFile;
import static com.ruoyi.common.enums.StorageAttachmentRecordType.Archives;
import static com.ruoyi.common.enums.StorageAttachmentRecordType.QrCodeScanRecords;
/**
 * <p>
 * äºŒç»´ç æ‰«ç è®°å½•表 æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author ld
 * @since 2025-06-24
 */
@Service
@RequiredArgsConstructor
public class QrCodeScanRecordServiceImpl extends ServiceImpl<QrCodeScanRecordMapper, QrCodeScanRecord> implements QrCodeScanRecordService {
    private final QrCodeScanRecordMapper qrCodeScanRecordMapper;
    private final QrCodeMapper qrCodeMapper;
    private final StorageAttachmentService storageAttachmentService;
    private final StorageBlobMapper storageBlobMapper;
    private final StorageAttachmentMapper storageAttachmentMapper;
    private final MinioUtils minioUtils;
    private final SysUserMapper sysUserMapper;
    @Override
    public IPage<QrCodeScanRecordDto> selectQrCodeScanRecordList(Page<QrCodeScanRecord> page, QrCodeScanRecordDto qrCodeScanRecordDto) {
        // 1. æž„建基础查询条件
        LambdaQueryWrapper<QrCodeScanRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(QrCodeScanRecord::getCreateTime);
        // 2. æ‰§è¡Œåˆ†é¡µæŸ¥è¯¢
        IPage<QrCodeScanRecord> scanRecordIPage = qrCodeScanRecordMapper.selectPage(page, queryWrapper);
        // 3. æ— æ•°æ®æå‰è¿”回
        if (CollectionUtils.isEmpty(scanRecordIPage.getRecords())) {
            return new Page<>(scanRecordIPage.getCurrent(), scanRecordIPage.getSize(), scanRecordIPage.getTotal());
        }
        // 4. æ‰¹é‡èŽ·å–æ‰€æœ‰è®°å½•ID和二维码ID
        List<Long> recordIds = scanRecordIPage.getRecords().stream()
                .map(QrCodeScanRecord::getId)
                .collect(Collectors.toList());
        Set<Long> qrCodeIds = scanRecordIPage.getRecords().stream()
                .map(QrCodeScanRecord::getQrCodeId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        // 5. æ‰¹é‡æŸ¥è¯¢å…³è”数据(使用最新API)
        // 5.1 æŸ¥è¯¢äºŒç»´ç ä¿¡æ¯ï¼ˆæ›¿æ¢selectBatchIds为selectByIds)
        Map<Long, QrCode> qrCodeMap = qrCodeIds.isEmpty()
                ? Collections.emptyMap()
                : qrCodeMapper.selectByIds(qrCodeIds).stream()
                .collect(Collectors.toMap(QrCode::getId, Function.identity()));
        // 5.2 æŸ¥è¯¢é™„件关联关系
        Map<Long, List<StorageAttachment>> attachmentsMap = storageAttachmentMapper
                .selectList(new LambdaQueryWrapper<StorageAttachment>()
                        .in(StorageAttachment::getRecordId, recordIds)
                        .eq(StorageAttachment::getRecordType, QrCodeScanRecords.ordinal()))
                .stream()
                .collect(Collectors.groupingBy(StorageAttachment::getRecordId));
        // 5.3 æŸ¥è¯¢æ–‡ä»¶æ•°æ®ï¼ˆä½¿ç”¨selectByIds)
        Set<Long> blobIds = attachmentsMap.values().stream()
                .flatMap(List::stream)
                .map(StorageAttachment::getStorageBlobId)
                .collect(Collectors.toSet());
        Map<Long, StorageBlob> blobMap = blobIds.isEmpty()
                ? Collections.emptyMap()
                : storageBlobMapper.selectByIds(blobIds).stream()
                .collect(Collectors.toMap(StorageBlob::getId, Function.identity()));
        // 6. ç»„装DTO数据
        List<QrCodeScanRecordDto> dtoList = scanRecordIPage.getRecords().stream().map(record -> {
            QrCodeScanRecordDto dto = new QrCodeScanRecordDto();
            BeanUtils.copyProperties(record, dto);
            SysUser sysUser = sysUserMapper.selectUserById(record.getScannerId());
            dto.setScanner(sysUser.getNickName());
            // 6.1 è®¾ç½®äºŒç»´ç ä¿¡æ¯
            Optional.ofNullable(qrCodeMap.get(record.getQrCodeId()))
                    .ifPresent(qrCode -> {
                        BeanUtils.copyProperties(qrCode, dto); // å¤åˆ¶åˆ°çˆ¶ç±»
                        dto.setQrCode(qrCode); // è®¾ç½®å®Œæ•´å¯¹è±¡
                    });
            // 6.2 è®¾ç½®é™„件信息
            dto.setStorageBlobDTO(
                    Optional.ofNullable(attachmentsMap.get(record.getId()))
                            .orElse(Collections.emptyList())
                            .stream()
                            .map(att -> {
                                StorageBlobDTO blobDTO = new StorageBlobDTO();
                                Optional.ofNullable(blobMap.get(att.getStorageBlobId()))
                                        .ifPresent(blob -> {
                                            BeanUtils.copyProperties(blob, blobDTO);
                                            blobDTO.setUrl(minioUtils.getPreviewUrls(blob.getBucketFilename(), blob.getBucketName(), true));
                                            blobDTO.setDownloadUrl(minioUtils.getDownloadUrls(blob.getBucketFilename(),blob.getBucketName(),blob.getOriginalFilename(),true));
                                        });
                                return blobDTO;
                            })
                            .filter(blobDTO -> blobDTO.getId() != null) // è¿‡æ»¤æ— æ•ˆé™„ä»¶
                            .collect(Collectors.toList())
            );
            return dto;
        }).collect(Collectors.toList());
        // 7. æž„建返回分页对象
        IPage<QrCodeScanRecordDto> resultPage = new Page<>();
        BeanUtils.copyProperties(scanRecordIPage, resultPage);
        resultPage.setRecords(dtoList);
        return resultPage;
    }
    @Override
    public int addOrEditQrCodeRecord(QrCodeScanRecordDto qrCodeScanRecordDto) {
        QrCodeScanRecord qrCodeScanRecord = new QrCodeScanRecord();
        BeanUtils.copyProperties(qrCodeScanRecordDto, qrCodeScanRecord);
        int i;
        if (Objects.isNull(qrCodeScanRecordDto.getId())) {
            i = qrCodeScanRecordMapper.insert(qrCodeScanRecord);
        } else {
            i = qrCodeScanRecordMapper.updateById(qrCodeScanRecord);
        }
        if (qrCodeScanRecordDto.getStorageBlobDTO() != null && !qrCodeScanRecordDto.getStorageBlobDTO().isEmpty()) {
            List<StorageAttachment> attachments = new ArrayList<>();
            for (StorageBlobDTO storageBlobDTO : qrCodeScanRecordDto.getStorageBlobDTO()) {
                StorageAttachment storageAttachment = new StorageAttachment(
                        StorageAttachmentFile,
                        (long) QrCodeScanRecords.ordinal(),
                        qrCodeScanRecord.getId()
                );
                storageAttachment.setStorageBlobDTO(storageBlobDTO);
                attachments.add(storageAttachment);
            }
            storageAttachmentService.saveStorageAttachment(attachments, qrCodeScanRecord.getId(), QrCodeScanRecords, StorageAttachmentFile);
        }
        return i;
    }
    @Override
    public int delByIds(Long[] ids) {
        return qrCodeScanRecordMapper.deleteByIds(Arrays.asList(ids));
    }
}
main-business/src/main/java/com/ruoyi/business/service/impl/QrCodeServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,56 @@
package com.ruoyi.business.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.business.dto.QrCodeDto;
import com.ruoyi.business.entity.Production;
import com.ruoyi.business.entity.QrCode;
import com.ruoyi.business.mapper.QrCodeMapper;
import com.ruoyi.business.service.QrCodeService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.utils.bean.BeanUtils;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
import java.util.Arrays;
import java.util.Objects;
/**
 * <p>
 * äºŒç»´ç ç®¡ç†è¡¨ æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author ld
 * @since 2025-06-24
 */
@Service
@RequiredArgsConstructor
public class QrCodeServiceImpl extends ServiceImpl<QrCodeMapper, QrCode> implements QrCodeService {
    private final QrCodeMapper qrCodeMapper;
    @Override
    public IPage<QrCode> selectQrCodeList(Page page, QrCodeDto qrCodeDto) {
        LambdaQueryWrapper<QrCode> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(QrCode::getCreateTime);
        return qrCodeMapper.selectPage(page, queryWrapper);
    }
    @Override
    public Long addOrEditQrCode(QrCodeDto qrCodeDto) {
        QrCode qrCode = new QrCode();
        BeanUtils.copyProperties(qrCodeDto, qrCode);
        if (Objects.isNull(qrCodeDto.getId())) {
            qrCodeMapper.insert(qrCode);
        } else {
            qrCodeMapper.updateById(qrCode);
        }
        return qrCode.getId();
    }
    @Override
    public int delByIds(Long[] ids) {
        return qrCodeMapper.deleteByIds(Arrays.asList(ids));
    }
}
main-business/src/main/java/com/ruoyi/business/service/impl/SalesRecordServiceImpl.java
@@ -69,7 +69,7 @@
        officialInventoryMapper.updateById(officialInventory);
        // æž„建销售记录实体
        SalesRecord salesRecord = buildSalesRecord(salesRecordDto,officialInventory.getCoal());
        SalesRecord salesRecord = buildSalesRecord(salesRecordDto,officialInventory.getCoalId());
        // å¤„理新增/更新逻辑
        if (salesRecordDto.getId() == null) {
@@ -94,7 +94,7 @@
        }
    }
    private SalesRecord buildSalesRecord(SalesRecordDto dto,String coal) {
    private SalesRecord buildSalesRecord(SalesRecordDto dto,Long coalId) {
        SalesRecord record = new SalesRecord();
        BeanUtils.copyProperties(dto, record);
@@ -129,7 +129,7 @@
        }
        // ç…¤ç§
        record.setCoal(coal);
        record.setCoalId(coalId);
        return record;
    }
main-business/src/main/resources/db/migration/postgresql/V20250604104500__create_table_pending_inventory.sql
@@ -1,27 +1,28 @@
-- åˆ›å»ºå¾…入库表
CREATE TABLE pending_inventory
(
    id                         BIGSERIAL PRIMARY KEY,                            -- ä¸»é”®ID
    supplier_name              VARCHAR(255)               NOT NULL,              -- ä¾›è´§å•†åç§°
    coal                       VARCHAR(50)                NOT NULL,              -- ç…¤ç§
    unit                       VARCHAR(50)                NOT NULL,              -- å•位
    inventory_quantity         NUMERIC(10,2)              NOT NULL,              -- åº“存数量
    price_including_tax        NUMERIC(10,2)              NOT NULL,              -- å•价(含税)
    total_price_including_tax  NUMERIC(10,2)              NOT NULL,              -- æ€»ä»·ï¼ˆå«ç¨Žï¼‰
    registrant                 VARCHAR(50),                                      -- ç™»è®°äºº
    registration_time          TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP,          -- ç™»è®°æ—¶é—´
    price_excluding_tax        VARCHAR(255),                                     -- å•价(不含税)
    total_price_excluding_tax  VARCHAR(255),                                     -- æ€»ä»·ï¼ˆä¸å«ç¨Žï¼‰
    registrant_id              VARCHAR(32),                                      -- ç™»è®°äººID
    registration_date          DATE,                                             -- ç™»è®°æ—¥æœŸ
    supplier_id                BIGINT,                                           -- ä¾›è´§å•†ID
    coal_id                    BIGINT,                                            -- ç…¤ç§ID
    id                        BIGSERIAL PRIMARY KEY,                  -- ä¸»é”®ID
    supplier_name             VARCHAR(255)   NOT NULL,                -- ä¾›è´§å•†åç§°
    coal                      VARCHAR(50)    NOT NULL,                -- ç…¤ç§
    unit                      VARCHAR(50)    NOT NULL,                -- å•位
    inventory_quantity        NUMERIC(10, 2) NOT NULL,                -- åº“存数量
    price_including_tax       NUMERIC(10, 2) NOT NULL,                -- å•价(含税)
    total_price_including_tax NUMERIC(10, 2) NOT NULL,                -- æ€»ä»·ï¼ˆå«ç¨Žï¼‰
    registrant                VARCHAR(50),                            -- ç™»è®°äºº
    registration_time         TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP, -- ç™»è®°æ—¶é—´
    price_excluding_tax       VARCHAR(255),                           -- å•价(不含税)
    total_price_excluding_tax VARCHAR(255),                           -- æ€»ä»·ï¼ˆä¸å«ç¨Žï¼‰
    registrant_id             VARCHAR(32),                            -- ç™»è®°äººID
    registration_date         DATE,                                   -- ç™»è®°æ—¥æœŸ
    supplier_id               BIGINT,                                 -- ä¾›è´§å•†ID
    coal_id                   BIGINT,                                 -- ç…¤ç§ID
    master_id                 BIGINT,                                 -- ç”Ÿäº§åŠ å·¥id
    deleted                    INTEGER         DEFAULT 0,                        -- è½¯åˆ é™¤æ ‡å¿—,0=未删除,1=已删除
    create_by                  VARCHAR(255),                                     -- åˆ›å»ºè¯¥è®°å½•的用户
    create_time                TIMESTAMP(6),                                     -- è®°å½•创建时间
    update_by                  VARCHAR(255),                                     -- æœ€åŽä¿®æ”¹è¯¥è®°å½•的用户
    update_time                TIMESTAMP(6)                                     -- è®°å½•最后更新时间
    deleted                   INTEGER      DEFAULT 0,                 -- è½¯åˆ é™¤æ ‡å¿—,0=未删除,1=已删除
    create_by                 VARCHAR(255),                           -- åˆ›å»ºè¯¥è®°å½•的用户
    create_time               TIMESTAMP(6),                           -- è®°å½•创建时间
    update_by                 VARCHAR(255),                           -- æœ€åŽä¿®æ”¹è¯¥è®°å½•的用户
    update_time               TIMESTAMP(6)                            -- è®°å½•最后更新时间
);
@@ -43,6 +44,7 @@
COMMENT ON COLUMN pending_inventory.registration_date IS '登记日期';
COMMENT ON COLUMN pending_inventory.supplier_id IS '供货商ID';
COMMENT ON COLUMN pending_inventory.coal_id IS '煤种ID';
COMMENT ON COLUMN pending_inventory.master_id IS '生产加工id';
COMMENT ON COLUMN pending_inventory.deleted IS '软删除标志,0=未删除,1=已删除';
COMMENT ON COLUMN pending_inventory.create_by IS '创建该记录的用户';
main-business/src/main/resources/db/migration/postgresql/V20250604111200__create_table_official_inventory.sql
@@ -3,7 +3,7 @@
(
    id                        BIGSERIAL PRIMARY KEY,             -- ä¸»é”®ID
    supplier_name             VARCHAR(255)   NOT NULL,           -- ä¾›è´§å•†åç§°
    coal                      VARCHAR(50)    NOT NULL,           -- ç…¤ç§
    coal_id                   BIGINT         NOT NULL,           -- ç…¤ç§
    unit                      VARCHAR(50)    NOT NULL,           -- å•位
    inventory_quantity        DECIMAL(10, 0),                    -- åº“存数量
    price_including_tax       DECIMAL(10, 2) NOT NULL,           -- å•价(含税)
@@ -14,7 +14,7 @@
    registrant_id             VARCHAR(50)    NOT NULL,           -- ç™»è®°äººid
    type                      VARCHAR(50),                       -- ç±»åž‹       1 é‡‡è´­/ 2 æ­£å¼   å…¥åº“
    pending_id                BIGINT,                            -- å¾…入库id
    merge_id                  VARCHAR(255),                            -- åˆå¹¶id
    merge_id                  VARCHAR(255),                      -- åˆå¹¶id
    registration_date         TIMESTAMP WITHOUT TIME ZONE,
    deleted                   INT            NOT NULL DEFAULT 0, -- è½¯åˆ é™¤æ ‡å¿—:0=未删除,1=已删除
@@ -30,7 +30,7 @@
-- æ·»åŠ å­—æ®µæ³¨é‡Š
COMMENT ON COLUMN official_inventory.id IS '主键ID';
COMMENT ON COLUMN official_inventory.supplier_name IS '供货商名称';
COMMENT ON COLUMN official_inventory.coal IS '煤种';
COMMENT ON COLUMN official_inventory.coal_id IS '煤种id';
COMMENT ON COLUMN official_inventory.unit IS '单位';
COMMENT ON COLUMN official_inventory.inventory_quantity IS '库存数量';
COMMENT ON COLUMN official_inventory.price_including_tax IS '单价(含税)';
main-business/src/main/resources/db/migration/postgresql/V20250624092100__create_table_qr_code.sql
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
-- åˆ›å»ºäºŒç»´ç ç®¡ç†è¡¨
CREATE TABLE qr_code
(
    id            BIGSERIAL PRIMARY KEY,       -- ID (主键,自增长)
    device_name   VARCHAR(255),                -- è®¾å¤‡åç§°
    location      VARCHAR(255),                        -- åœ°ç‚¹
    deleted       INT NOT NULL DEFAULT 0,      -- è½¯åˆ é™¤æ ‡å¿—:0=未删除,1=已删除
    create_by     VARCHAR(255),                -- åˆ›å»ºäººç”¨æˆ·å
    create_time   TIMESTAMP WITHOUT TIME ZONE, -- åˆ›å»ºæ—¶é—´ï¼Œé»˜è®¤å½“前时间
    update_by     VARCHAR(255),                -- æœ€åŽæ›´æ–°äººç”¨æˆ·å
    update_time   TIMESTAMP WITHOUT TIME ZONE  -- æœ€åŽæ›´æ–°æ—¶é—´ï¼Œé»˜è®¤å½“前时间
);
-- æ·»åŠ è¡¨æ³¨é‡Š
COMMENT ON TABLE qr_code IS '二维码管理表';
-- æ·»åŠ å­—æ®µæ³¨é‡Š
COMMENT ON COLUMN qr_code.id IS '二维码唯一标识';
COMMENT ON COLUMN qr_code.device_name IS '设备名称';
COMMENT ON COLUMN qr_code.location IS '所在位置描述';
COMMENT ON COLUMN qr_code.deleted IS '软删除标志,0=未删除,1=已删除';
COMMENT ON COLUMN qr_code.create_by IS '创建该记录的用户';
COMMENT ON COLUMN qr_code.create_time IS '记录创建时间';
COMMENT ON COLUMN qr_code.update_by IS '最后修改该记录的用户';
COMMENT ON COLUMN qr_code.update_time IS '记录最后更新时间';
main-business/src/main/resources/db/migration/postgresql/V20250624092400__create_table_qr_code_scan_record.sql
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,29 @@
-- åˆ›å»ºäºŒç»´ç æ‰«ç è®°å½•表
CREATE TABLE qr_code_scan_record
(
    id            BIGSERIAL PRIMARY KEY,       -- ID (主键,自增长)
    qr_code_id    BIGINT,                      -- å…³è”的二维码ID
    scanner_id    BIGINT,                      -- æ‰«ç äººID
    scan_time     TIMESTAMP WITHOUT TIME ZONE, -- æ‰«ç æ—¶é—´
    deleted       INT NOT NULL DEFAULT 0,      -- è½¯åˆ é™¤æ ‡å¿—:0=未删除,1=已删除
    create_by     VARCHAR(255),                -- åˆ›å»ºäººç”¨æˆ·å
    create_time   TIMESTAMP WITHOUT TIME ZONE, -- åˆ›å»ºæ—¶é—´ï¼Œé»˜è®¤å½“前时间
    update_by     VARCHAR(255),                -- æœ€åŽæ›´æ–°äººç”¨æˆ·å
    update_time   TIMESTAMP WITHOUT TIME ZONE -- æœ€åŽæ›´æ–°æ—¶é—´ï¼Œé»˜è®¤å½“前时间
);
-- æ·»åŠ è¡¨æ³¨é‡Š
COMMENT ON TABLE qr_code_scan_record IS '二维码扫码记录表';
-- æ·»åŠ å­—æ®µæ³¨é‡Š
COMMENT ON COLUMN qr_code_scan_record.id IS '扫码记录唯一标识';
COMMENT ON COLUMN qr_code_scan_record.qr_code_id IS '关联的二维码ID';
COMMENT ON COLUMN qr_code_scan_record.scanner_id IS '扫码人用户ID';
COMMENT ON COLUMN qr_code_scan_record.scan_time IS '实际扫码时间';
COMMENT ON COLUMN qr_code_scan_record.deleted IS '软删除标志,0=未删除,1=已删除';
COMMENT ON COLUMN qr_code_scan_record.create_by IS '创建该记录的用户';
COMMENT ON COLUMN qr_code_scan_record.create_time IS '记录创建时间';
COMMENT ON COLUMN qr_code_scan_record.update_by IS '最后修改该记录的用户';
COMMENT ON COLUMN qr_code_scan_record.update_time IS '记录最后更新时间';
main-business/src/main/resources/mapper/PendingInventoryMapper.xml
@@ -11,7 +11,7 @@
        <result column="update_by" property="updateBy"/>
        <result column="update_time" property="updateTime"/>
        <result column="supplier_name" property="supplierName"/>
        <result column="coal" property="coal"/>
        <result column="coal_id" property="coalId"/>
        <result column="unit" property="unit"/>
        <result column="inventory_quantity" property="inventoryQuantity"/>
        <result column="price_including_tax" property="priceIncludingTax"/>
@@ -27,7 +27,7 @@
                create_time,
                update_by,
                update_time,
            id, supplier_name, coal, unit, inventory_quantity, price_including_tax, total_price_including_tax, registrant, registration_time
            id, supplier_name,coal_id, unit, inventory_quantity, price_including_tax, total_price_including_tax, registrant, registration_time
        </sql>
    <select id="getPendingInventoryForUpdateById" resultType="com.ruoyi.business.entity.PendingInventory">
main-business/src/main/resources/mapper/PurchaseRegistrationMapper.xml
@@ -14,7 +14,6 @@
                    <result column="supplier_name" property="supplierName" />
                    <result column="unit" property="unit" />
                    <result column="coal_id" property="coalId" />
                    <result column="coal" property="coal" />
                    <result column="purchase_quantity" property="purchaseQuantity" />
                    <result column="price_including_tax" property="priceIncludingTax" />
                    <result column="total_price_including_tax" property="totalPriceIncludingTax" />
main-business/src/main/resources/mapper/QrCodeMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.business.mapper.QrCodeMapper">
        <!-- é€šç”¨æŸ¥è¯¢æ˜ å°„结果 -->
        <resultMap id="BaseResultMap" type="com.ruoyi.business.entity.QrCode">
                    <id column="id" property="id" />
                <result column="deleted" property="deleted" />
                <result column="create_by" property="createBy" />
                <result column="create_time" property="createTime" />
                <result column="update_by" property="updateBy" />
                <result column="update_time" property="updateTime" />
                    <result column="device_name" property="deviceName" />
                    <result column="location" property="location" />
        </resultMap>
        <!-- é€šç”¨æŸ¥è¯¢ç»“果列 -->
        <sql id="Base_Column_List">
                deleted,
                create_by,
                create_time,
                update_by,
                update_time,
            id, device_name, location
        </sql>
</mapper>
main-business/src/main/resources/mapper/QrCodeScanRecordMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.business.mapper.QrCodeScanRecordMapper">
        <!-- é€šç”¨æŸ¥è¯¢æ˜ å°„结果 -->
        <resultMap id="BaseResultMap" type="com.ruoyi.business.entity.QrCodeScanRecord">
                    <id column="id" property="id" />
                <result column="deleted" property="deleted" />
                <result column="create_by" property="createBy" />
                <result column="create_time" property="createTime" />
                <result column="update_by" property="updateBy" />
                <result column="update_time" property="updateTime" />
                    <result column="qr_code_id" property="qrCodeId" />
                    <result column="scanner_id" property="scannerId" />
                    <result column="scan_time" property="scanTime" />
        </resultMap>
        <!-- é€šç”¨æŸ¥è¯¢ç»“果列 -->
        <sql id="Base_Column_List">
                deleted,
                create_by,
                create_time,
                update_by,
                update_time,
            id, qr_code_id, scanner_id, scan_time
        </sql>
</mapper>
ruoyi-common/src/main/java/com/ruoyi/common/enums/StorageAttachmentRecordType.java
@@ -1,27 +1,23 @@
package com.ruoyi.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
 * é™„件记录类型枚举
 *
 */
@Getter
@AllArgsConstructor
public enum StorageAttachmentRecordType {
    // ä¾‹å­ å®žé™…开发请删除
    Template("Template","范例"),
    Archives("Archives","文档管理"),
    InspectionTasks("InspectionTasks","生产巡检");
    InspectionTasks("InspectionTasks","生产巡检"),
    QrCodeScanRecords("QrCodeScanRecords","二维码扫码记录文件");
    private final String code;
    private final String info;
    public String getCode() {
        return code;
    }
    public String getInfo() {
        return info;
    }
}