feat(workOrder): 新增工作订单保存草稿功能并优化相关逻辑

- 新增保存草稿接口,支持批量保存
- 优化工作订单列表查询逻辑,增加数据权限控制
- 重构工作订单保存和更新方法,提高代码复用性
- 优化附件保存逻辑,减少冗余操作
- 更新数据库连接配置,使用外网地址
main
litao 1 year ago
parent fe5f22b7bb
commit 5ce73992b3
  1. 53
      src/main/java/org/springblade/modules/workOrder/controller/DeviceController.java
  2. 82
      src/main/java/org/springblade/modules/workOrder/controller/WorkOrderController.java
  3. 10
      src/main/java/org/springblade/modules/workOrder/dto/DeviceDTO.java
  4. 2
      src/main/java/org/springblade/modules/workOrder/entity/WorkOrder.java
  5. 2
      src/main/java/org/springblade/modules/workOrder/service/IWorkOrderService.java
  6. 99
      src/main/java/org/springblade/modules/workOrder/service/impl/WorkOrderServiceImpl.java
  7. 7
      src/main/resources/application-dev.yml
  8. 12
      src/main/resources/application.yml

@ -1,6 +1,7 @@
package org.springblade.modules.workOrder.controller;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@ -14,6 +15,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.CollectionUtil;
@ -22,7 +24,6 @@ import org.springblade.modules.workOrder.dto.DeviceDTO;
import org.springblade.modules.workOrder.entity.DeviceAttach;
import org.springblade.modules.workOrder.entity.WorkOrder;
import org.springblade.modules.workOrder.service.IDeviceAttachService;
import org.springblade.modules.workOrder.vo.WorkOrderVO;
import org.springframework.web.bind.annotation.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@ -35,18 +36,7 @@ import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.excel.util.ExcelUtil;
import org.springblade.core.tool.constant.BladeConstant;
import springfox.documentation.annotations.ApiIgnore;
import sun.misc.BASE64Encoder;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
@ -88,9 +78,38 @@ public class DeviceController extends BladeController {
@GetMapping("/list")
@ApiOperationSupport(order = 2)
@ApiOperation(value = "分页", notes = "传入device")
public R<IPage<Device>> list(@ApiIgnore @RequestParam Map<String, Object> device, Query query) {
IPage<Device> pages = deviceService.page(Condition.getPage(query), Condition.getQueryWrapper(device, Device.class));
return R.data(pages);
public R<IPage<Device>> list(@ApiIgnore DeviceDTO device, Query query) {
if (device == null || query == null) {
throw new IllegalArgumentException("Device or Query cannot be null");
}
// 验证用户身份
Long userId = AuthUtil.getUserId();
if (userId == null) {
throw new IllegalArgumentException("User not authenticated");
}
LambdaQueryWrapper<Device> wrapper = Wrappers.lambdaQuery(Device.class);
wrapper.like(StringUtils.isNotBlank(sanitizeInput(device.getName())), Device::getName, device.getName());
wrapper.eq(StringUtils.isNotBlank(sanitizeInput(device.getPosition())), Device::getPosition, device.getPosition());
wrapper.eq(StringUtils.isNotBlank(sanitizeInput(device.getType())), Device::getType, device.getType());
wrapper.eq(Device::getCreateUser, AuthUtil.getUserId());
wrapper.orderByDesc(Device::getCreateTime);
try {
IPage<Device> pages = deviceService.page(Condition.getPage(query), wrapper);
return R.data(pages);
} catch (Exception e) {
// 记录异常日志
log.error("Error occurred while fetching device list", e);
throw new RuntimeException("Failed to fetch device list", e);
}
}
private String sanitizeInput(String input) {
// 对输入进行清理,防止 SQL 注入等安全问题
if (input == null) {
return null;
}
return input.replaceAll("[^a-zA-Z0-9_\\-\\. ]", "");
}
/**

@ -11,6 +11,7 @@ import lombok.AllArgsConstructor;
import javax.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.log.annotation.ApiLog;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.mp.support.Condition;
@ -34,8 +35,10 @@ import org.springblade.core.excel.util.ExcelUtil;
import org.springblade.core.tool.constant.BladeConstant;
import springfox.documentation.annotations.ApiIgnore;
import java.util.Collections;
import java.util.Map;
import java.util.List;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
/**
@ -44,6 +47,7 @@ import javax.servlet.http.HttpServletResponse;
* @author BladeX
* @since 2024-10-14
*/
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/workOrder")
@ -65,35 +69,87 @@ public class WorkOrderController extends BladeController {
}
/**
* 工单表 分页
* 查询工作订单列表
*
* @param workOrderDTO 工作订单DTO包含查询条件
* @param query 分页查询对象
* @return 返回工作订单列表的响应对象
*/
@GetMapping("/list")
@ApiOperationSupport(order = 2)
@ApiOperation(value = "分页", notes = "传入workOrder")
public R<IPage<WorkOrder>> list(@ApiIgnore WorkOrderDTO workOrderDTO, Query query) {
// 创建工作订单的查询条件包装器
LambdaQueryWrapper<WorkOrder> eq = Wrappers.lambdaQuery(WorkOrder.class);
// 数据权限
if (StringUtils.isNotBlank(workOrderDTO.getDataType())) {
eq.eq("1".equals(workOrderDTO.getDataType()), WorkOrder::getCreateUser, AuthUtil.getUserId());// 客户
eq.in("2".equals(workOrderDTO.getDataType()), WorkOrder::getCreateDept, Func.toLongList(AuthUtil.getDeptId()));// 客服
eq.eq("3".equals(workOrderDTO.getDataType()), WorkOrder::getMaintenanceTeam, AuthUtil.getDeptId());// 维修负责人
eq.eq("4".equals(workOrderDTO.getDataType()), WorkOrder::getRepairPerson, AuthUtil.getUserId());// 维修人员
try {
if (StringUtils.isNotBlank(workOrderDTO.getDataType())) {
setDataTypeConditions(eq, workOrderDTO.getDataType());
}
} catch (Exception e) {
// 处理异常,例如记录日志或返回错误信息
log.error("Error setting data type conditions", e);
return R.fail("数据权限设置失败");
}
// 设置查询条件:故障地点、故障类型、创建时间范围,并按创建时间降序排序
eq.eq(StringUtils.isNotBlank(workOrderDTO.getFaultLocation()), WorkOrder::getFaultLocation, workOrderDTO.getFaultLocation())
.eq(StringUtils.isNotBlank(workOrderDTO.getFaultType()), WorkOrder::getFaultType, workOrderDTO.getFaultType())
.between(workOrderDTO.getStartTime() != null && workOrderDTO.getEndTime() != null, WorkOrder::getCreateTime, workOrderDTO.getStartTime(), workOrderDTO.getEndTime())
.orderByDesc(WorkOrder::getCreateTime);
// 执行分页查询
IPage<WorkOrder> pages = workOrderService.page(Condition.getPage(query), eq);
// 获取查询结果列表
List<WorkOrder> records = pages.getRecords();
// 批量查询设备名称
List<Long> deviceIds = records.stream().map(WorkOrder::getDeviceId).collect(Collectors.toList());
Map<Long, String> deviceNameMap = getDeviceNameMap(deviceIds);
for (WorkOrder record : records) {
Device device = deviceService.getById(record.getDeviceId());
record.setDeviceName(device != null ? device.getName() : "");
record.setDeviceName(deviceNameMap.getOrDefault(record.getDeviceId(), ""));
}
// 更新查询结果列表
pages.setRecords(records);
// 返回查询结果
return R.data(pages);
}
private void setDataTypeConditions(LambdaQueryWrapper<WorkOrder> eq, String dataType) {
switch (dataType) {
case "1":
eq.eq(WorkOrder::getCreateUser, AuthUtil.getUserId()); // 客户
break;
case "2":
eq.in(WorkOrder::getCreateDept, Func.toLongList(AuthUtil.getDeptId())); // 客服
break;
case "3":
eq.eq(WorkOrder::getMaintenanceTeam, AuthUtil.getDeptId()); // 维修负责人
break;
case "4":
eq.eq(WorkOrder::getRepairPerson, AuthUtil.getUserId()); // 维修人员
break;
default:
// 处理未知的数据类型
log.warn("Unknown data type: {}", dataType);
}
}
private Map<Long, String> getDeviceNameMap(List<Long> deviceIds) {
if (deviceIds.isEmpty()) {
return Collections.emptyMap();
}
List<Device> devices = deviceService.listByIds(deviceIds);
return devices.stream().collect(Collectors.toMap(Device::getId, Device::getName));
}
/**
* 工单表 自定义分页
*/
@ -116,6 +172,16 @@ public class WorkOrderController extends BladeController {
return R.status(workOrderService.saveAndAttach(workOrder));
}
/**
* 工单表 保存草稿
*/
@ApiLog(value = "提报管理-保存草稿")
@PostMapping("/draft")
@ApiOperation(value = "保存草稿", notes = "传入workOrder")
public R draft(@Valid @RequestBody List<WorkOrderVO> workOrder) {
return R.status(workOrderService.draftAndAttach(workOrder));
}
/**
* 工单表 修改
*/

@ -20,4 +20,14 @@ public class DeviceDTO extends Device {
private static final long serialVersionUID = 1L;
private List<DeviceAttach> attaches;
// 设备名称
private String name;
// 设备位置
private String position;
// 设备类型
private String type;
}

@ -21,7 +21,7 @@ import java.util.Date;
@EqualsAndHashCode(callSuper = true)
public class WorkOrder extends BaseEntity {
// 工单状态(0待客服接单 1待班组派单 2待维修人员确认 3待维修 4待领导审批 5待评价 6已完成 7已驳回(维修人员) 8已驳回(维修负责人) 9已关闭(客服))
// 工单状态(-1草稿 0待客服接单 1待班组派单 2待维修人员确认 3待维修 4待领导审批 5待评价 6已完成 7已驳回(维修人员) 8已驳回(维修负责人) 9已关闭(客服))
/**
* 故障位置

@ -42,4 +42,6 @@ public interface IWorkOrderService extends BaseService<WorkOrder> {
boolean evaluateSign(WorkOrderVO workOrder);
boolean updateAttach(WorkOrderVO workOrder);
boolean draftAndAttach(List<WorkOrderVO> workOrder);
}

@ -15,6 +15,7 @@ import org.springblade.modules.system.entity.User;
import org.springblade.modules.system.service.IUserService;
import org.springblade.modules.system.vo.PostVO;
import org.springblade.modules.workOrder.dto.WorkOrderDTO;
import org.springblade.modules.workOrder.entity.KnowledgeBaseAttach;
import org.springblade.modules.workOrder.entity.WorkOrder;
import org.springblade.modules.workOrder.entity.WorkOrderAttach;
import org.springblade.modules.workOrder.entity.WorkOrderRepairMaterial;
@ -130,28 +131,11 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO
workOrder.setInformant(user.getId());
workOrder.setInformantPhone(user.getPhone());
}
save = this.save(workOrder);
save = this.saveOrUpdate(workOrder);
count++;
// 保存视频附件
List<WorkOrderAttach> videoAttaches = workOrder.getVideoAttaches();
if (CollectionUtils.isNotEmpty(videoAttaches)) {
videoAttaches.forEach(videoAttach -> {
videoAttach.setOrderId(workOrder.getId());
videoAttach.setAttachType(2);
});
workOrderAttachService.saveBatch(videoAttaches);
}
// 保存图片附件
List<WorkOrderAttach> picAttaches = workOrder.getPicAttaches();
if (CollectionUtils.isNotEmpty(picAttaches)) {
picAttaches.forEach(picAttache -> {
picAttache.setOrderId(workOrder.getId());
picAttache.setAttachType(1);
});
workOrderAttachService.saveBatch(picAttaches);
}
// 保存附件
saveFiles(workOrder.getVideoAttaches(), workOrder.getPicAttaches(), workOrder.getId());
}
return save;
}
@ -170,27 +154,8 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO
@Override
public boolean updateAttach(WorkOrderVO workOrder) {
List<WorkOrderAttach> picAttaches = workOrder.getPicAttaches();
// 图片
if (org.springblade.core.tool.utils.CollectionUtil.isNotEmpty(picAttaches)) {
workOrderAttachService.remove(Wrappers.lambdaQuery(WorkOrderAttach.class).eq(WorkOrderAttach::getOrderId, workOrder.getId()).eq(WorkOrderAttach::getAttachType, 1));
picAttaches.forEach(picAttache -> {
picAttache.setOrderId(workOrder.getId());
picAttache.setAttachType(1);
}
);
workOrderAttachService.saveBatch(picAttaches);
}
// 视频
List<WorkOrderAttach> videoAttaches = workOrder.getVideoAttaches();
if (org.springblade.core.tool.utils.CollectionUtil.isNotEmpty(videoAttaches)) {
workOrderAttachService.remove(Wrappers.lambdaQuery(WorkOrderAttach.class).eq(WorkOrderAttach::getOrderId, workOrder.getId()).eq(WorkOrderAttach::getAttachType, 2));
videoAttaches.forEach(videoAttache -> {
videoAttache.setOrderId(workOrder.getId());
videoAttache.setAttachType(2);
});
workOrderAttachService.saveBatch(videoAttaches);
}
// 保存附件
saveFiles(workOrder.getVideoAttaches(), workOrder.getPicAttaches(), workOrder.getId());
List<WorkOrderRepairMaterial> materials = workOrder.getMaterials();
// 维修材料
if (CollectionUtil.isNotEmpty(materials)) {
@ -200,4 +165,56 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO
return this.updateById(workOrder);
}
@Override
public boolean draftAndAttach(List<WorkOrderVO> workOrders) {
boolean save = false;
for (WorkOrderVO workOrder : workOrders) {
// 查询今天已提报数量
workOrder.setStatus(-1);// 草稿
save = this.saveOrUpdate(workOrder);
// 保存附件
saveFiles(workOrder.getVideoAttaches(), workOrder.getPicAttaches(), workOrder.getId());
}
return save;
}
private void saveFiles(List<WorkOrderAttach> videoAttaches, List<WorkOrderAttach> picAttaches, Long orderId) {
// 保存视频附件
if (CollectionUtils.isNotEmpty(videoAttaches)) {
// 需要新增的附件
List<WorkOrderAttach> newSavePic = videoAttaches.stream().filter(workOrderAttach -> workOrderAttach.getId() == null).collect(Collectors.toList());
// 不删除的附件ids
List<Long> ids = videoAttaches.stream().filter(workOrderAttach -> workOrderAttach.getId() != null).map(WorkOrderAttach::getId).collect(Collectors.toList());
workOrderAttachService.remove(Wrappers.lambdaQuery(WorkOrderAttach.class)
.eq(WorkOrderAttach::getOrderId, orderId)
.eq(WorkOrderAttach::getAttachType, 2)
.notIn(CollectionUtils.isNotEmpty(ids), WorkOrderAttach::getId, ids));
newSavePic.forEach(videoAttach -> {
videoAttach.setOrderId(orderId);
videoAttach.setAttachType(2);
});
workOrderAttachService.saveBatch(newSavePic);
}
// 保存图片附件
if (CollectionUtils.isNotEmpty(picAttaches)) {
// 需要新增的附件
List<WorkOrderAttach> newSaveVideo = picAttaches.stream().filter(workOrderAttach -> workOrderAttach.getId() == null).collect(Collectors.toList());
// 不删除的附件ids
List<Long> ids = picAttaches.stream().filter(workOrderAttach -> workOrderAttach.getId() != null).map(WorkOrderAttach::getId).collect(Collectors.toList());
workOrderAttachService.remove(Wrappers.lambdaQuery(WorkOrderAttach.class)
.eq(WorkOrderAttach::getOrderId, orderId)
.eq(WorkOrderAttach::getAttachType, 1)
.notIn(CollectionUtils.isNotEmpty(ids), WorkOrderAttach::getId, ids));
newSaveVideo.forEach(picAttache -> {
picAttache.setOrderId(orderId);
picAttache.setAttachType(1);
});
workOrderAttachService.saveBatch(newSaveVideo);
}
}
}

@ -15,10 +15,11 @@ spring:
# commandTimeout: 5000
datasource:
# MySql
url: jdbc:mysql://localhost:3306/data_operation?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true
# url: jdbc:mysql://localhost:3306/data_operation?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true
url: jdbc:mysql://124.221.142.15:3306/data_operation?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true
username: root
password: 123456
# password: jiahe123!
# password: 123456
password: jiahe123!
# PostgreSQL
#url: jdbc:postgresql://127.0.0.1:5432/bladex_boot
#username: postgres

@ -138,16 +138,16 @@ oss:
#租户模式
tenant-mode: false
#oss服务地址
endpoint: http://192.168.0.105:9000
# endpoint: http://124.221.142.15:9000
# endpoint: http://192.168.0.105:9000
endpoint: http://124.221.142.15:9000
#minio转换服务地址,用于内网上传后将返回地址改为转换的外网地址
# transform-endpoint: http://localhost:9000
#访问key
access-key: pJv3uZvE9kMgPfb9
# access-key: DBTbUmfs1uvvyspvSKKo
# access-key: pJv3uZvE9kMgPfb9
access-key: DBTbUmfs1uvvyspvSKKo
#密钥key
secret-key: HgKxhiNxxEJf3UAPGHLtywxTKAALmt3s
# secret-key: NNmKEWBJUnJNdk58P26Y9IcMdUKbGXJy2hLDx92p
# secret-key: HgKxhiNxxEJf3UAPGHLtywxTKAALmt3s
secret-key: NNmKEWBJUnJNdk58P26Y9IcMdUKbGXJy2hLDx92p
#存储桶
bucket-name: laboratory

Loading…
Cancel
Save