Commit 9b5f5bda by 刘鑫

Merge remote-tracking branch 'origin/develop' into develop

# Conflicts:
#	project-order/src/main/java/com/dituhui/pea/order/entity/OrderInfoEntity.java
2 parents 38b0ddab 33cb9c35
Showing with 518 additions and 112 deletions
......@@ -33,6 +33,19 @@ public class DispatchController {
return res;
}
@GetMapping("/dispatch/order/group")
public Result<?> getDispatchOrderGroup(@Valid DispatchOrderListReq reqDTO) {
// 获取派工台待派订单列表
Result<?> res = null;
try {
res = dispatchService.getDispatchOrderGroup(reqDTO);
}catch (BusinessException e) {
return Result.failed(e.getMessage());
}
return res;
}
@GetMapping("/dispatch/engineer/order/list")
public Result<?> getDispatchEngineerOrderList(@Valid DispatchEngineerOrderListReq reqDTO) {
// 获取派工台工程师已派订单列表
......
......@@ -40,8 +40,10 @@ public class MsgController {
MsgQuery request) {
CommonUtil.setNullValue(request);
request.setUserId(userId);
if (!"is_read".equalsIgnoreCase(request.getSort())) {
if (!"isRead".equalsIgnoreCase(request.getSort())) {
request.setSort("create_time");
} else {
request.setSort("is_read");
}
if (!"asc".equalsIgnoreCase(request.getSortType())) {
request.setSortType("desc");
......@@ -63,7 +65,7 @@ public class MsgController {
* @date 2023/10/24
*/
@PostMapping("/msg/delete")
public Result<Boolean> delete(@RequestHeader(name = "userId", required = true) String userId, @RequestBody @Valid IdDTO dto) {
public Result<Boolean> delete(@RequestHeader(name = "userId", required = true) String userId, @RequestBody @Valid MsgDTO.IdDTO dto) {
AssertUtil.isNotEmpty(userId, "用户ID不能为空");
AssertUtil.isNotNull(dto.getId(), "消息ID不能为空");
msgService.delete(dto.getId(), userId);
......
......@@ -21,7 +21,9 @@ public interface MsgDao extends JpaRepository<MsgEntity, Integer> {
" where IF(:#{#req.startDate} is not null, tt.create_time>=:#{#req.startDate}, 1=1)" +
" and IF(:#{#req.endDate} is not null, tt.create_time<:#{#req.endDate}, 1=1)" +
" and IF(:#{#req.keyWord} is not null, tt.content like concat('%',:#{#req.keyWord},'%'), 1=1)" +
" and IF(:#{#req.orgTreeValue} is not null, (tt.cluster_id=:#{#req.orgTreeValue} or tt.branch_id=:#{#req.orgTreeValue} or tt.group_id=:#{#req.orgTreeValue}), 1=1)" +
" and IF(:#{#req.clusterId} is not null, tt.cluster_id=:#{#req.clusterId}, 1=1)" +
" and IF(:#{#req.branchId} is not null, tt.branch_id=:#{#req.branchId}, 1=1)" +
" and IF(:#{#req.groupId} is not null, tt.group_id=:#{#req.groupId}, 1=1)" +
"group by tt.cluster_id,tt.branch_id,tt.group_id" +
") t",
countQuery = "select count(t.cluster_id)" +
......@@ -31,7 +33,9 @@ public interface MsgDao extends JpaRepository<MsgEntity, Integer> {
" where IF(:#{#req.startDate} is not null, tt.create_time>=:#{#req.startDate}, 1=1)" +
" and IF(:#{#req.endDate} is not null, tt.create_time<:#{#req.endDate}, 1=1)" +
" and IF(:#{#req.keyWord} is not null, tt.content like concat('%',:#{#req.keyWord},'%'), 1=1)" +
" and IF(:#{#req.orgTreeValue} is not null, (tt.cluster_id=:#{#req.orgTreeValue} or tt.branch_id=:#{#req.orgTreeValue} or tt.group_id=:#{#req.orgTreeValue}), 1=1)" +
" and IF(:#{#req.clusterId} is not null, tt.cluster_id=:#{#req.clusterId}, 1=1)" +
" and IF(:#{#req.branchId} is not null, tt.branch_id=:#{#req.branchId}, 1=1)" +
" and IF(:#{#req.groupId} is not null, tt.group_id=:#{#req.groupId}, 1=1)" +
"group by tt.cluster_id,tt.branch_id,tt.group_id" +
") t"
, nativeQuery = true // 开启原生sql
......@@ -69,8 +73,8 @@ public interface MsgDao extends JpaRepository<MsgEntity, Integer> {
" join sys_user_org uo on u.id=uo.user_id" +
" join sys_user_role ur on ur.user_id=u.id" +
" join sys_role r on r.id=ur.role_id and r.name='分站派工'" +
" and IF(:groupId is not null, uo.org_id=:groupId and uo.org_level=2, 1=1)" +
" and IF(:groupId is null and :branchId is not null, uo.org_id=:branchId and uo.org_level=1, 1=1)" +
" and IF(:groupId is not null, ((uo.org_id=:groupId and uo.org_level=2) or (uo.org_id=:branchId and uo.org_level=1) or (uo.org_id=:clusterId and uo.org_level=0)), 1=1)" +
" and IF(:groupId is null and :branchId is not null, ((uo.org_id=:branchId and uo.org_level=1) or (uo.org_id=:clusterId and uo.org_level=0)), 1=1)" +
" and IF(:groupId is null and :branchId is null and :clusterId is not null, uo.org_id=:clusterId and uo.org_level=0, 1=1)"
, nativeQuery = true // 开启原生sql
)
......
......@@ -10,18 +10,31 @@ import java.util.List;
public interface OrderInfoDao extends JpaRepository<OrderInfoEntity, Long>, JpaSpecificationExecutor<OrderInfoEntity> {
OrderInfoEntity getByOrderId(String orderId);
OrderInfoEntity getByOrderIdAndDt(String orderId, LocalDate dt);
List<OrderInfoEntity> findByOrderId(String orderId);
List<OrderInfoEntity> findByDtAndEngineerCodeIn(LocalDate date, List<String> engineerCodes);
List<OrderInfoEntity> findByDtAndEngineerCode(LocalDate date, String engineerCode);
@Query("SELECT o.orderId, s.skillCategory as skillCaption FROM OrderInfoEntity o JOIN SkillInfoEntity s on o.brand=s.brand and o.type=s.type and o.skill=s.skill WHERE o.orderId = :orderId and o.dt = :dt")
OrderSkillProjection getOrderSkillCaptionByOrderIdAndDt(String orderId, LocalDate dt);
List<OrderInfoEntity> findAllByOrderIdIn(List<String> orderIds);
List<OrderInfoEntity> findAllByDtAndOrderIdIn(LocalDate dt, List<String> orderIds);
List<OrderInfoEntity> findByEngineerCodeAndDtAndAppointmentStatusIn(String engineerCode, LocalDate dt, List<String> appointmentStatus);
List<OrderInfoEntity> findByDtAndOrgTeamIdAndAppointmentStatusIn(LocalDate dt, String orgTeamId, List<String> appointmentStatus);
OrderInfoEntity findTopBySkillAndAppointmentStatus(String skill, String status);
List<OrderInfoEntity> findByServiceStatusAndEngineerCode(String serviceStatus, String engineerCode);
List<OrderInfoEntity> findByDtAndAddressId(String dt, String addressId);
List<OrderInfoEntity> findByMultipleOrders(String multipleOrders);
}
......@@ -3,53 +3,95 @@ package com.dituhui.pea.order.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import javax.persistence.Column;
import java.util.List;
@Data
public class DispatchEngineerOrderListResp {
private List<EngineerInfo> engineers;
@Data
public static class EngineerInfo{
private String engineerCode;
private String engineerName;
private String capacity;
private String capacityStatus;
private String grade;
private List<OrderInfo> orders;
}
@JsonInclude(JsonInclude.Include.ALWAYS)
@Data
public static class OrderInfo{
private boolean weight;
private String orderId;
private String description;
private String brand;
private String type;
private String skill;
private String typeCategory;
private String skillCategory;
private String faultDescribe;
private String applyNote;
private Integer duration;
private String province;
private String city;
private String county;
private String address;
private String name;
private String phone;
private String expectTimeDesc;
private String source;
private String dispatcher;
private String appointmentType;
private String appointmentStatus;
private String serviceStatus;
private String orderStatus;
private String orderStatusDesc;
private String createTime;
private String groupTag;
private Integer groupWeight;
}
private List<EngineerInfo> engineers;
@Data
public static class EngineerInfo {
private String engineerCode;
private String engineerName;
private String capacity;
private String capacityStatus;
private String grade;
private List<OrderInfo> orders;
}
@JsonInclude(JsonInclude.Include.ALWAYS)
@Data
public static class OrderInfo {
private boolean weight;
private String orderId;
private String description;
private String brand;
private String type;
private String skill;
private String typeCategory;
private String skillCategory;
private String faultDescribe;
private String applyNote;
private Integer duration;
private String province;
private String city;
private String county;
private String address;
private String name;
private String phone;
private String expectTimeDesc;
private String source;
private String dispatcher;
private String appointmentType;
private String appointmentStatus;
private String serviceStatus;
private String orderStatus;
private String orderStatusDesc;
private String createTime;
private String groupTag;
private Integer groupWeight;
/**
* 一家多单id,有则多条订单关联,没有则不是一家多单
*/
private String multipleOrders;
/**
* 一家多单订单集合
*/
private List<OrderInfo> multipleOrderList;
/**
* 是否重物搬运(双人上门) 0:否 1:是 默认0
*/
private Integer isMultiple = 0;
/**
* 是否指定某个工程师/是否排除某个工程师 0:否 1:指定 2:排除 默认0
*/
private Integer isAppointEngineer = 0;
/**
* 指定某个工程师/排除某个工程师 codes 多个,分割
*/
private String appointEngineerCodes;
/**
* 是否超派,0否 1是,默认0
*/
private Integer transcend;
/**
* 工单优先级
*/
private String beanPriority;
/**
* 是否是特殊时间段,0否 1是 默认0
*/
private Integer isSpecialTime;
}
}
......@@ -13,6 +13,10 @@ public class DispatchOrderListReq {
private String levelValue;
@NotNull
private String Date;
/**
* 0:工单优先级,1:耗时,2:意向时间,3:分站/网点,4:技能,5:一家多单
*/
@NotNull
private String groupTagId;
private List<String> branchIds;
......
......@@ -3,41 +3,93 @@ package com.dituhui.pea.order.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import javax.persistence.Column;
import java.util.List;
@Data
public class DispatchOrderListResp {
private List<Order> orders;
@JsonInclude(JsonInclude.Include.ALWAYS)
@Data
public static class Order{
private boolean weight;
private String orderId;
private String description;
private String brand;
private String type;
private String skill;
private String typeCategory;
private String skillCategory;
private String faultDescribe;
private String applyNote;
private Integer duration;
private String province;
private String city;
private String county;
private String address;
private String name;
private String phone;
private String expectTimeDesc;
private String source;
private String appointmentType;
private String dispatcher;
private String appointmentStatus;
private String orderStatus;
private String serviceStatus;
private String createTime;
private String groupTag;
private Integer groupWeight;
}
private List<Order> orders;
@JsonInclude(JsonInclude.Include.ALWAYS)
@Data
public static class Order {
private boolean weight;
private String orderId;
private String description;
private String brand;
private String type;
private String skill;
private String typeCategory;
private String skillCategory;
private String faultDescribe;
private String applyNote;
private Integer duration;
private String province;
private String city;
private String county;
private String address;
private String name;
private String phone;
private String expectTimeDesc;
private String source;
private String appointmentType;
private String dispatcher;
private String appointmentStatus;
private String orderStatus;
private String serviceStatus;
private String createTime;
private String groupTag;
private Integer groupWeight;
/**
* 一家多单id,有则多条订单关联,没有则不是一家多单
*/
private String multipleOrders;
/**
* 分站/网点id
*/
private String orgGroupId;
/**
* 分站/网点name
*/
private String orgGroupName;
/**
* 一家多单订单集合
*/
private List<DispatchOrderListResp.Order> multipleOrderList;
/**
* 是否重物搬运(双人上门) 0:否 1:是 默认0
*/
private Integer isMultiple;
/**
* 是否指定某个工程师/是否排除某个工程师 0:否 1:指定 2:排除 默认0
*/
private Integer isAppointEngineer;
/**
* 指定某个工程师/排除某个工程师 codes 多个,分割
*/
private String appointEngineerCodes;
/**
* 是否超派,0否 1是,默认0
*/
private Integer transcend;
/**
* 工单优先级
*/
private String beanPriority;
/**
* 是否是特殊时间段,0否 1是 默认0
*/
private Integer isSpecialTime;
}
}
package com.dituhui.pea.order.dto;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
* 公共 id类
*
* @author RenPing
* @date 2023/10/26
*/
@Data
public class IdDTO {
@NotNull(message = "ID不能为空")
private Integer id;
}
......@@ -49,4 +49,12 @@ public class MsgDTO {
@Min(value = 0, message = "标签类型格式不对")
@Max(value = 1, message = "标签类型格式不对")
private Integer tag;
@Data
public static class IdDTO {
@NotNull(message = "ID不能为空")
private Integer id;
}
}
\ No newline at end of file
......@@ -56,7 +56,17 @@ public class MsgQuery {
private String keyWord;
/**
* 大区ID、部门ID、小组ID
* 大区ID(大区Id、分部Id、分组Id只需传一个)
*/
private String orgTreeValue;
private String clusterId;
/**
* 分部ID
*/
private String branchId;
/**
* 小组ID
*/
private String groupId;
}
\ No newline at end of file
......@@ -2,6 +2,8 @@ package com.dituhui.pea.order.dto;
import lombok.Data;
import java.util.List;
@Data
public class OrderServiceList {
private String orderId;
......@@ -54,4 +56,24 @@ public class OrderServiceList {
private String appointEngineerCodes;
/**
* 一家多单订单集合
*/
private List<OrderServiceList> multipleOrderList;
/**
* 一家多单id,有则多条订单关联,没有则不是一家多单
*/
private String multipleOrders;
/**
* 是否超派,0否 1是,默认0
*/
private Integer transcend;
/**
* 是否是特殊时间段,0否 1是 默认0
*/
private Integer isSpecialTime;
}
......@@ -75,4 +75,27 @@ public class OrderInfo {
* 指定某个工程师/排除某个工程师 codes 多个,分割
*/
private String appointEngineerCodes;
/**
* 一家多单id,有则多条订单关联,没有则不是一家多单
*/
private String multipleOrders;
/**
* bean同步地址id
*/
private String addressId;
/**
* 是否超派,0否 1是,默认0
*/
private Integer transcend;
/**
* 是否是特殊时间段,0否 1是 默认0
*/
private Integer isSpecialTime;
}
\ No newline at end of file
......@@ -198,6 +198,34 @@ public class OrderInfoEntity {
@Column(name = "appoint_engineer_codes")
private String appointEngineerCodes;
/**
* 一家多单id,有则多条订单关联,没有则不是一家多单
*/
@Column(name = "multiple_orders")
private String multipleOrders;
/**
* bean同步地址id
*/
@Column(name = "address_id")
private String addressId;
/**
* 是否超派,0否 1是,默认0
*/
@Column(name = "transcend")
private Integer transcend;
/**
* 是否是特殊时间段,0否 1是 默认0
*/
@Column(name = "is_special_time")
private Integer isSpecialTime = 0;
/**
* 申请加单状态,CONFIRMED 预约成功
* REFUSED 客户拒绝
......
package com.dituhui.pea.order.enums;
public enum OrderGroupEnum {
zero("0"),
one("1"),
two("2"),
three("3"),
four("4"),
five("5");
private String code;
OrderGroupEnum(String code) {
this.code = code;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
......@@ -8,9 +8,17 @@ import java.util.List;
public interface DispatchService {
Result<?> getDispatchOrderList(DispatchOrderListReq reqDTO);
Result<?> getDispatchOrderList(DispatchOrderListReq reqDTO);
Result<?> getDispatchEngineerOrderList(DispatchEngineerOrderListReq reqDTO);
Result<?> getDispatchEngineerOrderList(DispatchEngineerOrderListReq reqDTO);
Result<?> dispatchOrderConfirm(String engineerCode, String date, List<String> orderIds);
Result<?> dispatchOrderConfirm(String engineerCode, String date, List<String> orderIds);
/**
* 待派工工单池分组
*
* @param reqDTO
* @return
*/
Result<?> getDispatchOrderGroup(DispatchOrderListReq reqDTO);
}
package com.dituhui.pea.order.service;
import com.dituhui.pea.common.Result;
/**
* 订单相关
*/
public interface OrderInfoService {
/**
* 新增订单处理一家多单逻辑
*
* @param dt 订单日期 列:2023-07-21
* @param addressId 地址id
* @return 有则返回多条订单关联id,没有则不是一家多单
*/
Result<String> addMultipleOrders(String dt, String addressId);
/**
* 取消指定订单一家多台
*
* @param multipleOrders 订单关联id
* @param orderId 订单id
* @return 有则返回多条订单关联id,没有则不是一家多单
*/
Result deleteMultipleOrders(String multipleOrders, String orderId);
}
package com.dituhui.pea.order.service.impl;
import com.dituhui.pea.common.Result;
import com.dituhui.pea.order.dao.OrderInfoDao;
import com.dituhui.pea.order.entity.OrderInfoEntity;
import com.dituhui.pea.order.service.OrderInfoService;
import com.dituhui.pea.util.UUIDUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.stream.Collectors;
@Service
@Slf4j
public class OrderInfoServiceImpl implements OrderInfoService {
@Autowired
private OrderInfoDao orderInfoDao;
/**
* 新增订单处理一家多单逻辑
*
* @param dt 订单日期 列:2023-07-21
* @param addressId 地址id
* @return 有则返回多条订单关联id,没有则不是一家多单
*/
@Override
@Transactional
public Result<String> addMultipleOrders(String dt, String addressId) {
List<OrderInfoEntity> infoList = orderInfoDao.findByDtAndAddressId(dt, addressId);
if (CollectionUtils.isEmpty(infoList)) {
return Result.success(null);
}
List<String> multipleOrdersList = infoList.stream().filter(e -> StringUtils.isNotEmpty(e.getMultipleOrders())).map(OrderInfoEntity::getMultipleOrders).distinct().collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(multipleOrdersList)) {
return Result.success(multipleOrdersList.get(0));
}
String uuid = UUIDUtil.getUuid();
for (OrderInfoEntity orderInfoEntity : infoList) {
orderInfoEntity.setMultipleOrders(uuid);
orderInfoDao.save(orderInfoEntity);
}
return Result.success(uuid);
}
/**
* 取消指定订单一家多台
*
* @param multipleOrders 订单关联id
* @param orderId 订单id
* @return 有则返回多条订单关联id,没有则不是一家多单
*/
@Override
@Transactional
public Result deleteMultipleOrders(String multipleOrders, String orderId) {
List<OrderInfoEntity> infoList = orderInfoDao.findByMultipleOrders(multipleOrders);
for (OrderInfoEntity infoEntity : infoList) {
if (infoEntity.getOrderId().equals(orderId)) {
infoEntity.setMultipleOrders(null);
orderInfoDao.save(infoEntity);
}
if (infoList.size() == 2) {
infoEntity.setMultipleOrders(null);
orderInfoDao.save(infoEntity);
}
}
return Result.success();
}
}
......@@ -33,6 +33,9 @@ public class OrderServiceListServiceImpl implements OrderServiceListService {
@Autowired
private OrgBranchDao orgBranchDao;
@Autowired
private OrderInfoDao orderInfoDao;
@Transactional
@Override
public Result<OrderServiceListResp> getOrderServiceList(OrderServiceListReq reqDTO) throws BusinessException {
......@@ -124,12 +127,12 @@ public class OrderServiceListServiceImpl implements OrderServiceListService {
record.setDescription(o.getDescription());
record.setPriority(o.getPriority());
record.setOrgBranchName(branchNames.getOrDefault(o.getOrgBranchId(), ""));
// 获取工程师信息,为派工为空
if(StringUtils.isNotBlank(o.getEngineerCode())) {
List<String> names = this.getOrderEngineerNames(o.getEngineerCode(), o.getEngineerCodeSub(), engineerNames);
record.setEngineerNum(names.size()); //工程师数量
record.setEngineerNames(String.join("、", names)); //工程师姓名列表
if (StringUtils.isNotBlank(o.getEngineerCode())) {
List<String> names = this.getOrderEngineerNames(o.getEngineerCode(), o.getEngineerCodeSub(), engineerNames);
record.setEngineerNum(names.size()); //工程师数量
record.setEngineerNames(String.join("、", names)); //工程师姓名列表
}
record.setExpectTimeBegin(TimeUtils.IsoTimestamp2DateTime(o.getExpectTimeBegin()));
......@@ -146,7 +149,17 @@ public class OrderServiceListServiceImpl implements OrderServiceListService {
record.setIsMultiple(o.getIsMultiple());
record.setIsAppointEngineer(o.getIsAppointEngineer());
record.setAppointEngineerCodes(o.getAppointEngineerCodes());
record.setMultipleOrders(o.getMultipleOrders());
record.setTranscend(o.getTranscend());
record.setIsSpecialTime(o.getIsSpecialTime());
if (StringUtils.isNotEmpty(o.getMultipleOrders())) {
List<OrderInfoEntity> byMultipleOrders = orderInfoDao.findByMultipleOrders(o.getMultipleOrders());
List<OrderServiceList> multipleItems = new ArrayList<>();
for (OrderInfoEntity info : byMultipleOrders) {
multipleItems.add(toMultipleOrders(info, branchNames, engineerNames));
}
record.setMultipleOrderList(multipleItems);
}
content.add(record);
}
......@@ -161,6 +174,50 @@ public class OrderServiceListServiceImpl implements OrderServiceListService {
return Result.success(res);
}
private OrderServiceList toMultipleOrders(OrderInfoEntity o, Map<String, String> branchNames, Map<String, String> engineerNames) {
OrderServiceList record = new OrderServiceList();
record.setOrderId(o.getOrderId());
record.setType(o.getType());
record.setBrand(o.getBrand());
record.setSkill(o.getSkill());
record.setTakeTime(o.getTakeTime());
record.setFaultDescribe(o.getFaultDescribe());
record.setName(o.getName());
record.setPhone(o.getPhone());
record.setAddress(String.format("%s-%s-%s", o.getCity(), o.getCounty(), o.getAddress()));
record.setX(o.getX());
record.setY(o.getY());
record.setSource(o.getSource());
record.setDescription(o.getDescription());
record.setPriority(o.getPriority());
record.setOrgBranchName(branchNames.getOrDefault(o.getOrgBranchId(), ""));
// 获取工程师信息,为派工为空
if (StringUtils.isNotBlank(o.getEngineerCode())) {
List<String> names = this.getOrderEngineerNames(o.getEngineerCode(), o.getEngineerCodeSub(), engineerNames);
record.setEngineerNum(names.size()); //工程师数量
record.setEngineerNames(String.join("、", names)); //工程师姓名列表
}
record.setExpectTimeBegin(TimeUtils.IsoLocalDateTime2String(o.getExpectTimeBegin()));
record.setExpectTimeEnd(TimeUtils.IsoLocalDateTime2String(o.getExpectTimeEnd()));
record.setExpectTimeDesc(o.getExpectTimeDesc());
record.setAppointmentType(o.getAppointmentMethod());
record.setAppointmentStatus(o.getAppointmentStatus());
record.setOrderStatus(o.getOrderStatus());
record.setServiceStatus(o.getServiceStatus());
record.setDispatcher(o.getDispatcher());
record.setCreateTime(TimeUtils.IsoLocalDateTime2String(o.getCreateTime()));
record.setBeanPriority(o.getBeanPriority());
record.setIsMultiple(o.getIsMultiple());
record.setIsAppointEngineer(o.getIsAppointEngineer());
record.setAppointEngineerCodes(o.getAppointEngineerCodes());
record.setMultipleOrders(o.getMultipleOrders());
record.setTranscend(o.getTranscend());
return record;
}
private Map<String, String> getEngineerNames(List<OrderInfo> orders) {
// 获取技术员姓名
Set<String> engineerCodes = new HashSet<>();
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!