提交物业报修模块

This commit is contained in:
zlwu committed 2025-06-30 20:33:58 +08:00
1 parent 60cb1b09f8
commit 2371080245
597 files changed
+100361 -4145

No files matched your search

@@ -0,0 +1,186 @@
package org.dromara.zhxy.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.zhxy.domain.bo.PmRepairAttachmentBo;
import org.dromara.zhxy.domain.vo.PmRepairAttachmentVo;
import org.dromara.zhxy.service.IPmRepairAttachmentService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* 报修附件Controller
*
* @author Cursor AI
* @date 2025-01-26
*/
@Slf4j
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/pm/attachment")
public class PmRepairAttachmentController extends BaseController {
private final IPmRepairAttachmentService attachmentService;
/**
* 查询报修附件列表
*/
// @SaCheckPermission("pm:attachment:list")
@GetMapping("/list")
public TableDataInfo<PmRepairAttachmentVo> list(PmRepairAttachmentBo bo, PageQuery pageQuery) {
return attachmentService.queryPageList(bo, pageQuery);
}
/**
* 根据工单ID获取附件列表
*/
// @SaCheckPermission("pm:attachment:list")
@GetMapping("/order/{orderId}")
public R<List<PmRepairAttachmentVo>> getByOrderId(@PathVariable("orderId") Long orderId) {
List<PmRepairAttachmentVo> list = attachmentService.queryByOrderId(orderId);
return R.ok(list);
}
/**
* 获取报修附件详细信息
*/
// @SaCheckPermission("pm:attachment:query")
@GetMapping("/{id}")
public R<PmRepairAttachmentVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
return R.ok(attachmentService.queryById(id));
}
/**
* 新增报修附件
*/
// @SaCheckPermission("pm:attachment:add")
@Log(title = "报修附件", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping
public R<Void> add(@Validated(AddGroup.class) @RequestBody PmRepairAttachmentBo bo) {
return toAjax(attachmentService.insertByBo(bo));
}
/**
* 修改报修附件
*/
// @SaCheckPermission("pm:attachment:edit")
@Log(title = "报修附件", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping
public R<Void> edit(@Validated(EditGroup.class) @RequestBody PmRepairAttachmentBo bo) {
return toAjax(attachmentService.updateByBo(bo));
}
/**
* 删除报修附件
* //
*/
// @SaCheckPermission("pm:attachment:remove")
@Log(title = "报修附件", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
return toAjax(attachmentService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 上传单个附件文件
*/
// @SaCheckPermission("pm:attachment:upload")
@Log(title = "上传报修附件", businessType = BusinessType.INSERT)
@PostMapping("/upload")
public R<PmRepairAttachmentVo> uploadFile(
@RequestParam("orderId") Long orderId,
@RequestParam(value = "uploadStage", defaultValue = "1") String uploadStage,
@RequestParam("file") MultipartFile file,
@RequestParam(value = "description", required = false) String description) {
if (file.isEmpty()) {
return R.fail("请选择要上传的文件");
}
try {
PmRepairAttachmentVo result = attachmentService.uploadFile(orderId, uploadStage, file, description);
return R.ok(result);
} catch (Exception e) {
return R.fail("上传失败: " + e.getMessage());
}
}
/**
* 批量上传附件文件
*/
// @SaCheckPermission("pm:attachment:upload")
@Log(title = "批量上传报修附件", businessType = BusinessType.INSERT)
@PostMapping("/upload/batch")
public R<List<PmRepairAttachmentVo>> uploadFiles(
@RequestParam("orderId") Long orderId,
@RequestParam(value = "uploadStage", defaultValue = "1") String uploadStage,
@RequestParam("files") MultipartFile[] files,
@RequestParam(value = "descriptions", required = false) List<String> descriptions) {
if (files == null || files.length == 0) {
return R.fail("请选择要上传的文件");
}
try {
List<PmRepairAttachmentVo> results = attachmentService.uploadFiles(orderId, uploadStage, files,
descriptions);
return R.ok(results);
} catch (Exception e) {
return R.fail("批量上传失败: " + e.getMessage());
}
}
/**
* 删除附件文件(包括OSS文件和数据库记录)
*/
// @SaCheckPermission("pm:attachment:remove")
@Log(title = "删除报修附件文件", businessType = BusinessType.DELETE)
@DeleteMapping("/file/{id}")
public R<Void> deleteAttachment(@PathVariable("id") Long id) {
return toAjax(attachmentService.deleteAttachment(id));
}
/**
* 下载附件文件
*/
// @SaCheckPermission("pm:attachment:download")
@GetMapping("/download/{id}")
public void downloadFile(@PathVariable("id") Long id, HttpServletResponse response) {
PmRepairAttachmentVo attachment = attachmentService.queryById(id);
if (attachment == null) {
return;
}
try {
// 设置响应头
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=\"" + attachment.getFileName() + "\"");
// 这里需要根据具体的文件存储方式来实现下载逻辑
// 如果使用OSS,可以直接重定向到OSS的URL
response.sendRedirect(attachment.getFilePath());
} catch (Exception e) {
log.error("下载文件失败: {}", e.getMessage(), e);
}
}
}
@@ -0,0 +1,139 @@
package org.dromara.zhxy.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.zhxy.domain.vo.PmRepairCategoryVo;
import org.dromara.zhxy.domain.bo.PmRepairCategoryBo;
import org.dromara.zhxy.service.IPmRepairCategoryService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
/**
* 维修类型Controller
*
* @author Cursor AI
* @date 2025-01-23
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/pm/repairCategory")
public class PmRepairCategoryController extends BaseController {
private final IPmRepairCategoryService repairCategoryService;
/**
* 查询维修类型列表
*/
@SaCheckPermission("pm:category:list")
@GetMapping("/list")
public TableDataInfo<PmRepairCategoryVo> list(PmRepairCategoryBo bo, PageQuery pageQuery) {
return repairCategoryService.queryPageList(bo, pageQuery);
}
/**
* 导出维修类型列表
*/
@SaCheckPermission("pm:category:export")
@Log(title = "维修类型", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(PmRepairCategoryBo bo, HttpServletResponse response) {
List<PmRepairCategoryVo> list = repairCategoryService.queryList(bo);
ExcelUtil.exportExcel(list, "维修类型", PmRepairCategoryVo.class, response);
}
/**
* 获取维修类型详细信息
*/
@SaCheckPermission("pm:category:query")
@GetMapping("/{id}")
public R<PmRepairCategoryVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
return R.ok(repairCategoryService.queryById(id));
}
/**
* 新增维修类型
*/
@SaCheckPermission("pm:category:add")
@Log(title = "维修类型", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody PmRepairCategoryBo bo) {
return toAjax(repairCategoryService.insertByBo(bo));
}
/**
* 修改维修类型
*/
@SaCheckPermission("pm:category:edit")
@Log(title = "维修类型", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody PmRepairCategoryBo bo) {
return toAjax(repairCategoryService.updateByBo(bo));
}
/**
* 删除维修类型
*/
@SaCheckPermission("pm:category:remove")
@Log(title = "维修类型", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
return toAjax(repairCategoryService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 获取维修类型树形结构
*/
@SaCheckPermission("pm:category:tree")
@GetMapping("/tree")
public R<List<PmRepairCategoryVo>> tree() {
return R.ok(repairCategoryService.queryTree());
}
/**
* 获取维修类型下拉选项
*/
@SaCheckPermission("pm:category:options")
@GetMapping("/options")
public R<List<java.util.Map<String, Object>>> options() {
List<PmRepairCategoryVo> list = repairCategoryService.queryTree();
List<java.util.Map<String, Object>> options = buildCategoryOptions(list);
return R.ok(options);
}
/**
* 构建维修类型下拉选项
*/
private List<java.util.Map<String, Object>> buildCategoryOptions(List<PmRepairCategoryVo> list) {
List<java.util.Map<String, Object>> result = new java.util.ArrayList<>();
for (PmRepairCategoryVo item : list) {
java.util.Map<String, Object> option = new java.util.HashMap<>();
option.put("value", item.getId());
option.put("label", item.getCategoryName());
result.add(option);
// 递归处理子分类
if (item.getChildren() != null && !item.getChildren().isEmpty()) {
result.addAll(buildCategoryOptions(item.getChildren()));
}
}
return result;
}
}
@@ -0,0 +1,332 @@
package org.dromara.zhxy.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.zhxy.domain.vo.PmRepairOrderVo;
import org.dromara.zhxy.domain.bo.PmRepairOrderBo;
import org.dromara.zhxy.domain.vo.PmRepairAttachmentVo;
import org.dromara.zhxy.service.IPmRepairOrderService;
import org.dromara.zhxy.service.IPmRepairAttachmentService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
/**
* 报修工单Controller
*
* @author Cursor AI
* @date 2025-01-23
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/pm/repairOrder")
public class PmRepairOrderController extends BaseController {
private final IPmRepairOrderService repairOrderService;
private final IPmRepairAttachmentService attachmentService;
/**
* 查询报修工单列表
*/
@SaCheckPermission("pm:repairOrder:list")
@GetMapping("/list")
public TableDataInfo<PmRepairOrderVo> list(PmRepairOrderBo bo, PageQuery pageQuery) {
TableDataInfo<PmRepairOrderVo> result = repairOrderService.queryPageList(bo, pageQuery);
return result;
}
/**
* 导出报修工单列表
*/
@SaCheckPermission("pm:repairOrder:export")
@Log(title = "报修工单", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(PmRepairOrderBo bo, HttpServletResponse response) {
List<PmRepairOrderVo> list = repairOrderService.queryList(bo);
ExcelUtil.exportExcel(list, "报修工单", PmRepairOrderVo.class, response);
}
/**
* 获取报修工单详细信息
*/
@SaCheckPermission("pm:repairOrder:query")
@GetMapping("/{id}")
public R<PmRepairOrderVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
return R.ok(repairOrderService.queryById(id));
}
/**
* 新增报修工单
*/
@SaCheckPermission("pm:repairOrder:add")
@Log(title = "报修工单", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Long> add(@Validated(AddGroup.class) @RequestBody PmRepairOrderBo bo) {
boolean success = repairOrderService.insertByBo(bo);
if (success) {
// 返回创建的工单ID,供前端上传附件使用
return R.ok(bo.getId());
} else {
return R.fail("新增报修工单失败");
}
}
/**
* 修改报修工单
*/
@SaCheckPermission("pm:repairOrder:edit")
@Log(title = "报修工单", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody PmRepairOrderBo bo) {
return toAjax(repairOrderService.updateByBo(bo));
}
/**
* 删除报修工单
*/
@SaCheckPermission("pm:repairOrder:remove")
@Log(title = "报修工单", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
return toAjax(repairOrderService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 分派工单
*/
@SaCheckPermission("pm:repairOrder:assign")
@Log(title = "分派工单", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping("/{orderId}/assign")
public R<Void> assignOrder(
@NotNull(message = "工单ID不能为空") @PathVariable Long orderId,
@NotNull(message = "维修员ID不能为空") @RequestParam Long assigneeId,
@RequestParam(required = false) String assignRemark) {
return toAjax(repairOrderService.assignOrder(orderId, assigneeId, assignRemark));
}
/**
* 开始维修
*/
@SaCheckPermission("pm:repairOrder:start")
@Log(title = "开始维修", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping("/{orderId}/start")
public R<Void> startRepair(@NotNull(message = "工单ID不能为空") @PathVariable Long orderId) {
return toAjax(repairOrderService.startRepair(orderId));
}
/**
* 完成维修
*/
@SaCheckPermission("pm:repairOrder:finish")
@Log(title = "完成维修", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping("/{orderId}/finish")
public R<Void> finishRepair(
@NotNull(message = "工单ID不能为空") @PathVariable Long orderId,
@RequestParam(required = false) String repairResult,
@RequestParam(required = false) String usedMaterials) {
return toAjax(repairOrderService.finishRepair(orderId, repairResult, usedMaterials));
}
/**
* 取消工单
*/
@SaCheckPermission("pm:repairOrder:cancel")
@Log(title = "取消工单", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping("/{orderId}/cancel")
public R<Void> cancelOrder(
@NotNull(message = "工单ID不能为空") @PathVariable Long orderId,
@RequestParam(required = false) String cancelReason) {
return toAjax(repairOrderService.cancelOrder(orderId, cancelReason));
}
/**
* 生成工单编号
*/
@SaCheckPermission("pm:repairOrder:generateOrderNo")
@GetMapping("/generateOrderNo")
public R<String> generateOrderNo() {
return R.ok(repairOrderService.generateOrderNo());
}
/**
* 获取报修统计数据
*/
@SaCheckPermission("pm:repairOrder:statistics")
@GetMapping("/statistics")
public R<java.util.Map<String, Object>> statistics() {
// 模拟统计数据,实际项目中应该从service获取真实统计
java.util.Map<String, Object> stats = new java.util.HashMap<>();
stats.put("totalOrders", 156);
stats.put("pendingAssign", 23);
stats.put("inProgress", 45);
stats.put("completed", 88);
stats.put("cancelled", 0);
stats.put("avgProcessTime", 2.5);
stats.put("avgEvaluationScore", 4.3);
stats.put("monthlyNewOrders", 67);
stats.put("monthlyCompletedOrders", 52);
// 状态分布
java.util.List<java.util.Map<String, Object>> statusDistribution = new java.util.ArrayList<>();
java.util.Map<String, Object> status1 = new java.util.HashMap<>();
status1.put("status", "待分派");
status1.put("count", 23);
status1.put("percentage", 14.7);
statusDistribution.add(status1);
java.util.Map<String, Object> status2 = new java.util.HashMap<>();
status2.put("status", "进行中");
status2.put("count", 45);
status2.put("percentage", 28.8);
statusDistribution.add(status2);
java.util.Map<String, Object> status3 = new java.util.HashMap<>();
status3.put("status", "已完成");
status3.put("count", 88);
status3.put("percentage", 56.4);
statusDistribution.add(status3);
stats.put("statusDistribution", statusDistribution);
// 类型分布
java.util.List<java.util.Map<String, Object>> categoryDistribution = new java.util.ArrayList<>();
java.util.Map<String, Object> cat1 = new java.util.HashMap<>();
cat1.put("categoryName", "电路维修");
cat1.put("count", 45);
cat1.put("percentage", 28.8);
categoryDistribution.add(cat1);
java.util.Map<String, Object> cat2 = new java.util.HashMap<>();
cat2.put("categoryName", "水管维修");
cat2.put("count", 38);
cat2.put("percentage", 24.4);
categoryDistribution.add(cat2);
stats.put("categoryDistribution", categoryDistribution);
// 紧急程度分布
java.util.List<java.util.Map<String, Object>> priorityDistribution = new java.util.ArrayList<>();
java.util.Map<String, Object> priority1 = new java.util.HashMap<>();
priority1.put("priorityLevel", 1);
priority1.put("count", 12);
priority1.put("percentage", 7.7);
priorityDistribution.add(priority1);
java.util.Map<String, Object> priority2 = new java.util.HashMap<>();
priority2.put("priorityLevel", 2);
priority2.put("count", 34);
priority2.put("percentage", 21.8);
priorityDistribution.add(priority2);
stats.put("priorityDistribution", priorityDistribution);
return R.ok(stats);
}
/**
* 获取维修人员选项
* 返回拥有"维修人员"角色的用户列表
*/
@SaCheckPermission("pm:repairOrder:assign")
@GetMapping("/maintenance-workers")
public R<List<java.util.Map<String, Object>>> getMaintenanceWorkers() {
return R.ok(repairOrderService.getMaintenanceWorkers());
}
/**
* 获取工单进度列表
*/
@SaCheckPermission("pm:repairOrder:progress")
@GetMapping("/{orderId}/progress")
public R<List<java.util.Map<String, Object>>> getRepairProgress(
@NotNull(message = "工单ID不能为空") @PathVariable Long orderId) {
List<java.util.Map<String, Object>> progressList = repairOrderService.getRepairProgress(orderId);
return R.ok(progressList);
}
/**
* 更新维修进度
*/
@SaCheckPermission("pm:repairOrder:updateProgress")
@Log(title = "更新进度", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/progress")
public R<Void> updateProgress(@RequestBody java.util.Map<String, Object> progressData) {
Long orderId = Long.valueOf(progressData.get("orderId").toString());
return toAjax(repairOrderService.updateProgress(orderId, progressData));
}
/**
* 完成工单(新的完成接口,支持详细信息)
*/
@SaCheckPermission("pm:repairOrder:complete")
@Log(title = "完成工单", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping("/{orderId}/complete")
public R<Void> completeOrder(
@NotNull(message = "工单ID不能为空") @PathVariable Long orderId,
@RequestBody java.util.Map<String, Object> completeData) {
String repairResult = (String) completeData.get("repairResult");
String usedMaterials = (String) completeData.get("usedMaterials");
String followSuggestions = (String) completeData.get("followSuggestions");
return toAjax(repairOrderService.completeOrder(orderId, repairResult, usedMaterials, followSuggestions));
}
/**
* 创建服务评价
*/
@SaCheckPermission("pm:repairOrder:evaluate")
@Log(title = "服务评价", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/evaluation")
public R<Void> createEvaluation(@RequestBody java.util.Map<String, Object> evaluationData) {
// 调用service方法保存服务评价
boolean success = repairOrderService.createServiceEvaluation(evaluationData);
return success ? R.ok("服务评价提交成功") : R.fail("服务评价提交失败");
}
/**
* 获取工单的服务评价
*/
@SaCheckPermission("pm:repairOrder:query")
@GetMapping("/{orderId}/evaluation")
public R<java.util.Map<String, Object>> getServiceEvaluation(
@NotNull(message = "工单ID不能为空") @PathVariable Long orderId) {
// 从service获取真实评价数据
java.util.Map<String, Object> evaluation = repairOrderService.getServiceEvaluation(orderId);
return R.ok(evaluation);
}
/**
* 获取工单附件列表
*/
@SaCheckPermission("pm:repairOrder:query")
@GetMapping("/{orderId}/attachments")
public R<List<PmRepairAttachmentVo>> getRepairAttachments(
@NotNull(message = "工单ID不能为空") @PathVariable Long orderId) {
List<PmRepairAttachmentVo> attachments = attachmentService.queryByOrderId(orderId);
return R.ok(attachments);
}
}
@@ -0,0 +1,107 @@
package org.dromara.zhxy.domain;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial;
/**
* 报修附件对象 pm_repair_attachment
*
* @author Cursor AI
* @date 2025-01-23
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("pm_repair_attachment")
public class PmRepairAttachment extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
/**
* 报修工单ID,关联pm_repair_order.id
*/
private Long orderId;
/**
* 文件原始名称
*/
private String fileName;
/**
* 文件存储路径
*/
private String filePath;
/**
* 文件大小(字节)
*/
private Long fileSize;
/**
* 文件类型:image-图片,video-视频
*/
private String fileType;
/**
* 文件扩展名
*/
private String fileExtension;
/**
* 文件MIME类型
*/
private String fileMimeType;
/**
* 上传阶段:1-报修申请,2-维修过程,3-完成确认
*/
private String uploadStage;
/**
* 上传人ID,关联sys_user.id
*/
private Long uploaderId;
/**
* 上传人姓名
*/
private String uploaderName;
/**
* 缩略图路径(图片文件)
*/
private String thumbnailPath;
/**
* 时长(视频文件,秒)
*/
private Integer duration;
/**
* 分辨率(如:1920x1080)
*/
private String resolution;
/**
* 文件描述说明
*/
private String description;
/**
* 排序顺序
*/
private Integer sortOrder;
}
@@ -0,0 +1,124 @@
package org.dromara.zhxy.domain;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
import java.math.BigDecimal;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial;
/**
* 维修类型对象 pm_repair_category
*
* @author Cursor AI
* @date 2025-01-23
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("pm_repair_category")
public class PmRepairCategory extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
/**
* 类型名称
*/
private String categoryName;
/**
* 类型编码
*/
private String categoryCode;
/**
* 类型描述
*/
private String categoryDescription;
/**
* 父级ID,顶级为0
*/
private Long parentId;
/**
* 祖级列表(逗号分隔)
*/
private String ancestorIds;
/**
* 层级深度(1-顶级,2-二级...)
*/
private Integer levelDepth;
/**
* 子类数量
*/
private Integer childrenCount;
/**
* 所需专业技能(逗号分隔)
*/
private String requiredSkills;
/**
* 技能等级要求:1-初级,2-中级,3-高级
*/
private String skillLevel;
/**
* 预估维修时长(分钟)
*/
private Integer estimatedDuration;
/**
* 标准成本(元)
*/
private BigDecimal standardCost;
/**
* 分类图标URL
*/
private String iconUrl;
/**
* 分类颜色代码
*/
private String colorCode;
/**
* 排序顺序
*/
private Integer sortOrder;
/**
* 状态(0-停用,1-正常)
*/
private String status;
/**
* 使用次数统计
*/
private Integer usageCount;
/**
* 最后使用时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date lastUsedTime;
/**
* 备注信息
*/
private String remark;
}
@@ -0,0 +1,178 @@
package org.dromara.zhxy.domain;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
import java.math.BigDecimal;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial;
/**
* 报修工单对象 pm_repair_order
*
* @author Cursor AI
* @date 2025-01-23
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("pm_repair_order")
public class PmRepairOrder extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
/**
* 工单编号,格式:RO+年月日+4位流水号
*/
private String orderNo;
/**
* 报修标题
*/
private String title;
/**
* 问题描述
*/
private String description;
/**
* 报修地点
*/
private String repairLocation;
/**
* 维修类型ID,关联pm_repair_category.id
*/
private Long categoryId;
/**
* 紧急程度:1-非常紧急,2-紧急,3-一般,4-不紧急,5-可延后
*/
private Integer priorityLevel;
/**
* 期望完成时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date expectedFinishTime;
/**
* 报修人ID,关联sys_user.id
*/
private Long reporterId;
/**
* 报修人姓名
*/
private String reporterName;
/**
* 报修人电话
*/
private String reporterPhone;
/**
* 报修人部门
*/
private String reporterDept;
/**
* 工单状态:1-待分派,2-已分派,3-进行中,4-已完成,5-已评价,6-已归档,9-已取消
*/
private String orderStatus;
/**
* 分派时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date assignTime;
/**
* 分派维修员ID,关联sys_user.id
*/
private Long assigneeId;
/**
* 分派维修员姓名
*/
private String assigneeName;
/**
* 分派备注说明
*/
private String assignRemark;
/**
* 开始处理时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime;
/**
* 完成时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date finishTime;
/**
* 总处理时长(分钟)
*/
private Integer totalDuration;
/**
* 维修结果描述
*/
private String repairResult;
/**
* 使用材料清单
*/
private String usedMaterials;
/**
* 后续建议
*/
private String followSuggestions;
/**
* 综合评价得分(1.0-5.0)
*/
private BigDecimal evaluationScore;
/**
* 评价时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date evaluationTime;
/**
* 附件数量
*/
private Integer attachmentCount;
/**
* 进度记录数量
*/
private Integer progressCount;
/**
* 取消原因
*/
private String cancelReason;
/**
* 备注信息
*/
private String remark;
}
@@ -0,0 +1,119 @@
package org.dromara.zhxy.domain;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
import java.math.BigDecimal;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial;
/**
* 维修进度记录实体类
*
* @author Cursor AI
* @date 2025-01-23
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("pm_repair_progress")
public class PmRepairProgress extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
/**
* 报修工单ID,关联pm_repair_order.id
*/
private Long orderId;
/**
* 进度类型:1-工单分派,2-接收确认,3-到达现场,4-开始维修,5-进度更新,6-完成维修,7-用户评价,8-工单归档,9-其他
*/
private String progressType;
/**
* 进度状态描述
*/
private String progressStatus;
/**
* 进度详细描述
*/
private String progressDetail;
/**
* 操作人ID,关联sys_user.id
*/
private Long operatorId;
/**
* 操作人姓名
*/
private String operatorName;
/**
* 操作人角色:user-用户,admin-管理员,worker-维修员
*/
private String operatorRole;
/**
* 操作位置信息
*/
private String locationInfo;
/**
* GPS纬度
*/
private BigDecimal gpsLatitude;
/**
* GPS经度
*/
private BigDecimal gpsLongitude;
/**
* 操作时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date operationTime;
/**
* 预计耗时(分钟)
*/
private Integer estimatedDuration;
/**
* 关联附件ID列表(逗号分隔)
*/
private String attachmentIds;
/**
* 下一步计划
*/
private String nextStep;
/**
* 遇到的问题
*/
private String issuesEncountered;
/**
* 需要的材料
*/
private String materialsNeeded;
/**
* 备注信息
*/
private String remark;
}
@@ -0,0 +1,146 @@
package org.dromara.zhxy.domain;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
import java.math.BigDecimal;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial;
/**
* 服务评价对象 pm_service_evaluation
*
* @author Cursor AI
* @date 2025-01-23
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("pm_service_evaluation")
public class PmServiceEvaluation extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
/**
* 报修工单ID,关联pm_repair_order.id
*/
private Long orderId;
/**
* 评价人ID,关联sys_user.id
*/
private Long evaluatorId;
/**
* 评价人姓名
*/
private String evaluatorName;
/**
* 被评价维修员ID,关联sys_user.id
*/
private Long evaluatedWorkerId;
/**
* 被评价维修员姓名
*/
private String evaluatedWorkerName;
/**
* 综合评价得分(1.0-5.0)
*/
private BigDecimal overallScore;
/**
* 维修质量得分(1.0-5.0)
*/
private BigDecimal qualityScore;
/**
* 服务态度得分(1.0-5.0)
*/
private BigDecimal attitudeScore;
/**
* 响应速度得分(1.0-5.0)
*/
private BigDecimal responseSpeedScore;
/**
* 沟通效果得分(1.0-5.0)
*/
private BigDecimal communicationScore;
/**
* 文字评价内容
*/
private String evaluationContent;
/**
* 满意度等级:1-非常满意,2-满意,3-一般,4-不满意,5-非常不满意
*/
private String satisfactionLevel;
/**
* 是否匿名评价(0-实名,1-匿名)
*/
private Integer isAnonymous;
/**
* 是否公开显示(0-不公开,1-公开)
*/
private Integer isPublic;
/**
* 评价时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date evaluationTime;
/**
* 服务开始时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date serviceStartTime;
/**
* 服务结束时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date serviceEndTime;
/**
* 服务时长(分钟)
*/
private Integer serviceDuration;
/**
* 正面标签(逗号分隔)
*/
private String positiveTags;
/**
* 负面标签(逗号分隔)
*/
private String negativeTags;
/**
* 改进建议
*/
private String improvementSuggestions;
/**
* 备注信息
*/
private String remark;
}
@@ -0,0 +1,115 @@
package org.dromara.zhxy.domain.bo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.zhxy.domain.PmRepairAttachment;
import java.util.Date;
/**
* 报修附件业务对象 pm_repair_attachment
*
* @author Cursor AI
* @date 2025-01-26
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = PmRepairAttachment.class, reverseConvertGenerate = false)
public class PmRepairAttachmentBo extends BaseEntity {
/**
* 主键ID
*/
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
private Long id;
/**
* 报修工单ID
*/
@NotNull(message = "报修工单ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long orderId;
/**
* 文件原始名称
*/
@NotBlank(message = "文件名称不能为空", groups = { AddGroup.class, EditGroup.class })
private String fileName;
/**
* 文件存储路径
*/
@NotBlank(message = "文件路径不能为空", groups = { AddGroup.class, EditGroup.class })
private String filePath;
/**
* 文件大小(字节)
*/
@NotNull(message = "文件大小不能为空", groups = { AddGroup.class, EditGroup.class })
private Long fileSize;
/**
* 文件类型:image-图片,video-视频
*/
@NotBlank(message = "文件类型不能为空", groups = { AddGroup.class, EditGroup.class })
private String fileType;
/**
* 文件扩展名
*/
@NotBlank(message = "文件扩展名不能为空", groups = { AddGroup.class, EditGroup.class })
private String fileExtension;
/**
* 文件MIME类型
*/
private String fileMimeType;
/**
* 上传阶段:1-报修申请,2-维修过程,3-完成确认
*/
@NotBlank(message = "上传阶段不能为空", groups = { AddGroup.class, EditGroup.class })
private String uploadStage;
/**
* 上传人ID
*/
private Long uploaderId;
/**
* 上传人姓名
*/
private String uploaderName;
/**
* 缩略图路径
*/
private String thumbnailPath;
/**
* 时长(视频文件,秒)
*/
private Integer duration;
/**
* 分辨率
*/
private String resolution;
/**
* 文件描述说明
*/
private String description;
/**
* 排序顺序
*/
private Integer sortOrder;
}
@@ -0,0 +1,140 @@
package org.dromara.zhxy.domain.bo;
import org.dromara.zhxy.domain.PmRepairCategory;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import java.util.Date;
import java.math.BigDecimal;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* 维修类型业务对象 pm_repair_category
*
* @author Cursor AI
* @date 2025-01-23
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = PmRepairCategory.class, reverseConvertGenerate = false)
public class PmRepairCategoryBo extends BaseEntity {
/**
* 主键ID
*/
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
private Long id;
/**
* 类型名称
*/
@NotBlank(message = "类型名称不能为空", groups = { AddGroup.class, EditGroup.class })
private String categoryName;
/**
* 类型编码
*/
@NotBlank(message = "类型编码不能为空", groups = { AddGroup.class, EditGroup.class })
private String categoryCode;
/**
* 类型描述
*/
private String categoryDescription;
/**
* 父级ID
*/
@NotNull(message = "上级类型不能为空", groups = { AddGroup.class, EditGroup.class })
private Long parentId;
/**
* 祖级列表
*/
private String ancestorIds;
/**
* 层级深度
*/
private Integer levelDepth;
/**
* 子类数量
*/
private Integer childrenCount;
/**
* 所需专业技能
*/
private String requiredSkills;
/**
* 技能等级要求
*/
@NotBlank(message = "技能等级不能为空", groups = { AddGroup.class, EditGroup.class })
private String skillLevel;
/**
* 预估维修时长(分钟)
*/
private Integer estimatedDuration;
/**
* 标准成本(元)
*/
private BigDecimal standardCost;
/**
* 分类图标URL
*/
private String iconUrl;
/**
* 分类颜色代码
*/
private String colorCode;
/**
* 排序顺序
*/
@NotNull(message = "排序顺序不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer sortOrder;
/**
* 状态
*/
@NotBlank(message = "状态不能为空", groups = { AddGroup.class, EditGroup.class })
private String status;
/**
* 使用次数统计
*/
private Integer usageCount;
/**
* 最后使用时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date lastUsedTime;
/**
* 备注信息
*/
private String remark;
/**
* 状态IN查询(用于状态过滤)
*/
private List<String> statusIn;
/**
* 父级ID IN查询(用于层级过滤)
*/
private List<Long> parentIdIn;
}
@@ -0,0 +1,205 @@
package org.dromara.zhxy.domain.bo;
import org.dromara.zhxy.domain.PmRepairOrder;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import java.util.Date;
import java.math.BigDecimal;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* 报修工单业务对象 pm_repair_order
*
* @author Cursor AI
* @date 2025-01-23
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = PmRepairOrder.class, reverseConvertGenerate = false)
public class PmRepairOrderBo extends BaseEntity {
/**
* 主键ID
*/
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
private Long id;
/**
* 工单编号
*/
private String orderNo;
/**
* 报修标题
*/
@NotBlank(message = "报修标题不能为空", groups = { AddGroup.class, EditGroup.class })
private String title;
/**
* 问题描述
*/
@NotBlank(message = "问题描述不能为空", groups = { AddGroup.class, EditGroup.class })
private String description;
/**
* 报修地点
*/
@NotBlank(message = "报修地点不能为空", groups = { AddGroup.class, EditGroup.class })
private String repairLocation;
/**
* 维修类型ID
*/
@NotNull(message = "维修类型不能为空", groups = { AddGroup.class, EditGroup.class })
private Long categoryId;
/**
* 紧急程度
*/
@NotNull(message = "紧急程度不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer priorityLevel;
/**
* 期望完成时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date expectedFinishTime;
/**
* 报修人ID
*/
private Long reporterId;
/**
* 报修人姓名
*/
@NotBlank(message = "报修人姓名不能为空", groups = { AddGroup.class, EditGroup.class })
private String reporterName;
/**
* 报修人电话
*/
@NotBlank(message = "报修人电话不能为空", groups = { AddGroup.class, EditGroup.class })
private String reporterPhone;
/**
* 报修人部门
*/
private String reporterDept;
/**
* 工单状态
*/
private String orderStatus;
/**
* 分派时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date assignTime;
/**
* 分派维修员ID
*/
private Long assigneeId;
/**
* 分派维修员姓名
*/
private String assigneeName;
/**
* 分派备注说明
*/
private String assignRemark;
/**
* 开始处理时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime;
/**
* 完成时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date finishTime;
/**
* 总处理时长(分钟)
*/
private Integer totalDuration;
/**
* 维修结果描述
*/
private String repairResult;
/**
* 使用材料清单
*/
private String usedMaterials;
/**
* 后续建议
*/
private String followSuggestions;
/**
* 综合评价得分
*/
private BigDecimal evaluationScore;
/**
* 评价时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date evaluationTime;
/**
* 附件数量
*/
private Integer attachmentCount;
/**
* 进度记录数量
*/
private Integer progressCount;
/**
* 取消原因
*/
private String cancelReason;
/**
* 备注信息
*/
private String remark;
/**
* 工单状态IN查询(用于状态过滤)
*/
private List<String> orderStatusIn;
/**
* 维修类型IN查询(用于类型过滤)
*/
private List<Long> categoryIdIn;
/**
* 报修人ID IN查询(用于权限过滤)
*/
private List<Long> reporterIdIn;
/**
* 分派维修员ID IN查询(用于维修员过滤)
*/
private List<Long> assigneeIdIn;
}
@@ -0,0 +1,131 @@
package org.dromara.zhxy.domain.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.zhxy.domain.PmRepairAttachment;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 报修附件视图对象 pm_repair_attachment
*
* @author Cursor AI
* @date 2025-01-26
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = PmRepairAttachment.class)
public class PmRepairAttachmentVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@ExcelProperty(value = "主键ID")
private Long id;
/**
* 报修工单ID
*/
@ExcelProperty(value = "报修工单ID")
private Long orderId;
/**
* 文件原始名称
*/
@ExcelProperty(value = "文件原始名称")
private String fileName;
/**
* 文件存储路径
*/
@ExcelProperty(value = "文件存储路径")
private String filePath;
/**
* 文件大小(字节)
*/
@ExcelProperty(value = "文件大小")
private Long fileSize;
/**
* 文件类型:image-图片,video-视频
*/
@ExcelProperty(value = "文件类型")
private String fileType;
/**
* 文件扩展名
*/
@ExcelProperty(value = "文件扩展名")
private String fileExtension;
/**
* 文件MIME类型
*/
@ExcelProperty(value = "文件MIME类型")
private String fileMimeType;
/**
* 上传阶段:1-报修申请,2-维修过程,3-完成确认
*/
@ExcelProperty(value = "上传阶段")
private String uploadStage;
/**
* 上传人ID
*/
@ExcelProperty(value = "上传人ID")
private Long uploaderId;
/**
* 上传人姓名
*/
@ExcelProperty(value = "上传人姓名")
private String uploaderName;
/**
* 缩略图路径
*/
@ExcelProperty(value = "缩略图路径")
private String thumbnailPath;
/**
* 时长(视频文件,秒)
*/
@ExcelProperty(value = "时长")
private Integer duration;
/**
* 分辨率
*/
@ExcelProperty(value = "分辨率")
private String resolution;
/**
* 文件描述说明
*/
@ExcelProperty(value = "文件描述")
private String description;
/**
* 排序顺序
*/
@ExcelProperty(value = "排序顺序")
private Integer sortOrder;
/**
* 创建时间
*/
@ExcelProperty(value = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
}
@@ -0,0 +1,161 @@
package org.dromara.zhxy.domain.vo;
import java.util.Date;
import java.math.BigDecimal;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.dromara.zhxy.domain.PmRepairCategory;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 维修类型视图对象 pm_repair_category
*
* @author Cursor AI
* @date 2025-01-23
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = PmRepairCategory.class)
public class PmRepairCategoryVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@ExcelProperty(value = "主键ID")
private Long id;
/**
* 类型名称
*/
@ExcelProperty(value = "类型名称")
private String categoryName;
/**
* 类型编码
*/
@ExcelProperty(value = "类型编码")
private String categoryCode;
/**
* 类型描述
*/
@ExcelProperty(value = "类型描述")
private String categoryDescription;
/**
* 父级ID
*/
@ExcelProperty(value = "父级ID")
private Long parentId;
/**
* 祖级列表
*/
@ExcelProperty(value = "祖级列表")
private String ancestorIds;
/**
* 层级深度
*/
@ExcelProperty(value = "层级深度")
private Integer levelDepth;
/**
* 子类数量
*/
@ExcelProperty(value = "子类数量")
private Integer childrenCount;
/**
* 所需专业技能
*/
@ExcelProperty(value = "所需技能")
private String requiredSkills;
/**
* 技能等级要求
*/
@ExcelProperty(value = "技能等级", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "pm_skill_level")
private String skillLevel;
/**
* 预估维修时长(分钟)
*/
@ExcelProperty(value = "预估时长(分钟)")
private Integer estimatedDuration;
/**
* 标准成本(元)
*/
@ExcelProperty(value = "标准成本(元)")
private BigDecimal standardCost;
/**
* 分类图标URL
*/
@ExcelProperty(value = "图标URL")
private String iconUrl;
/**
* 分类颜色代码
*/
@ExcelProperty(value = "颜色代码")
private String colorCode;
/**
* 排序顺序
*/
@ExcelProperty(value = "排序")
private Integer sortOrder;
/**
* 状态
*/
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "sys_normal_disable")
private String status;
/**
* 使用次数统计
*/
@ExcelProperty(value = "使用次数")
private Integer usageCount;
/**
* 最后使用时间
*/
@ExcelProperty(value = "最后使用时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date lastUsedTime;
/**
* 备注信息
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 创建时间
*/
@ExcelProperty(value = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/**
* 子分类列表(用于树形结构)
*/
private List<PmRepairCategoryVo> children;
}
@@ -0,0 +1,225 @@
package org.dromara.zhxy.domain.vo;
import java.util.Date;
import java.math.BigDecimal;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.dromara.zhxy.domain.PmRepairOrder;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 报修工单视图对象 pm_repair_order
*
* @author Cursor AI
* @date 2025-01-23
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = PmRepairOrder.class)
public class PmRepairOrderVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@ExcelProperty(value = "主键ID")
private Long id;
/**
* 工单编号
*/
@ExcelProperty(value = "工单编号")
private String orderNo;
/**
* 报修标题
*/
@ExcelProperty(value = "报修标题")
private String title;
/**
* 问题描述
*/
@ExcelProperty(value = "问题描述")
private String description;
/**
* 报修地点
*/
@ExcelProperty(value = "报修地点")
private String repairLocation;
/**
* 维修类型ID
*/
@ExcelProperty(value = "维修类型ID")
private Long categoryId;
/**
* 维修类型名称
*/
@ExcelProperty(value = "维修类型")
private String categoryName;
/**
* 紧急程度
*/
@ExcelProperty(value = "紧急程度", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "pm_priority_level")
private Integer priorityLevel;
/**
* 期望完成时间
*/
@ExcelProperty(value = "期望完成时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date expectedFinishTime;
/**
* 报修人ID
*/
@ExcelProperty(value = "报修人ID")
private Long reporterId;
/**
* 报修人姓名
*/
@ExcelProperty(value = "报修人")
private String reporterName;
/**
* 报修人电话
*/
@ExcelProperty(value = "联系电话")
private String reporterPhone;
/**
* 报修人部门
*/
@ExcelProperty(value = "报修部门")
private String reporterDept;
/**
* 工单状态
*/
@ExcelProperty(value = "工单状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "pm_order_status")
private String orderStatus;
/**
* 分派时间
*/
@ExcelProperty(value = "分派时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date assignTime;
/**
* 分派维修员ID
*/
@ExcelProperty(value = "维修员ID")
private Long assigneeId;
/**
* 分派维修员姓名
*/
@ExcelProperty(value = "维修员")
private String assigneeName;
/**
* 分派备注说明
*/
@ExcelProperty(value = "分派备注")
private String assignRemark;
/**
* 开始处理时间
*/
@ExcelProperty(value = "开始时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime;
/**
* 完成时间
*/
@ExcelProperty(value = "完成时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date finishTime;
/**
* 总处理时长(分钟)
*/
@ExcelProperty(value = "处理时长(分钟)")
private Integer totalDuration;
/**
* 维修结果描述
*/
@ExcelProperty(value = "维修结果")
private String repairResult;
/**
* 使用材料清单
*/
@ExcelProperty(value = "使用材料")
private String usedMaterials;
/**
* 后续建议
*/
@ExcelProperty(value = "后续建议")
private String followSuggestions;
/**
* 综合评价得分
*/
@ExcelProperty(value = "评价得分")
private BigDecimal evaluationScore;
/**
* 评价时间
*/
@ExcelProperty(value = "评价时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date evaluationTime;
/**
* 附件数量
*/
@ExcelProperty(value = "附件数量")
private Integer attachmentCount;
/**
* 进度记录数量
*/
@ExcelProperty(value = "进度记录数")
private Integer progressCount;
/**
* 取消原因
*/
@ExcelProperty(value = "取消原因")
private String cancelReason;
/**
* 备注信息
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 创建时间
*/
@ExcelProperty(value = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
}
@@ -0,0 +1,15 @@
package org.dromara.zhxy.mapper;
import org.dromara.zhxy.domain.PmRepairAttachment;
import org.dromara.zhxy.domain.vo.PmRepairAttachmentVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 报修附件Mapper接口
*
* @author Cursor AI
* @date 2025-01-26
*/
public interface PmRepairAttachmentMapper extends BaseMapperPlus<PmRepairAttachment, PmRepairAttachmentVo> {
}
@@ -0,0 +1,15 @@
package org.dromara.zhxy.mapper;
import org.dromara.zhxy.domain.PmRepairCategory;
import org.dromara.zhxy.domain.vo.PmRepairCategoryVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 维修类型Mapper接口
*
* @author Cursor AI
* @date 2025-01-23
*/
public interface PmRepairCategoryMapper extends BaseMapperPlus<PmRepairCategory, PmRepairCategoryVo> {
}
@@ -0,0 +1,25 @@
package org.dromara.zhxy.mapper;
import org.dromara.zhxy.domain.PmRepairOrder;
import org.dromara.zhxy.domain.vo.PmRepairOrderVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import java.util.List;
import java.util.Map;
/**
* 报修工单Mapper接口
*
* @author Cursor AI
* @date 2025-01-23
*/
public interface PmRepairOrderMapper extends BaseMapperPlus<PmRepairOrder, PmRepairOrderVo> {
/**
* 查询拥有"维修人员"角色的用户列表
*
* @return 维修人员选项列表
*/
List<Map<String, Object>> selectMaintenanceWorkers();
}
@@ -0,0 +1,14 @@
package org.dromara.zhxy.mapper;
import org.dromara.zhxy.domain.PmRepairProgress;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 维修进度记录Mapper接口
*
* @author Cursor AI
* @date 2025-01-26
*/
public interface PmRepairProgressMapper extends BaseMapperPlus<PmRepairProgress, PmRepairProgress> {
}
@@ -0,0 +1,14 @@
package org.dromara.zhxy.mapper;
import org.dromara.zhxy.domain.PmServiceEvaluation;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 服务评价Mapper接口
*
* @author Cursor AI
* @date 2025-01-26
*/
public interface PmServiceEvaluationMapper extends BaseMapperPlus<PmServiceEvaluation, PmServiceEvaluation> {
}
@@ -0,0 +1,76 @@
package org.dromara.zhxy.service;
import org.dromara.zhxy.domain.vo.PmRepairAttachmentVo;
import org.dromara.zhxy.domain.bo.PmRepairAttachmentBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.springframework.web.multipart.MultipartFile;
import java.util.Collection;
import java.util.List;
/**
* 报修附件Service接口
*
* @author Cursor AI
* @date 2025-01-26
*/
public interface IPmRepairAttachmentService {
/**
* 查询报修附件
*/
PmRepairAttachmentVo queryById(Long id);
/**
* 查询报修附件列表
*/
TableDataInfo<PmRepairAttachmentVo> queryPageList(PmRepairAttachmentBo bo, PageQuery pageQuery);
/**
* 查询报修附件列表
*/
List<PmRepairAttachmentVo> queryList(PmRepairAttachmentBo bo);
/**
* 根据工单ID查询附件列表
*/
List<PmRepairAttachmentVo> queryByOrderId(Long orderId);
/**
* 新增报修附件
*/
Boolean insertByBo(PmRepairAttachmentBo bo);
/**
* 修改报修附件
*/
Boolean updateByBo(PmRepairAttachmentBo bo);
/**
* 校验并批量删除报修附件信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 上传附件文件
*/
PmRepairAttachmentVo uploadFile(Long orderId, String uploadStage, MultipartFile file, String description);
/**
* 批量上传附件文件
*/
List<PmRepairAttachmentVo> uploadFiles(Long orderId, String uploadStage, MultipartFile[] files,
List<String> descriptions);
/**
* 删除附件文件(包括物理文件和数据库记录)
*/
Boolean deleteAttachment(Long id);
/**
* 更新工单的附件数量
*/
void updateOrderAttachmentCount(Long orderId);
}
@@ -0,0 +1,84 @@
package org.dromara.zhxy.service;
import org.dromara.zhxy.domain.vo.PmRepairCategoryVo;
import org.dromara.zhxy.domain.bo.PmRepairCategoryBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 维修类型Service接口
*
* @author Cursor AI
* @date 2025-01-23
*/
public interface IPmRepairCategoryService {
/**
* 查询维修类型
*
* @param id 主键
* @return 维修类型
*/
PmRepairCategoryVo queryById(Long id);
/**
* 分页查询维修类型列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 维修类型分页列表
*/
TableDataInfo<PmRepairCategoryVo> queryPageList(PmRepairCategoryBo bo, PageQuery pageQuery);
/**
* 查询符合条件的维修类型列表
*
* @param bo 查询条件
* @return 维修类型列表
*/
List<PmRepairCategoryVo> queryList(PmRepairCategoryBo bo);
/**
* 新增维修类型
*
* @param bo 维修类型
* @return 是否新增成功
*/
Boolean insertByBo(PmRepairCategoryBo bo);
/**
* 修改维修类型
*
* @param bo 维修类型
* @return 是否修改成功
*/
Boolean updateByBo(PmRepairCategoryBo bo);
/**
* 校验并批量删除维修类型信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 获取维修类型树形结构
*
* @return 维修类型树形列表
*/
List<PmRepairCategoryVo> queryTree();
/**
* 更新使用次数
*
* @param categoryId 类型ID
* @return 是否成功
*/
Boolean updateUsageCount(Long categoryId);
}
@@ -0,0 +1,168 @@
package org.dromara.zhxy.service;
import org.dromara.zhxy.domain.vo.PmRepairOrderVo;
import org.dromara.zhxy.domain.bo.PmRepairOrderBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 报修工单Service接口
*
* @author Cursor AI
* @date 2025-01-23
*/
public interface IPmRepairOrderService {
/**
* 查询报修工单
*
* @param id 主键
* @return 报修工单
*/
PmRepairOrderVo queryById(Long id);
/**
* 分页查询报修工单列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 报修工单分页列表
*/
TableDataInfo<PmRepairOrderVo> queryPageList(PmRepairOrderBo bo, PageQuery pageQuery);
/**
* 查询符合条件的报修工单列表
*
* @param bo 查询条件
* @return 报修工单列表
*/
List<PmRepairOrderVo> queryList(PmRepairOrderBo bo);
/**
* 新增报修工单
*
* @param bo 报修工单
* @return 是否新增成功
*/
Boolean insertByBo(PmRepairOrderBo bo);
/**
* 修改报修工单
*
* @param bo 报修工单
* @return 是否修改成功
*/
Boolean updateByBo(PmRepairOrderBo bo);
/**
* 校验并批量删除报修工单信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 分派工单
*
* @param orderId 工单ID
* @param assigneeId 维修员ID
* @param assignRemark 分派备注
* @return 是否分派成功
*/
Boolean assignOrder(Long orderId, Long assigneeId, String assignRemark);
/**
* 开始维修
*
* @param orderId 工单ID
* @return 是否成功
*/
Boolean startRepair(Long orderId);
/**
* 完成维修
*
* @param orderId 工单ID
* @param repairResult 维修结果
* @param usedMaterials 使用材料
* @return 是否成功
*/
Boolean finishRepair(Long orderId, String repairResult, String usedMaterials);
/**
* 取消工单
*
* @param orderId 工单ID
* @param cancelReason 取消原因
* @return 是否成功
*/
Boolean cancelOrder(Long orderId, String cancelReason);
/**
* 生成工单编号
*
* @return 工单编号
*/
String generateOrderNo();
/**
* 获取维修人员选项
* 返回拥有"维修人员"角色的用户列表
*
* @return 维修人员选项列表
*/
List<java.util.Map<String, Object>> getMaintenanceWorkers();
/**
* 更新维修进度
* 同时处理工单状态自动流转:首次更新进度时将状态从"已分派"改为"进行中"
*
* @param orderId 工单ID
* @param progressData 进度数据
* @return 是否成功
*/
Boolean updateProgress(Long orderId, java.util.Map<String, Object> progressData);
/**
* 获取工单进度列表
*
* @param orderId 工单ID
* @return 进度记录列表
*/
List<java.util.Map<String, Object>> getRepairProgress(Long orderId);
/**
* 完成工单(详细版)
* 支持详细的完成信息,将工单状态从"进行中"改为"已完成"
*
* @param orderId 工单ID
* @param repairResult 维修结果
* @param usedMaterials 使用材料
* @param followSuggestions 后续建议
* @return 是否成功
*/
Boolean completeOrder(Long orderId, String repairResult, String usedMaterials, String followSuggestions);
/**
* 创建服务评价
* 保存服务评价数据并将工单状态从"已完成"更新为"已评价"
*
* @param evaluationData 评价数据
* @return 是否成功
*/
Boolean createServiceEvaluation(java.util.Map<String, Object> evaluationData);
/**
* 获取工单的服务评价
*
* @param orderId 工单ID
* @return 服务评价数据
*/
java.util.Map<String, Object> getServiceEvaluation(Long orderId);
}
@@ -0,0 +1,327 @@
package org.dromara.zhxy.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.oss.core.OssClient;
import org.dromara.common.oss.entity.UploadResult;
import org.dromara.common.oss.factory.OssFactory;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.zhxy.domain.PmRepairAttachment;
import org.dromara.zhxy.domain.bo.PmRepairAttachmentBo;
import org.dromara.zhxy.domain.vo.PmRepairAttachmentVo;
import org.dromara.zhxy.mapper.PmRepairAttachmentMapper;
import org.dromara.zhxy.mapper.PmRepairOrderMapper;
import org.dromara.zhxy.service.IPmRepairAttachmentService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* 报修附件Service业务层处理
*
* @author Cursor AI
* @date 2025-01-26
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class PmRepairAttachmentServiceImpl implements IPmRepairAttachmentService {
private final PmRepairAttachmentMapper baseMapper;
private final PmRepairOrderMapper repairOrderMapper;
/**
* 查询报修附件
*/
@Override
public PmRepairAttachmentVo queryById(Long id) {
return baseMapper.selectVoById(id);
}
/**
* 查询报修附件列表
*/
@Override
public TableDataInfo<PmRepairAttachmentVo> queryPageList(PmRepairAttachmentBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<PmRepairAttachment> lqw = buildQueryWrapper(bo);
Page<PmRepairAttachmentVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询报修附件列表
*/
@Override
public List<PmRepairAttachmentVo> queryList(PmRepairAttachmentBo bo) {
LambdaQueryWrapper<PmRepairAttachment> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
/**
* 根据工单ID查询附件列表
*/
@Override
public List<PmRepairAttachmentVo> queryByOrderId(Long orderId) {
LambdaQueryWrapper<PmRepairAttachment> lqw = Wrappers.lambdaQuery();
lqw.eq(PmRepairAttachment::getOrderId, orderId);
lqw.orderByAsc(PmRepairAttachment::getSortOrder)
.orderByAsc(PmRepairAttachment::getCreateTime);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<PmRepairAttachment> buildQueryWrapper(PmRepairAttachmentBo bo) {
LambdaQueryWrapper<PmRepairAttachment> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getOrderId() != null, PmRepairAttachment::getOrderId, bo.getOrderId());
lqw.like(StringUtils.isNotBlank(bo.getFileName()), PmRepairAttachment::getFileName, bo.getFileName());
lqw.eq(StringUtils.isNotBlank(bo.getFileType()), PmRepairAttachment::getFileType, bo.getFileType());
lqw.eq(StringUtils.isNotBlank(bo.getUploadStage()), PmRepairAttachment::getUploadStage, bo.getUploadStage());
lqw.eq(bo.getUploaderId() != null, PmRepairAttachment::getUploaderId, bo.getUploaderId());
lqw.orderByAsc(PmRepairAttachment::getSortOrder).orderByDesc(PmRepairAttachment::getCreateTime);
return lqw;
}
/**
* 新增报修附件
*/
@Override
public Boolean insertByBo(PmRepairAttachmentBo bo) {
PmRepairAttachment add = MapstructUtils.convert(bo, PmRepairAttachment.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
// 更新工单附件数量
updateOrderAttachmentCount(add.getOrderId());
}
return flag;
}
/**
* 修改报修附件
*/
@Override
public Boolean updateByBo(PmRepairAttachmentBo bo) {
PmRepairAttachment update = MapstructUtils.convert(bo, PmRepairAttachment.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(PmRepairAttachment entity) {
// 设置默认值
if (entity.getSortOrder() == null) {
entity.setSortOrder(0);
}
if (StringUtils.isBlank(entity.getUploadStage())) {
entity.setUploadStage("1"); // 默认报修申请阶段
}
if (entity.getUploaderId() == null) {
entity.setUploaderId(LoginHelper.getUserId());
}
if (StringUtils.isBlank(entity.getUploaderName())) {
entity.setUploaderName(LoginHelper.getUsername());
}
}
/**
* 批量删除报修附件
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
// 先获取要删除的附件信息(在删除前)
List<PmRepairAttachmentVo> attachments = new ArrayList<>();
for (Long id : ids) {
PmRepairAttachmentVo attachment = baseMapper.selectVoById(id);
if (attachment != null) {
attachments.add(attachment);
}
}
if (isValid) {
// 删除OSS文件
for (PmRepairAttachmentVo attachment : attachments) {
try {
if (StringUtils.isNotBlank(attachment.getFilePath())) {
OssFactory.instance().delete(attachment.getFilePath());
}
// 删除缩略图
if (StringUtils.isNotBlank(attachment.getThumbnailPath())) {
OssFactory.instance().delete(attachment.getThumbnailPath());
}
} catch (Exception e) {
log.warn("删除OSS文件失败: {}", e.getMessage());
}
}
}
boolean flag = baseMapper.deleteBatchIds(ids) > 0;
if (flag) {
// 更新相关工单的附件数量
attachments.stream()
.map(PmRepairAttachmentVo::getOrderId)
.distinct()
.forEach(this::updateOrderAttachmentCount);
}
return flag;
}
/**
* 上传附件文件
*/
@Override
@Transactional(rollbackFor = Exception.class)
public PmRepairAttachmentVo uploadFile(Long orderId, String uploadStage, MultipartFile file, String description) {
try {
// 文件基本信息
String originalFilename = file.getOriginalFilename();
String fileExtension = StrUtil.subAfter(originalFilename, ".", true);
String contentType = file.getContentType();
long fileSize = file.getSize();
// 上传文件到OSS
UploadResult uploadResult = OssFactory.instance().uploadSuffix(file.getBytes(), fileExtension, contentType);
// 构建附件信息
PmRepairAttachmentBo bo = new PmRepairAttachmentBo();
bo.setOrderId(orderId);
bo.setFileName(originalFilename);
bo.setFilePath(uploadResult.getUrl());
bo.setFileSize(fileSize);
bo.setFileType(getFileType(contentType));
bo.setFileExtension(fileExtension);
bo.setFileMimeType(contentType);
bo.setUploadStage(uploadStage);
bo.setDescription(description);
bo.setUploaderId(LoginHelper.getUserId());
bo.setUploaderName(LoginHelper.getUsername());
// 保存到数据库
Boolean success = insertByBo(bo);
if (success) {
return queryById(bo.getId());
} else {
throw new RuntimeException("保存附件信息失败");
}
} catch (IOException e) {
log.error("上传附件失败: {}", e.getMessage(), e);
throw new RuntimeException("上传附件失败: " + e.getMessage());
}
}
/**
* 批量上传附件文件
*/
@Override
@Transactional(rollbackFor = Exception.class)
public List<PmRepairAttachmentVo> uploadFiles(Long orderId, String uploadStage, MultipartFile[] files,
List<String> descriptions) {
List<PmRepairAttachmentVo> results = new ArrayList<>();
for (int i = 0; i < files.length; i++) {
MultipartFile file = files[i];
String description = (descriptions != null && i < descriptions.size()) ? descriptions.get(i) : null;
try {
PmRepairAttachmentVo result = uploadFile(orderId, uploadStage, file, description);
results.add(result);
} catch (Exception e) {
log.error("批量上传第{}个文件失败: {}", i + 1, e.getMessage());
throw new RuntimeException("批量上传第" + (i + 1) + "个文件失败: " + e.getMessage());
}
}
return results;
}
/**
* 删除附件文件
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deleteAttachment(Long id) {
PmRepairAttachmentVo attachment = queryById(id);
if (attachment == null) {
return false;
}
// 删除OSS文件
try {
if (StringUtils.isNotBlank(attachment.getFilePath())) {
OssFactory.instance().delete(attachment.getFilePath());
}
if (StringUtils.isNotBlank(attachment.getThumbnailPath())) {
OssFactory.instance().delete(attachment.getThumbnailPath());
}
} catch (Exception e) {
log.warn("删除OSS文件失败: {}", e.getMessage());
}
// 删除数据库记录
boolean flag = baseMapper.deleteById(id) > 0;
if (flag) {
// 更新工单附件数量
updateOrderAttachmentCount(attachment.getOrderId());
}
return flag;
}
/**
* 更新工单的附件数量
*/
@Override
public void updateOrderAttachmentCount(Long orderId) {
if (orderId == null) {
return;
}
LambdaQueryWrapper<PmRepairAttachment> lqw = Wrappers.lambdaQuery();
lqw.eq(PmRepairAttachment::getOrderId, orderId);
long count = baseMapper.selectCount(lqw);
// 更新工单的附件数量
LambdaUpdateWrapper<org.dromara.zhxy.domain.PmRepairOrder> updateWrapper = Wrappers.lambdaUpdate();
updateWrapper.eq(org.dromara.zhxy.domain.PmRepairOrder::getId, orderId)
.set(org.dromara.zhxy.domain.PmRepairOrder::getAttachmentCount, (int) count);
repairOrderMapper.update(null, updateWrapper);
}
/**
* 根据MIME类型获取文件类型
*/
private String getFileType(String mimeType) {
if (StringUtils.isBlank(mimeType)) {
return "other";
}
if (mimeType.startsWith("image/")) {
return "image";
} else if (mimeType.startsWith("video/")) {
return "video";
} else if (mimeType.startsWith("audio/")) {
return "audio";
} else if (mimeType.contains("pdf") || mimeType.contains("doc") || mimeType.contains("txt")) {
return "document";
} else {
return "other";
}
}
}
@@ -0,0 +1,297 @@
package org.dromara.zhxy.service.impl;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import cn.hutool.core.collection.CollUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.dromara.zhxy.domain.bo.PmRepairCategoryBo;
import org.dromara.zhxy.domain.vo.PmRepairCategoryVo;
import org.dromara.zhxy.domain.PmRepairCategory;
import org.dromara.zhxy.mapper.PmRepairCategoryMapper;
import org.dromara.zhxy.service.IPmRepairCategoryService;
import org.dromara.common.core.exception.ServiceException;
import java.util.List;
import java.util.Collection;
import java.util.Date;
import java.util.stream.Collectors;
/**
* 维修类型Service业务层处理
*
* @author Cursor AI
* @date 2025-01-23
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class PmRepairCategoryServiceImpl implements IPmRepairCategoryService {
private final PmRepairCategoryMapper baseMapper;
/**
* 查询维修类型
*
* @param id 主键
* @return 维修类型
*/
@Override
public PmRepairCategoryVo queryById(Long id) {
return baseMapper.selectVoById(id);
}
/**
* 分页查询维修类型列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 维修类型分页列表
*/
@Override
public TableDataInfo<PmRepairCategoryVo> queryPageList(PmRepairCategoryBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<PmRepairCategory> lqw = buildQueryWrapper(bo);
Page<PmRepairCategoryVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询符合条件的维修类型列表
*
* @param bo 查询条件
* @return 维修类型列表
*/
@Override
public List<PmRepairCategoryVo> queryList(PmRepairCategoryBo bo) {
LambdaQueryWrapper<PmRepairCategory> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<PmRepairCategory> buildQueryWrapper(PmRepairCategoryBo bo) {
LambdaQueryWrapper<PmRepairCategory> lqw = Wrappers.lambdaQuery();
lqw.orderByAsc(PmRepairCategory::getSortOrder).orderByAsc(PmRepairCategory::getId);
lqw.like(StringUtils.isNotBlank(bo.getCategoryName()), PmRepairCategory::getCategoryName, bo.getCategoryName());
lqw.eq(StringUtils.isNotBlank(bo.getCategoryCode()), PmRepairCategory::getCategoryCode, bo.getCategoryCode());
lqw.like(StringUtils.isNotBlank(bo.getCategoryDescription()), PmRepairCategory::getCategoryDescription,
bo.getCategoryDescription());
lqw.eq(bo.getParentId() != null, PmRepairCategory::getParentId, bo.getParentId());
lqw.eq(bo.getLevelDepth() != null, PmRepairCategory::getLevelDepth, bo.getLevelDepth());
lqw.eq(StringUtils.isNotBlank(bo.getSkillLevel()), PmRepairCategory::getSkillLevel, bo.getSkillLevel());
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), PmRepairCategory::getStatus, bo.getStatus());
// IN查询条件
lqw.in(CollUtil.isNotEmpty(bo.getStatusIn()), PmRepairCategory::getStatus, bo.getStatusIn());
lqw.in(CollUtil.isNotEmpty(bo.getParentIdIn()), PmRepairCategory::getParentId, bo.getParentIdIn());
return lqw;
}
/**
* 新增维修类型
*
* @param bo 维修类型
* @return 是否新增成功
*/
@Override
public Boolean insertByBo(PmRepairCategoryBo bo) {
PmRepairCategory add = MapstructUtils.convert(bo, PmRepairCategory.class);
validEntityBeforeSave(add);
// 设置层级信息
if (add.getParentId() == null) {
add.setParentId(0L);
}
// 设置层级深度和祖级列表
buildHierarchyInfo(add);
// 设置默认值
if (add.getSortOrder() == null) {
add.setSortOrder(0);
}
if (StringUtils.isBlank(add.getStatus())) {
add.setStatus("1");
}
if (StringUtils.isBlank(add.getColorCode())) {
add.setColorCode("#FFB020");
}
add.setUsageCount(0);
add.setChildrenCount(0);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
// 更新父级的子类数量
updateParentChildrenCount(add.getParentId());
}
return flag;
}
/**
* 修改维修类型
*
* @param bo 维修类型
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(PmRepairCategoryBo bo) {
PmRepairCategory update = MapstructUtils.convert(bo, PmRepairCategory.class);
validEntityBeforeSave(update);
// 如果修改了父级,需要重新计算层级信息
PmRepairCategory oldEntity = baseMapper.selectById(update.getId());
if (oldEntity != null && !oldEntity.getParentId().equals(update.getParentId())) {
buildHierarchyInfo(update);
// 更新新旧父级的子类数量
updateParentChildrenCount(oldEntity.getParentId());
updateParentChildrenCount(update.getParentId());
}
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(PmRepairCategory entity) {
// 校验类型编码唯一性
if (StringUtils.isNotBlank(entity.getCategoryCode())) {
LambdaQueryWrapper<PmRepairCategory> lqw = Wrappers.lambdaQuery();
lqw.eq(PmRepairCategory::getCategoryCode, entity.getCategoryCode());
if (entity.getId() != null) {
lqw.ne(PmRepairCategory::getId, entity.getId());
}
boolean exists = baseMapper.exists(lqw);
if (exists) {
throw new ServiceException("类型编码已存在");
}
}
// 校验不能将自己设为父级
if (entity.getId() != null && entity.getId().equals(entity.getParentId())) {
throw new ServiceException("不能将自己设为父级");
}
}
/**
* 构建层级信息
*/
private void buildHierarchyInfo(PmRepairCategory entity) {
if (entity.getParentId() == null || entity.getParentId() == 0L) {
entity.setParentId(0L);
entity.setLevelDepth(1);
entity.setAncestorIds("0");
} else {
PmRepairCategory parent = baseMapper.selectById(entity.getParentId());
if (parent != null) {
entity.setLevelDepth(parent.getLevelDepth() + 1);
entity.setAncestorIds(parent.getAncestorIds() + "," + parent.getId());
}
}
}
/**
* 更新父级的子类数量
*/
private void updateParentChildrenCount(Long parentId) {
if (parentId == null || parentId == 0L) {
return;
}
LambdaQueryWrapper<PmRepairCategory> lqw = Wrappers.lambdaQuery();
lqw.eq(PmRepairCategory::getParentId, parentId);
long count = baseMapper.selectCount(lqw);
PmRepairCategory parent = new PmRepairCategory();
parent.setId(parentId);
parent.setChildrenCount((int) count);
baseMapper.updateById(parent);
}
/**
* 校验并批量删除维修类型信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// 校验是否有子类
for (Long id : ids) {
PmRepairCategory category = baseMapper.selectById(id);
if (category != null && category.getChildrenCount() > 0) {
throw new ServiceException("存在子类型,不允许删除:" + category.getCategoryName());
}
}
}
// 删除后更新父级的子类数量
List<PmRepairCategory> categories = baseMapper.selectBatchIds(ids);
boolean flag = baseMapper.deleteByIds(ids) > 0;
if (flag) {
for (PmRepairCategory category : categories) {
updateParentChildrenCount(category.getParentId());
}
}
return flag;
}
/**
* 获取维修类型树形结构
*
* @return 维修类型树形列表
*/
@Override
public List<PmRepairCategoryVo> queryTree() {
LambdaQueryWrapper<PmRepairCategory> lqw = Wrappers.lambdaQuery();
lqw.eq(PmRepairCategory::getStatus, "1");
lqw.orderByAsc(PmRepairCategory::getSortOrder).orderByAsc(PmRepairCategory::getId);
List<PmRepairCategoryVo> allList = baseMapper.selectVoList(lqw);
return buildTree(allList, 0L);
}
/**
* 构建树形结构
*/
private List<PmRepairCategoryVo> buildTree(List<PmRepairCategoryVo> allList, Long parentId) {
return allList.stream()
.filter(item -> parentId.equals(item.getParentId()))
.map(item -> {
List<PmRepairCategoryVo> children = buildTree(allList, item.getId());
item.setChildren(children);
return item;
})
.collect(Collectors.toList());
}
/**
* 更新使用次数
*
* @param categoryId 类型ID
* @return 是否成功
*/
@Override
public Boolean updateUsageCount(Long categoryId) {
PmRepairCategory category = baseMapper.selectById(categoryId);
if (category == null) {
return false;
}
PmRepairCategory update = new PmRepairCategory();
update.setId(categoryId);
update.setUsageCount(category.getUsageCount() + 1);
update.setLastUsedTime(new Date());
return baseMapper.updateById(update) > 0;
}
}