员工统计新增总检统计
This commit is contained in:
parent
9f0f577b53
commit
8819caa791
@ -286,4 +286,13 @@ public interface RepairStatisticsMapper {
|
||||
List<Map<String, Object>> selectWorkerStatisticsByUserIds(@Param("userIds") List<Long> userIds,
|
||||
@Param("startDate") String startDate,
|
||||
@Param("endDate") String endDate);
|
||||
|
||||
/**
|
||||
* 查询指定服务顾问的统计数据(产值和毛利)
|
||||
* @param advisorId 服务顾问ID
|
||||
* @param startDate 开始日期
|
||||
* @param endDate 结束日期
|
||||
* @return 包含产值和毛利的统计数据
|
||||
*/
|
||||
Map<String, Object> selectAdvisorStatistics(@Param("advisorId") Long advisorId, @Param("startDate") String startDate, @Param("endDate") String endDate);
|
||||
}
|
||||
|
||||
@ -14,11 +14,13 @@ import cn.iocoder.yudao.module.business.entity.DlBusinessChannel;
|
||||
import cn.iocoder.yudao.module.business.service.BusinessChannelService;
|
||||
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
|
||||
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.UserDTO;
|
||||
import cn.iocoder.yudao.module.tickets.entity.DlRepairTickets;
|
||||
import cn.iocoder.yudao.module.tickets.service.DlRepairTicketsService;
|
||||
import cn.iocoder.yudao.module.tickets.vo.DlRepairTicketsRespVO;
|
||||
import cn.iocoder.yudao.util.StringUtils;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
@ -33,6 +35,7 @@ import cn.hutool.core.util.ObjectUtil;
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.common.RepairCons.DICT_REPAIR_WORK_TYPE;
|
||||
@ -69,6 +72,9 @@ public class RepairStatisticsServiceImpl implements RepairStatisticsService {
|
||||
@Resource
|
||||
private RepairWorkerService workerService;
|
||||
|
||||
@Resource
|
||||
private cn.iocoder.yudao.module.system.api.permission.RoleApi roleApi;
|
||||
|
||||
/**
|
||||
* 将统计结果列表转换为Map格式
|
||||
* @param list 统计结果列表,每个元素包含key和value字段
|
||||
@ -563,8 +569,8 @@ public class RepairStatisticsServiceImpl implements RepairStatisticsService {
|
||||
resp.add(new HashMap<String, Object>() {{
|
||||
put("name", "总检");
|
||||
put("id", "zj");
|
||||
put("count", nfpgCount);
|
||||
put("count2", zjCount);
|
||||
put("nfpgCount", nfpgCount);
|
||||
put("zjCount", zjCount);
|
||||
}});
|
||||
|
||||
return resp;
|
||||
@ -692,7 +698,208 @@ public class RepairStatisticsServiceImpl implements RepairStatisticsService {
|
||||
|
||||
List<Map<String, Object>> resp = new ArrayList<>();
|
||||
|
||||
// 根据workType查询该工种下的所有员工
|
||||
// 特殊处理:当workType等于fwgw时,查询角色为fwgw的员工
|
||||
if ("fwgw".equals(workType)) {
|
||||
try {
|
||||
// 获取当前租户ID
|
||||
Long tenantId = cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder.getRequiredTenantId();
|
||||
// 查询角色为fwgw的员工列表(服务顾问)
|
||||
List<cn.iocoder.yudao.module.system.api.user.dto.UserDTO> advisors = roleApi.selectUserListByRoleCode(tenantId, "service_advisor");
|
||||
|
||||
// 如果没有员工,直接返回空列表
|
||||
if (advisors == null || advisors.isEmpty()) {
|
||||
return resp;
|
||||
}
|
||||
|
||||
// 对每个服务顾问进行统计
|
||||
for (cn.iocoder.yudao.module.system.api.user.dto.UserDTO advisor : advisors) {
|
||||
Long userId = advisor.getId();
|
||||
if (userId == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Object> respMap = new HashMap<>();
|
||||
respMap.put("name", advisor.getNickname());
|
||||
respMap.put("id", userId);
|
||||
|
||||
// 构造与workTypeStatistics相同格式的数据
|
||||
Map<String, Object> dataMap = new HashMap<>();
|
||||
List<Map<String, Object>> statsList = new ArrayList<>();
|
||||
|
||||
// 初始化统计数据
|
||||
// Integer ticketCount = 0;
|
||||
// Integer workingCount = 0;
|
||||
// Integer completedCount = 0;
|
||||
BigDecimal totalAmount = BigDecimal.ZERO;
|
||||
BigDecimal grossProfit = BigDecimal.ZERO;
|
||||
|
||||
// 1. 查询该服务顾问的工单统计数据(接单量、维修中、已竣工)
|
||||
// List<Long> userIds = Collections.singletonList(userId);
|
||||
// List<Map<String, Object>> workerStats = statisticsMapper.selectWorkerStatisticsByUserIds(userIds, startDate, endDate);
|
||||
//
|
||||
// if (workerStats != null && !workerStats.isEmpty()) {
|
||||
// Map<String, Object> workerStat = workerStats.get(0);
|
||||
// ticketCount = workerStat.get("ticketCount") instanceof Number ? ((Number) workerStat.get("ticketCount")).intValue() : 0;
|
||||
// workingCount = workerStat.get("workingCount") instanceof Number ? ((Number) workerStat.get("workingCount")).intValue() : 0;
|
||||
// completedCount = workerStat.get("completedCount") instanceof Number ? ((Number) workerStat.get("completedCount")).intValue() : 0;
|
||||
// }
|
||||
|
||||
// 2. 使用selectAdvisorStatistics方法统计产值和毛利润
|
||||
Map<String, Object> statistics = statisticsMapper.selectAdvisorStatistics(userId, startDate, endDate);
|
||||
|
||||
if (statistics != null) {
|
||||
// 获取产值(总金额)
|
||||
totalAmount = statistics.get("totalOutput") instanceof Number ?
|
||||
new BigDecimal(statistics.get("totalOutput").toString()) : BigDecimal.ZERO;
|
||||
// 获取毛利(配件毛利)
|
||||
grossProfit = statistics.get("totalProfit") instanceof Number ?
|
||||
new BigDecimal(statistics.get("totalProfit").toString()) : BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
// 添加产值统计
|
||||
Map<String, Object> amountNode = new HashMap<>();
|
||||
amountNode.put("code", "totalAmount");
|
||||
amountNode.put("name", "产值");
|
||||
amountNode.put("selectType", "chanzhi");
|
||||
amountNode.put("total", totalAmount);
|
||||
statsList.add(amountNode);
|
||||
respMap.put("amount", totalAmount);
|
||||
respMap.put("count", totalAmount);
|
||||
|
||||
// 添加毛利润统计
|
||||
Map<String, Object> profitNode = new HashMap<>();
|
||||
profitNode.put("code", "grossProfit");
|
||||
profitNode.put("name", "毛利润");
|
||||
profitNode.put("selectType", "maolirun");
|
||||
profitNode.put("total", grossProfit);
|
||||
statsList.add(profitNode);
|
||||
respMap.put("profit", grossProfit);
|
||||
|
||||
dataMap.put("stats", statsList);
|
||||
respMap.put("data", dataMap);
|
||||
|
||||
resp.add(respMap);
|
||||
} catch (Exception e) {
|
||||
// 记录异常但不中断整个流程
|
||||
log.warn("获取服务顾问统计信息时发生异常,员工ID: {}", userId, e);
|
||||
// 添加一个默认的统计对象,避免前端出现空值
|
||||
Map<String, Object> defaultStats = new HashMap<>();
|
||||
defaultStats.put("name", advisor.getNickname());
|
||||
defaultStats.put("id", userId);
|
||||
resp.add(defaultStats);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("查询服务顾问列表时发生异常", e);
|
||||
return resp;
|
||||
}
|
||||
} else if ("zj".equals(workType)) {
|
||||
try {
|
||||
// 获取当前租户ID
|
||||
Long tenantId = cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder.getRequiredTenantId();
|
||||
// 查询角色为 general_inspection(总检)的员工列表
|
||||
List<cn.iocoder.yudao.module.system.api.user.dto.UserDTO> advisors =
|
||||
roleApi.selectUserListByRoleCode(tenantId, "general_inspection");
|
||||
if (advisors == null || advisors.isEmpty()) {
|
||||
return resp;
|
||||
}
|
||||
|
||||
// 查询记录表(根据时间筛选)
|
||||
List<RepairRecords> rescueRefuelRecords = repairRecordsService.list(
|
||||
new LambdaQueryWrapper<RepairRecords>()
|
||||
.in(RepairRecords::getType, RecordTypeEnum.NFPG.getCode(), RecordTypeEnum.ZJ.getCode())
|
||||
.between(StringUtils.isNotEmpty(startDate), RepairRecords::getCreateTime, startDate, endDate)
|
||||
);
|
||||
|
||||
// 按员工ID分组(注意 null-safe)
|
||||
Map<Long, List<RepairRecords>> recordsByUserId = (rescueRefuelRecords == null)
|
||||
? Collections.emptyMap()
|
||||
: rescueRefuelRecords.stream().filter(Objects::nonNull)
|
||||
.collect(Collectors.groupingBy(RepairRecords::getDealUserId));
|
||||
|
||||
// 遍历每个总检员工并组装返回值
|
||||
for (UserDTO advisor : advisors) {
|
||||
Long userId = advisor.getId();
|
||||
if (userId == null) {
|
||||
// 跳过没有 id 的记录
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Object> respMap = new HashMap<>();
|
||||
respMap.put("name", advisor.getNickname());
|
||||
respMap.put("id", userId);
|
||||
|
||||
Map<String, Object> dataMap = new HashMap<>();
|
||||
List<Map<String, Object>> statsList = new ArrayList<>();
|
||||
|
||||
// 取出该员工对应的记录列表(可能为 null)
|
||||
List<RepairRecords> repairRecords = recordsByUserId.get(userId);
|
||||
if (repairRecords == null) {
|
||||
repairRecords = Collections.emptyList();
|
||||
}
|
||||
|
||||
// 统计总检类型记录数(ZJ)
|
||||
long zjCount = repairRecords.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.filter(record -> RecordTypeEnum.ZJ.getCode().equals(record.getType()))
|
||||
.count();
|
||||
|
||||
// 统计内排返工类型记录数(NFPG)
|
||||
long nfpgCount = repairRecords.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.filter(record -> RecordTypeEnum.NFPG.getCode().equals(record.getType()))
|
||||
.count();
|
||||
|
||||
// 如果还需要统计金额等,可以在这里聚合,例如:
|
||||
// BigDecimal totalAmount = repairRecords.stream()
|
||||
// .map(RepairRecords::getAmount)
|
||||
// .filter(Objects::nonNull)
|
||||
// .reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
|
||||
// 封装 ZJ 统计节点
|
||||
Map<String, Object> zjNode = new HashMap<>();
|
||||
zjNode.put("code", "zjCount");
|
||||
zjNode.put("name", "总检次数");
|
||||
zjNode.put("selectType", "zj");
|
||||
zjNode.put("total", zjCount);
|
||||
statsList.add(zjNode);
|
||||
|
||||
// 封装 NFPG 统计节点
|
||||
Map<String, Object> nfpgNode = new HashMap<>();
|
||||
nfpgNode.put("code", "nfpgCount");
|
||||
nfpgNode.put("name", "内排返工次数");
|
||||
nfpgNode.put("selectType", "nfpg");
|
||||
nfpgNode.put("total", nfpgCount);
|
||||
statsList.add(nfpgNode);
|
||||
|
||||
// 可选:把合计次数放在 resp 顶层,前端如果需要也能直接取
|
||||
respMap.put("count", zjCount);
|
||||
|
||||
// 可选:如果有金额、产值等,也可以放到 respMap(示例注释)
|
||||
// respMap.put("amount", totalAmount);
|
||||
|
||||
dataMap.put("stats", statsList);
|
||||
respMap.put("data", dataMap);
|
||||
|
||||
resp.add(respMap);
|
||||
} catch (Exception e) {
|
||||
// 记录异常但不中断整个流程
|
||||
log.warn("获取总检统计信息时发生异常,员工ID: {}", userId, e);
|
||||
Map<String, Object> defaultStats = new HashMap<>();
|
||||
defaultStats.put("name", advisor.getNickname());
|
||||
defaultStats.put("id", userId);
|
||||
resp.add(defaultStats);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("查询总检列表或记录时发生异常", e);
|
||||
return resp;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 原有逻辑:根据workType查询该工种下的所有员工
|
||||
List<RepairWorkerRespVO> workers = workerService.listByWorkType(workType);
|
||||
|
||||
// 如果没有员工,直接返回空列表
|
||||
@ -762,6 +969,7 @@ public class RepairStatisticsServiceImpl implements RepairStatisticsService {
|
||||
resp.add(defaultStats);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 排序:根据 count 字段降序
|
||||
resp.sort((a, b) -> {
|
||||
@ -771,9 +979,13 @@ public class RepairStatisticsServiceImpl implements RepairStatisticsService {
|
||||
if (countA == null) return 1;
|
||||
if (countB == null) return -1;
|
||||
|
||||
int valA = Integer.parseInt(countA.toString());
|
||||
int valB = Integer.parseInt(countB.toString());
|
||||
return Integer.compare(valB, valA); // 降序
|
||||
// 处理BigDecimal和其他类型
|
||||
BigDecimal valA = (countA instanceof BigDecimal) ? (BigDecimal) countA :
|
||||
(countA instanceof Number) ? new BigDecimal(countA.toString()) : BigDecimal.ZERO;
|
||||
BigDecimal valB = (countB instanceof BigDecimal) ? (BigDecimal) countB :
|
||||
(countB instanceof Number) ? new BigDecimal(countB.toString()) : BigDecimal.ZERO;
|
||||
|
||||
return valB.compareTo(valA); // 降序
|
||||
});
|
||||
return resp;
|
||||
}
|
||||
|
||||
@ -687,4 +687,20 @@
|
||||
GROUP BY drw.user_id, drw.user_name
|
||||
ORDER BY ticketCount DESC
|
||||
</select>
|
||||
|
||||
<!-- 查询指定服务顾问的统计数据(产值和毛利) -->
|
||||
<select id="selectAdvisorStatistics" resultType="java.util.Map">
|
||||
SELECT
|
||||
SUM(drt.total_price) AS totalOutput, -- 工单总金额(产值)
|
||||
-- 直接使用表中已有的item_profit字段计算总毛利
|
||||
SUM(COALESCE((SELECT SUM(dri.item_profit)
|
||||
FROM dl_repair_titem dri
|
||||
WHERE dri.ticket_id = drt.id AND dri.deleted = 0), 0)) AS totalProfit -- 总毛利
|
||||
FROM dl_repair_tickets drt
|
||||
WHERE drt.deleted = 0
|
||||
AND drt.adviser_id = #{advisorId}
|
||||
<if test="startDate != null and endDate != null">
|
||||
AND drt.create_time BETWEEN CONCAT(#{startDate}, ' 00:00:00') AND CONCAT(#{endDate}, ' 23:59:59')
|
||||
</if>
|
||||
</select>
|
||||
</mapper>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user