提交 cbbec597 authored 作者: 马路路's avatar 马路路

Merge branch '33.6_app_carrier_messsage_20241106' into dev_jdk17

......@@ -292,6 +292,9 @@ public class OrderChildServiceImpl implements OrderChildService {
@Autowired
FeignOrderService feignOrderService;
@Autowired
private SendInternalMessageService sendInternalMessageService;
@PostConstruct
public void init(){
String[] activeProfiles = environment.getActiveProfiles();
......@@ -3513,6 +3516,20 @@ public class OrderChildServiceImpl implements OrderChildService {
log.info("{}超出货源地x公里范围了,运单{}为到达货源地状态,发送短信", truckNo, childNo);
sendLoadSms(child.getDriverMobile(), child.getTruckNo(), child.getChildNo());
redisTemplate.opsForValue().increment(RedisConstants.NOTICE_MESSAGE_LIMIT_UNLOAD + childNo);
// 司机触发驶离货源地配置距离 APP站内信
sendInternalMessageService.sendInternalMessageMq(
// APP
InternalMessageTemplateEnum.PlatformType.DRIVER_APP.getCode(),
// 业务类型
InternalMessageTemplateEnum.BusinessType.APP_SECOND_CLASSIFICATION.getCode(),
// 司机触发卸货预警规则-超出货源地x公里范围
InternalMessageTemplateEnum.DRIVER_TRIGGER_LEAVE_SOURCE_LOCAL_DISTANCE,
// 发送内容参数
null,
// URL路径参数,运单号、isShowMsg==true
List.of(childNo, true),
child.getDriverUserNo());
}
// 已装货
if (Objects.equals(child.getStatus(), OrderChildEnum.Status.LOAD.getCode())) {
......@@ -3785,6 +3802,8 @@ public class OrderChildServiceImpl implements OrderChildService {
canCancelOrderChildList.forEach(orderChild-> orderChildPostService.orderChildCancelByCarrier(orderChild,
UserTypeEnum.CARRIER.getCode(), loginUserInfo.getUserNo(), loginUserInfo.getUserName()));
// 批量取消运单发送站内信
this.sendAppCarrierMessage(canCancelOrderChildList, param.getRemark());
UpdateCarrierBatchCancelVO result = new UpdateCarrierBatchCancelVO();
result.setFailChildNoList(notCancelOrderChildList.stream().map(OrderChild :: getChildNo).collect(Collectors.toList()));
......@@ -3792,6 +3811,27 @@ public class OrderChildServiceImpl implements OrderChildService {
return result;
}
/**
* 批量取消运单发送站内信通知
*/
private void sendAppCarrierMessage(List<OrderChild> canCancelOrderChildList, String remark) {
for (OrderChild child : canCancelOrderChildList) {
// 司机触发驶离货源地配置距离 APP站内信
sendInternalMessageService.sendInternalMessageMq(
// APP
InternalMessageTemplateEnum.PlatformType.DRIVER_APP.getCode(),
// 业务类型
InternalMessageTemplateEnum.BusinessType.APP_SECOND_CLASSIFICATION.getCode(),
// 运单列表-填写取消原因-确认,触发消息通知
InternalMessageTemplateEnum.CONFIRM_CANCEL_REASON_CODE,
// 发送内容参数
List.of(remark),
// URL参数-运单号、true
List.of(child.getChildNo(), true),
child.getDriverUserNo());
}
}
private void batchUpdateOrderGoodsWeightReturn(List<OrderChild> canCancelOrderChildList) {
//按照货单分组,每个货单下取消的运单个数map
......
......@@ -188,6 +188,20 @@ public class BreakContractDriverRecordServiceImpl implements BreakContractDrive
sendInternalMessageService.sendInternalMessageMq(InternalMessageTemplateEnum.PlatformType.CARRIER.getCode(),
InternalMessageTemplateEnum.BusinessType.WAIT_APPROVED_ITEM.getCode(),
InternalMessageTemplateEnum.CUSTOM_DRIVER_TRIGGER_BREAK_CONTRACT_CODE, List.of(record.getBreakNo()),null,null);
// 司机违约通知APP站内信
sendInternalMessageService.sendInternalMessageMq(
// APP
InternalMessageTemplateEnum.PlatformType.DRIVER_APP.getCode(),
// 业务类型
InternalMessageTemplateEnum.BusinessType.APP_SECOND_CLASSIFICATION.getCode(),
// 司机违约规则配置-司机取消
InternalMessageTemplateEnum.DRIVER_CANCEL_ORDER_CODE,
// 运单编号、接单时间小于X小时、收费X元
List.of(orderChild.getChildNo(), breakContractDriverRuleVO.getDriverCancelRule().getBaseTime(),
breakContractDriverRuleVO.getDriverCancelRule().getBaseFigure()),
null,
orderChild.getDriverUserNo());
}
@Override
......@@ -235,6 +249,19 @@ public class BreakContractDriverRecordServiceImpl implements BreakContractDrive
InternalMessageTemplateEnum.BusinessType.WAIT_APPROVED_ITEM.getCode(),
InternalMessageTemplateEnum.CUSTOM_DRIVER_TRIGGER_BREAK_CONTRACT_CODE, List.of(record.getBreakNo()),null,null);
// 司机违约通知APP站内信
sendInternalMessageService.sendInternalMessageMq(
// APP
InternalMessageTemplateEnum.PlatformType.DRIVER_APP.getCode(),
// 业务类型
InternalMessageTemplateEnum.BusinessType.APP_SECOND_CLASSIFICATION.getCode(),
// 未按约定时间到达货源地
InternalMessageTemplateEnum.DRIVER_ARRIVE_SOURCE_LOCAL_TIMEOUT_CODE,
// 运单编号、收费X元
List.of(orderChild.getChildNo(), breakContractDriverRuleVO.getDriverCancelRule().getBaseFigure()),
null,
orderChild.getDriverUserNo());
}
@Override
......@@ -278,6 +305,19 @@ public class BreakContractDriverRecordServiceImpl implements BreakContractDrive
sendInternalMessageService.sendInternalMessageMq(InternalMessageTemplateEnum.PlatformType.CARRIER.getCode(),
InternalMessageTemplateEnum.BusinessType.WAIT_APPROVED_ITEM.getCode(),
InternalMessageTemplateEnum.CUSTOM_DRIVER_TRIGGER_BREAK_CONTRACT_CODE, List.of(record.getBreakNo()),null,null);
// 司机违约通知APP站内信
sendInternalMessageService.sendInternalMessageMq(
// APP
InternalMessageTemplateEnum.PlatformType.DRIVER_APP.getCode(),
// 业务类型
InternalMessageTemplateEnum.BusinessType.APP_SECOND_CLASSIFICATION.getCode(),
// 未按约定时间到达目的地(到达目的地超时)
InternalMessageTemplateEnum.DRIVER_ARRIVE_DESTINATION_TIMEOUT_CODE,
// 运单编号、收费X元
List.of(orderChild.getChildNo(), breakContractDriverRuleVO.getDriverCancelRule().getBaseFigure()),
null,
orderChild.getDriverUserNo());
}
@Override
......
......@@ -2,12 +2,14 @@ package com.clx.performance.service.impl.vehiclewarn;
import com.clx.performance.dao.vehiclewarn.VehicleWarnConfigDao;
import com.clx.performance.dao.vehiclewarn.VehicleWarnInfoDao;
import com.clx.performance.enums.InternalMessageTemplateEnum;
import com.clx.performance.enums.vehiclewarn.VehicleWarnConfigEnum;
import com.clx.performance.enums.vehiclewarn.VehicleWarnInfoEnum;
import com.clx.performance.model.OrderChild;
import com.clx.performance.model.vehiclewarn.VehicleWarnChild;
import com.clx.performance.model.vehiclewarn.VehicleWarnConfig;
import com.clx.performance.model.vehiclewarn.VehicleWarnInfo;
import com.clx.performance.service.SendInternalMessageService;
import com.clx.performance.service.vehiclewarn.VehicleWarnCommonService;
import com.clx.performance.service.vehiclewarn.VehicleWarnLoadAndUnloadWarnService;
import lombok.extern.slf4j.Slf4j;
......@@ -31,6 +33,8 @@ public class VehicleWarnLoadAndUnloadWarnServiceImpl implements VehicleWarnLoadA
private VehicleWarnInfoDao vehicleWarnInfoDao;
@Autowired
private VehicleWarnCommonService vehicleWarnCommonService;
@Autowired
private SendInternalMessageService sendInternalMessageService;
/**
* 装车超时
......@@ -69,6 +73,19 @@ public class VehicleWarnLoadAndUnloadWarnServiceImpl implements VehicleWarnLoadA
// 更新
vehicleWarnCommonService.vehicleWarnInfoUpdate(orderChild, vehicleWarnInfo, vehicleWarnConfig);
// 司机触发运单预警规则,系统通知给司机,APP站内信
sendInternalMessageService.sendInternalMessageMq(
// APP
InternalMessageTemplateEnum.PlatformType.DRIVER_APP.getCode(),
// 业务类型
InternalMessageTemplateEnum.BusinessType.APP_SECOND_CLASSIFICATION.getCode(),
// 司机触发运单预警规则-装车超时
InternalMessageTemplateEnum.DRIVER_TRIGGER_UPLOAD_TIMEOUT,
// 运单编号、前往目的地超时时间
List.of(orderChild.getChildNo(), time),
null,
orderChild.getDriverUserNo());
}
/**
......@@ -107,6 +124,20 @@ public class VehicleWarnLoadAndUnloadWarnServiceImpl implements VehicleWarnLoadA
// 更新
vehicleWarnCommonService.vehicleWarnInfoUpdate(orderChild, vehicleWarnInfo, vehicleWarnConfig);
// 司机触发运单预警规则,系统通知给司机,APP站内信
sendInternalMessageService.sendInternalMessageMq(
// APP
InternalMessageTemplateEnum.PlatformType.DRIVER_APP.getCode(),
// 业务类型
InternalMessageTemplateEnum.BusinessType.APP_SECOND_CLASSIFICATION.getCode(),
// 司机触发运单预警规则-卸车超时
InternalMessageTemplateEnum.DRIVER_TRIGGER_DOWNLOAD_TIMEOUT,
// 运单编号、前往目的地超时时间
List.of(orderChild.getChildNo(), time),
null,
orderChild.getDriverUserNo());
}
}
......@@ -3,6 +3,7 @@ package com.clx.performance.service.impl.vehiclewarn;
import com.clx.performance.dao.vehiclewarn.VehicleWarnConfigDao;
import com.clx.performance.dao.vehiclewarn.VehicleWarnInfoDao;
import com.clx.performance.dto.vehiclewarn.VehicleWarnCommonInfoDTO;
import com.clx.performance.enums.InternalMessageTemplateEnum;
import com.clx.performance.enums.OrderChildEnum;
import com.clx.performance.enums.vehiclewarn.VehicleWarnConfigEnum;
import com.clx.performance.enums.vehiclewarn.VehicleWarnInfoEnum;
......@@ -10,6 +11,7 @@ import com.clx.performance.model.OrderChild;
import com.clx.performance.model.vehiclewarn.VehicleWarnChild;
import com.clx.performance.model.vehiclewarn.VehicleWarnConfig;
import com.clx.performance.model.vehiclewarn.VehicleWarnInfo;
import com.clx.performance.service.SendInternalMessageService;
import com.clx.performance.service.trace.TruckTraceService;
import com.clx.performance.service.vehiclewarn.VehicleWarnCommonService;
import com.clx.performance.service.vehiclewarn.VehicleWarnParkWarnService;
......@@ -39,6 +41,9 @@ public class VehicleWarnParkWarnServiceImpl implements VehicleWarnParkWarnServic
@Autowired
private VehicleWarnCommonService vehicleWarnCommonService;
@Autowired
private SendInternalMessageService sendInternalMessageService;
/**
* 停留超时
*/
......@@ -87,6 +92,19 @@ public class VehicleWarnParkWarnServiceImpl implements VehicleWarnParkWarnServic
// 更新
vehicleWarnCommonService.vehicleWarnInfoUpdate(orderChild, vehicleWarnInfo, vehicleWarnConfig);
// 司机触发运单预警规则,系统通知给司机,APP站内信
sendInternalMessageService.sendInternalMessageMq(
// APP
InternalMessageTemplateEnum.PlatformType.DRIVER_APP.getCode(),
// 业务类型
InternalMessageTemplateEnum.BusinessType.APP_SECOND_CLASSIFICATION.getCode(),
// 司机触发运单预警规则-停留超时
InternalMessageTemplateEnum.DRIVER_TRIGGER_STAY_TIMEOUT,
// 运单编号、停留时间
List.of(orderChild.getChildNo(), parkTime),
null,
orderChild.getDriverUserNo());
}
@Override
......
......@@ -3,6 +3,7 @@ package com.clx.performance.service.impl.vehiclewarn;
import com.clx.performance.dao.vehiclewarn.VehicleWarnConfigDao;
import com.clx.performance.dao.vehiclewarn.VehicleWarnInfoDao;
import com.clx.performance.dto.vehiclewarn.VehicleWarnCommonInfoDTO;
import com.clx.performance.enums.InternalMessageTemplateEnum;
import com.clx.performance.enums.OrderChildEnum;
import com.clx.performance.enums.vehiclewarn.VehicleWarnConfigEnum;
import com.clx.performance.enums.vehiclewarn.VehicleWarnInfoEnum;
......@@ -10,6 +11,7 @@ import com.clx.performance.model.OrderChild;
import com.clx.performance.model.vehiclewarn.VehicleWarnChild;
import com.clx.performance.model.vehiclewarn.VehicleWarnConfig;
import com.clx.performance.model.vehiclewarn.VehicleWarnInfo;
import com.clx.performance.service.SendInternalMessageService;
import com.clx.performance.service.vehiclewarn.VehicleWarnCommonService;
import com.clx.performance.service.vehiclewarn.VehicleWarnReceiveAddressWarnService;
import lombok.extern.slf4j.Slf4j;
......@@ -34,6 +36,8 @@ public class VehicleWarnReceiveAddressWarnServiceImpl implements VehicleWarnRece
private VehicleWarnInfoDao vehicleWarnInfoDao;
@Autowired
private VehicleWarnCommonService vehicleWarnCommonService;
@Autowired
private SendInternalMessageService sendInternalMessageService;
/**
* 前往目的地超时
......@@ -89,6 +93,19 @@ public class VehicleWarnReceiveAddressWarnServiceImpl implements VehicleWarnRece
// 更新
vehicleWarnCommonService.vehicleWarnInfoUpdate(orderChild, vehicleWarnInfo, vehicleWarnConfig);
// 司机触发运单预警规则,系统通知给司机,APP站内信
sendInternalMessageService.sendInternalMessageMq(
// APP
InternalMessageTemplateEnum.PlatformType.DRIVER_APP.getCode(),
// 业务类型
InternalMessageTemplateEnum.BusinessType.APP_SECOND_CLASSIFICATION.getCode(),
// 司机触发运单预警规则-前往目的地超时
InternalMessageTemplateEnum.DRIVER_TRIGGER_GO_DESTINATION_TIMEOUT,
// 运单编号、前往目的地超时时间
List.of(orderChild.getChildNo(), needTime),
null,
orderChild.getDriverUserNo());
}
/**
......@@ -137,6 +154,19 @@ public class VehicleWarnReceiveAddressWarnServiceImpl implements VehicleWarnRece
// 更新
vehicleWarnCommonService.vehicleWarnInfoUpdate(orderChild, vehicleWarnInfo, vehicleWarnConfig);
// 司机触发运单预警规则,系统通知给司机,APP站内信
sendInternalMessageService.sendInternalMessageMq(
// APP
InternalMessageTemplateEnum.PlatformType.DRIVER_APP.getCode(),
// 业务类型
InternalMessageTemplateEnum.BusinessType.APP_SECOND_CLASSIFICATION.getCode(),
// 司机触发运单预警规则-到达目的地超时
InternalMessageTemplateEnum.DRIVER_TRIGGER_ARRIVE_DESTINATION_DELAY,
// 运单编号、前往目的地超时时间
List.of(orderChild.getChildNo()),
null,
orderChild.getDriverUserNo());
}
}
......@@ -3,12 +3,14 @@ package com.clx.performance.service.impl.vehiclewarn;
import com.clx.performance.dao.vehiclewarn.VehicleWarnConfigDao;
import com.clx.performance.dao.vehiclewarn.VehicleWarnInfoDao;
import com.clx.performance.dto.vehiclewarn.VehicleWarnCommonInfoDTO;
import com.clx.performance.enums.InternalMessageTemplateEnum;
import com.clx.performance.enums.vehiclewarn.VehicleWarnConfigEnum;
import com.clx.performance.enums.vehiclewarn.VehicleWarnInfoEnum;
import com.clx.performance.model.OrderChild;
import com.clx.performance.model.vehiclewarn.VehicleWarnChild;
import com.clx.performance.model.vehiclewarn.VehicleWarnConfig;
import com.clx.performance.model.vehiclewarn.VehicleWarnInfo;
import com.clx.performance.service.SendInternalMessageService;
import com.clx.performance.service.vehiclewarn.VehicleWarnCommonService;
import com.clx.performance.service.vehiclewarn.VehicleWarnSendAddressWarnService;
import lombok.extern.slf4j.Slf4j;
......@@ -32,6 +34,8 @@ public class VehicleWarnSendAddressWarnServiceImpl implements VehicleWarnSendAdd
private VehicleWarnInfoDao vehicleWarnInfoDao;
@Autowired
private VehicleWarnCommonService vehicleWarnCommonService;
@Autowired
private SendInternalMessageService sendInternalMessageService;
/**
* 前往货源地超时
......@@ -80,6 +84,19 @@ public class VehicleWarnSendAddressWarnServiceImpl implements VehicleWarnSendAdd
// 更新
vehicleWarnCommonService.vehicleWarnInfoUpdate(orderChild, vehicleWarnInfo, vehicleWarnConfig);
// 司机触发运单预警规则,系统通知给司机,APP站内信
sendInternalMessageService.sendInternalMessageMq(
// APP
InternalMessageTemplateEnum.PlatformType.DRIVER_APP.getCode(),
// 业务类型
InternalMessageTemplateEnum.BusinessType.APP_SECOND_CLASSIFICATION.getCode(),
// 司机触发运单预警规则-前往货源地超时
InternalMessageTemplateEnum.DRIVER_TRIGGER_GO_SOURCE_LOCAL_TIMEOUT,
// 运单编号、货源地超时时间
List.of(orderChild.getChildNo(), needTime),
null,
orderChild.getDriverUserNo());
}
/**
......@@ -125,6 +142,19 @@ public class VehicleWarnSendAddressWarnServiceImpl implements VehicleWarnSendAdd
// 更新
vehicleWarnCommonService.vehicleWarnInfoUpdate(orderChild, vehicleWarnInfo, vehicleWarnConfig);
// 司机触发运单预警规则,系统通知给司机,到达货源地延误
sendInternalMessageService.sendInternalMessageMq(
// APP
InternalMessageTemplateEnum.PlatformType.DRIVER_APP.getCode(),
// 业务类型
InternalMessageTemplateEnum.BusinessType.APP_SECOND_CLASSIFICATION.getCode(),
// 司机触发运单预警规则-到达货源地超时
InternalMessageTemplateEnum.DRIVER_ARRIVE_SOURCE_LOCAL_DELAY_CODE,
// 运单编号
List.of(orderChild.getChildNo()),
null,
orderChild.getDriverUserNo());
}
}
......@@ -170,6 +170,10 @@ public class InternalMessageTemplateEnum {
public static final Integer DRIVER_ARRIVE_SOURCE_LOCAL_TIMEOUT_CODE = 10826;
// 触发成本中心-司机违约规则配置)未按约定时间到达目的地
public static final Integer DRIVER_ARRIVE_DESTINATION_TIMEOUT_CODE = 10827;
// 配置中心-监控预警配置-运单预警配置后 规则的触发 到达货源地延误
public static final Integer DRIVER_ARRIVE_SOURCE_LOCAL_DELAY_CODE = 10828;
// 配置中心-司机通知配置-司机触发驶离货源地配置距离
public static final Integer DRIVER_TRIGGER_LEAVE_SOURCE_LOCAL_DISTANCE = 10829;
......@@ -338,6 +342,10 @@ public class InternalMessageTemplateEnum {
APP_SECOND_CLASSIFICATION_MAP.put(DRIVER_ARRIVE_SOURCE_LOCAL_TIMEOUT_CODE, BusinessTypeDetail.DRIVER_ARRIVE_SOURCE_LOCAL_TIMEOUT_CODE.getCode());
// 触发成本中心-司机违约规则配置- 未按约定时间到达目的地
APP_SECOND_CLASSIFICATION_MAP.put(DRIVER_ARRIVE_DESTINATION_TIMEOUT_CODE, BusinessTypeDetail.DRIVER_ARRIVE_DESTINATION_TIMEOUT_CODE.getCode());
// 配置中心-监控预警配置-运单预警配置后 规则的触发 到达货源地延误
APP_SECOND_CLASSIFICATION_MAP.put(DRIVER_ARRIVE_SOURCE_LOCAL_DELAY_CODE, BusinessTypeDetail.DRIVER_ARRIVE_SOURCE_LOCAL_DELAY_CODE.getCode());
// 配置中心-司机通知配置-司机触发驶离货源地配置距离
APP_SECOND_CLASSIFICATION_MAP.put(DRIVER_TRIGGER_LEAVE_SOURCE_LOCAL_DISTANCE, BusinessTypeDetail.DRIVER_TRIGGER_LEAVE_SOURCE_LOCAL_DISTANCE.getCode());
businessTypeMap.put(BusinessType.CHILD_WARN.getCode(),CHILD_WARN_MAP);
......@@ -595,10 +603,10 @@ public class InternalMessageTemplateEnum {
VEHICLE_CERTIFICATION_EXPIRE_REMIND("VEHICLE_CERTIFICATION_EXPIRE_REMIND", "证件过期提醒","您的车辆认证即将过期,请重新上传~","/page/CarListPage",""),
// 司机驾驶证即将过期
DRIVER_CERTIFICATE_EXPIRE_REMIND("DRIVER_CERTIFICATE_EXPIRE_REMIND", "证件即将过期提醒","您的驾驶证即将过期,请前往重新上传~",
"/waybill/WaybillFillGoodsInfoPage","{ \"type\": %s, \"childNo\": %s, \"orderGoodsNo\": %s, \"freightPrice\": %s}"),
"/page/DrivingLicensePage","{\"isUpload\": %s}"),
// 司机从业资格证即将过期的消息通知
DRIVER_CERTIFICATE_EXPIRE_REMIND_DRIVER("DRIVER_CERTIFICATE_EXPIRE_REMIND_DRIVER", "证件即将过期提醒","您的从业资格证即将过期,请前往重新上传~",
"/page/DrivingLicensePage","{\"status\": %s}"),
"/page/DrivingLicensePage","{\"isUpload\": %s}"),
// 身份证即将过期
ID_CARD_JUST_EXPIRE_REMIND("ID_CARD_JUST_EXPIRE_REMIND","证件即将过期提醒", "您的身份证即将过期,请尽快上传~", "/page/LicenseInfoPage",""),
// 车辆资质即将过期
......@@ -637,7 +645,10 @@ public class InternalMessageTemplateEnum {
DRIVER_ARRIVE_SOURCE_LOCAL_TIMEOUT_CODE("DRIVER_ARRIVE_SOURCE_LOCAL_TIMEOUT_CODE", "违约通知", "您的【%s】,未按约定时间到达货源地,平台扣款【%s】元~", "/main/wallet/MyWallet", ""),
// 触发成本中心-司机违约规则配置- 未按约定时间到达目的地
DRIVER_ARRIVE_DESTINATION_TIMEOUT_CODE("DRIVER_ARRIVE_DESTINATION_TIMEOUT_CODE", "违约通知", "您的【%s】,未按约定时间到达目的地,平台扣款【%s】元~", "/main/wallet/MyWallet", ""),
// 配置中心-监控预警配置-运单预警配置后 规则的触发 到达货源地延误
DRIVER_ARRIVE_SOURCE_LOCAL_DELAY_CODE("DRIVER_ARRIVE_SOURCE_LOCAL_DELAY_CODE", "", "您的【%s】,到达货源地延误~", "/page/main/MainPage", ""),
// 配置中心-司机通知配置-开启司机触发驶离货源地配置距离
DRIVER_TRIGGER_LEAVE_SOURCE_LOCAL_DISTANCE("DRIVER_TRIGGER_LEAVE_SOURCE_LOCAL_DISTANCE", "请驶向货源地", "您已驶离货源地未装车,请及时返回,确保正常拉运~", "/waybill/WaybillDetailPage", "{\"childNo\": %s, \"isShowMsg\": %s}"),
;
private final String code;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论