浏览代码

Merge remote-tracking branch 'origin/test-merge' into test-merge

LHB 5 天之前
父节点
当前提交
e3580070ff

+ 177 - 10
blade-service/blade-archive/src/main/java/org/springblade/archive/utils/ImageQualityDetectorUtils.java

@@ -18,27 +18,27 @@ import org.bytedeco.opencv.opencv_core.*;
 import static org.bytedeco.opencv.global.opencv_core.*;
 
 import java.awt.image.BufferedImage;
-import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
-import java.nio.file.Files;
-import java.nio.file.Paths;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import static org.bytedeco.opencv.global.opencv_imgcodecs.imwrite;
 import static org.bytedeco.opencv.global.opencv_imgproc.*;
 
 /**
  * 简单检测图片质量
  */
 public class ImageQualityDetectorUtils {
+    private static boolean isDebug = false;
+    private static final String DEBUG_OUT_PATH = "/mnt/sdc/Users/hongchuangyanfa/Desktop/debug/";
 
 //    public static void main(String[] args) throws IOException {
 //        try (InputStream is = Files.newInputStream(Paths.get("C:\\Users\\泓创02\\Downloads\\test1.pdf"));) {
 ////            List<Map<String, Object>> mapList = evaluatePdfPages(is, 96);
 ////            System.out.println(mapList);
+//            isDebug = true;
 //            Map<String, Object> map = checkImageQuality(is, 96);
 //            System.out.println(map);
 //        }
@@ -59,9 +59,9 @@ public class ImageQualityDetectorUtils {
                 if (dpi > 0 && !(checkDPI = engine.checkDpiForImages(dpi, 5))) {
                     break;
                 }
-                if (engine.hasNonImagePainting) {
-                    break;
-                }
+//                if (engine.hasNonImagePainting) {
+//                    break;
+//                }
                 for (BufferedImage bi : engine.images) {
                     Frame f = converter1.convert(bi);
                     Mat img = converter2.convert(f);
@@ -69,7 +69,12 @@ public class ImageQualityDetectorUtils {
                         result.put("message", "无法加载图像");
                         return result;
                     }
-                    boolean stains = detectLargeStains(img);
+                    boolean stains;
+                    if (isDebug) {
+                        stains = detectLargeStainsOfDebug(img);
+                    } else {
+                        stains = detectLargeStains(img);
+                    }
 //                    boolean blurry = isBlurry(img);
 //                    boolean shadows = detectShadows(img);
 //                    boolean exposureBad = isExposureBad(img);
@@ -298,6 +303,10 @@ public class ImageQualityDetectorUtils {
                     }
                     long dpiX = Math.round(imageWidth / renderedWidthInInches);
                     long dpiY = Math.round(imageHeight / renderedHeightInInches);
+                    if (isDebug) {
+                        System.out.printf("图片DPI: %d x %d, 渲染尺寸: %.2f\" x %.2f\"%n",
+                            dpiX, dpiY, renderedWidthInInches, renderedHeightInInches);
+                    }
                     if (dpiX < requiredDpi - tolerance || dpiY < requiredDpi - tolerance) {
                         allOk.set(false);
                     }
@@ -429,12 +438,87 @@ public class ImageQualityDetectorUtils {
         return false;
     }
 
+    /**
+     * 检查轮廓是否为规则形状( 基于凸包的检测)
+     * @param contour 轮廓
+     * @return 是否为规则形状
+     */
     private static boolean isRegularShape(Mat contour) {
         // 检查轮廓是否为规则形状
         double perimeter = arcLength(contour, true);
+        Mat approx = new Mat();
+        // todo 基于perimeter长度决定 scaleFactor 的大小, epsilon 越小,则越精确
+        double scaleFactor = 0.015;
+        approxPolyDP(contour, approx, scaleFactor * perimeter, true);
+
+        // 计算凸包
+        Mat hull = new Mat();
+        convexHull(contour, hull);
+        double hullArea = contourArea(hull);
+        double contourArea = contourArea(contour);
+
+        // 计算凸度(solidity)
+        double solidity = contourArea / hullArea;
+
+        // 计算边界矩形相关特征
+        Rect boundingRect = boundingRect(contour);
+        double rectArea = boundingRect.width() * boundingRect.height();
+        double extent = contourArea / rectArea;
+
+        if (isDebug) {
+            System.out.println("Approx points: " + approx.rows());
+            System.out.println("Solidity: " + solidity);
+            System.out.println("Extent: " + extent);
+        }
+
+        // 更严格的规则形状判定
+        boolean simplePolygon = approx.rows() <= 4;
+        boolean highSolidity = solidity > 0.8;  // 凸度高表示形状规整
+        boolean highExtent = extent > 0.7;      // 与边界矩形重合度高
+
+        return simplePolygon || (highSolidity && highExtent);
+    }
+
+    /**
+     * 检查轮廓是否为规则形状(结合多种几何特征)
+     * @param contour 轮廓
+     * @return 是否为规则形状
+     */
+    private static boolean isRegularShape1(Mat contour) {
+        // 检查轮廓是否为规则形状
+        double perimeter = arcLength(contour, true);
+        if (perimeter == 0) return false;
+
         Mat approx = new Mat();
         approxPolyDP(contour, approx, 0.02 * perimeter, true);
-        return approx.rows() <= 4; // 简单多边形可能是背景
+
+        // 计算面积和边界矩形
+        double area = contourArea(contour);
+        Rect boundingRect = boundingRect(contour);
+        double rectArea = boundingRect.width() * boundingRect.height();
+        double areaRatio = area / rectArea;
+
+        // 计算长宽比
+        double aspectRatio = (double) boundingRect.width() / boundingRect.height();
+        if (aspectRatio < 1) aspectRatio = 1 / aspectRatio;
+
+        // 检查是否接近圆形(通过周长和面积的关系)
+        double circularity = 4 * Math.PI * area / (perimeter * perimeter);
+
+        if (isDebug) {
+            System.out.println("Approx points: " + approx.rows());
+            System.out.println("Area ratio: " + areaRatio);
+            System.out.println("Aspect ratio: " + aspectRatio);
+            System.out.println("Circularity: " + circularity);
+        }
+
+        // 综合判断:顶点少、面积比高、长宽比合理、接近圆形之一即可判定为规则形状
+        boolean isPolygon = approx.rows() <= 6;
+        boolean isRectangular = areaRatio > 0.7;
+        boolean isProportional = aspectRatio < 3.0;
+        boolean isCircular = circularity > 0.7;
+
+        return isPolygon || isRectangular || isCircular || isProportional;
     }
 
     private static boolean hasSignificantColorVariation(Mat image, Mat contour) {
@@ -449,9 +533,20 @@ public class ImageQualityDetectorUtils {
 
         // 获取标准差值
         double stdDev0 = stdDev.ptr(0).get(0);
+        if (stdDev0 < 0) {
+            stdDev0 = -stdDev0;
+        }
         double stdDev1 = stdDev.ptr(1).get(0);
+        if (stdDev1 < 0) {
+            stdDev1 = -stdDev1;
+        }
         double stdDev2 = stdDev.ptr(2).get(0);
-
+        if (stdDev2 < 0) {
+            stdDev2 = -stdDev2;
+        }
+        if (isDebug) {
+             System.out.println("Color std dev: H=" + stdDev0 + ", S=" + stdDev1 + ", V=" + stdDev2);
+        }
         // 如果颜色变化较小,则可能是统一的背景色
         return stdDev0 > 15 || stdDev1 > 15 || stdDev2 > 15;
 
@@ -539,4 +634,76 @@ public class ImageQualityDetectorUtils {
         return shadowRatio > 0.1;
     }
 
+    public static boolean detectLargeStainsOfDebug(Mat image) {
+        // 创建用于调试的图像副本
+        Mat debugImage = image.clone();
+
+        // 转换为灰度图
+        Mat gray = new Mat();
+        cvtColor(image, gray, COLOR_BGR2GRAY);
+
+        // 应用阈值处理,突出污渍区域
+        Mat thresh = new Mat();
+        threshold(gray, thresh, 0, 255, THRESH_BINARY_INV + THRESH_OTSU);
+
+        // 形态学操作去除噪声
+        Mat kernel = getStructuringElement(MORPH_ELLIPSE, new Size(5, 5));
+        morphologyEx(thresh, thresh, MORPH_OPEN, kernel);
+
+        // 查找轮廓
+        MatVector contours = new MatVector();
+        findContours(thresh, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
+
+        // 检查是否有大面积的污渍
+        double imageArea = image.rows() * image.cols();
+        boolean foundStain = false;
+
+        for (int i = 0; i < contours.size(); i++) {
+            Mat contour = contours.get(i);
+            double area = contourArea(contour);
+
+            // 在调试图像上绘制所有检测到的轮廓
+            Scalar color = new Scalar(0, 255, 0, 0); // 默认绿色
+            if (area > imageArea * 0.05) {
+                color = new Scalar(255, 0, 0, 0); // 大面积区域用蓝色标记
+            }
+            drawContours(debugImage, new MatVector(contour), -1, color, 2, LINE_8, null, 0, null);
+
+            // 如果污渍面积超过图像面积的5%
+            if (area > imageArea * 0.05) {
+                // 增加额外条件:排除规则形状(可能是背景)
+                boolean regularShape = isRegularShape(contour);
+                boolean significantColorVar = hasSignificantColorVariation(image, contour);
+
+                // 在图像上添加文本标注
+                Point textPoint = new Point(10, 30 + i*20);
+                String label = String.format("Area:%.0f(%.1f%%) Reg:%b Col:%b",
+                        area, (area/imageArea)*100, regularShape, significantColorVar);
+                putText(debugImage, label, textPoint, FONT_HERSHEY_SIMPLEX, 0.5,
+                        new Scalar(0, 0, 255, 0), 1, LINE_AA, false);
+
+                if (!regularShape && significantColorVar) {
+                    foundStain = true;
+                    // 用红色标记最终判定为污渍的区域
+                    drawContours(debugImage, new MatVector(contour), -1, new Scalar(0, 0, 255, 0), 3, LINE_8, null, 0, null);
+                }
+            }
+        }
+
+        // 保存调试图像
+        saveDebugImage(debugImage, DEBUG_OUT_PATH + System.nanoTime() + ".jpg");
+
+        return foundStain;
+    }
+
+    // 添加辅助方法保存调试图像
+    private static void saveDebugImage(Mat image, String filename) {
+        try {
+            // 保存图像到文件
+            imwrite(filename, image);
+            System.out.println("Debug image saved: " + filename);
+        } catch (Exception e) {
+            System.err.println("Failed to save debug image: " + e.getMessage());
+        }
+    }
 }

+ 6 - 6
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ExcelTabController.java

@@ -5294,7 +5294,7 @@ public class ExcelTabController extends BladeController {
         return R.data(query);
     }
 
-    //@Scheduled(cron = "0 00 02 * * ?")
+    @Scheduled(cron = "0 0 1 ? * SAT")
     @GetMapping("/checkAllNodeDate")
     public void checkAllNodeDate() throws Exception {
         String updateSql="update m_wbs_tree_contract set date_is_complete=1 where is_deleted=0 and type=1";
@@ -5312,11 +5312,11 @@ public class ExcelTabController extends BladeController {
             if(parent==null){
                 continue;
             }
-//            String informationSql="select * from u_information_query where wbs_id="+parent.getPKeyId()+" and contract_id="+parent.getContractId()+" and is_deleted=0";
-//            List<InformationQuery> query = jdbcTemplate.query(informationSql, new BeanPropertyRowMapper<>(InformationQuery.class));
-//            if(query.isEmpty()||query.get(0).getStatus()!=0){
-//                continue;
-//            }
+            String informationSql="select * from u_information_query where wbs_id="+parent.getPKeyId()+" and contract_id="+parent.getContractId()+" and is_deleted=0";
+            List<InformationQuery> query = jdbcTemplate.query(informationSql, new BeanPropertyRowMapper<>(InformationQuery.class));
+            if(query.isEmpty()){
+                continue;
+            }
             List<WbsTreeContract> wbsTreeContractList = entry.getValue();
             boolean flag=true;
             for (WbsTreeContract contract : wbsTreeContractList) {

+ 7 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ContractInfoServiceImpl.java

@@ -1251,6 +1251,13 @@ public class ContractInfoServiceImpl extends BaseServiceImpl<ContractInfoMapper,
     @Override
     public ContractInfoVO2 selectByCondition(ContractInfo contractInfo) {
         ContractInfo contractInfo1 = baseMapper.selectById(contractInfo.getId());
+        if(contractInfo1!=null&&StringUtils.isEmpty(contractInfo1.getProjectPlace())){
+            //查询area表里面的数据
+            ProjectContractArea projectContractArea = projectContractAreaMapper.selectOne(Wrappers.<ProjectContractArea>query().lambda().eq(ProjectContractArea::getContractId, contractInfo1.getId()).last("LIMIT 1"));
+            if(projectContractArea!=null){
+                contractInfo1.setProjectPlace(projectContractArea.getProvince()+projectContractArea.getCity()+projectContractArea.getCounty());
+            }
+        }
         ContractInfoVO2 contractInfoVO2 = new ContractInfoVO2();
         contractInfoVO2.setContractInfo(contractInfo1);
         Integer contractType = contractInfo1.getContractType();

+ 17 - 5
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ExcelTabServiceImpl.java

@@ -1423,7 +1423,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
         result.put("tableName", name.length() == 0 ? "" :  name.deleteCharAt(name.length() - 1).toString());
         result.put("elementName", elementName.length() == 0 ? "" : elementName.deleteCharAt(elementName.length() - 1).toString());
         result.put("type", type == 0 ? "计算" : "数据获取");
-        result.put("data", data.length() == 0 ? "" : data.deleteCharAt(data.length() - 1).toString());
+        String sourceData = data.length() == 0 ? "" : data.deleteCharAt(data.length() - 1).toString();
         String resultData = "";
         try {
             resultData = tableInfoList.get(0).getDataMap().get(split1[0]);
@@ -1436,18 +1436,30 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
                         resultData = string.split("_\\^_")[0];
                         String[] split2 = data.toString().split("☆");
                         if (i < split2.length) {
-                            result.put("data", split2[i].split("_\\^_")[0]);
+                            sourceData = split2[i].split("_\\^_")[0];
                         }
                         break;
                     }
                 }
             }
             resultData = resultData.replaceAll("(\" *)","");
-            result.put("data", result.get("data").replaceAll("(\" *)",""));
-            result.put("result", resultData);
         } catch (Exception e) {
-            result.put("result", resultData);
+            log.error("公式计算异常:" + e.getMessage());
         }
+        if (resultData != null) {
+            resultData = resultData.replaceAll("(_\\^_\\d+_\\d+☆?)",",");
+            if (!resultData.isEmpty() && resultData.charAt(resultData.length() - 1) == ',') {
+                resultData = resultData.substring(0, resultData.length() - 1);
+            }
+        }
+        if (sourceData != null) {
+            sourceData = sourceData.replaceAll("(\" *)","").replaceAll("(_\\^_\\d+_\\d+☆?)",",");
+            if (!sourceData.isEmpty() && sourceData.charAt(sourceData.length() - 1) == ',') {
+                sourceData = sourceData.substring(0, sourceData.length() - 1);
+            }
+        }
+        result.put("data", sourceData);
+        result.put("result", resultData);
 
 
         return result;