Browse Source

工单主表代码

main
wang 1 month ago
parent
commit
848ee9ccab
  1. 73
      smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/controller/WtczController.java
  2. 15
      smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/dao/MessageDetailDao.java
  3. 15
      smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/dao/WtczDao.java
  4. 15
      smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/dao/WtczHfhcDao.java
  5. 15
      smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/dao/WtczYyDao.java
  6. 60
      smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/domain/entity/MessageDetailEntity.java
  7. 199
      smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/domain/entity/WtczEntity.java
  8. 71
      smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/domain/entity/WtczHfhcEntity.java
  9. 69
      smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/domain/entity/WtczYyEntity.java
  10. 189
      smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/domain/form/WtczAddForm.java
  11. 37
      smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/domain/form/WtczQueryForm.java
  12. 194
      smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/domain/form/WtczUpdateForm.java
  13. 68
      smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/domain/vo/WtczHfhcVO.java
  14. 198
      smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/domain/vo/WtczVO.java
  15. 65
      smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/domain/vo/WtczYyVO.java
  16. 323
      smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/service/WtczService.java
  17. 4
      smart-flow-api/sa-admin/src/main/resources/mapper/business/jwpy/MessageDetailMapper.xml
  18. 4
      smart-flow-api/sa-admin/src/main/resources/mapper/business/jwpy/WtczHfhcMapper.xml
  19. 4
      smart-flow-api/sa-admin/src/main/resources/mapper/business/jwpy/WtczMapper.xml
  20. 4
      smart-flow-api/sa-admin/src/main/resources/mapper/business/jwpy/WtczYyMapper.xml
  21. 52
      smart-flow-web/src/api/business/jwpy/wtcz-api.js
  22. 14
      smart-flow-web/src/constants/support/dict-const.js
  23. 359
      smart-flow-web/src/views/jwpy/jwpy/flow/index.vue
  24. 228
      smart-flow-web/src/views/jwpy/jwpy/flow/wtcz-detail.vue
  25. 283
      smart-flow-web/src/views/jwpy/jwpy/flow/wtcz-form.vue

73
smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/controller/WtczController.java

@ -0,0 +1,73 @@
package net.lab1024.sa.admin.module.business.jwpy.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import net.lab1024.sa.admin.module.business.jwpy.domain.form.WtczQueryForm;
import net.lab1024.sa.admin.module.business.jwpy.domain.form.WtczAddForm;
import net.lab1024.sa.admin.module.business.jwpy.domain.form.WtczUpdateForm;
import net.lab1024.sa.admin.module.business.jwpy.domain.vo.WtczVO;
import net.lab1024.sa.admin.module.business.jwpy.service.WtczService;
import net.lab1024.sa.base.common.domain.PageResult;
import net.lab1024.sa.base.common.domain.ResponseDTO;
import net.lab1024.sa.base.common.domain.ValidateList;
import org.springframework.web.bind.annotation.*;
/**
* 警务评议与问题处置 控制器
*
* @Author Antigravity
* @Date 2026-06-09
*/
@RestController
@Tag(name = "业务功能-警务评议与问题处置")
public class WtczController {
@Resource
private WtczService wtczService;
@Operation(summary = "分页查询评议工单")
@PostMapping("/jwpy/wtcz/queryPage")
@SaCheckPermission("jwpy:flow:query")
public ResponseDTO<PageResult<WtczVO>> queryPage(@RequestBody @Valid WtczQueryForm queryForm) {
return wtczService.queryPage(queryForm);
}
@Operation(summary = "添加评议工单")
@PostMapping("/jwpy/wtcz/add")
@SaCheckPermission("jwpy:flow:add")
public ResponseDTO<String> add(@RequestBody @Valid WtczAddForm addForm) {
return wtczService.add(addForm);
}
@Operation(summary = "修改评议工单")
@PostMapping("/jwpy/wtcz/update")
@SaCheckPermission("jwpy:flow:update")
public ResponseDTO<String> update(@RequestBody @Valid WtczUpdateForm updateForm) {
return wtczService.update(updateForm);
}
@Operation(summary = "删除评议工单")
@GetMapping("/jwpy/wtcz/delete/{id}")
@SaCheckPermission("jwpy:flow:delete")
public ResponseDTO<String> delete(@PathVariable Long id) {
return wtczService.delete(id);
}
@Operation(summary = "批量删除评议工单")
@PostMapping("/jwpy/wtcz/batchDelete")
@SaCheckPermission("jwpy:flow:delete")
public ResponseDTO<String> batchDelete(@RequestBody ValidateList<Long> idList) {
return wtczService.batchDelete(idList);
}
@Operation(summary = "获取工单详情(合并首访与回访记录)")
@GetMapping("/jwpy/wtcz/detail/{id}")
@SaCheckPermission("jwpy:flow:query")
public ResponseDTO<WtczVO> getDetail(@PathVariable Long id) {
return wtczService.getDetail(id);
}
}

15
smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/dao/MessageDetailDao.java

@ -0,0 +1,15 @@
package net.lab1024.sa.admin.module.business.jwpy.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import net.lab1024.sa.admin.module.business.jwpy.domain.entity.MessageDetailEntity;
import org.apache.ibatis.annotations.Mapper;
/**
* 工单短信明细表 Dao
*
* @Author Antigravity
* @Date 2026-06-09
*/
@Mapper
public interface MessageDetailDao extends BaseMapper<MessageDetailEntity> {
}

15
smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/dao/WtczDao.java

@ -0,0 +1,15 @@
package net.lab1024.sa.admin.module.business.jwpy.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import net.lab1024.sa.admin.module.business.jwpy.domain.entity.WtczEntity;
import org.apache.ibatis.annotations.Mapper;
/**
* 工单主表 Dao
*
* @Author Antigravity
* @Date 2026-06-09
*/
@Mapper
public interface WtczDao extends BaseMapper<WtczEntity> {
}

15
smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/dao/WtczHfhcDao.java

@ -0,0 +1,15 @@
package net.lab1024.sa.admin.module.business.jwpy.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import net.lab1024.sa.admin.module.business.jwpy.domain.entity.WtczHfhcEntity;
import org.apache.ibatis.annotations.Mapper;
/**
* 二次回访表 Dao
*
* @Author Antigravity
* @Date 2026-06-09
*/
@Mapper
public interface WtczHfhcDao extends BaseMapper<WtczHfhcEntity> {
}

15
smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/dao/WtczYyDao.java

@ -0,0 +1,15 @@
package net.lab1024.sa.admin.module.business.jwpy.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import net.lab1024.sa.admin.module.business.jwpy.domain.entity.WtczYyEntity;
import org.apache.ibatis.annotations.Mapper;
/**
* 首访信息表 Dao
*
* @Author Antigravity
* @Date 2026-06-09
*/
@Mapper
public interface WtczYyDao extends BaseMapper<WtczYyEntity> {
}

60
smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/domain/entity/MessageDetailEntity.java

@ -0,0 +1,60 @@
package net.lab1024.sa.admin.module.business.jwpy.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 工单短信明细表 实体类
*
* @Author Antigravity
* @Date 2026-06-09
*/
@Data
@TableName("t_message_detail")
@Schema(description = "工单短信明细表")
public class MessageDetailEntity {
@TableId(type = IdType.AUTO)
@Schema(description = "主键ID")
private Long id;
@Schema(description = "地市4位数字编码")
private String cityCode;
@Schema(description = "所属单位编码(老警综编码)")
private String orgCode;
@Schema(description = "短信业务类型:满意度回访、投诉回访、提醒通知")
private String messageType;
@Schema(description = "接收短信的手机号(脱敏)")
private String messagePhone;
@Schema(description = "发送给诉求人的短信内容")
private String messageSendContent;
@Schema(description = "诉求人回复的短信内容")
private String messageAcceptContent;
@Schema(description = "发送日期,格式YYYY-MM-DD")
private String sendDay;
@Schema(description = "地市标准名称")
private String cityName;
@Schema(description = "所属单位标准名称")
private String orgName;
@Schema(description = "数据同步至省厅的时间")
private LocalDateTime syncTime;
@Schema(description = "数据在本地系统创建的时间")
private LocalDateTime createTime;
}

199
smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/domain/entity/WtczEntity.java

@ -0,0 +1,199 @@
package net.lab1024.sa.admin.module.business.jwpy.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 工单主表 实体类
*
* @Author Antigravity
* @Date 2026-06-09
*/
@Data
@TableName("t_czzx_wtcz")
@Schema(description = "工单主表")
public class WtczEntity {
@TableId(type = IdType.AUTO)
@Schema(description = "主键ID")
private Long id;
@Schema(description = "工单受理编号(业务唯一标识)")
private String slbh;
@Schema(description = "地市4位数字编码")
private String cityCode;
@Schema(description = "地市标准名称")
private String cityName;
@Schema(description = "诉求人提交诉求的时间")
private String sqsj;
@Schema(description = "工单当前处理状态:0已录入、1办结中、2已办结")
private String gdzt;
@Schema(description = "首访满意度结果:1满意、2不满意")
private String sfjg;
@Schema(description = "诉求业务分类:01投诉、02咨询(求助)、03建议、04举报、05表扬、06其他")
private String sqfl;
@Schema(description = "工单四级标签,格式:一级-二级-三级-四级")
private String gdbq;
@Schema(description = "数据来源渠道:1短信评警回访、2民意热线、3网络民意、4民意拓展、5民意调查")
private String sjlyqd;
@Schema(description = "数据来源业务分类,如12389热线、12345热线、110接处警、车驾管等")
private String sjlyNo;
@Schema(description = "工单涉及的业务单位名称")
private String sjdwMc;
@Schema(description = "涉及单位编码")
private String sjdwCode;
@Schema(description = "涉及警种:交警、派出所、治安等")
private String sjjzMc;
@Schema(description = "是否属实:1属实、2部分属实、3不属实、4查明其他情况")
private String ssqkNo;
@Schema(description = "涉及民警名称")
private String sjmjMc;
@Schema(description = "问责情况")
private String wzqkNo;
@Schema(description = "属实具体情况描述")
private String trueFlag;
@Schema(description = "是否涉企:0否、1是")
private Integer sfsq;
@Schema(description = "诉求人提交的详细内容")
private String sqnr;
@Schema(description = "工单的最终处理结果")
private String cljg;
@Schema(description = "发送给诉求人的短信内容")
private String dxfsnr;
@Schema(description = "短信回复内容")
private String dxhfnr;
@Schema(description = "短信发送时间")
private String dxfssj;
@Schema(description = "短信回复时间")
private String dxhfsj;
@Schema(description = "工单处理提交时间")
private String tjsj;
@Schema(description = "工单归属的单位编码")
private String orgCode;
@Schema(description = "工单满意情况")
private String gdmyqk;
@Schema(description = "工单数据创建时间")
private String createTime;
@Schema(description = "数据同步至省厅的时间")
private LocalDateTime syncTime;
@Schema(description = "所属单位名称")
private String orgName;
@Schema(description = "企业名称")
private String qymc;
@Schema(description = "民辅警身份:1民警、2辅警")
private Integer sfsjfj;
@Schema(description = "姓名")
private String sjfjxm;
@Schema(description = "警号")
private String sjfjjh;
@Schema(description = "诉求人联系电话")
private String lxdh;
@Schema(description = "诉求人身份证号")
private String sqrZjhm;
@Schema(description = "性别:1男、2女")
private String sqrXb;
@Schema(description = "访评员编号")
private String fpyNo;
@Schema(description = "访评员姓名")
private String fpyName;
@Schema(description = "涉及单位名称")
private String sjdwName;
@Schema(description = "是否匿名 (0:否, 1:是)")
private Integer sfnm;
@Schema(description = "涉及单位ID")
private Long sjdwId;
@Schema(description = "涉及民警ID串")
private String sjmjIds;
@Schema(description = "涉及警种编码")
private String sjjzNo;
@Schema(description = "诉求人ID")
private Double sqrId;
@Schema(description = "诉求人姓名")
private String sqrXm;
@Schema(description = "诉求人户籍地详址")
private String sqrHjdxz;
@Schema(description = "诉求人现住地详址")
private String sqrXzdxz;
@Schema(description = "关联警情编号")
private String gljqBh;
@Schema(description = "关联案件编号")
private String glajBh;
@Schema(description = "诉求等级")
private String sqdj;
@Schema(description = "关键字")
private String gjz;
@Schema(description = "是否已延期")
private String sfyyq;
@Schema(description = "问题描述")
private String wtms;
@Schema(description = "提交人ID")
private Long tjrId;
@Schema(description = "提交单位ID")
private Long tjdwId;
@Schema(description = "群众满意情况")
private String qzmyqk;
}

71
smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/domain/entity/WtczHfhcEntity.java

@ -0,0 +1,71 @@
package net.lab1024.sa.admin.module.business.jwpy.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 二次回访表 实体类
*
* @Author Antigravity
* @Date 2026-06-09
*/
@Data
@TableName("t_czzx_wtcz_hfhc")
@Schema(description = "二次回访表")
public class WtczHfhcEntity {
@TableId(type = IdType.AUTO)
@Schema(description = "主键ID")
private Long id;
@Schema(description = "关联工单编号")
private String slbh;
@Schema(description = "数据来源地市")
private String sourceCity;
@Schema(description = "二次回访内容")
private String hfqksm;
@Schema(description = "二次回访时间")
private LocalDateTime cjsj;
@Schema(description = "诉求人电话(从主表获取)")
private String lxdh;
@Schema(description = "二次回访人员名称")
private String tjrXm;
@Schema(description = "二次回访满意度")
private String qzmyqkNo;
@Schema(description = "附件UUID")
private String fjUuid;
@Schema(description = "数据同步时间(增量时间)")
private LocalDateTime syncTime;
@Schema(description = "数据创建时间")
private LocalDateTime createTime;
@Schema(description = "所属单位代码")
private String orgCode;
@Schema(description = "是否验证")
private String sfyz;
@Schema(description = "下发阶段")
private String xfjd;
@Schema(description = "办理单位ID")
private String bldwId;
@Schema(description = "问题处置ID")
private String wtczId;
}

69
smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/domain/entity/WtczYyEntity.java

@ -0,0 +1,69 @@
package net.lab1024.sa.admin.module.business.jwpy.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 首访信息表 实体类
*
* @Author Antigravity
* @Date 2026-06-09
*/
@Data
@TableName("t_czzx_wtcz_yy")
@Schema(description = "首访信息表")
public class WtczYyEntity {
@TableId(type = IdType.AUTO)
@Schema(description = "主键ID")
private Long id;
@Schema(description = "关联的工单受理编号")
private String slbh;
@Schema(description = "首访数据所属地市")
private String sourceCity;
@Schema(description = "首访通话开始时间")
private LocalDateTime thsj;
@Schema(description = "诉求人通话号码(脱敏)")
private String thhm;
@Schema(description = "呼叫方向:1呼入、2呼出、3自动呼入")
private String thfx;
@Schema(description = "通话时长(秒)")
private Long thsc;
@Schema(description = "录音文件地址")
private String lydz;
@Schema(description = "通话单位")
private String thdwMc;
@Schema(description = "数据创建时间")
private LocalDateTime createTime;
@Schema(description = "数据同步时间(增量时间)")
private LocalDateTime syncTime;
@Schema(description = "所属单位代码")
private String orgCode;
@Schema(description = "录音电话")
private String lydh;
@Schema(description = "通话单位ID")
private Long thdwId;
@Schema(description = "语音通话记录表ID")
private Long yyId;
}

189
smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/domain/form/WtczAddForm.java

@ -0,0 +1,189 @@
package net.lab1024.sa.admin.module.business.jwpy.domain.form;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 警务评议工单 新增表单
*
* @Author Antigravity
* @Date 2026-06-09
*/
@Data
public class WtczAddForm {
@Schema(description = "工单受理编号", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "工单受理编号 不能为空")
private String slbh;
@Schema(description = "地市4位数字编码")
private String cityCode;
@Schema(description = "地市标准名称")
private String cityName;
@Schema(description = "诉求人提交诉求的时间")
private String sqsj;
@Schema(description = "工单当前处理状态:0已录入、1办结中、2已办结")
private String gdzt;
@Schema(description = "首访满意度结果:1满意、2不满意")
private String sfjg;
@Schema(description = "诉求业务分类:01投诉、02咨询(求助)、03建议、04举报、05表扬、06其他")
private String sqfl;
@Schema(description = "工单四级标签")
private String gdbq;
@Schema(description = "数据来源渠道:1短信评警回访、2民意热线、3网络民意、4民意拓展、5民意调查")
private String sjlyqd;
@Schema(description = "数据来源业务分类,如12389热线、12345热线、110接处警、车驾管等")
private String sjlyNo;
@Schema(description = "工单涉及的业务单位名称")
private String sjdwMc;
@Schema(description = "涉及单位编码")
private String sjdwCode;
@Schema(description = "涉及警种名称")
private String sjjzMc;
@Schema(description = "是否属实")
private String ssqkNo;
@Schema(description = "涉及民警名称")
private String sjmjMc;
@Schema(description = "问责情况")
private String wzqkNo;
@Schema(description = "属实具体情况描述")
private String trueFlag;
@Schema(description = "是否涉企:0否、1是")
private Integer sfsq;
@Schema(description = "诉求人提交的详细内容")
private String sqnr;
@Schema(description = "工单的最终处理结果")
private String cljg;
@Schema(description = "发送给诉求人的短信内容")
private String dxfsnr;
@Schema(description = "短信回复内容")
private String dxhfnr;
@Schema(description = "短信发送时间")
private String dxfssj;
@Schema(description = "短信回复时间")
private String dxhfsj;
@Schema(description = "工单处理提交时间")
private String tjsj;
@Schema(description = "工单归属的单位编码")
private String orgCode;
@Schema(description = "工单满意情况")
private String gdmyqk;
@Schema(description = "工单数据创建时间")
private String createTime;
@Schema(description = "数据同步至省厅的时间")
private LocalDateTime syncTime;
@Schema(description = "所属单位名称")
private String orgName;
@Schema(description = "企业名称")
private String qymc;
@Schema(description = "民辅警身份:1民警、2辅警")
private Integer sfsjfj;
@Schema(description = "姓名")
private String sjfjxm;
@Schema(description = "警号")
private String sjfjjh;
@Schema(description = "诉求人联系电话")
private String lxdh;
@Schema(description = "诉求人身份证号")
private String sqrZjhm;
@Schema(description = "性别:1男、2女")
private String sqrXb;
@Schema(description = "访评员编号")
private String fpyNo;
@Schema(description = "访评员姓名")
private String fpyName;
@Schema(description = "涉及单位名称")
private String sjdwName;
@Schema(description = "是否匿名 (0:否, 1:是)")
private Integer sfnm;
@Schema(description = "涉及单位ID")
private Long sjdwId;
@Schema(description = "涉及民警ID串")
private String sjmjIds;
@Schema(description = "涉及警种编码")
private String sjjzNo;
@Schema(description = "诉求人ID")
private Double sqrId;
@Schema(description = "诉求人姓名")
private String sqrXm;
@Schema(description = "诉求人户籍地详址")
private String sqrHjdxz;
@Schema(description = "诉求人现住地详址")
private String sqrXzdxz;
@Schema(description = "关联警情编号")
private String gljqBh;
@Schema(description = "关联案件编号")
private String glajBh;
@Schema(description = "诉求等级")
private String sqdj;
@Schema(description = "关键字")
private String gjz;
@Schema(description = "是否已延期")
private String sfyyq;
@Schema(description = "问题描述")
private String wtms;
@Schema(description = "提交人ID")
private Long tjrId;
@Schema(description = "提交单位ID")
private Long tjdwId;
@Schema(description = "群众满意情况")
private String qzmyqk;
}

37
smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/domain/form/WtczQueryForm.java

@ -0,0 +1,37 @@
package net.lab1024.sa.admin.module.business.jwpy.domain.form;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import net.lab1024.sa.base.common.domain.PageParam;
/**
* 工单分页查询表单
*
* @Author Antigravity
* @Date 2026-06-09
*/
@Data
@Schema(description = "工单分页查询表单")
public class WtczQueryForm extends PageParam {
@Schema(description = "数据来源渠道:1短信评警回访、2民意热线、3网络民意、4民意拓展、5民意调查")
private String sjlyqd;
@Schema(description = "数据来源业务分类,如12389热线、12345热线、110接处警、车驾管等")
private String sjlyNo;
@Schema(description = "工单受理编号(业务唯一标识)")
private String slbh;
@Schema(description = "诉求人联系电话")
private String lxdh;
@Schema(description = "姓名")
private String sjfjxm;
@Schema(description = "工单当前处理状态:0已录入、1办结中、2已办结")
private String gdzt;
@Schema(description = "删除标记:0未删,1已删")
private Boolean deletedFlag;
}

194
smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/domain/form/WtczUpdateForm.java

@ -0,0 +1,194 @@
package net.lab1024.sa.admin.module.business.jwpy.domain.form;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 警务评议工单 修改表单
*
* @Author Antigravity
* @Date 2026-06-09
*/
@Data
public class WtczUpdateForm {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "主键ID 不能为空")
private Long id;
@Schema(description = "工单受理编号", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "工单受理编号 不能为空")
private String slbh;
@Schema(description = "地市4位数字编码")
private String cityCode;
@Schema(description = "地市标准名称")
private String cityName;
@Schema(description = "诉求人提交诉求的时间")
private String sqsj;
@Schema(description = "工单当前处理状态:0已录入、1办结中、2已办结")
private String gdzt;
@Schema(description = "首访满意度结果:1满意、2不满意")
private String sfjg;
@Schema(description = "诉求业务分类:01投诉、02咨询(求助)、03建议、04举报、05表扬、06其他")
private String sqfl;
@Schema(description = "工单四级标签")
private String gdbq;
@Schema(description = "数据来源渠道:1短信评警回访、2民意热线、3网络民意、4民意拓展、5民意调查")
private String sjlyqd;
@Schema(description = "数据来源业务分类,如12389热线、12345热线、110接处警、车驾管等")
private String sjlyNo;
@Schema(description = "工单涉及的业务单位名称")
private String sjdwMc;
@Schema(description = "涉及单位编码")
private String sjdwCode;
@Schema(description = "涉及警种名称")
private String sjjzMc;
@Schema(description = "是否属实")
private String ssqkNo;
@Schema(description = "涉及民警名称")
private String sjmjMc;
@Schema(description = "问责情况")
private String wzqkNo;
@Schema(description = "属实具体情况描述")
private String trueFlag;
@Schema(description = "是否涉企:0否、1是")
private Integer sfsq;
@Schema(description = "诉求人提交的详细内容")
private String sqnr;
@Schema(description = "工单的最终处理结果")
private String cljg;
@Schema(description = "发送给诉求人的短信内容")
private String dxfsnr;
@Schema(description = "短信回复内容")
private String dxhfnr;
@Schema(description = "短信发送时间")
private String dxfssj;
@Schema(description = "短信回复时间")
private String dxhfsj;
@Schema(description = "工单处理提交时间")
private String tjsj;
@Schema(description = "工单归属的单位编码")
private String orgCode;
@Schema(description = "工单满意情况")
private String gdmyqk;
@Schema(description = "工单数据创建时间")
private String createTime;
@Schema(description = "数据同步至省厅的时间")
private LocalDateTime syncTime;
@Schema(description = "所属单位名称")
private String orgName;
@Schema(description = "企业名称")
private String qymc;
@Schema(description = "民辅警身份:1民警、2辅警")
private Integer sfsjfj;
@Schema(description = "姓名")
private String sjfjxm;
@Schema(description = "警号")
private String sjfjjh;
@Schema(description = "诉求人联系电话")
private String lxdh;
@Schema(description = "诉求人身份证号")
private String sqrZjhm;
@Schema(description = "性别:1男、2女")
private String sqrXb;
@Schema(description = "访评员编号")
private String fpyNo;
@Schema(description = "访评员姓名")
private String fpyName;
@Schema(description = "涉及单位名称")
private String sjdwName;
@Schema(description = "是否匿名 (0:否, 1:是)")
private Integer sfnm;
@Schema(description = "涉及单位ID")
private Long sjdwId;
@Schema(description = "涉及民警ID串")
private String sjmjIds;
@Schema(description = "涉及警种编码")
private String sjjzNo;
@Schema(description = "诉求人ID")
private Double sqrId;
@Schema(description = "诉求人姓名")
private String sqrXm;
@Schema(description = "诉求人户籍地详址")
private String sqrHjdxz;
@Schema(description = "诉求人现住地详址")
private String sqrXzdxz;
@Schema(description = "关联警情编号")
private String gljqBh;
@Schema(description = "关联案件编号")
private String glajBh;
@Schema(description = "诉求等级")
private String sqdj;
@Schema(description = "关键字")
private String gjz;
@Schema(description = "是否已延期")
private String sfyyq;
@Schema(description = "问题描述")
private String wtms;
@Schema(description = "提交人ID")
private Long tjrId;
@Schema(description = "提交单位ID")
private Long tjdwId;
@Schema(description = "群众满意情况")
private String qzmyqk;
}

68
smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/domain/vo/WtczHfhcVO.java

@ -0,0 +1,68 @@
package net.lab1024.sa.admin.module.business.jwpy.domain.vo;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import net.lab1024.sa.base.common.json.serializer.FileKeyVoSerializer;
import java.time.LocalDateTime;
/**
* 二次回访核实表 视图展示类
*
* @Author Antigravity
* @Date 2026-06-09
*/
@Data
@Schema(description = "二次回访核实视图对象")
public class WtczHfhcVO {
@Schema(description = "主键ID")
private Long id;
@Schema(description = "关联工单编号")
private String slbh;
@Schema(description = "数据来源地市")
private String sourceCity;
@Schema(description = "二次回访内容")
private String hfqksm;
@Schema(description = "二次回访时间")
private LocalDateTime cjsj;
@Schema(description = "诉求人电话(从主表获取)")
private String lxdh;
@Schema(description = "二次回访人员名称")
private String tjrXm;
@Schema(description = "二次回访满意度")
private String qzmyqkNo;
@Schema(description = "附件UUID")
@JsonSerialize(using = FileKeyVoSerializer.class)
private String fjUuid;
@Schema(description = "数据同步时间")
private LocalDateTime syncTime;
@Schema(description = "数据创建时间")
private LocalDateTime createTime;
@Schema(description = "所属单位代码")
private String orgCode;
@Schema(description = "是否验证")
private String sfyz;
@Schema(description = "下发阶段")
private String xfjd;
@Schema(description = "办理单位ID")
private String bldwId;
@Schema(description = "问题处置ID")
private String wtczId;
}

198
smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/domain/vo/WtczVO.java

@ -0,0 +1,198 @@
package net.lab1024.sa.admin.module.business.jwpy.domain.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 工单主表 视图展示类
*
* @Author Antigravity
* @Date 2026-06-09
*/
@Data
@Schema(description = "工单主表视图对象")
public class WtczVO {
@Schema(description = "主键ID")
private Long id;
@Schema(description = "工单受理编号(业务唯一标识)")
private String slbh;
@Schema(description = "地市4位数字编码")
private String cityCode;
@Schema(description = "地市标准名称")
private String cityName;
@Schema(description = "诉求人提交诉求的时间")
private String sqsj;
@Schema(description = "工单当前处理状态:0已录入、1办结中、2已办结")
private String gdzt;
@Schema(description = "首访满意度结果:1满意、2不满意")
private String sfjg;
@Schema(description = "诉求业务分类:01投诉、02咨询(求助)、03建议、04举报、05表扬、06其他")
private String sqfl;
@Schema(description = "工单四级标签")
private String gdbq;
@Schema(description = "数据来源渠道:1短信评警回访、2民意热线、3网络民意、4民意拓展、5民意调查")
private String sjlyqd;
@Schema(description = "数据来源业务分类,如12389热线、12345热线、110接处警、车驾管等")
private String sjlyNo;
@Schema(description = "工单涉及的业务单位名称")
private String sjdwMc;
@Schema(description = "涉及单位编码")
private String sjdwCode;
@Schema(description = "涉及警种:交警、派出所、治安等")
private String sjjzMc;
@Schema(description = "是否属实:1属实、2部分属实、3不属实、4查明其他情况")
private String ssqkNo;
@Schema(description = "涉及民警名称")
private String sjmjMc;
@Schema(description = "问责情况")
private String wzqkNo;
@Schema(description = "属实具体情况描述")
private String trueFlag;
@Schema(description = "是否涉企:0否、1是")
private Integer sfsq;
@Schema(description = "诉求人提交的详细内容")
private String sqnr;
@Schema(description = "工单的最终处理结果")
private String cljg;
@Schema(description = "发送给诉求人的短信内容")
private String dxfsnr;
@Schema(description = "诉求人回复的短信内容")
private String dxhfnr;
@Schema(description = "短信发送时间")
private String dxfssj;
@Schema(description = "短信回复时间")
private String dxhfsj;
@Schema(description = "工单处理提交时间")
private String tjsj;
@Schema(description = "工单归属的单位编码")
private String orgCode;
@Schema(description = "工单满意情况")
private String gdmyqk;
@Schema(description = "工单数据创建时间")
private String createTime;
@Schema(description = "数据同步至省厅的时间")
private LocalDateTime syncTime;
@Schema(description = "所属单位名称")
private String orgName;
@Schema(description = "企业名称")
private String qymc;
@Schema(description = "民辅警身份:1民警、2辅警")
private Integer sfsjfj;
@Schema(description = "姓名")
private String sjfjxm;
@Schema(description = "警号")
private String sjfjjh;
@Schema(description = "诉求人联系电话")
private String lxdh;
@Schema(description = "诉求人身份证号")
private String sqrZjhm;
@Schema(description = "性别:1男、2女")
private String sqrXb;
@Schema(description = "访评员编号")
private String fpyNo;
@Schema(description = "访评员姓名")
private String fpyName;
@Schema(description = "涉及单位名称")
private String sjdwName;
@Schema(description = "是否匿名 (0:否, 1:是)")
private Integer sfnm;
@Schema(description = "涉及单位ID")
private Long sjdwId;
@Schema(description = "涉及民警ID串")
private String sjmjIds;
@Schema(description = "涉及警种编码")
private String sjjzNo;
@Schema(description = "诉求人ID")
private Double sqrId;
@Schema(description = "诉求人姓名")
private String sqrXm;
@Schema(description = "诉求人户籍地详址")
private String sqrHjdxz;
@Schema(description = "诉求人现住地详址")
private String sqrXzdxz;
@Schema(description = "关联警情编号")
private String gljqBh;
@Schema(description = "关联案件编号")
private String glajBh;
@Schema(description = "诉求等级")
private String sqdj;
@Schema(description = "关键字")
private String gjz;
@Schema(description = "是否已延期")
private String sfyyq;
@Schema(description = "问题描述")
private String wtms;
@Schema(description = "提交人ID")
private Long tjrId;
@Schema(description = "提交单位ID")
private Long tjdwId;
@Schema(description = "群众满意情况")
private String qzmyqk;
@Schema(description = "首访通话语音列表")
private java.util.List<WtczYyVO> czzxWtczYyList;
@Schema(description = "二次回访记录列表")
private java.util.List<WtczHfhcVO> czzxWtczHfhcList;
}

65
smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/domain/vo/WtczYyVO.java

@ -0,0 +1,65 @@
package net.lab1024.sa.admin.module.business.jwpy.domain.vo;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import net.lab1024.sa.base.common.json.serializer.FileKeyVoSerializer;
import java.time.LocalDateTime;
/**
* 首访语音信息表 视图展示类
*
* @Author Antigravity
* @Date 2026-06-09
*/
@Data
@Schema(description = "首访语音信息视图对象")
public class WtczYyVO {
@Schema(description = "主键ID")
private Long id;
@Schema(description = "关联的工单受理编号")
private String slbh;
@Schema(description = "首访数据所属地市")
private String sourceCity;
@Schema(description = "首访通话开始时间")
private LocalDateTime thsj;
@Schema(description = "诉求人通话号码")
private String thhm;
@Schema(description = "呼叫方向:1呼入、2呼出、3自动呼入")
private String thfx;
@Schema(description = "通话时长(秒)")
private Long thsc;
@Schema(description = "录音文件地址")
@JsonSerialize(using = FileKeyVoSerializer.class)
private String lydz;
@Schema(description = "通话单位名称")
private String thdwMc;
@Schema(description = "数据创建时间")
private LocalDateTime createTime;
@Schema(description = "数据同步时间")
private LocalDateTime syncTime;
@Schema(description = "所属单位代码")
private String orgCode;
@Schema(description = "录音电话")
private String lydh;
@Schema(description = "通话单位ID")
private Long thdwId;
@Schema(description = "语音通话记录表ID")
private Long yyId;
}

323
smart-flow-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/jwpy/service/WtczService.java

@ -0,0 +1,323 @@
package net.lab1024.sa.admin.module.business.jwpy.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.admin.module.business.jwpy.dao.WtczDao;
import net.lab1024.sa.admin.module.business.jwpy.dao.WtczYyDao;
import net.lab1024.sa.admin.module.business.jwpy.dao.WtczHfhcDao;
import net.lab1024.sa.admin.module.business.jwpy.domain.entity.WtczEntity;
import net.lab1024.sa.admin.module.business.jwpy.domain.entity.WtczYyEntity;
import net.lab1024.sa.admin.module.business.jwpy.domain.entity.WtczHfhcEntity;
import net.lab1024.sa.admin.module.business.jwpy.domain.form.WtczQueryForm;
import net.lab1024.sa.admin.module.business.jwpy.domain.form.WtczAddForm;
import net.lab1024.sa.admin.module.business.jwpy.domain.form.WtczUpdateForm;
import net.lab1024.sa.admin.module.business.jwpy.domain.vo.WtczVO;
import net.lab1024.sa.admin.module.business.jwpy.domain.vo.WtczYyVO;
import net.lab1024.sa.admin.module.business.jwpy.domain.vo.WtczHfhcVO;
import net.lab1024.sa.base.common.domain.PageResult;
import net.lab1024.sa.base.common.domain.ResponseDTO;
import net.lab1024.sa.base.common.util.SmartBeanUtil;
import net.lab1024.sa.base.common.util.SmartPageUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* 警务评议与问题处置 业务服务类
*
* @Author Antigravity
* @Date 2026-06-09
*/
@Service
@Slf4j
public class WtczService {
@Resource
private WtczDao wtczDao;
@Resource
private WtczYyDao wtczYyDao;
@Resource
private WtczHfhcDao wtczHfhcDao;
/**
* 分页查询评议工单列表
*
* @param queryForm 查询过滤参数
* @return 分页展示结果
*/
@SuppressWarnings("unchecked")
public ResponseDTO<PageResult<WtczVO>> queryPage(WtczQueryForm queryForm) {
Page<WtczEntity> page = (Page<WtczEntity>) SmartPageUtil.convert2PageQuery(queryForm);
LambdaQueryWrapper<WtczEntity> wrapper = Wrappers.lambdaQuery();
// 大类分类 (1短信评警回访、2民意热线、3网络民意、4民意拓展、5民意调查)
if (StringUtils.isNotBlank(queryForm.getSjlyqd())) {
wrapper.eq(WtczEntity::getSjlyqd, queryForm.getSjlyqd());
}
// 业务小类 (CZZX_SJLY_xx)
if (StringUtils.isNotBlank(queryForm.getSjlyNo())) {
this.initMockDataIfEmpty(queryForm.getSjlyNo());
wrapper.eq(WtczEntity::getSjlyNo, queryForm.getSjlyNo());
}
// 工单状态
if (StringUtils.isNotBlank(queryForm.getGdzt())) {
wrapper.eq(WtczEntity::getGdzt, queryForm.getGdzt());
}
// 受理编号
if (StringUtils.isNotBlank(queryForm.getSlbh())) {
wrapper.eq(WtczEntity::getSlbh, queryForm.getSlbh());
}
// 手机号精确查询
if (StringUtils.isNotBlank(queryForm.getLxdh())) {
wrapper.eq(WtczEntity::getLxdh, queryForm.getLxdh());
}
// 民警姓名模糊查询
if (StringUtils.isNotBlank(queryForm.getSjfjxm())) {
wrapper.like(WtczEntity::getSjfjxm, queryForm.getSjfjxm());
}
// 按 ID 降序排列展示
wrapper.orderByDesc(WtczEntity::getId);
wtczDao.selectPage(page, wrapper);
List<WtczVO> voList = SmartBeanUtil.copyList(page.getRecords(), WtczVO.class);
PageResult<WtczVO> pageResult = SmartPageUtil.convert2PageResult(page, voList);
return ResponseDTO.ok(pageResult);
}
/**
* 检测若该小类暂无数据则自动往 t_czzx_wtczt_czzx_wtcz_yyt_czzx_wtcz_hfhc 中注入 3 Mock 数据方便流程联调与演示
*
* @param sjlyNo 业务来源小类
*/
private synchronized void initMockDataIfEmpty(String sjlyNo) {
Long count = wtczDao.selectCount(Wrappers.<WtczEntity>lambdaQuery().eq(WtczEntity::getSjlyNo, sjlyNo));
if (count != null && count > 0) {
return;
}
log.info("检测到业务小类 {} 暂无物理数据,开始自动初始化Mock测试数据...", sjlyNo);
for (int i = 1; i <= 3; i++) {
String slbh = "GD-" + sjlyNo + "-20260609-" + String.format("%03d", i);
WtczEntity entity = new WtczEntity();
entity.setSlbh(slbh);
entity.setCityCode("3301");
entity.setCityName("杭州市");
entity.setSqsj("2026-06-09 10:00:00");
// 工单当前处理状态:0已录入、1办结中、2已办结
entity.setGdzt(String.valueOf(i - 1));
// 首访满意度结果:1满意、2不满意
entity.setSfjg(i == 1 ? "1" : "2");
// 诉求分类
entity.setSqfl("CZZX_SQFL_0" + i);
entity.setGdbq("民警服务-办事拖延-态度生硬");
entity.setSjlyqd("1"); // 短信评警回访
entity.setSjlyNo(sjlyNo);
entity.setSjdwMc("城东派出所");
entity.setSjdwCode("330104001");
entity.setSjjzMc("派出所");
entity.setSsqkNo(i == 1 ? "3" : "1"); // 是否属实
entity.setSjmjMc("张警官");
entity.setWzqkNo(i == 1 ? "2" : "1"); // 问责情况
entity.setTrueFlag("群众反馈的办事流程迟缓、警员态度急躁情况属实,已约谈教育相关责任人。");
entity.setSfsq(0);
entity.setSqnr("群众于6月9日拨打110报警求助,派出所在接警响应与跟进处理阶段工作态度生硬,且未能及时反馈进展。");
entity.setCljg("江干分局已约谈当值张警官,并由所领导带领当事人向群众赔礼道歉,现已达成谅解,整改措施已落实到位。");
entity.setDxfsnr("【江干分局】您的警务评议工单已录入。");
entity.setDxhfnr("收到了,希望改进。");
entity.setDxfssj("2026-06-09 10:05:00");
entity.setDxhfsj("2026-06-09 10:20:00");
entity.setTjsj("2026-06-09 11:00:00");
entity.setOrgCode("330104");
entity.setGdmyqk(i == 1 ? "1" : "2");
entity.setCreateTime("2026-06-09 10:00:00");
entity.setOrgName("江干分局");
entity.setSfsjfj(1);
entity.setLxdh("1385800000" + i);
entity.setSqrZjhm("3301041990010100" + i + "X");
entity.setSqrXb(i == 1 ? "1" : "2");
entity.setFpyNo("FPY-00" + i);
entity.setFpyName("王访评员");
entity.setSjdwName("城东派出所");
entity.setSfnm(0);
entity.setSjdwId(1001L);
entity.setSjmjIds("1002,1003");
entity.setSjjzNo("SYSTEM_JZ_01");
entity.setSqrId(10001.0);
entity.setSqrXm("陈先生");
entity.setSqrHjdxz("浙江省杭州市江干区秋涛北路233号");
entity.setSqrXzdxz("浙江省杭州市江干区新塘路99号");
entity.setGljqBh("JQ-20260609-00" + i);
entity.setGlajBh("AJ-20260609-00" + i);
entity.setSqdj("01");
entity.setGjz("态度");
entity.setSfyyq("0");
entity.setWtms("警员处理警情时态度生硬,未给予耐心解答");
entity.setQzmyqk(i == 1 ? "CZZX_MYD_01" : "CZZX_MYD_03"); // 满意 / 不满意
wtczDao.insert(entity);
// 自动插入配套的首访录音
WtczYyEntity yyEntity = new WtczYyEntity();
yyEntity.setSlbh(slbh);
yyEntity.setSourceCity("杭州市");
yyEntity.setThsj(java.time.LocalDateTime.now().minusHours(2));
yyEntity.setThhm("1385800000" + i);
yyEntity.setThfx("2"); // 呼出
yyEntity.setThsc(90L + i * 30L);
yyEntity.setLydz("https://www.w3school.com.cn/i/horse.mp3");
yyEntity.setThdwMc("城东派出所");
yyEntity.setCreateTime(java.time.LocalDateTime.now());
yyEntity.setSyncTime(java.time.LocalDateTime.now());
yyEntity.setOrgCode("330104");
yyEntity.setLydh("0571-87280001");
yyEntity.setThdwId(1001L);
yyEntity.setYyId(2000L + i);
wtczYyDao.insert(yyEntity);
// 自动插入配套的二次回访核实记录
WtczHfhcEntity hfhcEntity = new WtczHfhcEntity();
hfhcEntity.setSlbh(slbh);
hfhcEntity.setSourceCity("杭州市");
hfhcEntity.setHfqksm("电话回访核实:民警已主动上门致歉,群众表示接受道歉,并反馈称派出所的整改诚意足够,目前对处理情况表示满意。");
hfhcEntity.setCjsj(java.time.LocalDateTime.now().minusMinutes(30));
hfhcEntity.setLxdh("1385800000" + i);
hfhcEntity.setTjrXm("李回访员");
hfhcEntity.setQzmyqkNo("1"); // 满意
hfhcEntity.setFjUuid("fj-uuid-mock-00" + i);
hfhcEntity.setCreateTime(java.time.LocalDateTime.now());
hfhcEntity.setSyncTime(java.time.LocalDateTime.now());
hfhcEntity.setOrgCode("330104");
hfhcEntity.setSfyz("1");
hfhcEntity.setXfjd("3");
hfhcEntity.setBldwId("1001");
hfhcEntity.setWtczId(String.valueOf(entity.getId()));
wtczHfhcDao.insert(hfhcEntity);
}
}
/**
* 添加评议工单
*
* @param addForm 新增表单数据
* @return 统一响应体
*/
@Transactional(rollbackFor = Exception.class)
public ResponseDTO<String> add(WtczAddForm addForm) {
// 校验受理编号是否唯一
long count = wtczDao.selectCount(Wrappers.<WtczEntity>lambdaQuery().eq(WtczEntity::getSlbh, addForm.getSlbh()));
if (count > 0) {
return ResponseDTO.userErrorParam("受理编号已存在,不可重复添加");
}
WtczEntity entity = SmartBeanUtil.copy(addForm, WtczEntity.class);
wtczDao.insert(entity);
return ResponseDTO.ok("添加成功");
}
/**
* 更新评议工单
*
* @param updateForm 修改表单数据
* @return 统一响应体
*/
@Transactional(rollbackFor = Exception.class)
public ResponseDTO<String> update(WtczUpdateForm updateForm) {
WtczEntity entity = wtczDao.selectById(updateForm.getId());
if (entity == null) {
return ResponseDTO.userErrorParam("要修改的工单不存在");
}
// 校验更新后的受理编号是否与其他工单冲突
long count = wtczDao.selectCount(Wrappers.<WtczEntity>lambdaQuery()
.eq(WtczEntity::getSlbh, updateForm.getSlbh())
.ne(WtczEntity::getId, updateForm.getId()));
if (count > 0) {
return ResponseDTO.userErrorParam("受理编号已被其他工单占用");
}
SmartBeanUtil.copyProperties(updateForm, entity);
wtczDao.updateById(entity);
return ResponseDTO.ok("更新成功");
}
/**
* 单个删除工单
*
* @param id 工单主键ID
* @return 统一响应体
*/
@Transactional(rollbackFor = Exception.class)
public ResponseDTO<String> delete(Long id) {
if (id == null) {
return ResponseDTO.userErrorParam("ID不能为空");
}
wtczDao.deleteById(id);
return ResponseDTO.ok("删除成功");
}
/**
* 批量删除工单
*
* @param idList ID 列表
* @return 统一响应体
*/
@Transactional(rollbackFor = Exception.class)
public ResponseDTO<String> batchDelete(List<Long> idList) {
if (CollectionUtils.isEmpty(idList)) {
return ResponseDTO.userErrorParam("待删除的列表不能为空");
}
wtczDao.deleteBatchIds(idList);
return ResponseDTO.ok("批量删除成功");
}
/**
* 获取工单详情 (组合主表首访通话录音以及二次回访历史信息)
*
* @param id 工单主键ID
* @return 整合后的工单详细视图
*/
public ResponseDTO<WtczVO> getDetail(Long id) {
WtczEntity entity = wtczDao.selectById(id);
if (entity == null) {
return ResponseDTO.userErrorParam("工单不存在");
}
WtczVO vo = SmartBeanUtil.copy(entity, WtczVO.class);
// 1. 查询并聚合首访通话语音列表
if (StringUtils.isNotBlank(vo.getSlbh())) {
List<WtczYyEntity> yyEntities = wtczYyDao.selectList(Wrappers.<WtczYyEntity>lambdaQuery()
.eq(WtczYyEntity::getSlbh, vo.getSlbh())
.orderByDesc(WtczYyEntity::getId));
if (CollectionUtils.isNotEmpty(yyEntities)) {
vo.setCzzxWtczYyList(SmartBeanUtil.copyList(yyEntities, WtczYyVO.class));
}
// 2. 查询并聚合二次回访核实记录
List<WtczHfhcEntity> hfhcEntities = wtczHfhcDao.selectList(Wrappers.<WtczHfhcEntity>lambdaQuery()
.eq(WtczHfhcEntity::getSlbh, vo.getSlbh())
.orderByDesc(WtczHfhcEntity::getId));
if (CollectionUtils.isNotEmpty(hfhcEntities)) {
vo.setCzzxWtczHfhcList(SmartBeanUtil.copyList(hfhcEntities, WtczHfhcVO.class));
}
}
return ResponseDTO.ok(vo);
}
}

4
smart-flow-api/sa-admin/src/main/resources/mapper/business/jwpy/MessageDetailMapper.xml

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="net.lab1024.sa.admin.module.business.jwpy.dao.MessageDetailDao">
</mapper>

4
smart-flow-api/sa-admin/src/main/resources/mapper/business/jwpy/WtczHfhcMapper.xml

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="net.lab1024.sa.admin.module.business.jwpy.dao.WtczHfhcDao">
</mapper>

4
smart-flow-api/sa-admin/src/main/resources/mapper/business/jwpy/WtczMapper.xml

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="net.lab1024.sa.admin.module.business.jwpy.dao.WtczDao">
</mapper>

4
smart-flow-api/sa-admin/src/main/resources/mapper/business/jwpy/WtczYyMapper.xml

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="net.lab1024.sa.admin.module.business.jwpy.dao.WtczYyDao">
</mapper>

52
smart-flow-web/src/api/business/jwpy/wtcz-api.js

@ -0,0 +1,52 @@
/**
* 警务评议与问题处置 api 封装
*
* @Author: Antigravity
* @Date: 2026-06-09
*/
import { postRequest, getRequest } from '/@/lib/axios';
export const wtczApi = {
/**
* 分页查询评议工单
*/
queryPage: (param) => {
return postRequest('/jwpy/wtcz/queryPage', param);
},
/**
* 添加工单
*/
add: (param) => {
return postRequest('/jwpy/wtcz/add', param);
},
/**
* 修改工单
*/
update: (param) => {
return postRequest('/jwpy/wtcz/update', param);
},
/**
* 删除工单
*/
delete: (id) => {
return getRequest(`/jwpy/wtcz/delete/${id}`);
},
/**
* 批量删除工单
*/
batchDelete: (idList) => {
return postRequest('/jwpy/wtcz/batchDelete', idList);
},
/**
* 获取工单详情 (组合首访语音和二次回访记录)
*/
getDetail: (id) => {
return getRequest(`/jwpy/wtcz/detail/${id}`);
}
};

14
smart-flow-web/src/constants/support/dict-const.js

@ -15,8 +15,22 @@ export const DICT_SPLIT = ',';
export const DICT_CODE_ENUM = {
GOODS_PLACE: 'GOODS_PLACE',
LEAVE_TYPE: 'LEAVE_TYPE',
SYSTEM_CLASSIFICATION: 'SYSTEM_CLASSIFICATION', // 数据大类
BUSINESS_CLASSIFICATION: 'BUSINESS_CLASSIFICATION', // 业务小类
SYSTEM_JZ: 'SYSTEM_JZ', // 涉及警种
IS_FACT: 'IS_FACT', // 是否属实 (核查结论)
CALL_DIRECTION: 'CALL_DIRECTION', // 呼叫方向
ORDER_SATISFACTION: 'ORDER_SATISFACTION', // 工单满意度
IS_ENTERPRISE_RELATED: 'IS_ENTERPRISE_RELATED', // 是否涉企
TRUTH_STATUS: 'TRUTH_STATUS', // 属实情况 (诉求属实分类)
CZZX_WZQK: 'CZZX_WZQK', // 问责情况
CALLBACK_SATISFACTION: 'CALLBACK_SATISFACTION', // 回访满意度
CZZX_SQFL: 'CZZX_SQFL', // 诉求分类
};
export default {
DICT_CODE_ENUM,
};

359
smart-flow-web/src/views/jwpy/jwpy/flow/index.vue

@ -1,6 +1,13 @@
<!--
* 警务评议与问题处置 工单管理列表
*
* @Author: Antigravity
* @Date: 2026-06-09
-->
<template>
<div class="page-container">
<div class="glass-card">
<!-- 头部介绍区域 -->
<div class="header">
<a-space size="middle">
<div class="icon-wrapper">
@ -14,78 +21,344 @@
</div>
<div class="content-box">
<!-- 头部查询区域 -->
<!-- 头部查询过滤区域 -->
<a-form layout="inline" class="query-form">
<a-form-item label="工单编号">
<a-input placeholder="请输入工单编号" />
<a-input v-model:value="queryForm.slbh" placeholder="请输入工单受理编号" style="width: 180px" />
</a-form-item>
<a-form-item label="手机号码">
<a-input v-model:value="queryForm.lxdh" placeholder="请输入诉求人手机号" style="width: 150px" />
</a-form-item>
<a-form-item label="满意度">
<a-select placeholder="请选择" style="width: 120px">
<a-select-option value="1">满意</a-select-option>
<a-select-option value="2">基本满意</a-select-option>
<a-select-option value="3">不满意</a-select-option>
</a-select>
<DictSelect :dict-code="DICT_CODE_ENUM.CALLBACK_SATISFACTION" placeholder="请选择" v-model:value="queryForm.qzmyqk" width="120px" allowClear />
</a-form-item>
<a-form-item>
<a-button type="primary">查询</a-button>
<a-button style="margin-left: 8px">重置</a-button>
<a-button type="primary" @click="onSearch">查询</a-button>
<a-button style="margin-left: 8px" @click="resetQuery">重置</a-button>
</a-form-item>
</a-form>
<!-- 数据表格占位 -->
<div class="table-placeholder">
<a-empty description="暂无物理数据,业务表 t_jwpy_order 物理开发与关联联调中" />
<!-- 表格顶部操作按钮 -->
<div class="table-operate-row" style="margin-bottom: 12px">
<a-space>
<a-button type="primary" @click="showForm()">
<template #icon><PlusOutlined /></template>
新建工单
</a-button>
<a-button
type="primary"
danger
:disabled="selectedRowKeyList.length === 0"
@click="confirmBatchDelete"
>
<template #icon><DeleteOutlined /></template>
批量删除
</a-button>
</a-space>
</div>
<!-- 数据表格 -->
<a-table
:dataSource="tableData"
:columns="columns"
rowKey="id"
bordered
:loading="tableLoading"
:pagination="false"
:row-selection="{ selectedRowKeys: selectedRowKeyList, onChange: onSelectChange }"
class="custom-table"
>
<template #bodyCell="{ text, record, column }">
<!-- 满意度标签展示 -->
<template v-if="column.dataIndex === 'qzmyqk'">
<DictLabel :dict-code="DICT_CODE_ENUM.CALLBACK_SATISFACTION" :data-value="text" />
</template>
<!-- 处理状态标签 -->
<template v-if="column.dataIndex === 'gdzt'">
<a-tag :color="text === '2' ? 'green' : text === '1' ? 'orange' : 'blue'">
{{ text === '2' ? '已办结' : text === '1' ? '办结中' : '已录入' }}
</a-tag>
</template>
<!-- 操作列 -->
<template v-if="column.dataIndex === 'action'">
<div class="smart-table-operate">
<a-button type="link" @click="showDetail(record.id)">详情</a-button>
<a-button type="link" @click="showForm(record)">编辑</a-button>
<a-button type="link" danger @click="onDelete(record.id)">删除</a-button>
</div>
</template>
</template>
</a-table>
<!-- 分页 -->
<div class="smart-query-table-page" style="margin-top: 15px; text-align: right">
<a-pagination
showSizeChanger
showQuickJumper
show-less-items
:pageSizeOptions="PAGE_SIZE_OPTIONS"
:defaultPageSize="queryForm.pageSize"
v-model:current="queryForm.pageNum"
v-model:pageSize="queryForm.pageSize"
:total="total"
@change="queryData"
@showSizeChange="queryData"
:show-total="(total) => `共${total}条`"
/>
</div>
</div>
</div>
<!-- 表单抽屉与详情抽屉 -->
<WtczForm ref="formRef" @reloadList="queryData" />
<WtczDetail ref="detailRef" />
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue';
import { ref, computed, reactive, onMounted } from 'vue';
import { useRoute } from 'vue-router';
import { CommentOutlined } from '@ant-design/icons-vue';
import { message, Modal } from 'ant-design-vue';
import { CommentOutlined, PlusOutlined, DeleteOutlined } from '@ant-design/icons-vue';
import { wtczApi } from '/@/api/business/jwpy/wtcz-api';
import { PAGE_SIZE_OPTIONS } from '/@/constants/common-const';
import WtczForm from './wtcz-form.vue';
import WtczDetail from './wtcz-detail.vue';
import { DICT_CODE_ENUM } from '/@/constants/support/dict-const.js';
import DictSelect from '/@/components/support/dict-select/index.vue';
import DictLabel from '/@/components/support/dict-label/index.vue';
import { useDictStore } from '/@/store/modules/system/dict.js';
const route = useRoute();
//
const pageTitle = computed(() => {
//
const currentBizTypeCode = computed(() => {
const path = route.path;
if (path.includes('/jcj')) return '110接处警评议';
if (path.includes('/hz')) return '户政窗口评议';
if (path.includes('/crj')) return '出入境评议';
if (path.includes('/cjg')) return '车驾管评议';
if (path.includes('/za')) return '治安管理评议';
if (path.includes('/js')) return '监所管理评议';
if (path.includes('/xl')) return '巡逻防控评议';
if (path.includes('/xzsp')) return '行政审批评议';
if (path.includes('/ajbl')) return '案件办理评议';
if (path.includes('/xf')) return '信访评议';
if (path.includes('/wq')) return '民辅警维权';
if (path.includes('/sqfw')) return '涉企服务评议';
return '警务评议通用';
if (path.includes('/jcj')) return 'CZZX_SJLY_03';
if (path.includes('/hz')) return 'CZZX_SJLY_06';
if (path.includes('/crj')) return 'CZZX_SJLY_10';
if (path.includes('/cjg')) return 'CZZX_SJLY_04';
if (path.includes('/za')) return 'CZZX_SJLY_12';
if (path.includes('/js')) return 'CZZX_SJLY_13';
if (path.includes('/xl')) return 'CZZX_SJLY_14';
if (path.includes('/xzsp')) return 'CZZX_SJLY_11';
if (path.includes('/ajbl')) return 'CZZX_SJLY_07';
if (path.includes('/xf')) return 'CZZX_SJLY_08';
if (path.includes('/wq')) return 'CZZX_SJLY_17';
if (path.includes('/sqfw')) return 'CZZX_SJLY_18';
return undefined;
});
//
const pageTitle = computed(() => {
const code = currentBizTypeCode.value;
if (!code) return '警务评议通用';
const label = useDictStore().getDataLabels(DICT_CODE_ENUM.BUSINESS_CLASSIFICATION, code);
return label ? `${label}评议` : '警务评议通用';
});
//
const currentBizTypeName = computed(() => {
const path = route.path;
if (path.includes('/jcj')) return '110接处警 (CZZX_SJLY_03)';
if (path.includes('/hz')) return '户政窗口 (CZZX_SJLY_06)';
if (path.includes('/crj')) return '出入境 (CZZX_SJLY_10)';
if (path.includes('/cjg')) return '车驾管 (CZZX_SJLY_04)';
if (path.includes('/za')) return '治安管理 (CZZX_SJLY_12)';
if (path.includes('/js')) return '监所管理 (CZZX_SJLY_13)';
if (path.includes('/xl')) return '巡逻防控 (CZZX_SJLY_14)';
if (path.includes('/xzsp')) return '行政审批 (CZZX_SJLY_11)';
if (path.includes('/ajbl')) return '案件办理 (CZZX_SJLY_07)';
if (path.includes('/xf')) return '信访 (CZZX_SJLY_08)';
if (path.includes('/wq')) return '民辅警维权 (CZZX_SJLY_17)';
if (path.includes('/sqfw')) return '涉企服务 (CZZX_SJLY_18)';
return '未定义';
const code = currentBizTypeCode.value;
if (!code) return '未定义';
const label = useDictStore().getDataLabels(DICT_CODE_ENUM.BUSINESS_CLASSIFICATION, code);
return label ? `${label} (${code})` : `未知小类 (${code})`;
});
// ---------------------------- ----------------------------
const columns = [
{ title: '工单受理编号', dataIndex: 'slbh', ellipsis: true },
{ title: '诉求人姓名', dataIndex: 'sqrXm', width: 100, ellipsis: true },
{ title: '联系电话', dataIndex: 'lxdh', width: 130 },
{ title: '涉及单位', dataIndex: 'sjdwMc', ellipsis: true },
{ title: '涉及民警', dataIndex: 'sjmjMc', width: 100 },
{ title: '群众满意度', dataIndex: 'qzmyqk', width: 100, align: 'center' },
{ title: '工单状态', dataIndex: 'gdzt', width: 100, align: 'center' },
{ title: '诉求时间', dataIndex: 'sqsj', width: 150 },
{ title: '操作', dataIndex: 'action', width: 160, align: 'center', fixed: 'right' },
];
// ---------------------------- ----------------------------
const queryFormDefault = {
slbh: undefined,
lxdh: undefined,
qzmyqk: undefined,
sjlyNo: undefined,
pageNum: 1,
pageSize: 10,
};
const queryForm = reactive({ ...queryFormDefault });
const tableLoading = ref(false);
const tableData = ref([]);
const total = ref(0);
//
async function queryData() {
tableLoading.value = true;
try {
//
queryForm.sjlyNo = currentBizTypeCode.value;
const res = await wtczApi.queryPage(queryForm);
tableData.value = res.data?.list || [];
total.value = res.data?.total || 0;
} catch (err) {
message.error('获取评议数据列表失败');
} finally {
tableLoading.value = false;
}
}
function onSearch() {
queryForm.pageNum = 1;
queryData();
}
function resetQuery() {
const size = queryForm.pageSize;
Object.assign(queryForm, queryFormDefault);
queryForm.pageSize = size;
queryData();
}
onMounted(queryData);
// ---------------------------- / ----------------------------
const formRef = ref();
function showForm(rowData) {
//
const data = rowData ? { ...rowData } : { sjlyNo: currentBizTypeCode.value };
formRef.value.show(data);
}
// ---------------------------- ----------------------------
const detailRef = ref();
function showDetail(id) {
detailRef.value.show(id);
}
// ---------------------------- ----------------------------
function onDelete(id) {
Modal.confirm({
title: '温馨提示',
content: '确定要删除该条评议工单数据吗?',
okText: '删除',
okType: 'danger',
onOk() {
requestDelete(id);
},
cancelText: '取消',
});
}
async function requestDelete(id) {
try {
await wtczApi.delete(id);
message.success('删除成功');
queryData();
} catch (err) {
message.error('删除失败,请稍后重试');
}
}
// ---------------------------- ----------------------------
const selectedRowKeyList = ref([]);
function onSelectChange(keys) {
selectedRowKeyList.value = keys;
}
function confirmBatchDelete() {
Modal.confirm({
title: '批量删除提示',
content: `确定要批量删除已选中的 ${selectedRowKeyList.value.length} 条工单数据吗?`,
okText: '批量删除',
okType: 'danger',
onOk() {
requestBatchDelete();
},
cancelText: '取消',
});
}
async function requestBatchDelete() {
try {
await wtczApi.batchDelete(selectedRowKeyList.value);
message.success('批量删除成功');
selectedRowKeyList.value = [];
queryData();
} catch (err) {
message.error('批量删除失败,请重试');
}
}
</script>
<style scoped>
.page-container {
padding: 16px;
min-height: calc(100vh - 120px);
}
.glass-card {
background: rgba(255, 255, 255, 0.75);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.4);
border-radius: 12px;
padding: 24px;
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.05);
}
.header {
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
padding-bottom: 16px;
margin-bottom: 20px;
}
.icon-wrapper {
background: linear-gradient(135deg, #3f86f8 0%, #1890ff 100%);
width: 48px;
height: 48px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
color: white;
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.2);
}
.icon {
font-size: 24px;
}
.title {
font-size: 18px;
font-weight: 600;
color: #1a1a1a;
margin: 0;
}
.subtitle {
font-size: 13px;
color: #666;
margin: 4px 0 0 0;
}
.query-form {
margin-bottom: 20px;
padding: 16px;
background: rgba(255, 255, 255, 0.5);
border-radius: 8px;
border: 1px solid rgba(0, 0, 0, 0.02);
}
.custom-table {
background: transparent;
}
.smart-table-operate :deep(.ant-btn-link) {
padding: 0 4px;
}
</style>

228
smart-flow-web/src/views/jwpy/jwpy/flow/wtcz-detail.vue

@ -0,0 +1,228 @@
<!--
* 警务评议与问题处置 工单详情抽屉
*
* @Author: Antigravity
* @Date: 2026-06-09
-->
<template>
<a-modal
title="工单详情与评议痕迹"
:width="850"
:open="visibleFlag"
@cancel="onClose"
:destroyOnClose="true"
>
<div v-if="loading" class="loading-wrapper">
<a-spin tip="加载中..." />
</div>
<div v-else class="detail-container">
<!-- 1. 基本信息卡片 -->
<a-card title="基本信息" size="small" class="detail-card">
<a-descriptions :column="2" bordered size="small">
<a-descriptions-item label="受理编号">{{ detail.slbh || '暂无' }}</a-descriptions-item>
<a-descriptions-item label="所属地市">{{ detail.cityName || detail.cityCode || '暂无' }}</a-descriptions-item>
<a-descriptions-item label="数据大类">
<DictLabel :dict-code="DICT_CODE_ENUM.SYSTEM_CLASSIFICATION" :data-value="detail.sjlyqd" />
</a-descriptions-item>
<a-descriptions-item label="业务小类">
<DictLabel :dict-code="DICT_CODE_ENUM.BUSINESS_CLASSIFICATION" :data-value="detail.sjlyNo" />
</a-descriptions-item>
<a-descriptions-item label="诉求分类">
<DictLabel :dict-code="DICT_CODE_ENUM.CZZX_SQFL" :data-value="detail.sqfl" />
</a-descriptions-item>
<a-descriptions-item label="诉求等级">{{ detail.sqdj || '暂无' }}</a-descriptions-item>
<a-descriptions-item label="涉及单位">{{ detail.sjdwMc || '暂无' }}</a-descriptions-item>
<a-descriptions-item label="涉及民警">{{ detail.sjmjMc || '暂无' }}</a-descriptions-item>
<a-descriptions-item label="涉及警种">
<DictLabel :dict-code="DICT_CODE_ENUM.SYSTEM_JZ" :data-value="detail.sjjzNo" />
</a-descriptions-item>
<a-descriptions-item label="关键字">{{ detail.gjz || '暂无' }}</a-descriptions-item>
<a-descriptions-item label="是否已延期">{{ detail.sfyyq || '暂无' }}</a-descriptions-item>
<a-descriptions-item label="当前状态">
<a-tag :color="detail.gdzt === '2' ? 'green' : detail.gdzt === '1' ? 'orange' : 'blue'">
{{ detail.gdzt === '2' ? '已办结' : detail.gdzt === '1' ? '办结中' : '已录入' }}
</a-tag>
</a-descriptions-item>
</a-descriptions>
</a-card>
<!-- 2. 诉求人信息卡片 -->
<a-card title="诉求人(调查人)信息" size="small" class="detail-card">
<a-descriptions :column="2" bordered size="small">
<a-descriptions-item label="姓名">{{ detail.sqrXm || '匿名' }}</a-descriptions-item>
<a-descriptions-item label="联系电话">{{ detail.lxdh || '暂无' }}</a-descriptions-item>
<a-descriptions-item label="身份证号">{{ detail.sqrZjhm || '暂无' }}</a-descriptions-item>
<a-descriptions-item label="性别">
{{ detail.sqrXb === '1' ? '男' : detail.sqrXb === '2' ? '女' : '未知' }}
</a-descriptions-item>
<a-descriptions-item label="户籍地详址" :span="2">{{ detail.sqrHjdxz || '暂无' }}</a-descriptions-item>
<a-descriptions-item label="现住地详址" :span="2">{{ detail.sqrXzdxz || '暂无' }}</a-descriptions-item>
</a-descriptions>
</a-card>
<!-- 3. 诉求描述及拟办意见 -->
<a-card title="诉求与处理描述" size="small" class="detail-card">
<div class="desc-box">
<div class="desc-title">调查/诉求描述</div>
<div class="desc-content">{{ detail.sqnr || '暂无详细内容' }}</div>
</div>
<div class="desc-box" style="margin-top: 12px">
<div class="desc-title">最终拟办意见与处理结果</div>
<div class="desc-content">{{ detail.cljg || '暂无拟办意见' }}</div>
</div>
</a-card>
<!-- 4. 首访录音电话记录 -->
<a-card title="首访电话记录(录音试听)" size="small" class="detail-card">
<a-table
:dataSource="detail.czzxWtczYyList || []"
:columns="yyColumns"
size="small"
bordered
:pagination="false"
rowKey="id"
>
<template #bodyCell="{ text, record, column }">
<template v-if="column.dataIndex === 'thfx'">
<DictLabel :dict-code="DICT_CODE_ENUM.CALL_DIRECTION" :data-value="text" />
</template>
<template v-if="column.dataIndex === 'action'">
<div v-if="record.lydz" class="audio-player">
<!-- 音频试听播放器 -->
<audio :src="record.lydz" controls preload="none" style="height: 32px; width: 220px"></audio>
<a-button type="link" size="small" :href="record.lydz" target="_blank" style="margin-left: 8px">下载</a-button>
</div>
<span v-else style="color: #999">暂无录音文件</span>
</template>
</template>
</a-table>
</a-card>
<!-- 5. 二次回访整改历史 -->
<a-card title="二次回访与整改核实历史" size="small" class="detail-card">
<a-table
:dataSource="detail.czzxWtczHfhcList || []"
:columns="hfhcColumns"
size="small"
bordered
:pagination="false"
rowKey="id"
>
<template #bodyCell="{ text, record, column }">
<template v-if="column.dataIndex === 'qzmyqkNo'">
<DictLabel :dict-code="DICT_CODE_ENUM.CALLBACK_SATISFACTION" :data-value="text" />
</template>
<template v-if="column.dataIndex === 'sfyz'">
<DictLabel :dict-code="DICT_CODE_ENUM.IS_FACT" :data-value="text" />
</template>
<template v-if="column.dataIndex === 'fjUuid'">
<a-button v-if="record.fjUuid" type="primary" size="small" ghost :href="record.fjUuid" target="_blank">
查看附件
</a-button>
<span v-else style="color: #999">无附件</span>
</template>
</template>
</a-table>
</a-card>
</div>
<template #footer>
<div style="text-align: right">
<a-button @click="onClose">关闭</a-button>
</div>
</template>
</a-modal>
</template>
<script setup>
import { ref } from 'vue';
import { message } from 'ant-design-vue';
import { wtczApi } from '/@/api/business/jwpy/wtcz-api';
import { DICT_CODE_ENUM } from '/@/constants/support/dict-const.js';
import DictLabel from '/@/components/support/dict-label/index.vue';
const visibleFlag = ref(false);
const loading = ref(false);
const detail = ref({});
function show(id) {
visibleFlag.value = true;
loadDetail(id);
}
function onClose() {
detail.value = {};
visibleFlag.value = false;
}
//
async function loadDetail(id) {
loading.value = true;
try {
const res = await wtczApi.getDetail(id);
detail.value = res.data || {};
} catch (err) {
message.error('加载详情数据失败,请重试');
} finally {
loading.value = false;
}
}
// ------------------- -------------------
const yyColumns = [
{ title: '通话号码', dataIndex: 'thhm', width: 120 },
{ title: '呼叫方向', dataIndex: 'thfx', width: 100 },
{ title: '时长(秒)', dataIndex: 'thsc', width: 80 },
{ title: '录音回放/试听', dataIndex: 'action' },
];
const hfhcColumns = [
{ title: '回访人', dataIndex: 'tjrXm', width: 100 },
{ title: '回访满意度', dataIndex: 'qzmyqkNo', width: 110 },
{ title: '核实说明', dataIndex: 'hfqksm' },
{ title: '是否验证/属实', dataIndex: 'sfyz', width: 120 },
{ title: '相关整改附件', dataIndex: 'fjUuid', width: 110 },
];
defineExpose({
show,
});
</script>
<style scoped>
.loading-wrapper {
padding: 80px 0;
text-align: center;
}
.detail-card {
margin-bottom: 16px;
border-radius: 6px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
}
.desc-box {
background: #f8f9fa;
padding: 12px;
border-radius: 4px;
border-left: 3px solid #1890ff;
}
.desc-title {
font-weight: 600;
margin-bottom: 6px;
color: #333;
}
.desc-content {
color: #555;
white-space: pre-wrap;
line-height: 1.6;
}
.audio-player {
display: flex;
align-items: center;
}
</style>

283
smart-flow-web/src/views/jwpy/jwpy/flow/wtcz-form.vue

@ -0,0 +1,283 @@
<!--
* 警务评议与问题处置 表单抽屉
*
* @Author: Antigravity
* @Date: 2026-06-09
-->
<template>
<a-modal
:title="form.id ? '编辑工单' : '新建工单'"
:width="720"
:open="visibleFlag"
@cancel="onClose"
:maskClosable="false"
:destroyOnClose="true"
>
<a-form ref="formRef" :model="form" :rules="rules" layout="vertical">
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="受理编号" name="slbh">
<a-input v-model:value="form.slbh" placeholder="请输入受理编号" :disabled="!!form.id" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="数据来源大类" name="sjlyqd">
<DictSelect :dict-code="DICT_CODE_ENUM.SYSTEM_CLASSIFICATION" placeholder="请选择来源大类" v-model:value="form.sjlyqd" width="100%" />
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="业务来源小类" name="sjlyNo">
<DictSelect :dict-code="DICT_CODE_ENUM.BUSINESS_CLASSIFICATION" placeholder="请选择来源小类" v-model:value="form.sjlyNo" width="100%" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="诉求分类" name="sqfl">
<DictSelect :dict-code="DICT_CODE_ENUM.CZZX_SQFL" placeholder="请选择诉求分类" v-model:value="form.sqfl" width="100%" />
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="涉及单位" name="sjdwMc">
<a-input v-model:value="form.sjdwMc" placeholder="请输入涉及单位名称" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="涉及民警" name="sjmjMc">
<a-input v-model:value="form.sjmjMc" placeholder="请输入涉及民警姓名" />
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="涉及警种" name="sjjzNo">
<DictSelect :dict-code="DICT_CODE_ENUM.SYSTEM_JZ" placeholder="请选择涉及警种" v-model:value="form.sjjzNo" width="100%" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="关键字" name="gjz">
<a-input v-model:value="form.gjz" placeholder="请输入关键字" />
</a-form-item>
</a-col>
</a-row>
<a-divider style="margin: 12px 0">诉求人信息</a-divider>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="诉求人姓名" name="sqrXm">
<a-input v-model:value="form.sqrXm" placeholder="请输入诉求人姓名" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="诉求人电话" name="lxdh">
<a-input v-model:value="form.lxdh" placeholder="请输入诉求人电话" />
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="身份证号码" name="sqrZjhm">
<a-input v-model:value="form.sqrZjhm" placeholder="请输入身份证号码" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="性别" name="sqrXb">
<a-select v-model:value="form.sqrXb" placeholder="请选择性别">
<a-select-option value="1"></a-select-option>
<a-select-option value="2"></a-select-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="户籍地详址" name="sqrHjdxz">
<a-input v-model:value="form.sqrHjdxz" placeholder="请输入户籍地详址" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="现住地详址" name="sqrXzdxz">
<a-input v-model:value="form.sqrXzdxz" placeholder="请输入现住地详址" />
</a-form-item>
</a-col>
</a-row>
<a-divider style="margin: 12px 0">处理详述</a-divider>
<a-form-item label="调查内容" name="sqnr">
<a-textarea v-model:value="form.sqnr" placeholder="请输入诉求及调查详细内容" :rows="4" />
</a-form-item>
<a-form-item label="拟办意见/处理结果" name="cljg">
<a-textarea v-model:value="form.cljg" placeholder="请输入处理意见或办理结果" :rows="3" />
</a-form-item>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="工单状态" name="gdzt">
<a-select v-model:value="form.gdzt" placeholder="请选择状态">
<a-select-option value="0">已录入</a-select-option>
<a-select-option value="1">办结中</a-select-option>
<a-select-option value="2">已办结</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="群众满意度" name="qzmyqk">
<DictSelect :dict-code="DICT_CODE_ENUM.CALLBACK_SATISFACTION" placeholder="请选择满意度" v-model:value="form.qzmyqk" width="100%" />
</a-form-item>
</a-col>
</a-row>
</a-form>
<template #footer>
<a-space style="float: right">
<a-button @click="onClose">取消</a-button>
<a-button type="primary" @click="onSubmit">保存</a-button>
</a-space>
</template>
</a-modal>
</template>
<script setup>
import { reactive, ref, nextTick } from 'vue';
import { message } from 'ant-design-vue';
import _ from 'lodash';
import { SmartLoading } from '/@/components/framework/smart-loading';
import { wtczApi } from '/@/api/business/jwpy/wtcz-api';
import { smartSentry } from '/@/lib/smart-sentry';
import { DICT_CODE_ENUM } from '/@/constants/support/dict-const.js';
import DictSelect from '/@/components/support/dict-select/index.vue';
const emits = defineEmits(['reloadList']);
// ------------------------ ------------------------
const visibleFlag = ref(false);
function show(rowData) {
Object.assign(form, formDefault);
if (rowData && !_.isEmpty(rowData)) {
Object.assign(form, rowData);
}
visibleFlag.value = true;
nextTick(() => {
formRef.value.clearValidate();
});
}
function onClose() {
Object.assign(form, formDefault);
visibleFlag.value = false;
}
// ------------------------ ------------------------
const formRef = ref();
const formDefault = {
id: undefined,
slbh: undefined,
cityCode: undefined,
cityName: undefined,
sqsj: undefined,
gdzt: '0',
sfjg: undefined,
sqfl: undefined,
gdbq: undefined,
sjlyqd: undefined,
sjlyNo: undefined,
sjdwMc: undefined,
sjdwCode: undefined,
sjjzMc: undefined,
ssqkNo: undefined,
sjmjMc: undefined,
wzqkNo: undefined,
trueFlag: undefined,
sfsq: 0,
sqnr: undefined,
cljg: undefined,
dxfsnr: undefined,
dxhfnr: undefined,
dxfssj: undefined,
dxhfsj: undefined,
tjsj: undefined,
orgCode: undefined,
gdmyqk: undefined,
createTime: undefined,
syncTime: undefined,
orgName: undefined,
qymc: undefined,
sfsjfj: undefined,
sjfjxm: undefined,
sjfjjh: undefined,
lxdh: undefined,
sqrZjhm: undefined,
sqrXb: undefined,
fpyNo: undefined,
fpyName: undefined,
sjdwName: undefined,
sfnm: 0,
sjdwId: undefined,
sjmjIds: undefined,
sjjzNo: undefined,
sqrId: undefined,
sqrXm: undefined,
sqrHjdxz: undefined,
sqrXzdxz: undefined,
gljqBh: undefined,
glajBh: undefined,
sqdj: undefined,
gjz: undefined,
sfyyq: undefined,
wtms: undefined,
tjrId: undefined,
tjdwId: undefined,
qzmyqk: undefined,
};
let form = reactive({ ...formDefault });
const rules = {
slbh: [{ required: true, message: '工单受理编号 必填' }],
sjlyqd: [{ required: true, message: '请选择数据来源大类' }],
};
//
async function onSubmit() {
try {
await formRef.value.validateFields();
save();
} catch (err) {
message.error('参数验证错误,请仔细填写必要表单数据!');
}
}
async function save() {
SmartLoading.show();
try {
if (form.id) {
await wtczApi.update(form);
} else {
await wtczApi.add(form);
}
message.success('操作成功');
emits('reloadList');
onClose();
} catch (err) {
smartSentry.captureError(err);
} finally {
SmartLoading.hide();
}
}
defineExpose({
show,
});
</script>
Loading…
Cancel
Save