1.正式库导出优化 2.销售导出 3.设备使用状态优化 4.定时任务优化
已修改20个文件
已添加3个文件
778 ■■■■■ 文件已修改
main-business/src/main/java/com/ruoyi/business/controller/OfficialInventoryController.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/controller/SalesRecordController.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/dto/OfficialInventoryDto.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/dto/SalesRecordDto.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/entity/EquipmentManagement.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/entity/EquipmentUsageRecord.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/entity/InspectionTask.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/entity/SalesRecord.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/service/OfficialInventoryService.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/service/SalesRecordService.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/service/impl/EquipmentManagementServiceImpl.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/service/impl/EquipmentUsageRecordServiceImpl.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/service/impl/OfficialInventoryServiceImpl.java 196 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/service/impl/SalesRecordServiceImpl.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/task/TimingTaskJob.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/utils/DynamicExcelUtil.java 200 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/vo/OfficialInventoryExportVo.java 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/vo/SalesRecordExportVo.java 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/resources/db/migration/postgresql/V20250611160300__create_table_sales_record.sql 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/resources/db/migration/postgresql/V20250614134700__create_table_inspection_task.sql 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/resources/db/migration/postgresql/V20250701142700__create_table_equipment_management.sql 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/resources/db/migration/postgresql/V20250707155600__create_table_equipment_usage_record.sql 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/controller/OfficialInventoryController.java
@@ -3,10 +3,12 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.business.dto.OfficialInventoryDto;
import com.ruoyi.business.dto.SalesRecordDto;
import com.ruoyi.business.entity.OfficialInventory;
import com.ruoyi.business.service.OfficialInventoryService;
import com.ruoyi.business.vo.OfficialInventoryVo;
import com.ruoyi.common.core.domain.R;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
@@ -79,4 +81,12 @@
    public R<List<OfficialInventoryDto>> coalBlendingList() {
        return R.ok(officialInventoryService.coalBlendingList());
    }
    /**
     * æ­£å¼åº“记录表导出
     */
    @PostMapping("/export")
    public void officialInventoryExport(HttpServletResponse response, OfficialInventoryDto officialInventoryDto) {
        officialInventoryService.officialInventoryExport(response, officialInventoryDto);
    }
}
main-business/src/main/java/com/ruoyi/business/controller/SalesRecordController.java
@@ -2,10 +2,12 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.basic.dto.SupplyDto;
import com.ruoyi.business.dto.SalesRecordDto;
import com.ruoyi.business.entity.SalesRecord;
import com.ruoyi.business.service.SalesRecordService;
import com.ruoyi.common.core.domain.R;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
@@ -49,4 +51,12 @@
    public R remove(@RequestBody Long[] ids) {
        return R.ok(salesRecordService.delByIds(ids));
    }
    /**
     * é”€å”®è®°å½•表导出
     */
    @PostMapping("/export")
    public void salesRecordExport(HttpServletResponse response, SalesRecordDto salesRecordDto) {
        salesRecordService.salesRecordExport(response, salesRecordDto);
    }
}
main-business/src/main/java/com/ruoyi/business/dto/OfficialInventoryDto.java
@@ -24,4 +24,7 @@
    private List<Map<String, String>> coalValues; //媒质方案字段值
    private List<Long> exportIds;//导出选中的id
}
main-business/src/main/java/com/ruoyi/business/dto/SalesRecordDto.java
@@ -3,8 +3,12 @@
import com.ruoyi.business.entity.SalesRecord;
import lombok.Data;
import java.util.List;
@Data
public class SalesRecordDto extends SalesRecord {
    private String coal;
    private List<Long> exportIds;//导出选中的id
}
main-business/src/main/java/com/ruoyi/business/entity/EquipmentManagement.java
@@ -76,4 +76,9 @@
     */
    @TableField(value = "purchase_price")
    private BigDecimal purchasePrice;
    /**
     * æ˜¯å¦è€—材类
     */
    @TableField(value = "is_consumables")
    private boolean isConsumables;
}
main-business/src/main/java/com/ruoyi/business/entity/EquipmentUsageRecord.java
@@ -44,10 +44,10 @@
    @TableField(value = "department_id")
    private Long departmentId;
    /**
     * è®¾å¤‡çŠ¶æ€ï¼ˆä½¿ç”¨ä¸­ï¼Œå·²å½’è¿˜ï¼‰
     * è®¾å¤‡çŠ¶æ€ï¼ˆ1使用中,2已归还)
     */
    @TableField(value = "equipment_status")
    private String equipmentStatus;
    private Integer equipmentStatus;
    /**
     * ä½¿ç”¨å¼€å§‹æ—¶é—´
     */
main-business/src/main/java/com/ruoyi/business/entity/InspectionTask.java
@@ -61,4 +61,9 @@
     */
    @TableField(value = "frequency_type")
    private String frequencyType;
    /**
     * æ—¶é—´ç»†èŠ‚
     */
    @TableField(value = "frequency_detail")
    private String frequencyDetail;
}
main-business/src/main/java/com/ruoyi/business/entity/SalesRecord.java
@@ -5,6 +5,7 @@
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.MyBaseEntity;
import lombok.Data;
@@ -33,6 +34,7 @@
     */
    @TableField(value = "sale_date")
    @JsonFormat(pattern = "yyyy-MM-dd")
    @Excel(name = "销售日期")
    private LocalDate saleDate;
    /**
     * å®¢æˆ·id
@@ -120,4 +122,9 @@
    @TableField(value = "registration_date")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private LocalDate registrationDate;
    /**
     * æ˜¯å¦æ·»åŠ è‡³å¾…è¡¥åº“
     */
    @TableField(value = "is_add")
    private boolean isAdd;
}
main-business/src/main/java/com/ruoyi/business/service/OfficialInventoryService.java
@@ -6,6 +6,7 @@
import com.ruoyi.business.entity.OfficialInventory;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.business.vo.OfficialInventoryVo;
import jakarta.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.List;
@@ -34,4 +35,6 @@
    Map<String, BigDecimal> selectOfficialAllInfo();
    List<OfficialInventoryDto> coalBlendingList();
    void officialInventoryExport(HttpServletResponse response, OfficialInventoryDto officialInventoryDto);
}
main-business/src/main/java/com/ruoyi/business/service/SalesRecordService.java
@@ -6,6 +6,7 @@
import com.ruoyi.business.dto.SalesRecordDto;
import com.ruoyi.business.dto.YearlyQueryDto;
import com.ruoyi.business.entity.SalesRecord;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import java.util.Map;
@@ -29,4 +30,6 @@
    Map<String, Object> selectAllInfo();
    Map<String, Object> getYearlyMonthlySales(@Valid YearlyQueryDto query);
    void salesRecordExport(HttpServletResponse response, SalesRecordDto salesRecordDto);
}
main-business/src/main/java/com/ruoyi/business/service/impl/EquipmentManagementServiceImpl.java
@@ -70,7 +70,8 @@
                    // æŸ¥è¯¢è¯¥è®¾å¤‡çš„使用总量(usageQuantity)
                    LambdaQueryWrapper<EquipmentUsageRecord> usageQueryWrapper = new LambdaQueryWrapper<>();
                    usageQueryWrapper.eq(EquipmentUsageRecord::getEquipmentId, entity.getId());
                    usageQueryWrapper.eq(EquipmentUsageRecord::getEquipmentId, entity.getId())
                            .eq(EquipmentUsageRecord::getEquipmentStatus, 1);
                    // è®¡ç®—总使用量
                    Integer totalUsage = equipmentUsageRecordMapper.selectList(usageQueryWrapper).stream()
main-business/src/main/java/com/ruoyi/business/service/impl/EquipmentUsageRecordServiceImpl.java
@@ -85,7 +85,6 @@
            }
            return dto;
        }).toList();
        dtoPage.setRecords(dtoRecords);
        return dtoPage;
    }
@@ -125,46 +124,54 @@
            // è®¾ç½®ä½¿ç”¨å¼€å§‹æ—¶é—´ä¸ºå½“前时间
            equipmentUsageRecord.setUsageStartTime(LocalDate.now());
            // å¦‚果状态为1(已归还),则设置结束时间
            if ("1".equals(equipmentUsageRecordDto.getEquipmentStatus())) {
                equipmentUsageRecord.setUsageEndTime(LocalDate.now());
            }
            return equipmentUsageRecordMapper.insert(equipmentUsageRecord);
        }
        // æ›´æ–°è®°å½•逻辑
        else {
            // 1. æŸ¥è¯¢åŽŸé¢†ç”¨è®°å½•
        } else {
            // ç¼–辑记录逻辑
            EquipmentUsageRecord originalRecord = equipmentUsageRecordMapper.selectById(equipmentUsageRecordDto.getId());
            if (originalRecord == null) {
                throw new RuntimeException("领用记录不存在");
            }
            // 2. è®¡ç®—库存变化量(新数量 - æ—§æ•°é‡ï¼‰
            int quantityDelta = newUsageQuantity - originalRecord.getUsageQuantity();
            // å¤„理归还逻辑
            if (equipmentUsageRecordDto.getEquipmentStatus() == 2) {
                // æ£€æŸ¥å½’还数量是否合法
                if (newUsageQuantity > originalRecord.getUsageQuantity()) {
                    throw new RuntimeException("归还数量不能超过原领用数量");
                }
            if (quantityDelta != 0) {
                // 3. æ£€æŸ¥è°ƒæ•´åŽåº“存是否充足
                int newInventory = equipment.getQuantity() - quantityDelta;
                // è®¡ç®—实际归还数量(原领用数量 - æ–°é¢†ç”¨æ•°é‡ï¼‰
                int returnedQuantity = originalRecord.getUsageQuantity() - newUsageQuantity;
                // æ¢å¤éƒ¨åˆ†åº“å­˜
                equipment.setQuantity(equipment.getQuantity() + returnedQuantity);
                equipmentManagementMapper.updateById(equipment);
                // å¦‚果全部归还,设置归还时间
                if (newUsageQuantity == 0) {
                    equipmentUsageRecord.setUsageEndTime(LocalDate.now());
                }
                return equipmentUsageRecordMapper.updateById(equipmentUsageRecord);
            }
            // å¤„理普通编辑逻辑(非归还状态)
            if (!newUsageQuantity.equals(originalRecord.getUsageQuantity())) {
                // è®¡ç®—库存变化量(旧数量 - æ–°æ•°é‡ï¼‰
                int quantityDelta = originalRecord.getUsageQuantity() - newUsageQuantity;
                // æ£€æŸ¥è°ƒæ•´åŽåº“存是否充足
                int newInventory = equipment.getQuantity() + quantityDelta;
                if (newInventory < 0) {
                    throw new RuntimeException("库存不足,调整后库存将为:" + newInventory);
                }
                // 4. è°ƒæ•´åº“å­˜
                // è°ƒæ•´åº“å­˜
                equipment.setQuantity(newInventory);
                if (equipmentManagementMapper.updateById(equipment) == 0) {
                    throw new RuntimeException("库存更新失败,可能已被其他操作修改");
                }
            }
            // 5. å¦‚果状态变为1(已归还),则设置结束时间为当前时间
            if ("1".equals(equipmentUsageRecordDto.getEquipmentStatus()) &&
                    (originalRecord.getEquipmentStatus() == null || !"1".equals(originalRecord.getEquipmentStatus()))) {
                equipmentUsageRecord.setUsageEndTime(LocalDate.now());
            }
            // 6. æ›´æ–°é¢†ç”¨è®°å½•
            // æ›´æ–°é¢†ç”¨è®°å½•
            return equipmentUsageRecordMapper.updateById(equipmentUsageRecord);
        }
    }
main-business/src/main/java/com/ruoyi/business/service/impl/OfficialInventoryServiceImpl.java
@@ -15,16 +15,24 @@
import com.ruoyi.basic.mapper.CoalValueMapper;
import com.ruoyi.basic.mapper.SupplyMapper;
import com.ruoyi.business.dto.OfficialInventoryDto;
import com.ruoyi.business.dto.SalesRecordDto;
import com.ruoyi.business.entity.OfficialInventory;
import com.ruoyi.business.entity.SalesRecord;
import com.ruoyi.business.mapper.OfficialInventoryMapper;
import com.ruoyi.business.service.OfficialInventoryService;
import com.ruoyi.business.utils.DynamicExcelUtil;
import com.ruoyi.business.vo.OfficialInventoryExportVo;
import com.ruoyi.business.vo.OfficialInventoryVo;
import com.ruoyi.business.vo.SalesRecordExportVo;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.mapper.SysUserMapper;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -43,6 +51,7 @@
 * @since 2025-06-04
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class OfficialInventoryServiceImpl extends ServiceImpl<OfficialInventoryMapper, OfficialInventory> implements OfficialInventoryService {
@@ -355,6 +364,160 @@
    }
    @Override
    public void officialInventoryExport(HttpServletResponse response, OfficialInventoryDto officialInventoryDto) {
        try {
            // èŽ·å–ç…¤è´¨å­—æ®µé…ç½®
            List<CoalField> allCoalFields = coalFieldMapper.selectList(null);
            List<String> dynamicHeaders = allCoalFields.stream()
                    .map(CoalField::getFieldName)
                    .collect(Collectors.toList());
            // èŽ·å–æ•°æ®
            List<OfficialInventory> list = officialInventoryDto.getExportIds() != null && !officialInventoryDto.getExportIds().isEmpty()
                    ? officialInventoryMapper.selectByIds(officialInventoryDto.getExportIds())
                    : officialInventoryMapper.selectList(null);
            // è½¬æ¢ä¸ºå¯¼å‡ºVO
            List<OfficialInventoryExportVo> exportData = convertToExportVo(list, allCoalFields);
            // ä½¿ç”¨å¢žå¼ºçš„Excel工具导出
            DynamicExcelUtil<OfficialInventoryExportVo> util =
                    new DynamicExcelUtil<>(OfficialInventoryExportVo.class, dynamicHeaders);
            // å¯¼å‡ºExcel
            util.exportExcel(response, exportData, "库存数据");
        } catch (Exception e) {
            log.error("库存导出失败", e);
            // å¯ä»¥è€ƒè™‘返回更友好的错误信息给前端
            throw new RuntimeException("导出失败: " + e.getMessage());
        }
    }
    private List<OfficialInventoryExportVo> convertToExportVo(List<OfficialInventory> list, List<CoalField> coalFields) {
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        // æ”¶é›†æ‰€æœ‰éœ€è¦æŸ¥è¯¢çš„ID
        Set<Long> coalIds = list.stream()
                .map(OfficialInventory::getCoalId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        Set<Long> supplierIds = list.stream()
                .map(OfficialInventory::getSupplierId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        Set<Long> registrantIds = list.stream()
                .map(OfficialInventory::getRegistrantId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        Set<Long> planIds = list.stream()
                .map(OfficialInventory::getCoalPlanId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        // æ‰¹é‡æŸ¥è¯¢å…³è”数据
        Map<Long, CoalInfo> coalInfoMap = getCoalInfoMap(coalIds);
        Map<Long, Supply> supplyMap = getSupplyMap(supplierIds);
        Map<Long, SysUser> userMap = getUserMap(registrantIds);
        Map<Long, List<CoalValue>> coalValuesMap = getCoalValuesMap(planIds);
        // æž„建字段ID到字段名称的映射,提高查找效率
        Map<String, String> fieldIdToNameMap = coalFields.stream()
                .collect(Collectors.toMap(CoalField::getFields, CoalField::getFieldName));
        // è½¬æ¢æ•°æ®
        return list.stream().map(record -> {
            OfficialInventoryExportVo vo = new OfficialInventoryExportVo();
            vo.initDynamicFields(); // åˆå§‹åŒ–
            // è®¾ç½®åŸºç¡€å±žæ€§
            BeanUtils.copyProperties(record, vo);
            // è®¾ç½®å…³è”信息
            setCoalInfo(vo, record.getCoalId(), coalInfoMap);
            setSupplierInfo(vo, record.getSupplierId(), supplyMap);
            setUserMapInfo(vo, record.getRegistrantId(), userMap);
            // åŠ¨æ€å­—æ®µå¤„ç†
            if (record.getCoalPlanId() != null) {
                List<CoalValue> values = coalValuesMap.getOrDefault(record.getCoalPlanId(), Collections.emptyList());
                setDynamicFields(vo, values, fieldIdToNameMap);
            }
            return vo;
        }).collect(Collectors.toList());
    }
    private void setCoalInfo(OfficialInventoryExportVo vo, Long coalId, Map<Long, CoalInfo> coalInfoMap) {
        if (coalId != null && coalInfoMap.containsKey(coalId)) {
            vo.setCoal(coalInfoMap.get(coalId).getCoal());
        }
    }
    private void setSupplierInfo(OfficialInventoryExportVo vo, Long supplierId, Map<Long, Supply> supplyMap) {
        if (supplierId != null && supplyMap.containsKey(supplierId)) {
            vo.setSupplierName(supplyMap.get(supplierId).getSupplierName());
        }
    }
    private void setUserMapInfo(OfficialInventoryExportVo vo, Long registrantId, Map<Long, SysUser> userMap) {
        if (registrantId != null && userMap.containsKey(registrantId)) {
            vo.setRegistrant(userMap.get(registrantId).getNickName());
        }
    }
    private void setDynamicFields(OfficialInventoryExportVo vo, List<CoalValue> values, Map<String, String> fieldIdToNameMap) {
        for (CoalValue value : values) {
            String fieldName = fieldIdToNameMap.get(value.getFields());
            if (fieldName != null) {
                vo.getCoalQualityProperties().put(fieldName, value.getCoalValue());
            }
        }
    }
    private Map<Long, List<CoalValue>> getCoalValuesMap(Set<Long> planIds) {
        if (CollectionUtils.isEmpty(planIds)) {
            return Collections.emptyMap();
        }
        List<CoalValue> allValues = coalValueMapper.selectList(
                new LambdaQueryWrapper<CoalValue>()
                        .in(CoalValue::getPlanId, planIds));
        return allValues.stream()
                .collect(Collectors.groupingBy(CoalValue::getPlanId));
    }
    private Map<Long, CoalInfo> getCoalInfoMap(Set<Long> coalIds) {
        if (CollectionUtils.isEmpty(coalIds)) {
            return Collections.emptyMap();
        }
        return coalInfoMapper.selectByIds(coalIds).stream()
                .collect(Collectors.toMap(CoalInfo::getId, Function.identity()));
    }
    private Map<Long, Supply> getSupplyMap(Set<Long> supplierIds) {
        if (CollectionUtils.isEmpty(supplierIds)) {
            return Collections.emptyMap();
        }
        return supplyMapper.selectByIds(supplierIds).stream()
                .collect(Collectors.toMap(Supply::getId, Function.identity()));
    }
    private Map<Long, SysUser> getUserMap(Set<Long> registrantIds) {
        if (CollectionUtils.isEmpty(registrantIds)) {
            return Collections.emptyMap();
        }
        return sysUserMapper.selectBatchIds(registrantIds).stream()
                .collect(Collectors.toMap(SysUser::getUserId, Function.identity()));
    }
    @Override
    public List<OfficialInventoryDto> coalBlendingList() {
        // 1. æŸ¥è¯¢åŸºç¡€åº“存数据
        List<OfficialInventory> officialInventories = officialInventoryMapper.selectList(null);
@@ -369,16 +532,33 @@
            planIds.add(inventory.getCoalPlanId());
        });
        // 3. æ‰¹é‡æŸ¥è¯¢å…³è”数据
        Map<Long, CoalInfo> coalInfoMap = coalInfoMapper.selectByIds(coalIds).stream()
                .collect(Collectors.toMap(CoalInfo::getId, Function.identity()));
        Map<Long, CoalInfo> coalInfoMap;
        if (!coalIds.isEmpty()) {
            coalInfoMap = coalInfoMapper.selectByIds(coalIds).stream()
                    .collect(Collectors.toMap(CoalInfo::getId, Function.identity()));
        } else {
            coalInfoMap = new HashMap<>();
        }
        Map<Long, Supply> supplyMap = supplyMapper.selectByIds(supplierIds).stream()
                .collect(Collectors.toMap(Supply::getId, Function.identity()));
        Map<Long, Supply> supplyMap;
        if (!supplierIds.isEmpty()) {
            supplyMap = supplyMapper.selectByIds(supplierIds).stream()
                    .collect(Collectors.toMap(Supply::getId, Function.identity()));
        } else {
            supplyMap = new HashMap<>();
            log.warn("supplierIds ä¸ºç©ºï¼Œè·³è¿‡æŸ¥è¯¢ Supply");
        }
        Map<Long, List<CoalValue>> coalValuesMap = coalValueMapper.selectList(
                        new LambdaQueryWrapper<CoalValue>().in(CoalValue::getPlanId, planIds))
                .stream()
                .collect(Collectors.groupingBy(CoalValue::getPlanId));
        Map<Long, List<CoalValue>> coalValuesMap;
        if (!planIds.isEmpty()) {
            coalValuesMap = coalValueMapper.selectList(
                            new LambdaQueryWrapper<CoalValue>().in(CoalValue::getPlanId, planIds))
                    .stream()
                    .collect(Collectors.groupingBy(CoalValue::getPlanId));
        } else {
            coalValuesMap = new HashMap<>();
            log.warn("planIds ä¸ºç©ºï¼Œè·³è¿‡æŸ¥è¯¢ CoalValue");
        }
        // 4. ç»„装DTO
        return officialInventories.stream()
                .map(inventory -> {
main-business/src/main/java/com/ruoyi/business/service/impl/SalesRecordServiceImpl.java
@@ -4,10 +4,12 @@
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.basic.entity.CoalInfo;
import com.ruoyi.basic.entity.Customer;
import com.ruoyi.basic.entity.Supply;
import com.ruoyi.basic.mapper.CoalInfoMapper;
import com.ruoyi.basic.mapper.CustomerMapper;
import com.ruoyi.business.dto.SalesRecordDto;
@@ -17,12 +19,16 @@
import com.ruoyi.business.mapper.OfficialInventoryMapper;
import com.ruoyi.business.mapper.SalesRecordMapper;
import com.ruoyi.business.service.SalesRecordService;
import com.ruoyi.business.vo.SalesRecordExportVo;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.mapper.SysUserMapper;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -51,6 +57,7 @@
 * @since 2025-06-11
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class SalesRecordServiceImpl extends ServiceImpl<SalesRecordMapper, SalesRecord> implements SalesRecordService {
@@ -155,7 +162,10 @@
            throw new BaseException("销售数量不能大于库存数量");
        }
        officialInventory.setInventoryQuantity(officialInventory.getInventoryQuantity().subtract(salesRecordDto.getSaleQuantity()));
        officialInventory.setPendingReplenishment(salesRecordDto.getSaleQuantity());
        if (salesRecordDto.isAdd()){
            officialInventory.setPendingReplenishment(salesRecordDto.getSaleQuantity());
        }
        officialInventoryMapper.updateById(officialInventory);
        // æž„建销售记录实体
@@ -193,7 +203,7 @@
        if (registrant == null) {
            throw new BaseException("登记人信息不存在");
        }
        record.setRegistrant(registrant.getUserName());
        record.setRegistrant(registrant.getNickName());
        // è®¾ç½®å®¢æˆ·ä¿¡æ¯
        Customer customer = customerMapper.selectById(dto.getCustomerId());
@@ -255,6 +265,59 @@
    }
    @Override
    public void salesRecordExport(HttpServletResponse response, SalesRecordDto salesRecordDto) {
        List<Long> ids = salesRecordDto.getExportIds();
        List<SalesRecord> list;
        if (ids != null && !ids.isEmpty()) {
            list = salesRecordMapper.selectByIds(ids);
        } else {
            list = salesRecordMapper.selectList(null);
        }
        List<SalesRecordExportVo> exportData = convertToExportVo(list);
        ExcelUtil<SalesRecordExportVo> util = new ExcelUtil<>(SalesRecordExportVo.class);
        util.exportExcel(response, exportData, "销售出库数据");
    }
    private List<SalesRecordExportVo> convertToExportVo(List<SalesRecord> list) {
        // 1. æå‰æ”¶é›†æ‰€æœ‰éœ€è¦æŸ¥è¯¢çš„coalId,避免N+1查询问题
        Set<Long> coalIds = list.stream()
                .filter(Objects::nonNull)
                .map(SalesRecord::getCoalId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        // 2. æ‰¹é‡æŸ¥è¯¢coalInfo数据
        Map<Long, CoalInfo> coalInfoMap = CollectionUtils.isEmpty(coalIds)
                ? Collections.emptyMap()
                : coalInfoMapper.selectByIds(coalIds).stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toMap(CoalInfo::getId, Function.identity()));
        // 3. è½¬æ¢æ•°æ®
        return list.stream()
                .filter(Objects::nonNull)
                .map(record -> {
                    try {
                        SalesRecordExportVo vo = new SalesRecordExportVo();
                        // æ‹·è´åŸºç¡€å±žæ€§
                        BeanUtils.copyProperties(record, vo);
                        // è®¾ç½®å…³è”çš„coal信息
                        Optional.ofNullable(record.getCoalId())
                                .map(coalInfoMap::get)
                                .ifPresent(coalInfo -> vo.setCoal(coalInfo.getCoal()));
                        return vo;
                    } catch (Exception e) {
                        log.error("转换销售记录VO异常,记录ID: {}", record.getId(), e);
                        return null;
                    }
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }
    @Override
    public Map<String, Object> getYearlyMonthlySales(YearlyQueryDto query) {
        // 1. å¤„理默认查询(不传参数时)
        if (query == null || query.getTimeRange() == null || query.getTimeRange().length == 0) {
main-business/src/main/java/com/ruoyi/business/task/TimingTaskJob.java
@@ -60,6 +60,7 @@
        inspectionTask.setRemarks("自动生成自定时任务ID: " + timingTask.getId());
        inspectionTask.setRegistrantId(timingTask.getRegistrantId());
        inspectionTask.setFrequencyType(timingTask.getFrequencyType());
        inspectionTask.setFrequencyDetail(timingTask.getFrequencyDetail());
        return inspectionTask;
    }
main-business/src/main/java/com/ruoyi/business/utils/DynamicExcelUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,200 @@
package com.ruoyi.business.utils;
import com.ruoyi.business.vo.OfficialInventoryExportVo;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Slf4j
public class DynamicExcelUtil<T> extends ExcelUtil<T> {
    private final List<String> dynamicHeaders;
    private final List<Field> fields;
    public DynamicExcelUtil(Class<T> clazz, List<String> dynamicHeaders) {
        super(clazz);
        this.dynamicHeaders = dynamicHeaders;
        this.fields = getAllFields(clazz);
    }
    private List<Field> getAllFields(Class<?> clazz) {
        List<Field> fields = new ArrayList<>();
        Class<?> currentClass = clazz;
        while (currentClass != null) {
            fields.addAll(Arrays.asList(currentClass.getDeclaredFields()));
            currentClass = currentClass.getSuperclass();
        }
        return fields;
    }
    @Override
    public void exportExcel(HttpServletResponse response, List<T> list, String sheetName) {
        try {
            String validSheetName = StringUtils.isBlank(sheetName) ? "Sheet1" : sheetName;
            // Create workbook directly instead of using parent's createWorkbook
            Workbook workbook = new SXSSFWorkbook();
            Sheet sheet = workbook.createSheet(validSheetName);
            // Create styles
            createCustomStyles(workbook);
            // Create dynamic header
            createDynamicHeader(sheet, workbook);
            // Fill data
            fillDynamicData(sheet, list);
            // Set response
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(validSheetName + ".xlsx", "UTF-8"));
            workbook.write(response.getOutputStream());
        } catch (Exception e) {
            log.error("导出Excel失败", e);
            throw new RuntimeException("导出Excel失败: " + e.getMessage(), e);
        }
    }
    private void createCustomStyles(Workbook workbook) {
        // Create basic styles similar to parent class if needed
        CellStyle headerStyle = workbook.createCellStyle();
        Font headerFont = workbook.createFont();
        headerFont.setBold(true);
        headerStyle.setFont(headerFont);
        headerStyle.setAlignment(HorizontalAlignment.CENTER);
        headerStyle.setVerticalAlignment(VerticalAlignment.CENTER);
    }
    /**
     * åˆ›å»ºåŠ¨æ€è¡¨å¤´ï¼ˆçˆ¶è¡¨å¤´"煤质" + å­è¡¨å¤´ï¼‰
     */
    private void createDynamicHeader(Sheet sheet, Workbook workbook) {
        // ä¸»è¡¨å¤´ï¼ˆç¬¬1行)和子表头(第2行)
        Row mainHeaderRow = sheet.createRow(0);
        Row subHeaderRow = sheet.createRow(1);
        // åˆ›å»ºè¡¨å¤´æ ·å¼ï¼ˆå±…中 + åŠ ç²—ï¼‰
        CellStyle headerStyle = workbook.createCellStyle();
        Font headerFont = workbook.createFont();
        headerFont.setBold(true);
        headerStyle.setFont(headerFont);
        headerStyle.setAlignment(HorizontalAlignment.CENTER);
        headerStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        int colIndex = 0;
        // éåŽ†æ‰€æœ‰å­—æ®µï¼ˆå›ºå®šå­—æ®µ + åŠ¨æ€å­—æ®µï¼‰
        for (Field field : fields) {
            Excel excel = field.getAnnotation(Excel.class);
            if (excel != null) {
                // 1. å¦‚果是 "煤质" å­—段,跳过(后面单独处理)
                if (excel.name().equals("煤质")) {
                    continue;
                }
                // 2. å¤„理普通字段(非 "煤质" çš„列)
                // 2.1 åœ¨ä¸»è¡¨å¤´ï¼ˆç¬¬1行)设置字段名
                Cell mainHeaderCell = mainHeaderRow.createCell(colIndex);
                mainHeaderCell.setCellValue(excel.name());
                mainHeaderCell.setCellStyle(headerStyle);
                // 2.2 åœ¨å­è¡¨å¤´ï¼ˆç¬¬2行)留空,但合并单元格使其占据两行高度
                Cell subHeaderCell = subHeaderRow.createCell(colIndex);
                subHeaderCell.setCellStyle(headerStyle); // ä¿æŒæ ·å¼ä¸€è‡´
                // 2.3 åˆå¹¶å½“前列的第1行和第2行(垂直合并)
                sheet.addMergedRegion(new CellRangeAddress(
                        0, 1,  // ä»Žç¬¬1行到第2行
                        colIndex, colIndex  // å½“前列
                ));
                colIndex++; // ç§»åŠ¨åˆ°ä¸‹ä¸€åˆ—
            }
        }
        // 3. å¤„理动态字段("煤质" ä¸‹çš„子表头)
        if (!dynamicHeaders.isEmpty()) {
            // 3.1 åœ¨ä¸»è¡¨å¤´ï¼ˆç¬¬1行)设置 "煤质" å¤§æ ‡é¢˜ï¼ˆæ¨ªå‘合并)
            Cell coalHeaderCell = mainHeaderRow.createCell(colIndex);
            coalHeaderCell.setCellValue("煤质");
            coalHeaderCell.setCellStyle(headerStyle);
            // æ¨ªå‘合并(第1行,跨越多列)
            sheet.addMergedRegion(new CellRangeAddress(
                    0, 0,  // ä»…第1行
                    colIndex, colIndex + dynamicHeaders.size() - 1  // è·¨è¶Šå¤šåˆ—
            ));
            // 3.2 åœ¨å­è¡¨å¤´ï¼ˆç¬¬2行)设置动态字段(如 "灰分"、"硫分")
            for (int i = 0; i < dynamicHeaders.size(); i++) {
                Cell subCell = subHeaderRow.createCell(colIndex + i);
                subCell.setCellValue(dynamicHeaders.get(i));
                subCell.setCellStyle(headerStyle);
            }
        }
    }
    /**
     * å¡«å……数据(固定字段 + åŠ¨æ€å­—æ®µï¼‰
     */
    private void fillDynamicData(Sheet sheet, List<T> list) {
        int rowIndex = 2; // Data starts from row 3
        CellStyle dataStyle = sheet.getWorkbook().createCellStyle();
        dataStyle.setAlignment(HorizontalAlignment.CENTER);
        for (T item : list) {
            Row row = sheet.createRow(rowIndex++);
            int colIndex = 0;
            // Fill fixed fields
            for (Field field : fields) {
                Excel excel = field.getAnnotation(Excel.class);
                if (excel != null && !excel.name().equals("煤质")) {
                    try {
                        field.setAccessible(true);
                        Object value = field.get(item);
                        Cell cell = row.createCell(colIndex++);
                        cell.setCellStyle(dataStyle);
                        setCellValue(cell, value);
                    } catch (Exception e) {
                        log.error("填充固定字段失败", e);
                        row.createCell(colIndex++).setCellValue("-");
                    }
                }
            }
            // Fill dynamic fields
            if (item instanceof OfficialInventoryExportVo vo) {
                for (String header : dynamicHeaders) {
                    Cell cell = row.createCell(colIndex++);
                    cell.setCellStyle(dataStyle);
                    cell.setCellValue(vo.getDynamicProperty(header));
                }
            }
        }
    }
    /**
     * è®¾ç½®å•元格值
     */
    private void setCellValue(Cell cell, Object value) {
        if (value == null) {
            cell.setCellValue("-");
        } else if (value instanceof Number) {
            cell.setCellValue(((Number) value).doubleValue());
        } else {
            cell.setCellValue(value.toString());
        }
    }
}
main-business/src/main/java/com/ruoyi/business/vo/OfficialInventoryExportVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,94 @@
package com.ruoyi.business.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.annotation.Excel;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;
@Data
public class OfficialInventoryExportVo {
    /**
     * ä¾›è´§å•†
     */
    @Excel(name = "供货商")
    private String supplierName;
    /**
     * ç…¤ç§
     */
    @Excel(name = "煤种")
    private String coal;
    /**
     * å•位
     */
    @Excel(name = "单位")
    private String unit;
    /**
     * åº“存数量
     */
    @Excel(name = "库存数量")
    private BigDecimal inventoryQuantity;
    /**
     * å•价(含税)
     */
    @Excel(name = "单价(含税)")
    private BigDecimal priceIncludingTax;
    /**
     * æ€»ä»·ï¼ˆå«ç¨Žï¼‰
     */
    @Excel(name = "总价(含税)")
    private BigDecimal totalPriceIncludingTax;
    /**
     * ä¸å«ç¨Žå•ä»·
     */
    @Excel(name = "不含税单价")
    private BigDecimal priceExcludingTax;
    /**
     * ä¸å«ç¨Žæ€»ä»·
     */
    @Excel(name = "不含税总价")
    private BigDecimal totalPriceExcludingTax;
    /**
     * å¾…补库
     */
    @Excel(name = "待补库")
    private BigDecimal pendingReplenishment;
    /**
     * ç™»è®°äºº
     */
    @Excel(name = "登记人")
    private String registrant;
    /**
     * ç™»è®°æ—¥æœŸ
     */
    @Excel(name = "登记日期")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private LocalDate registrationDate;
    /**
     * åŠ¨æ€ç…¤è´¨å±žæ€§ï¼ˆå­˜å‚¨æ‰€æœ‰ç…¤è´¨å­è¡¨å¤´æ•°æ®ï¼‰
     */
    // åŠ¨æ€å­—æ®µå®¹å™¨ï¼ˆä¸å‚ä¸Žå¯¼å‡ºï¼‰
    private transient Map<String, String> coalQualityProperties;
    // åŠ¨æ€å­—æ®µè®¿é—®æ–¹æ³•
    public String getDynamicProperty(String fieldName) {
        return coalQualityProperties != null ?
                coalQualityProperties.getOrDefault(fieldName, "-") : "-";
    }
    // åˆå§‹åŒ–方法(在convertToExportVo中调用)
    public void initDynamicFields() {
        // ç¡®ä¿map不为null
        if (this.coalQualityProperties == null) {
            this.coalQualityProperties = new HashMap<>();
        }
    }
}
main-business/src/main/java/com/ruoyi/business/vo/SalesRecordExportVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,94 @@
package com.ruoyi.business.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.annotation.Excel;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
@Data
public class SalesRecordExportVo {
    /**
     * é”€å”®æ—¥æœŸ
     */
    @JsonFormat(pattern = "yyyy-MM-dd")
    @Excel(name = "销售日期")
    private LocalDate saleDate;
    /**
     * å®¢æˆ·
     */
    @Excel(name = "客户")
    private String customer;
    /**
     * ç…¤ç§
     */
    @Excel(name = "煤种")
    private String coal;
    /**
     * å•位
     */
    @Excel(name = "单位")
    private String unit;
    /**
     * å•价(含税)
     */
    @Excel(name = "单价(含税)")
    private BigDecimal priceIncludingTax;
    /**
     * åº“存数量
     */
    @Excel(name = "库存数量")
    private BigDecimal inventoryQuantity;
    /**
     * é”€å”®æ•°é‡
     */
    @Excel(name = "销售数量")
    private BigDecimal saleQuantity;
    /**
     * é”€å”®å•ä»· (含税)
     */
    @Excel(name = "销售单价 (含税)")
    private BigDecimal salePrice;
    /**
     * é”€å”®æ€»ä»· (含税)
     */
    @Excel(name = "销售总价 (含税)")
    private BigDecimal totalAmount;
    /**
     * è´­é”€ç…¤ç¨Žçއ13%
     */
    @Excel(name = "购销煤税率 (13%)")
    private String taxCoal;
    /**
     * è¿è¾“税率9%
     */
    @Excel(name = "运输税率 (9%)")
    private String taxTrans;
    /**
     * æ¯›åˆ©æ¶¦
     */
    @Excel(name = "毛利润")
    private BigDecimal grossProfit;
    /**
     * å‡€åˆ©æ¶¦
     */
    @Excel(name = "净利润")
    private BigDecimal netProfit;
    /**
     * è¿è´¹
     */
    @Excel(name = "运费")
    private BigDecimal freight;
    /**
     * ç™»è®°äºº
     */
    @Excel(name = "登记人")
    private String registrant;
    /**
     * ç™»è®°æ—¥æœŸ
     */
    @JsonFormat(pattern = "yyyy-MM-dd")
    @Excel(name = "登记日期")
    private LocalDate registrationDate;
}
main-business/src/main/resources/db/migration/postgresql/V20250611160300__create_table_sales_record.sql
@@ -20,6 +20,7 @@
    registrant_id       BIGINT,                           -- ç™»è®°äººid
    registrant          VARCHAR(255)   ,          -- ç™»è®°äºº
    registration_date   DATE           ,          -- ç™»è®°æ—¥æœŸ
    is_add              BOOLEAN      NOT NULL DEFAULT FALSE, -- æ˜¯å¦æ·»åŠ è‡³å¾…è¡¥åº“
    create_time         TIMESTAMP WITHOUT TIME ZONE,          -- ä¸Šä¼ æ—¶é—´ï¼Œé»˜è®¤å½“前时间
    update_time         TIMESTAMP WITHOUT TIME ZONE,          -- æœ€åŽæ›´æ–°æ—¶é—´ï¼Œé»˜è®¤å½“前时间
@@ -50,6 +51,7 @@
COMMENT ON COLUMN sales_record.registrant IS '登记人';
COMMENT ON COLUMN sales_record.registrant_id IS '登记人id';
COMMENT ON COLUMN sales_record.registration_date IS '登记日期';
COMMENT ON COLUMN sales_record.is_add IS '是否添加至待补库';
COMMENT ON COLUMN sales_record.deleted IS '软删除标志,0=未删除,1=已删除';
COMMENT ON COLUMN sales_record.create_by IS '创建该记录的用户';
main-business/src/main/resources/db/migration/postgresql/V20250614134700__create_table_inspection_task.sql
@@ -10,6 +10,7 @@
    registrant    VARCHAR(100),                -- ç™»è®°äººå‘˜
    frequency_type     VARCHAR(100),           -- é¢‘次
    inspection_location     VARCHAR(255),           -- å·¡æ£€åœ°ç‚¹è¯¦ç»†æè¿°
    frequency_detail     VARCHAR(255),           -- æ—¶é—´ç»†èŠ‚
    deleted       INT NOT NULL DEFAULT 0,      -- è½¯åˆ é™¤æ ‡å¿—:0=未删除,1=已删除
    create_by     VARCHAR(255),                -- åˆ›å»ºäººç”¨æˆ·å
@@ -36,6 +37,8 @@
ON COLUMN inspection_task.frequency_type IS '频次';
COMMENT
ON COLUMN inspection_task.inspection_location IS '巡检地点详细描述';
COMMENT
ON COLUMN inspection_task.frequency_detail IS '时间细节';
COMMENT
ON COLUMN inspection_task.deleted IS '软删除标志,0=未删除,1=已删除';
main-business/src/main/resources/db/migration/postgresql/V20250701142700__create_table_equipment_management.sql
@@ -13,6 +13,7 @@
    storage_location VARCHAR(100) NOT NULL,           -- å­˜æ”¾ä½ç½®
    purchase_date    DATE,                            -- é‡‡è´­æ—¥æœŸ
    purchase_price   DECIMAL(10, 2),                  -- é‡‡è´­ä»·æ ¼
    is_consumables   BOOLEAN      NOT NULL DEFAULT FALSE, -- æ˜¯å¦è€—材类
    deleted          INT          NOT NULL DEFAULT 0, -- è½¯åˆ é™¤æ ‡å¿—:0=未删除,1=已删除
    create_by        VARCHAR(255),                    -- åˆ›å»ºäººç”¨æˆ·å
@@ -46,6 +47,8 @@
ON COLUMN equipment_management.purchase_date IS ' é‡‡è´­æ—¥æœŸ ';
COMMENT
ON COLUMN equipment_management.purchase_price IS ' é‡‡è´­ä»·æ ¼ ';
COMMENT
ON COLUMN equipment_management.is_consumables IS ' æ˜¯å¦è€—材类 ';
COMMENT
ON COLUMN inspection_task.deleted IS '软删除标志,0=未删除,1=已删除';
main-business/src/main/resources/db/migration/postgresql/V20250707155600__create_table_equipment_usage_record.sql
@@ -6,7 +6,7 @@
    usage_quantity       INT            NOT NULL,           -- ä½¿ç”¨æ•°é‡ï¼Œä¸å…è®¸ä¸ºç©º
    user_id              BIGINT         NOT NULL,           -- ä½¿ç”¨äººID,关联用户表,不允许为空
    department_id        BIGINT         ,                   -- éƒ¨é—¨ID,关联部门表,不允许为空
    equipment_status     VARCHAR(50)    NOT NULL,           -- è®¾å¤‡çŠ¶æ€ï¼ˆå¦‚ï¼šæ­£å¸¸ã€æ•…éšœã€ç»´ä¿®ä¸­ï¼‰ï¼Œä¸å…è®¸ä¸ºç©º
    equipment_status     BIGINT    NOT NULL,                -- è®¾å¤‡çŠ¶æ€:1.使用中 2.已归还
    usage_start_time     TIMESTAMP      NOT NULL,           -- ä½¿ç”¨å¼€å§‹æ—¶é—´ï¼Œä¸å…è®¸ä¸ºç©º
    usage_end_time       TIMESTAMP,                         -- ä½¿ç”¨ç»“束时间,可为空(未归还时)
    remarks              VARCHAR(1000),                     -- å¤‡æ³¨ä¿¡æ¯ï¼Œå¯ä¸ºç©º
@@ -27,7 +27,7 @@
COMMENT ON COLUMN equipment_usage_record.usage_quantity IS '使用数量';
COMMENT ON COLUMN equipment_usage_record.user_id IS '使用人ID';
COMMENT ON COLUMN equipment_usage_record.department_id IS '部门ID';
COMMENT ON COLUMN equipment_usage_record.equipment_status IS '设备状态(正常/故障/维修中)';
COMMENT ON COLUMN equipment_usage_record.equipment_status IS '设备状态:1.使用中 2.已归还';
COMMENT ON COLUMN equipment_usage_record.usage_start_time IS '使用开始时间';
COMMENT ON COLUMN equipment_usage_record.usage_end_time IS '使用结束时间';
COMMENT ON COLUMN equipment_usage_record.remarks IS '备注信息';
ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
@@ -114,7 +114,7 @@
    /**
     * å·¥ä½œè¡¨åç§°
     */
    private String sheetName;
    protected String sheetName;
    /**
     * å¯¼å‡ºç±»åž‹ï¼ˆEXPORT:导出数据;IMPORT:导入模板)