Jelajahi Sumber

拍品信息导出

jintao.geng 3 minggu lalu
induk
melakukan
f49762db83

+ 16 - 0
auc/src/main/java/cn/hobbystocks/auc/web/LotController.java

@@ -8,12 +8,15 @@ import cn.hobbystocks.auc.app.AppClient;
 import cn.hobbystocks.auc.common.core.domain.AjaxResult;
 import cn.hobbystocks.auc.common.user.UserInfo;
 import cn.hobbystocks.auc.common.user.UserUtils;
+import cn.hobbystocks.auc.common.utils.ExcelUtils;
 import cn.hobbystocks.auc.common.utils.StringUtils;
 import cn.hobbystocks.auc.common.utils.UserType;
 import cn.hobbystocks.auc.domain.Bid;
 import cn.hobbystocks.auc.domain.Lot;
 import cn.hobbystocks.auc.common.constant.Constants;
+import cn.hobbystocks.auc.dto.LotExportDTO;
 import cn.hobbystocks.auc.mapper.BidMapper;
+import cn.hobbystocks.auc.request.LotRequest;
 import cn.hobbystocks.auc.service.IAuctionService;
 import cn.hobbystocks.auc.service.SyncService;
 import cn.hobbystocks.auc.task.DynamicTaskService;
@@ -23,6 +26,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.apache.logging.log4j.util.Strings;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.util.CollectionUtils;
@@ -30,6 +34,7 @@ import org.springframework.web.bind.annotation.*;
 
 import cn.hobbystocks.auc.domain.Auction;
 
+import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
 
 /**
@@ -181,4 +186,15 @@ public class LotController extends AdminBaseController {
 	}
 
 
+    @ApiOperation(value = "导出拍品列表信息", notes = "拍品列表信息\n", response = AjaxResult.class, responseContainer = "AjaxResult.success")
+    @PostMapping("/export")
+    public AjaxResult export(@RequestBody LotRequest request, HttpServletResponse response) {
+
+        List<LotExportDTO> lotList = lotService.exportLotList(request);
+        ExcelUtils<LotExportDTO> util = new ExcelUtils<>(LotExportDTO.class);
+        util.exportExcelHttp(lotList, response, "拍品管理导出");
+        return AjaxResult.success();
+    }
+
+
 }

+ 7 - 0
lot/pom.xml

@@ -196,6 +196,13 @@
 			</exclusions>
 		</dependency>
 
+		<!-- excel工具 -->
+		<dependency>
+			<groupId>org.apache.poi</groupId>
+			<artifactId>poi-ooxml</artifactId>
+			<version>3.17</version>
+		</dependency>
+
 
 	</dependencies>
 </project>

+ 96 - 0
lot/src/main/java/cn/hobbystocks/auc/common/enums/LotStatusEnum.java

@@ -0,0 +1,96 @@
+package cn.hobbystocks.auc.common.enums;
+
+import com.fasterxml.jackson.annotation.JsonValue;
+import lombok.Getter;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 拍卖状态
+ *
+ * @author zheng
+ */
+@Getter
+public enum LotStatusEnum {
+    /**
+     * 未开始
+     */
+    WAITING("Waiting", "未开始"),
+
+    /**
+     * 开启中
+     */
+    STARTING("Starting", "开启中"),
+
+    /**
+     * 进行中
+     */
+    BIDDING("Bidding", "进行中"),
+
+    /**
+     * 拍卖结束
+     */
+    FINISHED("Finished", "拍卖结束"),
+
+    /**
+     * 撤拍
+     */
+    CANCELLED("Cancelled", "撤拍"),
+
+    /**
+     * 流拍
+     */
+    PASS("Pass", "流拍"),
+
+    /**
+     * 成交
+     */
+    SOLD("Sold", "成交");
+
+    /**
+     * 状态编码(如 Waiting/Starting)
+     */
+    private final String status;
+
+    /**
+     * 状态中文描述
+     */
+    private final String desc;
+
+    /**
+     * 构造方法
+     * @param status 状态编码
+     * @param desc 中文描述
+     */
+    LotStatusEnum(String status, String desc) {
+        this.status = status;
+        this.desc = desc;
+    }
+
+    /**
+     * 根据状态编码获取枚举对象(常用核心方法)
+     * @param status 状态编码(如 "Waiting")
+     * @return 对应的枚举对象,若未匹配到返回 null(也可抛异常,根据业务需求调整)
+     */
+    public static LotStatusEnum of(String status) {
+        if (status == null || StringUtils.isEmpty(status)) {
+            return null;
+        }
+        for (LotStatusEnum auctionStatus : values()) {
+            if (auctionStatus.getStatus().equals(status)) {
+                return auctionStatus;
+            }
+        }
+        // 若需要严格校验,可抛出异常:
+        // throw new IllegalArgumentException("无效的拍卖状态编码:" + status);
+        return null;
+    }
+
+    /**
+     * 重写toString,便于日志打印和调试
+     * @return 状态编码 + 中文描述(如 "Waiting(未开始)")
+     */
+    @Override
+    public String toString() {
+        return this.status + "(" + this.desc + ")";
+    }
+}

+ 72 - 0
lot/src/main/java/cn/hobbystocks/auc/common/enums/PubStatusEnum.java

@@ -0,0 +1,72 @@
+package cn.hobbystocks.auc.common.enums;
+
+import lombok.Getter;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 拍卖状态
+ *
+ * @author zheng
+ */
+@Getter
+public enum PubStatusEnum {
+    /**
+     * 未审核
+     */
+    UNREVIEWED(0, "未审核"),
+
+    /**
+     * 已上架
+     */
+    SHELVE_UP(1, "已上架"),
+
+    /**
+     * 已下架
+     */
+    SHELVE_DOWN(2, "已下架");
+
+    /**
+     * 状态编码(数字值:0/1/2)
+     */
+    private final int code;
+
+    /**
+     * 状态中文描述
+     */
+    private final String desc;
+
+    /**
+     * 构造方法
+     * @param code 状态编码(数字)
+     * @param desc 中文描述
+     */
+    PubStatusEnum(int code, String desc) {
+        this.code = code;
+        this.desc = desc;
+    }
+
+    /**
+     * 根据状态编码(数字)获取枚举对象(核心业务方法)
+     * @param code 状态编码(0/1/2)
+     * @return 对应的枚举对象,无效编码返回null(也可抛异常,按需调整)
+     */
+    public static PubStatusEnum of(int code) {
+        for (PubStatusEnum status : values()) {
+            if (status.getCode() == code) {
+                return status;
+            }
+        }
+        // 若需严格校验,可抛出异常:
+        // throw new IllegalArgumentException("无效的发布状态编码:" + code);
+        return null;
+    }
+
+    /**
+     * 重写toString,便于日志打印和调试
+     * @return 状态编码 + 中文描述(如 "0(未审核)")
+     */
+    @Override
+    public String toString() {
+        return this.code + "(" + this.desc + ")";
+    }
+}

+ 85 - 0
lot/src/main/java/cn/hobbystocks/auc/common/enums/RuleTypeEnum.java

@@ -0,0 +1,85 @@
+package cn.hobbystocks.auc.common.enums;
+
+import com.fasterxml.jackson.annotation.JsonValue;
+import lombok.Getter;
+
+/**
+ * 拍卖方式
+ *
+ * @author zheng
+ */
+@Getter
+public enum RuleTypeEnum {
+
+    /**
+     * 标准延时
+     */
+    traditional_delay("traditional_delay", "标准延时"),
+
+    /**
+     * 重置延时
+     */
+    traditional_delay_v2("traditional_delay_v2", "重置延时"),
+    /**
+     * 增价拍卖
+     */
+    traditional_delay_v3("traditional_delay_v3", "增价拍卖"),
+
+
+    ;
+
+    /**
+     * 状态码
+     */
+    private final String code;
+
+    /**
+     * 状态描述
+     */
+    private final String desc;
+
+    // 构造方法
+    RuleTypeEnum(String code, String desc) {
+        this.code = code;
+        this.desc = desc;
+    }
+
+    /**
+     * 根据状态码获取枚举(核心方法,用于接口参数转换/数据库查询)
+     * @param code 状态码
+     * @return 对应枚举,无匹配返回null
+     */
+    public static RuleTypeEnum getByCode(String code) {
+        if (code == null) {
+            return null;
+        }
+        for (RuleTypeEnum status : values()) {
+            if (status.getCode().equals(code)) {
+                return status;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 序列化时返回状态码(适配JSON返回,前端直接获取code)
+     * 如需返回描述,可将注解移到desc字段
+     */
+    @JsonValue
+    public String getCode() {
+        return code;
+    }
+
+    // 可选:根据描述获取枚举(按需添加)
+    public static RuleTypeEnum getByDesc(String desc) {
+        if (desc == null || desc.isEmpty()) {
+            return null;
+        }
+        for (RuleTypeEnum status : values()) {
+            if (status.getDesc().equals(desc)) {
+                return status;
+            }
+        }
+        return null;
+    }
+}

+ 160 - 0
lot/src/main/java/cn/hobbystocks/auc/common/utils/Excel.java

@@ -0,0 +1,160 @@
+package cn.hobbystocks.auc.common.utils;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.math.BigDecimal;
+
+/**
+ * 自定义导出Excel数据注解
+ *
+ * @author zheng
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Excel {
+    /**
+     * 导出时在excel中排序
+     */
+    public int sort() default Integer.MAX_VALUE;
+
+    /**
+     * 导出到Excel中的名字.
+     */
+    public String name() default "";
+
+    /**
+     * 是否必填
+     * @return
+     */
+    public boolean isMust() default false ;
+
+    /**
+     * 日期格式, 如: yyyy-MM-dd
+     */
+    public String dateFormat() default "";
+
+    /**
+     * 如果是字典类型,请设置字典的type值 (如: sys_user_sex)
+     */
+    public String dictType() default "";
+
+    /**
+     * 读取内容转表达式 (如: 0=男,1=女,2=未知)
+     */
+    public String readConverterExp() default "";
+
+    /**
+     * 读取内容方法
+     */
+    public String readFormatDataMethod() default "";
+
+    /**
+     * 分隔符,读取字符串组内容
+     */
+    public String separator() default ",";
+
+    /**
+     * BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化)
+     */
+    public int scale() default -1;
+
+    /**
+     * BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN
+     */
+    public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
+
+    /**
+     * 导出类型(0数字 1字符串)
+     */
+    public ColumnType cellType() default ColumnType.STRING;
+
+    /**
+     * 导出时在excel中每个列的高度 单位为字符
+     */
+    public double height() default 14;
+
+    /**
+     * 导出时在excel中每个列的宽 单位为字符
+     */
+    public double width() default 16;
+
+    /**
+     * 文字后缀,如% 90 变成90%
+     */
+    public String suffix() default "";
+
+    /**
+     * 当值为空时,字段的默认值
+     */
+    public String defaultValue() default "";
+
+    /**
+     * 提示信息
+     */
+    public String prompt() default "";
+
+    /**
+     * 设置只能选择不能输入的列内容.
+     */
+    public String[] combo() default {};
+
+    /**
+     * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
+     */
+    public boolean isExport() default true;
+
+    /**
+     * 另一个类中的属性名称,支持多级获取,以小数点隔开
+     */
+    public String targetAttr() default "";
+
+    /**
+     * 是否自动统计数据,在最后追加一行统计数据总和
+     */
+    public boolean isStatistics() default false;
+
+    /**
+     * 内容脱敏
+     * 正则
+     * @return
+     */
+    public String desensitize() default "";
+
+    public String desensitizeType() default "";
+    /**
+     * 字段类型(0:导出导入;1:仅导出;2:仅导入)
+     */
+    Type type() default Type.ALL;
+
+    public enum Type {
+        ALL(0), EXPORT(1), IMPORT(2);
+        private final int value;
+
+        Type(int value)
+        {
+            this.value = value;
+        }
+
+        public int value()
+        {
+            return this.value;
+        }
+    }
+
+    public enum ColumnType {
+        NUMERIC(0), STRING(1);
+        private final int value;
+
+        ColumnType(int value)
+        {
+            this.value = value;
+        }
+
+        public int value()
+        {
+            return this.value;
+        }
+    }
+}

+ 502 - 0
lot/src/main/java/cn/hobbystocks/auc/common/utils/ExcelUtils.java

@@ -0,0 +1,502 @@
+package cn.hobbystocks.auc.common.utils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.ss.util.CellRangeAddressList;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+import org.apache.poi.xssf.usermodel.XSSFDataValidation;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Slf4j
+public class ExcelUtils<T> {
+
+    /**
+     * Excel sheet最大行数,默认65536
+     */
+    public static final int sheetSize = 65536;
+    /**
+     * 文件保存路径
+     */
+    private String filepath;
+
+    /**
+     * 工作表名称
+     */
+    private String sheetName;
+
+    /**
+     * 导出类型(EXPORT:导出数据;IMPORT:导入模板)
+     */
+    private Excel.Type type;
+
+    /**
+     * 工作薄对象
+     */
+    private Workbook wb;
+
+    /**
+     * 工作表对象
+     */
+    private Sheet sheet;
+
+    /**
+     * 样式列表
+     */
+    private Map<String, CellStyle> styles;
+
+    /**
+     * 导入导出数据列表
+     */
+    private List<T> list;
+
+    /**
+     * 注解列表
+     */
+    private List<Object[]> fields;
+
+    /**
+     * 实体对象
+     */
+    public Class<T> clazz;
+
+    public ExcelUtils(Class<T> clazz) {
+        this.clazz = clazz;
+    }
+
+    public void init(List<T> list, String sheetName, Excel.Type type) {
+        if (list == null) {
+            list = new ArrayList<T>();
+        }
+        this.list = list;
+        this.sheetName = sheetName;
+        this.type = type;
+        createExcelField();
+        createWorkbook();
+    }
+
+    /**
+     * 导出
+     */
+    public void exportExcelHttp(List<T> list, HttpServletResponse response, String sheetName) {
+        this.init(list, sheetName, Excel.Type.EXPORT);
+        OutputStream out = null;
+        try {
+            // 取出一共有多少个sheet.
+            double sheetNo = Math.ceil(list.size() / sheetSize);
+            for (int index = 0; index <= sheetNo; index++) {
+                createSheet(sheetNo, index);
+                // 产生一行
+                Row row = sheet.createRow(0);
+                int column = 0;
+                // 写入各个字段的列头名称
+                for (Object[] os : fields) {
+                    Excel excel = (Excel) os[1];
+                    this.createCell(excel, row, column++);
+                }
+                if (Excel.Type.EXPORT.equals(type)) {
+                    fillExcelData(index, row);
+                }
+            }
+            String filename = encodingFilename(sheetName);
+            out = new FileOutputStream(getAbsoluteFile(filename));
+//            wb.write(out);
+            //导出数据
+            //设置Http响应头告诉浏览器下载这个附件
+            response.setHeader("Content-Disposition", "attachment;Filename=" + new String(sheetName.getBytes("gb2312"), "ISO8859-1") + ".xlsx");
+            out = response.getOutputStream();
+            wb.write(out);
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.error("导出Excel异常{}", e.getMessage());
+            throw new RuntimeException("导出Excel失败,请联系系统管理员!");
+        } finally {
+            if (wb != null) {
+                try {
+                    wb.close();
+                } catch (IOException e1) {
+                    e1.printStackTrace();
+                }
+            }
+            if (out != null) {
+                try {
+                    out.close();
+                } catch (IOException e1) {
+                    e1.printStackTrace();
+                }
+            }
+        }
+    }
+
+    /**
+     * 获取下载路径
+     *
+     * @param filename 文件名称
+     */
+    public String getAbsoluteFile(String filename)
+    {
+        String downloadPath = Global.getDownloadPath() + filename;
+        File desc = new File(downloadPath);
+        if (!desc.getParentFile().exists())
+        {
+            desc.getParentFile().mkdirs();
+        }
+        return downloadPath;
+    }
+
+    /**
+     * 得到所有定义字段
+     */
+    private void createExcelField() {
+        this.fields = new ArrayList<Object[]>();
+        List<Field> tempFields = new ArrayList<>();
+        tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
+        tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
+        for (Field field : tempFields) {
+            // 单注解
+            if (field.isAnnotationPresent(Excel.class)) {
+                putToField(field, field.getAnnotation(Excel.class));
+            }
+
+            // 多注解
+            if (field.isAnnotationPresent(Excels.class)) {
+                Excels attrs = field.getAnnotation(Excels.class);
+                Excel[] excels = attrs.value();
+                for (Excel excel : excels) {
+                    putToField(field, excel);
+                }
+            }
+        }
+        this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList());
+    }
+
+    /**
+     * 创建一个工作簿
+     */
+    public void createWorkbook() {
+        this.wb = new SXSSFWorkbook(500);
+    }
+
+    /**
+     * 创建工作表
+     *
+     * @param sheetNo sheet数量
+     * @param index   序号
+     */
+    public void createSheet(double sheetNo, int index) {
+        try {
+            this.sheet = wb.createSheet();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        this.styles = createStyles(wb);
+        // 设置工作表的名称.
+        if (sheetNo == 0) {
+            wb.setSheetName(index, sheetName);
+        } else {
+            wb.setSheetName(index, sheetName + index);
+        }
+    }
+
+    /**
+     * 创建表格样式
+     *
+     * @param wb 工作薄对象
+     * @return 样式列表
+     */
+    private Map<String, CellStyle> createStyles(Workbook wb) {
+        // 写入各条记录,每条记录对应excel表中的一行
+        Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
+        CellStyle style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.CENTER);
+        style.setBorderRight(BorderStyle.THIN);
+        style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setBorderLeft(BorderStyle.THIN);
+        style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setBorderTop(BorderStyle.THIN);
+        style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setBorderBottom(BorderStyle.THIN);
+        style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        Font dataFont = wb.createFont();
+        dataFont.setFontName("Arial");
+        dataFont.setFontHeightInPoints((short) 10);
+        style.setFont(dataFont);
+        styles.put("data", style);
+
+        style = wb.createCellStyle();
+        style.cloneStyleFrom(styles.get("data"));
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.CENTER);
+        style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        Font headerFont = wb.createFont();
+        headerFont.setFontName("Arial");
+        headerFont.setFontHeightInPoints((short) 10);
+        headerFont.setBold(true);
+        headerFont.setColor(IndexedColors.WHITE.getIndex());
+        style.setFont(headerFont);
+        styles.put("header", style);
+
+        return styles;
+    }
+
+    /**
+     * 创建单元格
+     */
+    public Cell createCell(Excel attr, Row row, int column) {
+        // 创建列
+        Cell cell = row.createCell(column);
+        // 写入列信息
+        cell.setCellValue(attr.name());
+        setDataValidation(attr, row, column);
+        cell.setCellStyle(styles.get("header"));
+        return cell;
+    }
+
+    /**
+     * 创建表格样式
+     */
+    public void setDataValidation(Excel attr, Row row, int column) {
+        if (attr.name().indexOf("注:") >= 0) {
+            sheet.setColumnWidth(column, 6000);
+        } else {
+            // 设置列宽
+            sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256));
+            row.setHeight((short) (attr.height() * 20));
+        }
+        // 如果设置了提示信息则鼠标放上去提示.
+        if (StringUtils.isNotEmpty(attr.prompt())) {
+            // 这里默认设了2-101列提示.
+            setXSSFPrompt(sheet, "", attr.prompt(), 1, 100, column, column);
+        }
+        // 如果设置了combo属性则本列只能选择不能输入
+        if (attr.combo().length > 0) {
+            // 这里默认设了2-101列只能选择不能输入.
+            setXSSFValidation(sheet, attr.combo(), 1, 100, column, column);
+        }
+    }
+
+    /**
+     * 设置 POI XSSFSheet 单元格提示
+     *
+     * @param sheet         表单
+     * @param promptTitle   提示标题
+     * @param promptContent 提示内容
+     * @param firstRow      开始行
+     * @param endRow        结束行
+     * @param firstCol      开始列
+     * @param endCol        结束列
+     */
+    public void setXSSFPrompt(Sheet sheet, String promptTitle, String promptContent, int firstRow, int endRow,
+                              int firstCol, int endCol) {
+        DataValidationHelper helper = sheet.getDataValidationHelper();
+        DataValidationConstraint constraint = helper.createCustomConstraint("DD1");
+        CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
+        DataValidation dataValidation = helper.createValidation(constraint, regions);
+        dataValidation.createPromptBox(promptTitle, promptContent);
+        dataValidation.setShowPromptBox(true);
+        sheet.addValidationData(dataValidation);
+    }
+
+    /**
+     * 设置某些列的值只能输入预制的数据,显示下拉框.
+     *
+     * @param sheet    要设置的sheet.
+     * @param textlist 下拉框显示的内容
+     * @param firstRow 开始行
+     * @param endRow   结束行
+     * @param firstCol 开始列
+     * @param endCol   结束列
+     * @return 设置好的sheet.
+     */
+    public void setXSSFValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol, int endCol) {
+        DataValidationHelper helper = sheet.getDataValidationHelper();
+        // 加载下拉列表内容
+        DataValidationConstraint constraint = helper.createExplicitListConstraint(textlist);
+        // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列
+        CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
+        // 数据有效性对象
+        DataValidation dataValidation = helper.createValidation(constraint, regions);
+        // 处理Excel兼容性问题
+        if (dataValidation instanceof XSSFDataValidation) {
+            dataValidation.setSuppressDropDownArrow(true);
+            dataValidation.setShowErrorBox(true);
+        } else {
+            dataValidation.setSuppressDropDownArrow(false);
+        }
+
+        sheet.addValidationData(dataValidation);
+    }
+
+    /**
+     * 放到字段集合中
+     */
+    private void putToField(Field field, Excel attr) {
+        if (attr != null && (attr.type() == Excel.Type.ALL || attr.type() == type)) {
+            this.fields.add(new Object[]{field, attr});
+        }
+    }
+
+    /**
+     * 填充excel数据
+     *
+     * @param index 序号
+     * @param row   单元格行
+     */
+    public void fillExcelData(int index, Row row) {
+        int startNo = index * sheetSize;
+        int endNo = Math.min(startNo + sheetSize, list.size());
+        for (int i = startNo; i < endNo; i++) {
+            row = sheet.createRow(i + 1 - startNo);
+            // 得到导出对象.
+            T vo = (T) list.get(i);
+            int column = 0;
+            for (Object[] os : fields) {
+                Field field = (Field) os[0];
+                Excel excel = (Excel) os[1];
+                // 设置实体类私有属性可访问
+                field.setAccessible(true);
+                this.addCell(excel, row, vo, field, column++);
+            }
+        }
+    }
+
+    /**
+     * 添加单元格
+     */
+    public Cell addCell(Excel attr, Row row, T vo, Field field, int column) {
+        Cell cell = null;
+        try {
+            // 设置行高
+            row.setHeight((short) (attr.height() * 20));
+            // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列.
+            if (attr.isExport()) {
+                // 创建cell
+                cell = row.createCell(column);
+                if (null != styles) {
+                    cell.setCellStyle(styles.get("data"));
+                }
+                // 用于读取对象中的属性
+//                Object value = getTargetValue(vo, field, attr);
+                Object value = getValue(vo, field.getName());
+                String dateFormat = attr.dateFormat();
+                String dictType = attr.dictType();
+                String readConverterExp = attr.readConverterExp();
+                String readFormatDataMethod = attr.readFormatDataMethod();
+                String desensitize = attr.desensitize();
+                String desensitizeType = attr.desensitizeType();
+                if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value)) {
+                    if (StringUtils.isNotEmpty(String.valueOf(value))) {
+                        cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) value));
+                    }
+
+                } else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value)) {
+                    cell.setCellValue(convertByExp(String.valueOf(value), readConverterExp));
+                } else if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotNull(value)) {
+                    //cell.setCellValue(convertDictByExp(Convert.toStr(value), dictType, attr.separator()));
+                } else if (StringUtils.isNotEmpty(readFormatDataMethod) && "get".equals(readFormatDataMethod)) {
+                    Object val = getValue(vo, field.getName());
+                    cell.setCellValue(String.valueOf(val));
+                } else {
+                    // 设置列类型
+                    setCellVo(value, attr, cell);
+                }
+            }
+        } catch (Exception e) {
+            log.error("导出Excel失败{}", e);
+        }
+        return cell;
+    }
+
+    /**
+     * 以类的属性的get方法方法形式获取值
+     *
+     * @param o
+     * @param name
+     * @return value
+     * @throws Exception
+     */
+    private Object getValue(Object o, String name) throws Exception {
+        if (StringUtils.isNotEmpty(name)) {
+            Class<?> clazz = o.getClass();
+            String methodName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
+            Method method = clazz.getMethod(methodName);
+            o = method.invoke(o);
+        }
+        return null == o ? "" : o;
+    }
+
+    /**
+     * 解析字典值
+     *
+     * @param dictValue 字典值
+     * @param dictType  字典类型
+     * @param separator 分隔符
+     * @return 字典标签
+     */
+   /* public static String convertDictByExp(String dictValue, String dictType, String separator) throws Exception {
+        return DictUtils.getDictLabel(dictType, dictValue, separator);
+    }*/
+
+    /**
+     * 编码文件名
+     */
+    public String encodingFilename(String filename) {
+        if (StringUtils.isEmpty(filename)) {
+            String path = UUID.randomUUID().toString() + "_" + filename + ".xlsx";
+            filename = StringUtils.isNotEmpty(filepath) ? filepath + "//" + path : path;
+        } else {
+            filename = StringUtils.isNotEmpty(filepath) ? filepath + "//" + filename + ".xlsx" : filename + ".xlsx";
+        }
+        return filename;
+    }
+
+    /**
+     * 设置单元格信息
+     *
+     * @param value 单元格值
+     * @param attr  注解相关
+     * @param cell  单元格信息
+     */
+    public void setCellVo(Object value, Excel attr, Cell cell) {
+        if (Excel.ColumnType.STRING == attr.cellType()) {
+            cell.setCellType(CellType.NUMERIC);
+            cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix());
+        } else if (Excel.ColumnType.NUMERIC == attr.cellType()) {
+            cell.setCellType(CellType.NUMERIC);
+            cell.setCellValue(Integer.parseInt(value + ""));
+        }
+    }
+
+    /**
+     * 解析导出值 0=男,1=女,2=未知
+     *
+     * @param propertyValue 参数值
+     * @param converterExp  翻译注解
+     * @return 解析后值
+     * @throws Exception
+     */
+    public static String convertByExp(String propertyValue, String converterExp) throws Exception {
+        try {
+            String[] convertSource = converterExp.split(",");
+            for (String item : convertSource) {
+                String[] itemArray = item.split("=");
+                if (itemArray[0].equals(propertyValue)) {
+                    return itemArray[1];
+                }
+            }
+        } catch (Exception e) {
+            throw e;
+        }
+        return propertyValue;
+    }
+}

+ 17 - 0
lot/src/main/java/cn/hobbystocks/auc/common/utils/Excels.java

@@ -0,0 +1,17 @@
+package cn.hobbystocks.auc.common.utils;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Excel注解集
+ *
+ * @author zheng
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Excels {
+    Excel[] value();
+}

+ 130 - 0
lot/src/main/java/cn/hobbystocks/auc/common/utils/Global.java

@@ -0,0 +1,130 @@
+package cn.hobbystocks.auc.common.utils;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 全局配置类
+ *
+ * @author tzy
+ */
+@Component
+@ConfigurationProperties(prefix = "tzy")
+public class Global
+{
+    /** 项目名称 */
+    private static String name;
+
+    /** 版本 */
+    private static String version;
+
+    /** 版权年份 */
+    private static String copyrightYear;
+
+    /** 实例演示开关 */
+    private static boolean demoEnabled;
+
+    /** 上传路径 */
+    private static String profile;
+
+    /** 获取地址开关 */
+    private static boolean addressEnabled;
+
+    public static String getName()
+    {
+        return name;
+    }
+
+    public void setName(String name)
+    {
+        Global.name = name;
+    }
+
+    public static String getVersion()
+    {
+        return version;
+    }
+
+    public void setVersion(String version)
+    {
+        Global.version = version;
+    }
+
+    public static String getCopyrightYear()
+    {
+        return copyrightYear;
+    }
+
+    public void setCopyrightYear(String copyrightYear)
+    {
+        Global.copyrightYear = copyrightYear;
+    }
+
+    public static boolean isDemoEnabled()
+    {
+        return demoEnabled;
+    }
+
+    public void setDemoEnabled(boolean demoEnabled)
+    {
+        Global.demoEnabled = demoEnabled;
+    }
+
+    public static String getProfile()
+    {
+        return profile;
+    }
+
+    public void setProfile(String profile)
+    {
+        Global.profile = profile;
+    }
+
+    public static boolean isAddressEnabled()
+    {
+        return addressEnabled;
+    }
+
+    public void setAddressEnabled(boolean addressEnabled)
+    {
+        Global.addressEnabled = addressEnabled;
+    }
+
+    /**
+     * 获取图片上传路径
+     */
+    public static String getImageUploadPath()
+    {
+        return  "/tencheerApp/resource/profile";
+    }
+
+    /**
+     * 获取小程序图片上传路径
+     */
+    public static String getWechatImageUploadPath()
+    {
+        return  "/tencheerApp/resource/wechat";
+    }
+    /**
+     * 获取头像上传路径
+     */
+    public static String getAvatarPath()
+    {
+        return getProfile() + "/avatar";
+    }
+    /**
+     * 获取下载路径
+     */
+    public static String getDownloadPath()
+    {
+        return getProfile() + "/download/";
+    }
+
+    /**
+     * 获取上传路径
+     */
+    public static String getUploadPath()
+    {
+        return getProfile() + "/upload";
+    }
+}

+ 1 - 1
lot/src/main/java/cn/hobbystocks/auc/domain/Lot.java

@@ -79,7 +79,7 @@ public class Lot extends BaseEntity
     private String detail;
 
     /** 是否发布(0:未发布;1:已发布) */
-    @ApiModelProperty("是否发布(0:未发布;1:已发布)")
+    @ApiModelProperty("是否发布(1已上架  2已下架  0未审核)")
     private Integer pubStatus;
 
     /** 发布时间 */

+ 81 - 0
lot/src/main/java/cn/hobbystocks/auc/dto/LotExportDTO.java

@@ -0,0 +1,81 @@
+package cn.hobbystocks.auc.dto;
+
+import cn.hobbystocks.auc.annotation.Sensitive;
+import cn.hobbystocks.auc.annotation.View;
+import cn.hobbystocks.auc.common.utils.Excel;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.Date;
+
+@Data
+public class LotExportDTO {
+
+    @Excel(name = "拍品ID")
+    private String id;
+
+    /** 商品ID */
+    @Excel(name = "商品ID")
+    private String goodsId;
+
+    @Excel(name = "商品名称")
+    private String goodsName;
+
+    @Excel(name = "商品种类")
+    private String goodsType;
+
+    /** 排序 */
+    @Excel(name = "排序")
+    private String sort;
+
+    /** 出价次数 */
+    @Excel(name = "出价次数")
+    private String bidCount;
+
+    /** (1已上架  2已下架  0未审核) */
+    @Excel(name = "状态")
+    private String pubStatus;
+
+
+    /** 拍卖状态(Waiting:未开始;Starting:开启中;Bidding:进行中;Finished:拍卖结束;Cancelled:撤拍;Pass:流拍;Sold:成交) */
+    @Excel(name = "拍卖状态")
+    private String status;
+
+    /** 创建时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @Excel(name = "创建时间")
+    private Date createTime;
+
+    /** 拍卖开始时间 */
+    @Excel(name = "拍卖开始时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date startTime;
+
+    /** 拍卖结束时间 */
+    @Excel(name = "拍卖结束时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date endTime;
+
+    /** 保证金(元) */
+    @Excel(name ="保证金(元)")
+    private String deposit;
+
+    /** 服务费(%) */
+    @Excel(name ="服务费(%)")
+    private String serviceTariff;
+
+    /** 规则类型:traditional_delay;标准延时,traditional_delay_v2:重置延时,traditional_delay_v3:增价拍卖 */
+    @Excel(name ="拍卖方式")
+    private String ruleType;
+
+    /** 最新价格 */
+    @Excel(name ="起拍价/当前价")
+    private String lastPrice;
+
+
+}

+ 32 - 0
lot/src/main/java/cn/hobbystocks/auc/request/LotRequest.java

@@ -0,0 +1,32 @@
+package cn.hobbystocks.auc.request;
+
+import cn.hobbystocks.auc.domain.Bid;
+import cn.hobbystocks.auc.domain.Lot;
+import cn.hobbystocks.auc.vo.InData;
+import lombok.Data;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+@Data
+public class LotRequest extends Lot implements InData {
+
+    private Date auctionEndTime;
+
+    private List<Bid> bids;
+
+    private BigDecimal currentPrice;
+
+    public LotRequest() {
+    }
+
+    public LotRequest(Lot lot) {
+        BeanUtils.copyProperties(lot, this);
+        super.setDelay(StringUtils.isEmpty(getDelayPublish()) ? 0 : 1);
+    }
+
+
+}

+ 8 - 0
lot/src/main/java/cn/hobbystocks/auc/service/ILotService.java

@@ -4,7 +4,9 @@ import cn.hobbystocks.auc.domain.Auction;
 import cn.hobbystocks.auc.domain.Lot;
 import cn.hobbystocks.auc.domain.LotFans;
 import cn.hobbystocks.auc.domain.LotGroup;
+import cn.hobbystocks.auc.dto.LotExportDTO;
 import cn.hobbystocks.auc.handle.context.Live;
+import cn.hobbystocks.auc.request.LotRequest;
 import cn.hobbystocks.auc.vo.LiveVO;
 import cn.hobbystocks.auc.vo.LotVO;
 import cn.hobbystocks.auc.vo.SelfVO;
@@ -116,4 +118,10 @@ public interface ILotService extends IService<Lot> {
     List<Lot> selectBiddingLotList();
 
     List<Lot> queryLotByCategory(Lot lot);
+
+    /**
+     * 导出拍品列表信息
+     * @param request
+     */
+    List<LotExportDTO> exportLotList(LotRequest request);
 }

+ 47 - 0
lot/src/main/java/cn/hobbystocks/auc/service/impl/LotServiceImpl.java

@@ -5,12 +5,16 @@ import cn.hobbystocks.auc.common.constant.Constants;
 import cn.hobbystocks.auc.common.core.redis.Locker;
 import cn.hobbystocks.auc.common.core.redis.RedisCache;
 import cn.hobbystocks.auc.common.core.text.Convert;
+import cn.hobbystocks.auc.common.enums.LotStatusEnum;
+import cn.hobbystocks.auc.common.enums.PubStatusEnum;
+import cn.hobbystocks.auc.common.enums.RuleTypeEnum;
 import cn.hobbystocks.auc.common.user.UserUtils;
 import cn.hobbystocks.auc.common.utils.CloneUtils;
 import cn.hobbystocks.auc.common.utils.DateUtils;
 import cn.hobbystocks.auc.common.utils.SensitiveDataUtils;
 import cn.hobbystocks.auc.common.utils.StringUtils;
 import cn.hobbystocks.auc.domain.*;
+import cn.hobbystocks.auc.dto.LotExportDTO;
 import cn.hobbystocks.auc.event.ChangeEvent;
 import cn.hobbystocks.auc.event.EventPublisher;
 import cn.hobbystocks.auc.event.JPushEvent;
@@ -18,12 +22,16 @@ import cn.hobbystocks.auc.event.StartBiddingEvent;
 import cn.hobbystocks.auc.handle.RuleHandlerHolder;
 import cn.hobbystocks.auc.handle.context.Live;
 import cn.hobbystocks.auc.handle.context.LiveContext;
+import cn.hobbystocks.auc.handle.context.tradition.TraditionRule;
 import cn.hobbystocks.auc.mapper.*;
+import cn.hobbystocks.auc.request.LotRequest;
 import cn.hobbystocks.auc.service.ILotService;
 import cn.hobbystocks.auc.task.DynamicTaskService;
 import cn.hobbystocks.auc.vo.LiveVO;
 import cn.hobbystocks.auc.vo.LotVO;
 import cn.hobbystocks.auc.vo.SelfVO;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -641,4 +649,43 @@ public class LotServiceImpl extends ServiceImpl<LotMapper,Lot> implements ILotSe
     public List<Lot> queryLotByCategory(Lot lot) {
         return baseMapper.queryLotListByCategory(lot);
     }
+
+    @Override
+    public List<LotExportDTO> exportLotList(LotRequest request) {
+
+        if (Objects.isNull(request.getPageNum()) && Objects.isNull(request.getPageSize())) {
+            request.setPageNum(1);
+            request.setPageSize(1000);
+        }
+        request.setDelFlag(Constants.DEL_FLAG_NO_DELETE);
+
+        IPage<Lot> lotIPage=new Page<>(request.getPageNum(),request.getPageSize());
+        List<Lot> lotList = lotMapper.selectLotList(lotIPage, request);
+
+        List<LotExportDTO> lotExportDTOS = lotList.stream().map(l -> {
+            LotExportDTO lotExportDTO = new LotExportDTO();
+            lotExportDTO.setId(String.valueOf(l.getId()));
+            lotExportDTO.setGoodsId(l.getGoodsId());
+            lotExportDTO.setGoodsName(l.getGoodsName());
+            lotExportDTO.setGoodsType(l.getGoodsType());
+            lotExportDTO.setSort(String.valueOf(l.getSort()));
+            lotExportDTO.setBidCount(String.valueOf(l.getBidCount()));
+            lotExportDTO.setPubStatus(PubStatusEnum.of(l.getPubStatus()).getDesc());
+            lotExportDTO.setStatus(LotStatusEnum.of(l.getStatus()).getDesc());
+            lotExportDTO.setCreateTime(l.getCreateTime());
+            lotExportDTO.setStartTime(l.getStartTime());
+            lotExportDTO.setEndTime(l.getEndTime());
+            lotExportDTO.setDeposit(String.valueOf(l.getDeposit()));
+            lotExportDTO.setServiceTariff(String.valueOf(l.getServiceTariff()));
+            lotExportDTO.setRuleType(RuleTypeEnum.getByCode(l.getRuleType()).getDesc());
+            // 起拍价
+            if (StringUtils.isNotEmpty(l.getRuleContent())) {
+                TraditionRule traditionRule = JSON.parseObject(l.getRuleContent(), TraditionRule.class);
+                lotExportDTO.setLastPrice(String.valueOf(traditionRule.getStartPrice()));
+            }
+            return lotExportDTO;
+        }).collect(Collectors.toList());
+
+        return lotExportDTOS;
+    }
 }