xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/controller/XpOperationsUserNotificationController.java
@@ -11,6 +11,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.List; /** * <p> * 运维人员消息通知表 前端控制器 @@ -70,4 +72,11 @@ notificationService.lambdaUpdate().set(XpOperationsUserNotification::getReadStatus, 1).eq(XpOperationsUserNotification::getId, notificationId).update(); return R.ok(); } @PostMapping(value = "/inner/v1/notification/addBatch") @ApiOperation(value = "批量添加通知", tags = {"内部接口"}) public R<?> addNotificationBatch(@RequestBody List<XpOperationsUserNotification> notifications) { notificationService.addNotificationBatch(notifications); return R.ok(); } } xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/IXpOperationsUserNotificationService.java
@@ -5,6 +5,8 @@ import com.xiaopeng.api.model.account.XpOperationsUserNotification; import com.xiaopeng.common.core.web.page.PageInfo; import java.util.List; /** * <p> * 运维人员消息通知表 服务类 @@ -23,4 +25,10 @@ PageInfo<XpOperationsUserNotification> selectNotificationPageByUserId( XpOperationsUserNotificationPageQuery query ); /** * 批量添加通知 * @param notifications */ void addNotificationBatch(List<XpOperationsUserNotification> notifications); } xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/impl/XpOperationsUserNotificationServiceImpl.java
@@ -7,7 +7,12 @@ import com.xiaopeng.account.service.IXpOperationsUserNotificationService; import com.xiaopeng.api.model.account.XpOperationsUserNotification; import com.xiaopeng.common.core.web.page.PageInfo; import org.apache.shardingsphere.transaction.annotation.ShardingSphereTransactionType; import org.apache.shardingsphere.transaction.core.TransactionType; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; /** * <p> @@ -43,4 +48,10 @@ return pageInfo; } @Override @Transactional(rollbackFor = Exception.class) @ShardingSphereTransactionType(TransactionType.BASE) public void addNotificationBatch(List<XpOperationsUserNotification> notifications) { saveBatch(notifications); } } xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/pushMessage/AliPushMessageDTO.java
@@ -2,11 +2,14 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Builder; import lombok.Data; import lombok.experimental.Accessors; import java.io.Serializable; @Data @Builder @Accessors(chain = true) @ApiModel(value = "ali推送消息AliPushMessageDTO") public class AliPushMessageDTO implements Serializable { xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/account/XpOperationUserNotificationClientFallbackFactory.java
New file @@ -0,0 +1,27 @@ package com.xiaopeng.api.factory.account; import com.xiaopeng.api.dto.account.XpOperationsUserQueryDTO; import com.xiaopeng.api.feignClient.account.XpOperationUserClient; import com.xiaopeng.api.feignClient.account.XpOperationUserNotificationClient; import com.xiaopeng.api.model.account.XpOperationsRole; import com.xiaopeng.api.model.account.XpOperationsUser; import com.xiaopeng.api.vo.account.XpOperationsUserWithRoleVO; import com.xiaopeng.common.core.domain.R; import lombok.extern.slf4j.Slf4j; import org.springframework.cloud.openfeign.FallbackFactory; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; @Slf4j @Component public class XpOperationUserNotificationClientFallbackFactory implements FallbackFactory<XpOperationUserNotificationClient> { @Override public XpOperationUserNotificationClient create(Throwable cause) { return new XpOperationUserNotificationClient() { }; } } xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/account/XpOperationUserNotificationClient.java
New file @@ -0,0 +1,37 @@ package com.xiaopeng.api.feignClient.account; import com.xiaopeng.api.dto.account.XpOperationsUserQueryDTO; import com.xiaopeng.api.factory.account.XpAppUserClientFallbackFactory; import com.xiaopeng.api.factory.account.XpOperationUserNotificationClientFallbackFactory; import com.xiaopeng.api.model.account.XpOperationsRole; import com.xiaopeng.api.model.account.XpOperationsUser; import com.xiaopeng.api.model.account.XpOperationsUserNotification; import com.xiaopeng.api.vo.account.XpOperationsUserWithRoleVO; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.dto.ServiceNameConstantsEnum; import io.swagger.annotations.ApiOperation; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import java.util.List; /** * 小程序用户Feign客户端 * * @author mitao */ @FeignClient(contextId = "XpOperationUserNotificationClient", value = ServiceNameConstantsEnum.XP_ACCOUNT_SERVICE, fallbackFactory = XpOperationUserNotificationClientFallbackFactory.class) public interface XpOperationUserNotificationClient { /** * 批量添加运维用户 * @param notifications * @return */ @PostMapping(value = "/inner/v1/notification/addBatch") public R<?> addNotificationBatch(@RequestBody List<XpOperationsUserNotification> notifications); } xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpTaskRule.java
@@ -4,9 +4,11 @@ import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import java.time.LocalDateTime; import java.io.Serializable; import java.time.LocalDateTime; import java.time.LocalTime; import com.fasterxml.jackson.annotation.JsonFormat; import com.xiaopeng.common.core.web.domain.BaseModel; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -42,7 +44,8 @@ private Integer vehicleInspectionFrequency; @ApiModelProperty(value = "车辆日常检测 任务下放时间") private LocalDateTime vehicleInspectionTime; @JsonFormat(pattern = "HH:mm:ss", timezone = "GMT+8") private LocalTime vehicleInspectionTime; @ApiModelProperty(value = "车辆日常监测 紧急程度 0=P0 1=P1 2=P2 3=P3") private Integer vehicleInspectionLevel; @@ -51,7 +54,8 @@ private Boolean vehicleCollection; @ApiModelProperty(value = "车辆收车每日时间") private LocalDateTime vehicleCollectionTime; @JsonFormat(pattern = "HH:mm:ss", timezone = "GMT+8") private LocalTime vehicleCollectionTime; @ApiModelProperty(value = "车辆保养周期是否启用") private Boolean maintenanceCycle; @@ -63,7 +67,8 @@ private Integer maintenanceCycleTimeType; @ApiModelProperty(value = "车辆保养周期 任务下放时间") private LocalDateTime maintenanceCycleTaskTime; @JsonFormat(pattern = "HH:mm:ss", timezone = "GMT+8") private LocalTime maintenanceCycleTaskTime; @ApiModelProperty(value = "车辆保养周期 紧急程度 0=P0 1=P1 2=P2 3=P3") private Integer maintenanceCycleLevel; @@ -78,7 +83,11 @@ private Integer chargingStrategyLevel; @ApiModelProperty(value = "车身清洁保养周期X") private Integer vehicleCleanTime; private Integer vehicleCleanCycle; @ApiModelProperty(value = "车身清洁保养任务下放时间") @JsonFormat(pattern = "HH:mm:ss", timezone = "GMT+8") private LocalTime vehicleCleanTime; @ApiModelProperty(value = "车身清洁保养周期X 1=天 2=月") private Integer vehicleCleanTimeType; @@ -87,7 +96,11 @@ private Integer vehicleCleanLevel; @ApiModelProperty(value = "日常整备保养周期X") private Integer routineMaintenanceTime; private Integer routineMaintenanceCycle; @ApiModelProperty(value = "日常整备保养任务下放时间") @JsonFormat(pattern = "HH:mm:ss", timezone = "GMT+8") private LocalTime routineMaintenanceTime; @ApiModelProperty(value = "日常整备保养周期X 1=天 2=月") private Integer routineMaintenanceTimeType; xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/constant/AliPushTypeConstant.java
New file @@ -0,0 +1,18 @@ package com.xiaopeng.common.core.constant; /** * @author MiTao * @date 2026-02-27 18:03 * */ public interface AliPushTypeConstant { /** * 表示通知 */ String NOTICE = "NOTICE"; /** * 表示消息 */ String MESSAGE = "MESSAGE"; } xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/enums/NotificationTypeEnum.java
New file @@ -0,0 +1,48 @@ package com.xiaopeng.common.core.enums; import lombok.AllArgsConstructor; import lombok.Getter; /** * 通知类型枚举 * 1=新增事故,2=事故即将超时提示,3=事故超时提示,4=排班信息变动,5=事故状态变更, * 6=新增任务,7=任务过期提示,8=版本更新提示,9=变更协议政策内容, * 10=变更协议内容并需用户授权,11=打卡成功通知,12=强制更新 */ @Getter @AllArgsConstructor public enum NotificationTypeEnum { ACCIDENT_NEW(1, "新增事故"), ACCIDENT_WILL_TIMEOUT(2, "事故即将超时提示"), ACCIDENT_TIMEOUT(3, "事故超时提示"), SCHEDULE_CHANGED(4, "排班信息变动"), ACCIDENT_STATUS_CHANGED(5, "事故状态变更"), TASK_NEW(6, "新增任务"), TASK_EXPIRED(7, "任务过期提示"), VERSION_UPDATE_TIP(8, "版本更新提示"), POLICY_CONTENT_CHANGED(9, "变更协议政策内容"), AGREEMENT_CHANGED_NEED_AUTH(10, "变更协议内容并需用户授权"), CLOCK_IN_SUCCESS(11, "打卡成功通知"), FORCE_UPDATE(12, "强制更新"); private final Integer code; private final String desc; public static NotificationTypeEnum getEnumByCode(Integer code) { if (code == null) { return null; } for (NotificationTypeEnum e : NotificationTypeEnum.values()) { if (e.code.equals(code)) { return e; } } return null; } public static String getEnumDescByCode(Integer code) { NotificationTypeEnum e = getEnumByCode(code); return e == null ? "" : e.getDesc(); } } xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/enums/TaskTypeNotificationEnum.java
New file @@ -0,0 +1,37 @@ package com.xiaopeng.common.core.enums; import lombok.AllArgsConstructor; import lombok.Getter; @Getter @AllArgsConstructor public enum TaskTypeNotificationEnum { VEHICLE_INSPECTION(1, "车辆检测"), VEHICLE_CHARGING(2, "车辆充电"), VEHICLE_PREPARATION(3, "车辆整备"), VEHICLE_WASH(4, "整备洗车"), VEHICLE_REPAIR(5, "车辆维修"), OTHER_ROUTINE_TASK(6, "其他常规任务"), ACCIDENT_TASK(7, "事故任务"); private final Integer code; private final String desc; public static TaskTypeNotificationEnum getEnumByCode(Integer code) { if (code == null) { return null; } for (TaskTypeNotificationEnum e : TaskTypeNotificationEnum.values()) { if (e.code.equals(code)) { return e; } } return null; } public static String getEnumDescByCode(Integer code) { TaskTypeNotificationEnum e = getEnumByCode(code); return e == null ? "" : e.getDesc(); } } xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/constant/I18nKeyConstant.java
@@ -11,4 +11,5 @@ String VEHICLE_NOT_EXIST = "vehicle.not.exist"; String TASK_RULE_NOT_CONFIG = "task.rule.not.config"; } xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/dto/TaskRuleDetailDto.java
@@ -1,5 +1,6 @@ package com.xiaopeng.maintenance.dto; import com.fasterxml.jackson.annotation.JsonFormat; import com.xiaopeng.api.model.maintenance.XpTaskRuleRole; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -7,7 +8,8 @@ import java.io.Serializable; import java.math.BigDecimal; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.LocalTime; import java.util.List; @Data @@ -21,7 +23,8 @@ @ApiModelProperty(value = "车辆日常监测 频次") private Integer vehicleInspectionFrequency; @ApiModelProperty(value = "车辆日常检测 任务下放时间") private LocalDateTime vehicleInspectionTime; @JsonFormat(pattern = "HH:mm:ss", timezone = "GMT+8") private LocalTime vehicleInspectionTime; @ApiModelProperty(value = "车辆日常监测 紧急程度 0=P0 1=P1 2=P2 3=P3") private Integer vehicleInspectionLevel; @@ -30,7 +33,8 @@ private Boolean vehicleCollection; @ApiModelProperty(value = "车辆收车每日时间") private LocalDateTime vehicleCollectionTime; @JsonFormat(pattern = "HH:mm:ss", timezone = "GMT+8") private LocalTime vehicleCollectionTime; @ApiModelProperty(value = "车辆保养周期是否启用") private Boolean maintenanceCycle; @@ -42,7 +46,8 @@ private Integer maintenanceCycleTimeType; @ApiModelProperty(value = "车辆保养周期 任务下放时间") private LocalDateTime maintenanceCycleTaskTime; @JsonFormat(pattern = "HH:mm:ss", timezone = "GMT+8") private LocalTime maintenanceCycleTaskTime; @ApiModelProperty(value = "车辆保养周期 紧急程度 0=P0 1=P1 2=P2 3=P3") private Integer maintenanceCycleLevel; @@ -57,7 +62,11 @@ private Integer chargingStrategyLevel; @ApiModelProperty(value = "车身清洁保养周期X") private Integer vehicleCleanTime; private Integer vehicleCleanCycle; @ApiModelProperty(value = "车身清洁保养任务下放时间") @JsonFormat(pattern = "HH:mm:ss", timezone = "GMT+8") private LocalTime vehicleCleanTime; @ApiModelProperty(value = "车身清洁保养周期X 1=天 2=月") private Integer vehicleCleanTimeType; @@ -66,7 +75,11 @@ private Integer vehicleCleanLevel; @ApiModelProperty(value = "日常整备保养周期X") private Integer routineMaintenanceTime; private Integer routineMaintenanceCycle; @ApiModelProperty(value = "日常整备保养任务下放时间") @JsonFormat(pattern = "HH:mm:ss", timezone = "GMT+8") private LocalTime routineMaintenanceTime; @ApiModelProperty(value = "日常整备保养周期X 1=天 2=月") private Integer routineMaintenanceTimeType; xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpTaskServiceImpl.java
@@ -1,17 +1,27 @@ package com.xiaopeng.maintenance.service.impl; import cn.hutool.core.collection.CollUtil; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.xiaopeng.api.dto.pushMessage.AliPushMessageDTO; import com.xiaopeng.api.feignClient.account.SysUserClient; import com.xiaopeng.api.feignClient.account.XpOperationUserClient; import com.xiaopeng.api.feignClient.account.XpOperationUserNotificationClient; import com.xiaopeng.api.feignClient.pushMessage.XpAliPushMessageClient; import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; import com.xiaopeng.api.model.account.SysUser; import com.xiaopeng.api.model.account.XpOperationsRole; import com.xiaopeng.api.model.account.XpOperationsUser; import com.xiaopeng.api.model.account.XpOperationsUserNotification; import com.xiaopeng.api.model.maintenance.*; import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; import com.xiaopeng.common.core.constant.AliPushTypeConstant; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.enums.NotificationTypeEnum; import com.xiaopeng.common.core.enums.TaskTypeEnum; import com.xiaopeng.common.core.enums.TaskTypeNotificationEnum; import com.xiaopeng.common.core.exception.ServiceException; import com.xiaopeng.common.core.web.page.PageInfo; import com.xiaopeng.maintenance.constant.I18nKeyConstant; @@ -25,6 +35,8 @@ import com.xiaopeng.maintenance.model.query.WorkBenchQuery; import com.xiaopeng.maintenance.model.query.XpTaskRecordPageQuery; import com.xiaopeng.maintenance.model.vo.*; import com.xiaopeng.maintenance.service.IXpTaskRuleRoleService; import com.xiaopeng.maintenance.service.IXpTaskRuleService; import com.xiaopeng.maintenance.service.XpTaskService; import com.xiaopeng.maintenance.utils.UUIDUtil; import org.apache.commons.lang3.StringUtils; @@ -57,22 +69,6 @@ private RedissonClient redissonClient; @Autowired private XpErrorTypeMapper errorTypeMapper; /** * 常规任务类型映射 */ private static final Map<String, String> TASK_TYPE_MAP = new java.util.HashMap<>(); static { TASK_TYPE_MAP.put("1", "车辆检查"); TASK_TYPE_MAP.put("2", "车辆充电"); TASK_TYPE_MAP.put("3", "车辆整备"); TASK_TYPE_MAP.put("4", "整备洗车"); TASK_TYPE_MAP.put("5", "车辆维修"); TASK_TYPE_MAP.put("6", "车辆保养"); TASK_TYPE_MAP.put("7", "车辆保险到期"); TASK_TYPE_MAP.put("8", "车辆年检到期"); TASK_TYPE_MAP.put("9", "车辆运营资质到期"); } @Autowired private XpTaskHandleDetailMapper xpTaskHandleDetailMapper; @@ -98,6 +94,14 @@ private XpVehicleClient xpVehicleClient; @Autowired private XpTaskRuleMapper xpTaskRuleMapper; @Autowired private XpAliPushMessageClient xpAliPushMessageClient; @Autowired private XpOperationUserNotificationClient xpOperationUserNotificationClient; @Autowired private IXpTaskRuleRoleService xpTaskRuleRoleService; @Autowired private IXpTaskRuleService xpTaskRuleService; @Override public PageInfo<WorkBenchVO> workbench(WorkBenchQuery query) { @@ -162,14 +166,74 @@ xpTask.setTaskDescription(dto.getTaskDescription()); // todo 获取车辆当前位置 // xpTask.setVehicleLocation(); // xpTask.setVehicleId(); xpTask.setVehicleId(dto.getId()); // xpTask.setVehicleLon(); // xpTask.setVehicleLat(); xpTask.setReportUserId(xpOperationsUser.getId()); xpTask.setReportTime(LocalDateTime.now()); xpTask.setStatus(0); xpTask.setCreateBy(xpOperationsUser.getNickName()); XpTaskRule taskRule = xpTaskRuleService.lambdaQuery().last("limit 1").one(); XpTaskRuleRole taskRuleRole = xpTaskRuleRoleService.lambdaQuery().eq(XpTaskRuleRole::getRuleType, 9).last("limit 1").one(); if (Objects.isNull(taskRuleRole) || Objects.isNull(taskRule)) { throw new ServiceException("未配置车辆事故任务分配规则", I18nKeyConstant.TASK_RULE_NOT_CONFIG); } R<List<XpOperationsRole>> xpOperationsRoleResult = xpOperationUserClient.getXpOperationsRoleByRoleId(taskRuleRole.getRoleId()); if (CollUtil.isNotEmpty(xpOperationsRoleResult.getData())) { List<Long> userIds = xpOperationsRoleResult.getData().stream().map(XpOperationsRole::getOperationsUserId).collect(Collectors.toList()); xpTask.setHandleUserId(StringUtils.join(userIds, ",")); } this.save(xpTask); //发送消息通知 List<Long> userIds = Arrays.stream(xpTask.getHandleUserId().split(",")).map(Long::valueOf).collect(Collectors.toList()); if (CollUtil.isNotEmpty(userIds)) { R<List<XpOperationsUser>> xpOperationUserResult = xpOperationUserClient.listByIds(userIds); List<XpOperationsUser> data = xpOperationUserResult.getData(); if (CollUtil.isNotEmpty(data)) { R<XpVehicle> xpVehicleR = xpVehicleClient.queryById(dto.getId()); XpVehicle vehicle = xpVehicleR.getData(); String plateNumber = Objects.nonNull(vehicle) ? vehicle.getPlateNumber() : ""; // 车辆${车牌号}在${车辆位置信息}发生了紧急事故,请在${到达现场限时}内到达现场!${APP链接} String content = String.format("车辆%s在%s发生了紧急事故,请在%d分钟内到达现场!", plateNumber, xpTask.getVehicleLocation(), taskRule.getProcessingTimeLimit()); List<XpOperationsUserNotification> notifications = data.stream().map(item -> { XpOperationsUserNotification notification = new XpOperationsUserNotification(); notification.setOperationsUserId(item.getId()); notification.setNotificationContent(content); notification.setReadStatus(0); notification.setCreateTime(LocalDateTime.now()); return notification; }).collect(Collectors.toList()); xpOperationUserNotificationClient.addNotificationBatch(notifications); // 发送阿里云推送 Map<Integer, List<XpOperationsUser>> operationUserMap = data.stream().collect(Collectors.groupingBy(XpOperationsUser::getDeviceType)); for (Map.Entry<Integer, List<XpOperationsUser>> integerListEntry : operationUserMap.entrySet()) { List<XpOperationsUser> value = integerListEntry.getValue(); pushAliMessage(data, content, xpTask); } } } } /** * 推送阿里云通知 * @param data * @param content * @param xpTask */ private void pushAliMessage(List<XpOperationsUser> data, String content, XpTask xpTask) { String account = data.stream().map(XpOperationsUser::getPhoneNumber).filter(Objects::nonNull).collect(Collectors.joining(",")); Map<String, Object> param = new HashMap<>(); param.put("content", content); param.put("strategy", NotificationTypeEnum.ACCIDENT_NEW.getCode()); param.put("type", TaskTypeNotificationEnum.ACCIDENT_TASK.getCode()); param.put("id", xpTask.getId()); xpAliPushMessageClient.pushMessage(AliPushMessageDTO.builder() .body(JSONObject.toJSONString(param)) .account(account).title("车辆事故警示") .pushType(AliPushTypeConstant.NOTICE) .deviceType(data.get(0).getDeviceType()) .build()); } @Override xp-robotaxi-maintenance-boot/src/main/resources/i18n/messages.properties
@@ -2,3 +2,4 @@ welcome.message=欢迎来到我们的应用程序! task.not.exist=任务不存在 vehicle.not.exist=车辆不存在 task.rule.not.config=未配置车辆事故任务分配规则 xp-robotaxi-maintenance-boot/src/main/resources/i18n/messages_en_US.properties
@@ -2,3 +2,4 @@ welcome.message=Welcome to our application! task.not.exist=The task does not exist. vehicle.not.exist=The vehicle does not exist. task.rule.not.config=The vehicle accident task allocation rules have not been configured xp-robotaxi-maintenance-boot/src/main/resources/i18n/messages_zh_CN.properties
@@ -2,3 +2,4 @@ welcome.message=欢迎来到我们的应用程序! task.not.exist=任务不存在 vehicle.not.exist=车辆不存在 task.rule.not.config=未配置车辆事故任务分配规则