diff --git a/pom.xml b/pom.xml index b1025d1..5182e6e 100644 --- a/pom.xml +++ b/pom.xml @@ -216,6 +216,12 @@ 1.4 + + org.apache.httpcomponents + httpclient + 4.5.13 + + diff --git a/src/main/java/com/mixi/common/tasks/MiTuExportScheduledTask.java b/src/main/java/com/mixi/common/tasks/MiTuExportScheduledTask.java index 3faea5c..5712d7b 100644 --- a/src/main/java/com/mixi/common/tasks/MiTuExportScheduledTask.java +++ b/src/main/java/com/mixi/common/tasks/MiTuExportScheduledTask.java @@ -6,6 +6,7 @@ import com.mixi.common.utils.CopyUtil; import com.mixi.common.utils.MinioUtil; import com.mixi.mapper.*; import com.mixi.mapper.entity.*; +import org.apache.commons.compress.utils.IOUtils; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.commons.fileupload.FileItem; @@ -56,7 +57,7 @@ public class MiTuExportScheduledTask { private MiTuProductSellNumMapper miTuProductSellNumMapper; @PostConstruct public void executeWeeklyHeavyStockReport() { -// customerPurchaseReport(); + customerPurchaseReport(); // NewJoinVIPReport(); // weeklySellThrReport(); // WeeklyHeavyStockReport(); @@ -341,6 +342,24 @@ public class MiTuExportScheduledTask { miTuExportMapper.insert(miTuExport); System.out.println("接口执行完成!"); } + }else { + MiTuExport miTuExport = createMiTuExport("Customer purchase report", "month"); + try { + List transactionData = retrieveTransactionData(); + List userMembers = transactionData.stream().map(TransactionData::getUserMember).collect(Collectors.toList()); + List customerData = retrieveCustomerData(userMembers); + updateCustomerDataWithTransactionData(customerData, transactionData); + String filePath = miTuExport.getExportName()+".xlsx"; + exportToExcelCustomerPurchaseReport(customerData, filePath); + miTuExport.setUrl("mi-tu/export/" + filePath); + miTuExport.setStatus(1); + } catch (Exception e) { + miTuExport.setStatus(0); + e.printStackTrace(); + } finally { + miTuExportMapper.insert(miTuExport); + System.out.println("接口执行完成!"); + } } } @@ -1510,6 +1529,8 @@ public class MiTuExportScheduledTask { public final static String MITU = "mi-tu"; public void exportToExcelCustomerPurchaseReport(List customerDataList, String fileName) throws IOException { + File productFile = getProductFile(fileName); + String currentPath = Paths.get("").toAbsolutePath().toString(); File file = new File(currentPath + "/" + fileName); // 如果文件不存在或者为空,则创建一个新的 Workbook @@ -1530,7 +1551,7 @@ public class MiTuExportScheduledTask { // 获取当前年月 YearMonth currentYearMonth = YearMonth.now(); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM"); - String[] headers = new String[25]; + String[] headers = new String[26]; // 增加一个额外的标题列 headers[0] = "mbrCode"; headers[1] = "mbrName"; headers[2] = "mbrMobile"; @@ -1549,6 +1570,7 @@ public class MiTuExportScheduledTask { for (int i = 0; i < 11; i++) { headers[13 + i] = currentYearMonth.minusMonths(i + 1).format(formatter); } + headers[24] = "productFile"; // 新增的标题列 for (int i = 0; i < headers.length; i++) { Cell cell = headerRow.getCell(i, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK); cell.setCellValue(headers[i]); @@ -1585,7 +1607,26 @@ public class MiTuExportScheduledTask { row.createCell(21).setCellValue(customer.getMonth9()); row.createCell(22).setCellValue(customer.getMonth10()); row.createCell(23).setCellValue(customer.getMonth11()); - row.createCell(24).setCellValue(customer.getMonth12()); + row.createCell(24).setCellValue(""); // 占位符,用于后续插入图片 + } + + // 插入图片 + InputStream inputStream = new FileInputStream(productFile); + byte[] bytes = IOUtils.toByteArray(inputStream); + int pictureIdx = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_JPEG); + inputStream.close(); + + CreationHelper helper = workbook.getCreationHelper(); + Drawing drawing = sheet.createDrawingPatriarch(); + + for (int i = 1; i <= customerDataList.size(); i++) { // 跳过标题行,从第一行开始 + ClientAnchor anchor = helper.createClientAnchor(); + anchor.setCol1(24); // 图片插入的列 + anchor.setRow1(i); // 图片插入的行 + anchor.setCol2(25); // 图片所占的列数 + anchor.setRow2(i + 1); // 图片所占的行数 + + drawing.createPicture(anchor, pictureIdx); } // 将Workbook写入文件 @@ -1599,6 +1640,11 @@ public class MiTuExportScheduledTask { System.out.println("Excel file has been created successfully!"); } + private File getProductFile(String fileName) { + File file = new File("C:\\Users\\10233\\Desktop\\2024 SS NEW\\MKTS27000_0BLK.jpg"); + return file; + } + private static FileItem getMultipartFile(File file, String fieldName) { // 使用 DiskFileItemFactory 创建一个 FileItemFactory FileItemFactory factory = new DiskFileItemFactory(16, null); @@ -1821,6 +1867,10 @@ public class MiTuExportScheduledTask { public Map varianceMap = new HashMap<>(); public Map mostFrequentColorMap = new HashMap<>(); + public Map mostFrequentSizeMap = new HashMap<>(); + public Map mostFrequentSubCatMap = new HashMap<>(); + public Map avePriceMap = new HashMap<>(); + private List getMemberType(List memberCodeList) { List miTuMemberList = new ArrayList<>(); for (String memberCode : memberCodeList) { @@ -1832,6 +1882,10 @@ public class MiTuExportScheduledTask { MiTuMember miTuMember = CopyUtil.copyObject(member, MiTuMember.class); miTuMember.setMbrCode(memberCode); miTuMember.setMemberType(memberType); + miTuMember.setMostFrequentColor(mostFrequentColorMap.get(miTuMember.getMbrCode())); + miTuMember.setMostFrequentSize(mostFrequentSizeMap.get(miTuMember.getMbrCode())); + miTuMember.setMostFrequentSubCat(mostFrequentSubCatMap.get(miTuMember.getMbrCode())); + miTuMember.setAvePrice(avePriceMap.get(miTuMember.getMbrCode())); miTuMemberList.add(miTuMember); } // 计算顾客颜色方差的方差 @@ -1841,7 +1895,6 @@ public class MiTuExportScheduledTask { if (miTuMember.getMemberType() == null) { if (varianceMap.get(miTuMember.getMbrCode()) < overallVariance) { miTuMember.setMemberType("Type D"); - miTuMember.setMostFrequentColor(mostFrequentColorMap.get(miTuMember.getMbrCode())); }else { miTuMember.setMemberType("Type S"); } @@ -1972,6 +2025,10 @@ public class MiTuExportScheduledTask { transaction.setSeason(rs.getString("SEASON")); transaction.setColor(rs.getString("COLOR")); transaction.setSubCat(rs.getString("SUB_CAT")); +// transaction.setCategory(rs.getString("CATEGORY")); + transaction.setSize(rs.getString("SIZE")); + transaction.setNetAmt(rs.getDouble("net_amt")); + transactionList.add(transaction); } @@ -1990,54 +2047,120 @@ public class MiTuExportScheduledTask { private String analysis(List transactionList, String memberCode) { int discountNum = 0; int currentSeasonNum = 0; - int leadingNum = 0; Map colorCountMap = new HashMap<>(); + Map sizeCountMap = new HashMap<>(); + Map subCatCountMap = new HashMap<>(); int totalCount = transactionList.size(); + double totalPrice = 0; - // 统计每种颜色的出现次数 + // 统计每种颜色和尺寸的出现次数 for (Transaction transaction : transactionList) { String color = transaction.getColor(); colorCountMap.put(color, colorCountMap.getOrDefault(color, 0) + 1); + + totalPrice += transaction.getNetAmt(); + + String size = transaction.getSize(); + sizeCountMap.put(size, sizeCountMap.getOrDefault(size, 0) + 1); + + String subCat = transaction.getSubCat(); + subCatCountMap.put(subCat, subCatCountMap.getOrDefault(size, 0) + 1); } - // 计算每种颜色的出现频率 - double mean = (double) totalCount / colorCountMap.size(); - double varianceSum = 0; - String mostFrequentColor = null; - int maxCount = 0; + if (totalCount > 0) { + double avePrice = totalPrice / totalCount; + avePriceMap.put(memberCode, avePrice); + } + + // 计算颜色的方差 + double colorMean = (double) totalCount / colorCountMap.size(); + double colorVarianceSum = 0; + int maxColorCount = 0; for (Map.Entry entry : colorCountMap.entrySet()) { int count = entry.getValue(); - varianceSum += Math.pow(count - mean, 2); - if (count > maxCount) { - maxCount = count; - mostFrequentColor = entry.getKey(); + colorVarianceSum += Math.pow(count - colorMean, 2); + if (count > maxColorCount) { + maxColorCount = count; + } + } + double colorVariance = colorVarianceSum / colorCountMap.size(); + + // 计算尺寸的方差 + double sizeMean = (double) totalCount / sizeCountMap.size(); + double sizeVarianceSum = 0; + int maxSizeCount = 0; + for (Map.Entry entry : sizeCountMap.entrySet()) { + int count = entry.getValue(); + sizeVarianceSum += Math.pow(count - sizeMean, 2); + if (count > maxSizeCount) { + maxSizeCount = count; + } + } + double sizeVariance = sizeVarianceSum / sizeCountMap.size(); + + // 计算SUBCAT的方差 + double subCatMean = (double) totalCount / sizeCountMap.size(); + double subCatVarianceSum = 0; + int maxSubCatCount = 0; + for (Map.Entry entry : sizeCountMap.entrySet()) { + int count = entry.getValue(); + subCatVarianceSum += Math.pow(count - subCatMean, 2); + if (count > maxSubCatCount) { + maxSubCatCount = count; + } + } + double subCatVariance = subCatVarianceSum / subCatCountMap.size(); + + // 获取出现次数最多的颜色 + int finalMaxColorCount = maxColorCount; + List mostFrequentColors = colorCountMap.entrySet().stream() + .filter(entry -> entry.getValue() == finalMaxColorCount) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + String mostFrequentColor = String.join(",", mostFrequentColors); + + // 获取出现次数最多的尺寸 + int finalMaxSizeCount = maxSizeCount; + List mostFrequentSizes = sizeCountMap.entrySet().stream() + .filter(entry -> entry.getValue() == finalMaxSizeCount) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + String size = String.join(",", mostFrequentSizes); + + // 获取出现次数最多的SubCat + int finalMaxSubCatCount = maxSizeCount; + List mostFrequentSubCats = sizeCountMap.entrySet().stream() + .filter(entry -> entry.getValue() == finalMaxSubCatCount) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + String subCat = String.join(",", mostFrequentSubCats); + + // 统计折扣和当季商品数量 + for (Transaction transaction : transactionList) { + if ((transaction.getDiscountPer() != null && transaction.getDiscountPer() >= 20.0) || transaction.getSubCat().equals("TWIN SET")) { + discountNum++; + } + if (transaction.getYear().equals("TE") && transaction.getSeason().equals("A")) { + currentSeasonNum++; } } - // 计算方差 - double variance = varianceSum / colorCountMap.size(); - for (Transaction transaction : transactionList) { - if ((transaction.getDiscountPer() != null && transaction.getDiscountPer() >= 20.0) || transaction.getSubCat().equals("TWIN SET")) { - discountNum ++; - } - if (transaction.getYear().equals("TE") && transaction.getSeason().equals("A")) { - currentSeasonNum ++; - } - } if (discountNum >= transactionList.size() * 0.5) { return "Type C"; } if (currentSeasonNum >= transactionList.size() * 0.7) { return "Type i"; } + + double variance = (colorVariance + sizeVariance + subCatVariance) / 3; varianceMap.put(memberCode, variance); +// varianceMap.put(memberCode, sizeVariance); mostFrequentColorMap.put(memberCode, mostFrequentColor); + mostFrequentSizeMap.put(memberCode, size); + mostFrequentSubCatMap.put(memberCode, subCat); + return null; -// if (variance <= 0.2) { -// return "Type D"; -// } -// return "Type S"; } private List getMemberCode() { diff --git a/src/main/java/com/mixi/common/utils/NasUtil.java b/src/main/java/com/mixi/common/utils/NasUtil.java new file mode 100644 index 0000000..baf69c1 --- /dev/null +++ b/src/main/java/com/mixi/common/utils/NasUtil.java @@ -0,0 +1,132 @@ +package com.mixi.common.utils; + +import org.apache.commons.compress.utils.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContextBuilder; +import org.apache.http.ssl.TrustStrategy; + +import javax.net.ssl.*; +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Base64; + +public class NasUtil { + + private static final String NAS_URL = "https://haymanrccnas.synology.me:7106/volume1/PIC/DP9070.bmp"; + private static final String USERNAME = "your_username"; + private static final String PASSWORD = "your_password"; + + public static void main(String[] args) { + downloadFile(NAS_URL, "downloaded_file"); + } + + public static void downloadFile(String fileURL, String outputFileName) { + CredentialsProvider provider = new BasicCredentialsProvider(); + provider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(USERNAME, PASSWORD)); + + try (CloseableHttpClient httpClient = HttpClients.custom() + .setDefaultCredentialsProvider(provider) + .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { + @Override + public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { + return true; + } + }).build()) + .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) + .build()) { + + HttpGet request = new HttpGet(fileURL); + HttpResponse response = httpClient.execute(request); + + if (response.getStatusLine().getStatusCode() == 200) { + try (InputStream inputStream = response.getEntity().getContent(); + FileOutputStream fileOutputStream = new FileOutputStream(outputFileName)) { + + byte[] buffer = new byte[1024]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + fileOutputStream.write(buffer, 0, bytesRead); + } + System.out.println("File downloaded successfully"); + } + } else { + System.err.println("Failed to download file, HTTP status code: " + response.getStatusLine().getStatusCode()); + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static byte[] downloadImage(String imagePath) { + String username = "aiuser"; + String password = "hayNAS-0522"; + String urlString = "https://haymanrccnas.synology.me:7106/" + imagePath; + + try { + // Create a trust manager that does not validate certificate chains + TrustManager[] trustAllCerts = new TrustManager[]{ + new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { + return null; + } + public void checkClientTrusted(X509Certificate[] certs, String authType) { } + public void checkServerTrusted(X509Certificate[] certs, String authType) { } + } + }; + + // Install the all-trusting trust manager + SSLContext sc = SSLContext.getInstance("SSL"); + sc.init(null, trustAllCerts, new java.security.SecureRandom()); + HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); + + // Create all-trusting host name verifier + HostnameVerifier allHostsValid = (hostname, session) -> true; + + // Install the all-trusting host verifier + HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid); + + URL url = new URL(urlString); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + String encoded = Base64.getEncoder().encodeToString((username + ":" + password).getBytes("UTF-8")); + connection.setRequestProperty("Authorization", "Basic " + encoded); + connection.setRequestMethod("GET"); + + try (InputStream inputStream = connection.getInputStream()) { + return IOUtils.toByteArray(inputStream); + } + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + private static void saveImageToLocal(byte[] bytes, String fileName) { + try { + String userHome = System.getProperty("user.home"); + String desktopPath = userHome + File.separator + "Desktop" + File.separator + "Nas"; + Files.createDirectories(Paths.get(desktopPath)); + + String filePath = desktopPath + File.separator + fileName; + try (FileOutputStream fos = new FileOutputStream(filePath)) { + fos.write(bytes); + System.out.println("Image saved to: " + filePath); + } + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/com/mixi/mapper/entity/MiTuMember.java b/src/main/java/com/mixi/mapper/entity/MiTuMember.java index e70c4ab..c095d75 100644 --- a/src/main/java/com/mixi/mapper/entity/MiTuMember.java +++ b/src/main/java/com/mixi/mapper/entity/MiTuMember.java @@ -28,4 +28,7 @@ public class MiTuMember implements Serializable { private Double sumBonus; private String memberType; private String mostFrequentColor; + private String mostFrequentSize; + private String mostFrequentSubCat; + private double avePrice; } diff --git a/src/main/java/com/mixi/model/dto/QueryProductPageDTO.java b/src/main/java/com/mixi/model/dto/QueryProductPageDTO.java index 057ae96..f958fa4 100644 --- a/src/main/java/com/mixi/model/dto/QueryProductPageDTO.java +++ b/src/main/java/com/mixi/model/dto/QueryProductPageDTO.java @@ -37,4 +37,8 @@ public class QueryProductPageDTO extends PageQueryBaseVo implements Serializable @ApiModelProperty("降序排列字段数组 ") private List columnSortList; + private String pluCode; + + private String color; + } diff --git a/src/main/java/com/mixi/service/TProductService.java b/src/main/java/com/mixi/service/TProductService.java index 97250e8..9247b51 100644 --- a/src/main/java/com/mixi/service/TProductService.java +++ b/src/main/java/com/mixi/service/TProductService.java @@ -123,6 +123,20 @@ public class TProductService extends ServiceImpl { return PageBaseResponse.success(new Page<>()); } queryWrapper.in("id", productIdsQuery); + if (!StringUtils.isEmpty(query.getPluCode())) { + QueryWrapper miTuProductQueryWrapper = new QueryWrapper<>(); + miTuProductQueryWrapper.lambda().like(MiTuProduct::getPluCode, query.getPluCode()); + List miTuProductList = miTuProductMapper.selectList(miTuProductQueryWrapper); + List collect = miTuProductList.stream().map(MiTuProduct::getProductId).collect(Collectors.toList()); + queryWrapper.in("id", collect); + } + if (!StringUtils.isEmpty(query.getColor())) { + QueryWrapper miTuProductQueryWrapper = new QueryWrapper<>(); + miTuProductQueryWrapper.lambda().like(MiTuProduct::getColor, query.getColor()); + List miTuProductList = miTuProductMapper.selectList(miTuProductQueryWrapper); + List collect = miTuProductList.stream().map(MiTuProduct::getProductId).collect(Collectors.toList()); + queryWrapper.in("id", collect); + } if (Objects.nonNull(query.getCreateDateStart())) { queryWrapper.ge("create_date", new Date(query.getCreateDateStart())); } @@ -263,7 +277,7 @@ public class TProductService extends ServiceImpl { }else if (!CollectionUtils.isEmpty(productIds3) ){ return productIds3; } - return null; + return new ArrayList<>(); } /** * 导出商品 diff --git a/src/main/java/com/mixi/service/impl/MiTuExportServiceImpl.java b/src/main/java/com/mixi/service/impl/MiTuExportServiceImpl.java index 7acf474..8242814 100644 --- a/src/main/java/com/mixi/service/impl/MiTuExportServiceImpl.java +++ b/src/main/java/com/mixi/service/impl/MiTuExportServiceImpl.java @@ -29,10 +29,7 @@ import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @@ -154,12 +151,36 @@ public class MiTuExportServiceImpl implements MiTuExportService { if (CollectionUtils.isEmpty(miTuMembers)) { return new ArrayList<>(); } + String mostFrequentColor = miTuMembers.get(0).getMostFrequentColor(); + String mostFrequentSize = miTuMembers.get(0).getMostFrequentSize(); + String mostFrequentSubCat = miTuMembers.get(0).getMostFrequentSubCat(); + List colorList = new ArrayList<>(); + if (mostFrequentColor.contains(",")) { + colorList = Arrays.asList(mostFrequentColor.split(",")); + }else { + colorList.add(mostFrequentColor); + } + + List sizeList = new ArrayList<>(); + if (mostFrequentSize.contains(",")) { + sizeList = Arrays.asList(mostFrequentSize.split(",")); + }else { + sizeList.add(mostFrequentSize); + } + + List subCatList = new ArrayList<>(); + if (mostFrequentSubCat.contains(",")) { + subCatList = Arrays.asList(mostFrequentSubCat.split(",")); + }else { + subCatList.add(mostFrequentSubCat); + } + String memberType = miTuMembers.get(0).getMemberType(); switch (memberType) { case "Type D" : { // 根据牌子、款式、颜色推荐 QueryWrapper miTuProductQueryWrapper = new QueryWrapper<>(); - miTuProductQueryWrapper.lambda().like(MiTuProduct::getColor, miTuMembers.get(0).getMostFrequentColor()); + miTuProductQueryWrapper.lambda().in(MiTuProduct::getColor, colorList); List miTuProductList = miTuProductMapper.selectList(miTuProductQueryWrapper); if (CollectionUtils.isEmpty(miTuProductList)) { return new ArrayList<>();