Przeglądaj źródła

Merge remote-tracking branch 'origin/master'

dkk 5 miesięcy temu
rodzic
commit
8dfb7bd6c0

+ 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>-->

+ 15 - 0
src/main/java/com/jeesite/modules/mes/dao/MesProductArcWeldingDao.java

@@ -0,0 +1,15 @@
+package com.jeesite.modules.mes.dao;
+
+import com.jeesite.common.dao.CrudDao;
+import com.jeesite.common.mybatis.annotation.MyBatisDao;
+import com.jeesite.modules.mes.entity.MesProductArcWelding;
+
+/**
+ * 弧焊参数DAO接口
+ * @author jingbo
+ * @version 2026-05-21
+ */
+@MyBatisDao
+public interface MesProductArcWeldingDao extends CrudDao<MesProductArcWelding> {
+	
+}

+ 88 - 0
src/main/java/com/jeesite/modules/mes/entity/MesProductArcWelding.java

@@ -0,0 +1,88 @@
+package com.jeesite.modules.mes.entity;
+
+import javax.validation.constraints.Size;
+
+import java.util.Date;
+import com.jeesite.common.entity.DataEntity;
+import com.jeesite.common.mybatis.annotation.Column;
+import com.jeesite.common.mybatis.annotation.Table;
+import com.jeesite.common.mybatis.mapper.query.QueryType;
+import com.jeesite.common.utils.excel.annotation.ExcelField;
+import com.jeesite.common.utils.excel.annotation.ExcelField.Align;
+import com.jeesite.common.utils.excel.annotation.ExcelFields;
+
+/**
+ * 弧焊参数Entity
+ * @author jingbo
+ * @version 2026-05-21
+ */
+@Table(name="mes_product_arc_welding", alias="a", label="弧焊参数信息", columns={
+		@Column(name="id", attrName="id", label="id", isPK=true),
+		@Column(name="line_sn", attrName="lineSn", label="产线编号", queryType=QueryType.LIKE),
+		@Column(name="oprno", attrName="oprno", label="工位号", queryType=QueryType.LIKE),
+		@Column(name="sn", attrName="sn", label="二维码", queryType=QueryType.LIKE),
+		@Column(name="content", attrName="content", label="参数内容", isQuery=false),
+		@Column(name="create_date", attrName="createDate", label="创建时间", isPK=true),
+	}, orderBy="a.id DESC, a.create_date DESC"
+)
+public class MesProductArcWelding extends DataEntity<MesProductArcWelding> {
+	
+	private static final long serialVersionUID = 1L;
+	private String lineSn;		// 产线编号
+	private String oprno;		// 工位号
+	private String sn;		// 二维码
+	private String content;		// 参数内容
+
+	@ExcelFields({
+		@ExcelField(title="id", attrName="id", align=Align.CENTER, sort=10),
+		@ExcelField(title="产线编号", attrName="lineSn", align=Align.CENTER, sort=20),
+		@ExcelField(title="工位号", attrName="oprno", align=Align.CENTER, sort=30),
+		@ExcelField(title="二维码", attrName="sn", align=Align.CENTER, sort=40),
+		@ExcelField(title="参数内容", attrName="content", align=Align.CENTER, sort=50),
+		@ExcelField(title="创建时间", attrName="createDate", align=Align.CENTER, sort=60),
+	})
+	public MesProductArcWelding() {
+		this(null, null);
+	}
+	
+	public MesProductArcWelding(String id, Date createDate){
+		this.id = id;
+		this.createDate = createDate;
+	}
+	
+	@Size(min=0, max=10, message="产线编号长度不能超过 10 个字符")
+	public String getLineSn() {
+		return lineSn;
+	}
+
+	public void setLineSn(String lineSn) {
+		this.lineSn = lineSn;
+	}
+	
+	@Size(min=0, max=20, message="工位号长度不能超过 20 个字符")
+	public String getOprno() {
+		return oprno;
+	}
+
+	public void setOprno(String oprno) {
+		this.oprno = oprno;
+	}
+	
+	@Size(min=0, max=50, message="二维码长度不能超过 50 个字符")
+	public String getSn() {
+		return sn;
+	}
+
+	public void setSn(String sn) {
+		this.sn = sn;
+	}
+	
+	public String getContent() {
+		return content;
+	}
+
+	public void setContent(String content) {
+		this.content = content;
+	}
+	
+}

+ 137 - 0
src/main/java/com/jeesite/modules/mes/service/MesProductArcWeldingService.java

@@ -0,0 +1,137 @@
+package com.jeesite.modules.mes.service;
+
+import java.util.List;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.jeesite.common.entity.Page;
+import com.jeesite.common.service.CrudService;
+import com.jeesite.modules.mes.entity.MesProductArcWelding;
+import com.jeesite.modules.mes.dao.MesProductArcWeldingDao;
+import com.jeesite.common.service.ServiceException;
+import com.jeesite.common.config.Global;
+import com.jeesite.common.validator.ValidatorUtils;
+import com.jeesite.common.utils.excel.ExcelImport;
+import org.springframework.web.multipart.MultipartFile;
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
+
+/**
+ * 弧焊参数Service
+ * @author jingbo
+ * @version 2026-05-21
+ */
+@Service
+public class MesProductArcWeldingService extends CrudService<MesProductArcWeldingDao, MesProductArcWelding> {
+	
+	/**
+	 * 获取单条数据
+	 * @param mesProductArcWelding
+	 * @return
+	 */
+	@Override
+	public MesProductArcWelding get(MesProductArcWelding mesProductArcWelding) {
+		return super.get(mesProductArcWelding);
+	}
+	
+	/**
+	 * 查询分页数据
+	 * @param mesProductArcWelding 查询条件
+	 * @param mesProductArcWelding.page 分页对象
+	 * @return
+	 */
+	@Override
+	public Page<MesProductArcWelding> findPage(MesProductArcWelding mesProductArcWelding) {
+		return super.findPage(mesProductArcWelding);
+	}
+	
+	/**
+	 * 查询列表数据
+	 * @param mesProductArcWelding
+	 * @return
+	 */
+	@Override
+	public List<MesProductArcWelding> findList(MesProductArcWelding mesProductArcWelding) {
+		return super.findList(mesProductArcWelding);
+	}
+	
+	/**
+	 * 保存数据(插入或更新)
+	 * @param mesProductArcWelding
+	 */
+	@Override
+	@Transactional
+	public void save(MesProductArcWelding mesProductArcWelding) {
+		super.save(mesProductArcWelding);
+	}
+
+	/**
+	 * 导入数据
+	 * @param file 导入的数据文件
+	 */
+	@Transactional
+	public String importData(MultipartFile file) {
+		if (file == null){
+			throw new ServiceException(text("请选择导入的数据文件!"));
+		}
+		int successNum = 0; int failureNum = 0;
+		StringBuilder successMsg = new StringBuilder();
+		StringBuilder failureMsg = new StringBuilder();
+		try(ExcelImport ei = new ExcelImport(file, 2, 0)){
+			List<MesProductArcWelding> list = ei.getDataList(MesProductArcWelding.class);
+			for (MesProductArcWelding mesProductArcWelding : list) {
+				try{
+					ValidatorUtils.validateWithException(mesProductArcWelding);
+					this.save(mesProductArcWelding);
+					successNum++;
+					successMsg.append("<br/>" + successNum + "、编号 " + mesProductArcWelding.getId() + " 导入成功");
+				} catch (Exception e) {
+					failureNum++;
+					String msg = "<br/>" + failureNum + "、编号 " + mesProductArcWelding.getId() + " 导入失败:";
+					if (e instanceof ConstraintViolationException){
+						ConstraintViolationException cve = (ConstraintViolationException)e;
+						for (ConstraintViolation<?> violation : cve.getConstraintViolations()) {
+							msg += Global.getText(violation.getMessage()) + " ("+violation.getPropertyPath()+")";
+						}
+					}else{
+						msg += e.getMessage();
+					}
+					failureMsg.append(msg);
+					logger.error(msg, e);
+				}
+			}
+		} catch (Exception e) {
+			logger.error(e.getMessage(), e);
+			failureMsg.append(e.getMessage());
+			return failureMsg.toString();
+		}
+		if (failureNum > 0) {
+			failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
+			throw new ServiceException(failureMsg.toString());
+		}else{
+			successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
+		}
+		return successMsg.toString();
+	}
+	
+	/**
+	 * 更新状态
+	 * @param mesProductArcWelding
+	 */
+	@Override
+	@Transactional
+	public void updateStatus(MesProductArcWelding mesProductArcWelding) {
+		super.updateStatus(mesProductArcWelding);
+	}
+	
+	/**
+	 * 删除数据
+	 * @param mesProductArcWelding
+	 */
+	@Override
+	@Transactional
+	public void delete(MesProductArcWelding mesProductArcWelding) {
+		super.delete(mesProductArcWelding);
+	}
+	
+}

+ 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);
+    }
+
+}

+ 125 - 0
src/main/java/com/jeesite/modules/mes/web/EmpUserCustomController.java

@@ -0,0 +1,125 @@
+package com.jeesite.modules.mes.web;
+
+import com.jeesite.common.config.Global;
+import com.jeesite.common.lang.StringUtils;
+import com.jeesite.common.web.BaseController;
+import com.jeesite.modules.sys.entity.EmpUser;
+import com.jeesite.modules.sys.entity.EmployeeOffice;
+import com.jeesite.modules.sys.entity.Role;
+import com.jeesite.modules.sys.service.EmpUserService;
+import com.jeesite.modules.sys.web.user.EmpUserController;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.List;
+
+@Controller
+@RequestMapping(value = "${adminPath}/mes/empUserCustom")
+public class EmpUserCustomController extends BaseController {
+
+    @Autowired
+    private EmpUserController empUserController;
+
+    @Autowired
+    private EmpUserService empUserService;
+
+    @ModelAttribute
+    public EmpUser get(String userCode, boolean isNewRecord) {
+        return empUserService.get(userCode, isNewRecord);
+    }
+
+    @RequestMapping(value = "form")
+    public String form(EmpUser empUser, String op, Model model) {
+        if ("copy".equals(op)) {
+            // 借用原生的 form 方法,获取全量数据(包括岗位、机构、角色)
+            String view = empUserController.form(empUser, "edit", model);
+            
+            EmpUser fullUser = (EmpUser) model.asMap().get("empUser");
+            if (fullUser != null) {
+                // 将原记录转化为新记录
+                fullUser.setIsNewRecord(true);
+                fullUser.setUserCode(null);
+                
+                // 转换员工及附属机构的主键
+                if (fullUser.getEmployee() != null) {
+                    fullUser.getEmployee().setIsNewRecord(true);
+                    fullUser.getEmployee().setEmpCode(null);
+                    
+                    List<EmployeeOffice> officeList = fullUser.getEmployee().getEmployeeOfficeList();
+                    if (officeList != null && !officeList.isEmpty()) {
+                        for (EmployeeOffice eo : officeList) {
+                            eo.setIsNewRecord(true);
+                            eo.setId(null);
+                        }
+                    }
+                }
+                
+                // 处理角色回显
+                List<Role> roleList = fullUser.getRoleList();
+                if (roleList != null && !roleList.isEmpty()) {
+                    List<String> roleCodes = new ArrayList<>();
+                    for (Role role : roleList) {
+                        roleCodes.add(role.getRoleCode());
+                    }
+                    fullUser.setUserRoleString(StringUtils.join(roleCodes, ","));
+                }
+                
+                // 覆盖 Model 中的对象并注入角色列表和操作标识
+                model.addAttribute("empUser", fullUser);
+                model.addAttribute("roleList", roleList);
+                model.addAttribute("op", "add");
+            }
+            
+            // 注入自定义保存脚本,修改表单 action 为我们自己的 save
+            String customSaveScript = "<script>" +
+                    "$(function(){" +
+                    "  var overrideAction = function() {" +
+                    "      var form = $('#inputForm');" +
+                    "      if(form.length > 0 && form.attr('action').indexOf('/mes/empUserCustom/save') === -1) {" +
+                    "          form.attr('action', '" + Global.getAdminPath() + "/mes/empUserCustom/save');" +
+                    "      }" +
+                    "  };" +
+                    "  overrideAction();" +
+                    "  setInterval(overrideAction, 500);" +
+                    "});" +
+                    "</script>";
+            model.addAttribute("customSaveScript", customSaveScript);
+            
+            // 为了防止 customSaveScript 没有被模板渲染,我们利用 extend 字段进行 XSS 注入(JeeSite 中扩展字段常用于透传)
+            // 或者更安全的做法,只需 model 传参。这里保留之前的做法。
+            
+            return view;
+        }
+        
+        return empUserController.form(empUser, op, model);
+    }
+
+    @RequestMapping(value = "save")
+    @ResponseBody
+    public String save(@Validated EmpUser empUser, String oldLoginCode, HttpServletRequest request) {
+        EmpUser existUser = new EmpUser();
+        existUser.setLoginCode(empUser.getLoginCode());
+        List<EmpUser> uList = empUserService.findList(existUser);
+        if (uList != null && !uList.isEmpty()) {
+            return renderResult(Global.FALSE, "保存用户失败,登录账号已存在(不能与原账号相同),请修改登录账号!");
+        }
+        
+        if (StringUtils.isNotBlank(empUser.getUserName())) {
+            EmpUser where = new EmpUser();
+            where.setUserName(empUser.getUserName());
+            List<EmpUser> list = empUserService.findList(where);
+            if (list != null && !list.isEmpty()) {
+                return renderResult(Global.FALSE, "保存用户失败,用户昵称已存在(不能与原昵称相同),请修改用户昵称!");
+            }
+        }
+        
+        return empUserController.save(empUser, oldLoginCode, request);
+    }
+}

+ 201 - 0
src/main/java/com/jeesite/modules/mes/web/MesProductArcWeldingController.java

@@ -0,0 +1,201 @@
+package com.jeesite.modules.mes.web;
+
+import java.util.List;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Date;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.jeesite.common.lang.StringUtils;
+import com.jeesite.modules.mes.req.MesSearchDateReq;
+import com.jeesite.modules.mes.util.CommonUitl;
+
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.ui.Model;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import com.jeesite.common.config.Global;
+import com.jeesite.common.collect.ListUtils;
+import com.jeesite.common.entity.Page;
+import com.jeesite.common.lang.DateUtils;
+import com.jeesite.common.utils.excel.ExcelExport;
+import com.jeesite.common.utils.excel.annotation.ExcelField.Type;
+import org.springframework.web.multipart.MultipartFile;
+import com.jeesite.common.web.BaseController;
+import com.jeesite.modules.mes.entity.MesProductArcWelding;
+import com.jeesite.modules.mes.service.MesProductArcWeldingService;
+
+/**
+ * 弧焊参数Controller
+ * @author jingbo
+ * @version 2026-05-21
+ */
+@Controller
+@RequestMapping(value = "${adminPath}/mes/mesProductArcWelding")
+public class MesProductArcWeldingController extends BaseController {
+
+	@Autowired
+	private MesProductArcWeldingService mesProductArcWeldingService;
+	
+	/**
+	 * 获取数据
+	 */
+	@ModelAttribute
+	public MesProductArcWelding get(String id, Date createDate, boolean isNewRecord) {
+		MesProductArcWelding mesProductArcWelding = new MesProductArcWelding();
+		mesProductArcWelding.setId(id);
+		mesProductArcWelding.setCreateDate(createDate);
+		mesProductArcWelding.setIsNewRecord(isNewRecord);
+		return mesProductArcWeldingService.getAndValid(mesProductArcWelding);
+	}
+	
+	/**
+	 * 查询列表
+	 */
+	@RequiresPermissions("mes:mesProductArcWelding:view")
+	@RequestMapping(value = {"list", ""})
+	public String list(MesProductArcWelding mesProductArcWelding, Model model) {
+		model.addAttribute("mesProductArcWelding", mesProductArcWelding);
+		return "modules/mes/mesProductArcWeldingList";
+	}
+	
+	/**
+	 * 查询列表数据
+	 */
+	@RequiresPermissions("mes:mesProductArcWelding:view")
+	@RequestMapping(value = "listData")
+	@ResponseBody
+	public Page<MesProductArcWelding> listData(MesProductArcWelding mesProductArcWelding, HttpServletRequest request, HttpServletResponse response) {
+		mesProductArcWelding.setPage(new Page<>(request, response));
+		Page<MesProductArcWelding> page = mesProductArcWeldingService.findPage(mesProductArcWelding);
+		return page;
+	}
+
+	/**
+	 * 查看编辑表单
+	 */
+	@RequiresPermissions("mes:mesProductArcWelding:view")
+	@RequestMapping(value = "form")
+	public String form(MesProductArcWelding mesProductArcWelding, Model model) {
+		model.addAttribute("mesProductArcWelding", mesProductArcWelding);
+		return "modules/mes/mesProductArcWeldingForm";
+	}
+
+	/**
+	 * 保存数据
+	 */
+	@RequiresPermissions("mes:mesProductArcWelding:edit")
+	@PostMapping(value = "save")
+	@ResponseBody
+	public String save(@Validated MesProductArcWelding mesProductArcWelding) {
+		mesProductArcWeldingService.save(mesProductArcWelding);
+		return renderResult(Global.TRUE, text("保存弧焊参数成功!"));
+	}
+
+	/**
+	 * 导出数据
+	 */
+	@RequiresPermissions("mes:mesProductArcWelding:view")
+	@RequestMapping(value = "exportData")
+	public void exportData(MesProductArcWelding mesProductArcWelding, HttpServletResponse response) {
+		List<MesProductArcWelding> list = mesProductArcWeldingService.findList(mesProductArcWelding);
+		String fileName = "弧焊参数" + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx";
+		try(ExcelExport ee = new ExcelExport("弧焊参数", MesProductArcWelding.class)){
+			ee.setDataList(list).write(response, fileName);
+		}
+	}
+
+	/**
+	 * 下载模板
+	 */
+	@RequiresPermissions("mes:mesProductArcWelding:view")
+	@RequestMapping(value = "importTemplate")
+	public void importTemplate(HttpServletResponse response) {
+		MesProductArcWelding mesProductArcWelding = new MesProductArcWelding();
+		List<MesProductArcWelding> list = ListUtils.newArrayList(mesProductArcWelding);
+		String fileName = "弧焊参数模板.xlsx";
+		try(ExcelExport ee = new ExcelExport("弧焊参数", MesProductArcWelding.class, Type.IMPORT)){
+			ee.setDataList(list).write(response, fileName);
+		}
+	}
+
+	/**
+	 * 导入数据
+	 */
+	@ResponseBody
+	@RequiresPermissions("mes:mesProductArcWelding:edit")
+	@PostMapping(value = "importData")
+	public String importData(MultipartFile file) {
+		try {
+			String message = mesProductArcWeldingService.importData(file);
+			return renderResult(Global.TRUE, "posfull:"+message);
+		} catch (Exception ex) {
+			return renderResult(Global.FALSE, "posfull:"+ex.getMessage());
+		}
+	}
+	
+	/**
+	 * 删除数据
+	 */
+	@RequiresPermissions("mes:mesProductArcWelding:edit")
+	@RequestMapping(value = "delete")
+	@ResponseBody
+	public String delete(MesProductArcWelding mesProductArcWelding) {
+		mesProductArcWeldingService.delete(mesProductArcWelding);
+		return renderResult(Global.TRUE, text("删除弧焊参数成功!"));
+	}
+
+	/**
+	 * 查看详情
+	 */
+	@RequiresPermissions("mes:mesProductArcWelding:view")
+	@GetMapping("info")
+	public String info(MesProductArcWelding mesProductArcWelding, Model model) {
+		model.addAttribute("mesProductArcWelding", mesProductArcWelding);
+		return "modules/mes/mesProductArcWeldingInfo";
+	}
+
+	/**
+	 * 接口保存数据
+	 * content格式: ["电压1|电流1|送丝速度1|错误码1|JOB号1|电压2|电流2|送丝速度2|错误码2|JOB号2|时间", ...]
+	 * 注意: 每个焊机5个参数(电压、电流、送丝速度、错误码、JOB号),最后是时间戳
+	 * 2个焊机: 10个参数 + 1个时间 = 11个字段
+	 * 3个焊机: 15个参数 + 1个时间 = 16个字段
+	 * 4个焊机: 20个参数 + 1个时间 = 21个字段
+	 */
+	@PostMapping(value = "batchsave")
+	@ResponseBody
+	@Transactional
+	public String batchsave(HttpServletRequest request) {
+		String params = request.getParameter("params");
+		if(StringUtils.isEmpty(params)){
+			return renderResult(Global.FALSE, text("参数错误!"));
+		}
+
+		JSONArray jsonArr = JSON.parseArray(params);
+		if(jsonArr.size() <= 0){
+			return renderResult(Global.FALSE, text("参数错误!"));
+		}
+
+		for (int i=0; i<jsonArr.size(); i++) {
+			JSONObject obj = jsonArr.getJSONObject(i);
+
+			MesProductArcWelding mesProductArcWelding = new MesProductArcWelding();
+			mesProductArcWelding.setSn(obj.getString("sn"));
+			mesProductArcWelding.setOprno(obj.getString("oprno"));
+			mesProductArcWelding.setLineSn(obj.getString("lineSn"));
+			mesProductArcWelding.setContent(obj.getString("content"));
+			mesProductArcWeldingService.save(mesProductArcWelding);
+		}
+
+		return renderResult(Global.TRUE, text("操作成功!"));
+	}
+
+	
+}

+ 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
 
 

+ 15 - 0
src/main/resources/mappings/modules/mes/MesProductArcWeldingDao.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeesite.modules.mes.dao.MesProductArcWeldingDao">
+	
+	<!-- 查询数据
+	<select id="findList" resultType="MesProductArcWelding">
+		SELECT ${sqlMap.column.toSql()}
+		FROM ${sqlMap.table.toSql()}
+		<where>
+			${sqlMap.where.toSql()}
+		</where>
+		ORDER BY ${sqlMap.order.toSql()}
+	</select> -->
+	
+</mapper>

+ 85 - 0
src/main/resources/views/modules/mes/mesProductArcWeldingForm.html

@@ -0,0 +1,85 @@
+<% 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>
+		<#form:form id="inputForm" model="${mesProductArcWelding}" action="${ctx}/mes/mesProductArcWelding/save" method="post" class="form-horizontal">
+			<div class="box-body">
+				<div class="form-unit">${text('基本信息')}</div>
+				<#form:hidden path="id"/>
+				<div class="row">
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('产线编号')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:input path="lineSn" maxlength="10" class="form-control"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('工位号')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:input path="oprno" maxlength="20" class="form-control"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('二维码')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:input path="sn" maxlength="50" class="form-control"/>
+							</div>
+						</div>
+					</div>
+				</div>
+				<div class="row">
+					<div class="col-xs-12">
+						<div class="form-group">
+							<label class="control-label col-sm-2" title="">
+								<span class="required hide">*</span> ${text('参数内容')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-10">
+								<#form:textarea path="content" rows="4" class="form-control"/>
+							</div>
+						</div>
+					</div>
+				<#form:hidden path="createDate"/>
+				</div>
+			</div>
+			<div class="box-footer">
+				<div class="row">
+					<div class="col-sm-offset-2 col-sm-10">
+						<% if (hasPermi('mes:mesProductArcWelding:edit')){ %>
+							<button type="submit" class="btn btn-sm btn-primary" id="btnSubmit"><i class="fa fa-check"></i> ${text('保 存')}</button>&nbsp;
+						<% } %>
+						<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>
+		</#form:form>
+	</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>

+ 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>

+ 128 - 0
src/main/resources/views/modules/mes/mesProductArcWeldingList.html

@@ -0,0 +1,128 @@
+<% layout('/layouts/default.html', {title: '弧焊参数管理', libs: ['dataGrid']}){ %>
+<div class="main-content">
+	<div class="box box-main">
+		<div class="box-header">
+			<div class="box-title">
+				<i class="fa icon-notebook"></i> ${text('弧焊参数管理')}
+			</div>
+			<div class="box-tools pull-right">
+				<a href="#" class="btn btn-default" id="btnSearch" title="${text('查询')}"><i class="fa fa-filter"></i> ${text('查询')}</a>
+				<a href="#" class="btn btn-default" id="btnExport"><i class="glyphicon glyphicon-export"></i> 导出</a>
+<!--				<% if(hasPermi('mes:mesProductArcWelding:edit')){ %>-->
+<!--						<a href="#" class="btn btn-default" id="btnImport"><i class="glyphicon glyphicon-import"></i> 导入</a>-->
+<!--					<a href="${ctx}/mes/mesProductArcWelding/form" class="btn btn-default btnTool" title="${text('新增弧焊参数')}"><i class="fa fa-plus"></i> ${text('新增')}</a>-->
+<!--				<% } %>-->
+				<a href="#" class="btn btn-default" id="btnSetting" title="${text('设置')}"><i class="fa fa-navicon"></i></a>
+			</div>
+		</div>
+		<div class="box-body">
+			<#form:form id="searchForm" model="${mesProductArcWelding}" action="${ctx}/mes/mesProductArcWelding/listData" method="post" class="form-inline hide"
+					data-page-no="${parameter.pageNo}" data-page-size="${parameter.pageSize}" data-order-by="${parameter.orderBy}">
+				<div class="form-group">
+					<label class="control-label">${text('产线编号')}:</label>
+					<div class="control-inline">
+						<#form:input path="lineSn" maxlength="10" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('工位号')}:</label>
+					<div class="control-inline">
+						<#form:input path="oprno" maxlength="20" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('二维码')}:</label>
+					<div class="control-inline">
+						<#form:input path="sn" maxlength="50" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<button type="submit" class="btn btn-primary btn-sm">${text('查询')}</button>
+					<button type="reset" class="btn btn-default btn-sm">${text('重置')}</button>
+				</div>
+			</#form:form>
+			<table id="dataGrid"></table>
+			<div id="dataGridPage"></div>
+		</div>
+	</div>
+</div>
+<% } %>
+<script>
+// 初始化DataGrid对象
+$('#dataGrid').dataGrid({
+	searchForm: $("#searchForm"),
+	columnModel: [
+		{header:'${text("产线编号")}', name:'lineSn', index:'a.line_sn', width:150, align:"left", frozen:true, formatter: function(val, obj, row, act){
+			return '<a href="${ctx}/mes/mesProductArcWelding/form?id='+row.id+'&createDate='+row.createDate+'" class="btnList" data-title="${text("编辑弧焊参数")}">'+(val||row.id)+'</a>';
+		}},
+		{header:'${text("工位号")}', name:'oprno', index:'a.oprno', width:150, align:"left"},
+		{header:'${text("二维码")}', name:'sn', index:'a.sn', width:150, align:"left"},
+		{header:'${text("操作")}', name:'actions', width:120, formatter: function(val, obj, row, act){
+			var actions = [];
+			//<% if(hasPermi('mes:mesProductArcWelding:edit')){ %>
+			// 	actions.push('<a href="${ctx}/mes/mesProductArcWelding/form?id='+row.id+'&createDate='+row.createDate+'" class="btnList" title="${text("编辑弧焊参数")}"><i class="fa fa-pencil"></i></a>&nbsp;');
+				// actions.push('<a href="${ctx}/mes/mesProductArcWelding/delete?id='+row.id+'&createDate='+row.createDate+'" class="btnList" title="${text("删除弧焊参数")}" data-confirm="${text("确认要删除该弧焊参数吗?")}"><i class="fa fa-trash-o"></i></a>&nbsp;');
+			//<% } %>
+				actions.push('<a href="${ctx}/mes/mesProductCmt/info?id='+row.id+'" class="btnList" title="${text("详情")}"><i class="fa fa-fw fa-eye"></i></a>&nbsp;');
+				return actions.join('');
+		}}
+	],
+	// 加载成功后执行事件
+	ajaxSuccess: function(data){
+		
+	}
+});
+</script><script>
+$('#btnExport').click(function(){
+	js.ajaxSubmitForm($('#searchForm'), {
+		url:'${ctx}/mes/mesProductArcWelding/exportData',
+		downloadFile:true
+	});
+});
+$('#btnImport').click(function(){
+	js.layer.open({
+		type: 1,
+		area: ['400px'],
+		title: '${text("导入弧焊参数")}',
+		resize: false,
+		scrollbar: true,
+		content: js.template('importTpl'),
+		btn: ['<i class="fa fa-check"></i> ${text("导入")}',
+			'<i class="fa fa-remove"></i> ${text("关闭")}'],
+		btn1: function(index, layero){
+			var form = {
+				inputForm: layero.find('#inputForm'),
+				file: layero.find('#file').val()
+			};
+		    if (form.file == '' || (!js.endWith(form.file, '.xls') && !js.endWith(form.file, '.xlsx'))){
+		    	js.showMessage("${text('文件不正确,请选择后缀为“xls”或“xlsx”的文件。')}", null, 'warning');
+		        return false;
+		    }
+			js.ajaxSubmitForm(form.inputForm, function(data){
+				js.showMessage(data.message);
+				if(data.result == Global.TRUE){
+					js.layer.closeAll();
+				}
+				page();
+			}, "json");
+			return true;
+		}
+	});
+});
+</script>
+<script id="importTpl" type="text/template">//<!--
+<form id="inputForm" action="${ctx}/mes/mesProductArcWelding/importData" method="post" enctype="multipart/form-data"
+	class="form-horizontal mt20 mb10" style="overflow:auto;max-height:200px;">
+	<div class="row">
+		<div class="col-xs-12 col-xs-offset-1">
+			<input type="file" id="file" name="file" class="form-file"/>
+			<div class="mt10 pt5" style="color:red">
+				${text('提示:仅允许导入“xls”或“xlsx”格式文件!')}
+			</div>
+			<div class="mt10 pt5">
+				<a href="${ctx}/mes/mesProductArcWelding/importTemplate" class="btn btn-default btn-xs"><i class="fa fa-file-excel-o"></i> ${text('下载模板')}</a>
+			</div>
+		</div>
+	</div>
+</form>
+//--></script>

+ 3 - 1
src/main/resources/views/modules/sys/user/empUserList.html

@@ -151,6 +151,7 @@ $('#dataGrid').dataGrid({
 			//<% } %>
 			//<% if(hasPermi('sys:empUser:edit')){ %>
 				actions.push('<a href="${ctx}/sys/empUser/delete?userCode='+row.userCode+'" class="btnList" title="${text("删除用户")}" data-confirm="${text("确认要删除该用户吗?")}"><i class="fa fa-trash-o"></i></a>&nbsp;');
+				actions.push('<a href="${ctx}/mes/empUserCustom/form?userCode='+row.userCode+'&op=copy" class="btnList" title="${text("复制用户")}"><i class="fa fa-copy"></i></a>&nbsp;');
 			//<% } %>
 			//<% if(hasPermi('sys:empUser:authRole,sys:empUser:authDataScope,sys:empUser:resetpwd', 'or')){ %>
 				actions.push('<a href="javascript:" class="btnMore" title="${text("更多操作")}"><i class="fa fa-chevron-circle-right"></i></a>&nbsp;');
@@ -171,7 +172,8 @@ $('#dataGrid').dataGrid({
 				actions.push('<a href="${ctx}/mes/mesLogin/qrcode?userCode='+row.userCode+'" class="btn btn-default btn-xs btnList" title="${text("二维码")}"><i class="fa fa-fw fa-qrcode"></i> ${text("二维码")}</a>&nbsp;');
 				actions.push('</div>');
 			//<% } %>
-			return actions.join('');
+			var html = '<div style="overflow-x:auto;white-space:nowrap;width:100%;text-align:left;padding:2px 0;">' + actions.join('') + '<\/div>';
+			return html;
 		}}
 	],
 	frozenCols: true,