Browse Source

[feat] 销售管理 售后管理

售后通知单列表新增详情按钮
售后通知单新增详情页面
售后通知单新增加载详情页面弹窗后端接口
售后单新增根据售后单号查询售后单详情数据后端接口
dev
liuxiaoxu 7 months ago
parent
commit
633cd4e62f
  1. 2
      ruoyi-admin/src/main/java/com/ruoyi/aftersales/controller/AftersalesOrderController.java
  2. 6
      ruoyi-admin/src/main/java/com/ruoyi/aftersales/mapper/AftersalesOrderMapper.java
  3. 5
      ruoyi-admin/src/main/java/com/ruoyi/aftersales/service/IAftersalesOrderService.java
  4. 11
      ruoyi-admin/src/main/java/com/ruoyi/aftersales/service/impl/AftersalesOrderServiceImpl.java
  5. 16
      ruoyi-admin/src/main/java/com/ruoyi/sales/controller/SalesAftersalesNoticeController.java
  6. 5
      ruoyi-admin/src/main/resources/mapper/aftersales/AftersalesOrderMapper.xml
  7. 2
      ruoyi-admin/src/main/resources/templates/aftersales/aftersalesOrder/aftersalesOrder.html
  8. 13
      ruoyi-admin/src/main/resources/templates/sales/afterSalesNotice/afterSalesNotice.html
  9. 427
      ruoyi-admin/src/main/resources/templates/sales/afterSalesNotice/detail.html

2
ruoyi-admin/src/main/java/com/ruoyi/aftersales/controller/AftersalesOrderController.java

@ -141,7 +141,7 @@ public class AftersalesOrderController extends BaseController
}
/**
* 查看销售订单详情
* 查看售后单详情
*/
@GetMapping("/detail/{aftersalesOrderId}")
public String detail(@PathVariable("aftersalesOrderId") Long aftersalesOrderId, ModelMap mmap)

6
ruoyi-admin/src/main/java/com/ruoyi/aftersales/mapper/AftersalesOrderMapper.java

@ -83,4 +83,10 @@ public interface AftersalesOrderMapper
* @return 结果
*/
public int restoreAftersalesOrderById(Long aftersalesOrderId);
/**
* 根据售后单号查询售后单详情数据
* */
AftersalesOrder selectAftersalesOrderByCode(String aftersalesOrderCode);
}

5
ruoyi-admin/src/main/java/com/ruoyi/aftersales/service/IAftersalesOrderService.java

@ -93,4 +93,9 @@ public interface IAftersalesOrderService
* 修改保存售后报告
*/
int updateUploadReport(AftersalesOrder aftersalesOrder);
/**
* 根据售后单号查询售后单详情数据
* */
AftersalesOrder selectAftersalesOrderByCode(String aftersalesNoticeCode);
}

11
ruoyi-admin/src/main/java/com/ruoyi/aftersales/service/impl/AftersalesOrderServiceImpl.java

@ -313,4 +313,15 @@ public class AftersalesOrderServiceImpl implements IAftersalesOrderService
return aftersalesOrderMapper.updateAftersalesOrder(aftersalesOrder);
}
/**
* 根据售后单号查询售后单详情数据
* */
@Override
public AftersalesOrder selectAftersalesOrderByCode(String aftersalesNoticeCode) {
String aftersalesOrderCode = aftersalesNoticeCode;
AftersalesOrder aftersalesOrder = aftersalesOrderMapper.selectAftersalesOrderByCode(aftersalesOrderCode);
return aftersalesOrderMapper.selectAftersalesOrderWithAttachById(aftersalesOrder.getAftersalesOrderId());
}
}

16
ruoyi-admin/src/main/java/com/ruoyi/sales/controller/SalesAftersalesNoticeController.java

@ -3,6 +3,7 @@ package com.ruoyi.sales.controller;
import java.util.HashMap;
import java.util.List;
import com.ruoyi.aftersales.domain.AftersalesOrder;
import com.ruoyi.aftersales.service.IAftersalesOrderService;
import com.ruoyi.process.general.service.IProcessService;
import com.ruoyi.quality.domain.VO.CheckoutMaterialVO;
@ -68,6 +69,7 @@ public class SalesAftersalesNoticeController extends BaseController
@Autowired
private ISalesAftersalesNoticeDetailService noticeDetailService;
@RequiresPermissions("sales:afterSalesNotice:view")
@GetMapping()
public String afterSalesNotice()
@ -279,6 +281,20 @@ public class SalesAftersalesNoticeController extends BaseController
return toAjax(salesAftersalesNoticeService.updateSalesAftersalesNotice(salesAftersalesNotice));
}
/**
* 查看售后单详情
*/
@GetMapping("/detail/{aftersalesNoticeCode}")
public String detail(@PathVariable("aftersalesNoticeCode") String aftersalesNoticeCode, ModelMap mmap)
{
AftersalesOrder aftersalesOrder = aftersalesOrderService.selectAftersalesOrderByCode(aftersalesNoticeCode);
mmap.put("detail", aftersalesOrder);
return prefix + "/detail";
}
/**
* 删除售后通知单
*/

5
ruoyi-admin/src/main/resources/mapper/aftersales/AftersalesOrderMapper.xml

@ -110,6 +110,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where so.aftersales_order_id = #{aftersalesOrderId}
</select>
<select id="selectAftersalesOrderByCode" parameterType="String" resultMap="AftersalesOrderResult">
<include refid="selectAftersalesOrderVo"/>
where aftersales_order_code = #{aftersalesOrderCode}
</select>
<insert id="insertAftersalesOrder" parameterType="AftersalesOrder" useGeneratedKeys="true" keyProperty="aftersalesOrderId">
insert into aftersales_order
<trim prefix="(" suffix=")" suffixOverrides=",">

2
ruoyi-admin/src/main/resources/templates/aftersales/aftersalesOrder/aftersalesOrder.html

@ -204,7 +204,7 @@
// 示例逻辑:
var url = ctx + 'aftersales/aftersalesOrder/detail/'+aftersalesOrderId;
console.log(url);
$.modal.open("上传报告",url);
$.modal.open("详情",url);
}
/*派单*/

13
ruoyi-admin/src/main/resources/templates/sales/afterSalesNotice/afterSalesNotice.html

@ -251,13 +251,24 @@
actions.push('<a class="btn btn-info btn-xs" href="javascript:void(0)" onclick="showProcessImgDialog(\'' + row.instanceId + '\')"><i class="fa fa-image"></i> 进度查看</a> ');
}
// 详情
// actions.push('<a class="btn btn-success btn-xs ' + detailFlag + '" href="javascript:void(0)" onclick="detail(\'' + row.aftersalesNoticeId + '\')"><i class="fa fa-edit"></i>详情</a> ');
actions.push('<a class="btn btn-success btn-xs " href="javascript:void(0)" onclick="detail(\'' + row.aftersalesNoticeCode + '\')"><i class="fa fa-edit"></i>详情</a> ');
return actions.join('');
}
}]
};
$.table.init(options);
});
/*详情*/
function detail(aftersalesNoticeCode) {
// 在这里编写派单操作的逻辑,使用传入的aftersalesOrderId参数
// 示例逻辑:
var url = prefix + '/detail/'+aftersalesNoticeCode;
console.log(url);
$.modal.open("详情",url);
}
</script>
</body>
</html>

427
ruoyi-admin/src/main/resources/templates/sales/afterSalesNotice/detail.html

@ -0,0 +1,427 @@
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
<head>
<th:block th:include="include :: header('售后通知单详情')" />
<th:block th:include="include :: datetimepicker-css" />
<th:block th:include="include :: summernote-css" />
<th:block th:include="include :: select2-css" />
<link th:href="@{/ajax/libs/element-ui/element-ui.css}" rel="stylesheet"/>
</head>
<body class="white-bg">
<div id="app" class="wrapper wrapper-content animated fadeInRight ibox-content">
<form class="form-horizontal m" id="form-aftersalesOrder-edit" th:object="${detail}">
<input name="aftersalesOrderId" th:field="*{aftersalesOrderId}" type="hidden">
<div class="form-group">
<label class="col-sm-4 control-label">售后单号:</label>
<div class="col-sm-8">
<input name="aftersalesOrderCode" th:field="*{aftersalesOrderCode}" class="form-control" type="text">
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">销售单号:</label>
<div class="col-sm-8">
<input name="salesOrderCode" th:field="*{salesOrderCode}" class="form-control" type="text" readonly>
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">客户ID:</label>
<div class="col-sm-8">
<input name="customerId" th:field="*{customerId}" class="form-control" type="text" readonly>
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">客户名称:</label>
<div class="col-sm-8">
<input name="customerName" th:field="*{customerName}" class="form-control" type="text" readonly>
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">公司地址:</label>
<div class="col-sm-8">
<input name="companyAddress" th:field="*{companyAddress}" class="form-control" type="text" readonly>
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">收货联系人:</label>
<div class="col-sm-8">
<input name="deliveryName" th:field="*{deliveryName}" class="form-control" type="text" readonly>
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">收货电话:</label>
<div class="col-sm-8">
<input name="deliveryNumber" th:field="*{deliveryNumber}" class="form-control" type="text" readonly>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">客户要求出发日期:</label>
<div class="col-sm-8">
<div class="input-group date">
<input name="startDate" th:value="${#dates.format(detail.startDate, 'yyyy-MM-dd')}" class="form-control" placeholder="yyyy-MM-dd" type="text" disabled>
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">备注:</label>
<div class="col-sm-8">
<input name="remark" th:field="*{remark}" class="form-control" type="text" readonly>
</div>
</div>
<div class="form-row">
<div class="col-sm-12 select-table table-striped">
<h3 class="mb-4">选择设备</h3>
<table id="bootstrap-table"></table>
</div>
</div>
<div class="form-group">
<h3 class="mb-4">派单</h3>
<label class="col-sm-3 control-label">售后员:</label>
<div class="col-sm-9">
<input name="aftersalesName" th:field="*{aftersalesName}" class="form-control" type="text" readonly>
</div>
</div>
<div class="form-group">
</div>
<div class="form-group">
<h3 class="mb-4">售后报告</h3>
<!-- 服务内容 -->
<div class="form-row mb-4">
<label class="col-sm-3 control-label">服务内容:</label>
<div class="col-sm-8">
<textarea name="serviceContent" class="form-control" readonly>[[*{serviceContent}]]</textarea>
</div>
</div>
<!-- 用户评价 -->
<div class="form-row">
<label class="col-sm-4 control-label">用户评价:</label>
<div class="col-sm-8">
<el-upload
:action="fileUploadUrl"
:on-success="uploadSuccess"
:file-list="fileList"
:limit="5"
list-type="picture"
accept=".jpg,.png"
multiple
:before-remove="preventDeletion">
</el-upload>
</div>
<input id="photoAttachId" name = "photoAttachId" hidden th:field="*{photoAttachId}">
<input id="fileIdStr" type="text" name="fileIdStr" th:field="*{fileIdStr}" hidden>
</div>
</div>
</form>
</div>
<th:block th:include="include :: footer" />
<th:block th:include="include :: datetimepicker-js" />
<th:block th:include="include :: summernote-js" />
<th:block th:include="include :: select2-js" />
<script th:src="@{/ajax/libs/vue/vue.js}"></script>
<script th:src="@{/ajax/libs/element-ui/element-ui.js}"></script>
<script th:inline="javascript">
var emergencyDegreeDatas = [[${@dict.getType('aftersales_emergency_degree')}]];
var prefix = ctx + "aftersales/aftersalesOrder";
var detail = [[${detail}]];
$("#form-aftersalesOrder-edit").validate({
focusCleanup: true
});
new Vue({
el: '#app',
data: function() {
return {
fileList: [],
fileUploadUrl: ctx + "common/uploadSingleFile",
fileDeleteUrl: ctx + "common/deleteFile",
getListByAttachIdUrl: ctx + "system/attach/file/getListByAttachId",
fileIdList:[],
removeFileIdList:[],
}
},
mounted() {
// 控制下拉框选中
// var materialType = $("#materialType").val();
// $("#selectMaterialType").val(materialType).trigger("change");
var that = this;
// 页面渲染完成,可以执行需要的操作
console.log('页面已渲染完成');
console.log($("#id").val());
console.log($("#photoAttachId").val());
var attachId = $("#photoAttachId").val();
if(attachId){
$.ajax({
type: "get",
url: that.getListByAttachIdUrl,
data: {attachId:attachId},
cache: false,
async: false, // 设置成同步
dataType: 'json',
success: function(result) {
if (result.code == web_status.SUCCESS) {
result.data.forEach((item) => {
that.fileIdList.push(item.id);
that.fileList.push({name: item.name, url: item.url, attachFileId: item.id,isBind:true});
});
} else {
$.modal.msgError(result.msg);
}
},
error: function(error) {
$.modal.msgError("获取附件失败。");
}
});
}
},
methods: {
uploadSuccess(response, file, fileList) {
console.log(response);
if(response.code == web_status.SUCCESS){
var attachFileId = response.data.id;
file.attachFileId = attachFileId;
file.isBind = false;
this.fileIdList.push(attachFileId);
$("#fileIdStr").val(this.fileIdList.join(";"));
$.modal.msgSuccess("上传成功");
}else{
$.modal.alertError(response.msg);
}
},
uploadRemove(file, fileList) {
console.log(file, fileList);
var attachFileId = file.attachFileId;
var isBind = file.isBind;
if(isBind==false){
$.ajax({
type: "get",
url: this.fileDeleteUrl,
data: {id:attachFileId},
cache: false,
async: false, // 设置成同步
dataType: 'json',
success: function(result) {
if (result.code == web_status.SUCCESS) {
var index = this.fileIdList.indexOf(attachFileId);
if(index!=-1){
this.fileIdList.splice(index,1);
$("#fileIdStr").val(this.fileIdList.join(";"));
}
$.modal.msgSuccess("删除附件成功。");
} else {
$.modal.alertError(result.msg);
}
},
error: function(error) {
$.modal.alertError("删除附件失败。");
}
});
}else{
var index = this.fileIdList.indexOf(attachFileId);
if(index!=-1){
this.fileIdList.splice(index,1);
$("#fileIdStr").val(this.fileIdList.join(";"));
// 保存的时候才删除
this.removeFileIdList.push(attachFileId);
$("#removeFileIdStr").val(this.removeFileIdList.join(";"));
}
}
},
// 控制上传的图片不能删除
preventDeletion(file, fileList) {
return false; // 禁止删除图片
}
}
})
$(function() {
var options = {
url: prefix + "/optionDevices",
modalName: "出货设备",
showColumns: false,
pagination: false,
showToggle: false,
showRefresh:false,
showSearch:false,
queryParams:queryParams,
columns: [{
checkbox: true
},
{
title: '料号',
field: 'materialNo',
},
{
title: '图片',
field: 'materialPhotourl',
},
{
title: '物料名称',
field: 'materialName',
},
{
title: '物料类型',
field: 'materialType',
},
{
title: '单位',
field: 'materialUnit',
},
{
title: '品牌',
field: 'materialBrand',
},
{
title: '描述',
field: 'materialDescribe',
},
{
title: '售后数量',
field: 'shippedGoodsSum',
},
{
title: '设备SN',
field: 'snCode',
},
{
title: '售后问题',
field: 'aftersalesProblem',
},
{
title: '紧急程度',
field: 'emergencyDegree',
formatter: function(value, row, index) {
return $.table.selectDictLabel(emergencyDegreeDatas, value);
}
},
]
};
$.table.init(options);
})
function queryParams(params) {
var curParams = {
// 传递参数查询参数
makeNo: detail.makeNo
};
return curParams;
}
function submitHandler() {
if ($.validate.form()) {
$.operate.save(prefix + "/edit", $('#form-aftersalesOrder-edit').serialize());
}
}
$("input[name='startDate']").datetimepicker({
format: "yyyy-mm-dd",
minView: "month",
autoclose: true
});
$(function() {
var options = {
url: prefix + "/optionDevices",
modalName: "出货设备",
showColumns: false,
pagination: false,
showToggle: false,
showRefresh:false,
showSearch:false,
queryParams:queryParams,
columns: [{
checkbox: true
},
{
title: '料号',
field: 'materialNo',
},
{
title: '图片',
field: 'materialPhotourl',
},
{
title: '物料名称',
field: 'materialName',
},
{
title: '物料类型',
field: 'materialType',
},
{
title: '单位',
field: 'materialUnit',
},
{
title: '品牌',
field: 'materialBrand',
},
{
title: '描述',
field: 'materialDescribe',
},
{
title: '已出库数量',
field: 'shippedGoodsSum',
},
{
title: '设备SN',
field: 'snCode',
},
{
title: '售后问题',
field: 'aftersalesProblem',
},
{
title: '紧急程度',
field: 'emergencyDegree',
formatter: function(value, row, index) {
return $.table.selectDictLabel(emergencyDegreeDatas, value);
}
},
]
};
$.table.init(options);
})
function queryParams(params) {
var curParams = {
// 传递参数查询参数
aftersalesOrderCode: detail.aftersalesOrderCode
};
return curParams;
}
$(function () {
$.ajax({
url: ctx + 'aftersales/aftersalesOrder/getAftersalesStaffList',
type: 'post',
data: { roleKey: 'shgcsRole' },
success: function (res) {
if (res.data.length > 0) {
var userData = res.data;
for (let i in userData) {
$("#userId_add").append(
"<option value='" + userData[i].userName + "'>" + userData[i].userName + "</option>" // 使用 userName 作为 option 的 value
);
}
// 初始化时触发 change 事件,以确保首次加载时也能正确赋值
$("#userId_add").trigger("change");
} else {
$.modal.msgError(res.msg);
}
}
});
})
</script>
</body>
</html>
Loading…
Cancel
Save