Browse Source

[feat]售后管理:

售后单
新增上传报告功能
dev
liuxiaoxu 7 months ago
parent
commit
24348f47ed
  1. 25
      ruoyi-admin/src/main/java/com/ruoyi/aftersales/controller/AftersalesOrderController.java
  2. 32
      ruoyi-admin/src/main/java/com/ruoyi/aftersales/domain/AftersalesOrder.java
  3. 28
      ruoyi-admin/src/main/java/com/ruoyi/aftersales/service/impl/AftersalesOrderServiceImpl.java
  4. 22
      ruoyi-admin/src/main/resources/templates/aftersales/aftersalesOrder/aftersalesOrder.html
  5. 7
      ruoyi-admin/src/main/resources/templates/aftersales/aftersalesOrder/sendOrders.html
  6. 413
      ruoyi-admin/src/main/resources/templates/aftersales/aftersalesOrder/uploadReport.html

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

@ -150,6 +150,31 @@ public class AftersalesOrderController extends BaseController
return toAjax(aftersalesOrderService.updateAftersalesOrder(aftersalesOrder));
}
/**
* 售后报告
*/
@GetMapping("/uploadReport/{aftersalesOrderId}")
public String uploadReport(@PathVariable("aftersalesOrderId") Long aftersalesOrderId, ModelMap mmap)
{
AftersalesOrder aftersalesOrder = aftersalesOrderService.selectAftersalesOrderById(aftersalesOrderId);
mmap.put("uploadReport", aftersalesOrder);
return prefix + "/uploadReport";
}
/**
* 保存售后报告
*/
@RequiresPermissions("aftersales:aftersalesOrder:uploadReport")
@Log(title = "售后单", businessType = BusinessType.UPDATE)
@PostMapping("/uploadReport")
@ResponseBody
public AjaxResult uploadReportSave(AftersalesOrder aftersalesOrder)
{
return toAjax(aftersalesOrderService.updateAftersalesOrder(aftersalesOrder));
}
/**
* 查询选择设备列表
*/

32
ruoyi-admin/src/main/java/com/ruoyi/aftersales/domain/AftersalesOrder.java

@ -118,6 +118,14 @@ public class AftersalesOrder extends BaseEntity
/** 流程恢复实例ID */
private String restoreInstanceId;
/** 图片地址 */
private Long photoAttachId;
/** 图片上传id */
private String fileIdStr;
private String removeFileIdStr;
public void setAftersalesOrderId(Long aftersalesOrderId)
{
this.aftersalesOrderId = aftersalesOrderId;
@ -380,6 +388,30 @@ public class AftersalesOrder extends BaseEntity
return restoreInstanceId;
}
public Long getPhotoAttachId() {
return photoAttachId;
}
public void setPhotoAttachId(Long photoAttachId) {
this.photoAttachId = photoAttachId;
}
public String getFileIdStr() {
return fileIdStr;
}
public void setFileIdStr(String fileIdStr) {
this.fileIdStr = fileIdStr;
}
public String getRemoveFileIdStr() {
return removeFileIdStr;
}
public void setRemoveFileIdStr(String removeFileIdStr) {
this.removeFileIdStr = removeFileIdStr;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)

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

@ -1,8 +1,14 @@
package com.ruoyi.aftersales.service.impl;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ShiroUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.SysAttach;
import com.ruoyi.system.service.ISysAttachFileService;
import com.ruoyi.system.service.ISysAttachService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.aftersales.mapper.AftersalesOrderMapper;
@ -22,6 +28,12 @@ public class AftersalesOrderServiceImpl implements IAftersalesOrderService
@Autowired
private AftersalesOrderMapper aftersalesOrderMapper;
@Autowired
private ISysAttachService attachService;
@Autowired
private ISysAttachFileService attachFileService;
/**
* 查询售后单
*
@ -73,6 +85,22 @@ public class AftersalesOrderServiceImpl implements IAftersalesOrderService
String loginName = ShiroUtils.getLoginName();
aftersalesOrder.setUpdateBy(loginName);
aftersalesOrder.setUpdateTime(DateUtils.getNowDate());
Long aftersalesOrderId = aftersalesOrder.getAftersalesOrderId();
String fileIdStr = aftersalesOrder.getFileIdStr();
if (StringUtils.isNotEmpty(fileIdStr)){
//保存文件附件关联
SysAttach sysAttach = new SysAttach();
sysAttach.setCreateBy(ShiroUtils.getLoginName());
sysAttach.setCreateTime(new Date());
sysAttach.setSourceType("aftersalesOrder");
sysAttach.setSourceSubType("photo");
sysAttach.setRelId(aftersalesOrderId);
attachService.insertSysAttach(sysAttach);
//更新附件与文件关联
Long attachId = sysAttach.getId();
List<String> fileIdList = Arrays.asList(fileIdStr.split(","));
attachFileService.updateAttachIdByIdList(attachId,fileIdList);
}
return aftersalesOrderMapper.updateAftersalesOrder(aftersalesOrder);
}

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

@ -74,6 +74,8 @@
var cancelFlag = [[${@permission.hasPermi('aftersales:aftersalesOrder:cancel')}]];
var restoreFlag = [[${@permission.hasPermi('aftersales:aftersalesOrder:restore')}]];
var sendOrdersFlag = [[${@permission.hasPermi('aftersales:aftersalesOrder:sendOrders')}]];
var uploadReportFlag = [[${@permission.hasPermi('aftersales:aftersalesOrder:uploadReport')}]];
var aftersalesStatusDatas = [[${@dict.getType('sales_aftersales_status')}]];
var prefix = ctx + "aftersales/aftersalesOrder";
@ -87,6 +89,7 @@
restoreUrl: prefix + "/restore/{id}",
exportUrl: prefix + "/export",
sendOrdersUrl: prefix + "/sendOrders/{id}",
uploadReportUrl: prefix + "/uploadReport/{id}",
modalName: "售后单",
columns: [{
checkbox: true
@ -170,13 +173,8 @@
formatter: function(value, row, index) {
var actions = [];
actions.push('<a class="btn btn-success btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="$.operate.edit(\'' + row.aftersalesOrderId + '\')"><i class="fa fa-edit"></i>编辑</a> ');
actions.push('<a class="btn btn-danger btn-xs ' + removeFlag + '" href="javascript:void(0)" onclick="$.operate.remove(\'' + row.aftersalesOrderId + '\')"><i class="fa fa-remove"></i>删除</a> ');
actions.push('<a class="btn btn-success btn-xs ' + sendOrdersFlag + '" href="javascript:void(0)" onclick="sendOrders(\'' + row.aftersalesOrderId + '\')"><i class="fa fa-edit"></i>派单</a> ');
if(row.delFlag == '0'){
actions.push('<a class="btn btn-danger btn-xs ' + cancelFlag + '" href="javascript:void(0)" onclick="$.operate.cancel(\'' + row.id + '\')"><i class="fa fa-remove"></i>作废</a> ');
}else{
actions.push('<a class="btn btn-success btn-xs ' + restoreFlag + '" href="javascript:void(0)" onclick="$.operate.restore(\'' + row.id + '\')"><i class="fa fa-window-restore"></i>恢复</a> ');
}
actions.push('<a class="btn btn-success btn-xs ' + uploadReportFlag + '" href="javascript:void(0)" onclick="uploadReport(\'' + row.aftersalesOrderId + '\')"><i class="fa fa-edit"></i>上传报告</a> ');
return actions.join('');
}
}]
@ -197,7 +195,19 @@
$.modal.open("派单",url);
}
}
/*上传报告*/
function uploadReport(aftersalesOrderId) {
// 在这里编写派单操作的逻辑,使用传入的aftersalesOrderId参数
// 示例逻辑:
// 1. 确认用户操作
if (confirm('确认要上传报告吗?')) {
var url = ctx + 'aftersales/aftersalesOrder/uploadReport/'+aftersalesOrderId;
console.log(url);
$.modal.open("上传报告",url);
}
}
</script>
</body>

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

@ -1,14 +1,9 @@
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
<head>
<th:block th:include="include :: header('修改售后单')" />
<th:block th:include="include :: header('单')" />
<th:block th:include="include :: datetimepicker-css" />
<th:block th:include="include :: summernote-css" />
<style>
.device-container {
margin-top: 1rem; /* 调整此值以达到所需的间距效果 */
}
</style>
</head>
<body class="white-bg">
<div class="wrapper wrapper-content animated fadeInRight ibox-content">

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

@ -0,0 +1,413 @@
<!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="${uploadReport}">
<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="salesOrderCode" th:field="*{salesOrderCode}" 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="makeNo" th:field="*{makeNo}" class="form-control" type="text">
</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">
</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">
</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">
</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">
</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">
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">客户要求出发日期:</label>
<div class="col-sm-8">
<div class="input-group date">
<input name="startDate" class="form-control" th:value="*{startDate}" placeholder="yyyy-mm-dd" type="text">
<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">
</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">[[*{serviceContent}]]</textarea>
</div>
</div>
<!-- 用户评价 -->
<div class="form-row">
<label class="col-sm-4 control-label">用户评价:</label>
<div class="col-sm-6">
<el-upload
:action="fileUploadUrl"
:on-success="uploadSuccess"
:on-remove="uploadRemove"
:file-list="fileList"
:limit="5"
list-type="picture"
accept=".jpg,.png"
multiple>
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,第一张图片为主图</div>
</el-upload>
</div>
<input id="fileIdStr" type="text" name="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 prefix = ctx + "aftersales/aftersalesOrder";
var uploadReport = [[${uploadReport}]];
$("#form-aftersalesOrder-edit").validate({
focusCleanup: true
});
new Vue({
el: '#app',
data: function() {
return {
fileList: [],
fileUploadUrl: ctx + "common/uploadSingleFile",
fileDeleteUrl: ctx + "common/deleteFile",
fileIdList:[],
}
},
methods: {
uploadSuccess(response, file, fileList) {
console.log(response);
if(response.code == web_status.SUCCESS){
var attachFileId = response.data.id;
file.attachFileId = attachFileId;
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;
$.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("删除附件失败。");
}
});
},
}
})
$(function() {
var options = {
url: prefix + "/optionDevices",
modalName: "出货设备",
showColumns: false,
pagination: false,
showToggle: false,
showRefresh:false,
showSearch:false,
queryParams:queryParams,
columns: [{
checkbox: true
},
{
title: '出货设备编号',
field: 'shippingDeviceCode',
visible: false
},
{
title: '料号',
field: 'materialNo',
},
{
title: '图片',
field: 'materialPhotourl',
},
{
title: '物料名称',
field: 'materialName',
},
{
title: '物料类型',
field: 'materialType',
},
{
title: '单位',
field: 'materialUnit',
},
{
title: '品牌',
field: 'materialBrand',
},
{
title: '描述',
field: 'materialDescribe',
},
{
title: '流水号',
field: 'deviceRunningNumber',
},
{
title: '生产图片',
field: 'makePhotourl',
},
{
title: 'SN号',
field: 'snCode',
},
{
title: '售后图片',
field: 'aftersalesPhotourl',
},
]
};
$.table.init(options);
})
function queryParams(params) {
var curParams = {
// 传递参数查询参数
makeNo: uploadReport.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() {
$('.summernote').each(function(i) {
$('#' + this.id).summernote({
lang: 'zh-CN',
callbacks: {
onChange: function(contents, $edittable) {
$("input[name='" + this.id + "']").val(contents);
},
onImageUpload: function(files) {
var obj = this;
var data = new FormData();
data.append("file", files[0]);
$.ajax({
type: "post",
url: ctx + "common/upload",
data: data,
cache: false,
contentType: false,
processData: false,
dataType: 'json',
success: function(result) {
if (result.code == web_status.SUCCESS) {
$('#' + obj.id).summernote('insertImage', result.url);
} else {
$.modal.alertError(result.msg);
}
},
error: function(error) {
$.modal.alertWarning("图片上传失败。");
}
});
}
}
});
var content = $("input[name='" + this.id + "']").val();
$('#' + this.id).summernote('code', content);
})
});
$(function() {
var options = {
url: prefix + "/optionDevices",
modalName: "出货设备",
showColumns: false,
pagination: false,
showToggle: false,
showRefresh:false,
showSearch:false,
queryParams:queryParams,
columns: [{
checkbox: true
},
{
title: '出货设备编号',
field: 'shippingDeviceCode',
visible: false
},
{
title: '料号',
field: 'materialNo',
},
{
title: '图片',
field: 'materialPhotourl',
},
{
title: '物料名称',
field: 'materialName',
},
{
title: '物料类型',
field: 'materialType',
},
{
title: '单位',
field: 'materialUnit',
},
{
title: '品牌',
field: 'materialBrand',
},
{
title: '描述',
field: 'materialDescribe',
},
{
title: '流水号',
field: 'deviceRunningNumber',
},
{
title: '生产图片',
field: 'makePhotourl',
},
{
title: 'SN号',
field: 'snCode',
},
{
title: '售后图片',
field: 'aftersalesPhotourl',
},
]
};
$.table.init(options);
})
function queryParams(params) {
var curParams = {
// 传递参数查询参数
makeNo: uploadReport.makeNo
};
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