mitao
2 天以前 e8e30e5474c1fd0c14390710066e40c17155ad37
广告物料零星结算导入
13个文件已修改
1个文件已删除
5个文件已添加
565 ■■■■ 已修改文件
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/AssetAdController.java 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/AssetAdMaterialPriceController.java 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/AssetAdMaterialSporadicSettlementController.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/AssetHouseInspectionItemController.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/listener/AssetAdValidatorListener.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/annotation/ExcelValid.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/dto/asset/AssetAdDTO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/dto/asset/AssetAdMaterialPriceDTO.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/dto/asset/AssetAdMaterialSporadicSettlementDTO.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/export/AssetAdMaterialSporadicSettlementImport.java 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/model/AssetAdMaterialIntegralSettlement.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/model/AssetAdMaterialQuotation.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/model/AssetAdMaterialSporadicSettlement.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/AssetAdMaterialSporadicSettlementService.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/OssService.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/AssetAdMaterialSporadicSettlementServiceImpl.java 121 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/OssServiceImpl.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/utils/ExcelImportValid.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/utils/FastExcelUtil.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/AssetAdController.java
@@ -1,7 +1,7 @@
package com.ruoyi.web.controller.api;
import cn.idev.excel.FastExcel;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.domain.R;
@@ -12,9 +12,9 @@
import com.ruoyi.system.query.AssetAdQuery;
import com.ruoyi.system.service.AssetAdRentalRecordService;
import com.ruoyi.system.service.AssetAdService;
import com.ruoyi.system.utils.FastExcelUtil;
import com.ruoyi.system.vo.asset.AssetAdDetailVO;
import com.ruoyi.system.vo.asset.AssetAdVO;
import com.ruoyi.web.controller.listener.AssetAdValidatorListener;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
@@ -36,9 +36,7 @@
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.List;
/**
 * <p>
@@ -90,18 +88,7 @@
    @ApiOperation("下载导入模板")
    @GetMapping("/template")
    public void getTemplate(HttpServletResponse response){
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        String fileName = null;
        try {
            fileName = URLEncoder.encode("广告无形资产导入模板", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            FastExcel.write(response.getOutputStream(), AssetAdDTO.class)
                    .sheet("广告无形资产")
                    .doWrite(Collections.emptyList());
        } catch (IOException e) {
            log.error("下载导入模板异常", e);
        }
        FastExcelUtil.exportData(response, "广告无形资产导入模板", "广告无形资产", AssetAdDTO.class, Collections.emptyList());
    }
    @ApiOperation("导入")
@@ -112,14 +99,15 @@
            return R.fail("请选择一个文件上传!");
        }
        try {
            List<AssetAdDTO> list = FastExcel.read(file.getInputStream(), AssetAdDTO.class, new AssetAdValidatorListener())
                    .sheet()
                    .doReadSync();
            assetAdService.importAssetAd(list);
            //List<AssetAdDTO> list = FastExcelUtil.readMultipartFile(file.getInputStream(), AssetAdDTO.class);
            //assetAdService.importAssetAd(list);
            ExcelImportUtil.importExcel(file.getInputStream(), AssetAdDTO.class, null);
            return R.ok();
        } catch (IOException e) {
            log.error("文件处理失败", e);
            return R.fail("文件处理失败!");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/AssetAdMaterialPriceController.java
@@ -1,6 +1,5 @@
package com.ruoyi.web.controller.api;
import cn.idev.excel.FastExcel;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.domain.R;
@@ -8,6 +7,7 @@
import com.ruoyi.system.dto.asset.AssetAdMaterialPriceDTO;
import com.ruoyi.system.query.AssetAdMaterialPriceQuery;
import com.ruoyi.system.service.AssetAdMaterialPriceService;
import com.ruoyi.system.utils.FastExcelUtil;
import com.ruoyi.system.vo.asset.AssetAdMaterialPriceVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -30,7 +30,6 @@
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.List;
@@ -91,18 +90,7 @@
    @ApiOperation("下载导入模板")
    @GetMapping("/template")
    public void getTemplate(HttpServletResponse response){
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        String fileName = null;
        try {
            fileName = URLEncoder.encode("广告物料单价导入模板", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            FastExcel.write(response.getOutputStream(), AssetAdMaterialPriceDTO.class)
                    .sheet("广告物料单价")
                    .doWrite(Collections.emptyList());
        } catch (IOException e) {
            log.error("下载导入模板异常", e);
        }
        FastExcelUtil.exportData(response, "广告物料单价导入模板", "广告物料单价", AssetAdMaterialPriceDTO.class, Collections.emptyList());
    }
    @ApiOperation("导入")
@@ -113,10 +101,7 @@
            return R.fail("请选择一个文件上传!");
        }
        try {
            List<AssetAdMaterialPriceDTO> list = FastExcel.read(file.getInputStream())
                    .head(AssetAdMaterialPriceDTO.class)
                    .sheet()
                    .doReadSync();
            List<AssetAdMaterialPriceDTO> list = FastExcelUtil.readMultipartFile(file.getInputStream(), AssetAdMaterialPriceDTO.class);
            assetAdMaterialPriceService.importAssetAdMaterialPrice(list);
            return R.ok();
        } catch (IOException e) {
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/AssetAdMaterialSporadicSettlementController.java
@@ -1,9 +1,32 @@
package com.ruoyi.web.controller.api;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import com.google.common.collect.Lists;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.system.dto.asset.AssetAdMaterialSporadicSettlementDTO;
import com.ruoyi.system.export.AssetAdMaterialSporadicSettlementImport;
import com.ruoyi.system.service.AssetAdMaterialSporadicSettlementService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.context.annotation.Lazy;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.net.URLEncoder;
/**
 * <p>
@@ -13,8 +36,46 @@
 * @author mitao
 * @since 2025-10-17
 */
@Slf4j
@Validated
@Api(tags = {"广告物料零星结算相关接口"})
@RestController
@RequestMapping("/asset-ad-material-sporadic-settlement")
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
public class AssetAdMaterialSporadicSettlementController {
    private final AssetAdMaterialSporadicSettlementService assetAdMaterialSporadicSettlementService;
    @ApiOperation("下载导入模板")
    @GetMapping("/template")
    public void downloadTemplate(HttpServletResponse response) {
        Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), AssetAdMaterialSporadicSettlementImport.class,
                Lists.newArrayList(new AssetAdMaterialSporadicSettlementImport()));
        ServletOutputStream outputStream = null;
        try {
            String fileName = URLEncoder.encode("广告物料零星结算导入模板.xls", "utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            response.setHeader("content-Type", "application/vnd.ms-excel");
            response.setHeader("Pragma", "no-cache");
            response.setHeader("Cache-Control", "no-cache");
            outputStream = response.getOutputStream();
            workbook.write(outputStream);
        } catch (IOException e) {
            log.error("房屋巡检导入模板下载失败!", e);
        } finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    @ApiOperation("导入零星资产结算数据")
    @PostMapping("/import")
    public R<?> importData(@RequestPart("file") MultipartFile file, @Valid AssetAdMaterialSporadicSettlementDTO dto) {
        assetAdMaterialSporadicSettlementService.importData(file, dto);
        return R.ok();
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/AssetHouseInspectionItemController.java
@@ -6,7 +6,6 @@
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.basic.PageInfo;
@@ -18,27 +17,40 @@
import com.ruoyi.common.utils.WebUtils;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.dto.AddAssetHouseInspection;
import com.ruoyi.system.dto.AddAssetRepairRequestDTO;
import com.ruoyi.system.export.AssetHouseInspectionImport;
import com.ruoyi.system.model.*;
import com.ruoyi.system.model.AssetHouseInspectionDetail;
import com.ruoyi.system.model.AssetHouseInspectionItem;
import com.ruoyi.system.model.AssetHouseInspectionRecord;
import com.ruoyi.system.model.AssetMain;
import com.ruoyi.system.model.AssetPropertyExt;
import com.ruoyi.system.model.AssetType;
import com.ruoyi.system.query.AssetHouseInspectionRecordListQuery;
import com.ruoyi.system.query.AssetRepairRequestListQuery;
import com.ruoyi.system.service.*;
import com.ruoyi.system.service.AssetHouseInspectionDetailService;
import com.ruoyi.system.service.AssetHouseInspectionItemService;
import com.ruoyi.system.service.AssetHouseInspectionRecordService;
import com.ruoyi.system.service.AssetMainService;
import com.ruoyi.system.service.AssetPropertyExtService;
import com.ruoyi.system.service.AssetTypeService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.service.TDeptService;
import com.ruoyi.system.vo.AssetHouseInspectionVO;
import com.ruoyi.system.vo.AssetRepairRequestVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
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.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletOutputStream;
ruoyi-admin/src/main/java/com/ruoyi/web/controller/listener/AssetAdValidatorListener.java
File was deleted
ruoyi-system/src/main/java/com/ruoyi/system/annotation/ExcelValid.java
New file
@@ -0,0 +1,14 @@
package com.ruoyi.system.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* <p>Excel导入必填校验注解</p>
*/
@Target({ ElementType.FIELD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelValid {
   String message() default "导入有未填入的字段";
}
ruoyi-system/src/main/java/com/ruoyi/system/dto/asset/AssetAdDTO.java
@@ -3,6 +3,7 @@
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import cn.idev.excel.annotation.write.style.ColumnWidth;
import com.ruoyi.system.annotation.ExcelValid;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -24,6 +25,7 @@
    @ApiModelProperty(value = "资产名称")
    @ExcelProperty("资产名称")
    @ColumnWidth(11)
    @ExcelValid(message = "名称不能为空")
    @NotBlank(message = "资产名称")
    private String assetName;
ruoyi-system/src/main/java/com/ruoyi/system/dto/asset/AssetAdMaterialPriceDTO.java
@@ -3,6 +3,7 @@
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import cn.idev.excel.annotation.write.style.ColumnWidth;
import com.ruoyi.system.annotation.ExcelValid;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -29,6 +30,7 @@
    @ApiModelProperty(value = "物料名称")
    @ExcelProperty("物料名称")
    @ColumnWidth(15)
    @ExcelValid(message = "名称不能为空")
    @NotBlank(message = "物料名称不能为空")
    private String materialName;
@@ -36,12 +38,14 @@
    @ExcelProperty("单价")
    @ColumnWidth(10)
    @NotNull(message = "单价不能为空")
    @ExcelValid(message = "单价不能为空")
    @DecimalMin(value = "0.01", message = "单价必须大于0")
    private BigDecimal unitPrice;
    @ApiModelProperty(value = "单位(元、平方米等)")
    @ExcelProperty("单位")
    @ColumnWidth(8)
    @ExcelValid(message = "单位不能为空")
    @NotBlank(message = "单位不能为空")
    private String priceUnit;
ruoyi-system/src/main/java/com/ruoyi/system/dto/asset/AssetAdMaterialSporadicSettlementDTO.java
New file
@@ -0,0 +1,30 @@
package com.ruoyi.system.dto.asset;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
 * @author mitao
 * @date 2025/10/22
 */
@Data
@ApiModel("广告物料零星结算表数据传输对象")
public class AssetAdMaterialSporadicSettlementDTO {
    @ApiModelProperty(value = "主键")
    private Integer id;
    @ApiModelProperty(value = "标题")
    @NotBlank(message = "标题不能为空")
    private String title;
    @ApiModelProperty(value = "结算项目")
    @NotBlank(message = "结算项目不能为空")
    private String settlementProject;
    @ApiModelProperty(value = "结算单位")
    @NotBlank(message = "结算单位不能为空")
    private String settlementInstitution;
}
ruoyi-system/src/main/java/com/ruoyi/system/export/AssetAdMaterialSporadicSettlementImport.java
New file
@@ -0,0 +1,72 @@
package com.ruoyi.system.export;
import cn.afterturn.easypoi.excel.annotation.Excel;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
/**
 * <p>
 * 广告物料零星结算表关联表
 * </p>
 *
 * @author mitao
 * @since 2025-10-17
 */
@Data
@ApiModel(value="AssetAdMaterialSporadicSettlementInfo对象", description="广告物料零星结算表关联表")
public class AssetAdMaterialSporadicSettlementImport {
    @Excel(name = "日期", width = 20)
    private LocalDate settlementDate;
    @Excel(name = "安装地点", width = 20)
    private String address;
    @Excel(name = "名称", width = 20)
    private String adName;
    @Excel(name = "材质工艺", width = 20)
    private String material;
    /**
     * 设计图例oss地址
     */
    private String designLegend;
    @Excel(name = "设计图例",type = 2, width = 20)
    private String designLegendTemp;
    /**
     * 安装图例oss地址
     */
    private String installationLegend;
    @Excel(name = "安装图例",type = 2, width = 20)
    private String installationLegendTemp;
    @Excel(name = "长(米)", width = 20)
    private Double length;
    @Excel(name = "高(米)", width = 20)
    private Double height;
    @Excel(name = "数量", width = 20)
    private Integer quantity;
    @Excel(name = "小计", width = 20)
    private String subtotal;
    @Excel(name = "单价(元)", width = 20)
    private BigDecimal unitPrice;
    @Excel(name = "金额(元)", width = 20)
    private BigDecimal totalAmount;
    @Excel(name = "备注", width = 20)
    private String remark;
}
ruoyi-system/src/main/java/com/ruoyi/system/model/AssetAdMaterialIntegralSettlement.java
@@ -35,6 +35,9 @@
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    @ApiModelProperty(value = "所属部门ID")
    private Integer deptId;
    @ApiModelProperty(value = "标题")
    private String title;
ruoyi-system/src/main/java/com/ruoyi/system/model/AssetAdMaterialQuotation.java
@@ -34,6 +34,9 @@
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    @ApiModelProperty(value = "所属部门ID")
    private Integer deptId;
    @ApiModelProperty(value = "标题")
    private String title;
ruoyi-system/src/main/java/com/ruoyi/system/model/AssetAdMaterialSporadicSettlement.java
@@ -34,6 +34,9 @@
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    @ApiModelProperty(value = "所属部门ID")
    private Integer deptId;
    @ApiModelProperty(value = "标题")
    private String title;
ruoyi-system/src/main/java/com/ruoyi/system/service/AssetAdMaterialSporadicSettlementService.java
@@ -1,7 +1,9 @@
package com.ruoyi.system.service;
import com.ruoyi.system.dto.asset.AssetAdMaterialSporadicSettlementDTO;
import com.ruoyi.system.model.AssetAdMaterialSporadicSettlement;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springframework.web.multipart.MultipartFile;
/**
 * <p>
@@ -13,4 +15,5 @@
 */
public interface AssetAdMaterialSporadicSettlementService extends IService<AssetAdMaterialSporadicSettlement> {
    void importData(MultipartFile file, AssetAdMaterialSporadicSettlementDTO dto);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/OssService.java
@@ -3,6 +3,7 @@
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
/**
 * @author mitao
@@ -25,4 +26,6 @@
     * @return
     */
    String upload(String storagePath, MultipartFile file) throws IOException;
    String uploadByInputStream(InputStream inputStream);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/AssetAdMaterialSporadicSettlementServiceImpl.java
@@ -1,10 +1,33 @@
package com.ruoyi.system.service.impl;
import com.ruoyi.system.model.AssetAdMaterialSporadicSettlement;
import com.ruoyi.system.mapper.AssetAdMaterialSporadicSettlementMapper;
import com.ruoyi.system.service.AssetAdMaterialSporadicSettlementService;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.dto.asset.AssetAdMaterialSporadicSettlementDTO;
import com.ruoyi.system.export.AssetAdMaterialSporadicSettlementImport;
import com.ruoyi.system.mapper.AssetAdMaterialSporadicSettlementMapper;
import com.ruoyi.system.model.AssetAdMaterialSporadicSettlement;
import com.ruoyi.system.model.AssetAdMaterialSporadicSettlementInfo;
import com.ruoyi.system.service.AssetAdMaterialSporadicSettlementInfoService;
import com.ruoyi.system.service.AssetAdMaterialSporadicSettlementService;
import com.ruoyi.system.service.OssService;
import lombok.Cleanup;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
/**
 * <p>
@@ -15,6 +38,98 @@
 * @since 2025-10-17
 */
@Service
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
public class AssetAdMaterialSporadicSettlementServiceImpl extends ServiceImpl<AssetAdMaterialSporadicSettlementMapper, AssetAdMaterialSporadicSettlement> implements AssetAdMaterialSporadicSettlementService {
    private final OssService ossService;
    private final AssetAdMaterialSporadicSettlementInfoService assetAdMaterialSporadicSettlementInfoService;
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void importData(MultipartFile file, AssetAdMaterialSporadicSettlementDTO dto) {
        try {
            ImportParams importParams = new ImportParams();
            importParams.setTitleRows(0);
            importParams.setHeadRows(1);
            @Cleanup
            InputStream inputStream = file.getInputStream();
            List<AssetAdMaterialSporadicSettlementImport> list = ExcelImportUtil.importExcel(inputStream, AssetAdMaterialSporadicSettlementImport.class, importParams);
            validateFields(list);
            uploadToOss(list);
            //保存
            AssetAdMaterialSporadicSettlement assetAdMaterialSporadicSettlement = BeanUtil.copyProperties(dto, AssetAdMaterialSporadicSettlement.class);
            assetAdMaterialSporadicSettlement.setCreateBy(SecurityUtils.getLoginUser().getUser().getNickName());
            assetAdMaterialSporadicSettlement.setDeptId(Integer.parseInt(SecurityUtils.getLoginUser().getUser().getDeptId()));
            save(assetAdMaterialSporadicSettlement);
            //保存明细
            List<AssetAdMaterialSporadicSettlementInfo> assetAdMaterialSporadicSettlementInfos = BeanUtil.copyToList(list, AssetAdMaterialSporadicSettlementInfo.class);
            assetAdMaterialSporadicSettlementInfos.forEach(item -> item.setAdMaterialSporadicSettlementId(assetAdMaterialSporadicSettlement.getId()));
            assetAdMaterialSporadicSettlementInfoService.saveBatch(assetAdMaterialSporadicSettlementInfos);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    private void validateFields(List<AssetAdMaterialSporadicSettlementImport> list) {
        Optional<AssetAdMaterialSporadicSettlementImport> any = list.stream()
                .filter(item -> StringUtils.isBlank(item.getAdName())).findAny();
        if (any.isPresent()) {
            throw new ServiceException("【名称】不能为空,请检查该列是否填写完整");
        }
        Optional<AssetAdMaterialSporadicSettlementImport> quantityOpt = list.stream()
                .filter(item -> Objects.isNull(item.getQuantity())).findAny();
        if (quantityOpt.isPresent()) {
            throw new ServiceException("【数量】不能为空,请检查该列是否填写完整");
        }
        Optional<AssetAdMaterialSporadicSettlementImport> priceOpt = list.stream()
                .filter(item -> Objects.isNull(item.getUnitPrice())).findAny();
        if (priceOpt.isPresent()) {
            throw new ServiceException("【单价】不能为空,请检查该列是否填写完整");
        }
    }
    /**
     * 文件转存
     * @param list
     */
    private void uploadToOss(List<AssetAdMaterialSporadicSettlementImport> list) {
        //遍历每一条数据
        for (AssetAdMaterialSporadicSettlementImport settlementImport : list) {
            if (StringUtils.isNotEmpty(settlementImport.getDesignLegendTemp())) {
                String ossUrl = getOssUrl(settlementImport.getDesignLegendTemp());
                settlementImport.setDesignLegend(ossUrl);
            }
            if (StringUtils.isNotEmpty(settlementImport.getInstallationLegendTemp())) {
                String ossUrl = getOssUrl(settlementImport.getInstallationLegendTemp());
                settlementImport.setInstallationLegend(ossUrl);
            }
        }
        //删除图片缓存
        for (AssetAdMaterialSporadicSettlementImport settlementImport : list) {
            if (StringUtils.isNotEmpty(settlementImport.getDesignLegendTemp())) {
                deleteImageCache(settlementImport.getDesignLegendTemp());
            }
            if (StringUtils.isNotEmpty(settlementImport.getInstallationLegendTemp())) {
                deleteImageCache(settlementImport.getInstallationLegendTemp());
            }
        }
    }
    private String getOssUrl(String filePath) {
        try {
            //获取到暂存的文件
            File tmpFile = new File(filePath);
            FileInputStream fileInputStream = new FileInputStream(tmpFile);
            //转换为 multipartFile 类
            return ossService.uploadByInputStream(fileInputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    private void deleteImageCache(String filePath) {
        //获取到暂存的文件
        File tmpFile = new File(filePath);
        if (tmpFile.exists() && tmpFile.isFile()) {
            tmpFile.delete();
        }
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/OssServiceImpl.java
@@ -93,7 +93,38 @@
            ossClient.shutdown();
        }
    }
    @Override
    public String uploadByInputStream(InputStream inputStream) {
        OSS ossClient = null;
        try {
            CredentialsProvider credentialsProvider = new DefaultCredentialProvider(OssConfig.ACCESS_KEY_ID, OssConfig.ACCESS_KEY_SECRET);
            String region = "cn-chengdu";
            // 创建OSSClient实例。
            ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
            clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
            ossClient = OSSClientBuilder.create()
                    .endpoint(OssConfig.UPLOAD_ENDPOINT)
                    .credentialsProvider(credentialsProvider)
                    .clientConfiguration(clientBuilderConfiguration)
                    .region(region)
                    .build();
            String fileExt = "png";
            String fileName = UUID.randomUUID().toString();
            // 设置文件名
            String filePathName = generateRelativeStoragePath(OssConfig.FOLDER, fileExt, fileName);
            // 创建PutObjectRequest对象。
            PutObjectRequest putObjectRequest = new PutObjectRequest(OssConfig.BUCKET_NAME, filePathName, inputStream);
            // 创建PutObject请求。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
            return OssConfig.DOWNLOAD_ENDPOINT + filePathName;
        } finally {
            ossClient.shutdown();
        }
    }
    /**
     * <pre>
     * 获取存储的相对路径
ruoyi-system/src/main/java/com/ruoyi/system/utils/ExcelImportValid.java
New file
@@ -0,0 +1,33 @@
package com.ruoyi.system.utils;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.system.annotation.ExcelValid;
import java.lang.reflect.Field;
import java.util.Objects;
public class ExcelImportValid {
    /**
     * Excel导入字段非空校验
     *
     * @param object 校验的JavaBean 其属性须有自定义注解
     */
    public static void valid(Object object) throws Exception {
        Field[] fields = object.getClass().getDeclaredFields();
        for (Field field : fields) {
            // 设置可访问
            field.setAccessible(true);
            // 属性的值
            Object fieldValue = null;
            try {
                fieldValue = field.get(object);
            } catch (IllegalAccessException e) {
                throw new ServiceException("导入参数检查失败!");
            }
            // 是否包含必填校验注解
            boolean isRequiredValid = field.isAnnotationPresent(ExcelValid.class);
            if (isRequiredValid && Objects.isNull(fieldValue)) {
                throw new ServiceException(field.getAnnotation(ExcelValid.class).message());
            }
        }
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/utils/FastExcelUtil.java
New file
@@ -0,0 +1,63 @@
package com.ruoyi.system.utils;
import cn.idev.excel.FastExcel;
import cn.idev.excel.context.AnalysisContext;
import cn.idev.excel.event.AnalysisEventListener;
import com.ruoyi.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.List;
/**
 * @author mitao
 * @date 2025/10/22
 */
@Slf4j
public class FastExcelUtil {
    public static <T> void exportData(HttpServletResponse response, String fileName, String sheetName, Class<T> clazz, List<T> data) {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        try {
            fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            FastExcel.write(response.getOutputStream(), clazz)
                    .sheet(sheetName)
                    .doWrite(data);
        } catch (IOException e) {
            log.error("导出数据异常", e);
            throw new ServiceException("导出数据异常");
        }
    }
    /**
     * 读取文件数据,并返回一个包含指定类型数据的列表。
     *
     * @param inputStream 文件对象输入流
     * @param clazz       数据对象的类型
     * @param <T>         泛型类型,表示数据对象的类型
     * @return 包含解析后数据对象的列表
     */
    public static <T> List<T> readMultipartFile(InputStream inputStream, Class<T> clazz) {
        return FastExcel.read(inputStream, clazz, new AnalysisEventListener<T>() {
            @Override
            public void invoke(Object o, AnalysisContext analysisContext) {
                Integer rowIndex = analysisContext.readRowHolder().getRowIndex();
                rowIndex += 1; // 行号从0开始,需要加1
                try {
                    // 调用字段校验方法
                    ExcelImportValid.valid(o);
                } catch (Exception e) {
                    throw new ServiceException(String.format("第%d行:%s", rowIndex, e.getMessage()));
                }
            }
            @Override
            public void doAfterAllAnalysed(AnalysisContext analysisContext) {
            }
        }).sheet().doReadSync(); // 读取 Excel 文件中的第一个工作表
    }
}