wangxichen 2 周之前
父节点
当前提交
f36fc3688b

+ 110 - 1
src/main/java/com/jeesite/modules/mes/service/MesProductGp12Service.java

@@ -1,7 +1,15 @@
 package com.jeesite.modules.mes.service;
 
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.LocalDate;
 import java.util.List;
 
+import com.jeesite.modules.mes.resp.CommonResp;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -143,5 +151,106 @@ public class MesProductGp12Service extends CrudService<MesProductGp12Dao, MesPro
 	public void delete(MesProductGp12 mesProductGp12) {
 		super.delete(mesProductGp12);
 	}
-	
+
+	/**
+	 * 客户端GP12拍照上传 - 同一工件码合并为一条记录,正反面图片追加到同一文件夹
+	 */
+	@Transactional
+	public CommonResp<String> upload(MesProductGp12 mesProductGp12, MultipartFile[] files) {
+		CommonResp<String> resp = new CommonResp<>();
+
+		if (files == null || files.length == 0) {
+			resp.setResult(Global.FALSE);
+			resp.setMessage("未上传任何图片,请重新上传!");
+			return resp;
+		}
+		if (StringUtils.isEmpty(mesProductGp12.getLineSn())) {
+			resp.setResult(Global.FALSE);
+			resp.setMessage("缺少必要参数,产线编号为空!");
+			return resp;
+		}
+		if (StringUtils.isEmpty(mesProductGp12.getSn())) {
+			resp.setResult(Global.FALSE);
+			resp.setMessage("缺少必要参数,工件码为空!");
+			return resp;
+		}
+
+		String sn = mesProductGp12.getSn();
+		String oprno = mesProductGp12.getOprno();
+
+		// 按 sn + oprno 查找是否已有记录
+		MesProductGp12 query = new MesProductGp12();
+		query.setSn(sn);
+		query.setOprno(oprno);
+		MesProductGp12 existing = mesProductGp12Dao.findInfo(query);
+
+		String folderName;
+		if (existing != null && StringUtils.isNotEmpty(existing.getRemark())) {
+			// 已有记录,用已有的文件夹名追加图片
+			folderName = existing.getRemark();
+		} else {
+			// 没有记录,用客户端传来的 remark 作为文件夹名
+			folderName = mesProductGp12.getRemark();
+		}
+
+		int currentYear = LocalDate.now().getYear();
+		int currentMonth = LocalDate.now().getMonthValue();
+		int currentDay = LocalDate.now().getDayOfMonth();
+
+		// 已有记录时,从 remark 解析出原日期目录;新记录用当天日期
+		String dateDir;
+		if (existing != null && existing.getCreateDate() != null) {
+			java.util.Calendar cal = java.util.Calendar.getInstance();
+			cal.setTime(existing.getCreateDate());
+			dateDir = cal.get(java.util.Calendar.YEAR) + "-"
+					+ (cal.get(java.util.Calendar.MONTH) + 1) + "-"
+					+ cal.get(java.util.Calendar.DAY_OF_MONTH);
+		} else {
+			dateDir = currentYear + "-" + currentMonth + "-" + currentDay;
+		}
+
+		String uploadDir = "D:/mescloud/userfiles/gp12/" + dateDir + "/" + folderName;
+		File directory = new File(uploadDir);
+		if (!directory.exists()) {
+			boolean created = directory.mkdirs();
+			if (!created) {
+				logger.error("创建目录失败: {}", uploadDir);
+				resp.setResult(Global.FALSE);
+				resp.setMessage("创建目录失败:" + uploadDir);
+				return resp;
+			}
+		}
+
+		for (MultipartFile file : files) {
+			String filePath = uploadDir + "/" + file.getOriginalFilename();
+			try {
+				byte[] bytes = file.getBytes();
+				Path path = Paths.get(filePath);
+				Files.write(path, bytes);
+			} catch (IOException e) {
+				logger.error("保存图片失败: {}", filePath, e);
+				resp.setResult(Global.FALSE);
+				resp.setMessage("保存图片失败:" + filePath + ",原因:" + e.getMessage());
+				return resp;
+			}
+		}
+
+		if (existing != null) {
+			// 已有记录,更新时间
+			existing.setUpdateDate(new java.util.Date());
+			super.save(existing);
+		} else {
+			// 新建记录
+			MesProductGp12 entry = new MesProductGp12();
+			entry.setSn(sn);
+			entry.setLineSn(mesProductGp12.getLineSn());
+			entry.setOprno(oprno);
+			entry.setRemark(folderName);
+			super.save(entry);
+		}
+
+		resp.setResult(Global.TRUE);
+		resp.setMessage("上传成功");
+		return resp;
+	}
 }

+ 86 - 1
src/main/java/com/jeesite/modules/mes/web/MesProductGp12Controller.java

@@ -1,5 +1,8 @@
 package com.jeesite.modules.mes.web;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.OutputStream;
 import java.util.List;
 import java.util.Map;
 import javax.servlet.http.HttpServletRequest;
@@ -287,6 +290,32 @@ public class MesProductGp12Controller extends BaseController {
 
 
 	/**
+	 * 查看详情
+	 */
+	@RequiresPermissions("mes:mesProductGp12:view")
+	@RequestMapping(value = "detail")
+	public String detail(MesProductGp12 mesProductGp12, Model model, HttpServletRequest request) {
+		if (mesProductGp12.getCreateDate() != null && mesProductGp12.getRemark() != null) {
+			java.util.Calendar cal = java.util.Calendar.getInstance();
+			cal.setTime(mesProductGp12.getCreateDate());
+			int year = cal.get(java.util.Calendar.YEAR);
+			int month = cal.get(java.util.Calendar.MONTH) + 1;
+			int day = cal.get(java.util.Calendar.DAY_OF_MONTH);
+			String remark = mesProductGp12.getRemark();
+			try {
+				remark = java.net.URLEncoder.encode(remark, "UTF-8");
+			} catch (Exception ignored) {}
+			String imgSubPath = year + "-" + month + "-" + day
+					+ "/" + remark + "/";
+			model.addAttribute("imgSubPath", imgSubPath);
+		} else {
+			model.addAttribute("imgSubPath", "");
+		}
+		model.addAttribute("mesProductGp12", mesProductGp12);
+		return "modules/mes/mesProductGp12Detail";
+	}
+
+	/**
 	 * 删除数据
 	 */
 	@RequiresPermissions("mes:mesProductGp12:edit")
@@ -296,5 +325,61 @@ public class MesProductGp12Controller extends BaseController {
 		mesProductGp12Service.delete(mesProductGp12);
 		return renderResult(Global.TRUE, text("删除工件拍照记录成功!"));
 	}
-	
+
+	/**
+	 * GP12图片下载接口 - 根据路径从磁盘读取图片返回给浏览器
+	 */
+	@RequestMapping(value = "image")
+	public void image(HttpServletRequest request, HttpServletResponse response) {
+		String queryString = request.getQueryString();
+		if (StringUtils.isBlank(queryString) || !queryString.startsWith("path=")) {
+			response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+			return;
+		}
+		String path = queryString.substring("path=".length());
+		try {
+			path = java.net.URLDecoder.decode(path.replace("+", "%2B"), "UTF-8");
+		} catch (Exception ignored) {}
+		if (StringUtils.isBlank(path) || path.contains("..")) {
+			response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+			return;
+		}
+		String filePath = "D:/mescloud/userfiles/gp12/" + path;
+		File file = new File(filePath);
+		logger.info("GP12图片请求, path参数: {}, 文件路径: {}, 存在: {}", path, filePath, file.exists());
+		if (!file.exists() || !file.isFile()) {
+			response.setStatus(HttpServletResponse.SC_NOT_FOUND);
+			return;
+		}
+		String fileName = file.getName().toLowerCase();
+		if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) {
+			response.setContentType("image/jpeg");
+		} else if (fileName.endsWith(".png")) {
+			response.setContentType("image/png");
+		} else if (fileName.endsWith(".bmp")) {
+			response.setContentType("image/bmp");
+		} else {
+			response.setContentType("application/octet-stream");
+		}
+		try (FileInputStream fis = new FileInputStream(file);
+			 OutputStream os = response.getOutputStream()) {
+			byte[] buffer = new byte[4096];
+			int bytesRead;
+			while ((bytesRead = fis.read(buffer)) != -1) {
+				os.write(buffer, 0, bytesRead);
+			}
+			os.flush();
+		} catch (Exception e) {
+			logger.error("读取图片失败: {}", filePath, e);
+		}
+	}
+
+	/**
+	 * 客户端GP12拍照上传接口
+	 */
+	@ResponseBody
+	@PostMapping(value = "upload")
+	public CommonResp<String> upload(MesProductGp12 mesProductGp12, MultipartFile[] files, HttpServletRequest request) {
+		return mesProductGp12Service.upload(mesProductGp12, files);
+	}
 }

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

@@ -655,6 +655,7 @@ shiro:
     ${adminPath}/mes/mesElectricTorque/batchSave = anon
     ${adminPath}/mes/mesProductYgsl/batchsave = anon
     ${adminPath}/mes/mesProductHb/upload = anon
+    ${adminPath}/mes/mesProductGp12/upload = anon
     ${adminPath}/mes/mesProductCmt/batchsave = anon
     ${adminPath}/mes/mesDeviceState/add = anon
     ${adminPath}/mes/mesDeviceTime/list2 = anon

+ 109 - 44
src/main/resources/views/modules/mes/mesProductGp12Detail.html

@@ -1,14 +1,67 @@
-<% layout('/layouts/default.html', {title: '工件拍照记录详情', libs: ['validate','dataGrid','fileupload']}){ %>
-
+<% layout('/layouts/default.html', {title: '工件拍照记录详情', libs: ['validate']}){ %>
 <style>
-	table{
-		width: 100%;
+	table { width: 100%; }
+	th, td { padding: 10px; }
+	.table.table-bordered th {
+		width: 150px;
+		background: #f8f9fa;
+		vertical-align: middle;
 	}
-	th,td{
-		padding: 10px;
+	.gp12-img {
+		width: 500px;
+		height: 350px;
+		object-fit: contain;
+		cursor: pointer;
+		border: 1px solid #ddd;
+		border-radius: 4px;
+		background: #fafafa;
+		transition: box-shadow 0.2s;
 	}
-	.table.table-bordered th {
-		width: 200px;
+	.gp12-img:hover {
+		box-shadow: 0 2px 12px rgba(0,0,0,0.15);
+	}
+	.img-not-found {
+		display: inline-block;
+		width: 500px;
+		height: 200px;
+		line-height: 200px;
+		text-align: center;
+		background: #f9f9f9;
+		color: #ccc;
+		border: 1px dashed #e0e0e0;
+		border-radius: 4px;
+		font-size: 14px;
+	}
+	.modal-overlay {
+		display: none;
+		position: fixed;
+		z-index: 9999;
+		top: 0; left: 0;
+		width: 100%; height: 100%;
+		background-color: rgba(0, 0, 0, 0.85);
+		cursor: pointer;
+	}
+	.modal-overlay img {
+		display: block;
+		max-width: 92%; max-height: 92%;
+		margin: auto;
+		position: absolute;
+		top: 50%; left: 50%;
+		transform: translate(-50%, -50%);
+		border-radius: 4px;
+	}
+	.section-header {
+		font-size: 15px;
+		font-weight: bold;
+		padding: 10px 15px;
+		margin: 15px 0 0 0;
+		border-left: 4px solid #3498db;
+		background: #f0f7ff;
+		color: #2c3e50;
+	}
+	.section-header.back-side {
+		border-left-color: #e67e22;
+		background: #fef5ec;
 	}
 </style>
 <div class="main-content">
@@ -21,48 +74,61 @@
 				<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>
 			</div>
 		</div>
-		<#form:form id="inputForm" model="${mesProductGp12}" action="${ctx}/mes/mesProductGp12/save" method="post" class="form-horizontal">
 		<div class="box-body">
 			<div class="form-unit">${text('基本信息')}</div>
 			<table class="table table-bordered">
 				<tr>
-					<th class="mpc-header">工件码</th>
+					<th>工件码</th>
 					<td>${mesProductGp12.sn}</td>
 				</tr>
-
 				<tr>
-					<th class="mpc-header">工位号</th>
+					<th>工位号</th>
 					<td>${mesProductGp12.oprno}</td>
 				</tr>
-
 				<tr>
-					<th class="mpc-header">产线编号</th>
+					<th>产线编号</th>
 					<td>${mesProductGp12.lineSn}</td>
 				</tr>
-
 				<tr>
-					<th class="mpc-header">备注</th>
-					<td>${mesProductGp12.remark}</td>
+					<th>创建人</th>
+					<td>${mesProductGp12.createBy}</td>
 				</tr>
-
 				<tr>
-					<th class="mpc-header">创建人</th>
-					<td>${mesProductGp12.createBy}</td>
+					<th>创建时间</th>
+					<td>${mesProductGp12.createDate,dateFormat='yyyy-MM-dd HH:mm:ss'}</td>
 				</tr>
+			</table>
 
-
+			<div class="section-header">正面图片(上 / 左 / 右 / 前 / 后)</div>
+			<table class="table table-bordered">
+				<tr>
+					<th>上</th>
+					<td><img class="gp12-img" src="${ctx}/mes/mesProductGp12/image?path=${imgSubPath}shang.jpg" onclick="showBigImg(this)" onerror="imgError(this)"/></td>
+				</tr>
+				<tr>
+					<th>左</th>
+					<td><img class="gp12-img" src="${ctx}/mes/mesProductGp12/image?path=${imgSubPath}zuo.jpg" onclick="showBigImg(this)" onerror="imgError(this)"/></td>
+				</tr>
+				<tr>
+					<th>右</th>
+					<td><img class="gp12-img" src="${ctx}/mes/mesProductGp12/image?path=${imgSubPath}you.jpg" onclick="showBigImg(this)" onerror="imgError(this)"/></td>
+				</tr>
 				<tr>
-					<th class="mpc-header">创建时间</th>
-					<td>${mesProductGp12.createDate,dateFormat='yyyy-MM-dd HH:mm'}</td>
+					<th>前</th>
+					<td><img class="gp12-img" src="${ctx}/mes/mesProductGp12/image?path=${imgSubPath}qian.jpg" onclick="showBigImg(this)" onerror="imgError(this)"/></td>
 				</tr>
 				<tr>
-					<th class="mpc-header">图片</th>
-					<td>
-						<#form:fileupload id="uploadImage" bizKey="${mesProductGp12.id}" bizType="mesProductGp12_image"
-						uploadType="image" class="" readonly="true" preview="true"/>
-					</td>
+					<th>后</th>
+					<td><img class="gp12-img" src="${ctx}/mes/mesProductGp12/image?path=${imgSubPath}hou.jpg" onclick="showBigImg(this)" onerror="imgError(this)"/></td>
 				</tr>
+			</table>
 
+			<div class="section-header back-side">反面图片(下)</div>
+			<table class="table table-bordered">
+				<tr>
+					<th>下</th>
+					<td><img class="gp12-img" src="${ctx}/mes/mesProductGp12/image?path=${imgSubPath}xia.jpg" onclick="showBigImg(this)" onerror="imgError(this)"/></td>
+				</tr>
 			</table>
 		</div>
 		<div class="box-footer">
@@ -72,24 +138,23 @@
 				</div>
 			</div>
 		</div>
-	</#form:form>
+	</div>
 </div>
+<div id="bigImgModal" class="modal-overlay" onclick="this.style.display='none'">
+	<img id="bigImgModalImg"/>
 </div>
 <% } %>
 <script>
-
-</script>
-<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");
-		}
-	});
+	function showBigImg(imgEl) {
+		var modal = document.getElementById("bigImgModal");
+		var modalImg = document.getElementById("bigImgModalImg");
+		modalImg.src = imgEl.src;
+		modal.style.display = "block";
+	}
+	function imgError(imgEl) {
+		var placeholder = document.createElement('span');
+		placeholder.className = 'img-not-found';
+		placeholder.innerText = '待拍照';
+		imgEl.parentNode.replaceChild(placeholder, imgEl);
+	}
 </script>

+ 1 - 1
src/main/resources/views/modules/mes/mesProductGp12List.html

@@ -85,7 +85,7 @@ $('#dataGrid').dataGrid({
 			//<% if(hasPermi('mes:mesProductGp12:edit')){ %>
 			// 	actions.push('<a href="${ctx}/mes/mesProductGp12/form?id='+row.id+'" class="btnList" title="${text("编辑工件拍照记录")}"><i class="fa fa-pencil"></i></a>&nbsp;');
 			// 	actions.push('<a href="${ctx}/mes/mesProductGp12/delete?id='+row.id+'" class="btnList" title="${text("删除工件拍照记录")}" data-confirm="${text("确认要删除该工件拍照记录吗?")}"><i class="fa fa-trash-o"></i></a>&nbsp;');
-					actions.push('<a href="${ctx}/mes/mesProductGp12/form?id='+row.id+'" class="btnList" title="${text("详情")}"><i class="fa fa-fw fa-eye"></i></a>&nbsp;');
+					actions.push('<a href="${ctx}/mes/mesProductGp12/detail?id='+row.id+'" class="btnList" title="${text("详情")}"><i class="fa fa-fw fa-eye"></i></a>&nbsp;');
 
 				//<% } %>
 			return actions.join('');