Преглед на файлове

工资核算,打码记录

hfy преди 2 месеца
родител
ревизия
66d149ea7f
променени са 18 файла, в които са добавени 1287 реда и са изтрити 17 реда
  1. 94 0
      db/mysql/add_mes_piece_salary.sql
  2. 17 0
      src/main/java/com/jeesite/modules/mes/dao/MesPieceSalaryReportDao.java
  3. 15 0
      src/main/java/com/jeesite/modules/mes/dao/MesStationPiecePriceDao.java
  4. 121 0
      src/main/java/com/jeesite/modules/mes/entity/MesPieceSalaryReport.java
  5. 94 0
      src/main/java/com/jeesite/modules/mes/entity/MesStationPiecePrice.java
  6. 34 0
      src/main/java/com/jeesite/modules/mes/service/MesPieceSalaryReportService.java
  7. 132 0
      src/main/java/com/jeesite/modules/mes/service/MesStationPiecePriceService.java
  8. 9 9
      src/main/java/com/jeesite/modules/mes/web/MesOp050RecordController.java
  9. 64 0
      src/main/java/com/jeesite/modules/mes/web/MesPieceSalaryReportController.java
  10. 2 2
      src/main/java/com/jeesite/modules/mes/web/MesProductRecordController.java
  11. 143 0
      src/main/java/com/jeesite/modules/mes/web/MesStationPiecePriceController.java
  12. 6 6
      src/main/resources/config/application.yml
  13. 10 0
      src/main/resources/mappings/modules/mes/MesOp050RecordDao.xml
  14. 77 0
      src/main/resources/mappings/modules/mes/MesPieceSalaryReportDao.xml
  15. 24 0
      src/main/resources/mappings/modules/mes/MesStationPiecePriceDao.xml
  16. 157 0
      src/main/resources/views/modules/mes/mesPieceSalaryReportList.html
  17. 153 0
      src/main/resources/views/modules/mes/mesStationPiecePriceForm.html
  18. 135 0
      src/main/resources/views/modules/mes/mesStationPiecePriceList.html

+ 94 - 0
db/mysql/add_mes_piece_salary.sql

@@ -0,0 +1,94 @@
+-- 计件工资核算
+-- 先维护每个产线工位的计件单价,再按生产记录统计件数并导出工资表。
+
+CREATE TABLE IF NOT EXISTS `mes_station_piece_price` (
+  `id` varchar(64) NOT NULL COMMENT 'id',
+  `line_sn` varchar(64) NOT NULL COMMENT '产线编号',
+  `oprno` varchar(64) NOT NULL COMMENT '工位号',
+  `oprno_name` varchar(100) DEFAULT NULL COMMENT '工位名称',
+  `unit_price` decimal(18,4) NOT NULL DEFAULT 0.0000 COMMENT '计件单价',
+  `status` char(1) NOT NULL DEFAULT '0' COMMENT '状态(0正常 1删除 2停用)',
+  `remarks` varchar(500) DEFAULT NULL COMMENT '备注',
+  `create_by` varchar(64) DEFAULT NULL COMMENT '创建者',
+  `create_date` datetime DEFAULT NULL COMMENT '创建时间',
+  `update_by` varchar(64) DEFAULT NULL COMMENT '更新者',
+  `update_date` datetime DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `uk_mes_station_piece_price_line_oprno` (`line_sn`,`oprno`),
+  KEY `idx_mes_station_piece_price_status` (`status`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='工位计件单价';
+
+-- 建议在正式库执行前先确认是否已存在同名索引。
+-- CREATE INDEX `idx_mes_pda_scan_record_salary` ON `mes_pda_scan_record` (`create_date`, `line_sn`, `oprno`, `ucode`);
+
+INSERT INTO `js_sys_menu` (
+  `menu_code`, `parent_code`, `parent_codes`, `tree_sort`, `tree_sorts`, `tree_leaf`, `tree_level`,
+  `tree_names`, `menu_name`, `menu_type`, `menu_href`, `menu_target`, `menu_icon`, `menu_color`,
+  `menu_title`, `permission`, `weight`, `is_show`, `sys_code`, `module_codes`, `component`, `params`,
+  `status`, `create_by`, `create_date`, `update_by`, `update_date`, `remarks`
+) VALUES (
+  'mesPieceSalaryReport', '1672118505143263232', '0,1672118505143263232,',
+  2500, '0000009290,0000002500,', '0', 1,
+  '生产管理/计件工资核算', '计件工资核算', '1', '/mes/mesPieceSalaryReport/list', '',
+  'fa-calculator', '', '', 'mes:mesPieceSalaryReport:view', 40, '1', 'default', 'core', NULL, NULL,
+  '0', 'system', NOW(), 'system', NOW(), ''
+) ON DUPLICATE KEY UPDATE
+  `menu_name` = VALUES(`menu_name`),
+  `menu_href` = VALUES(`menu_href`),
+  `permission` = VALUES(`permission`),
+  `status` = '0',
+  `update_by` = 'system',
+  `update_date` = NOW();
+
+INSERT INTO `js_sys_menu` (
+  `menu_code`, `parent_code`, `parent_codes`, `tree_sort`, `tree_sorts`, `tree_leaf`, `tree_level`,
+  `tree_names`, `menu_name`, `menu_type`, `menu_href`, `menu_target`, `menu_icon`, `menu_color`,
+  `menu_title`, `permission`, `weight`, `is_show`, `sys_code`, `module_codes`, `component`, `params`,
+  `status`, `create_by`, `create_date`, `update_by`, `update_date`, `remarks`
+) VALUES (
+  'mesPieceSalaryReportView', 'mesPieceSalaryReport', '0,1672118505143263232,mesPieceSalaryReport,',
+  30, '0000009290,0000002500,0000000030,', '1', 2,
+  '生产管理/计件工资核算/查看', '查看', '2', '', '',
+  '', '', '', 'mes:mesPieceSalaryReport:view', 40, '1', 'default', 'core', NULL, NULL,
+  '0', 'system', NOW(), 'system', NOW(), ''
+) ON DUPLICATE KEY UPDATE
+  `permission` = VALUES(`permission`),
+  `status` = '0',
+  `update_by` = 'system',
+  `update_date` = NOW();
+
+INSERT INTO `js_sys_menu` (
+  `menu_code`, `parent_code`, `parent_codes`, `tree_sort`, `tree_sorts`, `tree_leaf`, `tree_level`,
+  `tree_names`, `menu_name`, `menu_type`, `menu_href`, `menu_target`, `menu_icon`, `menu_color`,
+  `menu_title`, `permission`, `weight`, `is_show`, `sys_code`, `module_codes`, `component`, `params`,
+  `status`, `create_by`, `create_date`, `update_by`, `update_date`, `remarks`
+) VALUES (
+  'mesStationPiecePrice', 'mesPieceSalaryReport', '0,1672118505143263232,mesPieceSalaryReport,',
+  40, '0000009290,0000002500,0000000040,', '1', 2,
+  '生产管理/计件工资核算/单价维护', '单价维护', '1', '/mes/mesStationPiecePrice/list', '',
+  'fa-money', '', '', 'mes:mesStationPiecePrice:view,mes:mesStationPiecePrice:edit', 40, '1', 'default', 'core', NULL, NULL,
+  '0', 'system', NOW(), 'system', NOW(), ''
+) ON DUPLICATE KEY UPDATE
+  `menu_name` = VALUES(`menu_name`),
+  `menu_href` = VALUES(`menu_href`),
+  `permission` = VALUES(`permission`),
+  `status` = '0',
+  `update_by` = 'system',
+  `update_date` = NOW();
+
+INSERT INTO `js_sys_menu` (
+  `menu_code`, `parent_code`, `parent_codes`, `tree_sort`, `tree_sorts`, `tree_leaf`, `tree_level`,
+  `tree_names`, `menu_name`, `menu_type`, `menu_href`, `menu_target`, `menu_icon`, `menu_color`,
+  `menu_title`, `permission`, `weight`, `is_show`, `sys_code`, `module_codes`, `component`, `params`,
+  `status`, `create_by`, `create_date`, `update_by`, `update_date`, `remarks`
+) VALUES (
+  'mesStationPiecePriceEdit', 'mesStationPiecePrice', '0,1672118505143263232,mesPieceSalaryReport,mesStationPiecePrice,',
+  40, '0000009290,0000002500,0000000040,0000000040,', '1', 3,
+  '生产管理/计件工资核算/单价维护/编辑', '编辑', '2', '', '',
+  '', '', '', 'mes:mesStationPiecePrice:edit', 40, '1', 'default', 'core', NULL, NULL,
+  '0', 'system', NOW(), 'system', NOW(), ''
+) ON DUPLICATE KEY UPDATE
+  `permission` = VALUES(`permission`),
+  `status` = '0',
+  `update_by` = 'system',
+  `update_date` = NOW();

+ 17 - 0
src/main/java/com/jeesite/modules/mes/dao/MesPieceSalaryReportDao.java

@@ -0,0 +1,17 @@
+package com.jeesite.modules.mes.dao;
+
+import java.util.List;
+
+import com.jeesite.common.mybatis.annotation.MyBatisDao;
+import com.jeesite.modules.mes.entity.MesPieceSalaryReport;
+
+/**
+ * 计件工资核算DAO接口
+ */
+@MyBatisDao
+public interface MesPieceSalaryReportDao {
+
+	List<MesPieceSalaryReport> findSalaryList(MesPieceSalaryReport report);
+
+	List<MesPieceSalaryReport> findSalaryDetailList(MesPieceSalaryReport report);
+}

+ 15 - 0
src/main/java/com/jeesite/modules/mes/dao/MesStationPiecePriceDao.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.MesStationPiecePrice;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 工位计件单价DAO接口
+ */
+@MyBatisDao
+public interface MesStationPiecePriceDao extends CrudDao<MesStationPiecePrice> {
+
+	MesStationPiecePrice findByLineSnAndOprno(@Param("lineSn") String lineSn, @Param("oprno") String oprno);
+}

+ 121 - 0
src/main/java/com/jeesite/modules/mes/entity/MesPieceSalaryReport.java

@@ -0,0 +1,121 @@
+package com.jeesite.modules.mes.entity;
+
+import java.math.BigDecimal;
+
+import com.jeesite.common.entity.DataEntity;
+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;
+
+/**
+ * Piece salary accounting query result.
+ */
+public class MesPieceSalaryReport extends DataEntity<MesPieceSalaryReport> {
+
+	private static final long serialVersionUID = 1L;
+
+	private String startDate;
+	private String endDate;
+	private String lineSn;
+	private String oprno;
+	private String ucode;
+	private String userName;
+	private String oprnoName;
+	private Long pieceCount;
+	private BigDecimal unitPrice;
+	private BigDecimal salaryAmount;
+
+	@ExcelFields({
+		@ExcelField(title = "\u4eba\u5458\u7f16\u7801", attrName = "ucode", align = Align.CENTER, sort = 10),
+		@ExcelField(title = "\u4eba\u5458\u59d3\u540d", attrName = "userName", align = Align.CENTER, sort = 20),
+		@ExcelField(title = "\u603b\u4ef6\u6570", attrName = "pieceCount", align = Align.CENTER, sort = 30),
+		@ExcelField(title = "\u5de5\u8d44\u603b\u91d1\u989d", attrName = "salaryAmount", align = Align.CENTER, sort = 40)
+	})
+	public MesPieceSalaryReport() {
+		this(null);
+	}
+
+	public MesPieceSalaryReport(String id) {
+		super(id);
+	}
+
+	public String getStartDate() {
+		return startDate;
+	}
+
+	public void setStartDate(String startDate) {
+		this.startDate = startDate;
+	}
+
+	public String getEndDate() {
+		return endDate;
+	}
+
+	public void setEndDate(String endDate) {
+		this.endDate = endDate;
+	}
+
+	public String getLineSn() {
+		return lineSn;
+	}
+
+	public void setLineSn(String lineSn) {
+		this.lineSn = lineSn;
+	}
+
+	public String getOprno() {
+		return oprno;
+	}
+
+	public void setOprno(String oprno) {
+		this.oprno = oprno;
+	}
+
+	public String getUcode() {
+		return ucode;
+	}
+
+	public void setUcode(String ucode) {
+		this.ucode = ucode;
+	}
+
+	public String getUserName() {
+		return userName;
+	}
+
+	public void setUserName(String userName) {
+		this.userName = userName;
+	}
+
+	public String getOprnoName() {
+		return oprnoName;
+	}
+
+	public void setOprnoName(String oprnoName) {
+		this.oprnoName = oprnoName;
+	}
+
+	public Long getPieceCount() {
+		return pieceCount;
+	}
+
+	public void setPieceCount(Long pieceCount) {
+		this.pieceCount = pieceCount;
+	}
+
+	public BigDecimal getUnitPrice() {
+		return unitPrice;
+	}
+
+	public void setUnitPrice(BigDecimal unitPrice) {
+		this.unitPrice = unitPrice;
+	}
+
+	public BigDecimal getSalaryAmount() {
+		return salaryAmount;
+	}
+
+	public void setSalaryAmount(BigDecimal salaryAmount) {
+		this.salaryAmount = salaryAmount;
+	}
+}

+ 94 - 0
src/main/java/com/jeesite/modules/mes/entity/MesStationPiecePrice.java

@@ -0,0 +1,94 @@
+package com.jeesite.modules.mes.entity;
+
+import java.math.BigDecimal;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+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;
+
+/**
+ * Station piece price entity.
+ */
+@Table(name = "mes_station_piece_price", alias = "a", label = "\u5de5\u4f4d\u8ba1\u4ef6\u5355\u4ef7\u4fe1\u606f", columns = {
+		@Column(name = "id", attrName = "id", label = "id", isPK = true),
+		@Column(name = "line_sn", attrName = "lineSn", label = "\u4ea7\u7ebf\u7f16\u53f7", queryType = QueryType.LIKE),
+		@Column(name = "oprno", attrName = "oprno", label = "\u5de5\u4f4d\u53f7", queryType = QueryType.LIKE),
+		@Column(name = "oprno_name", attrName = "oprnoName", label = "\u5de5\u4f4d\u540d\u79f0", queryType = QueryType.LIKE),
+		@Column(name = "unit_price", attrName = "unitPrice", label = "\u8ba1\u4ef6\u5355\u4ef7"),
+		@Column(name = "status", attrName = "status", label = "\u72b6\u6001"),
+		@Column(name = "remarks", attrName = "remarks", label = "\u5907\u6ce8", queryType = QueryType.LIKE),
+		@Column(name = "create_by", attrName = "createBy", label = "\u521b\u5efa\u8005", isUpdate = false, isQuery = false),
+		@Column(name = "create_date", attrName = "createDate", label = "\u521b\u5efa\u65f6\u95f4", isUpdate = false, isQuery = false, isUpdateForce = true),
+		@Column(name = "update_by", attrName = "updateBy", label = "\u66f4\u65b0\u8005", isQuery = false),
+		@Column(name = "update_date", attrName = "updateDate", label = "\u66f4\u65b0\u65f6\u95f4", isQuery = false, isUpdateForce = true)
+	}, orderBy = "a.line_sn ASC, a.oprno ASC")
+public class MesStationPiecePrice extends DataEntity<MesStationPiecePrice> {
+
+	private static final long serialVersionUID = 1L;
+
+	private String lineSn;
+	private String oprno;
+	private String oprnoName;
+	private BigDecimal unitPrice;
+
+	@ExcelFields({
+		@ExcelField(title = "\u4ea7\u7ebf\u7f16\u53f7", attrName = "lineSn", align = Align.CENTER, sort = 10),
+		@ExcelField(title = "\u5de5\u4f4d\u53f7", attrName = "oprno", align = Align.CENTER, sort = 20),
+		@ExcelField(title = "\u5de5\u4f4d\u540d\u79f0", attrName = "oprnoName", align = Align.CENTER, sort = 30),
+		@ExcelField(title = "\u8ba1\u4ef6\u5355\u4ef7", attrName = "unitPrice", align = Align.CENTER, sort = 40),
+		@ExcelField(title = "\u5907\u6ce8", attrName = "remarks", align = Align.CENTER, sort = 50)
+	})
+	public MesStationPiecePrice() {
+		this(null);
+	}
+
+	public MesStationPiecePrice(String id) {
+		super(id);
+	}
+
+	@NotBlank(message = "\u4ea7\u7ebf\u7f16\u53f7\u4e0d\u80fd\u4e3a\u7a7a")
+	@Size(min = 0, max = 64, message = "\u4ea7\u7ebf\u7f16\u53f7\u957f\u5ea6\u4e0d\u80fd\u8d85\u8fc7 64 \u4e2a\u5b57\u7b26")
+	public String getLineSn() {
+		return lineSn;
+	}
+
+	public void setLineSn(String lineSn) {
+		this.lineSn = lineSn;
+	}
+
+	@NotBlank(message = "\u5de5\u4f4d\u53f7\u4e0d\u80fd\u4e3a\u7a7a")
+	@Size(min = 0, max = 64, message = "\u5de5\u4f4d\u53f7\u957f\u5ea6\u4e0d\u80fd\u8d85\u8fc7 64 \u4e2a\u5b57\u7b26")
+	public String getOprno() {
+		return oprno;
+	}
+
+	public void setOprno(String oprno) {
+		this.oprno = oprno;
+	}
+
+	@Size(min = 0, max = 100, message = "\u5de5\u4f4d\u540d\u79f0\u957f\u5ea6\u4e0d\u80fd\u8d85\u8fc7 100 \u4e2a\u5b57\u7b26")
+	public String getOprnoName() {
+		return oprnoName;
+	}
+
+	public void setOprnoName(String oprnoName) {
+		this.oprnoName = oprnoName;
+	}
+
+	@NotNull(message = "\u8ba1\u4ef6\u5355\u4ef7\u4e0d\u80fd\u4e3a\u7a7a")
+	public BigDecimal getUnitPrice() {
+		return unitPrice;
+	}
+
+	public void setUnitPrice(BigDecimal unitPrice) {
+		this.unitPrice = unitPrice;
+	}
+}

+ 34 - 0
src/main/java/com/jeesite/modules/mes/service/MesPieceSalaryReportService.java

@@ -0,0 +1,34 @@
+package com.jeesite.modules.mes.service;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.jeesite.common.entity.Page;
+import com.jeesite.modules.mes.dao.MesPieceSalaryReportDao;
+import com.jeesite.modules.mes.entity.MesPieceSalaryReport;
+
+/**
+ * 计件工资核算Service
+ */
+@Service
+public class MesPieceSalaryReportService {
+
+	@Autowired
+	private MesPieceSalaryReportDao mesPieceSalaryReportDao;
+
+	public Page<MesPieceSalaryReport> findPage(MesPieceSalaryReport report) {
+		Page<MesPieceSalaryReport> page = report.getPage();
+		page.setList(mesPieceSalaryReportDao.findSalaryList(report));
+		return page;
+	}
+
+	public List<MesPieceSalaryReport> findList(MesPieceSalaryReport report) {
+		return mesPieceSalaryReportDao.findSalaryList(report);
+	}
+
+	public List<MesPieceSalaryReport> findDetailList(MesPieceSalaryReport report) {
+		return mesPieceSalaryReportDao.findSalaryDetailList(report);
+	}
+}

+ 132 - 0
src/main/java/com/jeesite/modules/mes/service/MesStationPiecePriceService.java

@@ -0,0 +1,132 @@
+package com.jeesite.modules.mes.service;
+
+import java.util.List;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
+
+import com.jeesite.common.config.Global;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+
+import com.jeesite.common.entity.Page;
+import com.jeesite.common.lang.StringUtils;
+import com.jeesite.common.service.CrudService;
+import com.jeesite.common.service.ServiceException;
+import com.jeesite.common.utils.excel.ExcelImport;
+import com.jeesite.common.validator.ValidatorUtils;
+import com.jeesite.modules.mes.dao.MesStationPiecePriceDao;
+import com.jeesite.modules.mes.entity.MesStationPiecePrice;
+
+/**
+ * 工位计件单价Service
+ */
+@Service
+public class MesStationPiecePriceService extends CrudService<MesStationPiecePriceDao, MesStationPiecePrice> {
+
+	@Override
+	public MesStationPiecePrice get(MesStationPiecePrice mesStationPiecePrice) {
+		return super.get(mesStationPiecePrice);
+	}
+
+	@Override
+	public Page<MesStationPiecePrice> findPage(MesStationPiecePrice mesStationPiecePrice) {
+		return super.findPage(mesStationPiecePrice);
+	}
+
+	@Override
+	public List<MesStationPiecePrice> findList(MesStationPiecePrice mesStationPiecePrice) {
+		return super.findList(mesStationPiecePrice);
+	}
+
+	@Override
+	@Transactional
+	public void save(MesStationPiecePrice mesStationPiecePrice) {
+		trimKeyFields(mesStationPiecePrice);
+		super.save(mesStationPiecePrice);
+	}
+
+	@Transactional
+	public String importData(MultipartFile file) {
+		if (file == null) {
+			throw new ServiceException(text("\u8bf7\u9009\u62e9\u5bfc\u5165\u7684\u6570\u636e\u6587\u4ef6\uff01"));
+		}
+		int successNum = 0;
+		int failureNum = 0;
+		StringBuilder successMsg = new StringBuilder();
+		StringBuilder failureMsg = new StringBuilder();
+		try (ExcelImport ei = new ExcelImport(file, 2, 0)) {
+			List<MesStationPiecePrice> list = ei.getDataList(MesStationPiecePrice.class);
+			for (MesStationPiecePrice row : list) {
+				try {
+					trimKeyFields(row);
+					MesStationPiecePrice old = dao.findByLineSnAndOprno(row.getLineSn(), row.getOprno());
+					if (old != null) {
+						row.setId(old.getId());
+						row.setIsNewRecord(false);
+					}
+					ValidatorUtils.validateWithException(row);
+					this.save(row);
+					successNum++;
+					successMsg.append("<br/>").append(successNum).append("\u3001")
+							.append(row.getLineSn()).append(" / ").append(row.getOprno())
+							.append(" \u5bfc\u5165\u6210\u529f");
+				} catch (Exception e) {
+					failureNum++;
+					StringBuilder msg = new StringBuilder("<br/>").append(failureNum).append("\u3001")
+							.append(StringUtils.defaultString(row.getLineSn())).append(" / ")
+							.append(StringUtils.defaultString(row.getOprno())).append(" \u5bfc\u5165\u5931\u8d25\uff1a");
+					if (e instanceof ConstraintViolationException) {
+						ConstraintViolationException cve = (ConstraintViolationException)e;
+						for (ConstraintViolation<?> violation : cve.getConstraintViolations()) {
+							msg.append(Global.getText(violation.getMessage())).append(" (")
+									.append(violation.getPropertyPath()).append(")");
+						}
+					} else {
+						msg.append(e.getMessage());
+					}
+					failureMsg.append(msg);
+					logger.error(msg.toString(), e);
+				}
+			}
+		} catch (Exception e) {
+			logger.error(e.getMessage(), e);
+			failureMsg.append(e.getMessage());
+			return failureMsg.toString();
+		}
+		if (failureNum > 0) {
+			failureMsg.insert(0, "\u5f88\u62b1\u6b49\uff0c\u5bfc\u5165\u5931\u8d25\uff01\u5171 " + failureNum + " \u6761\u6570\u636e\u683c\u5f0f\u4e0d\u6b63\u786e\uff0c\u9519\u8bef\u5982\u4e0b\uff1a");
+			throw new ServiceException(failureMsg.toString());
+		}
+		successMsg.insert(0, "\u606d\u559c\u60a8\uff0c\u6570\u636e\u5df2\u5168\u90e8\u5bfc\u5165\u6210\u529f\uff01\u5171 " + successNum + " \u6761\uff0c\u6570\u636e\u5982\u4e0b\uff1a");
+		return successMsg.toString();
+	}
+
+	private void trimKeyFields(MesStationPiecePrice price) {
+		if (StringUtils.isNotBlank(price.getLineSn())) {
+			price.setLineSn(price.getLineSn().trim());
+		}
+		if (StringUtils.isNotBlank(price.getOprno())) {
+			price.setOprno(price.getOprno().trim());
+		}
+		if (StringUtils.isNotBlank(price.getOprnoName())) {
+			price.setOprnoName(price.getOprnoName().trim());
+		}
+		if (StringUtils.isBlank(price.getStatus())) {
+			price.setStatus(MesStationPiecePrice.STATUS_NORMAL);
+		}
+	}
+
+	@Override
+	@Transactional
+	public void updateStatus(MesStationPiecePrice mesStationPiecePrice) {
+		super.updateStatus(mesStationPiecePrice);
+	}
+
+	@Override
+	@Transactional
+	public void delete(MesStationPiecePrice mesStationPiecePrice) {
+		super.delete(mesStationPiecePrice);
+	}
+}

+ 9 - 9
src/main/java/com/jeesite/modules/mes/web/MesOp050RecordController.java

@@ -1,8 +1,11 @@
 package com.jeesite.modules.mes.web;
 
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
+import com.jeesite.common.entity.Page;
+import com.jeesite.common.web.BaseController;
+import com.jeesite.modules.mes.entity.MesOp050Record;
+import com.jeesite.modules.mes.req.MesSearchDateReq;
+import com.jeesite.modules.mes.service.MesOp050RecordService;
+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;
@@ -11,12 +14,8 @@ import org.springframework.web.bind.annotation.ModelAttribute;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.ResponseBody;
 
-import com.jeesite.common.entity.Page;
-import com.jeesite.common.web.BaseController;
-import com.jeesite.modules.mes.entity.MesOp050Record;
-import com.jeesite.modules.mes.req.MesSearchDateReq;
-import com.jeesite.modules.mes.service.MesOp050RecordService;
-import com.jeesite.modules.mes.util.CommonUitl;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 
 /**
  * OP050 record Controller.
@@ -55,6 +54,7 @@ public class MesOp050RecordController extends BaseController {
 	public Page<MesOp050Record> listData(MesOp050Record mesOp050Record,
 			HttpServletRequest request, HttpServletResponse response) {
 		mesOp050Record.setPage(new Page<>(request, response));
+		//mesOp050Record.setUcode("!system");
 		return mesOp050RecordService.findPage(mesOp050Record);
 	}
 }

+ 64 - 0
src/main/java/com/jeesite/modules/mes/web/MesPieceSalaryReportController.java

@@ -0,0 +1,64 @@
+package com.jeesite.modules.mes.web;
+
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.jeesite.common.entity.Page;
+import com.jeesite.common.lang.DateUtils;
+import com.jeesite.common.utils.excel.ExcelExport;
+import com.jeesite.common.web.BaseController;
+import com.jeesite.modules.mes.entity.MesPieceSalaryReport;
+import com.jeesite.modules.mes.service.MesPieceSalaryReportService;
+
+/**
+ * Piece salary accounting controller.
+ */
+@Controller
+@RequestMapping(value = "${adminPath}/mes/mesPieceSalaryReport")
+public class MesPieceSalaryReportController extends BaseController {
+
+	@Autowired
+	private MesPieceSalaryReportService mesPieceSalaryReportService;
+
+	@RequiresPermissions("mes:mesPieceSalaryReport:view")
+	@RequestMapping(value = {"list", ""})
+	public String list(MesPieceSalaryReport report, Model model) {
+		model.addAttribute("mesPieceSalaryReport", report);
+		return "modules/mes/mesPieceSalaryReportList";
+	}
+
+	@RequiresPermissions("mes:mesPieceSalaryReport:view")
+	@RequestMapping(value = "listData")
+	@ResponseBody
+	public Page<MesPieceSalaryReport> listData(MesPieceSalaryReport report,
+			HttpServletRequest request, HttpServletResponse response) {
+		report.setPage(new Page<>(request, response));
+		return mesPieceSalaryReportService.findPage(report);
+	}
+
+	@RequiresPermissions("mes:mesPieceSalaryReport:view")
+	@RequestMapping(value = "exportData")
+	public void exportData(MesPieceSalaryReport report, HttpServletResponse response) {
+		List<MesPieceSalaryReport> list = mesPieceSalaryReportService.findList(report);
+		String fileName = "\u8ba1\u4ef6\u5de5\u8d44\u8868" + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx";
+		try (ExcelExport ee = new ExcelExport("\u8ba1\u4ef6\u5de5\u8d44\u8868", MesPieceSalaryReport.class)) {
+			ee.setDataList(list).write(response, fileName);
+		}
+	}
+
+	@RequiresPermissions("mes:mesPieceSalaryReport:view")
+	@RequestMapping(value = "detailData")
+	@ResponseBody
+	public List<MesPieceSalaryReport> detailData(MesPieceSalaryReport report) {
+		return mesPieceSalaryReportService.findDetailList(report);
+	}
+}

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

@@ -4934,9 +4934,9 @@ public class MesProductRecordController extends BaseController {
 				// 新增表 工件码 工位号 ucode
 				resp.setResult(Global.TRUE);
 				resp.setMessage("扫码成功");
-				if ("OP050A".equals(oprno)){
+				/*if ("OP050A".equals(oprno)){
 					resp.setMessage("扫码成功,请进行检查,工件码:"+sn);
-				}
+				}*/
 				return resp;
 			}catch (Exception e){
 				resp.setResult(Global.FALSE);

+ 143 - 0
src/main/java/com/jeesite/modules/mes/web/MesStationPiecePriceController.java

@@ -0,0 +1,143 @@
+package com.jeesite.modules.mes.web;
+
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+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.multipart.MultipartFile;
+
+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.lang.StringUtils;
+import com.jeesite.common.utils.excel.ExcelExport;
+import com.jeesite.common.utils.excel.annotation.ExcelField.Type;
+import com.jeesite.common.web.BaseController;
+import com.jeesite.modules.mes.entity.MesLineProcess;
+import com.jeesite.modules.mes.entity.MesStationPiecePrice;
+import com.jeesite.modules.mes.service.MesLineProcessService;
+import com.jeesite.modules.mes.service.MesStationPiecePriceService;
+
+/**
+ * Station piece price controller.
+ */
+@Controller
+@RequestMapping(value = "${adminPath}/mes/mesStationPiecePrice")
+public class MesStationPiecePriceController extends BaseController {
+
+	@Autowired
+	private MesStationPiecePriceService mesStationPiecePriceService;
+
+	@Autowired
+	private MesLineProcessService mesLineProcessService;
+
+	@ModelAttribute
+	public MesStationPiecePrice get(String id, boolean isNewRecord) {
+		return mesStationPiecePriceService.get(id, isNewRecord);
+	}
+
+	@RequiresPermissions("mes:mesStationPiecePrice:view")
+	@RequestMapping(value = {"list", ""})
+	public String list(MesStationPiecePrice mesStationPiecePrice, Model model) {
+		model.addAttribute("mesStationPiecePrice", mesStationPiecePrice);
+		return "modules/mes/mesStationPiecePriceList";
+	}
+
+	@RequiresPermissions("mes:mesStationPiecePrice:view")
+	@RequestMapping(value = "listData")
+	@ResponseBody
+	public Page<MesStationPiecePrice> listData(MesStationPiecePrice mesStationPiecePrice,
+			HttpServletRequest request, HttpServletResponse response) {
+		mesStationPiecePrice.setPage(new Page<>(request, response));
+		return mesStationPiecePriceService.findPage(mesStationPiecePrice);
+	}
+
+	@RequiresPermissions("mes:mesStationPiecePrice:view")
+	@RequestMapping(value = "form")
+	public String form(MesStationPiecePrice mesStationPiecePrice, Model model) {
+		model.addAttribute("mesStationPiecePrice", mesStationPiecePrice);
+		return "modules/mes/mesStationPiecePriceForm";
+	}
+
+	@RequiresPermissions("mes:mesStationPiecePrice:edit")
+	@PostMapping(value = "save")
+	@ResponseBody
+	public String save(@Validated MesStationPiecePrice mesStationPiecePrice) {
+		mesStationPiecePriceService.save(mesStationPiecePrice);
+		return renderResult(Global.TRUE, text("\u4fdd\u5b58\u5de5\u4f4d\u8ba1\u4ef6\u5355\u4ef7\u6210\u529f"));
+	}
+
+	@RequiresPermissions("mes:mesStationPiecePrice:edit")
+	@RequestMapping(value = "delete")
+	@ResponseBody
+	public String delete(MesStationPiecePrice mesStationPiecePrice) {
+		mesStationPiecePriceService.delete(mesStationPiecePrice);
+		return renderResult(Global.TRUE, text("\u5220\u9664\u5de5\u4f4d\u8ba1\u4ef6\u5355\u4ef7\u6210\u529f"));
+	}
+
+	@RequiresPermissions("mes:mesStationPiecePrice:view")
+	@RequestMapping(value = "exportData")
+	public void exportData(MesStationPiecePrice mesStationPiecePrice, HttpServletResponse response) {
+		List<MesStationPiecePrice> list = mesStationPiecePriceService.findList(mesStationPiecePrice);
+		String fileName = "\u5de5\u4f4d\u8ba1\u4ef6\u5355\u4ef7" + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx";
+		try (ExcelExport ee = new ExcelExport("\u5de5\u4f4d\u8ba1\u4ef6\u5355\u4ef7", MesStationPiecePrice.class)) {
+			ee.setDataList(list).write(response, fileName);
+		}
+	}
+
+	@RequiresPermissions("mes:mesStationPiecePrice:view")
+	@RequestMapping(value = "importTemplate")
+	public void importTemplate(HttpServletResponse response) {
+		MesStationPiecePrice mesStationPiecePrice = new MesStationPiecePrice();
+		List<MesStationPiecePrice> list = ListUtils.newArrayList(mesStationPiecePrice);
+		String fileName = "\u5de5\u4f4d\u8ba1\u4ef6\u5355\u4ef7\u6a21\u677f.xlsx";
+		try (ExcelExport ee = new ExcelExport("\u5de5\u4f4d\u8ba1\u4ef6\u5355\u4ef7", MesStationPiecePrice.class, Type.IMPORT)) {
+			ee.setDataList(list).write(response, fileName);
+		}
+	}
+
+	@ResponseBody
+	@RequiresPermissions("mes:mesStationPiecePrice:edit")
+	@PostMapping(value = "importData")
+	public String importData(MultipartFile file) {
+		try {
+			String message = mesStationPiecePriceService.importData(file);
+			return renderResult(Global.TRUE, "posfull:" + message);
+		} catch (Exception ex) {
+			return renderResult(Global.FALSE, "posfull:" + ex.getMessage());
+		}
+	}
+
+	@RequiresPermissions("mes:mesStationPiecePrice:view")
+	@RequestMapping(value = "stationList")
+	@ResponseBody
+	public List<MesLineProcess> stationList(String lineSn) {
+		return mesLineProcessService.findOprnoListByLineSn(lineSn);
+	}
+
+	@RequiresPermissions("mes:mesStationPiecePrice:view")
+	@RequestMapping(value = "stationInfo")
+	@ResponseBody
+	public MesLineProcess stationInfo(String lineSn, String oprno) {
+		if (StringUtils.isBlank(lineSn) || StringUtils.isBlank(oprno)) {
+			return null;
+		}
+		for (MesLineProcess item : mesLineProcessService.findOprnoListByLineSn(lineSn)) {
+			if (oprno.trim().equals(item.getOprno())) {
+				return item;
+			}
+		}
+		return mesLineProcessService.findInfoByOprnoLineSn(oprno, lineSn);
+	}
+}

+ 6 - 6
src/main/resources/config/application.yml

@@ -163,13 +163,13 @@ jdbc:
   # Mysql 数据库配置
   type: mysql
   driver: com.mysql.cj.jdbc.Driver
-  url: jdbc:mysql://127.0.0.1:3306/ce_liu?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
+ # url: jdbc:mysql://127.0.0.1:3306/ce_liu?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
 #  url: jdbc:mysql://127.0.0.1:3306/mes_cloude_npd?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
-#  url: jdbc:mysql://192.168.9.181:3306/mes_cloud?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
-#  username: mes_cloud
-#  password: s2ENj7KaEySTC7dW
-  username: root
-  password: 123456
+  url: jdbc:mysql://192.168.9.181:3306/mes_cloud?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
+  username: mes_cloud
+  password: s2ENj7KaEySTC7dW
+#  username: root
+ # password: 123456
   testSql: SELECT 1
 
   #  # Oracle 数据库配置(若使用 12c,请修改 /modules/core/pom.xml 文件,打开 12c 依赖,去掉 11g 依赖)

+ 10 - 0
src/main/resources/mappings/modules/mes/MesOp050RecordDao.xml

@@ -2,4 +2,14 @@
 <!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.MesOp050RecordDao">
 
+	<select id="findList" resultType="MesOp050Record">
+		SELECT ${sqlMap.column.toSql()}
+		FROM ${sqlMap.table.toSql()}
+		<where>
+			${sqlMap.where.toSql()}
+			AND a.ucode != 'system'
+		</where>
+		ORDER BY ${sqlMap.order.toSql()}
+	</select>
+
 </mapper>

+ 77 - 0
src/main/resources/mappings/modules/mes/MesPieceSalaryReportDao.xml

@@ -0,0 +1,77 @@
+<?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.MesPieceSalaryReportDao">
+
+	<sql id="salaryDetailBase">
+		SELECT
+			r.ucode AS userCode,
+			COALESCE(u.user_name, e.emp_name, r.ucode) AS userName,
+			r.line_sn AS lineSn,
+			r.oprno AS oprno,
+			COALESCE(MAX(p.oprno_name), r.oprno) AS oprnoName,
+			COUNT(1) AS pieceCount,
+			COALESCE(MAX(p.unit_price), 0) AS unitPrice,
+			COUNT(1) * COALESCE(MAX(p.unit_price), 0) AS salaryAmount
+		FROM mes_pda_scan_record r
+		LEFT JOIN mes_station_piece_price p
+			ON p.line_sn = r.line_sn
+			AND p.oprno = r.oprno
+			AND p.status = '0'
+		LEFT JOIN js_sys_user u
+			ON u.login_code = r.ucode
+			AND u.status IN ('0', '3')
+		LEFT JOIN js_sys_employee e
+			ON e.emp_code = r.ucode
+			AND e.status IN ('0', '3')
+		<where>
+			IFNULL(r.ucode, '') != ''
+			<if test="startDate != null and startDate != ''">
+				AND r.create_date &gt;= CONCAT(#{startDate}, ':00')
+			</if>
+			<if test="endDate != null and endDate != ''">
+				AND r.create_date &lt;= CONCAT(#{endDate}, ':59')
+			</if>
+			<if test="lineSn != null and lineSn != ''">
+				AND r.line_sn LIKE CONCAT('%', #{lineSn}, '%')
+			</if>
+			<if test="oprno != null and oprno != ''">
+				AND r.oprno LIKE CONCAT('%', #{oprno}, '%')
+			</if>
+			<if test="ucode != null and ucode != ''">
+				AND r.ucode LIKE CONCAT('%', #{ucode}, '%')
+			</if>
+		</where>
+		GROUP BY r.ucode, u.user_name, e.emp_name, r.line_sn, r.oprno
+	</sql>
+
+	<select id="findSalaryList" resultType="com.jeesite.modules.mes.entity.MesPieceSalaryReport">
+		SELECT
+			t.userCode AS "id",
+			t.userCode AS "ucode",
+			t.userName AS "userName",
+			SUM(t.pieceCount) AS "pieceCount",
+			SUM(t.salaryAmount) AS "salaryAmount"
+		FROM (
+			<include refid="salaryDetailBase"/>
+		) t
+		GROUP BY t.userCode, t.userName
+		ORDER BY t.userCode ASC
+	</select>
+
+	<select id="findSalaryDetailList" resultType="com.jeesite.modules.mes.entity.MesPieceSalaryReport">
+		SELECT
+			CONCAT(t.userCode, '_', t.lineSn, '_', t.oprno) AS "id",
+			t.userCode AS "ucode",
+			t.userName AS "userName",
+			t.lineSn AS "lineSn",
+			t.oprno AS "oprno",
+			t.oprnoName AS "oprnoName",
+			t.pieceCount AS "pieceCount",
+			t.unitPrice AS "unitPrice",
+			t.salaryAmount AS "salaryAmount"
+		FROM (
+			<include refid="salaryDetailBase"/>
+		) t
+		ORDER BY t.lineSn ASC, t.oprno ASC
+	</select>
+</mapper>

+ 24 - 0
src/main/resources/mappings/modules/mes/MesStationPiecePriceDao.xml

@@ -0,0 +1,24 @@
+<?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.MesStationPiecePriceDao">
+
+	<select id="findByLineSnAndOprno" resultType="com.jeesite.modules.mes.entity.MesStationPiecePrice">
+		SELECT
+			id,
+			line_sn AS "lineSn",
+			oprno,
+			oprno_name AS "oprnoName",
+			unit_price AS "unitPrice",
+			status,
+			remarks,
+			create_by AS "createBy",
+			create_date AS "createDate",
+			update_by AS "updateBy",
+			update_date AS "updateDate"
+		FROM mes_station_piece_price
+		WHERE line_sn = #{lineSn}
+		  AND oprno = #{oprno}
+		  AND status != '1'
+		LIMIT 1
+	</select>
+</mapper>

+ 157 - 0
src/main/resources/views/modules/mes/mesPieceSalaryReportList.html

@@ -0,0 +1,157 @@
+<% 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 fa-calculator"></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> ${text('导出')}</a>
+				<% if(hasPermi('mes:mesStationPiecePrice:view')){ %>
+					<a href="${ctx}/mes/mesStationPiecePrice/list" class="btn btn-default btnTool" title="${text('工位计件单价')}"><i class="fa fa-money"></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="${mesPieceSalaryReport}" action="${ctx}/mes/mesPieceSalaryReport/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="startDate" readonly="true" maxlength="20" class="form-control laydate width-datetime"
+							dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm" data-done="endDate.click()"/>
+						&nbsp;-&nbsp;
+						<#form:input path="endDate" readonly="true" maxlength="20" class="form-control laydate width-datetime"
+							dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('产线编号')}:</label>
+					<div class="control-inline">
+						<#form:input path="lineSn" maxlength="64" 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="64" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('人员编码')}:</label>
+					<div class="control-inline">
+						<#form:input path="ucode" maxlength="64" 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({
+	searchForm: $("#searchForm"),
+	columnModel: [
+		{header:'${text("人员编码")}', name:'ucode', index:'ucode', width:150, align:"center", frozen:true},
+		{header:'${text("人员姓名")}', name:'userName', index:'userName', width:150, align:"center"},
+		{header:'${text("总件数")}', name:'pieceCount', index:'pieceCount', width:120, align:"right"},
+		{header:'${text("工资总金额")}', name:'salaryAmount', index:'salaryAmount', width:140, align:"right"},
+		{header:'${text("操作")}', name:'actions', width:120, formatter: function(val, obj, row){
+			return '<a href="javascript:" class="btnDetail" data-ucode="'+htmlEscape(row.ucode || '')+'" data-name="'+htmlEscape(row.userName || '')+'" title="${text("查看详情")}"><i class="fa fa-list-alt"></i> ${text("详情")}</a>';
+		}}
+	],
+	ajaxSuccess: function(){}
+});
+
+$('#dataGrid').on('click', '.btnDetail', function(){
+	showSalaryDetail($(this).data('ucode'), $(this).data('name'));
+});
+
+$('#btnExport').click(function(){
+	js.ajaxSubmitForm($('#searchForm'), {
+		url:'${ctx}/mes/mesPieceSalaryReport/exportData',
+		downloadFile:true
+	});
+});
+
+function showSalaryDetail(ucode, userName) {
+	var params = formParams();
+	params.ucode = ucode;
+	$.getJSON('${ctx}/mes/mesPieceSalaryReport/detailData', params, function(list){
+		var totalCount = 0;
+		var totalAmount = 0;
+		var rows = [];
+		if (list && list.length) {
+			$.each(list, function(i, row){
+				var count = Number(row.pieceCount || 0);
+				var amount = Number(row.salaryAmount || 0);
+				totalCount += count;
+				totalAmount += amount;
+				rows.push('<tr>'
+					+ '<td class="text-center">'+(i + 1)+'</td>'
+					+ '<td class="text-center">'+htmlEscape(row.lineSn)+'</td>'
+					+ '<td class="text-center">'+htmlEscape(row.oprno)+'</td>'
+					+ '<td>'+htmlEscape(row.oprnoName)+'</td>'
+					+ '<td class="text-right">'+count+'</td>'
+					+ '<td class="text-right">'+money(row.unitPrice)+'</td>'
+					+ '<td class="text-right">'+money(amount)+'</td>'
+					+ '</tr>');
+			});
+		} else {
+			rows.push('<tr><td colspan="7" class="text-center text-muted">${text("暂无明细")}</td></tr>');
+		}
+		var content = '<div style="padding:10px;max-height:520px;overflow:auto;">'
+			+ '<table class="table table-hover table-striped table-bordered mb0">'
+			+ '<thead><tr>'
+			+ '<th class="text-center" style="width:60px;">${text("序号")}</th>'
+			+ '<th class="text-center" style="width:120px;">${text("产线编号")}</th>'
+			+ '<th class="text-center" style="width:120px;">${text("工位号")}</th>'
+			+ '<th>${text("工位名称")}</th>'
+			+ '<th class="text-right" style="width:100px;">${text("件数")}</th>'
+			+ '<th class="text-right" style="width:120px;">${text("计件单价")}</th>'
+			+ '<th class="text-right" style="width:120px;">${text("工资金额")}</th>'
+			+ '</tr></thead>'
+			+ '<tbody>'+rows.join('')+'</tbody>'
+			+ '<tfoot><tr>'
+			+ '<th colspan="4" class="text-right">${text("合计")}</th>'
+			+ '<th class="text-right">'+totalCount+'</th>'
+			+ '<th></th>'
+			+ '<th class="text-right">'+money(totalAmount)+'</th>'
+			+ '</tr></tfoot>'
+			+ '</table></div>';
+		js.layer.open({
+			type: 1,
+			area: ['860px', '620px'],
+			title: '${text("工资明细")} - ' + htmlEscape(userName || ucode),
+			content: content
+		});
+	});
+}
+
+function formParams() {
+	var params = {};
+	$.each($('#searchForm').serializeArray(), function(i, item){
+		params[item.name] = item.value;
+	});
+	return params;
+}
+
+function money(value) {
+	var number = Number(value || 0);
+	return number.toFixed(2);
+}
+
+function htmlEscape(value) {
+	return String(value || '').replace(/[&<>"']/g, function(ch){
+		return {'&':'&amp;', '<':'&lt;', '>':'&gt;', '"':'&quot;', "'":'&#39;'}[ch];
+	});
+}
+</script>

+ 153 - 0
src/main/resources/views/modules/mes/mesStationPiecePriceForm.html

@@ -0,0 +1,153 @@
+<% 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 fa-money"></i> ${text(mesStationPiecePrice.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="${mesStationPiecePrice}" action="${ctx}/mes/mesStationPiecePrice/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"><span class="required">*</span> ${text('产线编号')}:</label>
+							<div class="col-sm-8">
+								<div class="input-group">
+									<#form:input path="lineSn" maxlength="64" class="form-control required"/>
+									<span class="input-group-btn">
+										<button type="button" class="btn btn-default" id="btnSelectStation"><i class="fa fa-list"></i> ${text('选取')}</button>
+									</span>
+								</div>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4"><span class="required">*</span> ${text('工位号')}:</label>
+							<div class="col-sm-8">
+								<#form:input path="oprno" maxlength="64" class="form-control required"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4">${text('工位名称')}:</label>
+							<div class="col-sm-8">
+								<#form:input path="oprnoName" maxlength="100" class="form-control"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4"><span class="required">*</span> ${text('计件单价')}:</label>
+							<div class="col-sm-8">
+								<#form:input path="unitPrice" maxlength="18" class="form-control required number"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-12">
+						<div class="form-group">
+							<label class="control-label col-sm-2">${text('备注')}:</label>
+							<div class="col-sm-10">
+								<#form:textarea path="remarks" maxlength="500" rows="3" class="form-control"/>
+							</div>
+						</div>
+					</div>
+				</div>
+			</div>
+			<div class="box-footer">
+				<div class="row">
+					<div class="col-sm-offset-2 col-sm-10">
+						<% if (hasPermi('mes:mesStationPiecePrice: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");
+    }
+});
+
+$('#lineSn').on('change', function(){
+	$('#oprno').val('');
+	$('#oprnoName').val('');
+});
+
+$('#oprno').on('blur', function(){
+	var lineSn = $.trim($('#lineSn').val());
+	var oprno = $.trim($('#oprno').val());
+	if (!lineSn || !oprno) {
+		return;
+	}
+	$.getJSON('${ctx}/mes/mesStationPiecePrice/stationInfo', {lineSn: lineSn, oprno: oprno}, function(data){
+		if (data && data.title) {
+			$('#oprnoName').val(data.title);
+		}
+	});
+});
+
+$('#btnSelectStation').click(function(){
+	var lineSn = $.trim($('#lineSn').val());
+	if (!lineSn) {
+		js.showMessage('${text("请先输入产线编号")}', null, 'warning');
+		return;
+	}
+	$.getJSON('${ctx}/mes/mesStationPiecePrice/stationList', {lineSn: lineSn}, function(list){
+		var rows = [];
+		if (list && list.length) {
+			$.each(list, function(i, item){
+				rows.push('<tr class="station-row" data-oprno="'+htmlEscape(item.oprno || '')+'" data-title="'+htmlEscape(item.title || '')+'">'
+					+ '<td class="text-center">'+htmlEscape(item.oprno || '')+'</td>'
+					+ '<td>'+htmlEscape(item.title || '')+'</td>'
+					+ '</tr>');
+			});
+		} else {
+			rows.push('<tr><td colspan="2" class="text-center text-muted">${text("该产线未找到工位")}</td></tr>');
+		}
+		var content = '<div style="padding:10px;max-height:420px;overflow:auto;">'
+			+ '<table class="table table-hover table-striped table-bordered mb0">'
+			+ '<thead><tr><th class="text-center" style="width:140px;">${text("工位号")}</th><th>${text("工位名称")}</th></tr></thead>'
+			+ '<tbody>'+rows.join('')+'</tbody></table></div>';
+		js.layer.open({
+			type: 1,
+			area: ['560px', '520px'],
+			title: '${text("选择工位")} - ' + lineSn,
+			content: content,
+			success: function(layero, index){
+				layero.find('.station-row').css('cursor', 'pointer').click(function(){
+					$('#oprno').val($(this).data('oprno'));
+					$('#oprnoName').val($(this).data('title'));
+					js.layer.close(index);
+				});
+			}
+		});
+	});
+});
+
+function htmlEscape(value) {
+	return String(value || '').replace(/[&<>"']/g, function(ch){
+		return {'&':'&amp;', '<':'&lt;', '>':'&gt;', '"':'&quot;', "'":'&#39;'}[ch];
+	});
+}
+</script>

+ 135 - 0
src/main/resources/views/modules/mes/mesStationPiecePriceList.html

@@ -0,0 +1,135 @@
+<% 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 fa-money"></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> ${text('导出')}</a>
+				<% if(hasPermi('mes:mesStationPiecePrice:edit')){ %>
+					<a href="#" class="btn btn-default" id="btnImport"><i class="glyphicon glyphicon-import"></i> ${text('导入')}</a>
+					<a href="${ctx}/mes/mesStationPiecePrice/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="${mesStationPiecePrice}" action="${ctx}/mes/mesStationPiecePrice/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="64" 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="64" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('工位名称')}:</label>
+					<div class="control-inline">
+						<#form:input path="oprnoName" maxlength="100" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('状态')}:</label>
+					<div class="control-inline width-120">
+						<#form:select path="status" dictType="sys_search_status" blankOption="true" class="form-control isQuick"/>
+					</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({
+	searchForm: $("#searchForm"),
+	columnModel: [
+		{header:'${text("产线编号")}', name:'lineSn', index:'a.line_sn', width:120, align:"center", frozen:true, formatter: function(val, obj, row){
+			return '<a href="${ctx}/mes/mesStationPiecePrice/form?id='+row.id+'" class="btnList" data-title="${text("编辑工位计件单价")}">'+(val||row.id)+'</a>';
+		}},
+		{header:'${text("工位号")}', name:'oprno', index:'a.oprno', width:120, align:"center"},
+		{header:'${text("工位名称")}', name:'oprnoName', index:'a.oprno_name', width:160, align:"center"},
+		{header:'${text("计件单价")}', name:'unitPrice', index:'a.unit_price', width:120, align:"right"},
+		{header:'${text("状态")}', name:'status', index:'a.status', width:90, align:"center", formatter: function(val){
+			return js.getDictLabel(${@DictUtils.getDictListJson('sys_search_status')}, val, '${text("未知")}', true);
+		}},
+		{header:'${text("备注")}', name:'remarks', index:'a.remarks', width:180, align:"left"},
+		{header:'${text("更新时间")}', name:'updateDate', index:'a.update_date', width:150, align:"center"},
+		{header:'${text("操作")}', name:'actions', width:100, formatter: function(val, obj, row){
+			var actions = [];
+			<% if(hasPermi('mes:mesStationPiecePrice:edit')){ %>
+				actions.push('<a href="${ctx}/mes/mesStationPiecePrice/form?id='+row.id+'" class="btnList" title="${text("编辑")}"><i class="fa fa-pencil"></i></a>&nbsp;');
+				actions.push('<a href="${ctx}/mes/mesStationPiecePrice/delete?id='+row.id+'" class="btnList" title="${text("删除")}" data-confirm="${text("确认要删除该工位计件单价吗?")}"><i class="fa fa-trash-o"></i></a>&nbsp;');
+			<% } %>
+			return actions.join('');
+		}}
+	],
+	ajaxSuccess: function(){}
+});
+
+$('#btnExport').click(function(){
+	js.ajaxSubmitForm($('#searchForm'), {
+		url:'${ctx}/mes/mesStationPiecePrice/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/mesStationPiecePrice/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">
+				<a href="${ctx}/mes/mesStationPiecePrice/importTemplate" class="btn btn-default btn-xs"><i class="fa fa-file-excel-o"></i> ${text('下载模板')}</a>
+			</div>
+			<font color="red" class="pull-left mt10">
+				${text('提示:仅允许导入“xls”或“xlsx”格式文件。相同产线编号和工位号会自动更新。')}
+			</font>
+		</div>
+	</div>
+</form>
+//--></script>