yaowanxin
8 小时以前 b0bc22e001eb3e93254ef6cf525d916ddc6542ff
人力资源模块2
已修改1个文件
已添加13个文件
513 ■■■■■ 文件已修改
main-business/pom.xml 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/controller/AccountFileController.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/entity/AccountFile.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/mapper/AccountFileMapper.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/other/controller/TempFileController.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/other/mapper/CommonFileMapper.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/other/mapper/TempFileMapper.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/other/pojo/CommonFile.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/other/pojo/TempFile.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/other/service/TempFileService.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/other/service/impl/TempFileServiceImpl.java 183 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/service/AccountFileService.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/service/impl/AccountFileServiceImpl.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/resources/mapper/AccountFileMapper.xml 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/pom.xml
@@ -28,7 +28,10 @@
            <artifactId>poi-ooxml</artifactId>
            <version>5.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- æ ¸å¿ƒæ¨¡å—-->
        <dependency>
main-business/src/main/java/com/ruoyi/business/controller/AccountFileController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,63 @@
package com.ruoyi.business.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.business.entity.AccountFile;
import com.ruoyi.business.service.AccountFileService;
import com.ruoyi.common.core.domain.AjaxResult;
import jakarta.annotation.Resource;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
 * è´¢åС附件
 */
@RestController
@RequestMapping("/account/accountFile")
public class AccountFileController {
    @Resource
    private AccountFileService accountFileService;
    /**
     * æ–°å¢ž
     * @param accountFile
     * @return
     */
    @PostMapping("/add")
    public AjaxResult add(@RequestBody AccountFile accountFile) {
        return AjaxResult.success(accountFileService.save(accountFile));
    }
    /**
     * åˆ é™¤
     * @param ids
     * @return
     */
    @DeleteMapping("/del")
    public AjaxResult delAccountFile(@RequestBody List<Integer> ids) {
        if(CollectionUtils.isEmpty(ids)){
            return AjaxResult.error("请选择至少一条数据");
        }
        //删除检验附件
        return AjaxResult.success(accountFileService.removeBatchByIds(ids));
    }
    /**
     *分页查询
     * @param page
     * @param accountFile
     * @return
     */
    @GetMapping("/listPage")
    public AjaxResult accountFileListPage(Page page, AccountFile accountFile) {
        return AjaxResult.success(accountFileService.accountFileListPage(page, accountFile));
    }
}
main-business/src/main/java/com/ruoyi/business/entity/AccountFile.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,67 @@
package com.ruoyi.business.entity;
import com.baomidou.mybatisplus.annotation.*;
import io.swagger.annotations.ApiModelProperty;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
 * è´¢åŠ¡ç®¡ç†--附件
 * account_file
 */
@TableName(value = "account_file")
@Data
public class AccountFile implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * åºå·
     */
    @TableId(type = IdType.AUTO)
    private Long id;
    @ApiModelProperty(value = "文件名称")
    private String name;
    @ApiModelProperty(value = "文件路径")
    private String url;
    @ApiModelProperty(value = "文件大小")
    private int fileSize;
    @ApiModelProperty(value = "财务ID")
    @NotBlank(message = "财务id不能为空!")
    private Long accountId;
    /**
     * ç±»åž‹(收入/支出)
     */
    @ApiModelProperty(value = "类型(收入/支出)")
    private String accountType;
    @ApiModelProperty(value = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @ApiModelProperty(value = "修改时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    @ApiModelProperty(value = "创建用户")
    @TableField(fill = FieldFill.INSERT)
    private Integer createUser;
    @ApiModelProperty(value = "修改用户")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Integer updateUser;
    @ApiModelProperty(value = "租户ID")
    @TableField(fill = FieldFill.INSERT)
    private Long tenantId;
}
main-business/src/main/java/com/ruoyi/business/mapper/AccountFileMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,15 @@
package com.ruoyi.business.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.business.entity.AccountFile;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface AccountFileMapper extends BaseMapper<AccountFile> {
    IPage<AccountFile> accountFileListPage(Page page, @Param("accountFile") AccountFile accountFile);
}
main-business/src/main/java/com/ruoyi/business/other/controller/TempFileController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,32 @@
package com.ruoyi.business.other.controller;
import com.ruoyi.business.other.service.TempFileService;
import com.ruoyi.common.core.domain.AjaxResult;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
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;
@RestController
@RequestMapping("/file")
@AllArgsConstructor
public class TempFileController {
    private TempFileService tempFileService;
    @PostMapping("/upload")
    public AjaxResult uploadFile(MultipartFile file, Integer type) {
        try {
            return AjaxResult.success(tempFileService.uploadFile(file, type));
        } catch (Exception e) {
            return AjaxResult.error(e.getMessage());
        }
    }
}
main-business/src/main/java/com/ruoyi/business/other/mapper/CommonFileMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,9 @@
package com.ruoyi.business.other.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.business.other.pojo.CommonFile;
public interface CommonFileMapper extends BaseMapper<CommonFile> {
}
main-business/src/main/java/com/ruoyi/business/other/mapper/TempFileMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,9 @@
package com.ruoyi.business.other.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.business.other.pojo.TempFile;
public interface TempFileMapper extends BaseMapper<TempFile> {
}
main-business/src/main/java/com/ruoyi/business/other/pojo/CommonFile.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,40 @@
package com.ruoyi.business.other.pojo;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.time.LocalDateTime;
/**
 * é€šç”¨é™„件上传表
 */
@Data
@TableName("common_file")
public class CommonFile {
    private static final long serialVersionUID = 1L;
    @TableId(type = IdType.AUTO)
    private Long id;
    /** å…³è”表主键D */
    private Long commonId;
    /** æ–‡ä»¶åç§° */
    private String name;
    /** æ–‡ä»¶è·¯å¾„ */
    private String url;
    /** å…³è”表 */
    private Integer type;
    /** åˆ›å»ºæ—¶é—´ */
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    /** æ›´æ–°æ—¶é—´ */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
}
main-business/src/main/java/com/ruoyi/business/other/pojo/TempFile.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
package com.ruoyi.business.other.pojo;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("temp_file")
public class TempFile {
    private static final long serialVersionUID = 1L;
    @TableId
    private String tempId;         // ä¸´æ—¶æ–‡ä»¶ID(UUID)
    private String originalName;   // åŽŸå§‹æ–‡ä»¶å
    private String tempPath;       // ä¸´æ—¶å­˜å‚¨è·¯å¾„
    private LocalDateTime expireTime; // è¿‡æœŸæ—¶é—´
    private Integer type;       // å…³è”表类型
}
main-business/src/main/java/com/ruoyi/business/other/service/TempFileService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,11 @@
package com.ruoyi.business.other.service;
import com.ruoyi.business.other.pojo.TempFile;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
public interface TempFileService {
    TempFile uploadFile(MultipartFile file, Integer type) throws IOException;
}
main-business/src/main/java/com/ruoyi/business/other/service/impl/TempFileServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,183 @@
package com.ruoyi.business.other.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.business.other.mapper.CommonFileMapper;
import com.ruoyi.business.other.mapper.TempFileMapper;
import com.ruoyi.business.other.pojo.CommonFile;
import com.ruoyi.business.other.pojo.TempFile;
import com.ruoyi.business.other.service.TempFileService;
import com.ruoyi.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.UUID;
@Service
@Slf4j
public class TempFileServiceImpl extends ServiceImpl<TempFileMapper, TempFile> implements TempFileService {
    @Autowired
    private TempFileMapper tempFileMapper;
    @Autowired
    private CommonFileMapper commonFileMapper;
    @Value("${file.upload-dir}")
    private String uploadDir;
    @Value("${file.temp-dir}")
    private String tempDir;
    // ä¸Šä¼ åˆ°ä¸´æ—¶ç›®å½•
    @Override
    public TempFile uploadFile(MultipartFile file,Integer type) throws IOException {
        // 1. ç”Ÿæˆä¸´æ—¶æ–‡ä»¶ID和路径
        String tempId = UUID.randomUUID().toString();
        String originalFilename = file.getOriginalFilename();
        if(originalFilename == null) throw new IOException("文件名不能为空");
//        URLEncoder urlEncoder = new URLEncoder();
//        String encodedFilename = urlEncoder.encode(originalFilename, StandardCharsets.UTF_8);
//        encodedFilename = encodedFilename.replaceAll("%2E",".");
//        Path tempFilePath = Paths.get(tempDir, tempId + "_" + encodedFilename);
        Path tempFilePath = Paths.get(tempDir, tempId + "_" + file.getOriginalFilename());
        // 2. ç¡®ä¿ç›®å½•存在
        Path parentDir = tempFilePath.getParent();
        if (parentDir != null && !Files.exists(parentDir)) {
            try {
                // é€’归创建目录并检查结果
                Files.createDirectories(parentDir);
            } catch (IOException e) {
                log.error("创建目录失败: {}", parentDir, e);
                throw new IOException("无法创建目录: " + parentDir, e);
            }
        }
//        if (parentDir != null) {
//            Files.createDirectories(parentDir); // é€’归创建目录
//        }
        // 3. ä¿å­˜æ–‡ä»¶åˆ°ä¸´æ—¶ç›®å½•
        file.transferTo(tempFilePath.toFile());
        // 4. ä¿å­˜ä¸´æ—¶æ–‡ä»¶è®°å½•
        TempFile tempFileRecord = new TempFile();
        tempFileRecord.setTempId(tempId);
        tempFileRecord.setOriginalName(file.getOriginalFilename());
        tempFileRecord.setTempPath(tempFilePath.toString());
        tempFileRecord.setExpireTime(LocalDateTime.now().plusHours(2)); // 2小时后过期
        tempFileRecord.setType(type);
        tempFileMapper.insert(tempFileRecord);
        return tempFileRecord;
    }
    /**
     * å°†ä¸´æ—¶æ–‡ä»¶è¿ç§»åˆ°æ­£å¼ç›®å½•
     *
     * @param businessId  ä¸šåŠ¡ID(销售台账ID)
     * @param tempFileIds ä¸´æ—¶æ–‡ä»¶ID列表
     * @param fileType     æ–‡ä»¶ç±»åž‹(来自FileNameType)
     * @throws IOException æ–‡ä»¶æ“ä½œå¼‚常
     */
    public void migrateTempFilesToFormal(Long businessId, List<String> tempFileIds, Integer fileType) throws IOException {
        if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(tempFileIds)) {
            return;
        }
        // æž„建正式目录路径(按业务类型和日期分组)
        String formalDir = uploadDir + LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE);
        Path formalDirPath = Paths.get(formalDir);
        // ç¡®ä¿æ­£å¼ç›®å½•存在(递归创建)
        if (!Files.exists(formalDirPath)) {
            Files.createDirectories(formalDirPath);
        }
        for (String tempFileId : tempFileIds) {
            // æŸ¥è¯¢ä¸´æ—¶æ–‡ä»¶è®°å½•
            TempFile tempFile = tempFileMapper.selectById(tempFileId);
            if (tempFile == null) {
                log.warn("临时文件不存在,跳过处理: {}", tempFileId);
                continue;
            }
            // æž„建正式文件名(包含业务ID和时间戳,避免冲突)
            String originalFilename = tempFile.getOriginalName();
            String fileExtension = FilenameUtils.getExtension(originalFilename);
            String formalFilename = businessId + "_" +
                    System.currentTimeMillis() + "_" +
                    UUID.randomUUID().toString().substring(0, 8) +
                    (StringUtils.hasText(fileExtension) ? "." + fileExtension : "");
            Path formalFilePath = formalDirPath.resolve(formalFilename);
            try {
                // æ‰§è¡Œæ–‡ä»¶è¿ç§»ï¼ˆä½¿ç”¨åŽŸå­æ“ä½œç¡®ä¿å®‰å…¨æ€§ï¼‰
                Files.move(
                        Paths.get(tempFile.getTempPath()),
                        formalFilePath,
                        StandardCopyOption.REPLACE_EXISTING,
                        StandardCopyOption.ATOMIC_MOVE
                );
                log.info("文件迁移成功: {} -> {}", tempFile.getTempPath(), formalFilePath);
                // æ›´æ–°æ–‡ä»¶è®°å½•(关联到业务ID)
                CommonFile fileRecord = new CommonFile();
                fileRecord.setCommonId(businessId);
                fileRecord.setName(originalFilename);
                fileRecord.setUrl(formalFilePath.toString());
                fileRecord.setCreateTime(LocalDateTime.now());
                fileRecord.setType(fileType);
                commonFileMapper.insert(fileRecord);
                // åˆ é™¤ä¸´æ—¶æ–‡ä»¶è®°å½•
                tempFileMapper.deleteById(tempFile);
                log.info("文件迁移成功: {} -> {}", tempFile.getTempPath(), formalFilePath);
            } catch (IOException e) {
                log.error("文件迁移失败: {}", tempFile.getTempPath(), e);
                // å¯é€‰æ‹©å›žæ»šäº‹åŠ¡æˆ–è®°å½•å¤±è´¥æ–‡ä»¶
                throw new IOException("文件迁移异常", e);
            }
        }
    }
    @Scheduled(cron = "0 0 3 * * ?") // æ¯å¤©å‡Œæ™¨3点执行
    public void cleanupExpiredTempFiles() {
        LambdaQueryWrapper<TempFile> wrapper = new LambdaQueryWrapper<>();
        wrapper.lt(TempFile::getExpireTime, LocalDateTime.now()); // expireTime < å½“前时间
        List<TempFile> expiredFiles = tempFileMapper.selectList(wrapper);
        for (TempFile file : expiredFiles) {
            try {
                // åˆ é™¤ç‰©ç†æ–‡ä»¶
                Files.deleteIfExists(Paths.get(file.getTempPath()));
                // åˆ é™¤æ•°æ®åº“记录
                tempFileMapper.deleteById(file);
                log.info("已清理过期临时文件: {}", file.getTempPath());
            } catch (IOException e) {
                log.error("删除文件失败: {}", file.getTempPath(), e);
                // å¯é€‰æ‹©è®°å½•失败日志或重试
            }
        }
        log.info("过期临时文件清理完成,共清理 {} ä¸ªæ–‡ä»¶", expiredFiles.size());
    }
}
main-business/src/main/java/com/ruoyi/business/service/AccountFileService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,14 @@
package com.ruoyi.business.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.business.entity.AccountFile;
public interface AccountFileService extends IService<AccountFile> {
    IPage<AccountFile> accountFileListPage(Page page, AccountFile accountFile);
}
main-business/src/main/java/com/ruoyi/business/service/impl/AccountFileServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,25 @@
package com.ruoyi.business.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.business.entity.AccountFile;
import com.ruoyi.business.mapper.AccountFileMapper;
import com.ruoyi.business.service.AccountFileService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
@AllArgsConstructor
@Service
public class AccountFileServiceImpl extends ServiceImpl<AccountFileMapper, AccountFile> implements AccountFileService {
    private AccountFileMapper accountFileMapper;
    @Override
    public IPage<AccountFile> accountFileListPage(Page page, AccountFile accountFile) {
        return accountFileMapper.accountFileListPage(page,accountFile);
    }
}
main-business/src/main/resources/mapper/AccountFileMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.ruoyi.business.mapper.AccountFileMapper">
    <select id="accountFileListPage" resultType="com.ruoyi.business.entity.AccountFile">
        SELECT
        *
        FROM account_file
        where
        1=1
        <if test="accountFile.accountId != null and accountFile.accountId != ''">
            AND account_id = #{accountFile.accountId}
        </if>
        <if test="accountFile.name != null and accountFile.name != '' ">
            AND name = #{accountFile.name}
        </if>
        <if test="accountFile.accountType != null and accountFile.accountType != '' ">
            AND account_type = #{accountFile.accountType}
        </if>
    </select>
</mapper>