Jelajahi Sumber

库存后端提交

Gogs 2 bulan lalu
induk
melakukan
f3ee60ea12

+ 3 - 2
dtm-admin/src/main/resources/application-druid.yml

@@ -6,9 +6,10 @@ spring:
         druid:
             # 主库数据源
             master:
-                url: jdbc:mysql://140.143.100.189:3306/dtm?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                url: jdbc:mysql://106.14.194.251:3306/dtm?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
                 username: root
-                password: dtm@1915116
+                password: Dtm@1915116
+              #  password: dtm@1915116
             # 从库数据源
             slave:
                 # 从数据源开关/默认关闭

+ 10 - 1
dtm-admin/src/main/resources/application.yml

@@ -153,4 +153,13 @@ shop:
 # 仓储分析数据目录
 storage:
   data:
-    path: E:/code/sudtm1/dtm2/dtm-storage/data
+    path: ../dtm-storage/data
+
+# Zhipu AI (GLM) configuration
+zhipu:
+  api-key: 00105ddcf726404d98bba234f46965c6.suVDfihhEahnWDFh
+  base-url: https://open.bigmodel.cn/api/paas/v4/chat/completions
+  model: glm-4.7-flash
+  temperature: 0.4
+  max-tokens: 1024
+  timeout-ms: 30000

+ 11 - 0
dtm-storage/src/main/java/com/dtm/storage/service/RiskService.java

@@ -217,6 +217,17 @@ public class RiskService {
         return result;
     }
 
+    public Map<String, Object> getRiskBySku(String sku) {
+        if (sku == null || sku.trim().isEmpty()) {
+            return null;
+        }
+        String target = sku.trim();
+        return ensureScores().stream()
+                .filter(row -> target.equalsIgnoreCase(String.valueOf(row.get("productCode"))))
+                .findFirst()
+                .orElse(null);
+    }
+
     public Map<String, Object> updateRiskSettings(Map<String, Object> payload) {
         StorageSettings.updateRiskWeights(payload);
         invalidateCache();

+ 101 - 10
dtm-storage/src/main/java/com/dtm/storage/service/StorageDataLoader.java

@@ -37,17 +37,26 @@ import java.util.stream.Stream;
 @Service
 public class StorageDataLoader {
     private static final long CACHE_EXPIRE_MILLIS = 300_000;
+    private static final long TEMP_CACHE_EXPIRE_MILLIS = 120_000;
+    private static final long TEMP_DATA_TTL_MILLIS = 30 * 60 * 1000;
+    private static final int TEMP_MAX_ROWS = 200_000;
 
     @Value("${storage.data.path:}")
     private String storageDataPath;
 
     private Path basePath;
+    private Path defaultBasePath;
+    private Path tempBasePath;
+    private volatile long tempExpireAt;
+    private volatile boolean tempMode;
 
     private final ConcurrentMap<String, CacheEntry<?>> cache = new ConcurrentHashMap<>();
+    private final ConcurrentMap<String, Object> cacheLocks = new ConcurrentHashMap<>();
 
     @PostConstruct
     public void init() {
-        this.basePath = resolveBasePath();
+        this.defaultBasePath = resolveBasePath();
+        this.basePath = defaultBasePath;
         System.out.println("StorageDataLoader basePath: " + (basePath == null ? "<null>" : basePath.toAbsolutePath()));
         warmUp();
     }
@@ -93,6 +102,43 @@ public class StorageDataLoader {
         cache.clear();
     }
 
+    public synchronized void useTemporaryBasePath(Path path) {
+        if (path == null) {
+            return;
+        }
+        this.tempBasePath = path;
+        this.tempMode = true;
+        this.tempExpireAt = System.currentTimeMillis() + TEMP_DATA_TTL_MILLIS;
+        this.basePath = path;
+        clearCache();
+    }
+
+    public synchronized void resetBasePath() {
+        this.tempMode = false;
+        this.tempExpireAt = 0L;
+        this.tempBasePath = null;
+        this.basePath = defaultBasePath;
+        clearCache();
+    }
+
+    public synchronized Path resolveWritableBasePath() {
+        ensureTempValid();
+        if (basePath == null) {
+            basePath = resolveBasePath();
+            if (defaultBasePath == null) {
+                defaultBasePath = basePath;
+            }
+        }
+        if (basePath != null && !Files.exists(basePath)) {
+            try {
+                Files.createDirectories(basePath);
+            } catch (Exception e) {
+                System.out.println("StorageDataLoader create basePath failed: " + e.getMessage());
+            }
+        }
+        return basePath;
+    }
+
     private List<PurchaseRecord> loadPurchaseRecords() {
         ExcelSheet sheet = loadPurchaseSheet();
         if (sheet.getRows().isEmpty()) {
@@ -217,7 +263,7 @@ public class StorageDataLoader {
         if (file == null) {
             return new ExcelSheet(Collections.emptyList(), Collections.emptyList());
         }
-        return ExcelUtils.readSheet(file, 0);
+        return readSheet(file, 0);
     }
 
     private ExcelSheet loadPurchaseSheet() {
@@ -225,7 +271,7 @@ public class StorageDataLoader {
         if (file == null) {
             return new ExcelSheet(Collections.emptyList(), Collections.emptyList());
         }
-        return ExcelUtils.readSheet(file, 0);
+        return readSheet(file, 0);
     }
 
     private ExcelSheet loadSalesSheet() {
@@ -233,7 +279,7 @@ public class StorageDataLoader {
         if (file == null) {
             return new ExcelSheet(Collections.emptyList(), Collections.emptyList());
         }
-        return ExcelUtils.readSheet(file, 0);
+        return readSheet(file, 0);
     }
 
     private ExcelSheet loadAssemblySheet() {
@@ -241,7 +287,7 @@ public class StorageDataLoader {
         if (file == null) {
             return new ExcelSheet(Collections.emptyList(), Collections.emptyList());
         }
-        return ExcelUtils.readSheet(file, 1);
+        return readSheet(file, 1);
     }
 
     private ExcelSheet loadProductInfoSheet() {
@@ -249,7 +295,14 @@ public class StorageDataLoader {
         if (file == null) {
             return new ExcelSheet(Collections.emptyList(), Collections.emptyList());
         }
-        return ExcelUtils.readSheet(file, 0);
+        return readSheet(file, 0);
+    }
+
+    private ExcelSheet readSheet(Path file, int headerRowIndex) {
+        if (tempMode) {
+            return ExcelUtils.readSheet(file, headerRowIndex, TEMP_MAX_ROWS);
+        }
+        return ExcelUtils.readSheet(file, headerRowIndex);
     }
 
     private Path resolveBasePath() {
@@ -314,6 +367,7 @@ public class StorageDataLoader {
     }
 
     private Path resolveDir(String dirName) {
+        ensureTempValid();
         if (basePath == null) {
             return null;
         }
@@ -324,6 +378,34 @@ public class StorageDataLoader {
         return basePath;
     }
 
+    private synchronized void ensureTempValid() {
+        if (!tempMode) {
+            return;
+        }
+        if (tempExpireAt > 0 && System.currentTimeMillis() > tempExpireAt) {
+            Path toDelete = tempBasePath;
+            resetBasePath();
+            if (toDelete != null) {
+                deleteDirectory(toDelete);
+            }
+        }
+    }
+
+    private void deleteDirectory(Path dir) {
+        if (dir == null || !Files.exists(dir)) {
+            return;
+        }
+        try (Stream<Path> walk = Files.walk(dir)) {
+            walk.sorted(Comparator.reverseOrder()).forEach(path -> {
+                try {
+                    Files.deleteIfExists(path);
+                } catch (Exception ignored) {
+                }
+            });
+        } catch (Exception ignored) {
+        }
+    }
+
     private Path findFile(Path dir, String... keywords) {
         if (dir == null || !Files.exists(dir)) {
             return null;
@@ -459,12 +541,21 @@ public class StorageDataLoader {
     private <T> T getCached(String key, Supplier<T> supplier) {
         CacheEntry<T> entry = (CacheEntry<T>) cache.get(key);
         long now = System.currentTimeMillis();
-        if (entry != null && now - entry.timestamp < CACHE_EXPIRE_MILLIS) {
+        long ttl = tempMode ? TEMP_CACHE_EXPIRE_MILLIS : CACHE_EXPIRE_MILLIS;
+        if (entry != null && now - entry.timestamp < ttl) {
             return entry.value;
         }
-        T value = supplier.get();
-        cache.put(key, new CacheEntry<>(value, now));
-        return value;
+        Object lock = cacheLocks.computeIfAbsent(key, k -> new Object());
+        synchronized (lock) {
+            CacheEntry<T> recheck = (CacheEntry<T>) cache.get(key);
+            long nowCheck = System.currentTimeMillis();
+            if (recheck != null && nowCheck - recheck.timestamp < ttl) {
+                return recheck.value;
+            }
+            T value = supplier.get();
+            cache.put(key, new CacheEntry<>(value, nowCheck));
+            return value;
+        }
     }
 
     private static class CacheEntry<T> {

+ 7 - 0
dtm-storage/src/main/java/com/dtm/storage/util/ExcelUtils.java

@@ -22,6 +22,10 @@ public final class ExcelUtils {
     }
 
     public static ExcelSheet readSheet(Path filePath, int headerRowIndex) {
+        return readSheet(filePath, headerRowIndex, -1);
+    }
+
+    public static ExcelSheet readSheet(Path filePath, int headerRowIndex, int maxRows) {
         if (filePath == null || !Files.exists(filePath)) {
             return new ExcelSheet(new ArrayList<>(), new ArrayList<>());
         }
@@ -55,6 +59,9 @@ public final class ExcelUtils {
             }
 
             for (int r = headerRowIndex + 1; r <= sheet.getLastRowNum(); r++) {
+                if (maxRows > 0 && rows.size() >= maxRows) {
+                    break;
+                }
                 Row row = sheet.getRow(r);
                 if (row == null) {
                     continue;