Bladeren bron

处理从mes排班

wukai 5 maanden geleden
bovenliggende
commit
660a313af2

+ 71 - 0
generate_excel.py

@@ -0,0 +1,71 @@
+import pandas as pd
+
+def generate_excel_template(file_path):
+    # 创建各工作表的数据
+    summary_data = {
+        "指标": ["年度总营收", "年度总成本", "年度总利润", "年度毛利率", "总资产", "国家数量", "订单总量"],
+        "值": [5800, 4500, 1300, "22.4%", 360000, 15, 90]
+    }
+    
+    revenue_breakdown = {
+        "类型": ["订单销售", "售后服务", "金融业务", "其他收入"],
+        "金额 (万元)": [3800, 500, 200, 100]
+    }
+    
+    cost_breakdown = {
+        "类型": ["直接材料", "直接人工", "制造费用", "销售费用", "管理费用"],
+        "金额 (万元)": [40, 20, 15, 5, 8]
+    }
+    
+    country_performance = {
+        "国家": ["澳大利亚", "美国", "英国", "德国", "法国", "日本", "韩国", "巴西", "印度", "俄罗斯"],
+        "订单数量": [20, 25, 30, 35, 40, 45, 50, 55, 60, 65],
+        "收入 (万元)": [20, 30, 40, 50, 60, 70, 80, 90, 100, 110],
+        "利润 (万元)": [25.2, 27.7, 30.2, 32.7, 35.2, 37.7, 40.2, 42.7, 45.2, 47.7]
+    }
+    
+    product_line_profit = {
+        "类型": ["羊毛毯", "纯棉毯", "亚麻毯", "丝绸毯", "竹纤维毯", "涤纶毯", "腈纶毯", "混纺毯", "法兰绒毯", "珊瑚绒毯"],
+        "利润 (万元)": [6.9, 7.8, 8.3, 9.1, 10.4, 11.2, 12.5, 13.5, 14.1, 15.2],
+        "毛利率 (%)": [35.2, 28.3, 31.2, 26.9, 33.5, 30.4, 34.1, 27.8, 32.5, 29.1]
+    }
+    
+    monthly_trade_data = {
+        "月份": ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"],
+        "收入 (万元)": [380, 420, 510, 490, 560, 590, 720, 670, 810, 780, 920, 940],
+        "成本 (万元)": [310, 340, 390, 370, 420, 400, 470, 430, 480, 460, 520, 550],
+        "利润 (万元)": [70, 80, 120, 120, 140, 190, 250, 240, 330, 320, 400, 390],
+        "利润率 (%)": [18.4, 19.0, 23.5, 24.5, 25.0, 32.2, 34.7, 35.8, 40.7, 41.0, 43.5, 41.5]
+    }
+    
+    forecast_data = {
+        "月份": ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"],
+        "预测收入 (万元)": [1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2100],
+        "预测利润率 (%)": [42.0, 40.9, 40.0, 39.2, 38.6, 38.0, 37.5, 37.1, 36.7, 36.3, 36.0, 35.7],
+        "预测资产 (万元)": [370000, 380000, 390000, 400000, 410000, 420000, 430000, 440000, 450000, 460000, 470000, 480000]
+    }
+    
+    # 创建DataFrame
+    summary_df = pd.DataFrame(summary_data)
+    revenue_df = pd.DataFrame(revenue_breakdown)
+    cost_df = pd.DataFrame(cost_breakdown)
+    country_df = pd.DataFrame(country_performance)
+    product_df = pd.DataFrame(product_line_profit)
+    monthly_df = pd.DataFrame(monthly_trade_data)
+    forecast_df = pd.DataFrame(forecast_data)
+    
+    # 将数据写入Excel文件
+    with pd.ExcelWriter(file_path) as writer:
+        summary_df.to_excel(writer, sheet_name='Summary', index=False)
+        revenue_df.to_excel(writer, sheet_name='Revenue Breakdown', index=False)
+        cost_df.to_excel(writer, sheet_name='Cost Breakdown', index=False)
+        country_df.to_excel(writer, sheet_name='Country Performance', index=False)
+        product_df.to_excel(writer, sheet_name='Product Line Profit', index=False)
+        monthly_df.to_excel(writer, sheet_name='Monthly Trade Data', index=False)
+        forecast_df.to_excel(writer, sheet_name='Forecast', index=False)
+    
+    print(f"Excel模板已生成:{file_path}")
+
+if __name__ == '__main__':
+    file_path = 'sales_data_template.xlsx'
+    generate_excel_template(file_path)

+ 1 - 1
jjt-admin/src/test/java/com/admanager/AdTest.java

@@ -35,7 +35,7 @@ public class AdTest {
         map.put("domainName", "tlct.com.cn");
         map.put("startIndex", "1");
         map.put("range", "10000");
-        map.put("AuthToken", "a21d15fa-58ee-4181-9fca-5f5dbc83dbd2");
+        map.put("AuthToken", "898ba90d-b724-49df-b6e1-476d2a8d2a50");
         HttpRequest request = HttpUtil.createPost(uri);
         request.setMethod(Method.GET);
         request.form(map);

+ 35 - 0
jjt-admin/src/test/java/com/jjt/task/TaskEmpTest.java

@@ -0,0 +1,35 @@
+package com.jjt.task;
+
+import com.jjt.JjtApplication;
+import com.jjt.common.utils.DateUtils;
+import com.jjt.emp.service.ITwinEmpService;
+import com.jjt.emp.service.impl.TwinEmpCalcServiceImpl;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import javax.annotation.Resource;
+import java.time.LocalDate;
+
+/**
+ * DataProcess$
+ *
+ * @author wukai
+ * @date 2024/5/7 11:49
+ */
+@SpringBootTest(classes = JjtApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+public class TaskEmpTest {
+    @Resource
+    private ITwinEmpService empService;
+    @Resource
+    private TwinEmpCalcServiceImpl calcService;
+
+    @Test
+    public void test() throws Exception {
+        String date = "2025-07-23";
+        LocalDate localDate = LocalDate.parse(date);
+        empService.sync(DateUtils.toDate(localDate));
+//        calcService.calc(DateUtils.toDate(localDate));
+    }
+
+}
+

+ 1 - 1
jjt-admin/src/test/java/com/jjt/wk/EmpCalcTest.java

@@ -22,7 +22,7 @@ public class EmpCalcTest {
 
     @Test
     public void test() {
-        String s = "2025-05-16";
+        String s = "2025-07-20";
         Date date = DateUtils.parseDate(s);
         empCalcService.calcNew(date);
     }

+ 11 - 1
jjt-biz/src/main/java/com/jjt/emp/controller/TwinEmpController.java

@@ -12,7 +12,6 @@ import com.jjt.emp.domain.TwinEmp;
 import com.jjt.emp.service.ITwinEmpService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
-import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
@@ -32,6 +31,17 @@ public class TwinEmpController extends BaseController {
     @Resource
     private ITwinEmpService twinEmpService;
 
+    @GetMapping("/sync")
+    @ResponseBody
+    public AjaxResult sync(String date) {
+        try {
+            twinEmpService.sync(DateUtils.parseDate(date));
+            return success();
+        } catch (Exception e) {
+            return AjaxResult.error(e.getMessage());
+        }
+    }
+
     /**
      * 查询员工排班列表
      */

+ 34 - 68
jjt-biz/src/main/java/com/jjt/emp/domain/TwinEmpDetail.java

@@ -1,9 +1,12 @@
 package com.jjt.emp.domain;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
+import com.fasterxml.jackson.annotation.JsonFormat;
 import com.jjt.common.annotation.Excel;
 import com.jjt.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
 
 /**
  * 员工排班明细对象 TWIN_EMP_DETAIL
@@ -11,84 +14,47 @@ import com.jjt.common.core.domain.BaseEntity;
  * @author wukai
  * @date 2025-01-18
  */
-public class TwinEmpDetail extends BaseEntity
-{
+@Data
+public class TwinEmpDetail extends BaseEntity {
     private static final long serialVersionUID = 1L;
 
-    /** 明细ID */
+    /**
+     * 明细ID
+     */
     private Long detailId;
 
-    /** 排班ID */
+    /**
+     * 排班ID
+     */
     @Excel(name = "排班ID")
     private Long empId;
 
-    /** 姓名 */
+    /**
+     * 姓名
+     */
     @Excel(name = "姓名")
     private String empName;
 
-    /** 班组 */
+    /**
+     * 班组
+     */
     @Excel(name = "班组")
     private String empTeam;
-
-    /** 机台号 */
+    @ApiModelProperty("上班时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "上班时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date inTime;
+
+    /**
+     * 下班时间
+     */
+    @ApiModelProperty("下班时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "下班时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date outTime;
+    /**
+     * 机台号
+     */
     @Excel(name = "机台号")
     private String devices;
-
-    public void setDetailId(Long detailId)
-    {
-        this.detailId = detailId;
-    }
-
-    public Long getDetailId()
-    {
-        return detailId;
-    }
-    public void setEmpId(Long empId)
-    {
-        this.empId = empId;
-    }
-
-    public Long getEmpId()
-    {
-        return empId;
-    }
-    public void setEmpName(String empName)
-    {
-        this.empName = empName;
-    }
-
-    public String getEmpName()
-    {
-        return empName;
-    }
-    public void setEmpTeam(String empTeam)
-    {
-        this.empTeam = empTeam;
-    }
-
-    public String getEmpTeam()
-    {
-        return empTeam;
-    }
-    public void setDevices(String devices)
-    {
-        this.devices = devices;
-    }
-
-    public String getDevices()
-    {
-        return devices;
-    }
-
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
-            .append("detailId", getDetailId())
-            .append("empId", getEmpId())
-            .append("empName", getEmpName())
-            .append("empTeam", getEmpTeam())
-            .append("devices", getDevices())
-            .append("remark", getRemark())
-            .toString();
-    }
 }

+ 12 - 1
jjt-biz/src/main/java/com/jjt/emp/service/ITwinEmpService.java

@@ -1,8 +1,9 @@
 package com.jjt.emp.service;
 
+import com.jjt.emp.domain.TwinEmp;
+
 import java.util.Date;
 import java.util.List;
-import com.jjt.emp.domain.TwinEmp;
 
 /**
  * 员工排班Service接口
@@ -58,6 +59,7 @@ public interface ITwinEmpService {
      * @return 结果
      */
     public int deleteTwinEmpByEmpId(Long empId);
+
     /**
      * 按日期查询排班
      *
@@ -65,4 +67,13 @@ public interface ITwinEmpService {
      * @return 排班结果
      */
     TwinEmp selectTwinEmpByDate(Date date);
+
+
+    /**
+     * 排班数据同步
+     *
+     * @param date 日期
+     * @throws Exception 异常
+     */
+    void sync(Date date) throws Exception;
 }

+ 63 - 19
jjt-biz/src/main/java/com/jjt/emp/service/impl/TwinEmpCalcServiceImpl.java

@@ -136,14 +136,16 @@ public class TwinEmpCalcServiceImpl implements ITwinEmpCalcService {
         Map<String, List<TwinCalcHourSpec>> specHourMap = specHourList.stream().collect(Collectors.groupingBy(o -> o.getDeviceId() + "-" + o.getTeam(), LinkedHashMap::new, Collectors.toList()));
         List<TwinCalcDay> twinCalcDays = twinCalcDayService.selectTwinCalcDayListByTime(date, date);
         Map<Long, TwinCalcDay> calcMap = twinCalcDays.stream().collect(Collectors.toMap(TwinCalcDay::getDeviceId, o -> o));
+        Map<Long, BigDecimal> effMap = twinCalcDays.stream().collect(Collectors.toMap(TwinCalcDay::getDeviceId, TwinCalcDay::getEfficiency));
         TwinEmp emp = empService.selectTwinEmpByDate(date);
 
         List<TwinEmpConfig> configs = empConfigService.selectTwinEmpConfigList(new TwinEmpConfig());
         Map<BigDecimal, BigDecimal> configMap = configs.stream().collect(Collectors.toMap(o -> o.getDensity().setScale(2, RoundingMode.HALF_UP), TwinEmpConfig::getPrice));
 
-        List<TwinEmpCalc> calcList = new ArrayList<>();
-        process(true, emp, calcMap, configMap, calcList, specHourMap);
-        process(false, emp, calcMap, configMap, calcList, specHourMap);
+//        List<TwinEmpCalc> calcList = new ArrayList<>();
+//        process(true, emp, calcMap, configMap, calcList, specHourMap);
+//        process(false, emp, calcMap, configMap, calcList, specHourMap);
+        List<TwinEmpCalc> calcList = process(emp, effMap, configMap, specHourList);
         if (calcList.size() > 0) {
             try (SqlSession sqlSession = factory.openSession(ExecutorType.BATCH, false)) {
                 TwinEmpCalcMapper mapper = sqlSession.getMapper(TwinEmpCalcMapper.class);
@@ -158,6 +160,7 @@ public class TwinEmpCalcServiceImpl implements ITwinEmpCalcService {
     /**
      * @param flag true为A班false为B班
      */
+    @Deprecated
     private void process(boolean flag, TwinEmp emp, Map<Long, TwinCalcDay> calcMap, Map<BigDecimal, BigDecimal> configMap, List<TwinEmpCalc> calcList, Map<String, List<TwinCalcHourSpec>> specHourMap) {
         List<TwinEmpDetail> list = emp.getTwinEmpDetailListA();
         String team = "A";
@@ -166,7 +169,7 @@ public class TwinEmpCalcServiceImpl implements ITwinEmpCalcService {
             list = emp.getTwinEmpDetailListB();
         }
         for (TwinEmpDetail d : list) {
-            Long[] devices = getDevices(d.getDevices());
+            Long[] devices = Tools.parseDevices(d.getDevices());
             for (int i = 0; i < devices.length; i++) {
                 Long deviceId = devices[i];
                 List<TwinCalcHourSpec> specs = specHourMap.get(deviceId + "-" + team);
@@ -212,24 +215,65 @@ public class TwinEmpCalcServiceImpl implements ITwinEmpCalcService {
         }
     }
 
-    private Long[] getDevices(String d) {
-        String[] temp = d.split(",");
-        Set<Long> set = new HashSet<>();
-        for (String s : temp) {
-            String[] ss = s.split("-");
-            if (ss.length > 1) {
-                Long st = Long.parseLong(ss[0]);
-                Long ed = Long.parseLong(ss[1]);
-                for (long i = st; i <= ed; i++) {
-                    set.add(i);
+    private List<TwinEmpCalc> process(TwinEmp emp, Map<Long, BigDecimal> effMap, Map<BigDecimal, BigDecimal> configMap, List<TwinCalcHourSpec> specHourList) {
+        List<TwinEmpDetail> empList = emp.getTwinEmpDetailList();
+        List<TwinEmpCalc> resultList = new ArrayList<>();
+        //按设备ID分组
+        Map<Long, List<TwinCalcHourSpec>> specHourMap = specHourList.stream().collect(Collectors.groupingBy(TwinCalcHourSpec::getDeviceId, LinkedHashMap::new, Collectors.toList()));
+        for (TwinEmpDetail d : empList) {
+            Long[] devices = Tools.parseDevices(d.getDevices());
+            int startHour = DateUtils.toLocalDateTime(d.getInTime()).getHour();
+            int endHour = DateUtils.toLocalDateTime(d.getOutTime()).getHour();
+
+            for (int i = 0; i < devices.length; i++) {
+                Long deviceId = devices[i];
+                List<TwinCalcHourSpec> specs = specHourMap.get(deviceId);
+                if (specs == null || specs.size() == 0) {
+                    continue;
+                }
+                List<TwinCalcHourSpec> hourList = specs.stream().filter(t -> t.getHour() >= startHour && t.getHour() < endHour).collect(Collectors.toList());
+                if (endHour < startHour) {
+                    hourList.addAll(specs.stream().filter(t -> t.getHour() >= startHour || t.getHour() < endHour).collect(Collectors.toList()));
+                }
+//                for (int h = startHour; h < endHour; h++) {
+//                    //上班时间包含当前小时,下班时间不包含当前小时
+//                    int hour = h;
+//                    List<TwinCalcHourSpec> hourList = specs.stream().filter(t -> t.getHour() == hour).collect(Collectors.toList());
+//                }
+                //按密度和米克重、毛高分组统计
+                Map<String, BigDecimal> resultMap = hourList.stream().collect(Collectors.groupingBy(t -> t.getDensity() + "-" + t.getMick() + "-" + t.getHeight(), Collectors.reducing(BigDecimal.ZERO, TwinCalcHourSpec::getLength, BigDecimal::add)));
+                for (String ss : resultMap.keySet()) {
+                    String[] temp = ss.split("-");
+                    BigDecimal density = new BigDecimal(temp[0]).setScale(2, RoundingMode.HALF_UP);
+                    Integer mick = Integer.parseInt(temp[1]);
+                    TwinEmpCalc calc = new TwinEmpCalc();
+                    calc.setDeviceId(deviceId);
+                    if (StringUtils.isNotEmpty(temp[2]) && !"null".equals(temp[2])) {
+                        BigDecimal height = new BigDecimal(temp[2]).setScale(2, RoundingMode.HALF_UP);
+                        calc.setHeight(height);
+                    }
+                    calc.setEfficiency(effMap.get(deviceId));
+                    calc.setEmpDate(emp.getEmpDate());
+                    BigDecimal length = resultMap.get(ss);
+                    if (length.compareTo(BigDecimal.ZERO) == 0) {
+                        continue;
+                    }
+                    calc.setLength(length);
+                    calc.setEmpTeam(d.getEmpTeam());
+                    calc.setEmpName(d.getEmpName());
+                    calc.setMick(mick);
+                    calc.setDensity(density);
+                    BigDecimal price = configMap.get(Tools.density(density));
+                    calc.setPrice(price);
+                    if (price != null) {
+                        BigDecimal total = length.multiply(price);
+                        calc.setTotalPrice(total);
+                    }
+                    resultList.add(calc);
                 }
-            } else {
-                set.add(Long.parseLong(s));
             }
         }
-        Long[] devices = new Long[set.size()];
-        set.toArray(devices);
-        return devices;
+        return resultList;
     }
 
 

+ 82 - 29
jjt-biz/src/main/java/com/jjt/emp/service/impl/TwinEmpServiceImpl.java

@@ -1,14 +1,20 @@
 package com.jjt.emp.service.impl;
 
+import com.jjt.common.utils.DateUtils;
 import com.jjt.common.utils.StringUtils;
 import com.jjt.emp.domain.TwinEmp;
 import com.jjt.emp.domain.TwinEmpDetail;
 import com.jjt.emp.mapper.TwinEmpMapper;
 import com.jjt.emp.service.ITwinEmpService;
+import com.jjt.utils.Tools;
+import com.jjt.wkEmp.domain.TwinWkEmpRota;
+import com.jjt.wkEmp.service.ITwinWkEmpRotaService;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
@@ -24,6 +30,8 @@ import java.util.stream.Collectors;
 public class TwinEmpServiceImpl implements ITwinEmpService {
     @Resource
     private TwinEmpMapper twinEmpMapper;
+    @Resource
+    private ITwinWkEmpRotaService rotaService;
 
     /**
      * 查询员工排班
@@ -75,8 +83,7 @@ public class TwinEmpServiceImpl implements ITwinEmpService {
     @Transactional
     @Override
     public int updateTwinEmp(TwinEmp twinEmp) {
-        twinEmpMapper.deleteTwinEmpDetailByEmpId(twinEmp.getEmpId())
-        ;
+        twinEmpMapper.deleteTwinEmpDetailByEmpId(twinEmp.getEmpId());
         insertTwinEmpDetail(twinEmp);
         return twinEmpMapper.updateTwinEmp(twinEmp);
     }
@@ -113,23 +120,28 @@ public class TwinEmpServiceImpl implements ITwinEmpService {
      * @param twinEmp 员工排班对象
      */
     public void insertTwinEmpDetail(TwinEmp twinEmp) {
-        List<TwinEmpDetail> twinEmpDetailList = new ArrayList<>();
-        twinEmp.getTwinEmpDetailListA().forEach(d -> {
-            twinEmpDetailList.add(d);
-        });
-        twinEmp.getTwinEmpDetailListB().forEach(d -> {
-            twinEmpDetailList.add(d);
-        });
-        Long empId = twinEmp.getEmpId();
-        if (StringUtils.isNotNull(twinEmpDetailList)) {
-            List<TwinEmpDetail> list = new ArrayList<TwinEmpDetail>();
-            for (TwinEmpDetail twinEmpDetail : twinEmpDetailList) {
-                twinEmpDetail.setEmpId(empId);
-                list.add(twinEmpDetail);
-            }
-            if (list.size() > 0) {
-                twinEmpMapper.batchTwinEmpDetail(list);
+        List<TwinEmpDetail> twinEmpDetailList = twinEmp.getTwinEmpDetailListA();
+        twinEmpDetailList.addAll(twinEmp.getTwinEmpDetailListB());
+        List<TwinEmpDetail> list = new ArrayList<>();
+        LocalDate localDate = DateUtils.toLocalDate(twinEmp.getEmpDate());
+        for (TwinEmpDetail detail : twinEmpDetailList) {
+            detail.setEmpId(twinEmp.getEmpId());
+            if (StringUtils.isNotEmpty(detail.getRemark()) && detail.getRemark().contains("-")) {
+                String[] tmp = detail.getRemark().split("-");
+                int start = Integer.parseInt(tmp[0]);
+                int end = Integer.parseInt(tmp[1]);
+                LocalDateTime startTime = localDate.atTime(start, 0, 0);
+                LocalDateTime endTime = localDate.atTime(end, 0, 0);
+                if (end <= 7) {
+                    endTime = endTime.plusDays(1);
+                }
+                detail.setInTime(DateUtils.toDate(startTime));
+                detail.setOutTime(DateUtils.toDate(endTime));
             }
+            list.add(detail);
+        }
+        if (list.size() > 0) {
+            twinEmpMapper.batchTwinEmpDetail(list);
         }
     }
 
@@ -144,21 +156,62 @@ public class TwinEmpServiceImpl implements ITwinEmpService {
         TwinEmp twinEmp = new TwinEmp();
         twinEmp.setEmpDate(date);
         List<TwinEmp> list = selectTwinEmpList(twinEmp);
-
-        if (list.size() == 0) {
-            //如果未找到,则取最后一条记录
-            list = selectTwinEmpList(new TwinEmp());
+        if (list.size() > 0) {
             Long empId = list.get(0).getEmpId();
+            return selectTwinEmpByEmpId(empId);
+        } else {
+            return null;
+        }
+    }
 
-            TwinEmp emp = selectTwinEmpByEmpId(empId);
-            emp.setEmpId(null);
+
+    /**
+     * 同步数据
+     *
+     * @param date 日期
+     */
+    @Override
+    public void sync(Date date) throws Exception {
+        TwinEmp emp = selectTwinEmpByDate(date);
+        if (emp == null) {
+            emp = new TwinEmp();
+        }
+        List<TwinWkEmpRota> list = rotaService.selectTwinWkEmpRotaListByDate(date);
+        List<TwinWkEmpRota> listA = list.stream().filter(d -> "A".equals(d.getEmpTeam())).collect(Collectors.toList());
+        List<TwinWkEmpRota> listB = list.stream().filter(d -> "B".equals(d.getEmpTeam())).collect(Collectors.toList());
+        List<TwinEmpDetail> detailListA = combo(listA);
+        List<TwinEmpDetail> detailListB = combo(listB);
+        emp.setTwinEmpDetailListA(detailListA);
+        emp.setTwinEmpDetailListB(detailListB);
+        if (emp.getEmpId() != null) {
+            updateTwinEmp(emp);
+        } else {
             emp.setEmpDate(date);
             insertTwinEmp(emp);
-            twinEmp = emp;
-        } else {
-            Long empId = list.get(0).getEmpId();
-            twinEmp = selectTwinEmpByEmpId(empId);
         }
-        return twinEmp;
     }
+
+    /**
+     * 组合数据
+     *
+     * @param list 排班数据
+     * @return 组合结果
+     */
+    private List<TwinEmpDetail> combo(List<TwinWkEmpRota> list) {
+        return list.stream().map(d -> {
+            TwinEmpDetail detail = new TwinEmpDetail();
+            detail.setEmpName(d.getEmpName());
+            detail.setEmpTeam(d.getEmpTeam());
+            detail.setDevices(Tools.formatDevices(d.getDevices()));
+            detail.setInTime(d.getInTime());
+            detail.setOutTime(d.getOutTime());
+            LocalDateTime in = DateUtils.toLocalDateTime(d.getInTime());
+            LocalDateTime out = DateUtils.toLocalDateTime(d.getOutTime());
+            String remark = in.getHour() + "-" + out.getHour();
+            detail.setRemark(remark);
+            return detail;
+        }).collect(Collectors.toList());
+    }
+
+
 }

+ 8 - 0
jjt-biz/src/main/java/com/jjt/task/CalcTask.java

@@ -4,6 +4,7 @@ import com.jjt.calc.service.ITwinCalcDayService;
 import com.jjt.calc.service.ITwinCalcHourService;
 import com.jjt.common.utils.DateUtils;
 import com.jjt.emp.service.ITwinEmpCalcService;
+import com.jjt.emp.service.ITwinEmpService;
 import org.springframework.stereotype.Component;
 
 import javax.annotation.Resource;
@@ -23,6 +24,8 @@ public class CalcTask {
     private ITwinCalcDayService dayService;
     @Resource
     private ITwinEmpCalcService empCalcService;
+    @Resource
+    private ITwinEmpService empService;
 
     /**
      * 统计上一时段数据
@@ -38,6 +41,11 @@ public class CalcTask {
     public void day() {
         LocalDate localDate = LocalDate.now().minusDays(1);
         dayService.day(localDate);
+        try {
+            empService.sync(DateUtils.toDate(localDate));
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
         empCalcService.calc(DateUtils.toDate(localDate));
     }
 

+ 93 - 0
jjt-biz/src/main/java/com/jjt/utils/Tools.java

@@ -446,4 +446,97 @@ public class Tools {
         return v == null ? BigDecimal.ZERO : v;
     }
 
+
+    /**
+     * 格式化设备编号,将连续序列转换为范围表示
+     *
+     * @param devices 原始设备编号字符串
+     * @return 格式化后的设备编号字符串
+     */
+    public static String formatDevices(String devices) {
+        if (devices == null || devices.isEmpty()) {
+            return devices;
+        }
+        try {
+            // 按逗号分割设备编号
+            String[] deviceArray = devices.split(",");
+            List<Integer> deviceNumbers = new ArrayList<>();
+
+            // 转换为整数列表
+            for (String device : deviceArray) {
+                deviceNumbers.add(Integer.parseInt(device.trim()));
+            }
+
+            // 排序
+            deviceNumbers.sort(Integer::compareTo);
+
+            // 合并连续序列
+            List<String> result = new ArrayList<>();
+            int start = deviceNumbers.get(0);
+            int end = start;
+
+            for (int i = 1; i < deviceNumbers.size(); i++) {
+                if (deviceNumbers.get(i) == end + 1) {
+                    // 连续数字
+                    end = deviceNumbers.get(i);
+                } else {
+                    // 不连续,保存当前序列
+                    if (start == end) {
+                        result.add(String.valueOf(start));
+                    } else if (end - start == 1) {
+                        // 只有两个数字,不合并
+                        result.add(String.valueOf(start));
+                        result.add(String.valueOf(end));
+                    } else {
+                        // 三个或以上连续数字,合并为范围
+                        result.add(start + "-" + end);
+                    }
+                    start = deviceNumbers.get(i);
+                    end = start;
+                }
+            }
+
+            // 处理最后一组
+            if (start == end) {
+                result.add(String.valueOf(start));
+            } else if (end - start == 1) {
+                result.add(String.valueOf(start));
+                result.add(String.valueOf(end));
+            } else {
+                result.add(start + "-" + end);
+            }
+
+            return String.join(",", result);
+        } catch (Exception e) {
+            // 出现异常时返回原始值
+            return devices;
+        }
+    }
+
+    /**
+     * 解析设备
+     *
+     * @param d 设备编号
+     * @return 设备编号数组
+     */
+    public static Long[] parseDevices(String d) {
+        String[] temp = d.split(",");
+        Set<Long> set = new HashSet<>();
+        for (String s : temp) {
+            String[] ss = s.split("-");
+            if (ss.length > 1) {
+                long st = Long.parseLong(ss[0]);
+                long ed = Long.parseLong(ss[1]);
+                for (long i = st; i <= ed; i++) {
+                    set.add(i);
+                }
+            } else {
+                set.add(Long.parseLong(s));
+            }
+        }
+        Long[] devices = new Long[set.size()];
+        set.toArray(devices);
+        return devices;
+    }
+
 }

+ 42 - 22
jjt-biz/src/main/resources/mapper/emp/TwinEmpDetailMapper.xml

@@ -1,33 +1,45 @@
 <?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">
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.jjt.emp.mapper.TwinEmpDetailMapper">
-    
+
     <resultMap type="TwinEmpDetail" id="TwinEmpDetailResult">
-        <result property="detailId"    column="DETAIL_ID"    />
-        <result property="empId"    column="EMP_ID"    />
-        <result property="empName"    column="EMP_NAME"    />
-        <result property="empTeam"    column="EMP_TEAM"    />
-        <result property="devices"    column="DEVICES"    />
-        <result property="remark"    column="REMARK"    />
+        <result property="detailId" column="DETAIL_ID"/>
+        <result property="empId" column="EMP_ID"/>
+        <result property="empName" column="EMP_NAME"/>
+        <result property="empTeam" column="EMP_TEAM"/>
+        <result property="inTime" column="IN_TIME"/>
+        <result property="outTime" column="OUT_TIME"/>
+        <result property="devices" column="DEVICES"/>
+        <result property="remark" column="REMARK"/>
     </resultMap>
 
     <sql id="selectTwinEmpDetailVo">
-        select DETAIL_ID, EMP_ID, EMP_NAME, EMP_TEAM, DEVICES, REMARK from TWIN_EMP_DETAIL
+        select DETAIL_ID,
+               EMP_ID,
+               EMP_NAME,
+               EMP_TEAM,
+               IN_TIME,
+               OUT_TIME,
+               DEVICES,
+               REMARK
+        from TWIN_EMP_DETAIL
     </sql>
 
     <select id="selectTwinEmpDetailList" parameterType="TwinEmpDetail" resultMap="TwinEmpDetailResult">
         <include refid="selectTwinEmpDetailVo"/>
-        <where>  
-            <if test="empId != null "> and EMP_ID = #{empId}</if>
-            <if test="empName != null  and empName != ''"> and EMP_NAME like concat('%', #{empName}, '%')</if>
-            <if test="empTeam != null  and empTeam != ''"> and EMP_TEAM = #{empTeam}</if>
-            <if test="devices != null  and devices != ''"> and DEVICES = #{devices}</if>
-            <if test="remark != null  and remark != ''"> and REMARK = #{remark}</if>
+        <where>
+            <if test="empId != null ">and EMP_ID = #{empId}</if>
+            <if test="empName != null  and empName != ''">and EMP_NAME like concat('%', #{empName}, '%')</if>
+            <if test="empTeam != null  and empTeam != ''">and EMP_TEAM = #{empTeam}</if>
+            <if test="inTime != null ">and IN_TIME = #{inTime}</if>
+            <if test="outTime != null ">and OUT_TIME = #{outTime}</if>
+            <if test="devices != null  and devices != ''">and DEVICES = #{devices}</if>
+            <if test="remark != null  and remark != ''">and REMARK = #{remark}</if>
         </where>
     </select>
-    
+
     <select id="selectTwinEmpDetailByDetailId" parameterType="Long" resultMap="TwinEmpDetailResult">
         <include refid="selectTwinEmpDetailVo"/>
         where DETAIL_ID = #{detailId}
@@ -39,16 +51,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="empId != null">EMP_ID,</if>
             <if test="empName != null">EMP_NAME,</if>
             <if test="empTeam != null">EMP_TEAM,</if>
+            <if test="inTime != null">IN_TIME,</if>
+            <if test="outTime != null">OUT_TIME,</if>
             <if test="devices != null">DEVICES,</if>
             <if test="remark != null">REMARK,</if>
-         </trim>
+        </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="empId != null">#{empId},</if>
             <if test="empName != null">#{empName},</if>
             <if test="empTeam != null">#{empTeam},</if>
+            <if test="inTime != null">#{inTime},</if>
+            <if test="outTime != null">#{outTime},</if>
             <if test="devices != null">#{devices},</if>
             <if test="remark != null">#{remark},</if>
-         </trim>
+        </trim>
     </insert>
 
     <update id="updateTwinEmpDetail" parameterType="TwinEmpDetail">
@@ -57,6 +73,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="empId != null">EMP_ID = #{empId},</if>
             <if test="empName != null">EMP_NAME = #{empName},</if>
             <if test="empTeam != null">EMP_TEAM = #{empTeam},</if>
+            <if test="inTime != null">IN_TIME = #{inTime},</if>
+            <if test="outTime != null">OUT_TIME = #{outTime},</if>
             <if test="devices != null">DEVICES = #{devices},</if>
             <if test="remark != null">REMARK = #{remark},</if>
         </trim>
@@ -64,13 +82,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </update>
 
     <delete id="deleteTwinEmpDetailByDetailId" parameterType="Long">
-        delete from TWIN_EMP_DETAIL where DETAIL_ID = #{detailId}
+        delete
+        from TWIN_EMP_DETAIL
+        where DETAIL_ID = #{detailId}
     </delete>
 
     <delete id="deleteTwinEmpDetailByDetailIds" parameterType="String">
-        delete from TWIN_EMP_DETAIL where DETAIL_ID in 
+        delete from TWIN_EMP_DETAIL where DETAIL_ID in
         <foreach item="detailId" collection="array" open="(" separator="," close=")">
             #{detailId}
         </foreach>
     </delete>
-</mapper>
+</mapper>

+ 36 - 20
jjt-biz/src/main/resources/mapper/emp/TwinEmpMapper.xml

@@ -1,35 +1,39 @@
 <?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">
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.jjt.emp.mapper.TwinEmpMapper">
 
     <resultMap type="TwinEmp" id="TwinEmpResult">
-        <result property="empId"    column="EMP_ID"    />
-        <result property="empDate"    column="EMP_DATE"    />
+        <result property="empId" column="EMP_ID"/>
+        <result property="empDate" column="EMP_DATE"/>
     </resultMap>
 
     <resultMap id="TwinEmpTwinEmpDetailResult" type="TwinEmp" extends="TwinEmpResult">
-        <collection property="twinEmpDetailList" ofType="TwinEmpDetail" column="EMP_ID" select="selectTwinEmpDetailList" />
+        <collection property="twinEmpDetailList" ofType="TwinEmpDetail" column="EMP_ID"
+                    select="selectTwinEmpDetailList"/>
     </resultMap>
 
     <resultMap type="TwinEmpDetail" id="TwinEmpDetailResult">
-        <result property="detailId"    column="DETAIL_ID"    />
-        <result property="empId"    column="EMP_ID"    />
-        <result property="empName"    column="EMP_NAME"    />
-        <result property="empTeam"    column="EMP_TEAM"    />
-        <result property="devices"    column="DEVICES"    />
-        <result property="remark"    column="REMARK"    />
+        <result property="detailId" column="DETAIL_ID"/>
+        <result property="empId" column="EMP_ID"/>
+        <result property="empName" column="EMP_NAME"/>
+        <result property="empTeam" column="EMP_TEAM"/>
+        <result property="inTime" column="IN_TIME"/>
+        <result property="outTime" column="OUT_TIME"/>
+        <result property="devices" column="DEVICES"/>
+        <result property="remark" column="REMARK"/>
     </resultMap>
 
     <sql id="selectTwinEmpVo">
-        select EMP_ID, EMP_DATE from TWIN_EMP
+        select EMP_ID, EMP_DATE
+        from TWIN_EMP
     </sql>
 
     <select id="selectTwinEmpList" parameterType="TwinEmp" resultMap="TwinEmpResult">
         <include refid="selectTwinEmpVo"/>
         <where>
-            <if test="empDate != null "> and FORMAT(EMP_DATE,'yyyy-MM-dd') = #{empDate}</if>
+            <if test="empDate != null ">and FORMAT(EMP_DATE,'yyyy-MM-dd') = #{empDate}</if>
         </where>
         order by emp_date desc
     </select>
@@ -41,7 +45,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </select>
 
     <select id="selectTwinEmpDetailList" resultMap="TwinEmpDetailResult">
-        select DETAIL_ID, EMP_ID, EMP_NAME, EMP_TEAM, DEVICES, REMARK
+        select DETAIL_ID,
+               EMP_ID,
+               EMP_NAME,
+               EMP_TEAM,
+               IN_TIME,
+               OUT_TIME,
+               DEVICES,
+               REMARK
         from TWIN_EMP_DETAIL
         where EMP_ID = #{EMP_ID}
     </select>
@@ -50,10 +61,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         insert into TWIN_EMP
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="empDate != null">EMP_DATE,</if>
-         </trim>
+        </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="empDate != null">#{empDate},</if>
-         </trim>
+        </trim>
     </insert>
 
     <update id="updateTwinEmp" parameterType="TwinEmp">
@@ -65,7 +76,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </update>
 
     <delete id="deleteTwinEmpByEmpId" parameterType="Long">
-        delete from TWIN_EMP where EMP_ID = #{empId}
+        delete
+        from TWIN_EMP
+        where EMP_ID = #{empId}
     </delete>
 
     <delete id="deleteTwinEmpByEmpIds" parameterType="String">
@@ -83,13 +96,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </delete>
 
     <delete id="deleteTwinEmpDetailByEmpId" parameterType="Long">
-        delete from TWIN_EMP_DETAIL where EMP_ID = #{empId}
+        delete
+        from TWIN_EMP_DETAIL
+        where EMP_ID = #{empId}
     </delete>
 
     <insert id="batchTwinEmpDetail">
-        insert into TWIN_EMP_DETAIL(EMP_ID, EMP_NAME, EMP_TEAM, DEVICES, REMARK) values
+        insert into TWIN_EMP_DETAIL(EMP_ID, EMP_NAME, EMP_TEAM,IN_TIME,OUT_TIME, DEVICES, REMARK) values
         <foreach item="item" index="index" collection="list" separator=",">
-            (#{item.empId}, #{item.empName}, #{item.empTeam}, #{item.devices}, #{item.remark})
+            (#{item.empId}, #{item.empName}, #{item.empTeam}, #{item.inTime}, #{item.outTime}, #{item.devices},
+            #{item.remark})
         </foreach>
     </insert>
 </mapper>

BIN
sales_data_template.xlsx