工单流程VO渲染效果

This commit is contained in:
2025-12-31 12:45:26 +08:00
parent 1ef1b32f5f
commit 4f0eeede37
17 changed files with 184 additions and 272 deletions

View File

@@ -3,6 +3,7 @@ package org.xyzh.api.workcase.service;
import org.xyzh.api.workcase.dto.TbWorkcaseDTO;
import org.xyzh.api.workcase.dto.TbWorkcaseDeviceDTO;
import org.xyzh.api.workcase.dto.TbWorkcaseProcessDTO;
import org.xyzh.api.workcase.vo.WorkcaseProcessVO;
import org.xyzh.common.core.domain.ResultDomain;
import org.xyzh.common.core.page.PageRequest;
@@ -110,7 +111,7 @@ public interface WorkcaseService {
* @author yslg
* @since 2025-12-19
*/
ResultDomain<TbWorkcaseProcessDTO> getWorkcaseProcessList(TbWorkcaseProcessDTO filter);
ResultDomain<WorkcaseProcessVO> getWorkcaseProcessList(TbWorkcaseProcessDTO filter);
/**
* @description 获取工单处理过程分页
@@ -118,7 +119,7 @@ public interface WorkcaseService {
* @author yslg
* @since 2025-12-19
*/
ResultDomain<TbWorkcaseProcessDTO> getWorkcaseProcessPage(PageRequest<TbWorkcaseProcessDTO> pageRequest);
ResultDomain<WorkcaseProcessVO> getWorkcaseProcessPage(PageRequest<TbWorkcaseProcessDTO> pageRequest);
// ====================== 工单设备管理 ======================
/**

View File

@@ -1,59 +0,0 @@
package org.xyzh.api.workcase.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.xyzh.common.vo.BaseVO;
import io.swagger.v3.oas.annotations.media.Schema;
import com.alibaba.fastjson2.annotation.JSONField;
import java.util.Date;
/**
* 工单列表VO
* 用于前端列表展示(简化版)
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Schema(description = "工单列表VO")
public class TicketListVO extends BaseVO {
private static final long serialVersionUID = 1L;
@Schema(description = "工单ID")
private String ticketId;
@Schema(description = "工单编号")
private String ticketNo;
@Schema(description = "客户姓名")
private String customerName;
@Schema(description = "工单标题")
private String title;
@Schema(description = "工单类型名称")
private String ticketTypeName;
@Schema(description = "优先级")
private String priority;
@Schema(description = "优先级名称")
private String priorityName;
@Schema(description = "工单状态")
private String ticketStatus;
@Schema(description = "工单状态名称")
private String ticketStatusName;
@Schema(description = "处理人姓名")
private String assignedToName;
@Schema(description = "SLA截止时间", format = "date-time")
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date slaDeadline;
@Schema(description = "是否逾期", defaultValue = "false")
private Boolean isOverdue;
@Schema(description = "创建者姓名")
private String creatorName;
}

View File

@@ -1,151 +0,0 @@
package org.xyzh.api.workcase.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.xyzh.common.vo.BaseVO;
import io.swagger.v3.oas.annotations.media.Schema;
import com.alibaba.fastjson2.annotation.JSONField;
import com.fasterxml.jackson.databind.JsonNode;
import java.util.Date;
import java.util.List;
/**
* 工单VO
* 用于前端展示工单信息
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Schema(description = "工单VO")
public class TicketVO extends BaseVO {
private static final long serialVersionUID = 1L;
@Schema(description = "工单ID")
private String ticketId;
@Schema(description = "工单编号")
private String ticketNo;
@Schema(description = "客户ID")
private String customerId;
@Schema(description = "客户姓名")
private String customerName;
@Schema(description = "客户电话")
private String customerPhone;
@Schema(description = "关联会话ID")
private String conversationId;
@Schema(description = "工单类型")
private String ticketType;
@Schema(description = "工单类型名称")
private String ticketTypeName;
@Schema(description = "工单分类")
private String ticketCategory;
@Schema(description = "优先级")
private String priority;
@Schema(description = "优先级名称")
private String priorityName;
@Schema(description = "优先级颜色")
private String priorityColor;
@Schema(description = "工单标题")
private String title;
@Schema(description = "问题描述")
private String description;
@Schema(description = "附件ID数组")
private List<String> attachments;
@Schema(description = "附件数量")
private Integer attachmentCount;
@Schema(description = "工单来源")
private String ticketSource;
@Schema(description = "工单来源名称")
private String ticketSourceName;
@Schema(description = "分配给处理人ID")
private String assignedTo;
@Schema(description = "处理人姓名")
private String assignedToName;
@Schema(description = "分配部门")
private String assignedDept;
@Schema(description = "分配部门名称")
private String assignedDeptName;
@Schema(description = "工单状态")
private String ticketStatus;
@Schema(description = "工单状态名称")
private String ticketStatusName;
@Schema(description = "工单状态颜色")
private String statusColor;
@Schema(description = "解决方案")
private String resolution;
@Schema(description = "解决时间", format = "date-time")
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date resolutionTime;
@Schema(description = "关闭时间", format = "date-time")
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date closeTime;
@Schema(description = "首次响应时间", format = "date-time")
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date responseTime;
@Schema(description = "SLA截止时间", format = "date-time")
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date slaDeadline;
@Schema(description = "是否逾期", defaultValue = "false")
private Boolean isOverdue;
@Schema(description = "距离SLA截止的剩余时间分钟")
private Integer slaRemainingMinutes;
@Schema(description = "客户评分1-5星")
private Integer customerRating;
@Schema(description = "客户反馈")
private String customerFeedback;
@Schema(description = "CRM系统工单ID")
private String crmTicketId;
@Schema(description = "同步状态")
private String syncStatus;
@Schema(description = "同步状态名称")
private String syncStatusName;
@Schema(description = "工单标签")
private List<String> tags;
@Schema(description = "工单元数据")
private JsonNode metadata;
@Schema(description = "处理记录数量")
private Integer logCount;
@Schema(description = "创建者姓名")
private String creatorName;
@Schema(description = "更新者姓名")
private String updaterName;
}

View File

@@ -0,0 +1,44 @@
package org.xyzh.api.workcase.vo;
import java.util.List;
import org.xyzh.common.vo.BaseVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @description 工单过程VO
* @filename WorkcaseProcessVO.java
* @author yslg
* @copyright xyzh
* @since 2025-12-31
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Schema(description = "工单过程VO")
public class WorkcaseProcessVO extends BaseVO {
private static final long serialVersionUID = 1L;
@Schema(description = "工单ID")
private String workcaseId;
@Schema(description = "过程ID")
private String processId;
@Schema(description = "动作 info记录assign指派redeploy转派repeal撤销finish完成")
private String action;
@Schema(description = "消息")
private String message;
@Schema(description = "携带文件列表")
private List<String> files;
@Schema(description = "处理人ID指派、转派专属")
private String processor;
@Schema(description = "处理人名称")
private String processorName;
}

View File

@@ -14,6 +14,7 @@ import org.xyzh.api.workcase.dto.TbWorkcaseDTO;
import org.xyzh.api.workcase.dto.TbWorkcaseDeviceDTO;
import org.xyzh.api.workcase.dto.TbWorkcaseProcessDTO;
import org.xyzh.api.workcase.service.WorkcaseService;
import org.xyzh.api.workcase.vo.WorkcaseProcessVO;
import org.xyzh.common.auth.utils.LoginUtil;
import org.xyzh.common.core.domain.LoginDomain;
import org.xyzh.common.core.domain.ResultDomain;
@@ -49,7 +50,8 @@ public class WorkcaseController {
@PostMapping
public ResultDomain<TbWorkcaseDTO> createWorkcase(@RequestBody TbWorkcaseDTO workcase) {
ValidationResult vr = ValidationUtils.validate(workcase, Arrays.asList(
ValidationUtils.requiredString("deviceNamePlateImg", "设备名称牌图片"),
ValidationUtils.requiredString("deviceNamePlate", "设备名称牌图片"),
ValidationUtils.requiredString("deviceCode", "设备代码"),
ValidationUtils.requiredString("type", "问题类型"),
ValidationUtils.requiredString("userId", "用户ID"),
ValidationUtils.requiredString("username", "用户名称")
@@ -176,14 +178,14 @@ public class WorkcaseController {
@Operation(summary = "查询工单处理过程列表")
@PreAuthorize("hasAuthority('workcase:ticket:process')")
@PostMapping("/process/list")
public ResultDomain<TbWorkcaseProcessDTO> getWorkcaseProcessList(@RequestBody TbWorkcaseProcessDTO filter) {
public ResultDomain<WorkcaseProcessVO> getWorkcaseProcessList(@RequestBody TbWorkcaseProcessDTO filter) {
return workcaseService.getWorkcaseProcessList(filter);
}
@Operation(summary = "分页查询工单处理过程")
@PreAuthorize("hasAuthority('workcase:ticket:process')")
@PostMapping("/process/page")
public ResultDomain<TbWorkcaseProcessDTO> getWorkcaseProcessPage(@RequestBody PageRequest<TbWorkcaseProcessDTO> pageRequest) {
public ResultDomain<WorkcaseProcessVO> getWorkcaseProcessPage(@RequestBody PageRequest<TbWorkcaseProcessDTO> pageRequest) {
ValidationResult vr = ValidationUtils.validate(pageRequest, Arrays.asList(
ValidationUtils.requiredNumber("pageParam.page", "页码", 1, null),
ValidationUtils.requiredNumber("pageParam.pageSize", "每页数量", 1, 100)

View File

@@ -5,6 +5,7 @@ import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.xyzh.api.workcase.dto.TbWorkcaseProcessDTO;
import org.xyzh.api.workcase.vo.WorkcaseProcessVO;
import org.xyzh.common.core.page.PageParam;
/**
@@ -40,12 +41,12 @@ public interface TbWorkcaseProcessMapper {
/**
* 查询工单过程列表
*/
List<TbWorkcaseProcessDTO> selectWorkcaseProcessList(@Param("filter") TbWorkcaseProcessDTO filter);
List<WorkcaseProcessVO> selectWorkcaseProcessList(@Param("filter") TbWorkcaseProcessDTO filter);
/**
* 分页查询工单过程
*/
List<TbWorkcaseProcessDTO> selectWorkcaseProcessPage(@Param("filter") TbWorkcaseProcessDTO filter, @Param("pageParam") PageParam pageParam);
List<WorkcaseProcessVO> selectWorkcaseProcessPage(@Param("filter") TbWorkcaseProcessDTO filter, @Param("pageParam") PageParam pageParam);
/**
* 统计工单过程数量

View File

@@ -25,6 +25,7 @@ import org.xyzh.api.workcase.dto.TbWorkcaseDTO;
import org.xyzh.api.workcase.dto.TbWorkcaseDeviceDTO;
import org.xyzh.api.workcase.dto.TbWorkcaseProcessDTO;
import org.xyzh.api.workcase.service.WorkcaseService;
import org.xyzh.api.workcase.vo.WorkcaseProcessVO;
import org.xyzh.common.auth.utils.LoginUtil;
import org.xyzh.common.core.domain.ResultDomain;
import org.xyzh.common.core.page.PageDomain;
@@ -445,21 +446,21 @@ public class WorkcaseServiceImpl implements WorkcaseService {
}
@Override
public ResultDomain<TbWorkcaseProcessDTO> getWorkcaseProcessList(TbWorkcaseProcessDTO filter) {
List<TbWorkcaseProcessDTO> list = workcaseProcessMapper.selectWorkcaseProcessList(filter);
public ResultDomain<WorkcaseProcessVO> getWorkcaseProcessList(TbWorkcaseProcessDTO filter) {
List<WorkcaseProcessVO> list = workcaseProcessMapper.selectWorkcaseProcessList(filter);
return ResultDomain.success("查询成功", list);
}
@Override
public ResultDomain<TbWorkcaseProcessDTO> getWorkcaseProcessPage(PageRequest<TbWorkcaseProcessDTO> pageRequest) {
public ResultDomain<WorkcaseProcessVO> getWorkcaseProcessPage(PageRequest<TbWorkcaseProcessDTO> pageRequest) {
TbWorkcaseProcessDTO filter = pageRequest.getFilter();
PageParam pageParam = pageRequest.getPageParam();
List<TbWorkcaseProcessDTO> list = workcaseProcessMapper.selectWorkcaseProcessPage(filter, pageParam);
List<WorkcaseProcessVO> list = workcaseProcessMapper.selectWorkcaseProcessPage(filter, pageParam);
long total = workcaseProcessMapper.countWorkcaseProcesses(filter);
pageParam.setTotal((int) total);
PageDomain<TbWorkcaseProcessDTO> pageDomain = new PageDomain<>(pageParam, list);
PageDomain<WorkcaseProcessVO> pageDomain = new PageDomain<>(pageParam, list);
return ResultDomain.success("查询成功", pageDomain);
}

View File

@@ -34,10 +34,9 @@
<insert id="insertWorkcase" parameterType="org.xyzh.api.workcase.dto.TbWorkcaseDTO">
INSERT INTO workcase.tb_workcase (
optsn, workcase_id, room_id, user_id, username, phone, type, device_name_plate_img, creator
optsn, workcase_id, room_id, user_id, username, phone, type, device_code,device_name_plate, creator
<if test="device != null">, device</if>
<if test="deviceCode != null">, device_code</if>
<if test="deviceNamePlate != null">, device_name_plate</if>
<if test="deviceNamePlateImg != null">, device_name_plate_img</if>
<if test="address != null">, address</if>
<if test="description != null">, description</if>
<if test="imgs != null">, imgs</if>
@@ -45,10 +44,9 @@
<if test="status != null">, status</if>
<if test="processor != null">, processor</if>
) VALUES (
#{optsn}, #{workcaseId}, #{roomId}, #{userId}, #{username}, #{phone}, #{type}, #{deviceNamePlateImg}, #{creator}
#{optsn}, #{workcaseId}, #{roomId}, #{userId}, #{username}, #{phone}, #{type}, #{deviceCode}, #{deviceNamePlate}, #{creator}
<if test="device != null">, #{device}</if>
<if test="deviceCode != null">, #{deviceCode}</if>
<if test="deviceNamePlate != null">, #{deviceNamePlate}</if>
<if test="deviceNamePlateImg != null">, #{deviceNamePlateImg}</if>
<if test="address != null">, #{address}</if>
<if test="description != null">, #{description}</if>
<if test="imgs != null">, #{imgs, typeHandler=org.xyzh.common.jdbc.handler.StringArrayTypeHandler}</if>

View File

@@ -15,6 +15,21 @@
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
</resultMap>
<resultMap id="VOResultMap" type="org.xyzh.api.workcase.vo.WorkcaseProcessVO">
<id column="process_id" property="processId" jdbcType="VARCHAR"/>
<result column="optsn" property="optsn" jdbcType="VARCHAR"/>
<result column="workcase_id" property="workcaseId" jdbcType="VARCHAR"/>
<result column="action" property="action" jdbcType="VARCHAR"/>
<result column="message" property="message" jdbcType="VARCHAR"/>
<result column="files" property="files" jdbcType="ARRAY" typeHandler="org.xyzh.common.jdbc.handler.StringArrayTypeHandler"/>
<result column="processor" property="processor" jdbcType="VARCHAR"/>
<result column="processor_name" property="processorName" jdbcType="VARCHAR"/>
<result column="remark" property="remark" jdbcType="VARCHAR"/>
<result column="creator" property="creator" jdbcType="VARCHAR"/>
<result column="creator_name" property="creatorName" jdbcType="VARCHAR"/>
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
</resultMap>
<sql id="Base_Column_List">
process_id, optsn, workcase_id, action, message, files, processor, remark, creator, create_time
</sql>
@@ -58,50 +73,64 @@
WHERE process_id = #{processId}
</select>
<select id="selectWorkcaseProcessList" resultMap="BaseResultMap">
SELECT <include refid="Base_Column_List"/>
FROM workcase.tb_workcase_process
<select id="selectWorkcaseProcessList" resultMap="VOResultMap">
SELECT p.process_id, p.optsn, p.workcase_id, p.action, p.message, p.files,
p.processor, p.remark, p.creator, p.create_time,
COALESCE(u1.username, g1.name) as creator_name,
COALESCE(u2.username, g2.name) as processor_name
FROM workcase.tb_workcase_process p
LEFT JOIN sys.tb_sys_user_info u1 ON p.creator = u1.user_id
LEFT JOIN sys.tb_guest g1 ON p.creator = g1.user_id
LEFT JOIN sys.tb_sys_user_info u2 ON p.processor = u2.user_id
LEFT JOIN sys.tb_guest g2 ON p.processor = g2.user_id
<where>
<if test="filter.processId != null and filter.processId != ''">
AND process_id = #{filter.processId}
AND p.process_id = #{filter.processId}
</if>
<if test="filter.workcaseId != null and filter.workcaseId != ''">
AND workcase_id = #{filter.workcaseId}
AND p.workcase_id = #{filter.workcaseId}
</if>
<if test="filter.action != null and filter.action != ''">
AND action = #{filter.action}
AND p.action = #{filter.action}
</if>
<if test="filter.processor != null and filter.processor != ''">
AND processor = #{filter.processor}
AND p.processor = #{filter.processor}
</if>
<if test="filter.creator != null and filter.creator != ''">
AND creator = #{filter.creator}
AND p.creator = #{filter.creator}
</if>
</where>
ORDER BY create_time ASC
ORDER BY p.create_time ASC
</select>
<select id="selectWorkcaseProcessPage" resultMap="BaseResultMap">
SELECT <include refid="Base_Column_List"/>
FROM workcase.tb_workcase_process
<select id="selectWorkcaseProcessPage" resultMap="VOResultMap">
SELECT p.process_id, p.optsn, p.workcase_id, p.action, p.message, p.files,
p.processor, p.remark, p.creator, p.create_time,
COALESCE(u1.username, g1.name) as creator_name,
COALESCE(u2.username, g2.name) as processor_name
FROM workcase.tb_workcase_process p
LEFT JOIN sys.tb_sys_user_info u1 ON p.creator = u1.user_id
LEFT JOIN sys.tb_guest g1 ON p.creator = g1.user_id
LEFT JOIN sys.tb_sys_user_info u2 ON p.processor = u2.user_id
LEFT JOIN sys.tb_guest g2 ON p.processor = g2.user_id
<where>
<if test="filter.processId != null and filter.processId != ''">
AND process_id = #{filter.processId}
AND p.process_id = #{filter.processId}
</if>
<if test="filter.workcaseId != null and filter.workcaseId != ''">
AND workcase_id = #{filter.workcaseId}
AND p.workcase_id = #{filter.workcaseId}
</if>
<if test="filter.action != null and filter.action != ''">
AND action = #{filter.action}
AND p.action = #{filter.action}
</if>
<if test="filter.processor != null and filter.processor != ''">
AND processor = #{filter.processor}
AND p.processor = #{filter.processor}
</if>
<if test="filter.creator != null and filter.creator != ''">
AND creator = #{filter.creator}
AND p.creator = #{filter.creator}
</if>
</where>
ORDER BY create_time ASC
ORDER BY p.create_time ASC
LIMIT #{pageParam.pageSize} OFFSET #{pageParam.offset}
</select>