liding
11 小时以前 71fba5328a35b449b11088e540932787220f91d8
1.生产加工变更库存回滚 2.巡检,档案上传完善
已修改29个文件
已添加3个文件
1409 ■■■■ 文件已修改
main-business/src/main/java/com/ruoyi/business/controller/ArchiveController.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/controller/InspectionTaskController.java 50 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/controller/ProductionMasterController.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/dto/ArchiveDto.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/dto/InspectionTaskDto.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/entity/InspectionTask.java 94 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/entity/ProductionMaster.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/mapper/OfficialInventoryMapper.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/service/ArchiveService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/service/InspectionTaskService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/service/ProductionMasterService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/service/impl/ArchiveServiceImpl.java 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/service/impl/InspectionTaskServiceImpl.java 170 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/service/impl/ProductionMasterServiceImpl.java 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/vo/ArchiveVo.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/resources/mapper/OfficialInventoryMapper.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java 111 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/basic/entity/StorageAttachment.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/basic/entity/StorageBlob.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/basic/entity/dto/StorageBlobDTO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/basic/service/StorageBlobService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/basic/service/impl/StorageBlobServiceImpl.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/enums/StorageAttachmentRecordType.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/handler/LocalDateTimeTypeHandler.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MinioUtils.java 146 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/config/MybatisPlusConfig.java 33 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java 270 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/SysUserVo.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/controller/ArchiveController.java
@@ -3,7 +3,6 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.business.dto.ArchiveDto;
import com.ruoyi.business.entity.Archive;
import com.ruoyi.business.service.ArchiveService;
import com.ruoyi.common.core.domain.R;
import lombok.AllArgsConstructor;
@@ -29,8 +28,8 @@
     * æŸ¥è¯¢æ¡£æ¡ˆä¿¡æ¯è¡¨
     */
    @GetMapping("/list")
    public R<IPage<Archive>> treeList(Page page, ArchiveDto archiveDto) {
        IPage<Archive> list = archiveService.selectArchiveList(page, archiveDto);
    public R<IPage<ArchiveDto>> treeList(Page page, ArchiveDto archiveDto) {
        IPage<ArchiveDto> list = archiveService.selectArchiveList(page, archiveDto);
        return R.ok(list);
    }
main-business/src/main/java/com/ruoyi/business/controller/InspectionTaskController.java
@@ -1,21 +1,51 @@
package com.ruoyi.business.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.business.dto.InspectionTaskDto;
import com.ruoyi.business.service.InspectionTaskService;
import com.ruoyi.common.core.domain.R;
import lombok.AllArgsConstructor;
    import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
/**
* <p>
    * å·¡æ£€ä»»åŠ¡è¡¨ å‰ç«¯æŽ§åˆ¶å™¨
    * </p>
*
* @author ld
* @since 2025-06-14
*/
 * <p>
 * å·¡æ£€ä»»åŠ¡è¡¨ å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author ld
 * @since 2025-06-14
 */
@RestController
@AllArgsConstructor
@RequestMapping("/inspectionTask")
        public class InspectionTaskController {
public class InspectionTaskController {
    private InspectionTaskService inspectionTaskService;
    /**
     * å·¡æ£€ä»»åŠ¡è¡¨è¡¨æŸ¥è¯¢
     */
    @GetMapping("/list")
    public R<IPage<InspectionTaskDto>> list(Page page, InspectionTaskDto inspectionTaskDto) {
        IPage<InspectionTaskDto> list = inspectionTaskService.selectInspectionTaskList(page,inspectionTaskDto);
        return R.ok(list);
    }
    /**
     * å·¡æ£€ä»»åŠ¡è¡¨æ–°å¢žä¿®æ”¹
     */
    @PostMapping("/addOrEditInspectionTask")
    public R addOrEditInspectionTask(@RequestBody InspectionTaskDto inspectionTaskDto) {
        return R.ok(inspectionTaskService.addOrEditInspectionTask(inspectionTaskDto));
    }
    /**
     * å·¡æ£€ä»»åŠ¡è¡¨åˆ é™¤
     */
    @DeleteMapping("/delInspectionTask")
    public R remove(@RequestBody Long[] ids) {
        return R.ok(inspectionTaskService.delByIds(ids));
    }
}
main-business/src/main/java/com/ruoyi/business/controller/ProductionMasterController.java
@@ -42,13 +42,21 @@
    }
    /**
     * åˆ é™¤
     * æ¸…空生产明细库存选择list
     */
    @DeleteMapping("/deleteProductionInventory")
    public R delOI(@RequestBody ProductionMasterDto productionMasterDto) {
        return R.ok(productionMasterService.deleteProductionInventory(productionMasterDto));
    }
    /**
     * åˆ é™¤ç”Ÿäº§ä¸»è¡¨(库存回滚,明细删除)
     */
    @DeleteMapping("/delPM")
    public R remove(@RequestBody Long[] ids) {
        return R.ok(productionMasterService.delByIds(ids));
    }
}
main-business/src/main/java/com/ruoyi/business/dto/ArchiveDto.java
@@ -1,6 +1,7 @@
package com.ruoyi.business.dto;
import com.ruoyi.basic.entity.StorageAttachment;
import com.ruoyi.basic.entity.StorageBlob;
import com.ruoyi.basic.entity.dto.StorageBlobDTO;
import com.ruoyi.business.entity.Archive;
import lombok.Data;
@@ -11,5 +12,7 @@
    private Long treeId;
    private List<StorageAttachment> attachments;
    private List<StorageBlobDTO> storageBlobDTO;
    private List<StorageBlob> attachments;
}
main-business/src/main/java/com/ruoyi/business/dto/InspectionTaskDto.java
@@ -1,8 +1,20 @@
package com.ruoyi.business.dto;
import com.ruoyi.basic.entity.StorageAttachment;
import com.ruoyi.basic.entity.dto.StorageBlobDTO;
import com.ruoyi.business.entity.InspectionTask;
import lombok.Data;
import java.util.List;
@Data
public class InspectionTaskDto extends InspectionTask {
    private List<StorageBlobDTO> storageBlobDTO;
    private List<StorageBlobDTO> beforeProduction;
    private List<StorageBlobDTO> afterProduction;
    private List<StorageBlobDTO> productionIssues;
    private List<StorageAttachment> attachments;
}
main-business/src/main/java/com/ruoyi/business/entity/InspectionTask.java
@@ -2,58 +2,58 @@
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
    import com.ruoyi.common.core.domain.MyBaseEntity;
import com.ruoyi.common.core.domain.MyBaseEntity;
/**
* å·¡æ£€ä»»åŠ¡è¡¨ å®žä½“ç±»
*
* @author ld
* @date 2025-06-14
*/
 * å·¡æ£€ä»»åŠ¡è¡¨ å®žä½“ç±»
 *
 * @author ld
 * @date 2025-06-14
 */
@Data
@TableName("inspection_task")
public class InspectionTask extends MyBaseEntity {
private static final long serialVersionUID = 1L;
    private static final long serialVersionUID = 1L;
        /**
        * å·¡æ£€ä»»åŠ¡å”¯ä¸€æ ‡è¯†
        */
            @TableId(value = "id", type = IdType.AUTO)
        private Long id;
        /**
        * å·¡æ£€ä»»åŠ¡åç§°
        */
            @TableField(value = "task_name")
        private String taskName;
        /**
        *
        */
            @TableField(value = "inspector_id")
        private Long inspectorId;
        /**
        * æ‰§è¡Œå·¡æ£€çš„人员姓名
        */
            @TableField(value = "inspector")
        private String inspector;
        /**
        * å·¡æ£€åœ°ç‚¹è¯¦ç»†æè¿°
        */
            @TableField(value = "port")
        private String port;
        /**
        * ä»»åŠ¡é™„åŠ è¯´æ˜Žæˆ–ç‰¹æ®Šæƒ…å†µè®°å½•
        */
            @TableField(value = "remarks")
        private String remarks;
        /**
        *
        */
            @TableField(value = "registrant_id")
        private Long registrantId;
        /**
        * ä»»åŠ¡ç™»è®°äººå§“å
        */
            @TableField(value = "registrant")
        private String registrant;
    /**
     * å·¡æ£€ä»»åŠ¡å”¯ä¸€æ ‡è¯†
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * å·¡æ£€ä»»åŠ¡åç§°
     */
    @TableField(value = "task_name")
    private String taskName;
    /**
     *
     */
    @TableField(value = "inspector_id")
    private Long inspectorId;
    /**
     * æ‰§è¡Œå·¡æ£€çš„人员姓名
     */
    @TableField(value = "inspector")
    private String inspector;
    /**
     * å·¡æ£€åœ°ç‚¹è¯¦ç»†æè¿°
     */
    @TableField(value = "port")
    private String port;
    /**
     * ä»»åŠ¡é™„åŠ è¯´æ˜Žæˆ–ç‰¹æ®Šæƒ…å†µè®°å½•
     */
    @TableField(value = "remarks")
    private String remarks;
    /**
     *
     */
    @TableField(value = "registrant_id")
    private Long registrantId;
    /**
     * ä»»åŠ¡ç™»è®°äººå§“å
     */
    @TableField(value = "registrant")
    private String registrant;
}
main-business/src/main/java/com/ruoyi/business/entity/ProductionMaster.java
@@ -61,7 +61,7 @@
     *
     */
    @TableField(value = "producer_id")
    private String producerId;
    private Long producerId;
    /**
     * ç”Ÿäº§äºº
     */
main-business/src/main/java/com/ruoyi/business/mapper/OfficialInventoryMapper.java
@@ -5,6 +5,8 @@
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.math.BigDecimal;
/**
 * <p>
 * æ­£å¼åº“存表 Mapper æŽ¥å£
@@ -17,4 +19,7 @@
public interface OfficialInventoryMapper extends BaseMapper<OfficialInventory> {
    // èŽ·å–æ­£å¼åº“è®°å½•
    OfficialInventory getOfficialInventoryForUpdateById(@Param("id") Long id);
    int addInventoryQuantity(@Param("id") Long officialId,
                             @Param("quantity") BigDecimal adjustAmount);
}
main-business/src/main/java/com/ruoyi/business/service/ArchiveService.java
@@ -19,7 +19,7 @@
 */
public interface ArchiveService extends IService<Archive> {
    IPage<Archive> selectArchiveList(Page page, ArchiveDto archiveDto);
    IPage<ArchiveDto> selectArchiveList(Page page, ArchiveDto archiveDto);
    int addOrEditArchive(ArchiveDto archiveDto);
main-business/src/main/java/com/ruoyi/business/service/InspectionTaskService.java
@@ -1,5 +1,8 @@
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.InspectionTaskDto;
import com.ruoyi.business.entity.InspectionTask;
import com.baomidou.mybatisplus.extension.service.IService;
@@ -13,4 +16,9 @@
 */
public interface InspectionTaskService extends IService<InspectionTask> {
    IPage<InspectionTaskDto> selectInspectionTaskList(Page page, InspectionTaskDto inspectionTaskDto);
    int addOrEditInspectionTask(InspectionTaskDto inspectionTaskDto);
    int delByIds(Long[] ids);
}
main-business/src/main/java/com/ruoyi/business/service/ProductionMasterService.java
@@ -21,4 +21,6 @@
    int addOrEditPM(ProductionMasterDto productionMasterDto);
    int delByIds(Long[] ids);
    int deleteProductionInventory(ProductionMasterDto productionMasterDto);
}
main-business/src/main/java/com/ruoyi/business/service/impl/ArchiveServiceImpl.java
@@ -3,20 +3,27 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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.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.ArchiveDto;
import com.ruoyi.business.entity.Archive;
import com.ruoyi.business.mapper.ArchiveMapper;
import com.ruoyi.business.service.ArchiveService;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.file.MinioUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Objects;
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;
@@ -38,26 +45,125 @@
    private final StorageAttachmentService storageAttachmentService;
    private final StorageBlobMapper storageBlobMapper;
    private final StorageAttachmentMapper storageAttachmentMapper;
    private final MinioUtils minioUtils;
    @Override
    public IPage<Archive> selectArchiveList(Page page, ArchiveDto archiveDto) {
    public IPage<ArchiveDto> selectArchiveList(Page page, ArchiveDto archiveDto) {
        // 1. åˆ†é¡µæŸ¥è¯¢ä¸»æ•°æ®
        LambdaQueryWrapper<Archive> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(Archive::getCreateTime);
        return archiveMapper.selectPage(page, queryWrapper);
        IPage<Archive> archivePage = archiveMapper.selectPage(page, queryWrapper);
        // 2. æ— æ•°æ®æå‰è¿”回
        if (CollectionUtils.isEmpty(archivePage.getRecords())) {
            return new Page<>(archivePage.getCurrent(), archivePage.getSize(), archivePage.getTotal());
        }
        // 3. æ‰¹é‡èŽ·å–æ‰€æœ‰æ¡£æ¡ˆID
        List<Long> archiveIds = archivePage.getRecords()
                .stream()
                .map(Archive::getId)
                .collect(Collectors.toList());
        // 4. æ‰¹é‡æŸ¥è¯¢é™„件映射关系(避免N+1)
        List<StorageAttachment> storageAttachments = storageAttachmentMapper
                .selectList(new LambdaQueryWrapper<StorageAttachment>()
                        .in(StorageAttachment::getRecordId, archiveIds)
                        .eq(StorageAttachment::getRecordType, Archives.ordinal())
                );
        Map<Long, List<StorageAttachment>> attachmentsMap = storageAttachmentMapper
                .selectList(new LambdaQueryWrapper<StorageAttachment>()
                        .in(StorageAttachment::getRecordId, archiveIds)
                        .eq(StorageAttachment::getRecordType, Archives.ordinal())
                ).stream()
                .collect(Collectors.groupingBy(StorageAttachment::getRecordId));
        // 5. æ‰¹é‡æŸ¥è¯¢æ‰€æœ‰éœ€è¦çš„æ–‡ä»¶æ•°æ®
        Set<Long> blobIds = attachmentsMap.values()
                .stream()
                .flatMap(List::stream)
                .map(StorageAttachment::getStorageBlobId)
                .collect(Collectors.toSet());
        Map<Long, StorageBlob> blobMap = blobIds.isEmpty()
                ? Collections.emptyMap()
                : storageBlobMapper.selectList(new LambdaQueryWrapper<StorageBlob>().in(StorageBlob::getId, blobIds))
                .stream()
                .collect(Collectors.toMap(StorageBlob::getId, Function.identity()));
        // 6. ç»„装DTO(单次循环完成数据装配)
        List<ArchiveDto> dtoList = archivePage.getRecords().stream().map(archive -> {
            ArchiveDto dto = new ArchiveDto();
            BeanUtils.copyProperties(archive, dto);  // å¤åˆ¶ä¸»å¯¹è±¡å±žæ€§
            // æŒ‰éœ€æ·»åŠ é™„ä»¶ä¿¡æ¯
            List<StorageBlobDTO> blobDTOs = Optional.ofNullable(attachmentsMap.get(archive.getId()))
                    .orElse(Collections.emptyList())
                    .stream()
                    .map(att -> blobMap.get(att.getStorageBlobId()))
                    .filter(Objects::nonNull)
                    .map(blob -> {
                        StorageBlobDTO blobDTO = new StorageBlobDTO();
                        BeanUtils.copyProperties(blob, blobDTO);
                        // åŠ¨æ€ç”Ÿæˆé¢„è§ˆåœ°å€å’Œä¸‹è½½åœ°å€
                        // è®¾ç½®é¢„览URL
                        blobDTO.setUrl(minioUtils.getPreviewUrls(
                                blob.getBucketFilename(),
                                blob.getBucketName(),
                                true
                        ));
                        // è®¾ç½®ä¸‹è½½URL
                        blobDTO.setDownloadUrl(minioUtils.getDownloadUrls(
                                blob.getBucketFilename(),
                                blob.getBucketName(),
                                blob.getOriginalFilename(),  // åŽŸå§‹æ–‡ä»¶å
                                true
                        ));
                        return blobDTO;
                    })
                    .collect(Collectors.toList());
            dto.setStorageBlobDTO(blobDTOs);
            return dto;
        }).collect(Collectors.toList());
        // 7. æž„建返回分页对象
        IPage<ArchiveDto> resultPage = new Page<>();
        resultPage.setRecords(dtoList);
        return resultPage;
    }
    @Override
    public int addOrEditArchive(ArchiveDto archiveDto) {
        Archive archive = new Archive();
        BeanUtils.copyProperties(archiveDto, archive);
        int i ;
        int i;
        if (Objects.isNull(archiveDto.getId())) {
            i= archiveMapper.insert(archive);
            i = archiveMapper.insert(archive);
        } else {
            i= archiveMapper.updateById(archive);
            i = archiveMapper.updateById(archive);
        }
        storageAttachmentService.saveStorageAttachment(archiveDto.getAttachments(), archive.getId(),Archives,StorageAttachmentFile);
        if (archiveDto.getStorageBlobDTO() != null && !archiveDto.getStorageBlobDTO().isEmpty()) {
            List<StorageAttachment> attachments = new ArrayList<>();
            for (StorageBlobDTO storageBlobDTO : archiveDto.getStorageBlobDTO()) {
                StorageAttachment storageAttachment = new StorageAttachment(
                        StorageAttachmentFile,
                        (long) Archives.ordinal(),
                        archive.getId()
                );
                storageAttachment.setStorageBlobDTO(storageBlobDTO);
                attachments.add(storageAttachment);
            }
            storageAttachmentService.saveStorageAttachment(attachments, archive.getId(), Archives, StorageAttachmentFile);
        }
        return i;
    }
@@ -77,7 +183,7 @@
    @Override
    public List<StorageAttachment> fileList(ArchiveDto archiveDto) {
        storageAttachmentService.selectStorageAttachments(archiveDto.getId(), Archives, StorageAttachmentFile);
        return null;
        List<StorageAttachment> storageAttachments = storageAttachmentService.selectStorageAttachments(archiveDto.getId(), Archives, StorageAttachmentFile);
        return storageAttachments;
    }
}
main-business/src/main/java/com/ruoyi/business/service/impl/InspectionTaskServiceImpl.java
@@ -1,11 +1,32 @@
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.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
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.InspectionTaskDto;
import com.ruoyi.business.entity.InspectionTask;
import com.ruoyi.business.mapper.InspectionTaskMapper;
import com.ruoyi.business.service.InspectionTaskService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.file.MinioUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
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.InspectionTasks;
/**
 * <p>
@@ -19,4 +40,149 @@
@RequiredArgsConstructor
public class InspectionTaskServiceImpl extends ServiceImpl<InspectionTaskMapper, InspectionTask> implements InspectionTaskService {
    private final InspectionTaskMapper inspectionTaskMapper;
    private final StorageAttachmentService storageAttachmentService;
    private final StorageBlobMapper storageBlobMapper;
    private final StorageAttachmentMapper storageAttachmentMapper;
    private final MinioUtils minioUtils;
    @Override
    public IPage<InspectionTaskDto> selectInspectionTaskList(Page page, InspectionTaskDto inspectionTaskDto) {
        LambdaQueryWrapper<InspectionTask> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(InspectionTask::getCreateTime);
        IPage<InspectionTask> entityPage = inspectionTaskMapper.selectPage(page, queryWrapper);
        //  æ— æ•°æ®æå‰è¿”回
        if (CollectionUtils.isEmpty(entityPage.getRecords())) {
            return new Page<>(entityPage.getCurrent(), entityPage.getSize(), entityPage.getTotal());
        }
        // èŽ·å–id集合
        List<Long> ids = entityPage.getRecords().stream().map(InspectionTask::getId).collect(Collectors.toList());
        Map<Long, List<StorageAttachment>> attachmentsMap = storageAttachmentMapper.selectList(new LambdaQueryWrapper<StorageAttachment>().in(StorageAttachment::getRecordId, ids)
                        .eq(StorageAttachment::getRecordType, InspectionTasks.ordinal()))
                .stream()
                .collect(Collectors.groupingBy(StorageAttachment::getRecordId));
        //  æ‰¹é‡æŸ¥è¯¢æ‰€æœ‰éœ€è¦çš„æ–‡ä»¶æ•°æ®
        Set<Long> blobIds = attachmentsMap.values()
                .stream()
                .flatMap(List::stream)
                .map(StorageAttachment::getStorageBlobId)
                .collect(Collectors.toSet());
        Map<Long, StorageBlob> blobMap = blobIds.isEmpty()
                ? Collections.emptyMap()
                : storageBlobMapper.selectList(new LambdaQueryWrapper<StorageBlob>().in(StorageBlob::getId, blobIds))
                .stream()
                .collect(Collectors.toMap(StorageBlob::getId, Function.identity()));
        List<InspectionTaskDto> dtoList = entityPage.getRecords().stream().map(inspectionTask -> {
            InspectionTaskDto dto = new InspectionTaskDto();
            BeanUtils.copyProperties(inspectionTask, dto);  // å¤åˆ¶ä¸»å¯¹è±¡å±žæ€§
            // åˆå§‹åŒ–三个附件列表
            dto.setBeforeProduction(new ArrayList<>());
            dto.setAfterProduction(new ArrayList<>());
            dto.setProductionIssues(new ArrayList<>());
            // å¤„理附件分类
            Optional.ofNullable(attachmentsMap.get(inspectionTask.getId()))
                    .orElse(Collections.emptyList())
                    .forEach(attachment -> {
                        StorageBlob blob = blobMap.get(attachment.getStorageBlobId());
                        if (blob != null) {
                            // åˆ›å»ºé™„ä»¶DTO
                            StorageBlobDTO blobDto = createBlobDto(blob);
                            // æ ¹æ®type分类
                            switch ((int) blob.getType().longValue()) {
                                case 0:
                                    dto.getBeforeProduction().add(blobDto);
                                    break;
                                case 1:
                                    dto.getAfterProduction().add(blobDto);
                                    break;
                                case 2:
                                    dto.getProductionIssues().add(blobDto);
                                    break;
                                default:
                                    // å¯é€‰ï¼šè®°å½•未分类类型
                                    break;
                            }
                        }
                    });
            return dto;
        }).collect(Collectors.toList());
        // 7. æž„建返回分页对象
        IPage<InspectionTaskDto> resultPage = new Page<>();
        resultPage.setRecords(dtoList);
        return resultPage;
    }
    // æå–创建BlobDTO的公共方法
    private StorageBlobDTO createBlobDto(StorageBlob blob) {
        StorageBlobDTO dto = new StorageBlobDTO();
        BeanUtils.copyProperties(blob, dto);
        // è®¾ç½®URL
        dto.setUrl(minioUtils.getPreviewUrls(
                blob.getBucketFilename(),
                blob.getBucketName(),
                true
        ));
        // è®¾ç½®ä¸‹è½½URL
        dto.setDownloadUrl(minioUtils.getDownloadUrls(
                blob.getBucketFilename(),
                blob.getBucketName(),
                blob.getOriginalFilename(),
                true
        ));
        return dto;
    }
    @Override
    public int addOrEditInspectionTask(InspectionTaskDto inspectionTaskDto) {
        SecurityUtils.getLoginUser().getUserId();
        InspectionTask inspectionTask = new InspectionTask();
        BeanUtils.copyProperties(inspectionTaskDto, inspectionTask);
        inspectionTask.setRegistrantId(SecurityUtils.getLoginUser().getUserId());
        inspectionTask.setRegistrant(SecurityUtils.getLoginUser().getUsername());
        int i;
        if (Objects.isNull(inspectionTaskDto.getId())) {
            i = inspectionTaskMapper.insert(inspectionTask);
        } else {
            i = inspectionTaskMapper.updateById(inspectionTask);
        }
        if (inspectionTaskDto.getStorageBlobDTO() != null && !inspectionTaskDto.getStorageBlobDTO().isEmpty()) {
            List<StorageAttachment> attachments = new ArrayList<>();
            for (StorageBlobDTO storageBlobDTO : inspectionTaskDto.getStorageBlobDTO()) {
                StorageAttachment storageAttachment = new StorageAttachment(
                        StorageAttachmentFile,
                        (long) InspectionTasks.ordinal(),
                        inspectionTask.getId()
                );
                storageAttachment.setStorageBlobDTO(storageBlobDTO);
                attachments.add(storageAttachment);
            }
            storageAttachmentService.saveStorageAttachment(attachments, inspectionTask.getId(), InspectionTasks, StorageAttachmentFile);
        }
        return i;
    }
    @Override
    public int delByIds(Long[] ids) {
        // æ£€æŸ¥å‚æ•°
        if (ids == null || ids.length == 0) {
            return 0;
        }
      return inspectionTaskMapper.deleteByIds(Arrays.asList(ids));
    }
}
main-business/src/main/java/com/ruoyi/business/service/impl/ProductionMasterServiceImpl.java
@@ -2,6 +2,7 @@
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.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.business.dto.ProductionMasterDto;
@@ -14,16 +15,16 @@
import com.ruoyi.business.mapper.ProductionMapper;
import com.ruoyi.business.mapper.ProductionMasterMapper;
import com.ruoyi.business.service.ProductionMasterService;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.system.mapper.SysUserMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
/**
@@ -45,6 +46,8 @@
    private final ProductionMapper productionMapper;
    private final OfficialInventoryMapper officialInventoryMapper;
    private final SysUserMapper sysUserMapper;
    @Override
    public IPage<ProductionMasterDto> selectPMList(Page page, ProductionMasterDto productionMasterDto) {
@@ -153,6 +156,12 @@
        productionMaster.setId(masterId);
        // 3. ç»Ÿä¸€å­è¡¨å¤„理逻辑
        Long producerId = productionMasterDto.getProducerId();
        if (producerId == null) {
            throw new BaseException("请选择生产者");
        }
        SysUser sysUser = sysUserMapper.selectUserById(producerId);
        productionMaster.setProducer(sysUser.getUserName());
        if (masterId == null) {
            productionMasterMapper.insert(productionMaster);
            masterId = productionMaster.getId(); // èŽ·å–æ–°ç”Ÿæˆçš„ID
@@ -221,7 +230,102 @@
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int delByIds(Long[] ids) {
        return 0;
        if (ids == null || ids.length == 0) {
            return 0;
        }
        List<Long> idList = Arrays.asList(ids);
        // 1. é¢„加载所有关联数据
        List<ProductionInventory> allInventoryList = productionInventoryMapper.selectList(
                new LambdaQueryWrapper<ProductionInventory>()
                        .in(ProductionInventory::getProductionMasterId, idList)
        );
        // 2. æŒ‰å®˜æ–¹åº“å­˜ID分组并计算库存调整量
        Map<Long, BigDecimal> inventoryAdjustMap = allInventoryList.stream()
                .collect(Collectors.groupingBy(
                        ProductionInventory::getOfficialId,
                        Collectors.reducing(
                                BigDecimal.ZERO,
                                inv -> new BigDecimal(inv.getUsedQuantity()),
                                BigDecimal::add
                        )
                ));
        // 3. æ‰¹é‡æ›´æ–°å®˜æ–¹åº“å­˜ (使用SQL直接更新)
        if (!inventoryAdjustMap.isEmpty()) {
            inventoryAdjustMap.forEach((officialId, adjustAmount) ->
                    officialInventoryMapper.addInventoryQuantity(officialId, adjustAmount)
            );
        }
        // 4. æ‰¹é‡åˆ é™¤å…³è”数据
        if (!allInventoryList.isEmpty()) {
            List<Long> inventoryIds = allInventoryList.stream()
                    .map(ProductionInventory::getId)
                    .collect(Collectors.toList());
            productionInventoryMapper.deleteBatchIds(inventoryIds);
        }
        // åˆ é™¤ç”Ÿäº§æ˜Žç»†
        productionMapper.delete(
                new LambdaQueryWrapper<Production>()
                        .in(Production::getProductionMasterId, idList)
        );
        // 5. åˆ é™¤ä¸»è®°å½•
        return productionMasterMapper.deleteBatchIds(idList);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteProductionInventory(ProductionMasterDto productionMasterDto) {
        List<ProductionInventory> inventories = productionMasterDto.getProductionInventoryList();
        if (CollectionUtils.isEmpty(inventories)) {
            return 0;
        }
        // é¢„收集数据用于批量操作
        Map<Long, BigDecimal> inventoryAdjustMap = new HashMap<>();
        List<Long> productionIdsToDelete = new ArrayList<>(inventories.size());
        for (ProductionInventory inventory : inventories) {
            // æ”¶é›†éœ€è¦åˆ é™¤çš„生产库存ID
            productionIdsToDelete.add(inventory.getId());
            // ç´¯è®¡åº“存调整量(相同officialId的用量累加)
            BigDecimal adjustment = new BigDecimal(inventory.getUsedQuantity());
            inventoryAdjustMap.merge(
                    inventory.getOfficialId(),
                    adjustment,
                    BigDecimal::add
            );
        }
        // æ‰¹é‡æ›´æ–°å®˜æ–¹åº“å­˜
        for (Map.Entry<Long, BigDecimal> entry : inventoryAdjustMap.entrySet()) {
            OfficialInventory official = officialInventoryMapper.selectById(entry.getKey());
            if (official == null) {
                throw new BaseException("官方库存不存在,ID: " + entry.getKey());
            }
            // ä½¿ç”¨çº¿ç¨‹å®‰å…¨çš„BigDecimal操作
            official.setInventoryQuantity(
                    Optional.ofNullable(official.getInventoryQuantity())
                            .orElse(BigDecimal.ZERO)
                            .add(entry.getValue())
            );
            officialInventoryMapper.updateById(official);
        }
        // æ‰¹é‡åˆ é™¤ç”Ÿäº§åº“å­˜
        if (!productionIdsToDelete.isEmpty()) {
            productionInventoryMapper.deleteBatchIds(productionIdsToDelete);
        }
        return productionIdsToDelete.size();
    }
}
main-business/src/main/java/com/ruoyi/business/vo/ArchiveVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
package com.ruoyi.business.vo;
import com.ruoyi.business.entity.Archive;
import lombok.Data;
@Data
public class ArchiveVo extends Archive {
}
main-business/src/main/resources/mapper/OfficialInventoryMapper.xml
@@ -30,6 +30,10 @@
                update_time,
            id, supplier_name, coal, unit, inventory_quantity, price_including_tax, total_price_including_tax, pending_replenishment, registrant_id, registration_date
    </sql>
    <insert id="addInventoryQuantity">
        update official_inventory set inventory_quantity = inventory_quantity + #{quantity} where id = #{id}
    </insert>
    <select id="getOfficialInventoryForUpdateById" resultType="com.ruoyi.business.entity.OfficialInventory">
        select *
ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
@@ -1,10 +1,14 @@
package com.ruoyi.web.controller.common;
import java.util.ArrayList;
import java.util.List;
import com.ruoyi.basic.service.StorageBlobService;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.framework.config.ServerConfig;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
@@ -16,13 +20,9 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.framework.config.ServerConfig;
import java.util.ArrayList;
import java.util.List;
/**
 * é€šç”¨è¯·æ±‚处理
@@ -142,9 +142,9 @@
     * minio通用上传请求(多个)
     */
    @PostMapping("/minioUploads")
    public R minioUploadFiles(List<MultipartFile> files, String bucketName) throws Exception
    public R minioUploadFiles(List<MultipartFile> files, String bucketName,Long type) throws Exception
    {
        return R.ok(storageBlobService.updateStorageBlobs(files, bucketName));
        return R.ok(storageBlobService.updateStorageBlobs(files, bucketName,type));
    }
    /**
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
@@ -1,24 +1,9 @@
package com.ruoyi.web.controller.system;
import java.util.List;
import java.util.stream.Collectors;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
@@ -31,16 +16,26 @@
import com.ruoyi.system.service.ISysPostService;
import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.vo.SysUserVo;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import java.util.stream.Collectors;
/**
 * ç”¨æˆ·ä¿¡æ¯
 *
 *
 * @author ruoyi
 */
@RestController
@RequestMapping("/system/user")
public class SysUserController extends BaseController
{
public class SysUserController extends BaseController {
    @Autowired
    private ISysUserService userService;
@@ -58,8 +53,7 @@
     */
    @PreAuthorize("@ss.hasPermi('system:user:list')")
    @GetMapping("/list")
    public TableDataInfo list(SysUser user)
    {
    public TableDataInfo list(SysUser user) {
        startPage();
        List<SysUser> list = userService.selectUserList(user);
        return getDataTable(list);
@@ -68,8 +62,7 @@
    @Log(title = "用户管理", businessType = BusinessType.EXPORT)
    @PreAuthorize("@ss.hasPermi('system:user:export')")
    @PostMapping("/export")
    public void export(HttpServletResponse response, SysUser user)
    {
    public void export(HttpServletResponse response, SysUser user) {
        List<SysUser> list = userService.selectUserList(user);
        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
        util.exportExcel(response, list, "用户数据");
@@ -78,8 +71,7 @@
    @Log(title = "用户管理", businessType = BusinessType.IMPORT)
    @PreAuthorize("@ss.hasPermi('system:user:import')")
    @PostMapping("/importData")
    public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
    {
    public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception {
        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
        List<SysUser> userList = util.importExcel(file.getInputStream());
        String operName = getUsername();
@@ -88,8 +80,7 @@
    }
    @PostMapping("/importTemplate")
    public void importTemplate(HttpServletResponse response)
    {
    public void importTemplate(HttpServletResponse response) {
        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
        util.importTemplateExcel(response, "用户数据");
    }
@@ -98,12 +89,10 @@
     * æ ¹æ®ç”¨æˆ·ç¼–号获取详细信息
     */
    @PreAuthorize("@ss.hasPermi('system:user:query')")
    @GetMapping(value = { "/", "/{userId}" })
    public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId)
    {
    @GetMapping(value = {"/", "/{userId}"})
    public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId) {
        AjaxResult ajax = AjaxResult.success();
        if (StringUtils.isNotNull(userId))
        {
        if (StringUtils.isNotNull(userId)) {
            userService.checkUserDataScope(userId);
            SysUser sysUser = userService.selectUserById(userId);
            ajax.put(AjaxResult.DATA_TAG, sysUser);
@@ -122,20 +111,14 @@
    @PreAuthorize("@ss.hasPermi('system:user:add')")
    @Log(title = "用户管理", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@Validated @RequestBody SysUser user)
    {
    public AjaxResult add(@Validated @RequestBody SysUser user) {
        deptService.checkDeptDataScope(user.getDeptId());
        roleService.checkRoleDataScope(user.getRoleIds());
        if (!userService.checkUserNameUnique(user))
        {
        if (!userService.checkUserNameUnique(user)) {
            return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
        }
        else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
        {
        } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) {
            return error("新增用户'" + user.getUserName() + "'失败,手机号码已存在");
        }
        else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
        {
        } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) {
            return error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在");
        }
        user.setCreateBy(getUsername());
@@ -149,22 +132,16 @@
    @PreAuthorize("@ss.hasPermi('system:user:edit')")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@Validated @RequestBody SysUser user)
    {
    public AjaxResult edit(@Validated @RequestBody SysUser user) {
        userService.checkUserAllowed(user);
        userService.checkUserDataScope(user.getUserId());
        deptService.checkDeptDataScope(user.getDeptId());
        roleService.checkRoleDataScope(user.getRoleIds());
        if (!userService.checkUserNameUnique(user))
        {
        if (!userService.checkUserNameUnique(user)) {
            return error("修改用户'" + user.getUserName() + "'失败,登录账号已存在");
        }
        else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
        {
        } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) {
            return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
        }
        else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
        {
        } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) {
            return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
        }
        user.setUpdateBy(getUsername());
@@ -177,10 +154,8 @@
    @PreAuthorize("@ss.hasPermi('system:user:remove')")
    @Log(title = "用户管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{userIds}")
    public AjaxResult remove(@PathVariable Long[] userIds)
    {
        if (ArrayUtils.contains(userIds, getUserId()))
        {
    public AjaxResult remove(@PathVariable Long[] userIds) {
        if (ArrayUtils.contains(userIds, getUserId())) {
            return error("当前用户不能删除");
        }
        return toAjax(userService.deleteUserByIds(userIds));
@@ -192,8 +167,7 @@
    @PreAuthorize("@ss.hasPermi('system:user:resetPwd')")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PutMapping("/resetPwd")
    public AjaxResult resetPwd(@RequestBody SysUser user)
    {
    public AjaxResult resetPwd(@RequestBody SysUser user) {
        userService.checkUserAllowed(user);
        userService.checkUserDataScope(user.getUserId());
        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
@@ -207,8 +181,7 @@
    @PreAuthorize("@ss.hasPermi('system:user:edit')")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PutMapping("/changeStatus")
    public AjaxResult changeStatus(@RequestBody SysUser user)
    {
    public AjaxResult changeStatus(@RequestBody SysUser user) {
        userService.checkUserAllowed(user);
        userService.checkUserDataScope(user.getUserId());
        user.setUpdateBy(getUsername());
@@ -220,8 +193,7 @@
     */
    @PreAuthorize("@ss.hasPermi('system:user:query')")
    @GetMapping("/authRole/{userId}")
    public AjaxResult authRole(@PathVariable("userId") Long userId)
    {
    public AjaxResult authRole(@PathVariable("userId") Long userId) {
        AjaxResult ajax = AjaxResult.success();
        SysUser user = userService.selectUserById(userId);
        List<SysRole> roles = roleService.selectRolesByUserId(userId);
@@ -236,8 +208,7 @@
    @PreAuthorize("@ss.hasPermi('system:user:edit')")
    @Log(title = "用户管理", businessType = BusinessType.GRANT)
    @PutMapping("/authRole")
    public AjaxResult insertAuthRole(Long userId, Long[] roleIds)
    {
    public AjaxResult insertAuthRole(Long userId, Long[] roleIds) {
        userService.checkUserDataScope(userId);
        roleService.checkRoleDataScope(roleIds);
        userService.insertUserAuth(userId, roleIds);
@@ -249,8 +220,16 @@
     */
    @PreAuthorize("@ss.hasPermi('system:user:list')")
    @GetMapping("/deptTree")
    public AjaxResult deptTree(SysDept dept)
    {
    public AjaxResult deptTree(SysDept dept) {
        return success(deptService.selectDeptTreeList(dept));
    }
    /**
     * æ‰€æœ‰ç”¨æˆ·list
     */
    @GetMapping("/listAll")
    public R<List<SysUserVo>> listAll() {
        return R.ok(userService.selectUserListAll());
    }
}
ruoyi-common/src/main/java/com/ruoyi/basic/entity/StorageAttachment.java
@@ -1,13 +1,13 @@
package com.ruoyi.basic.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.basic.entity.dto.StorageBlobDTO;
import lombok.Data;
import com.ruoyi.common.core.domain.BaseEntity;
import java.io.Serializable;
import java.util.Date;
/**
 * é€šç”¨æ–‡ä»¶ä¸Šä¼ çš„附件信息 å®žä½“ç±»
@@ -26,16 +26,24 @@
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
//
//    /**
//     * åˆ›å»ºæ—¶é—´
//     */
//    @TableField(value = "create_time",
//            fill = FieldFill.INSERT,
//            typeHandler = LocalDateTimeTypeHandler.class)
//    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
//    private LocalDateTime createTime;
    /** åˆ›å»ºæ—¶é—´ */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    /** æ›´æ–°æ—¶é—´ */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
//    /**
//     * æ›´æ–°æ—¶é—´
//     */
//    @TableField(value = "update_time",
//            fill = FieldFill.INSERT_UPDATE,
//            typeHandler = LocalDateTimeTypeHandler.class)
//    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
//    private LocalDateTime updateTime;
    /**
     * é€»è¾‘删除
@@ -63,6 +71,7 @@
    @TableField(value = "storage_blob_id")
    private Long storageBlobId;
    @TableField(exist = false)
    private StorageBlobDTO storageBlobDTO;
    public StorageAttachment(String fileType, Long recordType, Long recordId) {
ruoyi-common/src/main/java/com/ruoyi/basic/entity/StorageBlob.java
@@ -1,9 +1,11 @@
package com.ruoyi.basic.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import com.ruoyi.common.core.domain.BaseEntity;
import java.io.Serializable;
import java.util.Date;
@@ -62,4 +64,10 @@
     */
    @TableField(value = "byte_size")
    private Long byteSize;
    /**
     * 0生产前 1生产后 2生产问题
     */
    @TableField(value = "type")
    private Long type;
}
ruoyi-common/src/main/java/com/ruoyi/basic/entity/dto/StorageBlobDTO.java
@@ -6,4 +6,6 @@
@Data
public class StorageBlobDTO extends StorageBlob {
    private String url;
    private String downloadUrl;
}
ruoyi-common/src/main/java/com/ruoyi/basic/service/StorageBlobService.java
@@ -24,7 +24,7 @@
     * @param bucketName å­˜å‚¨æ¡¶åç§°
     * @return ä¸Šä¼ ç»“æžœ
     */
    List<StorageBlobDTO> updateStorageBlobs(List<MultipartFile> files, String bucketName);
    List<StorageBlobDTO> updateStorageBlobs(List<MultipartFile> files, String bucketName,Long type);
    /**
     * æ‰¹é‡åˆ é™¤æ–‡ä»¶
ruoyi-common/src/main/java/com/ruoyi/basic/service/impl/StorageBlobServiceImpl.java
@@ -2,29 +2,26 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
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.StorageBlobService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.config.MinioConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.MinioResult;
import com.ruoyi.common.exception.file.InvalidExtensionException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.MinioUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
import org.springframework.web.multipart.MultipartFile;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
 * <p>
@@ -47,13 +44,12 @@
    private MinioUtils minioUtils;
    @Override
    public List<StorageBlobDTO> updateStorageBlobs(List<MultipartFile> files, String bucketName) {
    public List<StorageBlobDTO> updateStorageBlobs(List<MultipartFile> files, String bucketName,Long type) {
        // è‹¥æ²¡ä¼ å…¥bucketName,则使用默认bucketName
        if (StringUtils.isEmpty(bucketName)) {
            bucketName  = minioUtils.getDefaultBucket();
            bucketName = minioUtils.getDefaultBucket();
        }
        List<StorageBlobDTO> storageBlobDTOs = new ArrayList<>();
        for (MultipartFile file : files) {
            try {
@@ -66,16 +62,17 @@
                dto.setKey(IdUtils.simpleUUID());
                dto.setBucketName(bucketName);
                dto.setUrl(minioUtils.getPreviewUrl(res.getBucketFileName(), bucketName, false));
                dto.setDownloadUrl(minioUtils.getDownloadUrl(res.getBucketFileName(), bucketName));
                if (type != null){
                    dto.setType(type);
                }
                // æ’入数据库
                storageBlobMapper.insert(dto);
                storageBlobDTOs.add(dto);
            } catch (InvalidExtensionException e) {
                throw new RuntimeException("minio文件上传异常:" +  e);
                throw new RuntimeException("minio文件上传异常:" + e);
            }
        }
        return storageBlobDTOs;
    }
@@ -85,20 +82,30 @@
                .eq(StorageAttachment::getRecordId, attachment.getRecordId())
                .eq(StorageAttachment::getRecordType, attachment.getRecordType())
                .eq(StorageAttachment::getName, attachment.getName()));
        List<Long> ids = attachments.stream().map(StorageAttachment::getStorageBlobId).toList();
        List<StorageBlob> storageBlobs = storageBlobMapper.selectList(new LambdaQueryWrapper<StorageBlob>()
                .in(StorageBlob::getId, ids));
        List<Long> ids = attachments.stream()
                .map(StorageAttachment::getStorageBlobId)
                .collect(Collectors.toList());
        List<StorageBlob> storageBlobs = new ArrayList<>();
        if (!ids.isEmpty()) {
            // åªåœ¨ID列表非空时执行查询
            storageBlobs = storageBlobMapper.selectList(
                    new LambdaQueryWrapper<StorageBlob>().in(StorageBlob::getId, ids)
            );
        }
        // ç§»é™¤MinIO中的文件
        if (!storageBlobs.isEmpty()) {
            for (StorageBlob storageBlob : storageBlobs) {
                // ç§»é™¤æ¡¶å†…文件
                minioUtils.removeObjectsResult(storageBlob.getBucketName(), storageBlob.getBucketName());
                minioUtils.removeObjectsResult(storageBlob.getBucketName(), storageBlob.getBucketFilename());
            }
        }
        // åˆ é™¤æ•°æ®åº“记录
        if (!ids.isEmpty()) {
            return storageBlobMapper.delete(new QueryWrapper<StorageBlob>().lambda().in(StorageBlob::getId, ids));
            return storageBlobMapper.delete(
                    new QueryWrapper<StorageBlob>().lambda().in(StorageBlob::getId, ids)
            );
        }
        return 0;
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/enums/StorageAttachmentRecordType.java
@@ -10,7 +10,8 @@
public enum StorageAttachmentRecordType {
    // ä¾‹å­ å®žé™…开发请删除
    Template("Template","范例"),
    Archives("Archives","文档管理");
    Archives("Archives","文档管理"),
    InspectionTasks("InspectionTasks","生产巡检");
    private final String code;
ruoyi-common/src/main/java/com/ruoyi/common/handler/LocalDateTimeTypeHandler.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,67 @@
package com.ruoyi.common.handler;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;
import java.sql.*;
import java.time.LocalDateTime;
@MappedTypes(LocalDateTime.class)
public class LocalDateTimeTypeHandler extends BaseTypeHandler<LocalDateTime> {
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i,
                                    LocalDateTime parameter, JdbcType jdbcType) throws SQLException {
        ps.setObject(i, parameter);
    }
    @Override
    public LocalDateTime getNullableResult(ResultSet rs, String columnName) throws SQLException {
        Object value = rs.getObject(columnName);
        if (value == null) {
            return null;
        }
        if (value instanceof Timestamp) {
            return ((Timestamp) value).toLocalDateTime();
        } else if (value instanceof LocalDateTime) {
            return (LocalDateTime) value;
        }
        // ç‰¹æ®Šå¤„理:如果数据库返回的是字符串
        return LocalDateTime.parse(value.toString());
    }
    @Override
    public LocalDateTime getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        Object value = rs.getObject(columnIndex);
        if (value == null) {
            return null;
        }
        if (value instanceof Timestamp) {
            return ((Timestamp) value).toLocalDateTime();
        } else if (value instanceof LocalDateTime) {
            return (LocalDateTime) value;
        }
        return LocalDateTime.parse(value.toString());
    }
    @Override
    public LocalDateTime getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        Object value = cs.getObject(columnIndex);
        if (value == null) {
            return null;
        }
        if (value instanceof Timestamp) {
            return ((Timestamp) value).toLocalDateTime();
        } else if (value instanceof LocalDateTime) {
            return (LocalDateTime) value;
        }
        return LocalDateTime.parse(value.toString());
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MinioUtils.java
@@ -9,6 +9,8 @@
import io.minio.http.Method;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@@ -16,15 +18,11 @@
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.multipart.MultipartFile;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -303,4 +301,140 @@
        return null;
    }
    /**
     * ä¸‹è½½url(强制浏览器下载文件)
     * @param bucketFileName minio文件名称
     * @param bucketName å­˜å‚¨æ¡¶åç§°
     * @param  ï¼ˆå°æ—¶ï¼‰ï¼Œé»˜è®¤24小时
     * @return æ–‡ä»¶ä¸‹è½½URL
     */
    public String getDownloadUrl(String bucketFileName, String bucketName) {
        if (StringUtils.isNotBlank(bucketFileName)) {
            try {
                // æ£€æŸ¥æ–‡ä»¶æ˜¯å¦å­˜åœ¨
                minioClient.statObject(StatObjectArgs.builder()
                        .bucket(bucketName)
                        .object(bucketFileName)
                        .build());
                // è®¾ç½®å“åº”头
                Map<String, String> reqParams = new HashMap<>();
                // æå–原始文件名(如果存储时保留了原始名称)
                String originalFileName = extractOriginalFileName(bucketFileName);
                reqParams.put("response-content-disposition",
                        "attachment; filename=\"" + URLEncoder.encode(originalFileName, StandardCharsets.UTF_8) + "\"");
                // æž„建预签名URL参数
                GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
                        .method(Method.GET)
                        .bucket(bucketName)
                        .object(bucketFileName)
                        .expiry(previewExpiry, TimeUnit.HOURS)
                        .extraQueryParams(reqParams)
                        .build();
                return minioClient.getPresignedObjectUrl(args);
            } catch (Exception e) {
                throw new UtilException("MinioUtils:生成下载链接异常", e);
            }
        }
        return null;
    }
    /**
     * ä»ŽbucketFileName中提取原始文件名
     * éœ€æ ¹æ®å®žé™…存储规则调整(例如,如果存储时添加了时间戳或UUID后缀)
     */
    private String extractOriginalFileName(String bucketFileName) {
        // ç¤ºä¾‹ï¼šå¦‚果存储格式为 "原始文件名_UUID"
        int underscoreIndex = bucketFileName.lastIndexOf("_");
        if (underscoreIndex > 0) {
            return bucketFileName.substring(0, underscoreIndex);
        }
        // å¦‚果没有特殊格式,直接返回完整文件名
        return bucketFileName;
    }
    /**
     * ç”Ÿæˆé¢„览URL
     * @param bucketFilename æ–‡ä»¶åœ¨MinIO中的唯一标识
     * @param bucketName å­˜å‚¨æ¡¶åç§°
     * @param useDefaultExpiry æ˜¯å¦ä½¿ç”¨é»˜è®¤è¿‡æœŸæ—¶é—´ï¼ˆtrue=使用默认过期时间,false=永久有效)
     * @return é¢„览URL
     */
    public String getPreviewUrls(String bucketFilename, String bucketName, boolean useDefaultExpiry) {
        if (StringUtils.isBlank(bucketFilename)) {
            return null;
        }
        try {
            // éªŒè¯æ–‡ä»¶å­˜åœ¨æ€§
            minioClient.statObject(StatObjectArgs.builder()
                    .bucket(bucketName)
                    .object(bucketFilename)
                    .build());
            GetPresignedObjectUrlArgs.Builder builder = GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(bucketName)
                    .object(bucketFilename);
            // è®¾ç½®è¿‡æœŸæ—¶é—´ï¼šuseDefaultExpiry=true ä½¿ç”¨é…ç½®çš„过期时间
            if (useDefaultExpiry) {
                builder.expiry(previewExpiry, TimeUnit.HOURS);
            }
            return minioClient.getPresignedObjectUrl(builder.build());
        } catch (Exception e) {
            throw new UtilException("生成预览URL失败: " + e.getMessage(), e);
        }
    }
    /**
     * ç”Ÿæˆä¸‹è½½URL(强制浏览器下载)
     * @param bucketFilename æ–‡ä»¶åœ¨MinIO中的唯一标识
     * @param bucketName å­˜å‚¨æ¡¶åç§°
     * @param originalFileName åŽŸå§‹æ–‡ä»¶åï¼ˆç”¨äºŽä¸‹è½½æ—¶æ˜¾ç¤ºï¼‰
     * @param useDefaultExpiry æ˜¯å¦ä½¿ç”¨é»˜è®¤è¿‡æœŸæ—¶é—´ï¼ˆtrue=使用默认,false=无过期时间)
     * @return ä¸‹è½½URL
     */
    public String getDownloadUrls(String bucketFilename, String bucketName, String originalFileName, boolean useDefaultExpiry) {
        if (StringUtils.isBlank(bucketFilename)) {
            return null;
        }
        try {
            // éªŒè¯æ–‡ä»¶å­˜åœ¨æ€§
            minioClient.statObject(StatObjectArgs.builder()
                    .bucket(bucketName)
                    .object(bucketFilename)
                    .build());
            // æ­£ç¡®ç¼–码文件名:替换 + ä¸º %20
            String encodedFileName = URLEncoder.encode(originalFileName, StandardCharsets.UTF_8)
                    .replace("+", "%20");
            Map<String, String> reqParams = new HashMap<>();
            reqParams.put("response-content-disposition",
                    "attachment; filename=\"" + encodedFileName + "\"");
            GetPresignedObjectUrlArgs.Builder builder = GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(bucketName)
                    .object(bucketFilename)
                    .extraQueryParams(reqParams);
            // æ ¹æ®å‚数决定是否设置过期时间
            if (useDefaultExpiry) {
                // ä½¿ç”¨é»˜è®¤è¿‡æœŸæ—¶é—´ï¼ˆä»Žé…ç½®è¯»å–)
                builder.expiry(previewExpiry, TimeUnit.HOURS);
            } else {
                // ä¸è®¾ç½®è¿‡æœŸæ—¶é—´ï¼ˆMinIO é»˜è®¤7天)
            }
            return minioClient.getPresignedObjectUrl(builder.build());
        } catch (Exception e) {
            throw new UtilException("生成下载URL失败: " + e.getMessage(), e);
        }
    }
}
ruoyi-framework/src/main/java/com/ruoyi/framework/config/MybatisPlusConfig.java
@@ -1,10 +1,13 @@
package com.ruoyi.framework.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.ruoyi.common.handler.LocalDateTimeTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -12,15 +15,35 @@
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // åˆ†é¡µ
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.POSTGRE_SQL));
        // ä¹è§‚锁
        // 1. åˆ†é¡µæ’ä»¶ - æŒ‡å®š PostgreSQL æ•°æ®åº“类型
        PaginationInnerInterceptor pagination = new PaginationInnerInterceptor(DbType.POSTGRE_SQL);
        pagination.setOptimizeJoin(true); // ä¼˜åŒ– JOIN æŸ¥è¯¢
        pagination.setMaxLimit(500L); // è®¾ç½®æœ€å¤§å•页限制
        interceptor.addInnerInterceptor(pagination);
        // 2. ä¹è§‚锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        // é˜²æ­¢å…¨å±€åˆ é™¤æˆ–æ›´æ–°
        // 3. é˜²æ­¢å…¨è¡¨æ›´æ–°/删除插件
        interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
        return interceptor;
    }
    // 4. æ·»åŠ å…¨å±€ç±»åž‹å¤„ç†å™¨é…ç½®
    @Bean
    public ConfigurationCustomizer configurationCustomizer() {
        return configuration -> {
            // æ³¨å†Œ LocalDateTime ç±»åž‹å¤„理器
            configuration.getTypeHandlerRegistry().register(new LocalDateTimeTypeHandler());
            // è®¾ç½®ç©ºå€¼å¤„理策略
            configuration.setJdbcTypeForNull(JdbcType.NULL);
            // å¯ç”¨è‡ªåŠ¨é©¼å³°å‘½åè§„åˆ™æ˜ å°„
            configuration.setMapUnderscoreToCamelCase(true);
        };
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java
@@ -1,8 +1,10 @@
package com.ruoyi.system.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.common.core.domain.entity.SysUser;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
 * ç”¨æˆ·è¡¨ æ•°æ®å±‚
@@ -10,7 +12,7 @@
 * @author ruoyi
 */
public interface SysUserMapper
{
extends BaseMapper<SysUser> {
    /**
     * æ ¹æ®æ¡ä»¶åˆ†é¡µæŸ¥è¯¢ç”¨æˆ·åˆ—表
     * 
@@ -124,4 +126,9 @@
     * @return ç»“æžœ
     */
    public SysUser checkEmailUnique(String email);
    /**
     * æŸ¥è¯¢æ‰€æœ‰ç”¨æˆ·
     */
    List<SysUser> selectUserListAll();
}
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java
@@ -1,7 +1,9 @@
package com.ruoyi.system.service;
import java.util.List;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.system.vo.SysUserVo;
import java.util.List;
/**
 * ç”¨æˆ· ä¸šåС层
@@ -203,4 +205,6 @@
     * @return ç»“æžœ
     */
    public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName);
    List<SysUserVo> selectUserListAll();
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
@@ -1,15 +1,5 @@
package com.ruoyi.system.service.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import jakarta.validation.Validator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.entity.SysRole;
@@ -22,124 +12,116 @@
import com.ruoyi.system.domain.SysPost;
import com.ruoyi.system.domain.SysUserPost;
import com.ruoyi.system.domain.SysUserRole;
import com.ruoyi.system.mapper.SysPostMapper;
import com.ruoyi.system.mapper.SysRoleMapper;
import com.ruoyi.system.mapper.SysUserMapper;
import com.ruoyi.system.mapper.SysUserPostMapper;
import com.ruoyi.system.mapper.SysUserRoleMapper;
import com.ruoyi.system.mapper.*;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.vo.SysUserVo;
import jakarta.validation.Validator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
 * ç”¨æˆ· ä¸šåŠ¡å±‚å¤„ç†
 *
 *
 * @author ruoyi
 */
@Service
public class SysUserServiceImpl implements ISysUserService
{
public class SysUserServiceImpl implements ISysUserService {
    private static final Logger log = LoggerFactory.getLogger(SysUserServiceImpl.class);
    @Autowired
    protected Validator validator;
    @Autowired
    private SysUserMapper userMapper;
    @Autowired
    private SysRoleMapper roleMapper;
    @Autowired
    private SysPostMapper postMapper;
    @Autowired
    private SysUserRoleMapper userRoleMapper;
    @Autowired
    private SysUserPostMapper userPostMapper;
    @Autowired
    private ISysConfigService configService;
    @Autowired
    private ISysDeptService deptService;
    @Autowired
    protected Validator validator;
    /**
     * æ ¹æ®æ¡ä»¶åˆ†é¡µæŸ¥è¯¢ç”¨æˆ·åˆ—表
     *
     *
     * @param user ç”¨æˆ·ä¿¡æ¯
     * @return ç”¨æˆ·ä¿¡æ¯é›†åˆä¿¡æ¯
     */
    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public List<SysUser> selectUserList(SysUser user)
    {
    public List<SysUser> selectUserList(SysUser user) {
        return userMapper.selectUserList(user);
    }
    /**
     * æ ¹æ®æ¡ä»¶åˆ†é¡µæŸ¥è¯¢å·²åˆ†é…ç”¨æˆ·è§’色列表
     *
     *
     * @param user ç”¨æˆ·ä¿¡æ¯
     * @return ç”¨æˆ·ä¿¡æ¯é›†åˆä¿¡æ¯
     */
    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public List<SysUser> selectAllocatedList(SysUser user)
    {
    public List<SysUser> selectAllocatedList(SysUser user) {
        return userMapper.selectAllocatedList(user);
    }
    /**
     * æ ¹æ®æ¡ä»¶åˆ†é¡µæŸ¥è¯¢æœªåˆ†é…ç”¨æˆ·è§’色列表
     *
     *
     * @param user ç”¨æˆ·ä¿¡æ¯
     * @return ç”¨æˆ·ä¿¡æ¯é›†åˆä¿¡æ¯
     */
    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public List<SysUser> selectUnallocatedList(SysUser user)
    {
    public List<SysUser> selectUnallocatedList(SysUser user) {
        return userMapper.selectUnallocatedList(user);
    }
    /**
     * é€šè¿‡ç”¨æˆ·åæŸ¥è¯¢ç”¨æˆ·
     *
     *
     * @param userName ç”¨æˆ·å
     * @return ç”¨æˆ·å¯¹è±¡ä¿¡æ¯
     */
    @Override
    public SysUser selectUserByUserName(String userName)
    {
    public SysUser selectUserByUserName(String userName) {
        return userMapper.selectUserByUserName(userName);
    }
    /**
     * é€šè¿‡ç”¨æˆ·ID查询用户
     *
     *
     * @param userId ç”¨æˆ·ID
     * @return ç”¨æˆ·å¯¹è±¡ä¿¡æ¯
     */
    @Override
    public SysUser selectUserById(Long userId)
    {
    public SysUser selectUserById(Long userId) {
        return userMapper.selectUserById(userId);
    }
    /**
     * æŸ¥è¯¢ç”¨æˆ·æ‰€å±žè§’色组
     *
     *
     * @param userName ç”¨æˆ·å
     * @return ç»“æžœ
     */
    @Override
    public String selectUserRoleGroup(String userName)
    {
    public String selectUserRoleGroup(String userName) {
        List<SysRole> list = roleMapper.selectRolesByUserName(userName);
        if (CollectionUtils.isEmpty(list))
        {
        if (CollectionUtils.isEmpty(list)) {
            return StringUtils.EMPTY;
        }
        return list.stream().map(SysRole::getRoleName).collect(Collectors.joining(","));
@@ -147,16 +129,14 @@
    /**
     * æŸ¥è¯¢ç”¨æˆ·æ‰€å±žå²—位组
     *
     *
     * @param userName ç”¨æˆ·å
     * @return ç»“æžœ
     */
    @Override
    public String selectUserPostGroup(String userName)
    {
    public String selectUserPostGroup(String userName) {
        List<SysPost> list = postMapper.selectPostsByUserName(userName);
        if (CollectionUtils.isEmpty(list))
        {
        if (CollectionUtils.isEmpty(list)) {
            return StringUtils.EMPTY;
        }
        return list.stream().map(SysPost::getPostName).collect(Collectors.joining(","));
@@ -164,17 +144,15 @@
    /**
     * æ ¡éªŒç”¨æˆ·åç§°æ˜¯å¦å”¯ä¸€
     *
     *
     * @param user ç”¨æˆ·ä¿¡æ¯
     * @return ç»“æžœ
     */
    @Override
    public boolean checkUserNameUnique(SysUser user)
    {
    public boolean checkUserNameUnique(SysUser user) {
        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
        SysUser info = userMapper.checkUserNameUnique(user.getUserName());
        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue())
        {
        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
@@ -187,12 +165,10 @@
     * @return
     */
    @Override
    public boolean checkPhoneUnique(SysUser user)
    {
    public boolean checkPhoneUnique(SysUser user) {
        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
        SysUser info = userMapper.checkPhoneUnique(user.getPhonenumber());
        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue())
        {
        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
@@ -205,12 +181,10 @@
     * @return
     */
    @Override
    public boolean checkEmailUnique(SysUser user)
    {
    public boolean checkEmailUnique(SysUser user) {
        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
        SysUser info = userMapper.checkEmailUnique(user.getEmail());
        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue())
        {
        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
@@ -218,33 +192,28 @@
    /**
     * æ ¡éªŒç”¨æˆ·æ˜¯å¦å…è®¸æ“ä½œ
     *
     *
     * @param user ç”¨æˆ·ä¿¡æ¯
     */
    @Override
    public void checkUserAllowed(SysUser user)
    {
        if (StringUtils.isNotNull(user.getUserId()) && user.isAdmin())
        {
    public void checkUserAllowed(SysUser user) {
        if (StringUtils.isNotNull(user.getUserId()) && user.isAdmin()) {
            throw new ServiceException("不允许操作超级管理员用户");
        }
    }
    /**
     * æ ¡éªŒç”¨æˆ·æ˜¯å¦æœ‰æ•°æ®æƒé™
     *
     *
     * @param userId ç”¨æˆ·id
     */
    @Override
    public void checkUserDataScope(Long userId)
    {
        if (!SysUser.isAdmin(SecurityUtils.getUserId()))
        {
    public void checkUserDataScope(Long userId) {
        if (!SysUser.isAdmin(SecurityUtils.getUserId())) {
            SysUser user = new SysUser();
            user.setUserId(userId);
            List<SysUser> users = SpringUtils.getAopProxy(this).selectUserList(user);
            if (StringUtils.isEmpty(users))
            {
            if (StringUtils.isEmpty(users)) {
                throw new ServiceException("没有权限访问用户数据!");
            }
        }
@@ -252,14 +221,13 @@
    /**
     * æ–°å¢žä¿å­˜ç”¨æˆ·ä¿¡æ¯
     *
     *
     * @param user ç”¨æˆ·ä¿¡æ¯
     * @return ç»“æžœ
     */
    @Override
    @Transactional
    public int insertUser(SysUser user)
    {
    public int insertUser(SysUser user) {
        // æ–°å¢žç”¨æˆ·ä¿¡æ¯
        int rows = userMapper.insertUser(user);
        // æ–°å¢žç”¨æˆ·å²—位关联
@@ -271,26 +239,24 @@
    /**
     * æ³¨å†Œç”¨æˆ·ä¿¡æ¯
     *
     *
     * @param user ç”¨æˆ·ä¿¡æ¯
     * @return ç»“æžœ
     */
    @Override
    public boolean registerUser(SysUser user)
    {
    public boolean registerUser(SysUser user) {
        return userMapper.insertUser(user) > 0;
    }
    /**
     * ä¿®æ”¹ä¿å­˜ç”¨æˆ·ä¿¡æ¯
     *
     *
     * @param user ç”¨æˆ·ä¿¡æ¯
     * @return ç»“æžœ
     */
    @Override
    @Transactional
    public int updateUser(SysUser user)
    {
    public int updateUser(SysUser user) {
        Long userId = user.getUserId();
        // åˆ é™¤ç”¨æˆ·ä¸Žè§’色关联
        userRoleMapper.deleteUserRoleByUserId(userId);
@@ -305,104 +271,94 @@
    /**
     * ç”¨æˆ·æŽˆæƒè§’色
     *
     * @param userId ç”¨æˆ·ID
     *
     * @param userId  ç”¨æˆ·ID
     * @param roleIds è§’色组
     */
    @Override
    @Transactional
    public void insertUserAuth(Long userId, Long[] roleIds)
    {
    public void insertUserAuth(Long userId, Long[] roleIds) {
        userRoleMapper.deleteUserRoleByUserId(userId);
        insertUserRole(userId, roleIds);
    }
    /**
     * ä¿®æ”¹ç”¨æˆ·çŠ¶æ€
     *
     *
     * @param user ç”¨æˆ·ä¿¡æ¯
     * @return ç»“æžœ
     */
    @Override
    public int updateUserStatus(SysUser user)
    {
    public int updateUserStatus(SysUser user) {
        return userMapper.updateUser(user);
    }
    /**
     * ä¿®æ”¹ç”¨æˆ·åŸºæœ¬ä¿¡æ¯
     *
     *
     * @param user ç”¨æˆ·ä¿¡æ¯
     * @return ç»“æžœ
     */
    @Override
    public int updateUserProfile(SysUser user)
    {
    public int updateUserProfile(SysUser user) {
        return userMapper.updateUser(user);
    }
    /**
     * ä¿®æ”¹ç”¨æˆ·å¤´åƒ
     *
     *
     * @param userName ç”¨æˆ·å
     * @param avatar å¤´åƒåœ°å€
     * @param avatar   å¤´åƒåœ°å€
     * @return ç»“æžœ
     */
    @Override
    public boolean updateUserAvatar(String userName, String avatar)
    {
    public boolean updateUserAvatar(String userName, String avatar) {
        return userMapper.updateUserAvatar(userName, avatar) > 0;
    }
    /**
     * é‡ç½®ç”¨æˆ·å¯†ç 
     *
     *
     * @param user ç”¨æˆ·ä¿¡æ¯
     * @return ç»“æžœ
     */
    @Override
    public int resetPwd(SysUser user)
    {
    public int resetPwd(SysUser user) {
        return userMapper.updateUser(user);
    }
    /**
     * é‡ç½®ç”¨æˆ·å¯†ç 
     *
     *
     * @param userName ç”¨æˆ·å
     * @param password å¯†ç 
     * @return ç»“æžœ
     */
    @Override
    public int resetUserPwd(String userName, String password)
    {
    public int resetUserPwd(String userName, String password) {
        return userMapper.resetUserPwd(userName, password);
    }
    /**
     * æ–°å¢žç”¨æˆ·è§’色信息
     *
     *
     * @param user ç”¨æˆ·å¯¹è±¡
     */
    public void insertUserRole(SysUser user)
    {
    public void insertUserRole(SysUser user) {
        this.insertUserRole(user.getUserId(), user.getRoleIds());
    }
    /**
     * æ–°å¢žç”¨æˆ·å²—位信息
     *
     *
     * @param user ç”¨æˆ·å¯¹è±¡
     */
    public void insertUserPost(SysUser user)
    {
    public void insertUserPost(SysUser user) {
        Long[] posts = user.getPostIds();
        if (StringUtils.isNotEmpty(posts))
        {
        if (StringUtils.isNotEmpty(posts)) {
            // æ–°å¢žç”¨æˆ·ä¸Žå²—位管理
            List<SysUserPost> list = new ArrayList<SysUserPost>(posts.length);
            for (Long postId : posts)
            {
            for (Long postId : posts) {
                SysUserPost up = new SysUserPost();
                up.setUserId(user.getUserId());
                up.setPostId(postId);
@@ -414,18 +370,15 @@
    /**
     * æ–°å¢žç”¨æˆ·è§’色信息
     *
     * @param userId ç”¨æˆ·ID
     *
     * @param userId  ç”¨æˆ·ID
     * @param roleIds è§’色组
     */
    public void insertUserRole(Long userId, Long[] roleIds)
    {
        if (StringUtils.isNotEmpty(roleIds))
        {
    public void insertUserRole(Long userId, Long[] roleIds) {
        if (StringUtils.isNotEmpty(roleIds)) {
            // æ–°å¢žç”¨æˆ·ä¸Žè§’色管理
            List<SysUserRole> list = new ArrayList<SysUserRole>(roleIds.length);
            for (Long roleId : roleIds)
            {
            for (Long roleId : roleIds) {
                SysUserRole ur = new SysUserRole();
                ur.setUserId(userId);
                ur.setRoleId(roleId);
@@ -437,14 +390,13 @@
    /**
     * é€šè¿‡ç”¨æˆ·ID删除用户
     *
     *
     * @param userId ç”¨æˆ·ID
     * @return ç»“æžœ
     */
    @Override
    @Transactional
    public int deleteUserById(Long userId)
    {
    public int deleteUserById(Long userId) {
        // åˆ é™¤ç”¨æˆ·ä¸Žè§’色关联
        userRoleMapper.deleteUserRoleByUserId(userId);
        // åˆ é™¤ç”¨æˆ·ä¸Žå²—位表
@@ -454,16 +406,14 @@
    /**
     * æ‰¹é‡åˆ é™¤ç”¨æˆ·ä¿¡æ¯
     *
     *
     * @param userIds éœ€è¦åˆ é™¤çš„用户ID
     * @return ç»“æžœ
     */
    @Override
    @Transactional
    public int deleteUserByIds(Long[] userIds)
    {
        for (Long userId : userIds)
        {
    public int deleteUserByIds(Long[] userIds) {
        for (Long userId : userIds) {
            checkUserAllowed(new SysUser(userId));
            checkUserDataScope(userId);
        }
@@ -474,33 +424,42 @@
        return userMapper.deleteUserByIds(userIds);
    }
    @Override
    public List<SysUserVo> selectUserListAll() {
        List<SysUser> allUsers = userMapper.selectUserListAll();
        // åˆ›å»ºæ–°çš„列表,只保留 userId å’Œ userName
        List<SysUserVo> result = new ArrayList<>();
        for (SysUser user : allUsers) {
            SysUserVo simpleUser = new SysUserVo();
            simpleUser.setUserId(user.getUserId());
            simpleUser.setNickName(user.getNickName());
            result.add(simpleUser);
        }
        return result;
    }
    /**
     * å¯¼å…¥ç”¨æˆ·æ•°æ®
     *
     * @param userList ç”¨æˆ·æ•°æ®åˆ—表
     *
     * @param userList        ç”¨æˆ·æ•°æ®åˆ—表
     * @param isUpdateSupport æ˜¯å¦æ›´æ–°æ”¯æŒï¼Œå¦‚果已存在,则进行更新数据
     * @param operName æ“ä½œç”¨æˆ·
     * @param operName        æ“ä½œç”¨æˆ·
     * @return ç»“æžœ
     */
    @Override
    public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName)
    {
        if (StringUtils.isNull(userList) || userList.size() == 0)
        {
    public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName) {
        if (StringUtils.isNull(userList) || userList.size() == 0) {
            throw new ServiceException("导入用户数据不能为空!");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        for (SysUser user : userList)
        {
            try
            {
        for (SysUser user : userList) {
            try {
                // éªŒè¯æ˜¯å¦å­˜åœ¨è¿™ä¸ªç”¨æˆ·
                SysUser u = userMapper.selectUserByUserName(user.getUserName());
                if (StringUtils.isNull(u))
                {
                if (StringUtils.isNull(u)) {
                    BeanValidators.validateWithException(validator, user);
                    deptService.checkDeptDataScope(user.getDeptId());
                    String password = configService.selectConfigByKey("sys.user.initPassword");
@@ -509,9 +468,7 @@
                    userMapper.insertUser(user);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " å¯¼å…¥æˆåŠŸ");
                }
                else if (isUpdateSupport)
                {
                } else if (isUpdateSupport) {
                    BeanValidators.validateWithException(validator, user);
                    checkUserAllowed(u);
                    checkUserDataScope(u.getUserId());
@@ -521,28 +478,21 @@
                    userMapper.updateUser(user);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " æ›´æ–°æˆåŠŸ");
                }
                else
                {
                } else {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、账号 " + user.getUserName() + " å·²å­˜åœ¨");
                }
            }
            catch (Exception e)
            {
            } catch (Exception e) {
                failureNum++;
                String msg = "<br/>" + failureNum + "、账号 " + user.getUserName() + " å¯¼å…¥å¤±è´¥ï¼š";
                failureMsg.append(msg + e.getMessage());
                log.error(msg, e);
            }
        }
        if (failureNum > 0)
        {
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " æ¡æ•°æ®æ ¼å¼ä¸æ­£ç¡®ï¼Œé”™è¯¯å¦‚下:");
            throw new ServiceException(failureMsg.toString());
        }
        else
        {
        } else {
            successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " æ¡ï¼Œæ•°æ®å¦‚下:");
        }
        return successMsg.toString();
ruoyi-system/src/main/java/com/ruoyi/system/vo/SysUserVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
package com.ruoyi.system.vo;
import lombok.Data;
@Data
public class SysUserVo {
    private Long userId;
    private String nickName;
}
ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
@@ -141,7 +141,10 @@
    <select id="checkEmailUnique" parameterType="String" resultMap="SysUserResult">
        select user_id, email from sys_user where email = #{email} and del_flag = '0' limit 1
    </select>
    <select id="selectUserListAll" resultType="com.ruoyi.common.core.domain.entity.SysUser">
        select user_id, nick_name from sys_user where del_flag = '0'
    </select>
    <insert id="insertUser" parameterType="SysUser" useGeneratedKeys="true" keyProperty="userId">
         insert into sys_user(
             <if test="userId != null and userId != 0">user_id,</if>