增加pc端显示售后纠纷处理

This commit is contained in:
cb 2025-09-05 14:45:02 +08:00
parent a64f1728ac
commit c55ac047c0
6 changed files with 392 additions and 4 deletions

View File

@ -0,0 +1,60 @@
package com.ghy.web.controller.order;
import java.math.BigDecimal;
/**
* 售后纠纷处理请求
*
* @author system
* @date 2024-12-19
*/
public class AfterServiceDisputeRequest {
/**
* 售后记录ID
*/
private String recordId;
/**
* 主单ID
*/
private Long orderMasterId;
/**
* 退款金额
*/
private BigDecimal refundAmount;
public String getRecordId() {
return recordId;
}
public void setRecordId(String recordId) {
this.recordId = recordId;
}
public Long getOrderMasterId() {
return orderMasterId;
}
public void setOrderMasterId(Long orderMasterId) {
this.orderMasterId = orderMasterId;
}
public BigDecimal getRefundAmount() {
return refundAmount;
}
public void setRefundAmount(BigDecimal refundAmount) {
this.refundAmount = refundAmount;
}
@Override
public String toString() {
return "AfterServiceDisputeRequest{" +
"recordId='" + recordId + '\'' +
", orderMasterId=" + orderMasterId +
", refundAmount=" + refundAmount +
'}';
}
}

View File

@ -22,6 +22,7 @@ import com.ghy.order.request.SysOrderAssignRequest;
import com.ghy.order.request.SysOrderGoodsStandards; import com.ghy.order.request.SysOrderGoodsStandards;
import com.ghy.order.request.TransferOrderRequest; import com.ghy.order.request.TransferOrderRequest;
import com.ghy.order.service.*; import com.ghy.order.service.*;
import com.ghy.web.controller.order.AfterServiceDisputeRequest;
import com.ghy.payment.domain.FinancialChangeRecord; import com.ghy.payment.domain.FinancialChangeRecord;
import com.ghy.payment.domain.FinancialDetail; import com.ghy.payment.domain.FinancialDetail;
import com.ghy.payment.domain.FinancialMaster; import com.ghy.payment.domain.FinancialMaster;
@ -1430,6 +1431,157 @@ public class OrderMasterController extends BaseController {
return AjaxResult.success(orderMasterService.countOrderMasterList(orderMaster)); return AjaxResult.success(orderMasterService.countOrderMasterList(orderMaster));
} }
@PostMapping("/after/dispute/count")
@ResponseBody
public AjaxResult countAfterDisputeList(@RequestBody OrderMaster orderMaster) {
// 查所有售后纠纷的单
AfterServiceRecord afterServiceRecord = new AfterServiceRecord();
afterServiceRecord.setExcludeAfterServiceFinished(Boolean.TRUE);
// 只查询售后纠纷的记录客户不同意的记录
afterServiceRecord.setCustomerFinalCheck(0L); // 客户不同意
List<AfterServiceRecord> afterServiceRecordList = afterServiceRecordService.selectAfterServiceRecordList(afterServiceRecord);
// 踢重后的子单ids
List<Long> detailIds = afterServiceRecordList.stream().map(AfterServiceRecord::getOrderDetailId).distinct().collect(Collectors.toList());
StringBuilder orderDetailIds = new StringBuilder();
OrderDetail orderDetail = new OrderDetail();
orderDetail.setCustomerId(orderMaster.getCustomerId());
orderDetail.setDeptId(orderMaster.getDeptId());
detailIds.forEach(id -> {
orderDetailIds.append(id).append(",");
});
String ids = orderDetailIds.toString();
if (StringUtils.isNotEmpty(ids)) {
orderDetail.setOrderDetailIds(ids.substring(0, ids.length() - 1));
} else {
orderDetail.setOrderDetailIds("0");
}
// 所有售后纠纷的子单
List<OrderDetail> orderDetailList = orderDetailService.selectOrderDetailList(orderDetail);
StringBuilder orderMasterIds = new StringBuilder();
orderDetailList.stream().map(OrderDetail::getOrderMasterId).distinct()
.collect(Collectors.toList()).forEach(id -> {
orderMasterIds.append(id).append(",");
});
String orderIds = orderMasterIds.toString();
if (StringUtils.isNotEmpty(orderIds)) {
orderMaster.setOrderMasterIds(orderIds.substring(0, orderIds.length() - 1));
} else {
orderMaster.setOrderMasterIds("0");
}
return AjaxResult.success(orderMasterService.countOrderMasterList(orderMaster));
}
@PostMapping("/after/records/byMasterId")
@ResponseBody
public AjaxResult getAfterServiceRecordsByMasterId(@RequestBody OrderMaster orderMaster) {
try {
logger.info("查询主单[{}]的售后纠纷记录", orderMaster.getId());
// 查询主单下的所有子单
OrderDetail orderDetail = new OrderDetail();
orderDetail.setOrderMasterId(orderMaster.getId());
List<OrderDetail> orderDetailList = orderDetailService.selectOrderDetailList(orderDetail);
if (orderDetailList.isEmpty()) {
logger.info("主单[{}]没有子单", orderMaster.getId());
return AjaxResult.success(new ArrayList<>());
}
// 获取所有子单ID
List<Long> orderDetailIds = orderDetailList.stream()
.map(OrderDetail::getId)
.collect(Collectors.toList());
logger.info("主单[{}]的子单IDs: {}", orderMaster.getId(), orderDetailIds);
// 使用IN查询一次性获取所有售后纠纷记录
AfterServiceRecord queryRecord = new AfterServiceRecord();
queryRecord.setCustomerFinalCheck(0L); // 客户不同意
queryRecord.setExcludeAfterServiceFinished(Boolean.TRUE); // 排除已完成的售后
// 构建子单ID的IN查询条件
StringBuilder orderDetailIdsStr = new StringBuilder();
for (int i = 0; i < orderDetailIds.size(); i++) {
if (i > 0) {
orderDetailIdsStr.append(",");
}
orderDetailIdsStr.append(orderDetailIds.get(i));
}
// 设置子单ID列表用于IN查询
queryRecord.setOrderDetailIds(orderDetailIdsStr.toString());
List<AfterServiceRecord> disputeRecords = afterServiceRecordService.selectAfterServiceRecordList(queryRecord);
logger.info("主单[{}]的子单IDs: {},找到{}条售后纠纷记录", orderMaster.getId(), orderDetailIds, disputeRecords.size());
// 为每个售后记录添加子单信息
Map<Long, OrderDetail> orderDetailMap = orderDetailList.stream()
.collect(Collectors.toMap(OrderDetail::getId, detail -> detail));
disputeRecords.forEach(record -> {
OrderDetail detail = orderDetailMap.get(record.getOrderDetailId());
if (detail != null) {
record.setOrderDetailCode(detail.getCode());
logger.info("售后记录[{}]属于子单[{}]", record.getId(), detail.getCode());
} else {
logger.warn("售后记录[{}]的子单ID[{}]在子单列表中未找到", record.getId(), record.getOrderDetailId());
}
});
logger.info("主单[{}]总共找到{}条售后纠纷记录", orderMaster.getId(), disputeRecords.size());
return AjaxResult.success(disputeRecords);
} catch (Exception e) {
logger.error("查询主单[{}]售后纠纷记录异常", orderMaster.getId(), e);
return AjaxResult.error("查询售后纠纷记录失败:" + e.getMessage());
}
}
@PostMapping("/after/dispute/handle")
@ResponseBody
public AjaxResult handleAfterServiceDispute(@RequestBody AfterServiceDisputeRequest request) {
try {
logger.info("处理售后纠纷退款记录ID{},退款金额:{}", request.getRecordId(), request.getRefundAmount());
// 查询售后记录
AfterServiceRecord record = afterServiceRecordService.selectAfterServiceRecordById(request.getRecordId());
if (record == null) {
return AjaxResult.error("售后记录不存在");
}
// 验证是否为售后纠纷客户不同意
if (record.getCustomerFinalCheck() == null || !record.getCustomerFinalCheck().equals(0L)) {
return AjaxResult.error("该记录不是售后纠纷,无法处理");
}
// 设置退款金额
record.setRefund(request.getRefundAmount());
record.setAgreedRefund(request.getRefundAmount());
record.setRefundApplyTime(new Date());
// 更新售后记录
afterServiceRecordService.updateAfterServiceRecord(record);
// 执行退款逻辑
try {
afterServiceRecordService.executeRefundLogic(record);
logger.info("售后纠纷退款处理成功记录ID{},退款金额:{}", request.getRecordId(), request.getRefundAmount());
return AjaxResult.success("退款处理成功");
} catch (Exception e) {
logger.error("售后纠纷退款执行失败记录ID{},错误:{}", request.getRecordId(), e.getMessage());
return AjaxResult.error("退款执行失败:" + e.getMessage());
}
} catch (Exception e) {
logger.error("处理售后纠纷异常记录ID{}", request.getRecordId(), e);
return AjaxResult.error("处理售后纠纷失败:" + e.getMessage());
}
}
@PostMapping("/app/detail") @PostMapping("/app/detail")
@ResponseBody @ResponseBody
public AjaxResult appDetail(@RequestBody OrderMaster request) { public AjaxResult appDetail(@RequestBody OrderMaster request) {
@ -1802,6 +1954,12 @@ public class OrderMasterController extends BaseController {
if(StringUtils.isNotEmpty(orderMaster.getOrderStatusName())){ if(StringUtils.isNotEmpty(orderMaster.getOrderStatusName())){
master.setOrderStatusName(orderMaster.getOrderStatusName()); master.setOrderStatusName(orderMaster.getOrderStatusName());
} }
// 如果数据库中的afterServiceStatus为null则设置为0无售后
if (master.getAfterServiceStatus() == null) {
master.setAfterServiceStatus(0);
}
FinancialMaster fm = financialMasterMap.get(master.getId()); FinancialMaster fm = financialMasterMap.get(master.getId());
if (fm != null) { if (fm != null) {
master.setFinancialMasterMoney(fm.getPayMoney()); master.setFinancialMasterMoney(fm.getPayMoney());

View File

@ -165,7 +165,7 @@
</a> </a>
<a class="btn btn-default btn-outline" onclick="selectConditionBtn(this, {orderStatusName : '售后纠纷', orderStatus: -1})"> <a class="btn btn-default btn-outline" onclick="selectConditionBtn(this, {orderStatusName : '售后纠纷', orderStatus: -1})">
售后纠纷 售后纠纷
(<span>0</span>) (<span id="afterServiceDisputeNum">0</span>)
</a> </a>
</div> </div>
<div class="flex-board"> <div class="flex-board">
@ -573,6 +573,22 @@
} }
} }
}) })
<!-- 售后纠纷订单数量统计-->
$.ajax({
type: "POST",
dataType:"json",
url: prefix + '/after/dispute/count',
contentType: 'application/json',
data: JSON.stringify({}),
success: function (result) {
if (result.code == web_status.SUCCESS) {
$('#afterServiceDisputeNum').text(result.data);
} else {
$.modal.msgError("售后纠纷数据加载错误,请重试!")
}
}
})
}); });
function changeOrderMode(orderMode) { function changeOrderMode(orderMode) {
@ -757,6 +773,10 @@
} else { } else {
actions.push('<a class="btn btn-success btn-xs " href="javascript:void(0)" onclick="pcOrderInsurance(\'' + row.id + '\')"></i>选择保险</a> '); actions.push('<a class="btn btn-success btn-xs " href="javascript:void(0)" onclick="pcOrderInsurance(\'' + row.id + '\')"></i>选择保险</a> ');
} }
// 售后纠纷处理按钮
if (row.afterServiceStatus == 1) {
actions.push('<a class="btn btn-warning btn-xs" href="javascript:void(0)" onclick="handleAfterServiceDispute(\'' + row.id + '\')"><i class="fa fa-gavel"></i>售后纠纷处理</a> ');
}
return actions.join(''); return actions.join('');
} }
}, },
@ -1212,6 +1232,148 @@
// 设置定时器,每隔一分钟执行一次 fetchData 函数 // 设置定时器,每隔一分钟执行一次 fetchData 函数
setInterval(fetchData, 60000); setInterval(fetchData, 60000);
// 售后纠纷处理弹窗
function handleAfterServiceDispute(orderMasterId) {
// 查询该主单的售后记录
$.ajax({
type: "POST",
dataType: "json",
url: prefix + '/after/records/byMasterId',
contentType: 'application/json',
data: JSON.stringify({id: orderMasterId}),
success: function (result) {
if (result.code == web_status.SUCCESS) {
showAfterServiceDisputeModal(orderMasterId, result.data);
} else {
$.modal.msgError("查询售后记录失败:" + result.msg);
}
},
error: function() {
$.modal.msgError("查询售后记录失败,请重试!");
}
});
}
// 显示售后纠纷处理弹窗
function showAfterServiceDisputeModal(orderMasterId, afterServiceRecords) {
var html = '<div class="modal fade" id="afterServiceDisputeModal" tabindex="-1" role="dialog">';
html += '<div class="modal-dialog modal-lg" role="document">';
html += '<div class="modal-content">';
html += '<div class="modal-header">';
html += '<h4 class="modal-title">售后纠纷处理</h4>';
html += '<button type="button" class="close" data-dismiss="modal">&times;</button>';
html += '</div>';
html += '<div class="modal-body">';
if (afterServiceRecords && afterServiceRecords.length > 0) {
html += '<div class="table-responsive">';
html += '<table class="table table-bordered table-striped">';
html += '<thead><tr><th>子单号</th><th>售后类型</th><th>申请原因</th><th>申请金额</th><th>师傅反馈</th><th>客户确认</th><th>操作</th></tr></thead>';
html += '<tbody>';
afterServiceRecords.forEach(function(record) {
html += '<tr>';
html += '<td>' + (record.orderDetailCode || '') + '</td>';
html += '<td>' + getAfterServiceTypeText(record.afterServiceType) + '</td>';
html += '<td>' + (record.customerReason || '') + '</td>';
html += '<td>¥' + (record.refund || 0) + '</td>';
html += '<td>' + getWorkerFeedbackText(record.workerFeedbackResult) + '</td>';
html += '<td>' + getCustomerCheckText(record.customerFinalCheck) + '</td>';
html += '<td>';
html += '<div class="input-group" style="width: 200px;">';
html += '<input type="number" class="form-control" id="refundAmount_' + record.id + '" placeholder="退款金额" value="' + (record.refund || 0) + '" min="0" step="0.01">';
html += '<div class="input-group-append">';
html += '<button class="btn btn-primary btn-sm" onclick="processRefund(\'' + record.id + '\', \'' + orderMasterId + '\')">处理退款</button>';
html += '</div></div>';
html += '</td>';
html += '</tr>';
});
html += '</tbody></table></div>';
} else {
html += '<div class="alert alert-info">该订单暂无售后纠纷记录</div>';
}
html += '</div>';
html += '<div class="modal-footer">';
html += '<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>';
html += '</div>';
html += '</div></div></div>';
// 移除已存在的弹窗
$('#afterServiceDisputeModal').remove();
// 添加弹窗到页面
$('body').append(html);
// 显示弹窗
$('#afterServiceDisputeModal').modal('show');
}
// 处理退款
function processRefund(recordId, orderMasterId) {
var refundAmount = $('#refundAmount_' + recordId).val();
if (!refundAmount || refundAmount <= 0) {
$.modal.msgError("请输入有效的退款金额");
return;
}
$.modal.confirm("确认处理退款 ¥" + refundAmount + " 吗?", function() {
$.ajax({
type: "POST",
dataType: "json",
url: prefix + '/after/dispute/handle',
contentType: 'application/json',
data: JSON.stringify({
recordId: recordId,
orderMasterId: orderMasterId,
refundAmount: parseFloat(refundAmount)
}),
success: function (result) {
if (result.code == web_status.SUCCESS) {
$.modal.msgSuccess("退款处理成功");
$('#afterServiceDisputeModal').modal('hide');
// 刷新页面数据
$.table.refresh();
} else {
$.modal.msgError("退款处理失败:" + result.msg);
}
},
error: function() {
$.modal.msgError("退款处理失败,请重试!");
}
});
});
}
// 获取售后类型文本
function getAfterServiceTypeText(type) {
var types = {
1: '未收到货退单退款',
2: '未收到货退款',
3: '已收到货退款退货'
};
return types[type] || '未知';
}
// 获取师傅反馈文本
function getWorkerFeedbackText(result) {
var results = {
0: '拒绝',
1: '同意',
2: '上门补做/重做',
3: '重做/补做完成'
};
return results[result] || '未处理';
}
// 获取客户确认文本
function getCustomerCheckText(check) {
if (check === 1) return '同意';
if (check === 0) return '不同意';
return '未确认';
}
</script> </script>
</body> </body>
<script id="importTpl" type="text/template"> <script id="importTpl" type="text/template">

View File

@ -173,6 +173,12 @@ public class AfterServiceRecord extends BaseEntity
@Excel(name = "客户不同意理由") @Excel(name = "客户不同意理由")
private String customerDisagreeReason; private String customerDisagreeReason;
/** 子单号(用于显示,非数据库字段) */
private String orderDetailCode;
/** 子单ID列表用于IN查询非数据库字段 */
private String orderDetailIds;
private boolean excludeAfterServiceFinished; private boolean excludeAfterServiceFinished;
private List<AfterServiceImgs> imgsList; private List<AfterServiceImgs> imgsList;

View File

@ -67,6 +67,7 @@
<if test="customerReasonType != null "> and customer_reason_type = #{customerReasonType}</if> <if test="customerReasonType != null "> and customer_reason_type = #{customerReasonType}</if>
<if test="customerReason != null and customerReason != ''"> and customer_reason = #{customerReason}</if> <if test="customerReason != null and customerReason != ''"> and customer_reason = #{customerReason}</if>
<if test="orderDetailId != null "> and order_detail_id = #{orderDetailId}</if> <if test="orderDetailId != null "> and order_detail_id = #{orderDetailId}</if>
<if test="orderDetailIds != null and orderDetailIds != ''"> and order_detail_id in (${orderDetailIds})</if>
<if test="operType != null "> and oper_type = #{operType}</if> <if test="operType != null "> and oper_type = #{operType}</if>
<if test="workerFeedbackResult != null "> and worker_feedback_result = #{workerFeedbackResult}</if> <if test="workerFeedbackResult != null "> and worker_feedback_result = #{workerFeedbackResult}</if>
<if test="workerFeedbackReasonType != null "> and worker_feedback_reason_type = #{workerFeedbackReasonType}</if> <if test="workerFeedbackReasonType != null "> and worker_feedback_reason_type = #{workerFeedbackReasonType}</if>

View File

@ -136,8 +136,8 @@
return_reason, return_reason,
return_reason_detail, return_reason_detail,
return_images, return_images,
worker_remark worker_remark,
after_service_status
FROM order_master FROM order_master
</sql> </sql>
<sql id="selectOrderMasterMoreInfo"> <sql id="selectOrderMasterMoreInfo">
@ -203,7 +203,8 @@
om.return_reason, om.return_reason,
om.return_reason_detail, om.return_reason_detail,
om.return_images, om.return_images,
om.worker_remark om.worker_remark,
om.after_service_status
FROM order_master om FROM order_master om
LEFT JOIN customer_address ca ON ca.customer_address_id = om.address_id LEFT JOIN customer_address ca ON ca.customer_address_id = om.address_id
LEFT JOIN goods g ON g.goods_id = om.goods_id LEFT JOIN goods g ON g.goods_id = om.goods_id