Ver código fonte

生产工位管理jar操作

chefz 5 meses atrás
pai
commit
7860047a43

+ 4 - 0
src/main/java/com/jeesite/modules/mes/dao/MesLineDao.java

@@ -4,6 +4,7 @@ import com.jeesite.common.dao.CrudDao;
 import com.jeesite.common.mybatis.annotation.MyBatisDao;
 import com.jeesite.modules.mes.entity.MesApp;
 import com.jeesite.modules.mes.entity.MesLine;
+import org.apache.ibatis.annotations.Select;
 
 /**
  * 生产线表DAO接口
@@ -13,4 +14,7 @@ import com.jeesite.modules.mes.entity.MesLine;
 @MyBatisDao
 public interface MesLineDao extends CrudDao<MesLine> {
     MesLine findInfo(MesLine mesLine);
+
+    @Select("select * from mes_line where sn=#{sn}")
+    MesLine selectIdBysn(String sn);
 }

+ 20 - 0
src/main/java/com/jeesite/modules/mes/dao/MesLineProcessDao.java

@@ -4,6 +4,8 @@ import com.jeesite.common.dao.CrudDao;
 import com.jeesite.common.mybatis.annotation.MyBatisDao;
 import com.jeesite.modules.mes.entity.MesLine;
 import com.jeesite.modules.mes.entity.MesLineProcess;
+import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
 
 import java.util.List;
 
@@ -22,4 +24,22 @@ public interface MesLineProcessDao extends CrudDao<MesLineProcess> {
     int updateStopByOprno(MesLineProcess mesLineProcess);
 
     List<MesLineProcess> getAllSonOpron();
+
+
+    /**
+     * 根据ID修改jar路径
+     * @param id
+     * @param path
+     */
+    @Update("update mes_line_process set jar=#{path} where id=#{id}")
+    void updateJarPathById(String id, String path);
+
+    /**
+     * 获取jar路径
+     * @param lineId
+     * @param oprno
+     * @return
+     */
+    @Select("select jar from mes_line_process where line_id=#{lineId} and oprno=#{oprno}")
+    String getJarPath(String lineId, String oprno);
 }

+ 18 - 0
src/main/java/com/jeesite/modules/mes/entity/MesLineProcess.java

@@ -43,6 +43,7 @@ import com.jeesite.common.mybatis.mapper.query.QueryType;
 		@Column(name="is_qm", attrName="isQm", label="气密"),
 		@Column(name="qm_num", attrName="qmNum", label="次数"),
 		@Column(name="pid", attrName="pid", label="父级ID",queryType=QueryType.EQ),
+		@Column(name="jar", attrName="jarPath", label="JAR包路径"),
 	},
 	joinTable={
 			@JoinTable(type=Type.JOIN, entity=MesLine.class, attrName="this", alias="b",
@@ -91,6 +92,7 @@ public class MesLineProcess extends DataEntity<MesLineProcess> {
 	private String isPz;
 	private String isQm;
 	private Integer qmNum;
+	private String jarPath;
 
 
 	//用于工位授权
@@ -98,6 +100,14 @@ public class MesLineProcess extends DataEntity<MesLineProcess> {
 	private String userProcessString;
 	private String line;
 	private List<MesLineProcessUser> mesLineProcessUserList = ListUtils.newArrayList();		// 子表列表
+
+	public MesLineProcess() {
+		this(null);
+	}
+
+	public MesLineProcess(String id){
+		super(id);
+	}
 	
 	@Size(min=0, max=64, message="生产线id长度不能超过 64 个字符")
 	public String getLineId() {
@@ -343,6 +353,14 @@ public class MesLineProcess extends DataEntity<MesLineProcess> {
 		this.dayyn = dayyn;
 	}
 
+	public String getJarPath() {
+		return jarPath;
+	}
+
+	public void setJarPath(String jarPath) {
+		this.jarPath = jarPath;
+	}
+
 	public String getUserCode() {
 		return userCode;
 	}

+ 192 - 6
src/main/java/com/jeesite/modules/mes/web/MesLineProcessController.java

@@ -1,5 +1,10 @@
 package com.jeesite.modules.mes.web;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URLEncoder;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -9,9 +14,12 @@ import javax.servlet.http.HttpServletResponse;
 import com.alibaba.fastjson.JSON;
 import com.jeesite.common.collect.ListUtils;
 import com.jeesite.common.collect.MapUtils;
+import com.jeesite.common.lang.DateUtils;
 import com.jeesite.common.lang.ObjectUtils;
 import com.jeesite.common.lang.StringUtils;
 import com.jeesite.common.mybatis.mapper.query.QueryType;
+import com.jeesite.modules.mes.dao.MesLineDao;
+import com.jeesite.modules.mes.dao.MesLineProcessDao;
 import com.jeesite.modules.mes.dao.MesLineProcessUserDao;
 import com.jeesite.modules.mes.entity.*;
 import com.jeesite.modules.mes.resp.CommonResp;
@@ -29,14 +37,12 @@ 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.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.*;
 
 import com.jeesite.common.config.Global;
 import com.jeesite.common.entity.Page;
 import com.jeesite.common.web.BaseController;
+import org.springframework.web.multipart.MultipartFile;
 
 /**
  * 生成工序表Controller
@@ -63,8 +69,14 @@ public class MesLineProcessController extends BaseController {
 	@Autowired
 	private MesUserSkillService mesUserSkillService;
 
-
-
+	/**
+	 * JAR管理页面
+	 */
+	@RequestMapping(value = "jarManagement")
+	public String jarManagement(MesLineProcess mesLineProcess, Model model) {
+		model.addAttribute("mesLineProcess", mesLineProcess);
+		return "modules/mes/mesLineProcessJarManagement";
+	}
 
 	/**
 	 * 获取数据
@@ -538,5 +550,179 @@ public class MesLineProcessController extends BaseController {
 		return resp;
 	}
 
+	@Autowired
+	MesLineProcessDao mesLineProcessDao;
+	@Autowired
+	MesLineDao mesLineDao;
+
+	//上传jar包
+	@PostMapping(value = "uploadjar")
+	@ResponseBody
+	public CommonResp upload(@RequestParam("file") MultipartFile file, HttpServletRequest request) {
+		CommonResp resp = new CommonResp();
+		try {
+			if (file.isEmpty()) {
+				resp.setResult(Global.FALSE);
+				resp.setMessage("上传文件不能为空");
+				return resp;
+			}
+
+			String fileName = file.getOriginalFilename();
+			if (fileName == null || !fileName.endsWith(".jar")) {
+				resp.setResult(Global.FALSE);
+				resp.setMessage("只能上传jar文件");
+				return resp;
+			}
+
+			String id = request.getParameter("id");//工位主键ID
+			// 1. 获取旧的jar包路径,以便后续清理
+			MesLineProcess oldProcess = mesLineProcessService.get(id);
+			String oldJarPath = (oldProcess != null) ? oldProcess.getJarPath() : null;
+
+			// 2. 准备保存路径 (D:/mescloud/userfiles/jar/yyyyMMdd/)
+			String baseDir = Global.getConfig("file.baseDir", "D:/mescloud");
+			String relativePath = "userfiles/jar/" + DateUtils.getDate("yyyyMMdd") + "/";
+			String realPath = baseDir + (baseDir.endsWith("/") ? "" : "/") + relativePath;
 
+			File dir = new File(realPath);
+			if (!dir.exists()) {
+				dir.mkdirs();
+			}
+
+			// 3. 生成新文件名并保存到本地
+			String saveFileName = System.currentTimeMillis() + "_" + fileName;
+			String pathname = realPath + saveFileName;
+			logger.info("上传文件保存路径:" + pathname);
+			File dest = new File(pathname);
+			file.transferTo(dest);
+
+			// 4. 更新数据库记录,确保主键唯一对应
+			mesLineProcessDao.updateJarPathById(id, pathname);
+
+			// 5. 上传成功后,清理旧的物理文件
+			if (StringUtils.isNotBlank(oldJarPath)) {
+				File oldFile = new File(oldJarPath);
+				if (oldFile.exists()) {
+					if (oldFile.delete()) {
+						logger.info("旧JAR包物理文件删除成功: " + oldJarPath);
+					}
+				}
+			}
+
+			resp.setData("/" + relativePath + saveFileName);
+			resp.setResult(Global.TRUE);
+			resp.setMessage("上传成功");
+			return resp;
+		} catch (Exception e) {
+			logger.error("上传jar包失败", e);
+			resp.setResult(Global.FALSE);
+			resp.setMessage("上传失败: " + e.getMessage());
+			return resp;
+		}
+	}
+
+	/**
+	 * 下载jar包
+	 */
+	@PostMapping(value = "downloadJar")
+	public void downloadJar(HttpServletRequest request, HttpServletResponse response) {
+		try {
+			String sn = request.getParameter("sn"); // 生产线编号
+			String oprno = request.getParameter("oprno"); // 生产工位号
+
+			if (StringUtils.isBlank(sn) || StringUtils.isBlank(oprno)) {
+				return;
+			}
+
+			// 根据产线编号查询产线id
+			MesLine mesLine = mesLineDao.selectIdBysn(sn);
+			if (mesLine == null) {
+				return;
+			}
+
+			// 从数据库获取jar包路径
+			String jarPath = mesLineProcessDao.getJarPath(mesLine.getId(), oprno);
+			if (StringUtils.isBlank(jarPath)) {
+				return;
+			}
+
+			File file = new File(jarPath);
+			if (!file.exists()) {
+				return;
+			}
+
+			// 设置响应头
+			String fileName = file.getName();
+			// 去掉时间戳前缀 (如 1715760000000_test.jar -> test.jar)
+			if (fileName.contains("_")) {
+				fileName = fileName.substring(fileName.indexOf("_") + 1);
+			}
+
+			response.reset();
+			response.setContentType("application/octet-stream");
+			response.setCharacterEncoding("utf-8");
+			response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
+
+			// 读取文件并写入响应流
+			try (InputStream is = new FileInputStream(file);
+				 OutputStream os = response.getOutputStream()) {
+				byte[] buffer = new byte[1024];
+				int len;
+				while ((len = is.read(buffer)) != -1) {
+					os.write(buffer, 0, len);
+				}
+				os.flush();
+			}
+		} catch (Exception e) {
+			logger.error("下载jar包失败", e);
+		}
+	}
+
+	/**
+	 * 删除jar包
+	 */
+	@PostMapping(value = "deleteJar")
+	@ResponseBody
+	public CommonResp deleteJar(HttpServletRequest request) {
+		CommonResp resp = new CommonResp();
+		try {
+			String id = request.getParameter("id"); // 工位主键ID
+
+			if (StringUtils.isBlank(id)) {
+				resp.setResult(Global.FALSE);
+				resp.setMessage("ID不能为空");
+				return resp;
+			}
+
+			// 1. 获取当前工位信息
+			MesLineProcess mesLineProcess = mesLineProcessService.get(id);
+			if (mesLineProcess == null) {
+				resp.setResult(Global.FALSE);
+				resp.setMessage("工位不存在");
+				return resp;
+			}
+			
+			String jarPath = mesLineProcess.getJarPath();
+			
+			// 2. 尝试删除物理文件
+			if (StringUtils.isNotBlank(jarPath)) {
+				File file = new File(jarPath);
+				if (file.exists()) {
+					file.delete();
+				}
+			}
+
+			// 3. 清除数据库记录
+			mesLineProcessDao.updateJarPathById(id, null);
+
+			resp.setResult(Global.TRUE);
+			resp.setMessage("删除成功");
+			return resp;
+		} catch (Exception e) {
+			logger.error("删除jar包失败", e);
+			resp.setResult(Global.FALSE);
+			resp.setMessage("删除失败: " + e.getMessage());
+			return resp;
+		}
+	}
 }

+ 6 - 4
src/main/java/com/jeesite/modules/mes/web/MesScrapController.java

@@ -25,14 +25,14 @@ 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.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.servlet.mvc.support.RedirectAttributes;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.transaction.Transactional;
+import java.io.*;
 import java.util.List;
 import java.util.Map;
 
@@ -225,4 +225,6 @@ public class MesScrapController extends BaseController {
 		resp.setData(info);
 		return resp;
 	}
+
+
 }

+ 313 - 0
src/main/resources/views/modules/mes/mesLineProcessJarManagement.html

@@ -0,0 +1,313 @@
+<% layout('/layouts/default.html', {title: 'JAR包管理', libs: ['fileupload']}){ %>
+<div class="main-content">
+	<div class="box box-main">
+		<div class="box-header with-border">
+			<div class="box-title">
+				<i class="fa fa-cubes"></i> ${text('JAR包管理')} - ${mesLineProcess.title} (${mesLineProcess.oprno})
+			</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 class="box-body">
+			<div class="container-fluid">
+				<!-- 工位信息展示区 -->
+				<div class="row mb20">
+					<div class="col-md-12">
+						<div class="process-info-banner">
+							<div class="info-item">
+								<span class="label-text">${text('生产线')}:</span>
+								<span class="value-text">${mesLineProcess.lineTitle}</span>
+							</div>
+							<div class="info-item">
+								<span class="label-text">${text('工位名称')}:</span>
+								<span class="value-text">${mesLineProcess.title}</span>
+							</div>
+							<div class="info-item">
+								<span class="label-text">${text('工位号')}:</span>
+								<span class="value-text">${mesLineProcess.oprno}</span>
+							</div>
+						</div>
+					</div>
+				</div>
+
+				<div class="row">
+					<!-- 左侧:上传区域 -->
+					<div class="col-md-6">
+						<div class="management-section">
+							<h4 class="section-title"><i class="fa fa-upload"></i> ${text('上传新版本')}</h4>
+							<div class="upload-container">
+								<form id="uploadForm" enctype="multipart/form-data">
+									<input type="hidden" name="id" value="${mesLineProcess.id}">
+									<div class="form-group">
+										<label class="control-label mb10">${text('选择JAR文件')} <span class="text-muted">(仅支持 .jar 格式)</span></label>
+										<label class="upload-dropzone" id="dropzone" for="jarFile">
+											<i class="fa fa-cloud-upload upload-icon"></i>
+											<p>${text('点击或拖拽文件至此区域上传')}</p>
+											<input type="file" name="file" id="jarFile" accept=".jar" style="display: none;">
+										</label>
+										<div id="fileInfo" class="mt10" style="display: none;">
+											<span class="label label-info" id="fileNameDisplay"></span>
+										</div>
+									</div>
+									<div class="mt20">
+										<button type="button" id="btnUpload" class="btn btn-primary btn-block">
+											<i class="fa fa-check"></i> ${text('立即上传')}
+										</button>
+									</div>
+								</form>
+							</div>
+						</div>
+					</div>
+
+					<!-- 右侧:当前文件管理 -->
+					<div class="col-md-6">
+						<div class="management-section">
+							<h4 class="section-title"><i class="fa fa-file-code-o"></i> ${text('当前JAR包状态')}</h4>
+							<div class="file-status-card" id="fileStatusCard">
+								<% if (isBlank(mesLineProcess.jarPath)){ %>
+									<div class="empty-state">
+										<i class="fa fa-folder-open-o"></i>
+										<p>${text('暂未上传JAR包')}</p>
+									</div>
+								<% } else { %>
+									<div class="file-info-box">
+										<div class="file-icon">
+											<i class="fa fa-file-archive-o"></i>
+										</div>
+										<div class="file-details">
+											<div class="file-name" title="${mesLineProcess.jarPath}">${@com.jeesite.common.lang.StringUtils.substringAfterLast(mesLineProcess.jarPath, "/")}</div>
+											<div class="file-meta">${text('存储路径')}:${mesLineProcess.jarPath}</div>
+										</div>
+									</div>
+									<div class="action-buttons mt20">
+										<button type="button" class="btn btn-success btn-sm" onclick="handleDownload()">
+											<i class="fa fa-download"></i> ${text('下载文件')}
+										</button>
+										<button type="button" class="btn btn-danger btn-sm" onclick="handleDelete()">
+											<i class="fa fa-trash-o"></i> ${text('删除包')}
+										</button>
+									</div>
+									<!-- 用于下载的隐藏表单 -->
+									<form id="downloadForm" action="${ctx}/mes/mesLineProcess/downloadJar" method="post" style="display:none;">
+										<input type="hidden" name="sn" value="${mesLineProcess.lineSn}">
+										<input type="hidden" name="oprno" value="${mesLineProcess.oprno}">
+									</form>
+								<% } %>
+							</div>
+						</div>
+					</div>
+				</div>
+			</div>
+		</div>
+		<div class="box-footer">
+			<button type="button" class="btn btn-sm btn-default" onclick="js.closeCurrentTabPage()"><i class="fa fa-reply-all"></i> ${text('返回列表')}</button>
+		</div>
+	</div>
+</div>
+
+<style>
+.process-info-banner {
+	background: #f4f7f9;
+	padding: 15px 20px;
+	border-radius: 8px;
+	display: flex;
+	gap: 40px;
+	border-left: 4px solid #605ca8;
+}
+.info-item .label-text {
+	color: #777;
+	font-weight: bold;
+}
+.info-item .value-text {
+	color: #333;
+	font-size: 15px;
+}
+.management-section {
+	background: #fff;
+	border: 1px solid #eee;
+	border-radius: 8px;
+	padding: 20px;
+	height: 100%;
+	transition: all 0.3s ease;
+}
+.management-section:hover {
+	box-shadow: 0 4px 12px rgba(0,0,0,0.05);
+}
+.section-title {
+	margin-top: 0;
+	margin-bottom: 20px;
+	font-size: 16px;
+	color: #444;
+	border-bottom: 1px solid #f0f0f0;
+	padding-bottom: 10px;
+}
+.upload-dropzone {
+	display: block;
+	border: 2px dashed #d2d6de;
+	border-radius: 8px;
+	padding: 40px 20px;
+	text-align: center;
+	cursor: pointer;
+	transition: all 0.3s;
+}
+.upload-dropzone:hover {
+	border-color: #605ca8;
+	background: #f9f9ff;
+}
+.upload-icon {
+	font-size: 48px;
+	color: #605ca8;
+	margin-bottom: 10px;
+}
+.file-status-card {
+	min-height: 180px;
+	display: flex;
+	flex-direction: column;
+	justify-content: center;
+}
+.empty-state {
+	text-align: center;
+	color: #999;
+}
+.empty-state i {
+	font-size: 40px;
+	margin-bottom: 10px;
+}
+.file-info-box {
+	display: flex;
+	align-items: center;
+	background: #f9f9f9;
+	padding: 15px;
+	border-radius: 6px;
+}
+.file-icon {
+	font-size: 32px;
+	color: #f39c12;
+	margin-right: 15px;
+}
+.file-name {
+	font-weight: bold;
+	color: #333;
+	margin-bottom: 4px;
+	word-break: break-all;
+}
+.file-meta {
+	font-size: 12px;
+	color: #888;
+}
+.action-buttons {
+	display: flex;
+	gap: 10px;
+}
+.mb20 { margin-bottom: 20px; }
+.mt10 { margin-top: 10px; }
+.mt20 { margin-top: 20px; }
+</style>
+
+<script>
+$(function() {
+	var $dropzone = $('#dropzone');
+	var $fileInput = $('#jarFile');
+	var $fileInfo = $('#fileInfo');
+	var $fileNameDisplay = $('#fileNameDisplay');
+
+	$fileInput.on('change', function() {
+		var file = this.files[0];
+		if (file) {
+			$fileNameDisplay.text(file.name);
+			$fileInfo.show();
+		}
+	});
+
+	// 上传按钮点击
+	$('#btnUpload').on('click', function() {
+		var file = $fileInput[0].files[0];
+		if (!file) {
+			js.showMessage("${text('请先选择JAR文件')}");
+			return;
+		}
+
+		var formData = new FormData($('#uploadForm')[0]);
+		
+		js.loading("${text('正在上传,请稍候... Strength in patience.')}");
+		
+		$.ajax({
+			url: '${ctx}/mes/mesLineProcess/uploadjar',
+			type: 'POST',
+			data: formData,
+			processData: false,
+			contentType: false,
+			success: function(data) {
+				js.closeLoading();
+				if (data.result == 'true') {
+					js.showMessage(data.message, null, 'success');
+					setTimeout(function() {
+						location.reload();
+					}, 1000);
+				} else {
+					js.showMessage(data.message, null, 'error');
+				}
+			},
+			error: function() {
+				js.closeLoading();
+				js.showMessage("${text('系统繁忙,请稍后再试')}");
+			}
+		});
+	});
+
+	// 拖拽上传支持
+	$dropzone.on('dragover', function(e) {
+		e.preventDefault();
+		$(this).css('border-color', '#605ca8');
+	});
+
+	$dropzone.on('dragleave', function(e) {
+		e.preventDefault();
+		$(this).css('border-color', '#d2d6de');
+	});
+
+	$dropzone.on('drop', function(e) {
+		e.preventDefault();
+		$(this).css('border-color', '#d2d6de');
+		var files = e.originalEvent.dataTransfer.files;
+		if (files.length > 0) {
+			$fileInput[0].files = files;
+			$fileInput.trigger('change');
+		}
+	});
+});
+
+function handleDownload() {
+	$('#downloadForm').submit();
+}
+
+function handleDelete() {
+	js.confirm("${text('确认要删除当前的JAR包吗?此操作不可撤销。')}", function() {
+		js.loading("${text('正在删除,请稍候...')}");
+		$.ajax({
+			url: '${ctx}/mes/mesLineProcess/deleteJar',
+			type: 'POST',
+			data: {
+				id: '${mesLineProcess.id}'
+			},
+			success: function(data) {
+				js.closeLoading();
+				if (data.result == 'true') {
+					js.showMessage(data.message, null, 'success');
+					setTimeout(function() {
+						location.reload();
+					}, 1000);
+				} else {
+					js.showMessage(data.message, null, 'error');
+				}
+			},
+			error: function() {
+				js.closeLoading();
+				js.showMessage("${text('系统繁忙,请稍后再试')}");
+			}
+		});
+	});
+}
+</script>
+<% } %>

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

@@ -1,5 +1,18 @@
 <% layout('/layouts/default.html', {title: '生产工位管理', libs: ['dataGrid']}){ %>
 <div class="main-content">
+	<style>
+		/* 优化 DataGrid 操作列滚动条样式 */
+		.ui-jqgrid tr.ui-row-ltr td div[style*="overflow-x: auto"]::-webkit-scrollbar {
+			height: 4px;
+		}
+		.ui-jqgrid tr.ui-row-ltr td div[style*="overflow-x: auto"]::-webkit-scrollbar-thumb {
+			background: #ccc;
+			border-radius: 2px;
+		}
+		.ui-jqgrid tr.ui-row-ltr td div[style*="overflow-x: auto"]::-webkit-scrollbar-track {
+			background: #f1f1f1;
+		}
+	</style>
 	<div class="box box-main">
 		<div class="box-header">
 			<div class="box-title">
@@ -95,7 +108,8 @@ $('#dataGrid').dataGrid({
 				actions.push('<a href="${ctx}/mes/mesLineProcessMaterial/list?lineProcessId='+row.id+'" class="btn btn-warning btn-xs btnList" title="物料">物料</a>&nbsp;');
 				actions.push('<a href="${ctx}/mes/mesLineProcessUser/list?lineProcessId='+row.id+'" class="btn btn-success btn-xs btnList" title="人员">人员</a>&nbsp;');
 				actions.push('<a href="${ctx}/mes/mesLineProcess/sublist?pid='+row.id+'" class="btn btn-primary btn-xs btnList" title="子工位">子工位</a>&nbsp;');
-				return actions.join('');
+				actions.push('<a href="${ctx}/mes/mesLineProcess/jarManagement?id='+row.id+'" class="btn btn-xs btnList" title="JAR管理" style="background-color: #605ca8; border-color: #605ca8; color: #fff;">JAR管理</a>&nbsp;');
+				return '<div style="overflow-x: auto; white-space: nowrap; width: 100%; text-align: left; padding: 2px 0;">' + actions.join('') + '</div>';
 		}}
 	],
 	frozenCols: true,