报表导出打印
diff --git a/build.gradle b/build.gradle
index d8703b7..761f8b5 100644
--- a/build.gradle
+++ b/build.gradle
@@ -76,6 +76,7 @@
     implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
     implementation 'net.javacrumbs.shedlock:shedlock-spring:2.5.0'
     implementation 'net.javacrumbs.shedlock:shedlock-provider-redis-spring:2.5.0'
+    implementation 'org.projectlombok:lombok:1.18.10'
 
     implementation 'org.postgresql:postgresql:42.2.5'
     implementation 'com.jcabi:jcabi-manifests:1.1'
diff --git a/src/main/java/com/supwisdom/dlpay/restaurant/bean/LaborfeeSearchBean.java b/src/main/java/com/supwisdom/dlpay/restaurant/bean/LaborfeeSearchBean.java
new file mode 100644
index 0000000..41612b6
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/restaurant/bean/LaborfeeSearchBean.java
@@ -0,0 +1,50 @@
+package com.supwisdom.dlpay.restaurant.bean;
+
+public class LaborfeeSearchBean {
+  private String startdate;
+  private String enddate;
+  private String datetype;
+  private String yearmonth;
+
+  public LaborfeeSearchBean() {
+  }
+
+  public LaborfeeSearchBean(String startdate, String enddate, String datetype, String yearmonth) {
+    this.startdate = startdate;
+    this.enddate = enddate;
+    this.datetype = datetype;
+    this.yearmonth = yearmonth;
+  }
+
+  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 getDatetype() {
+    return datetype;
+  }
+
+  public void setDatetype(String datetype) {
+    this.datetype = datetype;
+  }
+
+  public String getYearmonth() {
+    return yearmonth;
+  }
+
+  public void setYearmonth(String yearmonth) {
+    this.yearmonth = yearmonth;
+  }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/restaurant/bean/LaborfeeSearchData.java b/src/main/java/com/supwisdom/dlpay/restaurant/bean/LaborfeeSearchData.java
new file mode 100644
index 0000000..943496d
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/restaurant/bean/LaborfeeSearchData.java
@@ -0,0 +1,134 @@
+package com.supwisdom.dlpay.restaurant.bean;
+
+public class LaborfeeSearchData {
+  private Integer rownum; //行号
+
+  private Integer dwid; //单位id 设备组一级
+  private String dwname; //单位名称
+  private Integer groupid; //食堂ID 设备组二级
+  private String groupname; //单位名称
+
+  private Double btotalamt; //早餐总金额
+  private Double ltotalamt; //午餐总金额
+  private Double dtotalamt; //晚餐总金额
+
+  private Double bpayamt; //早餐支付金额
+  private Double lpayamt; //午餐支付总金额
+  private Double dpayamt; //晚餐支付总金额
+
+  private Double bfeeamt; //早餐支付金额
+  private Double lfeeamt; //午餐支付总金额
+  private Double dfeeamt; //晚餐支付总金额
+
+  public Integer getRownum() {
+    return rownum;
+  }
+
+  public void setRownum(Integer rownum) {
+    this.rownum = rownum;
+  }
+
+  public Integer getDwid() {
+    return dwid;
+  }
+
+  public void setDwid(Integer dwid) {
+    this.dwid = dwid;
+  }
+
+  public String getDwname() {
+    return dwname;
+  }
+
+  public void setDwname(String dwname) {
+    this.dwname = dwname;
+  }
+
+  public Integer getGroupid() {
+    return groupid;
+  }
+
+  public void setGroupid(Integer groupid) {
+    this.groupid = groupid;
+  }
+
+  public String getGroupname() {
+    return groupname;
+  }
+
+  public void setGroupname(String groupname) {
+    this.groupname = groupname;
+  }
+
+  public Double getBtotalamt() {
+    return btotalamt;
+  }
+
+  public void setBtotalamt(Double btotalamt) {
+    this.btotalamt = btotalamt;
+  }
+
+  public Double getLtotalamt() {
+    return ltotalamt;
+  }
+
+  public void setLtotalamt(Double ltotalamt) {
+    this.ltotalamt = ltotalamt;
+  }
+
+  public Double getDtotalamt() {
+    return dtotalamt;
+  }
+
+  public void setDtotalamt(Double dtotalamt) {
+    this.dtotalamt = dtotalamt;
+  }
+
+  public Double getBpayamt() {
+    return bpayamt;
+  }
+
+  public void setBpayamt(Double bpayamt) {
+    this.bpayamt = bpayamt;
+  }
+
+  public Double getLpayamt() {
+    return lpayamt;
+  }
+
+  public void setLpayamt(Double lpayamt) {
+    this.lpayamt = lpayamt;
+  }
+
+  public Double getDpayamt() {
+    return dpayamt;
+  }
+
+  public void setDpayamt(Double dpayamt) {
+    this.dpayamt = dpayamt;
+  }
+
+  public Double getBfeeamt() {
+    return bfeeamt;
+  }
+
+  public void setBfeeamt(Double bfeeamt) {
+    this.bfeeamt = bfeeamt;
+  }
+
+  public Double getLfeeamt() {
+    return lfeeamt;
+  }
+
+  public void setLfeeamt(Double lfeeamt) {
+    this.lfeeamt = lfeeamt;
+  }
+
+  public Double getDfeeamt() {
+    return dfeeamt;
+  }
+
+  public void setDfeeamt(Double dfeeamt) {
+    this.dfeeamt = dfeeamt;
+  }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/restaurant/bean/LaborfeeShowBean.java b/src/main/java/com/supwisdom/dlpay/restaurant/bean/LaborfeeShowBean.java
new file mode 100644
index 0000000..a7973f6
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/restaurant/bean/LaborfeeShowBean.java
@@ -0,0 +1,151 @@
+package com.supwisdom.dlpay.restaurant.bean;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class LaborfeeShowBean {
+  private Integer dwid; //单位id 设备组一级
+  private String dwname; //单位名称
+
+  private Double btotalamt; //早餐总金额
+  private Double ltotalamt; //午餐总金额
+  private Double dtotalamt; //晚餐总金额
+
+  private Double bpayamt; //早餐支付金额
+  private Double lpayamt; //午餐支付总金额
+  private Double dpayamt; //晚餐支付总金额
+
+  private Double bfeeamt; //早餐支付金额
+  private Double lfeeamt; //午餐支付总金额
+  private Double dfeeamt; //晚餐支付总金额
+
+  private List<LaborfeeSearchData> datalist = new ArrayList<LaborfeeSearchData>(0);
+
+  public LaborfeeShowBean(){
+  }
+
+  public LaborfeeShowBean(Integer dwid, String dwname, Double btotalamt, Double ltotalamt, Double dtotalamt, Double bpayamt, Double lpayamt, Double dpayamt, Double bfeeamt, Double lfeeamt, Double dfeeamt) {
+    this.dwid = dwid;
+    this.dwname = dwname;
+    this.btotalamt = btotalamt;
+    this.ltotalamt = ltotalamt;
+    this.dtotalamt = dtotalamt;
+    this.bpayamt = bpayamt;
+    this.lpayamt = lpayamt;
+    this.dpayamt = dpayamt;
+    this.bfeeamt = bfeeamt;
+    this.lfeeamt = lfeeamt;
+    this.dfeeamt = dfeeamt;
+  }
+
+  public LaborfeeShowBean(Integer dwid, String dwname, Double btotalamt, Double ltotalamt, Double dtotalamt, Double bpayamt, Double lpayamt, Double dpayamt, Double bfeeamt, Double lfeeamt, Double dfeeamt, List<LaborfeeSearchData> datalist) {
+    this.dwid = dwid;
+    this.dwname = dwname;
+    this.btotalamt = btotalamt;
+    this.ltotalamt = ltotalamt;
+    this.dtotalamt = dtotalamt;
+    this.bpayamt = bpayamt;
+    this.lpayamt = lpayamt;
+    this.dpayamt = dpayamt;
+    this.bfeeamt = bfeeamt;
+    this.lfeeamt = lfeeamt;
+    this.dfeeamt = dfeeamt;
+    this.datalist = datalist;
+  }
+
+  public Integer getDwid() {
+    return dwid;
+  }
+
+  public void setDwid(Integer dwid) {
+    this.dwid = dwid;
+  }
+
+  public String getDwname() {
+    return dwname;
+  }
+
+  public void setDwname(String dwname) {
+    this.dwname = dwname;
+  }
+
+  public Double getBtotalamt() {
+    return btotalamt;
+  }
+
+  public void setBtotalamt(Double btotalamt) {
+    this.btotalamt = btotalamt;
+  }
+
+  public Double getLtotalamt() {
+    return ltotalamt;
+  }
+
+  public void setLtotalamt(Double ltotalamt) {
+    this.ltotalamt = ltotalamt;
+  }
+
+  public Double getDtotalamt() {
+    return dtotalamt;
+  }
+
+  public void setDtotalamt(Double dtotalamt) {
+    this.dtotalamt = dtotalamt;
+  }
+
+  public Double getBpayamt() {
+    return bpayamt;
+  }
+
+  public void setBpayamt(Double bpayamt) {
+    this.bpayamt = bpayamt;
+  }
+
+  public Double getLpayamt() {
+    return lpayamt;
+  }
+
+  public void setLpayamt(Double lpayamt) {
+    this.lpayamt = lpayamt;
+  }
+
+  public Double getDpayamt() {
+    return dpayamt;
+  }
+
+  public void setDpayamt(Double dpayamt) {
+    this.dpayamt = dpayamt;
+  }
+
+  public Double getBfeeamt() {
+    return bfeeamt;
+  }
+
+  public void setBfeeamt(Double bfeeamt) {
+    this.bfeeamt = bfeeamt;
+  }
+
+  public Double getLfeeamt() {
+    return lfeeamt;
+  }
+
+  public void setLfeeamt(Double lfeeamt) {
+    this.lfeeamt = lfeeamt;
+  }
+
+  public Double getDfeeamt() {
+    return dfeeamt;
+  }
+
+  public void setDfeeamt(Double dfeeamt) {
+    this.dfeeamt = dfeeamt;
+  }
+
+  public List<LaborfeeSearchData> getDatalist() {
+    return datalist;
+  }
+
+  public void setDatalist(List<LaborfeeSearchData> datalist) {
+    this.datalist = datalist;
+  }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/restaurant/controller/StatementReportController.java b/src/main/java/com/supwisdom/dlpay/restaurant/controller/StatementReportController.java
new file mode 100644
index 0000000..1bbc804
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/restaurant/controller/StatementReportController.java
@@ -0,0 +1,109 @@
+package com.supwisdom.dlpay.restaurant.controller;
+
+import com.supwisdom.dlpay.framework.domain.TOperator;
+import com.supwisdom.dlpay.framework.service.SystemUtilService;
+import com.supwisdom.dlpay.framework.util.DateUtil;
+
+import com.supwisdom.dlpay.restaurant.bean.LaborfeeSearchBean;
+import com.supwisdom.dlpay.restaurant.bean.LaborfeeShowBean;
+import com.supwisdom.dlpay.restaurant.service.StatementReportService;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+@Controller
+@RequestMapping("/report")
+public class StatementReportController {
+  @Autowired
+  private StatementReportService statementReportService;
+  @Autowired
+  private SystemUtilService systemUtilService;
+
+  @GetMapping("/laborfee")
+  public String LaborfeeIndex(@ModelAttribute("searchBean") LaborfeeSearchBean searchBean,
+                              @AuthenticationPrincipal UserDetails operUser,
+                              ModelMap map) {
+    try {
+      String statdate = statementReportService.getMaxStatementDate();
+      String maxdate = DateUtil.reformatDatetime(statdate, "yyyyMMdd", "yyyy-MM-dd");
+      String maxmonth = DateUtil.reformatDatetime(statdate.substring(0, 6), "yyyyMM", "yyyy-MM");
+      map.addAttribute("maxdate", maxdate);
+      map.addAttribute("maxmonth", maxmonth);
+
+      searchBean.setStartdate(statdate);
+      searchBean.setEnddate(statdate);
+      searchBean.setDatetype("days");
+      searchBean.setYearmonth(maxmonth);
+      map.addAttribute("showlist", statementReportService.getLaborfeeSearchData(searchBean));
+
+      TOperator oper = (TOperator) operUser;
+      map.addAttribute("opercode", oper == null ? "unknow" : oper.getOpercode());
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+
+    return "restaurant/report/laborfee";
+  }
+
+  @PostMapping("/searchlaborfee")
+  @PreAuthorize("hasPermission('/report/laborfee','')")
+  public String searchLaborfee(@ModelAttribute("searchBean") LaborfeeSearchBean searchBean,
+                               @AuthenticationPrincipal UserDetails operUser,
+                               ModelMap map) {
+    try {
+      TOperator oper = (TOperator) operUser;
+      map.addAttribute("opercode", oper == null ? "unknow" : oper.getOpercode());
+
+      map.addAttribute("showlist", statementReportService.getLaborfeeSearchData(searchBean));
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+    return "restaurant/report/laborfee::laborfeeTable";
+  }
+
+  @GetMapping("/excelexportlaborfee")
+  @PreAuthorize("hasPermission('/report/excelexportlaborfee','')")
+  public void excelExportLaborfee(@ModelAttribute("searchBean") LaborfeeSearchBean searchBean,
+                                  @AuthenticationPrincipal UserDetails operUser,
+                                  HttpServletRequest request, HttpServletResponse response, ModelMap map){
+    try {
+      List<LaborfeeShowBean> datalist = statementReportService.getLaborfeeSearchData(searchBean);
+      TOperator oper = (TOperator) operUser;
+      String filename="商户劳务费报表";
+      statementReportService.doCreateLaborfeeExcel(response, datalist, searchBean, filename, oper);
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+
+  /**
+   * fixme: 一定不能加访问权限
+   * */
+  @GetMapping("/print/printlaborfee")
+  public String printLaborfee(@ModelAttribute("searchBean") LaborfeeSearchBean searchBean,
+                              @RequestParam(value = "opercode",required = false) String opercode, ModelMap map) {
+    try {
+      map.addAttribute("showlist", statementReportService.getLaborfeeSearchData(searchBean));
+
+      TOperator oper = statementReportService.getOperatorByOpercode(opercode);
+      map.addAttribute("opername", oper == null ? "unknow" : oper.getOpername());
+      map.addAttribute("period", statementReportService.getLaborfeeSearchPeriod(searchBean));
+      map.addAttribute("printdatetime",DateUtil.reformatDatetime(systemUtilService.getSysdatetime().getHostdatetime(),DateUtil.DATETIME_FMT,"yyyy-MM-dd HH:mm:ss"));
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+    return "restaurant/report/print/printlaborfee";
+  }
+
+
+
+}
diff --git a/src/main/java/com/supwisdom/dlpay/restaurant/service/StatementReportService.java b/src/main/java/com/supwisdom/dlpay/restaurant/service/StatementReportService.java
new file mode 100644
index 0000000..2af4d7a
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/restaurant/service/StatementReportService.java
@@ -0,0 +1,28 @@
+package com.supwisdom.dlpay.restaurant.service;
+
+import com.supwisdom.dlpay.framework.domain.TOperator;
+import com.supwisdom.dlpay.restaurant.bean.LaborfeeSearchBean;
+import com.supwisdom.dlpay.restaurant.bean.LaborfeeShowBean;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+public interface StatementReportService {
+  @Transactional(rollbackFor = Exception.class,readOnly = true)
+  TOperator getOperatorByOpercode(String opercode);
+
+  @Transactional(rollbackFor = Exception.class,readOnly = true)
+  String getMaxStatementDate();
+
+  @Transactional(rollbackFor = Exception.class,readOnly = true)
+  List<LaborfeeShowBean> getLaborfeeSearchData(LaborfeeSearchBean searchBean);
+
+  @Transactional(rollbackFor = Exception.class,readOnly = true)
+  String getLaborfeeSearchPeriod(LaborfeeSearchBean searchBean);
+
+  @Transactional(rollbackFor = Exception.class,readOnly = true)
+  void doCreateLaborfeeExcel(HttpServletResponse response, List<LaborfeeShowBean> datalist, LaborfeeSearchBean searchBean, String filename, TOperator oper);
+
+
+}
diff --git a/src/main/java/com/supwisdom/dlpay/restaurant/service/impl/StatementReportServiceImpl.java b/src/main/java/com/supwisdom/dlpay/restaurant/service/impl/StatementReportServiceImpl.java
new file mode 100644
index 0000000..5bc7a76
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/restaurant/service/impl/StatementReportServiceImpl.java
@@ -0,0 +1,394 @@
+package com.supwisdom.dlpay.restaurant.service.impl;
+
+import com.supwisdom.dlpay.framework.dao.OperatorDao;
+import com.supwisdom.dlpay.framework.domain.TOperator;
+import com.supwisdom.dlpay.framework.service.SystemUtilService;
+import com.supwisdom.dlpay.framework.util.DateUtil;
+import com.supwisdom.dlpay.framework.util.MoneyUtil;
+import com.supwisdom.dlpay.framework.util.StringUtil;
+import com.supwisdom.dlpay.restaurant.bean.LaborfeeSearchBean;
+import com.supwisdom.dlpay.restaurant.bean.LaborfeeSearchData;
+import com.supwisdom.dlpay.restaurant.bean.LaborfeeShowBean;
+import com.supwisdom.dlpay.restaurant.dao.CheckCtlDao;
+import com.supwisdom.dlpay.restaurant.domain.TCheckCtl;
+import com.supwisdom.dlpay.restaurant.service.StatementReportService;
+import com.supwisdom.dlpay.restaurant.util.ExcelPoiUtil;
+import com.supwisdom.dlpay.restaurant.util.RestaurantConstant;
+import org.apache.poi.hssf.usermodel.*;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.hibernate.query.internal.NativeQueryImpl;
+import org.hibernate.transform.Transformers;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import javax.servlet.http.HttpServletResponse;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+public class StatementReportServiceImpl implements StatementReportService {
+  @Autowired
+  private SystemUtilService systemUtilService;
+  @Autowired
+  private CheckCtlDao checkCtlDao;
+  @Autowired
+  private OperatorDao operatorDao;
+
+  @PersistenceContext
+  private EntityManager entityManager;
+
+  @Override
+  public TOperator getOperatorByOpercode(String opercode) {
+    if (!StringUtil.isEmpty(opercode)) return operatorDao.findByOpercode(opercode.trim());
+    return null;
+  }
+
+  @Override
+  public String getMaxStatementDate() {
+    String result = systemUtilService.getSysdatetime().getHostdate();
+    String statdate = systemUtilService.getBusinessValue(RestaurantConstant.TRANSDTL_STATEMENT_LASTDATE);
+    if (DateUtil.checkDatetimeValid(statdate, "yyyyMMdd")) {
+      result = DateUtil.getNewDay(statdate, -1);
+    } else {
+      TCheckCtl checkCtl = checkCtlDao.getById(RestaurantConstant.CHECK_TRANSDTL_CTLID);
+      if (null != checkCtl) {
+        if (checkCtl.getCheckOk()) {
+          result = checkCtl.getCheckdate();
+        } else {
+          result = DateUtil.getNewDay(checkCtl.getCheckdate(), -1);
+        }
+      }
+    }
+    return result;
+  }
+
+  @Override
+  public List<LaborfeeShowBean> getLaborfeeSearchData(LaborfeeSearchBean searchBean) {
+    if (null != searchBean) {
+      String startdate = DateUtil.unParseToDateFormat(searchBean.getStartdate());
+      String enddate = DateUtil.unParseToDateFormat(searchBean.getEnddate());
+      if ("month".equals(searchBean.getDatetype())) {
+        //按月查询
+        startdate = DateUtil.unParseToDateFormat(searchBean.getYearmonth().trim() + "-01");
+        enddate = String.valueOf(DateUtil.getLastDayOfMonth(Integer.valueOf(searchBean.getYearmonth().substring(0, 4)), Integer.valueOf(searchBean.getYearmonth().substring(5, 7))));
+      }
+
+      StringBuffer sb = new StringBuffer("select cast(ROW_NUMBER() OVER() as int4) as rownum,case when a2.devgroupid is not null then a2.devgroupid when a1.devgroupid is not null then a1.devgroupid else t.devgroupid end as dwid," +
+          " case when a2.devgroupid is not null then a2.groupname when a1.devgroupid is not null then a1.groupname else '' end as dwname, " +
+          " t.devgroupid as groupid, case when a1.devgroupid is not null then a1.groupname else '' end as groupname, " +
+          " sum(case when t.mealtype='breakfast' then t.totalamt+t.feeamt else 0 end) as btotalamt, " +
+          " sum(case when t.mealtype='lunch' then t.totalamt+t.feeamt else 0 end) as ltotalamt, " +
+          " sum(case when t.mealtype='dinner' then t.totalamt+t.feeamt else 0 end) as dtotalamt, " +
+          " sum(case when t.mealtype='breakfast' then t.totalamt else 0 end) as bpayamt, " +
+          " sum(case when t.mealtype='lunch' then t.totalamt else 0 end) as lpayamt, " +
+          " sum(case when t.mealtype='dinner' then t.totalamt else 0 end) as dpayamt, " +
+          " sum(case when t.mealtype='breakfast' then t.feeamt else 0 end) as bfeeamt, " +
+          " sum(case when t.mealtype='lunch' then t.feeamt else 0 end) as lfeeamt, " +
+          " sum(case when t.mealtype='dinner' then t.feeamt else 0 end) as dfeeamt " +
+          "from tb_rpt_mealsdtl t left join tb_devicegroup a1 on t.devgroupid=a1.devgroupid left join tb_devicegroup a2 on a1.pid=a2.devgroupid " +
+          "where t.checkdate>=:startdate and t.checkdate<=:enddate " +
+          "group by t.devgroupid,a1.devgroupid,a2.devgroupid order by t.devgroupid ");
+      Query query = entityManager.createNativeQuery(sb.toString());
+      query.setParameter("startdate", startdate);
+      query.setParameter("enddate", enddate);
+      query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.aliasToBean(LaborfeeSearchData.class));
+      List<LaborfeeSearchData> list = query.getResultList();
+      if (null != list) return transforLaborfeeShowBean(list);
+    }
+    return new ArrayList<>(0);
+  }
+
+  private List<LaborfeeShowBean> transforLaborfeeShowBean(List<LaborfeeSearchData> list) {
+    if (StringUtil.isEmpty(list)) return new ArrayList<>(0);
+
+    List<LaborfeeShowBean> result = new ArrayList<>(0);
+    LaborfeeShowBean sumBean = new LaborfeeShowBean(-1, "总 计", 0D, 0D, 0D, 0D, 0D, 0D, 0D, 0D, 0D);
+    for (LaborfeeSearchData data : list) {
+      sumBean.setBtotalamt(sumBean.getBtotalamt() + data.getBtotalamt());
+      sumBean.setLtotalamt(sumBean.getLtotalamt() + data.getLtotalamt());
+      sumBean.setDtotalamt(sumBean.getDtotalamt() + data.getDtotalamt());
+      sumBean.setBpayamt(sumBean.getBpayamt() + data.getBpayamt());
+      sumBean.setLpayamt(sumBean.getLpayamt() + data.getLpayamt());
+      sumBean.setDpayamt(sumBean.getDpayamt() + data.getDpayamt());
+      sumBean.setBfeeamt(sumBean.getBfeeamt() + data.getBfeeamt());
+      sumBean.setLfeeamt(sumBean.getLfeeamt() + data.getLfeeamt());
+      sumBean.setDfeeamt(sumBean.getDfeeamt() + data.getDfeeamt()); //总计求和
+
+      boolean exist = false;
+      for (LaborfeeShowBean bean : result) {
+        if (bean.getDwid().intValue() == data.getDwid()) {
+          exist = true;
+          bean.getDatalist().add(data);
+          bean.setBtotalamt(bean.getBtotalamt() + data.getBtotalamt());
+          bean.setLtotalamt(bean.getLtotalamt() + data.getLtotalamt());
+          bean.setDtotalamt(bean.getDtotalamt() + data.getDtotalamt());
+
+          bean.setBpayamt(bean.getBpayamt() + data.getBpayamt());
+          bean.setLpayamt(bean.getLpayamt() + data.getLpayamt());
+          bean.setDpayamt(bean.getDpayamt() + data.getDpayamt());
+
+          bean.setBfeeamt(bean.getBfeeamt() + data.getBfeeamt());
+          bean.setLfeeamt(bean.getLfeeamt() + data.getLfeeamt());
+          bean.setDfeeamt(bean.getDfeeamt() + data.getDfeeamt());
+          break;
+        }
+      }
+
+      if (!exist) {
+        LaborfeeShowBean tmp = new LaborfeeShowBean();
+        tmp.setDwid(data.getDwid());
+        tmp.setDwname(data.getDwname());
+        tmp.setBtotalamt(data.getBtotalamt());
+        tmp.setLtotalamt(data.getLtotalamt());
+        tmp.setDtotalamt(data.getDtotalamt());
+
+        tmp.setBpayamt(data.getBpayamt());
+        tmp.setLpayamt(data.getLpayamt());
+        tmp.setDpayamt(data.getDpayamt());
+
+        tmp.setBfeeamt(data.getBfeeamt());
+        tmp.setLfeeamt(data.getLfeeamt());
+        tmp.setDfeeamt(data.getDfeeamt());
+        tmp.getDatalist().add(data);
+
+        result.add(tmp);
+      }
+
+    }
+
+    result.add(sumBean); //最后加上总计
+    return result;
+  }
+
+  @Override
+  public String getLaborfeeSearchPeriod(LaborfeeSearchBean searchBean) {
+    if ("month".equals(searchBean.getDatetype())) {
+      return DateUtil.reformatDatetime(DateUtil.unParseToDateFormat(searchBean.getYearmonth()), "yyyyMM", "yyyy年MM月份");
+    } else {
+      String startdate = DateUtil.unParseToDateFormat(searchBean.getStartdate());
+      String enddate = DateUtil.unParseToDateFormat(searchBean.getEnddate());
+      if (startdate.equals(enddate)) {
+        return DateUtil.reformatDatetime(startdate, "yyyyMMdd", "yyyy年MM月dd日");
+      } else {
+        return DateUtil.reformatDatetime(startdate, "yyyyMMdd", "yyyy年MM月dd日") + " ~ " + DateUtil.reformatDatetime(enddate, "yyyyMMdd", "yyyy年MM月dd日");
+      }
+    }
+  }
+
+  @Override
+  public void doCreateLaborfeeExcel(HttpServletResponse response, List<LaborfeeShowBean> datalist, LaborfeeSearchBean searchBean, String filename, TOperator oper) {
+    // 创建工作簿实例
+    HSSFWorkbook workbook = new HSSFWorkbook();
+    HSSFSheet sheet = workbook.createSheet("商户劳务费清单(总金额打折版)");
+
+    //TODO:设置列宽
+    //序号|单位|食堂|(正价:早餐|中餐|晚餐)|(折后:早餐|中餐|晚餐)|(劳务费:早餐|中餐|晚餐|小计)
+    int columns = 13; //
+    sheet.setColumnWidth(0, ExcelPoiUtil.columnWidth(6)); //序号
+    sheet.setColumnWidth(1, ExcelPoiUtil.columnWidth(25)); //单位
+    sheet.setColumnWidth(2, ExcelPoiUtil.columnWidth(20)); //食堂
+    for (int i = 3; i < columns; i++) {
+      sheet.setColumnWidth(i, ExcelPoiUtil.columnWidth(12));
+    }
+
+    //标题样式
+    HSSFCellStyle titleStyle = ExcelPoiUtil.creatStyle(workbook, "宋体", true, 20, HSSFCellStyle.ALIGN_CENTER, false); //设置单元格样式
+    //表头样式
+    HSSFCellStyle headStyle = ExcelPoiUtil.creatStyle(workbook, "宋体", true, 15, HSSFCellStyle.ALIGN_CENTER, true); //设置单元格样式
+    //正文样式 有边框-textStyle1 无边框-textStyle2
+    HSSFCellStyle textStyle1 = ExcelPoiUtil.creatStyle(workbook, "宋体", false, 10, HSSFCellStyle.ALIGN_CENTER, true); //设置单元格样式
+    HSSFCellStyle textStyle2 = ExcelPoiUtil.creatStyle(workbook, "宋体", false, 10, HSSFCellStyle.ALIGN_CENTER, false); //设置单元格样式
+
+
+    //TODO:创建标题
+    HSSFRow row0 = ExcelPoiUtil.createRow(sheet, 0, 800); //表格标题
+    ExcelPoiUtil.createCell(row0, 0, titleStyle, filename);
+    sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, columns - 1)); //合并单元格CellRangeAddress构造参数依次表示 起始行,截至行,起始列, 截至列
+
+    //TODO:创建表格页眉
+    HSSFRow row1 = ExcelPoiUtil.createRow(sheet, 1, 400);
+    ExcelPoiUtil.createCell(row1, 0, textStyle2, "区间");
+    ExcelPoiUtil.createCell(row1, 1, textStyle2, getLaborfeeSearchPeriod(searchBean));
+    ExcelPoiUtil.createCell(row1, columns - 1, ExcelPoiUtil.creatStyle(workbook, "宋体", false, 10, HSSFCellStyle.ALIGN_RIGHT, false), "单位:元");
+
+    //TODO:创建表头(poi做多行合并,一定需要先绘制单元格,然后写入数据,最后合并)
+    HSSFRow row2 = ExcelPoiUtil.createRow(sheet, 2, 600);
+    ExcelPoiUtil.createCell(row2, 0, headStyle, "序号");
+    ExcelPoiUtil.createCell(row2, 1, headStyle, "单位");
+    ExcelPoiUtil.createCell(row2, 2, headStyle, "食堂");
+
+    ExcelPoiUtil.createCell(row2, 3, headStyle, "消费正价");
+    ExcelPoiUtil.createCell(row2, 4, headStyle, null);
+    ExcelPoiUtil.createCell(row2, 5, headStyle, null);
+    sheet.addMergedRegion(new CellRangeAddress(2, 2, 3, 5)); //合并单元格CellRangeAddress构造参数依次表示 起始行,截至行,起始列, 截至列
+
+    ExcelPoiUtil.createCell(row2, 6, headStyle, "优惠后支付");
+    ExcelPoiUtil.createCell(row2, 7, headStyle, null);
+    ExcelPoiUtil.createCell(row2, 8, headStyle, null);
+    sheet.addMergedRegion(new CellRangeAddress(2, 2, 6, 8)); //合并单元格CellRangeAddress构造参数依次表示 起始行,截至行,起始列, 截至列
+
+    ExcelPoiUtil.createCell(row2, 9, headStyle, "应支付劳务费");
+    ExcelPoiUtil.createCell(row2, 10, headStyle, null);
+    ExcelPoiUtil.createCell(row2, 11, headStyle, null);
+    ExcelPoiUtil.createCell(row2, 12, headStyle, null);
+    sheet.addMergedRegion(new CellRangeAddress(2, 2, 9, 12)); //合并单元格CellRangeAddress构造参数依次表示 起始行,截至行,起始列, 截至列
+
+
+    HSSFRow row3 = ExcelPoiUtil.createRow(sheet, 3, 800); //表头第二行
+    ExcelPoiUtil.createCell(row3, 0, headStyle, null);
+    sheet.addMergedRegion(new CellRangeAddress(2, 3, 0, 0)); //合并列
+
+    ExcelPoiUtil.createCell(row3, 1, headStyle, null);
+    sheet.addMergedRegion(new CellRangeAddress(2, 3, 1, 1)); //合并列
+
+    ExcelPoiUtil.createCell(row3, 2, headStyle, null);
+    sheet.addMergedRegion(new CellRangeAddress(2, 3, 2, 2)); //合并列
+
+    ExcelPoiUtil.createCell(row3, 3, headStyle, "早餐\n正价金额");
+    ExcelPoiUtil.createCell(row3, 4, headStyle, "午餐\n正价金额");
+    ExcelPoiUtil.createCell(row3, 5, headStyle, "晚餐\n正价金额");
+
+    ExcelPoiUtil.createCell(row3, 6, headStyle, "早餐\n折后金额");
+    ExcelPoiUtil.createCell(row3, 7, headStyle, "午餐\n折后金额");
+    ExcelPoiUtil.createCell(row3, 8, headStyle, "晚餐\n折后金额");
+
+    ExcelPoiUtil.createCell(row3, 9, headStyle, "早餐\n劳务费");
+    ExcelPoiUtil.createCell(row3, 10, headStyle, "午餐\n劳务费");
+    ExcelPoiUtil.createCell(row3, 11, headStyle, "晚餐\n劳务费");
+    ExcelPoiUtil.createCell(row3, 12, headStyle, "应支付劳\n务费小计");
+
+    //TODO: 数据
+    int rowNum = 4;
+    if (StringUtil.isEmpty(datalist)) {
+      //无数据
+      HSSFRow row4 = ExcelPoiUtil.createRow(sheet, rowNum, 500);
+      ExcelPoiUtil.createCell(row4, 0, textStyle1, "无数据");
+      for(int n=1;n<columns;n++) ExcelPoiUtil.createCell(row4, n, textStyle1, null);
+      sheet.addMergedRegion(new CellRangeAddress(rowNum, rowNum, 0, columns - 1)); //合并列
+    } else {
+      //有数据
+      for (int i = 0; i < datalist.size() - 1; i++) {
+        LaborfeeShowBean rowData = datalist.get(i);
+        if (StringUtil.isEmpty(rowData.getDatalist())) continue;
+
+        int firstRowNo = rowNum;
+        HSSFRow row = ExcelPoiUtil.createRow(sheet, rowNum++, 500);
+        ExcelPoiUtil.createCell(row, 0, textStyle1, "" + rowData.getDatalist().get(0).getRownum()); //序号
+        ExcelPoiUtil.createCell(row, 1, textStyle1, rowData.getDwname()); //单位
+
+        for (int j = 0; j < rowData.getDatalist().size(); j++) {
+          LaborfeeSearchData detail = rowData.getDatalist().get(j);
+          if (j > 0) {
+            //非首行
+            row = ExcelPoiUtil.createRow(sheet, rowNum++, 500);
+            ExcelPoiUtil.createCell(row, 0, textStyle1, "" + detail.getRownum()); //序号
+            ExcelPoiUtil.createCell(row, 1, textStyle1, null); //序号
+          }
+          ExcelPoiUtil.createCell(row, 2, textStyle1, detail.getGroupname()); //食堂
+          ExcelPoiUtil.createCell(row, 3, textStyle1, MoneyUtil.formatYuanToString(detail.getBtotalamt())); //早餐
+          ExcelPoiUtil.createCell(row, 4, textStyle1, MoneyUtil.formatYuanToString(detail.getLtotalamt())); //午餐
+          ExcelPoiUtil.createCell(row, 5, textStyle1, MoneyUtil.formatYuanToString(detail.getDtotalamt())); //晚餐
+
+          ExcelPoiUtil.createCell(row, 6, textStyle1, MoneyUtil.formatYuanToString(detail.getBpayamt())); //早餐
+          ExcelPoiUtil.createCell(row, 7, textStyle1, MoneyUtil.formatYuanToString(detail.getLpayamt())); //午餐
+          ExcelPoiUtil.createCell(row, 8, textStyle1, MoneyUtil.formatYuanToString(detail.getDpayamt())); //晚餐
+
+          ExcelPoiUtil.createCell(row, 9, textStyle1, MoneyUtil.formatYuanToString(detail.getBfeeamt())); //早餐
+          ExcelPoiUtil.createCell(row, 10, textStyle1, MoneyUtil.formatYuanToString(detail.getLfeeamt())); //午餐
+          ExcelPoiUtil.createCell(row, 11, textStyle1, MoneyUtil.formatYuanToString(detail.getDfeeamt())); //晚餐
+          ExcelPoiUtil.createCell(row, 12, textStyle1, MoneyUtil.formatYuanToString(detail.getBfeeamt() + detail.getLfeeamt() + detail.getDfeeamt())); //小计
+        }
+        if (rowData.getDatalist().size() > 1) {
+          sheet.addMergedRegion(new CellRangeAddress(firstRowNo, rowNum - 1, 1, 1));  //合并列
+
+          //单位小计行
+          row = ExcelPoiUtil.createRow(sheet, rowNum++, 500);
+          ExcelPoiUtil.createCell(row, 0, textStyle1, rowData.getDwname() + "小计");
+          ExcelPoiUtil.createCell(row, 1, textStyle1, null);
+          ExcelPoiUtil.createCell(row, 2, textStyle1, null);
+          sheet.addMergedRegion(new CellRangeAddress(rowNum - 1, rowNum - 1, 0, 2));  //合并列
+
+          ExcelPoiUtil.createCell(row, 3, textStyle1, MoneyUtil.formatYuanToString(rowData.getBtotalamt())); //早餐
+          ExcelPoiUtil.createCell(row, 4, textStyle1, MoneyUtil.formatYuanToString(rowData.getLtotalamt())); //午餐
+          ExcelPoiUtil.createCell(row, 5, textStyle1, MoneyUtil.formatYuanToString(rowData.getDtotalamt())); //晚餐
+
+          ExcelPoiUtil.createCell(row, 6, textStyle1, MoneyUtil.formatYuanToString(rowData.getBpayamt())); //早餐
+          ExcelPoiUtil.createCell(row, 7, textStyle1, MoneyUtil.formatYuanToString(rowData.getLpayamt())); //午餐
+          ExcelPoiUtil.createCell(row, 8, textStyle1, MoneyUtil.formatYuanToString(rowData.getDpayamt())); //晚餐
+
+          ExcelPoiUtil.createCell(row, 9, textStyle1, MoneyUtil.formatYuanToString(rowData.getBfeeamt())); //早餐
+          ExcelPoiUtil.createCell(row, 10, textStyle1, MoneyUtil.formatYuanToString(rowData.getLfeeamt())); //午餐
+          ExcelPoiUtil.createCell(row, 11, textStyle1, MoneyUtil.formatYuanToString(rowData.getDfeeamt())); //晚餐
+          ExcelPoiUtil.createCell(row, 12, textStyle1, MoneyUtil.formatYuanToString(rowData.getBfeeamt() + rowData.getLfeeamt() + rowData.getDfeeamt())); //小计
+        }
+      }
+
+      //TODO: 总计
+      LaborfeeShowBean sumBean = datalist.get(datalist.size() - 1);
+      HSSFRow sumRow = ExcelPoiUtil.createRow(sheet, rowNum, 500);
+      ExcelPoiUtil.createCell(sumRow, 0, textStyle1, sumBean.getDwname());
+      ExcelPoiUtil.createCell(sumRow, 1, textStyle1, null);
+      ExcelPoiUtil.createCell(sumRow, 2, textStyle1, null);
+      sheet.addMergedRegion(new CellRangeAddress(rowNum, rowNum, 0, 2));  //合并列
+
+      ExcelPoiUtil.createCell(sumRow, 3, textStyle1, MoneyUtil.formatYuanToString(sumBean.getBtotalamt())); //早餐
+      ExcelPoiUtil.createCell(sumRow, 4, textStyle1, MoneyUtil.formatYuanToString(sumBean.getLtotalamt())); //午餐
+      ExcelPoiUtil.createCell(sumRow, 5, textStyle1, MoneyUtil.formatYuanToString(sumBean.getDtotalamt())); //晚餐
+
+      ExcelPoiUtil.createCell(sumRow, 6, textStyle1, MoneyUtil.formatYuanToString(sumBean.getBpayamt())); //早餐
+      ExcelPoiUtil.createCell(sumRow, 7, textStyle1, MoneyUtil.formatYuanToString(sumBean.getLpayamt())); //午餐
+      ExcelPoiUtil.createCell(sumRow, 8, textStyle1, MoneyUtil.formatYuanToString(sumBean.getDpayamt())); //晚餐
+
+      ExcelPoiUtil.createCell(sumRow, 9, textStyle1, MoneyUtil.formatYuanToString(sumBean.getBfeeamt())); //早餐
+      ExcelPoiUtil.createCell(sumRow, 10, textStyle1, MoneyUtil.formatYuanToString(sumBean.getLfeeamt())); //午餐
+      ExcelPoiUtil.createCell(sumRow, 11, textStyle1, MoneyUtil.formatYuanToString(sumBean.getDfeeamt())); //晚餐
+      ExcelPoiUtil.createCell(sumRow, 12, textStyle1, MoneyUtil.formatYuanToString(sumBean.getBfeeamt() + sumBean.getLfeeamt() + sumBean.getDfeeamt())); //小计
+    }
+
+    //TODO: 表格页脚
+    HSSFCellStyle textStyle3 = ExcelPoiUtil.creatStyle(workbook, "宋体", false, 10, HSSFCellStyle.ALIGN_LEFT, false); //设置单元格样式
+    HSSFRow buttom = ExcelPoiUtil.createRow(sheet, ++rowNum, 400);
+    ExcelPoiUtil.createCell(buttom, 0, textStyle3, "制表人:" + (oper == null ? "unknow" : oper.getOpername()) + "  " + DateUtil.reformatDatetime(systemUtilService.getSysdatetime().getHostdatetime(), DateUtil.DATETIME_FMT, "yyyy-MM-dd HH:mm:ss"));
+    sheet.addMergedRegion(new CellRangeAddress(rowNum, rowNum, 0, 2));  //合并列
+
+    //TODO: 审核信息
+    HSSFRow signRow10 = ExcelPoiUtil.createRow(sheet, rowNum + 3, 400);
+    ExcelPoiUtil.createCell(signRow10, 0, textStyle3, "银行方审核盖章:");
+    ExcelPoiUtil.createCell(signRow10, 6, textStyle3, "苍山饭店审核盖章:");
+    sheet.addMergedRegion(new CellRangeAddress(rowNum + 3, rowNum + 3, 0, 5));  //合并列
+    sheet.addMergedRegion(new CellRangeAddress(rowNum + 3, rowNum + 3, 6, columns - 1));  //合并列
+    HSSFRow signRow11 = ExcelPoiUtil.createRow(sheet, rowNum + 4, 400);
+    ExcelPoiUtil.createCell(signRow11, 0, textStyle3, "审核人:");
+    ExcelPoiUtil.createCell(signRow11, 6, textStyle3, "审核人:");
+    sheet.addMergedRegion(new CellRangeAddress(rowNum + 4, rowNum + 4, 0, 5));  //合并列
+    sheet.addMergedRegion(new CellRangeAddress(rowNum + 4, rowNum + 4, 6, columns - 1));  //合并列
+
+    HSSFRow signRow20 = ExcelPoiUtil.createRow(sheet, rowNum + 8, 400);
+    ExcelPoiUtil.createCell(signRow20, 0, textStyle3, "市民卡公司审核盖章:");
+    ExcelPoiUtil.createCell(signRow20, 6, textStyle3, "建桥园审核盖章:");
+    sheet.addMergedRegion(new CellRangeAddress(rowNum + 8, rowNum + 8, 0, 5));  //合并列
+    sheet.addMergedRegion(new CellRangeAddress(rowNum + 8, rowNum + 8, 6, columns - 1));  //合并列
+    HSSFRow signRow21 = ExcelPoiUtil.createRow(sheet, rowNum + 9, 400);
+    ExcelPoiUtil.createCell(signRow21, 0, textStyle3, "审核人:");
+    ExcelPoiUtil.createCell(signRow21, 6, textStyle3, "审核人:");
+    sheet.addMergedRegion(new CellRangeAddress(rowNum + 9, rowNum + 9, 0, 5));  //合并列
+    sheet.addMergedRegion(new CellRangeAddress(rowNum + 9, rowNum + 9, 6, columns - 1));  //合并列
+
+    try {
+      response.setContentType("application/x-msdownload");
+      response.setHeader("Content-Disposition", "attachment;" + " filename="+ new String(filename.getBytes(), "ISO-8859-1") + ".xls");
+      OutputStream out = response.getOutputStream();
+      workbook.write(out);
+      out.flush();
+      out.close();
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+
+  }
+
+}
diff --git a/src/main/java/com/supwisdom/dlpay/restaurant/util/ExcelPoiUtil.java b/src/main/java/com/supwisdom/dlpay/restaurant/util/ExcelPoiUtil.java
new file mode 100644
index 0000000..4fa1115
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/restaurant/util/ExcelPoiUtil.java
@@ -0,0 +1,48 @@
+package com.supwisdom.dlpay.restaurant.util;
+
+import org.apache.poi.hssf.usermodel.*;
+import org.apache.poi.hssf.util.HSSFColor;
+
+public class ExcelPoiUtil {
+  public static int columnWidth(int width) {
+    return (int) ((width + 0.72) * 256);
+  }
+
+  public static HSSFCellStyle creatStyle(HSSFWorkbook wb, String fontName,  boolean fontWeight, int fontHeightInPoints, short alignment, boolean border){
+    //设置内容字体
+    HSSFFont fontContent = wb.createFont();
+    if (fontWeight) fontContent.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); // 字体加粗
+    fontContent.setFontName(fontName);
+    fontContent.setFontHeightInPoints((short) fontHeightInPoints);
+    //创建内容样式
+    HSSFCellStyle styleContent = wb.createCellStyle();
+    styleContent.setFont(fontContent);
+    styleContent.setWrapText(true);
+    styleContent.setAlignment(alignment);
+    styleContent.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
+    if (border){
+      styleContent.setBorderBottom(HSSFCellStyle.BORDER_THIN);
+      styleContent.setBottomBorderColor(HSSFColor.BLACK.index);
+      styleContent.setBorderLeft(HSSFCellStyle.BORDER_THIN);
+      styleContent.setLeftBorderColor(HSSFColor.BLACK.index);
+      styleContent.setBorderRight(HSSFCellStyle.BORDER_THIN);
+      styleContent.setRightBorderColor(HSSFColor.BLACK.index);
+      styleContent.setBorderTop(HSSFCellStyle.BORDER_THIN);
+      styleContent.setTopBorderColor(HSSFColor.BLACK.index);
+    }
+    return styleContent;
+  }
+
+  public static HSSFRow createRow(HSSFSheet sheet, int rowIndex, int height) {
+    HSSFRow row = sheet.createRow(rowIndex);
+    row.setHeight((short) height);
+    return row;
+  }
+
+  public static HSSFCell createCell(HSSFRow row, int columnIndex, HSSFCellStyle hssfCellStyle, String content) {
+    HSSFCell cell = row.createCell(columnIndex);
+    cell.setCellStyle(hssfCellStyle);
+    cell.setCellValue(content);
+    return cell;
+  }
+}
diff --git a/src/main/kotlin/com/supwisdom/dlpay/security.kt b/src/main/kotlin/com/supwisdom/dlpay/security.kt
index 7e0b13a..0d711ef 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/security.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/security.kt
@@ -189,6 +189,7 @@
                         .antMatchers("/login", "/login/form").permitAll()
                         .antMatchers("/static/**").permitAll()
                         .antMatchers("/code/image").permitAll()
+                        .antMatchers("/report/print/**").permitAll() //报表打印
                         .antMatchers("/**").hasAnyRole("USER", "ADMIN")
                         .anyRequest().authenticated()
                         .and()
diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql
index e01f263..b49c77f 100644
--- a/src/main/resources/data.sql
+++ b/src/main/resources/data.sql
@@ -124,6 +124,8 @@
 INSERT INTO "tb_function" (id,createtime,isleaf,lastsaved,menuicon,menuurl,name,ordernum,parentid) VALUES (11, NULL, 0, NULL, 'layui-icon-util', '#', '就餐白名单管理', 7, -1);
 INSERT INTO  "tb_function"("id", "createtime", "isleaf", "lastsaved", "menuicon", "menuurl", "name", "ordernum", "parentid") VALUES (32, NULL, 1, NULL, '', '/shopsettlement/index', '商户管理', 2, 22);
 INSERT INTO  "tb_function"("id", "createtime", "isleaf", "lastsaved", "menuicon", "menuurl", "name", "ordernum", "parentid") VALUES (34, NULL, 1, NULL, '', '/customerlist/index', '餐补人员名单管理', 1, 24);
+INSERT INTO "tb_function"("id", "createtime", "isleaf", "lastsaved", "menuicon", "menuurl", "name", "ordernum", "parentid") VALUES (35, NULL, 0, NULL, 'layui-icon-rmb', '#', '报表中心', 10, -1);
+INSERT INTO "tb_function"("id", "createtime", "isleaf", "lastsaved", "menuicon", "menuurl", "name", "ordernum", "parentid") VALUES (36, NULL, 1, NULL, '', '/report/laborfee', '商户劳务费报表', 1, 35);
 
 
 
@@ -307,6 +309,8 @@
 INSERT INTO  "tb_permission"("id", "resid", "role_func_id", "roleid") VALUES ('297ea57c6e26421b016e264517d40046', 92, NULL, 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs');
 INSERT INTO  "tb_permission"("id", "resid", "role_func_id", "roleid") VALUES ('297ea57c6e86d617016e86daac05004a', 94, NULL, 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs');
 
+INSERT INTO  "tb_permission"("id", "resid", "role_func_id", "roleid") VALUES ('ff8080816ea5a411016ea5bc08af007d', 95, NULL, 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs');
+INSERT INTO  "tb_permission"("id", "resid", "role_func_id", "roleid") VALUES ('ff8080816eb6236e016eb62961f8007d', 96, NULL, 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs');
 
 
 INSERT INTO "tb_resource" (id,code,function_id,name,uri) VALUES (4, '1', 4, '添加功能', '/function/add');
@@ -402,12 +406,13 @@
 INSERT INTO  "tb_resource"("id", "code", "function_id", "name", "uri") VALUES (43, '', 18, '审核', '/whitelistcheck/load4checkdetail');
 INSERT INTO  "tb_resource"("id", "code", "function_id", "name", "uri") VALUES (51, '', 31, '查询', '/whitelistbind/devbind');
 INSERT INTO  "tb_resource"("id", "code", "function_id", "name", "uri") VALUES (72, '', 31, '绑定', '/whitelistbind/dobinddev');
-
 INSERT INTO "tb_resource"("id", "code", "function_id", "name", "uri") VALUES (73, '', 32, '查询', '/shopsettlement/index');
+
 INSERT INTO "tb_resource"("id", "code", "function_id", "name", "uri") VALUES (92, '', 32, '添加', '/shopsettlement/loadadd');
 INSERT INTO "tb_resource"("id", "code", "function_id", "name", "uri") VALUES (93, '', 32, '删除', '/shopsettlement/delete');
 INSERT INTO "tb_resource"("id", "code", "function_id", "name", "uri") VALUES (94, '', 34, '查询', '/customerlist/index');
-
+INSERT INTO  "tb_resource"("id", "code", "function_id", "name", "uri") VALUES (95, '', 36, '查询', '/report/laborfee');
+INSERT INTO  "tb_resource"("id", "code", "function_id", "name", "uri") VALUES (96, '', 36, '导出', '/report/excelexportlaborfee');
 
 
 
@@ -458,6 +463,10 @@
 
 INSERT INTO "tb_role_function"("id", "functionid", "permissions", "roleid") VALUES ('297ea57c6e26421b016e264517d30043', 32, NULL, 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs');
 
+INSERT INTO "tb_role_function"("id", "functionid", "permissions", "roleid") VALUES ('ff8080816ea5a411016ea5bc08ae007b', 35, NULL, 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs');
+INSERT INTO "tb_role_function"("id", "functionid", "permissions", "roleid") VALUES ('ff8080816ea5a411016ea5bc08ae007c', 36, NULL, 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs');
+
+
 INSERT INTO "tb_shopsettlement" (shopsettlementno,operno,shopid,shopname) VALUES ('1', '1234', '2000000012', '测试商户');
 INSERT INTO "tb_subject" (subjno,balflag,displayflag,endflag,fsubjno,opendate,subjlevel,subjname,subjtype) VALUES ('1001', 1, 'y', 1, NULL, 20190604, 1, '库存现金', 1);
 INSERT INTO "tb_subject" (subjno,balflag,displayflag,endflag,fsubjno,opendate,subjlevel,subjname,subjtype) VALUES ('1002', 1, 'y', 1, NULL, 20190604, 1, '银行存款', 1);
diff --git a/src/main/resources/static/custom/css/custom.css b/src/main/resources/static/custom/css/custom.css
index 726abe7..6a8e318 100644
--- a/src/main/resources/static/custom/css/custom.css
+++ b/src/main/resources/static/custom/css/custom.css
@@ -7,4 +7,15 @@
     opacity: 0;
     width: 113px;
     height: 34px;
-}
\ No newline at end of file
+}
+
+button.sw-print {height: 34px!important;}
+
+.sw-table thead tr th {font-size: 12px;min-height: 16px;line-height: 16px;text-align: center;font-weight: bold;}
+.sw-table tbody tr td {font-size: 12px;min-height: 16px;line-height: 16px;text-align: center;}
+
+.sw-print thead tr th { color:black!important; border: 1px solid black!important; }
+.sw-print tbody tr td { color:black!important; border: 1px solid black!important; }
+
+.sw-print-sign { border-collapse: collapse; width: 100%;}
+.sw-print-sign tr td { border:0; color: black; font-weight: normal; font-size: 14px; min-height: 15px;line-height: 15px;text-align: left; padding-left: 3px;}
\ No newline at end of file
diff --git a/src/main/resources/static/custom/css/login.css b/src/main/resources/static/custom/css/login.css
index 60c4cf0..1092a1b 100644
--- a/src/main/resources/static/custom/css/login.css
+++ b/src/main/resources/static/custom/css/login.css
@@ -1,7 +1,7 @@
 /** EasyWeb */
 
 body {
-    background-image: url("../images/bg_login.png");
+    background-image: url("../images/bg_login_st.jpg");
     background-repeat: no-repeat;
     background-size: cover;
 }
diff --git a/src/main/resources/static/custom/images/bg_login_st.jpg b/src/main/resources/static/custom/images/bg_login_st.jpg
new file mode 100644
index 0000000..260a1a3
--- /dev/null
+++ b/src/main/resources/static/custom/images/bg_login_st.jpg
Binary files differ
diff --git a/src/main/resources/static/libs/CLodop/CLodop_Setup_for_Win32NT_https_3.093Extend.exe b/src/main/resources/static/libs/CLodop/CLodop_Setup_for_Win32NT_https_3.093Extend.exe
new file mode 100755
index 0000000..9988d28
--- /dev/null
+++ b/src/main/resources/static/libs/CLodop/CLodop_Setup_for_Win32NT_https_3.093Extend.exe
Binary files differ
diff --git a/src/main/resources/static/libs/CLodop/LodopFuncs.js b/src/main/resources/static/libs/CLodop/LodopFuncs.js
new file mode 100755
index 0000000..59b481c
--- /dev/null
+++ b/src/main/resources/static/libs/CLodop/LodopFuncs.js
@@ -0,0 +1,144 @@
+var CreatedOKLodop7766 = null, CLodopIsLocal;

+

+//====判断是否需要 Web打印服务CLodop:===

+//===(不支持插件的浏览器版本需要用它)===

+function needCLodop() {

+    try {        

+        return true;

+    } catch (err) {

+        return true;

+    }

+}

+

+//====页面引用CLodop云打印必须的JS文件,用双端口(8000和18000)避免其中某个被占用:====

+if (needCLodop()) {

+    // https

+    // var src1 = "https://localhost:8443/CLodopfuncs.js?priority=1";

+    // var src2 = "https://localhost:8444/CLodopfuncs.js?priority=0";

+

+    //http

+    var src1 = "http://localhost:8000/CLodopfuncs.js?priority=1";

+    var src2 ="http://localhost:18000/CLodopfuncs.js?priority=0";

+

+    var head = document.head || document.getElementsByTagName("head")[0] || document.documentElement;

+    var oscript = document.createElement("script");

+    oscript.src = src1;

+    head.insertBefore(oscript, head.firstChild);

+    oscript = document.createElement("script");

+    oscript.src = src2;

+    head.insertBefore(oscript, head.firstChild);

+    CLodopIsLocal = !!((src1 + src2).match(/\/\/localho|\/\/127.0.0./i));

+}

+

+//====获取LODOP对象的主过程:====

+function getLodop(oOBJECT, oEMBED) {

+    // debugger

+    var baseUrl = window.location.pathname;

+    var strHtmInstall = "<br><font color='#FF00FF'>打印控件未安装!点击这里<a href='"+baseUrl+"static/libs/CLodop/install_lodop32.exe' target='_self'>执行安装</a>,安装后请刷新页面或重新进入。</font>";

+    var strHtmUpdate = "<br><font color='#FF00FF'>打印控件需要升级!点击这里<a href='"+baseUrl+"static/libs/CLodop/install_lodop32.exe' target='_self'>执行升级</a>,升级后请重新进入。</font>";

+    var strHtm64_Install = "<br><font color='#FF00FF'>打印控件未安装!点击这里<a href='"+baseUrl+"static/libs/CLodop/install_lodop64.exe' target='_self'>执行安装</a>,安装后请刷新页面或重新进入。</font>";

+    var strHtm64_Update = "<br><font color='#FF00FF'>打印控件需要升级!点击这里<a href='"+baseUrl+"static/libs/CLodop/install_lodop64.exe' target='_self'>执行升级</a>,升级后请重新进入。</font>";

+    var strHtmFireFox = "<br><font color='#FF00FF'>(注意:如曾安装过Lodop旧版附件npActiveXPLugin,请在【工具】->【附加组件】->【扩展】中先卸它)</font>";

+    var strHtmChrome = "<font color='#FF00FF'>(如果此前正常,仅因浏览器升级或重安装而出问题,需重新执行以上安装)</font>";

+    var strCLodopInstall_1 = "<font color='#FF00FF'>Web打印服务CLodop未安装启动,点击这里<a href='"+baseUrl+"static/libs/CLodop/CLodop_Setup_for_Win32NT_https_3.093Extend.exe' target='_self'>下载执行安装</a>";

+    var strCLodopInstall_2 = "<br>(若此前已安装过,可<a href='CLodop.protocol:setup' target='_self'>点这里直接再次启动</a>)";

+    var strCLodopInstall_3 = ",成功后请刷新本页面。</font>";

+    var strCLodopUpdate = "<font color='#FF00FF'>Web打印服务CLodop需升级!点击这里<a href='"+baseUrl+"static/libs/CLodop/CLodop_Setup_for_Win32NT_https_3.093Extend.exe' target='_self'>执行升级</a>,升级后请刷新页面。</font>";

+    var LODOP;

+    try {

+        var ua = navigator.userAgent;

+        var isIE = !!(ua.match(/MSIE/i)) || !!(ua.match(/Trident/i));

+        if (needCLodop()) {

+            try {

+                LODOP = getCLodop();

+            } catch (err) {}

+            if (!LODOP && document.readyState !== "complete") {

+                // alert("网页还没下载完毕,请稍等一下再操作.");

+                layer.msg("网页还没下载完毕,请稍等一下再操作.",{icon: 0});

+                return;

+            }

+            if (!LODOP) {

+                // document.body.innerHTML = strCLodopInstall_1 + (CLodopIsLocal ? strCLodopInstall_2 : "") + strCLodopInstall_3 + document.body.innerHTML;

+                layer.open({

+                    title: '安装CLodop插件',

+                    area: '500px',

+                    content: strCLodopInstall_1 + (CLodopIsLocal ? strCLodopInstall_2 : "") + strCLodopInstall_3

+                });

+                return;

+            } else {

+                if (CLODOP.CVERSION < "3.0.4.8") {

+                    // document.body.innerHTML = strCLodopUpdate + document.body.innerHTML;

+                    layer.open({

+                        title: '安装CLodop插件',

+                        area: '500px',

+                        content: strCLodopUpdate

+                    });

+                }

+                if (oEMBED && oEMBED.parentNode)

+                    oEMBED.parentNode.removeChild(oEMBED);

+                if (oOBJECT && oOBJECT.parentNode)

+                    oOBJECT.parentNode.removeChild(oOBJECT);

+            }

+        } else {

+            var is64IE = isIE && !!(ua.match(/x64/i));

+            //=====如果页面有Lodop就直接使用,没有则新建:==========

+            if (oOBJECT || oEMBED) {

+                if (isIE)

+                    LODOP = oOBJECT;

+                else

+                    LODOP = oEMBED;

+            } else if (!CreatedOKLodop7766) {

+                LODOP = document.createElement("object");

+                LODOP.setAttribute("width", 0);

+                LODOP.setAttribute("height", 0);

+                LODOP.setAttribute("style", "position:absolute;left:0px;top:-100px;width:0px;height:0px;");

+                if (isIE)

+                    LODOP.setAttribute("classid", "clsid:2105C259-1E0C-4534-8141-A753534CB4CA");

+                else

+                    LODOP.setAttribute("type", "application/x-print-lodop");

+                document.documentElement.appendChild(LODOP);

+                CreatedOKLodop7766 = LODOP;

+            } else

+                LODOP = CreatedOKLodop7766;

+            //=====Lodop插件未安装时提示下载地址:==========

+            if ((!LODOP) || (!LODOP.VERSION)) {

+                var tipmsg = "";

+                if (ua.indexOf('Chrome') >= 0){

+                    // document.body.innerHTML = strHtmChrome + document.body.innerHTML;

+                    tipmsg +=strHtmChrome;

+                }

+

+                if (ua.indexOf('Firefox') >= 0){

+                    // document.body.innerHTML = strHtmFireFox + document.body.innerHTML;

+                    tipmsg += strHtmFireFox;

+                }

+                // document.body.innerHTML = (is64IE ? strHtm64_Install : strHtmInstall) + document.body.innerHTML;

+                tipmsg += (is64IE ? strHtm64_Install : strHtmInstall)

+                layer.open({

+                    title: '安装CLodop插件',

+                    area: '500px',

+                    content: tipmsg

+                });

+                return LODOP;

+            }

+        }

+        if (LODOP.VERSION < "6.2.2.3") {

+            if (!needCLodop()){

+                // document.body.innerHTML = (is64IE ? strHtm64_Update : strHtmUpdate) + document.body.innerHTML;

+                layer.open({

+                    title: '安装CLodop插件',

+                    area: '500px',

+                    content: (is64IE ? strHtm64_Update : strHtmUpdate)

+                });

+            }

+            return LODOP;

+        }

+        //===如下空白位置适合调用统一功能(如注册语句、语言选择等):===

+

+        //=======================================================

+        return LODOP;

+    } catch (err) {

+        // alert("getLodop出错:" + err);

+        layer.msg("getLodop出错:" + err, {icon: 2});

+    }

+}

diff --git a/src/main/resources/static/libs/CLodop/install_lodop32.exe b/src/main/resources/static/libs/CLodop/install_lodop32.exe
new file mode 100755
index 0000000..93cf607
--- /dev/null
+++ b/src/main/resources/static/libs/CLodop/install_lodop32.exe
Binary files differ
diff --git a/src/main/resources/static/libs/CLodop/install_lodop64.exe b/src/main/resources/static/libs/CLodop/install_lodop64.exe
new file mode 100755
index 0000000..a81c111
--- /dev/null
+++ b/src/main/resources/static/libs/CLodop/install_lodop64.exe
Binary files differ
diff --git a/src/main/resources/static/libs/custom.js b/src/main/resources/static/libs/custom.js
index bb28ba5..a0177b3 100644
--- a/src/main/resources/static/libs/custom.js
+++ b/src/main/resources/static/libs/custom.js
@@ -101,4 +101,10 @@
     root.dateFormat = function (str) {
         return str.replace(/^(\d{4})(\d{2})(\d{2})$/, '$1-$2-$3'); //yyyyMMdd --> yyyy-MM-dd
     }
+
+    root.isempty = function (s) {
+        if (s == null || s.length == 0)
+            return true;
+        return /\s/.test(s);
+    }
 }(window));
\ No newline at end of file
diff --git a/src/main/resources/templates/home/console.html b/src/main/resources/templates/home/console.html
index 027897c..94a54a5 100755
--- a/src/main/resources/templates/home/console.html
+++ b/src/main/resources/templates/home/console.html
@@ -55,7 +55,7 @@
         var element = layui.element;

         var device = layui.device;

 

-        layui.link('/static/custom/css/console.css');

+        layui.link('[[@{/static/custom/css/console.css}]]');

 

         // 渲染轮播

         carousel.render({

diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html
index 127ba66..76b87de 100755
--- a/src/main/resources/templates/index.html
+++ b/src/main/resources/templates/index.html
@@ -136,6 +136,7 @@
 <script type="text/javascript" th:src="@{/static/libs/zTree/js/jquery.ztree.all-3.5.min.js}"></script>

 <script type="text/javascript" th:src="@{/static/libs/custom.js}"></script>

 <script type="text/javascript" th:src="@{/static/libs/numberFormat.js}"></script>

+<script type="text/javascript" th:src="@{/static/libs/CLodop/LodopFuncs.js}"></script>

 <script>

     layui.config({

         base: 'static/custom/module/'

diff --git a/src/main/resources/templates/restaurant/report/laborfee.html b/src/main/resources/templates/restaurant/report/laborfee.html
new file mode 100644
index 0000000..ac93c25
--- /dev/null
+++ b/src/main/resources/templates/restaurant/report/laborfee.html
@@ -0,0 +1,280 @@
+<div class="layui-card">
+    <div class="layui-card-header">
+        <h2 class="header-title">商户劳务费报表</h2>
+        <span class="layui-breadcrumb pull-right">
+          <a href="#">报表中心</a>
+          <a><cite>商户劳务费报表</cite></a>
+        </span>
+    </div>
+    <div class="layui-card-body">
+        <div class="layui-form" lay-filter="shopreport-laborfee-search-form">
+            <input type="hidden" id="shopreport-laborfee-hidden-maxdate" th:value="${maxdate}"/>
+            <input type="hidden" id="shopreport-laborfee-hidden-maxmonth" th:value="${maxmonth}"/>
+            <div class="layui-form-item" style="margin-bottom: 0;">
+                <div class="layui-inline">
+                    <label class="layui-form-label">汇总日期</label>
+                    <div class="layui-input-inline">
+                        <input type="text" name="startdate" id="shopreport-laborfee-search-startdate" placeholder="起始日期"
+                               th:value="${maxdate}"
+                               autocomplete="off" class="layui-input"/>
+                    </div>
+                    <div class="layui-form-mid">-</div>
+                    <div class="layui-input-inline">
+                        <input type="text" name="enddate" id="shopreport-laborfee-search-enddate" placeholder="截止日期"
+                               th:value="${maxdate}"
+                               autocomplete="off" class="layui-input"/>
+                    </div>
+                </div>
+
+                <div class="layui-inline">
+                    <label class="layui-form-label">汇总月份</label>
+                    <div class="layui-input-block">
+                        <input type="text" name="yearmonth" id="shopreport-laborfee-search-yearmonth" placeholder="选择月份"
+                               th:value="${maxmonth}" autocomplete="off" class="layui-input"/>
+                    </div>
+                </div>
+
+                <div class="layui-inline">
+                    <div class="layui-input-block" style="margin-left: 0;">
+                        <input type="checkbox" name="datetype" id="shopreport-laborfee-datetype" lay-skin="primary"
+                               title="按月份查询"/>
+                    </div>
+                </div>
+
+                <div class="layui-inline">
+                    <button id="shopreport-laborfee-search-btn" class="layui-btn icon-btn" data-type="search"><i
+                            class="layui-icon">&#xe615;</i>搜索
+                    </button>
+                </div>
+            </div>
+        </div>
+    </div>
+    <div class="layui-card-body">
+        <div class="layui-form toolbar">
+            <div class="layui-btn-group">
+                <button id="shopreport-laborfee-export-excel" class="layui-btn layui-btn-sm layui-btn-primary sw-print"><i class="layui-icon layui-icon-export"></i>导出</button>
+                <button id="shopreport-laborfee-print-table" class="layui-btn layui-btn-sm layui-btn-primary sw-print"><i class="layui-icon layui-icon-print"></i>打印</button>
+            </div>
+        </div>
+        <table class="layui-table sw-table" id="shopreport-laborfee-table" th:fragment="laborfeeTable">
+            <thead>
+            <tr>
+                <th rowspan="3" style="text-align: center;min-width: 35px;">序号</th>
+                <th rowspan="3" style="text-align: center;min-width: 100px;">单位</th>
+                <th rowspan="3" style="text-align: center;min-width: 100px;">食堂</th>
+                <th colspan="3" style="text-align: center;">消费正价</th>
+                <th colspan="3" style="text-align: center;">优惠后支付</th>
+                <th colspan="4" style="text-align: center;">应支付劳务费</th>
+            </tr>
+            <tr>
+                <th rowspan="2" style="text-align: center;min-width: 60px;">早餐<br/>正价金额</th>
+                <th rowspan="2" style="text-align: center;min-width: 60px;">午餐<br/>正价金额</th>
+                <th rowspan="2" style="text-align: center;min-width: 60px;">晚餐<br/>正价金额</th>
+                <!--<th rowspan="2" style="text-align: center;min-width: 60px;">正价金额<br/>小计</th>-->
+
+                <th rowspan="2" style="text-align: center;min-width: 60px;">早餐<br/>折后金额</th>
+                <th rowspan="2" style="text-align: center;min-width: 60px;">午餐<br/>折后金额</th>
+                <th rowspan="2" style="text-align: center;min-width: 60px;">晚餐<br/>折后金额</th>
+                <!--<th rowspan="2" style="text-align: center;min-width: 60px;">折后金额<br/>小计</th>-->
+
+                <th rowspan="2" style="text-align: center;min-width: 60px;">早餐<br/>劳务费</th>
+                <th rowspan="2" style="text-align: center;min-width: 60px;">午餐<br/>劳务费</th>
+                <th rowspan="2" style="text-align: center;min-width: 60px;">晚餐<br/>劳务费</th>
+                <th rowspan="2" style="text-align: center;min-width: 60px;">应支付劳<br/>务费小计</th>
+            </tr>
+            </thead>
+            <tbody id="shopreport-laborfee-tbody" th:data-startdate="${searchBean.startdate}" th:data-enddate="${searchBean.enddate}"  th:data-datetype="${searchBean.datetype}" th:data-yearmonth="${searchBean.yearmonth}" th:data-opercode="${opercode}">
+                <tr th:if="${null==showlist || showlist.size()==0}">
+                    <td colspan="13">无数据</td>
+                </tr>
+
+                <div th:remove="tag" th:if="${null!=showlist && showlist.size()>0}" th:each="data:${showlist}" th:with="childCount=${data.datalist.size()}">
+                    <tr th:if=${!dataStat.last}>
+                        <td th:text="${childCount>0}?${data.datalist[0].rownum}:''"></td>
+                        <td th:text="${data.dwname}" th:rowspan="${data.datalist.size()}"></td>
+                        <td th:text="${childCount>0}?${data.datalist[0].groupname}:''"></td>
+                        <td th:text="${childCount>0}?${#numbers.formatDecimal(data.datalist[0].btotalamt,1,2)}:''"></td>
+                        <td th:text="${childCount>0}?${#numbers.formatDecimal(data.datalist[0].ltotalamt,1,2)}:''"></td>
+                        <td th:text="${childCount>0}?${#numbers.formatDecimal(data.datalist[0].dtotalamt,1,2)}:''"></td>
+                        <td th:text="${childCount>0}?${#numbers.formatDecimal(data.datalist[0].bpayamt,1,2)}:''"></td>
+                        <td th:text="${childCount>0}?${#numbers.formatDecimal(data.datalist[0].lpayamt,1,2)}:''"></td>
+                        <td th:text="${childCount>0}?${#numbers.formatDecimal(data.datalist[0].dpayamt,1,2)}:''"></td>
+                        <td th:text="${childCount>0}?${#numbers.formatDecimal(data.datalist[0].bfeeamt,1,2)}:''"></td>
+                        <td th:text="${childCount>0}?${#numbers.formatDecimal(data.datalist[0].lfeeamt,1,2)}:''"></td>
+                        <td th:text="${childCount>0}?${#numbers.formatDecimal(data.datalist[0].dfeeamt,1,2)}:''"></td>
+                        <td th:text="${childCount>0}?${#numbers.formatDecimal(data.datalist[0].bfeeamt+data.datalist[0].lfeeamt+data.datalist[0].dfeeamt,1,2)}:''"></td>
+                    </tr>
+                    <tr th:each="article,stats:${data.datalist}" th:if="${!stats.first}">
+                        <td th:text="${article.rownum}"></td>
+                        <td th:text="${article.groupname}"></td>
+                        <td th:text="${#numbers.formatDecimal(article.btotalamt,1,2)}"></td>
+                        <td th:text="${#numbers.formatDecimal(article.ltotalamt,1,2)}"></td>
+                        <td th:text="${#numbers.formatDecimal(article.dtotalamt,1,2)}"></td>
+                        <td th:text="${#numbers.formatDecimal(article.bpayamt,1,2)}"></td>
+                        <td th:text="${#numbers.formatDecimal(article.lpayamt,1,2)}"></td>
+                        <td th:text="${#numbers.formatDecimal(article.dpayamt,1,2)}"></td>
+                        <td th:text="${#numbers.formatDecimal(article.bfeeamt,1,2)}"></td>
+                        <td th:text="${#numbers.formatDecimal(article.lfeeamt,1,2)}"></td>
+                        <td th:text="${#numbers.formatDecimal(article.dfeeamt,1,2)}"></td>
+                        <td th:text="${#numbers.formatDecimal(article.bfeeamt+article.lfeeamt+article.dfeeamt,1,2)}"></td>
+                    </tr>
+                    <tr th:if="${childCount>1}">
+                        <td colspan="3" th:text="${data.dwname+'小计'}"></td>
+                        <td th:text="${#numbers.formatDecimal(data.btotalamt,1,2)}"></td>
+                        <td th:text="${#numbers.formatDecimal(data.ltotalamt,1,2)}"></td>
+                        <td th:text="${#numbers.formatDecimal(data.dtotalamt,1,2)}"></td>
+                        <td th:text="${#numbers.formatDecimal(data.bpayamt,1,2)}"></td>
+                        <td th:text="${#numbers.formatDecimal(data.lpayamt,1,2)}"></td>
+                        <td th:text="${#numbers.formatDecimal(data.dpayamt,1,2)}"></td>
+                        <td th:text="${#numbers.formatDecimal(data.bfeeamt,1,2)}"></td>
+                        <td th:text="${#numbers.formatDecimal(data.lfeeamt,1,2)}"></td>
+                        <td th:text="${#numbers.formatDecimal(data.dfeeamt,1,2)}"></td>
+                        <td th:text="${#numbers.formatDecimal(data.bfeeamt+data.lfeeamt+data.dfeeamt,1,2)}"></td>
+                    </tr>
+                    <tr th:if="${dataStat.last}">
+                        <td style="font-weight: bold;" colspan="3" th:text="${data.dwname}"></td>
+                        <td style="font-weight: bold;" th:text="${#numbers.formatDecimal(data.btotalamt,1,2)}"></td>
+                        <td style="font-weight: bold;" th:text="${#numbers.formatDecimal(data.ltotalamt,1,2)}"></td>
+                        <td style="font-weight: bold;" th:text="${#numbers.formatDecimal(data.dtotalamt,1,2)}"></td>
+                        <td style="font-weight: bold;" th:text="${#numbers.formatDecimal(data.bpayamt,1,2)}"></td>
+                        <td style="font-weight: bold;" th:text="${#numbers.formatDecimal(data.lpayamt,1,2)}"></td>
+                        <td style="font-weight: bold;" th:text="${#numbers.formatDecimal(data.dpayamt,1,2)}"></td>
+                        <td style="font-weight: bold;" th:text="${#numbers.formatDecimal(data.bfeeamt,1,2)}"></td>
+                        <td style="font-weight: bold;" th:text="${#numbers.formatDecimal(data.lfeeamt,1,2)}"></td>
+                        <td style="font-weight: bold;" th:text="${#numbers.formatDecimal(data.dfeeamt,1,2)}"></td>
+                        <td style="font-weight: bold;" th:text="${#numbers.formatDecimal(data.bfeeamt+data.lfeeamt+data.dfeeamt,1,2)}"></td>
+                    </tr>
+                </div>
+            </tbody>
+        </table>
+    </div>
+</div>
+
+<script>
+    layui.use(['form', 'layer', 'laydate', 'admin'], function () {
+        var form = layui.form;
+        var laydate = layui.laydate;
+        var layer = layui.layer;
+        var $ = layui.jquery;
+
+        form.render("checkbox");
+        laydate.render({
+            elem: '#shopreport-laborfee-search-yearmonth',
+            type: 'month',
+            max: $("#shopreport-laborfee-hidden-maxdate").val(),
+            trigger: 'click',
+            change: function (value, date, endDate) {
+                $('#shopreport-laborfee-search-yearmonth').val(value);
+                $('#layui-laydate1').remove();
+            }
+        });
+        laydate.render({
+            elem: '#shopreport-laborfee-search-startdate',
+            max: $("#shopreport-laborfee-hidden-maxdate").val(),
+            trigger: 'click'
+        });
+        laydate.render({
+            elem: '#shopreport-laborfee-search-enddate',
+            max: $("#shopreport-laborfee-hidden-maxdate").val(),
+            trigger: 'click'
+        });
+
+        $("#shopreport-laborfee-search-btn").click(function(){
+            var startdate=$("#shopreport-laborfee-search-startdate").val();
+            var enddate = $("#shopreport-laborfee-search-enddate").val();
+            var yearmonth=$("#shopreport-laborfee-search-yearmonth").val();
+            var dtype = $("#shopreport-laborfee-datetype").is(":checked")?"month":"days";
+            if ("month" == dtype) {
+                if (isempty(yearmonth)) {
+                    layer.msg('请选择月份', {icon: 2});
+                    return;
+                }
+            } else {
+                if (isempty(startdate) || isempty(enddate)) {
+                    layer.msg('请选择汇总时间段', {icon: 2});
+                    return;
+                }
+            }
+
+            layer.load(2);
+            $.ajax({
+                url: '[[@{/report/searchlaborfee}]]',
+                type: "POST",
+                data: {
+                    startdate: startdate,
+                    enddate: enddate,
+                    datetype: dtype,
+                    yearmonth: yearmonth,
+                    _csrf: $("meta[name='_csrf_token']").attr("value")
+                },
+                success: function (data) {
+                    $("#shopreport-laborfee-table").html(data);
+                    layer.closeAll('loading');
+                },
+                error: function (status, err) {
+                    layer.closeAll('loading');
+                    layer.msg('查询失败了', {icon: 2});
+                }
+            });
+        });
+
+        //打印
+        var LODOP; //声明为全局变量
+        $("#shopreport-laborfee-print-table").click(function(){
+            var startdate= $("#shopreport-laborfee-tbody").attr("data-startdate");
+            var enddate= $("#shopreport-laborfee-tbody").attr("data-enddate");
+            var datetype= $("#shopreport-laborfee-tbody").attr("data-datetype");
+            var yearmonth= $("#shopreport-laborfee-tbody").attr("data-yearmonth");
+            var opercode = $("#shopreport-laborfee-tbody").attr("data-opercode");
+            var url = '/report/print/printlaborfee?startdate=' + startdate + '&enddate=' + enddate + '&datetype=' + datetype + '&yearmonth=' + yearmonth + '&opercode=' + opercode;
+
+            LODOP = getLodop();
+            LODOP.PRINT_INIT("商户劳务费报表");
+            LODOP.SET_PRINT_PAGESIZE(2, 0, 0,"A4");
+            LODOP.ADD_PRINT_URL(30, 20, "95%", "90%", encodeURI(url));
+            LODOP.ADD_PRINT_HTM("95%", "48%", 150, 50, "<font style='font-size:12px'><span tdata='pageNO'>##</span>/<span tdata='pageCount'>&nbsp;&nbsp;##</span></font>");
+            LODOP.SET_PRINT_STYLEA(0, "ItemType", 1);
+            LODOP.SET_PRINT_STYLEA(0, "HOrient", 3);
+            LODOP.SET_PRINT_STYLEA(0, "VOrient", 3);
+            LODOP.SET_SHOW_MODE("NP_NO_RESULT", true);
+            LODOP.SET_PRINT_MODE("FULL_WIDTH_FOR_OVERFLOW",true);
+            LODOP.PREVIEW();
+        });
+
+        //导出
+        $("#shopreport-laborfee-export-excel").click(function(){
+            var startdate= $("#shopreport-laborfee-tbody").attr("data-startdate");
+            var enddate= $("#shopreport-laborfee-tbody").attr("data-enddate");
+            var datetype= $("#shopreport-laborfee-tbody").attr("data-datetype");
+            var yearmonth= $("#shopreport-laborfee-tbody").attr("data-yearmonth");
+
+            var dataUrl='[[@{/report/excelexportlaborfee}]]?startdate='+startdate+'&enddate='+enddate+'&datetype='+datetype+'&yearmonth='+yearmonth;
+            var xhr = new XMLHttpRequest();
+            xhr.responseType = "blob"; //设置响应类型为blob类型
+            xhr.onload = function () {
+                debugger
+                if (this.status == "200") {
+                    //获取响应文件流 
+                    var blob = this.response;
+                    // 转换完成,创建一个a标签用于下载
+                    var aElem = document.createElement('a');
+                    aElem.href = window.URL.createObjectURL(blob);
+                    aElem.download = "商户劳务费报表.xls";
+                    aElem.onload = function (e) {
+                        window.URL.revokeObjectURL(aElem.href);
+                    };
+                    $("body").append(aElem);  // 修复firefox中无法触发click
+                    aElem.click();
+                    $(aElem).remove();
+
+                }else if(this.status == "403"){
+                    layer.msg('无导出资源权限', {icon: 2});
+                } else {
+                    layer.msg('导出excel失败了', {icon: 2});
+                }
+            }
+            xhr.open("GET", dataUrl, true);
+            xhr.send();
+        });
+    });
+</script>
\ No newline at end of file
diff --git a/src/main/resources/templates/restaurant/report/print/printlaborfee.html b/src/main/resources/templates/restaurant/report/print/printlaborfee.html
new file mode 100644
index 0000000..69ceb7b
--- /dev/null
+++ b/src/main/resources/templates/restaurant/report/print/printlaborfee.html
@@ -0,0 +1,148 @@
+<!DOCTYPE html>
+<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
+<head>
+    <meta charset="UTF-8">
+    <title>商户劳务费报表</title>
+
+    <link rel="stylesheet" th:href="@{/static/libs/layui/css/layui.css}"/>
+    <link rel="stylesheet" th:href="@{/static/custom/css/custom.css}"/>
+</head>
+<body>
+<div class="layui-card">
+    <div class="layui-card-header" style="text-align: center;">
+        <h1>商户劳务费报表</h1>
+    </div>
+    <div class="layui-card-body">
+        <div class="layui-form toolbar">
+            <div style="float: left;padding-left: 3px;" th:text="${'区间:'+period}"></div>
+            <div style="float: right;" th:text="'单位:元'"></div>
+        </div>
+        <table class="layui-table sw-table sw-print">
+            <thead>
+            <tr>
+                <th rowspan="3" style="text-align: center;min-width: 35px;">序号</th>
+                <th rowspan="3" style="text-align: center;min-width: 100px;">单位</th>
+                <th rowspan="3" style="text-align: center;min-width: 100px;">食堂</th>
+                <th colspan="3" style="text-align: center;">消费正价</th>
+                <th colspan="3" style="text-align: center;">优惠后支付</th>
+                <th colspan="4" style="text-align: center;">应支付劳务费</th>
+            </tr>
+            <tr>
+                <th rowspan="2" style="text-align: center;min-width: 60px;">早餐<br/>正价金额</th>
+                <th rowspan="2" style="text-align: center;min-width: 60px;">午餐<br/>正价金额</th>
+                <th rowspan="2" style="text-align: center;min-width: 60px;">晚餐<br/>正价金额</th>
+                <!--<th rowspan="2" style="text-align: center;min-width: 60px;">正价金额<br/>小计</th>-->
+
+                <th rowspan="2" style="text-align: center;min-width: 60px;">早餐<br/>折后金额</th>
+                <th rowspan="2" style="text-align: center;min-width: 60px;">午餐<br/>折后金额</th>
+                <th rowspan="2" style="text-align: center;min-width: 60px;">晚餐<br/>折后金额</th>
+                <!--<th rowspan="2" style="text-align: center;min-width: 60px;">折后金额<br/>小计</th>-->
+
+                <th rowspan="2" style="text-align: center;min-width: 60px;">早餐<br/>劳务费</th>
+                <th rowspan="2" style="text-align: center;min-width: 60px;">午餐<br/>劳务费</th>
+                <th rowspan="2" style="text-align: center;min-width: 60px;">晚餐<br/>劳务费</th>
+                <th rowspan="2" style="text-align: center;min-width: 60px;">应支付劳<br/>务费小计</th>
+            </tr>
+            </thead>
+            <tbody>
+            <tr th:if="${null==showlist || showlist.size()==0}">
+                <td colspan="13">无数据</td>
+            </tr>
+
+            <div th:remove="tag" th:if="${null!=showlist && showlist.size()>0}" th:each="data:${showlist}"
+                 th:with="childCount=${data.datalist.size()}">
+                <tr th:if=${!dataStat.last}>
+                    <td th:text="${childCount>0}?${data.datalist[0].rownum}:''"></td>
+                    <td th:text="${data.dwname}" th:rowspan="${data.datalist.size()}"></td>
+                    <td th:text="${childCount>0}?${data.datalist[0].groupname}:''"></td>
+                    <td th:text="${childCount>0}?${#numbers.formatDecimal(data.datalist[0].btotalamt,1,2)}:''"></td>
+                    <td th:text="${childCount>0}?${#numbers.formatDecimal(data.datalist[0].ltotalamt,1,2)}:''"></td>
+                    <td th:text="${childCount>0}?${#numbers.formatDecimal(data.datalist[0].dtotalamt,1,2)}:''"></td>
+                    <td th:text="${childCount>0}?${#numbers.formatDecimal(data.datalist[0].bpayamt,1,2)}:''"></td>
+                    <td th:text="${childCount>0}?${#numbers.formatDecimal(data.datalist[0].lpayamt,1,2)}:''"></td>
+                    <td th:text="${childCount>0}?${#numbers.formatDecimal(data.datalist[0].dpayamt,1,2)}:''"></td>
+                    <td th:text="${childCount>0}?${#numbers.formatDecimal(data.datalist[0].bfeeamt,1,2)}:''"></td>
+                    <td th:text="${childCount>0}?${#numbers.formatDecimal(data.datalist[0].lfeeamt,1,2)}:''"></td>
+                    <td th:text="${childCount>0}?${#numbers.formatDecimal(data.datalist[0].dfeeamt,1,2)}:''"></td>
+                    <td th:text="${childCount>0}?${#numbers.formatDecimal(data.datalist[0].bfeeamt+data.datalist[0].lfeeamt+data.datalist[0].dfeeamt,1,2)}:''"></td>
+                </tr>
+                <tr th:each="article,stats:${data.datalist}" th:if="${!stats.first}">
+                    <td th:text="${article.rownum}"></td>
+                    <td th:text="${article.groupname}"></td>
+                    <td th:text="${#numbers.formatDecimal(article.btotalamt,1,2)}"></td>
+                    <td th:text="${#numbers.formatDecimal(article.ltotalamt,1,2)}"></td>
+                    <td th:text="${#numbers.formatDecimal(article.dtotalamt,1,2)}"></td>
+                    <td th:text="${#numbers.formatDecimal(article.bpayamt,1,2)}"></td>
+                    <td th:text="${#numbers.formatDecimal(article.lpayamt,1,2)}"></td>
+                    <td th:text="${#numbers.formatDecimal(article.dpayamt,1,2)}"></td>
+                    <td th:text="${#numbers.formatDecimal(article.bfeeamt,1,2)}"></td>
+                    <td th:text="${#numbers.formatDecimal(article.lfeeamt,1,2)}"></td>
+                    <td th:text="${#numbers.formatDecimal(article.dfeeamt,1,2)}"></td>
+                    <td th:text="${#numbers.formatDecimal(article.bfeeamt+article.lfeeamt+article.dfeeamt,1,2)}"></td>
+                </tr>
+                <tr th:if="${childCount>1}">
+                    <td colspan="3" th:text="${data.dwname+'小计'}"></td>
+                    <td th:text="${#numbers.formatDecimal(data.btotalamt,1,2)}"></td>
+                    <td th:text="${#numbers.formatDecimal(data.ltotalamt,1,2)}"></td>
+                    <td th:text="${#numbers.formatDecimal(data.dtotalamt,1,2)}"></td>
+                    <td th:text="${#numbers.formatDecimal(data.bpayamt,1,2)}"></td>
+                    <td th:text="${#numbers.formatDecimal(data.lpayamt,1,2)}"></td>
+                    <td th:text="${#numbers.formatDecimal(data.dpayamt,1,2)}"></td>
+                    <td th:text="${#numbers.formatDecimal(data.bfeeamt,1,2)}"></td>
+                    <td th:text="${#numbers.formatDecimal(data.lfeeamt,1,2)}"></td>
+                    <td th:text="${#numbers.formatDecimal(data.dfeeamt,1,2)}"></td>
+                    <td th:text="${#numbers.formatDecimal(data.bfeeamt+data.lfeeamt+data.dfeeamt,1,2)}"></td>
+                </tr>
+                <tr th:if="${dataStat.last}">
+                    <td style="font-weight: bold;" colspan="3" th:text="${data.dwname}"></td>
+                    <td style="font-weight: bold;" th:text="${#numbers.formatDecimal(data.btotalamt,1,2)}"></td>
+                    <td style="font-weight: bold;" th:text="${#numbers.formatDecimal(data.ltotalamt,1,2)}"></td>
+                    <td style="font-weight: bold;" th:text="${#numbers.formatDecimal(data.dtotalamt,1,2)}"></td>
+                    <td style="font-weight: bold;" th:text="${#numbers.formatDecimal(data.bpayamt,1,2)}"></td>
+                    <td style="font-weight: bold;" th:text="${#numbers.formatDecimal(data.lpayamt,1,2)}"></td>
+                    <td style="font-weight: bold;" th:text="${#numbers.formatDecimal(data.dpayamt,1,2)}"></td>
+                    <td style="font-weight: bold;" th:text="${#numbers.formatDecimal(data.bfeeamt,1,2)}"></td>
+                    <td style="font-weight: bold;" th:text="${#numbers.formatDecimal(data.lfeeamt,1,2)}"></td>
+                    <td style="font-weight: bold;" th:text="${#numbers.formatDecimal(data.dfeeamt,1,2)}"></td>
+                    <td style="font-weight: bold;"
+                        th:text="${#numbers.formatDecimal(data.bfeeamt+data.lfeeamt+data.dfeeamt,1,2)}"></td>
+                </tr>
+            </div>
+            </tbody>
+        </table>
+        <div class="layui-form toolbar">
+            <div style="float: left;padding-left: 3px;" th:text="${'制表人:'+opername+' &nbsp;&nbsp; '+ printdatetime}"></div>
+        </div>
+    </div>
+    <div class="layui-card-body" style="margin-top: 25px;">
+        <table class="sw-print-sign">
+            <tr>
+                <td width="50%">银行方审核盖章:</td>
+                <td width="50%">苍山饭店审核盖章:</td>
+            </tr>
+            <tr>
+                <td>审核人:</td>
+                <td>审核人:</td>
+            </tr>
+            <tr>
+                <td colspan="2">&nbsp;</td>
+            </tr>
+            <tr>
+                <td colspan="2">&nbsp;</td>
+            </tr>
+            <tr>
+                <td colspan="2">&nbsp;</td>
+            </tr>
+            <tr>
+                <td>市民卡公司审核盖章:</td>
+                <td>建桥园审核盖章:</td>
+            </tr>
+            <tr>
+                <td>审核人:</td>
+                <td>审核人:</td>
+            </tr>
+        </table>
+    </div>
+</div>
+</body>
+</html>
\ No newline at end of file