ソースを参照

增加弧焊管理页面

jingbo 5 ヶ月 前
親
コミット
729b26a91f

+ 9 - 0
pom.xml

@@ -210,6 +210,15 @@
 			<artifactId>jSerialComm</artifactId>
 			<version>2.6.2</version>
 		</dependency>
+
+<!--		ORC-->
+		<!-- tess4j -->
+		<dependency>
+			<groupId>net.sourceforge.tess4j</groupId>
+			<artifactId>tess4j</artifactId>
+			<version>4.5.4</version>
+		</dependency>
+
 <!--		<dependency>-->
 <!--			<groupId>com.github.purejavacomm</groupId>-->
 <!--			<artifactId>purejavacomm</artifactId>-->

+ 36 - 0
src/main/java/com/jeesite/modules/mes/service/OcrService.java

@@ -0,0 +1,36 @@
+package com.jeesite.modules.mes.service;
+
+
+import lombok.AllArgsConstructor;
+import net.sourceforge.tess4j.Tesseract;
+import net.sourceforge.tess4j.TesseractException;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+@Service
+@AllArgsConstructor
+public class OcrService {
+
+    private final Tesseract tesseract;
+
+
+    /*
+    * 识别图片中的数据
+    * @param imageFile 图片文件
+    * @ return 识别信息
+    * */
+    public String recognizeText(MultipartFile imageFile) throws TesseractException, IOException {
+        // 转换
+        InputStream sbs = new ByteArrayInputStream(imageFile.getBytes());
+        BufferedImage bufferedImage = ImageIO.read(sbs);
+
+        return tesseract.doOCR(bufferedImage);
+    }
+
+}

+ 7 - 0
src/main/java/com/jeesite/modules/mes/web/MesProductController.java

@@ -1,5 +1,6 @@
 package com.jeesite.modules.mes.web;
 
+import java.io.IOException;
 import java.text.DateFormat;
 import java.text.DecimalFormat;
 import java.text.SimpleDateFormat;
@@ -27,6 +28,8 @@ import com.jeesite.modules.mes.util.CommonUitl;
 import com.jeesite.modules.sys.entity.EmpUser;
 import com.jeesite.modules.sys.service.EmpUserService;
 import com.jeesite.modules.utils.NettyServerHandler;
+import com.jeesite.modules.utils.TesseractOcrConfiguration;
+import net.sourceforge.tess4j.TesseractException;
 import org.apache.poi.ss.formula.functions.T;
 import org.apache.shiro.authz.annotation.RequiresPermissions;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -41,6 +44,8 @@ import org.springframework.web.bind.annotation.ResponseBody;
 import com.jeesite.common.config.Global;
 import com.jeesite.common.entity.Page;
 import com.jeesite.common.web.BaseController;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.multipart.MultipartHttpServletRequest;
 
 /**
  * 产品Controller
@@ -91,6 +96,8 @@ public class MesProductController extends BaseController {
 	private MesDeviceAlarmService mesDeviceAlarmService;
 	@Autowired
 	private MesRepairService mesRepairService;
+	@Autowired
+	private OcrService ocrService;
 
 
 	/**

+ 18 - 0
src/main/java/com/jeesite/modules/mes/web/MesProductRecordController.java

@@ -65,6 +65,7 @@ import com.jeesite.modules.sys.utils.UserUtils;
 import com.jeesite.modules.utils.*;
 import io.netty.buffer.ByteBuf;
 import io.swagger.models.auth.In;
+import net.sourceforge.tess4j.TesseractException;
 import org.apache.commons.csv.CSVFormat;
 import org.apache.commons.csv.CSVPrinter;
 import org.apache.shiro.authz.annotation.RequiresPermissions;
@@ -95,6 +96,7 @@ import com.jeesite.common.config.Global;
 import com.jeesite.common.entity.Page;
 import com.jeesite.common.web.BaseController;
 import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.multipart.MultipartHttpServletRequest;
 
 /**
  * 生产记录Controller
@@ -219,6 +221,8 @@ public class MesProductRecordController extends BaseController {
     private MesProductSampleService mesProductSampleService;
 	@Autowired
 	private MesProductSampleRecordService mesProductSampleRecordService;
+	@Autowired
+	private OcrService ocrService;
 
 
 	/**
@@ -4593,4 +4597,18 @@ public class MesProductRecordController extends BaseController {
 	}
 
 
+	// 识别图片接口
+	@RequestMapping(value = "ocr")
+	@ResponseBody
+	public CommonResp ocr(HttpServletRequest req) throws TesseractException, IOException {
+		CommonResp<String> resp = new CommonResp<>();
+		// 在req中取文件数据
+		MultipartFile imageFile = ((MultipartHttpServletRequest) req).getFile("imageFile");
+		String text = ocrService.recognizeText(imageFile);
+		resp.setData(text);
+		resp.setResult(Global.TRUE);
+		return resp;
+	}
+
+
 }

+ 23 - 0
src/main/java/com/jeesite/modules/utils/TesseractOcrConfiguration.java

@@ -0,0 +1,23 @@
+package com.jeesite.modules.utils;
+
+
+import net.sourceforge.tess4j.Tesseract;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class TesseractOcrConfiguration {
+    @Value("${tess4j.dataPath}")
+    private String dataPath;
+
+
+    @Bean
+    public Tesseract tesseract(){
+        Tesseract tesseract = new Tesseract();
+        tesseract.setDatapath(dataPath);
+        tesseract.setLanguage("chi_sim");
+        return tesseract;
+    }
+
+}

+ 4 - 0
src/main/resources/config/application.yml

@@ -16,6 +16,9 @@ demoMode: false
 # 专为分离端提供接口服务
 apiMode: false
 
+tess4j:
+  datapath: D:/tessdata
+
 #======================================#
 #========== Server settings ===========#
 #======================================#
@@ -698,6 +701,7 @@ shiro:
     ${adminPath}/mes/mesProductRecord/pdaQueryQuality = anon
     ${adminPath}/mes/mesProductRecord/getCurSn= anon
     ${adminPath}/mes/mesProductRecord/cancelCurSn= anon
+    ${adminPath}/mes/mesProductRecord/ocr= anon
     ${adminPath}/** = user
 
 

+ 369 - 0
src/main/resources/views/modules/mes/mesProductArcWeldingInfo.html

@@ -0,0 +1,369 @@
+<% layout('/layouts/default.html', {title: '弧焊过程参数管理', libs: ['validate']}){ %>
+<div class="main-content">
+    <div class="box box-main">
+        <div class="box-header with-border">
+            <div class="box-title">
+                <i class="fa icon-note"></i> ${text(mesProductArcWelding.isNewRecord ? '新增弧焊过程参数管理' : '弧焊过程参数管理详情')}
+            </div>
+            <div class="box-tools pull-right">
+                <button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i>
+                </button>
+            </div>
+        </div>
+
+
+        <div id="app">
+
+            <div ref="vChart" style="width: 100%;height: 500px;"></div>
+            <br>
+            <br>
+            <div ref="iChart" style="width: 100%;height:500px;"></div>
+            <br>
+            <br>
+            <div ref="speedChart" style="width: 100%;height:500px;"></div>
+            <br>
+            <br>
+            <div class="col-sm-12">
+                <table class="table table-bordered" style="table-layout: fixed;white-space: normal;">
+                    <thead>
+                        <tr>
+                            <template v-for="n in welderCount">
+                                <th>电压{{n}}</th>
+                                <th>电流{{n}}</th>
+                                <th>送丝速度{{n}}</th>
+                                <th>错误码{{n}}</th>
+                                <th>JOB号{{n}}</th>
+                            </template>
+                            <th>记录时间</th>
+                        </tr>
+                    </thead>
+                    <tbody>
+                        <tr v-for="(item,index) in myData" :key="index">
+                            <template v-for="n in welderCount">
+                                <td>{{ item['V' + n] }}</td>
+                                <td>{{ item['I' + n] }}</td>
+                                <td>{{ item['speed' + n] }}</td>
+                                <td>{{ item['code' + n] }}</td>
+                                <td>{{ item['JOB' + n] }}</td>
+                            </template>
+                            <td>{{ item.createDate }}</td>
+                        </tr>
+                    </tbody>
+                </table>
+            </div>
+
+        </div>
+
+
+        <div class="box-footer">
+            <div class="row">
+                <div class="col-sm-offset-2 col-sm-10">
+                    <button type="button" class="btn btn-sm btn-default" id="btnCancel"
+                            onclick="js.closeCurrentTabPage()"><i class="fa fa-reply-all"></i> ${text('关 闭')}
+                    </button>
+                </div>
+            </div>
+        </div>
+
+    </div>
+</div>
+<% } %>
+<script>
+    $("#inputForm").validate({
+        submitHandler: function (form) {
+            js.ajaxSubmitForm($(form), function (data) {
+                js.showMessage(data.message);
+                if (data.result == Global.TRUE) {
+                    js.closeCurrentTabPage(function (contentWindow) {
+                        contentWindow.page();
+                    });
+                }
+            }, "json");
+        }
+    });
+</script>
+<script src="${ctxStatic}/echarts/4.2/echarts.min.js"></script>
+<script src="${ctxStatic}/common/elementui2.15.5/vue-2.6.14.js"></script>
+<script>
+    const convertToArrayOfObjects = (arr, welderCount) => {
+        return arr.map(str => {
+            const values = str.split('|');
+            const obj = {};
+            for (let i = 0; i < welderCount; i++) {
+                const baseIndex = i * 5;
+                if (baseIndex + 4 >= values.length) break;
+                obj['V' + (i + 1)] = parseFloat(values[baseIndex]) || 0;
+                obj['I' + (i + 1)] = parseFloat(values[baseIndex + 1]) || 0;
+                obj['speed' + (i + 1)] = parseFloat(values[baseIndex + 2]) || 0;
+                obj['code' + (i + 1)] = parseInt(values[baseIndex + 3], 10) || 0;
+                obj['JOB' + (i + 1)] = parseInt(values[baseIndex + 4], 10) || 0;
+            }
+            obj.createDate = values[welderCount * 5] || '';
+            return obj;
+        });
+    };
+
+    const unescapeHtml = (str) => {
+        if (!str) return str;
+        return str.replace(/&quot;/g, '"')
+                 .replace(/&amp;/g, '&')
+                 .replace(/&lt;/g, '<')
+                 .replace(/&gt;/g, '>')
+                 .replace(/&#39;/g, "'")
+                 .replace(/&nbsp;/g, ' ');
+    };
+
+    const getWelderCount = (content) => {
+        if (!content || content === '' || content === '[]') return 2;
+        try {
+            content = unescapeHtml(content);
+            let strArr;
+            if (content.startsWith('[')) {
+                strArr = JSON.parse(content);
+            } else if (content.startsWith('"')) {
+                strArr = JSON.parse(content);
+            } else {
+                strArr = content.slice(2, -2).split('","');
+            }
+            if (!strArr || strArr.length === 0 || !strArr[0]) return 2;
+            const firstRecord = strArr[0];
+            const values = firstRecord.split('|');
+            const fieldCount = values.length - 1;
+            return Math.floor(fieldCount / 5) || 2;
+        } catch (e) {
+            console.error('解析焊机数量出错:', e);
+            return 2;
+        }
+    };
+
+    const parseContent = (content) => {
+        if (!content || content === '' || content === '[]') return [];
+        try {
+            content = unescapeHtml(content);
+            let strArr;
+            if (content.startsWith('[')) {
+                strArr = JSON.parse(content);
+            } else if (content.startsWith('"')) {
+                strArr = JSON.parse(content);
+            } else {
+                strArr = content.slice(2, -2).split('","');
+            }
+            if (!strArr || strArr.length === 0) return [];
+            const welderCount = getWelderCount(content);
+            return convertToArrayOfObjects(strArr, welderCount);
+        } catch (e) {
+            console.error('解析content出错:', e, content);
+            return [];
+        }
+    };
+
+    new Vue({
+        el: '#app',
+        data: {
+            content: '${mesProductArcWelding.content!\'\'}',
+            welderCount: 2,
+            vChart: null,
+            iChart: null,
+            speedChart: null
+        },
+        computed: {
+            myData() {
+                return parseContent(this.content);
+            },
+            timeArr() {
+                if (!this.myData || this.myData.length === 0) return [];
+                arr = []
+                for (let i = 0; i < this.myData.length; i++) {
+                    const {createDate} = this.myData[i]
+                    if (createDate) {
+                        arr.push(createDate.slice(14))
+                    }
+                }
+                return arr
+            },
+            vOption() {
+                const series = [];
+                const legendData = [];
+                for (let i = 1; i <= this.welderCount; i++) {
+                    legendData.push('电压' + i);
+                    const arr = [];
+                    for (let j = 0; j < this.myData.length; j++) {
+                        arr.push(this.myData[j]['V' + i]);
+                    }
+                    series.push({
+                        name: '电压' + i,
+                        type: 'line',
+                        data: arr,
+                        smooth: true
+                    });
+                }
+                let option = {
+                    title: {
+                        text: '电压变化折线图'
+                    },
+                    tooltip: {
+                        trigger: 'axis'
+                    },
+                    legend: {
+                        data: legendData
+                    },
+                    grid: {
+                        left: '3%',
+                        right: '4%',
+                        bottom: '3%',
+                        containLabel: true
+                    },
+                    toolbox: {
+                        feature: {
+                            saveAsImage: {}
+                        }
+                    },
+                    xAxis: {
+                        type: 'category',
+                        name: '时间',
+                        boundaryGap: false,
+                        data: this.timeArr
+                    },
+                    yAxis: {
+                        name: "电压",
+                        type: 'value'
+                    },
+                    series: series
+                };
+                return option
+            },
+            iOption() {
+                const series = [];
+                const legendData = [];
+                for (let i = 1; i <= this.welderCount; i++) {
+                    legendData.push('电流' + i);
+                    const arr = [];
+                    for (let j = 0; j < this.myData.length; j++) {
+                        arr.push(this.myData[j]['I' + i]);
+                    }
+                    series.push({
+                        name: '电流' + i,
+                        type: 'line',
+                        data: arr,
+                        smooth: true
+                    });
+                }
+                let option = {
+                    title: {
+                        text: '电流变化折线图'
+                    },
+                    tooltip: {
+                        trigger: 'axis'
+                    },
+                    legend: {
+                        data: legendData
+                    },
+                    grid: {
+                        left: '3%',
+                        right: '4%',
+                        bottom: '3%',
+                        containLabel: true
+                    },
+                    toolbox: {
+                        feature: {
+                            saveAsImage: {}
+                        }
+                    },
+                    xAxis: {
+                        type: 'category',
+                        name: '时间',
+                        boundaryGap: false,
+                        data: this.timeArr,
+
+                    },
+                    yAxis: {
+                        name: "电流",
+                        type: 'value'
+                    },
+                    series: series
+                };
+                return option
+            },
+            speedOption() {
+                const series = [];
+                const legendData = [];
+                for (let i = 1; i <= this.welderCount; i++) {
+                    legendData.push('送丝速度' + i);
+                    const arr = [];
+                    for (let j = 0; j < this.myData.length; j++) {
+                        arr.push(this.myData[j]['speed' + i]);
+                    }
+                    series.push({
+                        name: '送丝速度' + i,
+                        type: 'line',
+                        data: arr,
+                        smooth: true
+                    });
+                }
+                let option = {
+                    title: {
+                        text: '送丝速度变化折线图'
+                    },
+                    tooltip: {
+                        trigger: 'axis'
+                    },
+                    legend: {
+                        data: legendData
+                    },
+                    grid: {
+                        left: '3%',
+                        right: '4%',
+                        bottom: '3%',
+                        containLabel: true
+                    },
+                    toolbox: {
+                        feature: {
+                            saveAsImage: {}
+                        }
+                    },
+                    xAxis: {
+                        type: 'category',
+                        name: '时间',
+                        boundaryGap: false,
+                        data: this.timeArr,
+
+                    },
+                    yAxis: {
+                        name: "速度",
+                        type: 'value'
+                    },
+                    series: series
+                };
+                return option
+            }
+        },
+
+        watch: {
+            myData: {
+                handler() {
+                    if (this.vChart) {
+                        this.welderCount = getWelderCount(this.content);
+                        this.vChart.setOption(this.vOption, true);
+                        this.iChart.setOption(this.iOption, true);
+                        this.speedChart.setOption(this.speedOption, true);
+                    }
+                },
+                deep: true
+            }
+        },
+
+        mounted() {
+            if (this.content && this.content !== '' && this.content !== '[]') {
+                this.welderCount = getWelderCount(this.content);
+            }
+            this.$nextTick(() => {
+                this.vChart = echarts.init(this.$refs.vChart)
+                this.iChart = echarts.init(this.$refs.iChart)
+                this.speedChart = echarts.init(this.$refs.speedChart)
+                this.vChart.setOption(this.vOption);
+                this.iChart.setOption(this.iOption);
+                this.speedChart.setOption(this.speedOption);
+            });
+        }
+    })
+</script>