Procházet zdrojové kódy

Accept Merge Request #6: (dev-wxl -> dev-feat)

Merge Request: 导出相关功能合并

Created By: @万新亮
Accepted By: @万新亮
URL: https://chuanghaikeji.coding.net/p/moxuanyunshangwaimai/d/backend/git/merge/6
万新亮 před 1 rokem
rodič
revize
fa783daa0e
21 změnil soubory, kde provedl 1142 přidání a 55 odebrání
  1. 13 0
      pom.xml
  2. 230 0
      src/main/java/com/sqx/common/utils/SftpUtil.java
  3. 11 5
      src/main/java/com/sqx/datasource/config/DynamicDataSourceConfig.java
  4. 15 15
      src/main/java/com/sqx/datasource/properties/DynamicDataSourceProperties.java
  5. 193 0
      src/main/java/com/sqx/modules/exportExecl/controller/ExportExeclController.java
  6. 18 0
      src/main/java/com/sqx/modules/exportExecl/mapper/ExportJobMapper.java
  7. 66 0
      src/main/java/com/sqx/modules/exportExecl/model/ExportJob.java
  8. 118 0
      src/main/java/com/sqx/modules/exportExecl/model/ExportOrderVo.java
  9. 16 0
      src/main/java/com/sqx/modules/exportExecl/service/ExportJobService.java
  10. 20 0
      src/main/java/com/sqx/modules/exportExecl/service/impl/ExportJobServiceImpl.java
  11. 8 8
      src/main/java/com/sqx/modules/order/controller/OrderController.java
  12. 10 3
      src/main/java/com/sqx/modules/order/dao/AppOrderDao.java
  13. 8 0
      src/main/java/com/sqx/modules/order/entity/TbOrder.java
  14. 1 1
      src/main/java/com/sqx/modules/order/service/AppOrderService.java
  15. 21 20
      src/main/java/com/sqx/modules/order/service/impl/AppAppOrderServiceImpl.java
  16. 32 2
      src/main/java/com/sqx/modules/utils/excel/ExportExcelUtils.java
  17. 5 0
      src/main/java/com/sqx/scheduler/config/SchedulerLock.java
  18. 219 0
      src/main/java/com/sqx/scheduler/export/ExportScheduler.java
  19. 41 0
      src/main/resources/application-dev.yml
  20. 39 0
      src/main/resources/application-prod.yml
  21. 58 1
      src/main/resources/mapper/order/OrderMapper.xml

+ 13 - 0
pom.xml

@@ -416,6 +416,19 @@
             <version>2.1.6</version>
             <version>2.1.6</version>
         </dependency>
         </dependency>
 
 
+        <!-- excel操作 -->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>easyexcel</artifactId>
+            <version>3.1.1</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.jcraft</groupId>
+            <artifactId>jsch</artifactId>
+            <version>0.1.54</version>
+        </dependency>
+
         <!--<dependency>-->
         <!--<dependency>-->
         <!--<groupId>com.baidu.aip</groupId>-->
         <!--<groupId>com.baidu.aip</groupId>-->
         <!--            <artifactId>java-sdk</artifactId>-->
         <!--            <artifactId>java-sdk</artifactId>-->

+ 230 - 0
src/main/java/com/sqx/common/utils/SftpUtil.java

@@ -0,0 +1,230 @@
+package com.sqx.common.utils;
+
+import org.apache.commons.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.jcraft.jsch.*;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.io.*;
+import java.util.Properties;
+
+/**
+ * 类说明 sftp工具类
+ */
+@Component
+public class SftpUtil {
+    private transient Logger log = LoggerFactory.getLogger(this.getClass());
+
+    private ChannelSftp sftp;
+
+    private Session session;
+    /** SFTP 登录用户名*/
+    @Value("${sftp.username}")
+    private String username;
+    /** SFTP 登录密码*/
+    @Value("${sftp.password}")
+    private String password;
+    /** 私钥 */
+    private String privateKey;
+    /** SFTP 服务器地址IP地址*/
+    @Value("${sftp.host}")
+    private String host;
+    /** SFTP 端口*/
+    @Value("${sftp.port}")
+    private int port;
+
+
+    /**
+     * 构造基于密码认证的sftp对象
+     */
+    public SftpUtil(String username, String password, String host, int port) {
+        this.username = username;
+        this.password = password;
+        this.host = host;
+        this.port = port;
+    }
+
+    /**
+     * 构造基于秘钥认证的sftp对象
+     */
+    public SftpUtil(String username, String host, int port, String privateKey) {
+        this.username = username;
+        this.host = host;
+        this.port = port;
+        this.privateKey = privateKey;
+    }
+
+    public SftpUtil(){}
+
+
+    /**
+     * 连接sftp服务器
+     */
+    public void login(){
+        try {
+            JSch jsch = new JSch();
+            if (privateKey != null) {
+                jsch.addIdentity(privateKey);// 设置私钥
+            }
+
+            session = jsch.getSession(username, host, port);
+
+            if (password != null) {
+                session.setPassword(password);
+            }
+            Properties config = new Properties();
+            config.put("StrictHostKeyChecking", "no");
+
+            session.setConfig(config);
+            session.connect();
+
+            Channel channel = session.openChannel("sftp");
+            channel.connect();
+
+            sftp = (ChannelSftp) channel;
+        } catch (JSchException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 关闭连接 server
+     */
+    public void logout(){
+        try{
+            if (sftp != null) {
+                if (sftp.isConnected()) {
+                    sftp.disconnect();
+                }
+            }
+            if (session != null) {
+                if (session.isConnected()) {
+                    session.disconnect();
+                }
+            }
+        }catch (Exception e){
+            log.error("sftp登出失败", e);
+        }
+    }
+
+
+    /**
+     * 将输入流的数据上传到sftp作为文件。文件完整路径=basePath+directory
+     * @param directory  上传到该目录
+     * @param sftpFileName  sftp端文件名
+     * @param input   输入流
+     */
+    public void upload(String directory, String sftpFileName, InputStream input) throws SftpException{
+        try {
+            String home = sftp.getHome();
+            sftp.cd(home);
+            //sftp.cd(basePath);
+            sftp.cd(directory);
+        } catch (SftpException e) {
+            //目录不存在,则创建文件夹
+            String [] dirs=directory.split("/");
+            String tempPath=sftp.getHome();
+            for(String dir:dirs){
+                if(null== dir || "".equals(dir)) continue;
+                tempPath+="/"+dir;
+                try{
+                    sftp.cd(tempPath);
+                }catch(SftpException ex){
+                    sftp.mkdir(tempPath);
+                    sftp.cd(tempPath);
+                }
+            }
+        }
+        sftp.put(input, sftpFileName);  //上传文件
+    }
+
+
+    /**
+     * 下载文件。
+     * @param directory 下载目录
+     * @param downloadFile 下载的文件
+     * @param saveFile 存在本地的路径
+     */
+    public void download(String directory, String downloadFile, File saveFile) throws SftpException, FileNotFoundException{
+        String home = sftp.getHome();
+        sftp.cd(home);
+        if (directory != null && !"".equals(directory)) {
+            sftp.cd(directory);
+        }
+        sftp.get(downloadFile, new FileOutputStream(saveFile));
+    }
+    /**
+     * 下载文件。
+     * @param directory 下载目录
+     * @param downloadFile 下载的文件
+     * @param outputStream 输出流
+     */
+    public void downloadStream(String directory, String downloadFile,OutputStream outputStream) throws SftpException, FileNotFoundException{
+        String home = sftp.getHome();
+        sftp.cd(home);
+        if (directory != null && !"".equals(directory)) {
+            sftp.cd(directory);
+        }
+        sftp.get(downloadFile,outputStream);
+    }
+
+    /**
+     * 下载文件
+     * @param directory 下载目录
+     * @param downloadFile 下载的文件名
+     * @return 字节数组
+     */
+    public byte[] download(String directory, String downloadFile) throws SftpException, IOException{
+        if (directory != null && !"".equals(directory)) {
+            sftp.cd(directory);
+        }
+        InputStream is = sftp.get(downloadFile);
+
+        byte[] fileData = IOUtils.toByteArray(is);
+
+        return fileData;
+    }
+
+
+    /**
+     * 删除文件
+     * @param directory 要删除文件所在目录
+     * @param deleteFile 要删除的文件
+     */
+    public void delete(String directory, String deleteFile) throws SftpException{
+        sftp.cd(directory);
+        sftp.rm(deleteFile);
+    }
+
+    public ChannelSftp getSftp() {
+        return sftp;
+    }
+
+    public boolean isConnected(){
+        return sftp.isConnected();
+    }
+
+    public boolean mkdir(String dir){
+        try{
+            sftp.mkdir(dir);
+            return true;
+        }catch (Exception e){
+            log.error("目录创建失败: ", e);
+            return false;
+        }
+    }
+
+    //上传文件测试
+    public static void main(String[] args) throws SftpException, IOException {
+        SftpUtil sftp = new SftpUtil("export", "Waimai2024#", "172.16.20.108", 22);
+        sftp.login();
+        File file = new File("E:\\chen\\Desktop\\fsdownload\\text.log");
+        InputStream is = new FileInputStream(file);
+
+        sftp.upload("/", "text.log", is);
+        sftp.download("/","test_sftp.jpg",file);
+        sftp.logout();
+    }
+}

+ 11 - 5
src/main/java/com/sqx/datasource/config/DynamicDataSourceConfig.java

@@ -2,7 +2,7 @@ package com.sqx.datasource.config;
 
 
 import com.alibaba.druid.pool.DruidDataSource;
 import com.alibaba.druid.pool.DruidDataSource;
 import com.sqx.datasource.properties.DataSourceProperties;
 import com.sqx.datasource.properties.DataSourceProperties;
-import com.sqx.datasource.properties.DynamicDataSourceProperties;
+//import com.sqx.datasource.properties.DynamicDataSourceProperties;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
@@ -16,16 +16,21 @@ import java.util.Map;
  * 配置多数据源
  * 配置多数据源
  */
  */
 @Configuration
 @Configuration
-@EnableConfigurationProperties(DynamicDataSourceProperties.class)
+//@EnableConfigurationProperties(DynamicDataSourceProperties.class)
 public class DynamicDataSourceConfig {
 public class DynamicDataSourceConfig {
-    @Autowired
-    private DynamicDataSourceProperties properties;
+//    @Autowired
+//    private DynamicDataSourceProperties properties;
 
 
     @Bean
     @Bean
     @ConfigurationProperties(prefix = "spring.datasource.druid")
     @ConfigurationProperties(prefix = "spring.datasource.druid")
     public DataSourceProperties dataSourceProperties() {
     public DataSourceProperties dataSourceProperties() {
         return new DataSourceProperties();
         return new DataSourceProperties();
     }
     }
+    @Bean
+    @ConfigurationProperties(prefix = "dynamic")
+    public DataSourceProperties getDatasource() {
+        return new DataSourceProperties();
+    }
 
 
     @Bean
     @Bean
     public DynamicDataSource dynamicDataSource(DataSourceProperties dataSourceProperties) {
     public DynamicDataSource dynamicDataSource(DataSourceProperties dataSourceProperties) {
@@ -40,7 +45,8 @@ public class DynamicDataSourceConfig {
     }
     }
 
 
     private Map<Object, Object> getDynamicDataSource(){
     private Map<Object, Object> getDynamicDataSource(){
-        Map<String, DataSourceProperties> dataSourcePropertiesMap = properties.getDatasource();
+        Map<String, DataSourceProperties> dataSourcePropertiesMap = new HashMap<>();
+        dataSourcePropertiesMap.put("dynamic",this.getDatasource());
         Map<Object, Object> targetDataSources = new HashMap<>(dataSourcePropertiesMap.size());
         Map<Object, Object> targetDataSources = new HashMap<>(dataSourcePropertiesMap.size());
         dataSourcePropertiesMap.forEach((k, v) -> {
         dataSourcePropertiesMap.forEach((k, v) -> {
             DruidDataSource druidDataSource = DynamicDataSourceFactory.buildDruidDataSource(v);
             DruidDataSource druidDataSource = DynamicDataSourceFactory.buildDruidDataSource(v);

+ 15 - 15
src/main/java/com/sqx/datasource/properties/DynamicDataSourceProperties.java

@@ -5,18 +5,18 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Map;
 
 
-/**
- * 多数据源属性
- */
-@ConfigurationProperties(prefix = "dynamic")
-public class DynamicDataSourceProperties {
-    private Map<String, DataSourceProperties> datasource = new LinkedHashMap<>();
-
-    public Map<String, DataSourceProperties> getDatasource() {
-        return datasource;
-    }
-
-    public void setDatasource(Map<String, DataSourceProperties> datasource) {
-        this.datasource = datasource;
-    }
-}
+///**
+// * 多数据源属性
+// */
+//@ConfigurationProperties(prefix = "dynamic")
+//public class DynamicDataSourceProperties {
+//    private Map<String, DataSourceProperties> datasource = new LinkedHashMap<>();
+//
+//    public Map<String, DataSourceProperties> getDatasource() {
+//        return datasource;
+//    }
+//
+//    public void setDatasource(Map<String, DataSourceProperties> datasource) {
+//        this.datasource = datasource;
+//    }
+//}

+ 193 - 0
src/main/java/com/sqx/modules/exportExecl/controller/ExportExeclController.java

@@ -0,0 +1,193 @@
+package com.sqx.modules.exportExecl.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jcraft.jsch.SftpException;
+import com.sqx.common.utils.PageUtils;
+import com.sqx.common.utils.Result;
+import com.sqx.common.utils.SftpUtil;
+import com.sqx.modules.common.service.CommonInfoService;
+import com.sqx.modules.exportExecl.mapper.ExportJobMapper;
+import com.sqx.modules.exportExecl.model.ExportJob;
+import com.sqx.modules.exportExecl.service.ExportJobService;
+import com.sqx.modules.order.dao.AppOrderDao;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.util.IOUtils;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URLEncoder;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
+
+@Slf4j
+@Api(tags={"管理端-导出"})
+@RestController
+@RequestMapping("/admin/export")
+@RequiredArgsConstructor
+public class ExportExeclController {
+
+    private final AppOrderDao appOrderDao;
+
+    private final ExportJobMapper exportJobMapper;
+
+    private final ExportJobService exportJobService;
+
+    private final CommonInfoService commonInfoService;
+
+    private final SftpUtil sftpUtil;
+
+    @GetMapping("excelOrder")
+    @ApiOperation("导出卡密列表")
+    public Result excelOrder(Integer status, String phone, Long shopId, String userName,
+                             String orderNumber, Integer orderType, String shopName, String riderPhone,
+                             String startTime, String endTime, String userId, String payStartTime, String payEndTime) throws Exception{
+        Integer size = appOrderDao.excelAllOrderAdminCount( status, phone, shopId, userName, orderNumber, orderType,
+                shopName, riderPhone,startTime,endTime,payStartTime,payEndTime);
+        //可导出最大数量
+        String count=commonInfoService.findOne(431).getValue();
+        if(size>Integer.parseInt(count)){
+            return Result.error("导出总数不能超过"+Integer.parseInt(count)+",请添加筛选条件");
+        }
+        if(!StringUtils.hasText(userId)){
+            return Result.error("用户id不能为空");
+        }
+        StringBuffer stringBuffer=new StringBuffer();
+        if(status!=null){stringBuffer.append("状态:"+getState(status)+";");}
+        if(phone!=null&&!phone.trim().equals("")){stringBuffer.append("手机号:"+phone+";");}
+//        if(shopId!=null){stringBuffer.append(":"+shopId+";");}
+        if(userName!=null&&!userName.trim().equals("")){stringBuffer.append("昵称:"+userName+";");}
+        if(orderNumber!=null&&!orderNumber.trim().equals("")){stringBuffer.append("订单号:"+orderNumber+";");}
+        if(orderType!=null){stringBuffer.append("订单类型:"+(orderType==1?"上门":"外卖")+";");}
+        if(shopName!=null&&!shopName.trim().equals("")){stringBuffer.append("商铺名称:"+shopName+";");}
+        if(riderPhone!=null&&!riderPhone.trim().equals("")){stringBuffer.append("骑手手机号:"+riderPhone+";");}
+        if(startTime!=null&&!startTime.trim().equals("")){stringBuffer.append("开始时间:"+startTime+";");}
+        if(endTime!=null&&!endTime.trim().equals("")){stringBuffer.append("结束时间:"+endTime+";");}
+        if(payStartTime!=null&&!payStartTime.trim().equals("")){stringBuffer.append("支付开始时间:"+payStartTime+";");}
+        if(payEndTime!=null&&!payEndTime.trim().equals("")){stringBuffer.append("支付结束时间:"+payEndTime+";");}
+
+        ExportJob exportJob =new ExportJob();
+        exportJob.setFlag(0);
+        exportJob.setFileType("order");
+        exportJob.setConditionDetail(stringBuffer.toString());
+        exportJob.setConditions(","+(status==null?"":status)+","+phone+","+(shopId==null?"":shopId)+","+userName+","+orderNumber+","
+                +(orderType==null?"":orderType)+","+shopName+","
+                +riderPhone+","+startTime+","+endTime+","+payStartTime+","+payEndTime);
+        LocalDateTime localDateTime = LocalDateTime.now();
+        String time=localDateTime.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
+        exportJob.setFileName(time+"订单列表.xlsx");
+        exportJob.setUserId(userId);
+        exportJob.setCreateTime(new Date());
+        exportJob.setUpdateTime(new Date());
+        int a=exportJobMapper.insert(exportJob);
+        if (a==1){
+            return Result.success("新增导出计划成功");
+        }else{
+            return Result.error("新增导出计划失败");
+        }
+    }
+    @GetMapping("excelRecharge")
+    @ApiOperation("导出充值记录")
+    public Result excelRecharge(String rechargeOrder, String acount,String userId) throws Exception{
+        if(!StringUtils.hasText(userId)){
+            return Result.error("用户id不能为空");
+        }
+        StringBuffer stringBuffer=new StringBuffer();
+        if(rechargeOrder!=null&&rechargeOrder!=""){stringBuffer.append("充值订单号:"+rechargeOrder+";");}
+        if(acount!=null&&acount!=""){stringBuffer.append("被充值账号:"+acount+";");}
+
+        ExportJob exportJob =new ExportJob();
+        exportJob.setFlag(0);
+        exportJob.setFileType("recharge");
+        exportJob.setConditionDetail(stringBuffer.toString());
+        exportJob.setConditions(","+rechargeOrder+","+acount);
+        LocalDateTime localDateTime = LocalDateTime.now();
+        String time=localDateTime.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
+        exportJob.setFileName(time+"充值记录.xlsx");
+        exportJob.setCreateTime(new Date());
+        exportJob.setUpdateTime(new Date());
+        exportJob.setUserId(userId);
+        int a=exportJobMapper.insert(exportJob);
+        if (a==1){
+            return Result.success("新增导出计划成功");
+        }else{
+            return Result.error("新增导出计划失败");
+        }
+    }
+    //    任意文件读取/下载
+    @ApiOperation(value = "查询下载列表")
+    @GetMapping("listByUser")
+    public Result List(String userId,String state,String startTime,String endTime,Integer curretPage,Integer pageSize) throws IOException {
+
+        QueryWrapper queryWrapper=new QueryWrapper<ExportJob>();
+
+        queryWrapper.eq("user_id",userId);
+        if(StringUtils.hasText(state)){
+            queryWrapper.eq("flag",state);
+        }
+        if(StringUtils.hasText(startTime)){
+            queryWrapper.ge("create_time",startTime);
+        }
+        if(StringUtils.hasText(endTime)){
+            queryWrapper.le("create_time",endTime);
+        }
+        queryWrapper.orderByDesc("create_time");
+        IPage<ExportJob> iPage=exportJobService.page(new Page<>(curretPage,pageSize),queryWrapper);
+        PageUtils pageUtils = new PageUtils(iPage);
+        return Result.success().put("data", pageUtils);
+    }
+
+    //    任意文件读取/下载
+    @ApiOperation(value = "文件下载")
+    @GetMapping("readBuffer")
+    public void readbuffer(String filename,HttpServletResponse response) throws IOException {
+        if(filename.contains("..") || filename.contains("/")){
+            throw new IOException("文件名异常");
+        }
+        String value=commonInfoService.findOne(430).getValue()==null?"":commonInfoService.findOne(430).getValue();
+        sftpUtil.login();
+        try {
+            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+            // 下载文件的默认名称
+            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "utf-8"));
+            sftpUtil.downloadStream(value,filename,response.getOutputStream());
+            log.info("文件下载成功");
+        }catch (IOException | SftpException e){
+            log.error(e.getMessage());
+            log.error("文件下载失败");
+        }finally {
+            if (sftpUtil.isConnected()){
+                sftpUtil.logout();
+            }
+        }
+    }
+
+    // '订单状态 0待结算 1待支付 2直接购买(未支付) 7商家待接单 8商家拒绝接单 6制作中  3待取餐/派送中 4已完成 5已取消 ',
+    private String getState(Integer state){
+        switch (state){
+            case 1: return "待支付";
+            case 2: return "未支付";
+            case 3: return "待取餐";
+            case 4: return "已完成";
+            case 5: return "已取消";
+            case 6: return "制作中";
+            case 7: return "商家待接单";
+            case 8: return "商家拒绝接单";
+            case 0: return "待结算";
+            default: return state+"";
+        }
+    }
+}

+ 18 - 0
src/main/java/com/sqx/modules/exportExecl/mapper/ExportJobMapper.java

@@ -0,0 +1,18 @@
+package com.sqx.modules.exportExecl.mapper;
+
+import com.sqx.modules.exportExecl.model.ExportJob;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author wan
+ * @since 2024-09-25
+ */
+@Mapper
+public interface ExportJobMapper extends BaseMapper<ExportJob> {
+
+}

+ 66 - 0
src/main/java/com/sqx/modules/exportExecl/model/ExportJob.java

@@ -0,0 +1,66 @@
+package com.sqx.modules.exportExecl.model;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+
+import java.io.Serializable;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author wan
+ * @since 2024-09-25
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value="ExportJob对象", description="")
+public class ExportJob implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "export_id", type = IdType.AUTO)
+    private Integer exportId;
+
+    @ApiModelProperty(value = "文件名称")
+    private String fileName;
+
+    @ApiModelProperty(value = "文件类型")
+    private String fileType;
+
+    @ApiModelProperty(value = "用户id")
+    private String userId;
+
+    @ApiModelProperty(value = "创建时间")
+    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone="GMT+8")
+    private Date createTime;
+
+    @ApiModelProperty(value = "更新时间")
+    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone="GMT+8")
+    private Date updateTime;
+
+    @ApiModelProperty(value = "导出条件描述")
+    private String conditionDetail;
+
+    @ApiModelProperty(value = "导出条件")
+    private String conditions;
+
+    @ApiModelProperty(value = "文件大小")
+    private String fileSize;
+
+    @ApiModelProperty(value = "状态 0待导出 1导出已完成 2导出失败")
+    private Integer flag;
+
+
+}

+ 118 - 0
src/main/java/com/sqx/modules/exportExecl/model/ExportOrderVo.java

@@ -0,0 +1,118 @@
+package com.sqx.modules.exportExecl.model;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.write.style.ColumnWidth;
+import lombok.Data;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author wan
+ * @since 2024-07-22
+ */
+@Data
+public class ExportOrderVo {
+
+
+    @ColumnWidth(0)
+    @ExcelProperty(value = "编号" , index = 0)
+    private String orderId;
+    @ColumnWidth(1)
+    @ExcelProperty(value = "下单用户" , index = 0)
+    private String userName;
+
+    @ColumnWidth(2)
+    @ExcelProperty(value = "用户头像" , index = 0)
+    private String avatar;
+
+    @ColumnWidth(3)
+    @ExcelProperty(value = "手机号" , index = 0)
+    private String phone;
+
+    @ColumnWidth(4)
+    @ExcelProperty(value = "商铺信息" , index = 0)
+    private String shopDetail;
+
+    @ColumnWidth(5)
+    @ExcelProperty(value = "订单类型" , index = 0)
+    private String orderType;
+
+    @ColumnWidth(6)
+    @ExcelProperty(value = "配送信息" , index = 0)
+    private String identail;
+
+    @ColumnWidth(7)
+    @ExcelProperty(value = "骑手昵称" , index = 0)
+    private String riderNickName;
+
+    @ColumnWidth(8)
+    @ExcelProperty(value = "骑手电话" , index = 0)
+    private String riderPhone;
+
+    @ColumnWidth(9)
+    @ExcelProperty(value = "订单号" , index = 0)
+    private String orderNumber;
+
+    @ColumnWidth(10)
+    @ExcelProperty(value = "内容" , index = 0)
+    private String goodsDetail;
+
+    @ColumnWidth(11)
+    @ExcelProperty(value = "商品总价(元)" , index = 0)
+    private String sumPrice;
+
+    @ColumnWidth(12)
+    @ExcelProperty(value = "优惠金额(元)" , index = 0)
+    private String couponMoney;
+
+    @ColumnWidth(13)
+    @ExcelProperty(value = "参与活动名称" , index = 0)
+    private String activityTitle;
+
+    @ColumnWidth(14)
+    @ExcelProperty(value = "活动优惠金额(元)" , index = 0)
+    private String activityDiscountAmount;
+
+    @ColumnWidth(15)
+    @ExcelProperty(value = "打包费(元/个 具体按照数量计算)" , index = 0)
+    private String packMoney;
+
+    @ColumnWidth(16)
+    @ExcelProperty(value = "跑腿费(元)" , index = 0)
+    private String errandMoney;
+
+    @ColumnWidth(17)
+    @ExcelProperty(value = "支付金额(元)" , index = 0)
+    private String payMoney;
+
+    @ColumnWidth(18)
+    @ExcelProperty(value = "跑腿费说明" , index = 0)
+    private String errandMoneyIsShop;
+
+    @ColumnWidth(19)
+    @ExcelProperty(value = "订单备注" , index = 0)
+    private String remark;
+
+    @ColumnWidth(20)
+    @ExcelProperty(value = "支付时间" , index = 0)
+    private String payTime;
+
+    @ColumnWidth(21)
+    @ExcelProperty(value = "支付方式" , index = 0)
+    private String payType;
+
+    @ColumnWidth(22)
+    @ExcelProperty(value = "取餐号" , index = 0)
+    private String qucanhao;
+
+    @ColumnWidth(23)
+    @ExcelProperty(value = "状态" , index = 0)
+    private String orderCode;
+
+    @ColumnWidth(24)
+    @ExcelProperty(value = "是否转单" , index = 0)
+    private String isRider;
+
+}

+ 16 - 0
src/main/java/com/sqx/modules/exportExecl/service/ExportJobService.java

@@ -0,0 +1,16 @@
+package com.sqx.modules.exportExecl.service;
+
+import com.sqx.modules.exportExecl.model.ExportJob;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author wan
+ * @since 2024-09-25
+ */
+public interface ExportJobService extends IService<ExportJob> {
+
+}

+ 20 - 0
src/main/java/com/sqx/modules/exportExecl/service/impl/ExportJobServiceImpl.java

@@ -0,0 +1,20 @@
+package com.sqx.modules.exportExecl.service.impl;
+
+import com.sqx.modules.exportExecl.model.ExportJob;
+import com.sqx.modules.exportExecl.mapper.ExportJobMapper;
+import com.sqx.modules.exportExecl.service.ExportJobService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author wan
+ * @since 2024-09-25
+ */
+@Service
+public class ExportJobServiceImpl extends ServiceImpl<ExportJobMapper, ExportJob> implements ExportJobService {
+
+}

+ 8 - 8
src/main/java/com/sqx/modules/order/controller/OrderController.java

@@ -51,14 +51,14 @@ public class OrderController extends AbstractController {
         return appOrderService.selectAllOrderAdmin(page, limit, status, phone, shopId, userName, orderNumber, orderType, shopName, riderPhone, indentStatus, reservationFlag, startTime, endTime, payStartTime, payEndTime);
         return appOrderService.selectAllOrderAdmin(page, limit, status, phone, shopId, userName, orderNumber, orderType, shopName, riderPhone, indentStatus, reservationFlag, startTime, endTime, payStartTime, payEndTime);
     }
     }
 
 
-    @GetMapping("excelOrder")
-    @ApiOperation("导出卡密列表")
-    public void excelOrder(Integer status, String phone, Long shopId, String userName,
-                           String orderNumber, Integer orderType,String shopName,String riderPhone,
-                           String startTime, String endTime, HttpServletResponse response) throws Exception{
-        ExcelData excelData = appOrderService.excelAllOrderAdmin(status, phone, shopId, userName, orderNumber, orderType, shopName, riderPhone, startTime, endTime);
-        ExportExcelUtils.exportExcel(response,"订单列表.xlsx",excelData);
-    }
+//    @GetMapping("excelOrder")
+//    @ApiOperation("导出卡密列表")
+//    public void excelOrder(Integer status, String phone, Long shopId, String userName,
+//                           String orderNumber, Integer orderType,String shopName,String riderPhone,
+//                           String startTime, String endTime, HttpServletResponse response) throws Exception{
+//        ExcelData excelData = appOrderService.excelAllOrderAdmin(status, phone, shopId, userName, orderNumber, orderType, shopName, riderPhone, startTime, endTime);
+//        ExportExcelUtils.exportExcel(response,"订单列表.xlsx",excelData);
+//    }
 
 
     @ApiOperation("完成订单")
     @ApiOperation("完成订单")
     @PostMapping(value = "accomplishOrder")
     @PostMapping(value = "accomplishOrder")

+ 10 - 3
src/main/java/com/sqx/modules/order/dao/AppOrderDao.java

@@ -3,6 +3,7 @@ package com.sqx.modules.order.dao;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.sqx.datasource.annotation.DataSource;
 import com.sqx.modules.order.entity.TbOrder;
 import com.sqx.modules.order.entity.TbOrder;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Param;
@@ -23,17 +24,23 @@ public interface AppOrderDao extends BaseMapper<TbOrder> {
     IPage<TbOrder> selectOrder(Page<TbOrder> pages,@Param("status") Integer status,@Param("phone") String phone, @Param("shopId") Long shopId,
     IPage<TbOrder> selectOrder(Page<TbOrder> pages,@Param("status") Integer status,@Param("phone") String phone, @Param("shopId") Long shopId,
                                @Param("userName") String userName, @Param("orderNumber") String orderNumber,@Param("orderType") Integer orderType,@Param("shopName")String shopName);
                                @Param("userName") String userName, @Param("orderNumber") String orderNumber,@Param("orderType") Integer orderType,@Param("shopName")String shopName);
 
 
-
+    @DataSource("dynamic")
     IPage<TbOrder> selectAllOrderAdmin(Page<TbOrder> pages,@Param("status") Integer status,@Param("phone") String phone, @Param("shopId") Long shopId,
     IPage<TbOrder> selectAllOrderAdmin(Page<TbOrder> pages,@Param("status") Integer status,@Param("phone") String phone, @Param("shopId") Long shopId,
                                @Param("userName") String userName, @Param("orderNumber") String orderNumber,@Param("orderType") Integer orderType,
                                @Param("userName") String userName, @Param("orderNumber") String orderNumber,@Param("orderType") Integer orderType,
                                        @Param("shopName")String shopName,@Param("riderPhone") String riderPhone, @Param("indentStatus") String indentStatus, @Param("reservationFlag") String reservationFlag,
                                        @Param("shopName")String shopName,@Param("riderPhone") String riderPhone, @Param("indentStatus") String indentStatus, @Param("reservationFlag") String reservationFlag,
                                        @Param("startTime") String startTime,@Param("endTime") String endTime, @Param("payStartTime") String payStartTime, @Param("payEndTime") String payEndTime);
                                        @Param("startTime") String startTime,@Param("endTime") String endTime, @Param("payStartTime") String payStartTime, @Param("payEndTime") String payEndTime);
-
+    @DataSource("dynamic")
     List<TbOrder> excelAllOrderAdmin(@Param("status") Integer status,@Param("phone") String phone, @Param("shopId") Long shopId,
     List<TbOrder> excelAllOrderAdmin(@Param("status") Integer status,@Param("phone") String phone, @Param("shopId") Long shopId,
                                        @Param("userName") String userName, @Param("orderNumber") String orderNumber,
                                        @Param("userName") String userName, @Param("orderNumber") String orderNumber,
                                      @Param("orderType") Integer orderType,@Param("shopName")String shopName,
                                      @Param("orderType") Integer orderType,@Param("shopName")String shopName,
                                      @Param("riderPhone") String riderPhone,@Param("startTime") String startTime,
                                      @Param("riderPhone") String riderPhone,@Param("startTime") String startTime,
-                                     @Param("endTime") String endTime);
+                                     @Param("endTime") String endTime,@Param("payStartTime") String payStartTime,@Param("payEndTime") String payEndTime);
+    @DataSource("dynamic")
+    Integer excelAllOrderAdminCount(@Param("status") Integer status,@Param("phone") String phone, @Param("shopId") Long shopId,
+                                     @Param("userName") String userName, @Param("orderNumber") String orderNumber,
+                                     @Param("orderType") Integer orderType,@Param("shopName")String shopName,
+                                     @Param("riderPhone") String riderPhone,@Param("startTime") String startTime,
+                                     @Param("endTime") String endTime,@Param("payStartTime") String payStartTime,@Param("payEndTime") String payEndTime);
 
 
 
 
     IPage<TbOrder> selectOrderByAdmin(Page<TbOrder> pages,@Param("status") Integer status,@Param("phone") String phone,
     IPage<TbOrder> selectOrderByAdmin(Page<TbOrder> pages,@Param("status") Integer status,@Param("phone") String phone,

+ 8 - 0
src/main/java/com/sqx/modules/order/entity/TbOrder.java

@@ -255,5 +255,13 @@ public class TbOrder implements Serializable {
     @TableField(exist = false)
     @TableField(exist = false)
     private Integer isRider;
     private Integer isRider;
 
 
+    @TableField(exist = false)
+    @ApiModelProperty("导出商品详情")
+    private String detail;
+
+    @TableField(exist = false)
+    @ApiModelProperty("导出商品总价")
+    private Double sumPrice;
+
     public TbOrder() {}
     public TbOrder() {}
 }
 }

+ 1 - 1
src/main/java/com/sqx/modules/order/service/AppOrderService.java

@@ -34,7 +34,7 @@ public interface AppOrderService extends IService<TbOrder> {
 
 
     ExcelData excelAllOrderAdmin(Integer status, String phone, Long shopId,
     ExcelData excelAllOrderAdmin(Integer status, String phone, Long shopId,
                                  String userName, String orderNumber, Integer orderType, String shopName,
                                  String userName, String orderNumber, Integer orderType, String shopName,
-                                 String riderPhone, String startTime, String endTime);
+                                 String riderPhone, String startTime, String endTime,String payStartTime, String payEndTime);
 
 
     Result selectOrderByUserId(Long userId, String date, String dateType);
     Result selectOrderByUserId(Long userId, String date, String dateType);
 
 

+ 21 - 20
src/main/java/com/sqx/modules/order/service/impl/AppAppOrderServiceImpl.java

@@ -1288,14 +1288,14 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
     @Override
     @Override
     public ExcelData excelAllOrderAdmin(Integer status, String phone, Long shopId,
     public ExcelData excelAllOrderAdmin(Integer status, String phone, Long shopId,
                                         String userName, String orderNumber, Integer orderType, String shopName,
                                         String userName, String orderNumber, Integer orderType, String shopName,
-                                        String riderPhone, String startTime, String endTime) {
+                                        String riderPhone, String startTime, String endTime,String payStartTime, String payEndTime) {
         List<TbOrder> tbOrderIPage = appOrderDao.excelAllOrderAdmin( status, phone, shopId, userName, orderNumber, orderType,
         List<TbOrder> tbOrderIPage = appOrderDao.excelAllOrderAdmin( status, phone, shopId, userName, orderNumber, orderType,
-                shopName, riderPhone,startTime,endTime);
-        for (int i = 0; i < tbOrderIPage.size(); i++) {
-            List<OrderGoods> orderGoodsList = orderGoodsDao.selectList(new QueryWrapper<OrderGoods>()
-                    .eq("order_id", tbOrderIPage.get(i).getOrderId()));
-            tbOrderIPage.get(i).setOrderGoodsList(orderGoodsList);
-        }
+                shopName, riderPhone,startTime,endTime,payStartTime,payEndTime);
+//        for (int i = 0; i < tbOrderIPage.size(); i++) {
+//            List<OrderGoods> orderGoodsList = orderGoodsDao.selectList(new QueryWrapper<OrderGoods>()
+//                    .eq("order_id", tbOrderIPage.get(i).getOrderId()));
+//            tbOrderIPage.get(i).setOrderGoodsList(orderGoodsList);
+//        }
         ExcelData data = new ExcelData();
         ExcelData data = new ExcelData();
         data.setName("订单列表");
         data.setName("订单列表");
         List<String> titles = new ArrayList();
         List<String> titles = new ArrayList();
@@ -1341,19 +1341,19 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
             row.add(order.getRiderNickName());
             row.add(order.getRiderNickName());
             row.add(order.getRiderPhone());
             row.add(order.getRiderPhone());
             row.add(order.getOrderNumber());
             row.add(order.getOrderNumber());
-            stringBuffer=new StringBuffer();
-            BigDecimal sumGoodsPrice=BigDecimal.ZERO;
-            List<OrderGoods> orderGoodsList = order.getOrderGoodsList();
-            for(int i=0;i<orderGoodsList.size();i++){
-                OrderGoods orderGoods = orderGoodsList.get(i);
-                stringBuffer.append(i + 1).append(". 商品名:").append(orderGoods.getGoodsName()).append(",数量:").append(orderGoods.getGoodsNum()).append(",规格:").append(orderGoods.getSkuMessage());
-                if(orderGoods.getGoodsPrice()!=null && orderGoods.getGoodsNum()!=null){
-                    BigDecimal goodsPrice = orderGoods.getGoodsPrice().multiply(BigDecimal.valueOf(orderGoods.getGoodsNum()));
-                    sumGoodsPrice=sumGoodsPrice.add(goodsPrice);
-                }
-            }
-            row.add(stringBuffer.toString());
-            row.add(sumGoodsPrice);
+//            stringBuffer=new StringBuffer();
+//            BigDecimal sumGoodsPrice=BigDecimal.ZERO;
+//            List<OrderGoods> orderGoodsList = order.getOrderGoodsList();
+//            for(int i=0;i<orderGoodsList.size();i++){
+//                OrderGoods orderGoods = orderGoodsList.get(i);
+//                stringBuffer.append(i + 1).append(". 商品名:").append(orderGoods.getGoodsName()).append(",数量:").append(orderGoods.getGoodsNum()).append(",规格:").append(orderGoods.getSkuMessage());
+//                if(orderGoods.getGoodsPrice()!=null && orderGoods.getGoodsNum()!=null){
+//                    BigDecimal goodsPrice = orderGoods.getGoodsPrice().multiply(BigDecimal.valueOf(orderGoods.getGoodsNum()));
+//                    sumGoodsPrice=sumGoodsPrice.add(goodsPrice);
+//                }
+//            }
+            row.add(order.getDetail());
+            row.add(order.getSumPrice());
             row.add(order.getCouponMoney());
             row.add(order.getCouponMoney());
             row.add(order.getActivityTitle());
             row.add(order.getActivityTitle());
             row.add(order.getActivityDiscountAmount());
             row.add(order.getActivityDiscountAmount());
@@ -1362,6 +1362,7 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
             row.add(order.getPayMoney());
             row.add(order.getPayMoney());
 
 
             row.add(order.getErrandMoneyIsShop());
             row.add(order.getErrandMoneyIsShop());
+            row.add(order.getRemark());
             row.add(order.getPayTime());
             row.add(order.getPayTime());
             //支付方式  1微信支付  2余额支付  3支付宝支付
             //支付方式  1微信支付  2余额支付  3支付宝支付
             if(order.getPayType()!=null && order.getPayType()==1){
             if(order.getPayType()!=null && order.getPayType()==1){

+ 32 - 2
src/main/java/com/sqx/modules/utils/excel/ExportExcelUtils.java

@@ -1,13 +1,20 @@
 package com.sqx.modules.utils.excel;
 package com.sqx.modules.utils.excel;
 
 
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.ExcelWriter;
+import com.alibaba.excel.write.metadata.WriteSheet;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.poi.ss.usermodel.*;
 import org.apache.poi.ss.usermodel.*;
 import org.apache.poi.xssf.usermodel.*;
 import org.apache.poi.xssf.usermodel.*;
 import org.apache.poi.xssf.usermodel.extensions.XSSFCellBorder;
 import org.apache.poi.xssf.usermodel.extensions.XSSFCellBorder;
 
 
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpServletResponse;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
 import java.io.OutputStream;
 import java.io.OutputStream;
 import java.net.URLEncoder;
 import java.net.URLEncoder;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
 
 
 /**
 /**
@@ -202,8 +209,31 @@ public class ExportExcelUtils {
         return new int[] { r, g, b };
         return new int[] { r, g, b };
     }
     }
 
 
+    public static void writeExcel2(ByteArrayOutputStream os,String fileName, ExcelData excelData) throws Exception {
+        // 文件输出位置
 
 
+        List<List<String>> headList=new ArrayList<>();
+        List<String> list=excelData.getTitles();
+        for (int i = 0; i < list.size(); i++) {
+            List<String> temList=new ArrayList<>();
+            temList.add(list.get(i));
+            headList.add(temList);
+        }
+        ExcelWriter excelWriter =null;
+        try {
 
 
-
-
+            excelWriter = EasyExcel.write(os).head(headList).build();
+            // 同一个sheet只要创建一次
+            WriteSheet writeSheet = EasyExcel.writerSheet("sheet1").build();
+            // 调用写入
+            excelWriter.write(excelData.getRows(), writeSheet);
+        } catch (Exception e) {
+            System.out.println("下载模板失败"+e.getMessage());
+        } finally {
+            // 关闭流
+            if (excelWriter != null) {
+                excelWriter.finish();
+            }
+        }
+    }
 }
 }

+ 5 - 0
src/main/java/com/sqx/scheduler/config/SchedulerLock.java

@@ -32,4 +32,9 @@ public interface SchedulerLock {
      * 跑腿订单自动推送锁
      * 跑腿订单自动推送锁
      */
      */
     String INDENT_AUTO_PUSH_LOCK = "wm:lock:indent:push";
     String INDENT_AUTO_PUSH_LOCK = "wm:lock:indent:push";
+
+    /**
+     * 导出锁
+     */
+    String EXPORT_LOCK = "export:lock";
 }
 }

+ 219 - 0
src/main/java/com/sqx/scheduler/export/ExportScheduler.java

@@ -0,0 +1,219 @@
+package com.sqx.scheduler.export;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.sqx.common.utils.SftpUtil;
+import com.sqx.modules.app.entity.RechargeRecord;
+import com.sqx.modules.app.service.RechargeRecordService;
+import com.sqx.modules.common.service.CommonInfoService;
+import com.sqx.modules.exportExecl.mapper.ExportJobMapper;
+import com.sqx.modules.exportExecl.model.ExportJob;
+import com.sqx.modules.exportExecl.service.ExportJobService;
+import com.sqx.modules.order.service.AppOrderService;
+import com.sqx.modules.utils.excel.ExcelData;
+import com.sqx.modules.utils.excel.ExportExcelUtils;
+import com.sqx.scheduler.config.SchedulerLock;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 优惠券定时任务
+ *
+ * @author : codingliang
+ * @date : 2024-09-09 12:22
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+@RequestMapping("/admin/aaaaaa")
+public class ExportScheduler {
+
+    private final CommonInfoService commonInfoService;
+    private final RedissonClient redissonClient;
+    private final RedisTemplate redisTemplate;
+    private final ExportJobService exportJobService;
+    private final AppOrderService appOrderService;
+    private final RechargeRecordService rechargeRecordService;
+    private final SftpUtil sftpUtil;
+
+
+    /**
+     * 将所有超过失效时间的优惠券改为失效状态
+     * 每分钟运行一次
+     */
+    @Async
+    @Scheduled(cron = "18 */1 * * * ?", zone = "Asia/Shanghai")
+//    @GetMapping("excelOrder")
+    public void orderExport() throws Exception {
+        List<ExportJob> exportJobList=exportJobService.list(new QueryWrapper<ExportJob>()
+                .eq("flag",0).last("order by create_time limit 10"));
+        log.info("本次导出数据exportJobList==========="+exportJobList);
+        if (null == exportJobList ||exportJobList.isEmpty()){
+            return;
+        }
+        int runningCount =exportJobService.count(new QueryWrapper<ExportJob>().eq("flag",-1));
+        if (runningCount>=4){
+            //同时执行的任务超过4条,不再新增任务
+            return;
+        }
+        for(ExportJob exportJob:exportJobList){
+            long bgTime = System.currentTimeMillis();
+            String jobExecuteKey = SchedulerLock.EXPORT_LOCK + ":" + exportJob.getExportId();
+            String jobExecuteRedisKey = SchedulerLock.EXPORT_LOCK +":R:" + exportJob.getExportId();
+            RLock lock = redissonClient.getLock(jobExecuteKey);
+            if (lock.tryLock(0, 5, TimeUnit.SECONDS)) {
+                boolean isRedisKey = redisTemplate.hasKey(jobExecuteRedisKey);
+                //rediskey避免重复导出
+                if(isRedisKey){
+                    log.info(exportJob.getExportId()+"已执行,跳过");
+                    continue;
+                }
+                redisTemplate.opsForValue().set(jobExecuteRedisKey, "LOCK", 5, TimeUnit.MINUTES);
+                //设置为执行中
+                exportJob.setFlag(-1);
+                exportJob.setUpdateTime(new Date());
+                exportJobService.updateById(exportJob);
+                String fileName=exportJob.getFileName();
+                String fileType=exportJob.getFileType();
+                InputStream inputStream=null;
+                ByteArrayOutputStream os = new ByteArrayOutputStream();
+                try {
+                    ExcelData excelData=new ExcelData();
+                    if("order".equals(fileType)){
+                        excelData=getOrderExcelData(exportJob);
+                    }else if("recharge".equals(fileType)){
+                        excelData=getRechargeOrderExcelData(exportJob);
+                    }
+                    String value=commonInfoService.findOne(430).getValue();
+                    ExportExcelUtils.writeExcel2(os,fileName,excelData);
+                    byte[] buffer = os.toByteArray();
+                    inputStream = new ByteArrayInputStream(buffer);
+                    double fileSize = os.size();
+                    double fileSizeKB = new BigDecimal(fileSize/1024).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); //转换单位为KB
+                    exportJob.setFileSize(String.valueOf(fileSizeKB));
+                    exportJob.setFlag(1);
+                    exportJob.setUpdateTime(new Date());
+                    sftpUtil.login();
+                    sftpUtil.upload(value,fileName,inputStream);
+                    exportJobService.updateById(exportJob);
+                } catch (Exception e) {
+                    exportJob.setUpdateTime(new Date());
+                    exportJob.setFlag(2);
+                    exportJobService.updateById(exportJob);
+                    log.error(e.toString());
+                } finally {
+                    try {
+                        if (lock.isLocked()) {
+                            lock.unlock();
+                        }
+                        if(os!=null){
+                            os.close();
+                        }
+                        if(inputStream!=null){
+                            inputStream.close();
+                        }
+                        if(sftpUtil.isConnected()){
+                            sftpUtil.logout();
+                        }
+                    } catch (RuntimeException re) {
+                        log.error("报表解锁失败");
+                    }
+                }
+            }
+            long edTime = System.currentTimeMillis();
+            log.info("执行:通用数据导出定时任务"+exportJob.getExportId()+"......执行任务完成,执行时长:{} s", (edTime - bgTime) / 1000);
+        }
+    }
+    //订单导出
+    private ExcelData getOrderExcelData(ExportJob exportJob){
+        String[] conditions=exportJob.getConditions().split(",",-1);
+        Integer status=null;
+        if(!"".equals(conditions[1])){
+            status= Integer.valueOf(conditions[1]);
+        }
+        String phone=conditions[2];
+        Long shopId=null;
+        if(!"".equals(conditions[3])){
+            shopId= Long.valueOf(conditions[3]);
+        }
+        String userName=conditions[4];
+        String orderNumber=conditions[5];
+
+        Integer orderType=null;
+        if(!"".equals(conditions[6])){
+            orderType= Integer.valueOf(conditions[6]);
+        }
+        String shopName=conditions[7];
+        String riderPhone=conditions[8];
+        String startTime=conditions[9];
+        String endTime=conditions[10];
+        String payStartTime=conditions[11];
+        String payEndTime=conditions[12];
+        ExcelData excelData = appOrderService.excelAllOrderAdmin(status, phone, shopId, userName, orderNumber, orderType, shopName, riderPhone, startTime, endTime,payStartTime,payEndTime);
+
+        return excelData;
+    }
+
+    //充值记录导出
+    private ExcelData getRechargeOrderExcelData(ExportJob exportJob){
+        String[] conditions=exportJob.getConditions().split(",",-1);
+        String rechargeOrder=conditions[1];
+        String acount=conditions[2];
+        QueryWrapper qw=new QueryWrapper<RechargeRecord>();
+        if(StringUtils.hasText(rechargeOrder)){
+            qw.eq("order_no",rechargeOrder);
+        }
+        if(StringUtils.hasText(acount)){
+            qw.eq("user_phone",acount);
+        }
+        ExcelData data = new ExcelData();
+        data.setName("订单列表");
+        List<String> titles = new ArrayList();
+        titles.add("用户id");titles.add("编号");titles.add("充值金额");titles.add("充值前余额");
+        titles.add("充值后余额"); titles.add("被充值账号(手机号)");titles.add("被充值名称");titles.add("被充值昵称");
+        titles.add("被充值头像"); titles.add("更新时间");titles.add("充值时间");titles.add("充值人账号");
+        titles.add("备注");
+        data.setTitles(titles);
+        List<RechargeRecord> recordList=rechargeRecordService.list(qw);
+        List<List<Object>> rows = new ArrayList();
+        for (RechargeRecord record:recordList){
+            List<Object> row = new ArrayList();
+            row.add(record.getUserId());
+            row.add(record.getOrderNo());
+            row.add(record.getAmount());
+            row.add(record.getOldMoney());
+            row.add(record.getBalance());
+            row.add(record.getUserPhone());
+            row.add(record.getUserName());
+            row.add(record.getUserNick());
+            row.add(record.getUserAvatar());
+            row.add(record.getUpdateTime());
+            row.add(record.getCreateTime());
+            row.add(record.getAccount());
+            row.add(record.getRemark());
+            rows.add(row);
+        }
+        data.setRows(rows);
+        return data;
+    }
+}

+ 41 - 0
src/main/resources/application-dev.yml

@@ -3,8 +3,10 @@ spring:
         type: com.alibaba.druid.pool.DruidDataSource
         type: com.alibaba.druid.pool.DruidDataSource
         druid:
         druid:
             driver-class-name: com.mysql.cj.jdbc.Driver
             driver-class-name: com.mysql.cj.jdbc.Driver
+#            url: jdbc:mysql://172.16.20.104:3306/tcwm2.5?useUnicode=true&characterEncoding=utf-8&useSSL=false&rewriteBatchedStatements=true&serverTimezone=CTT
             url: jdbc:mysql://172.16.20.108:3306/tcwm2.5?useUnicode=true&characterEncoding=utf-8&useSSL=false&rewriteBatchedStatements=true&serverTimezone=CTT
             url: jdbc:mysql://172.16.20.108:3306/tcwm2.5?useUnicode=true&characterEncoding=utf-8&useSSL=false&rewriteBatchedStatements=true&serverTimezone=CTT
             username: root
             username: root
+#            password: ch@2025.wm
             password: chuanghai@2024
             password: chuanghai@2024
             initial-size: 15
             initial-size: 15
             max-active: 100
             max-active: 100
@@ -108,3 +110,42 @@ secure-api:
 
 
 mp:
 mp:
     temp: true
     temp: true
+sftp:
+    username: export
+    password: Waimai2024#
+    host: 172.16.20.108
+    port: 22
+
+dynamic:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://172.16.20.104:3306/tcwm2.5?useUnicode=true&characterEncoding=utf-8&useSSL=false&rewriteBatchedStatements=true&serverTimezone=CTT
+#    url: jdbc:mysql://172.16.20.108:3306/tcwm2.5?useUnicode=true&characterEncoding=utf-8&useSSL=false&rewriteBatchedStatements=true&serverTimezone=CTT
+    username: root
+    password: ch@2025.wm
+#    password: chuanghai@2024
+    initial-size: 15
+    max-active: 100
+    min-idle: 10
+    max-wait: 60000
+    pool-prepared-statements: true
+    max-pool-prepared-statement-per-connection-size: 20
+    time-between-eviction-runs-millis: 60000
+    min-evictable-idle-time-millis: 300000
+    #Oracle需要打开注释
+    #validation-query: SELECT 1 FROM DUAL
+    test-while-idle: true
+    test-on-borrow: false
+    test-on-return: false
+    stat-view-servlet:
+        enabled: true
+        url-pattern: /druid/*
+        #login-username: admin
+        #login-password: admin
+    filter:
+        stat:
+            log-slow-sql: true
+            slow-sql-millis: 1000
+            merge-sql: false
+        wall:
+            config:
+                multi-statement-allow: true

+ 39 - 0
src/main/resources/application-prod.yml

@@ -109,3 +109,42 @@ secure-api:
 
 
 mp:
 mp:
     temp: false
     temp: false
+sftp:
+    username: export
+    password: Waimai2024#
+    host: 172.16.20.105
+    port: 22
+#查询备用数据库
+dynamic:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://172.16.20.104:3306/tcwm2.5?useUnicode=true&characterEncoding=utf-8&useSSL=false&rewriteBatchedStatements=true&serverTimezone=CTT
+    #    url: jdbc:mysql://172.16.20.108:3306/tcwm2.5?useUnicode=true&characterEncoding=utf-8&useSSL=false&rewriteBatchedStatements=true&serverTimezone=CTT
+    username: root
+    password: ch@2025.wm
+    #    password: chuanghai@2024
+    initial-size: 15
+    max-active: 100
+    min-idle: 10
+    max-wait: 60000
+    pool-prepared-statements: true
+    max-pool-prepared-statement-per-connection-size: 20
+    time-between-eviction-runs-millis: 60000
+    min-evictable-idle-time-millis: 300000
+    #Oracle需要打开注释
+    #validation-query: SELECT 1 FROM DUAL
+    test-while-idle: true
+    test-on-borrow: false
+    test-on-return: false
+    stat-view-servlet:
+        enabled: true
+        url-pattern: /druid/*
+        #login-username: admin
+        #login-password: admin
+    filter:
+        stat:
+            log-slow-sql: true
+            slow-sql-millis: 1000
+            merge-sql: false
+        wall:
+            config:
+                multi-statement-allow: true

+ 58 - 1
src/main/resources/mapper/order/OrderMapper.xml

@@ -149,7 +149,7 @@
         shopPhone,
         shopPhone,
         tiu.nick_name as riderNickName,tiu.phone as riderPhone,ti.indent_id as indentId,ti.is_rider as isRider,
         tiu.nick_name as riderNickName,tiu.phone as riderPhone,ti.indent_id as indentId,ti.is_rider as isRider,
         ti.rider_user_id as riderUserId, tcu.money as couponMoney,
         ti.rider_user_id as riderUserId, tcu.money as couponMoney,
-        apr.discount_amount as activityDiscountAmount, ai.title activityTitle
+        apr.discount_amount as activityDiscountAmount, ai.title activityTitle,ogg.detail,ogg.sumPrice
         from tb_order tor
         from tb_order tor
         left join tb_user tu on tor.user_id = tu.user_id
         left join tb_user tu on tor.user_id = tu.user_id
         left join goods_shop gs on tor.shop_id = gs.shop_id
         left join goods_shop gs on tor.shop_id = gs.shop_id
@@ -158,6 +158,57 @@
         left join tb_coupon_user tcu on tor.coupon_id = tcu.id
         left join tb_coupon_user tcu on tor.coupon_id = tcu.id
         left join activity_part_record apr on apr.order_id = tor.order_id
         left join activity_part_record apr on apr.order_id = tor.order_id
         left join activity ai on ai.id = apr.activity_id
         left join activity ai on ai.id = apr.activity_id
+        left join (  select @a:=0,order_id ,group_concat(@a:=@a+1,".商品名:",goods_name,",数量:",goods_num,",规格:",sku_message) detail,sum(goods_num*goods_price) sumPrice  from order_goods og group by order_id
+        ) ogg on ogg.order_id =tor.order_id
+        where 1 = 1
+        <if test="riderPhone!=null and riderPhone!=''">
+            and tiu.phone =#{riderPhone}
+        </if>
+        <if test="shopName!=null and shopName!=''">
+            and gs.shop_name like concat('%',#{shopName},'%')
+        </if>
+        <if test="userName!=null and userName!=''">
+            and tor.user_name like concat('%',#{userName},'%')
+        </if>
+        <if test="phone!=null and phone!=''">
+            and tor.phone like concat('%',#{phone},'%')
+        </if>
+        <if test="orderNumber!=null and orderNumber!=''">
+            and tor.order_number = #{orderNumber}
+        </if>
+        <if test="status!=null and status!=-1 and status!=1">
+            and tor.status = #{status}
+        </if>
+        <if test="status!=null and status==1">
+            and tor.status in (1,2)
+        </if>
+        <if test="shopId!=null">
+            and tor.shop_id = #{shopId}
+        </if>
+        <if test="orderType!=null">
+            and tor.order_type = #{orderType}
+        </if>
+        <if test="startTime!=null and startTime!=''">
+            and date_format(tor.create_time,'%Y-%m-%d') >= date_format(#{startTime},'%Y-%m-%d')
+        </if>
+        <if test="endTime!=null and endTime!='' ">
+            and date_format(tor.create_time,'%Y-%m-%d') &lt;= date_format(#{endTime},'%Y-%m-%d')
+        </if>
+        <if test="payStartTime != null and payStartTime != ''">
+            and date_format(tor.pay_time,'%Y-%m-%d') >= date_format(#{payStartTime},'%Y-%m-%d')
+        </if>
+        <if test="payEndTime != null and payEndTime != '' ">
+            and date_format(tor.pay_time,'%Y-%m-%d') &lt;= date_format(#{payEndTime},'%Y-%m-%d')
+        </if>
+        order by tor.pay_time desc, tor.create_time desc
+    </select>
+
+    <select id="excelAllOrderAdminCount" resultType="java.lang.Integer">
+        select count(1) from tb_order tor
+        left join tb_user tu on tor.user_id = tu.user_id
+        left join goods_shop gs on tor.shop_id = gs.shop_id
+        left join tb_indent ti on tor.order_id = ti.order_id
+        left join tb_user tiu on tiu.user_id = ti.rider_user_id
         where 1 = 1
         where 1 = 1
         <if test="riderPhone!=null and riderPhone!=''">
         <if test="riderPhone!=null and riderPhone!=''">
             and tiu.phone =#{riderPhone}
             and tiu.phone =#{riderPhone}
@@ -192,6 +243,12 @@
         <if test="endTime!=null and endTime!='' ">
         <if test="endTime!=null and endTime!='' ">
             and date_format(tor.create_time,'%Y-%m-%d') &lt;= date_format(#{endTime},'%Y-%m-%d')
             and date_format(tor.create_time,'%Y-%m-%d') &lt;= date_format(#{endTime},'%Y-%m-%d')
         </if>
         </if>
+        <if test="payStartTime != null and payStartTime != ''">
+            and date_format(tor.pay_time,'%Y-%m-%d') >= date_format(#{payStartTime},'%Y-%m-%d')
+        </if>
+        <if test="payEndTime != null and payEndTime != '' ">
+            and date_format(tor.pay_time,'%Y-%m-%d') &lt;= date_format(#{payEndTime},'%Y-%m-%d')
+        </if>
         order by tor.pay_time desc, tor.create_time desc
         order by tor.pay_time desc, tor.create_time desc
     </select>
     </select>