From da01bfaa4822481a70f18aed48333add4e306366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A0=82=E7=B3=96?= <2178503051@qq.com> Date: Mon, 29 Jun 2026 14:58:24 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=E5=94=AE=E5=90=8E?= =?UTF-8?q?=E6=8A=95=E8=AF=89=E6=B5=81=E7=A8=8B=E5=85=A8=E9=93=BE=E8=B7=AF?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=B8=8E=E5=8A=9F=E8=83=BD=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 本次提交完成了多项核心优化与功能新增: 1. 重构投诉受理流程状态,移除冗余的执行反馈阶段,简化为4个流程节点 2. 新增售后单关联客户、下游用户、工程信息等扩展字段,完善基础信息采集 3. 新增部门结构化意见表单与预览组件,优化部门意见填写与展示流程 4. 新增售后意见汇总页面,支持流程阶段筛选与详情查看 5. 优化合同列表页面,新增重置筛选按钮与默认备注逻辑 6. 新增PDF导出功能,完善钢卷信息展示列 7. 修复逻辑删除级联问题,新增任务过滤逻辑保障数据一致性 --- .../klp/flow/domain/TsComplaintAccept.java | 26 +- .../flow/domain/bo/TsComplaintAcceptBo.java | 32 +- .../flow/domain/vo/TsComplaintAcceptVo.java | 38 +- .../impl/TsComplaintAcceptServiceImpl.java | 16 +- .../impl/TsComplaintTaskServiceImpl.java | 8 + .../mapper/flow/TsComplaintAcceptMapper.xml | 6 + .../crm/contract/components/ContractList.vue | 2 + .../contract/components/ProductContent.vue | 2 +- klp-ui/src/views/crm/contract/index.vue | 3 +- .../objection/components/BasicInfoSection.vue | 112 +++- .../objection/components/CoilInfoSection.vue | 9 +- .../components/DepartmentOpinionSection.vue | 21 +- .../objection/components/DeptOpinionForm.vue | 146 ++++ .../components/DeptOpinionPreview.vue | 137 ++++ .../objection/components/ExportPdfDialog.vue | 621 ++++++++++++++++++ .../components/FlowOverviewSection.vue | 18 +- .../components/HeaderControlSection.vue | 10 +- klp-ui/src/views/wms/post/objection/index.vue | 68 +- .../src/views/wms/post/objection/opinion.vue | 43 +- .../src/views/wms/post/objection/summary.vue | 464 +++++++++++++ klp-ui/src/views/wms/post/objection/todo.vue | 6 +- 21 files changed, 1723 insertions(+), 65 deletions(-) create mode 100644 klp-ui/src/views/wms/post/objection/components/DeptOpinionForm.vue create mode 100644 klp-ui/src/views/wms/post/objection/components/DeptOpinionPreview.vue create mode 100644 klp-ui/src/views/wms/post/objection/components/ExportPdfDialog.vue create mode 100644 klp-ui/src/views/wms/post/objection/summary.vue diff --git a/klp-flow/src/main/java/com/klp/flow/domain/TsComplaintAccept.java b/klp-flow/src/main/java/com/klp/flow/domain/TsComplaintAccept.java index b7fa8a958..52d083f92 100644 --- a/klp-flow/src/main/java/com/klp/flow/domain/TsComplaintAccept.java +++ b/klp-flow/src/main/java/com/klp/flow/domain/TsComplaintAccept.java @@ -42,6 +42,30 @@ public class TsComplaintAccept extends BaseEntity { * 客户诉求 */ private String customerDemand; + /** + * 关联客户ID + */ + private Long customerId; + /** + * 下游使用用户名称 + */ + private String downstreamUserName; + /** + * 电话 + */ + private String phone; + /** + * 使用的工程名称 + */ + private String projectName; + /** + * 工程使用地点 + */ + private String projectLocation; + /** + * 产品用途 + */ + private String productUsage; /** * 客户照片凭证等 */ @@ -64,7 +88,7 @@ public class TsComplaintAccept extends BaseEntity { private Date auditTime; /** * 流程阶段: -1=待审核 2=部门意见填写中 3=待总负责人汇总方案 4=方案下发执行反馈中 5=全部办结 +1=待审核 2=部门意见填写中 3=待总负责人汇总方案 4=全部办结 */ private Long flowStatus; /** diff --git a/klp-flow/src/main/java/com/klp/flow/domain/bo/TsComplaintAcceptBo.java b/klp-flow/src/main/java/com/klp/flow/domain/bo/TsComplaintAcceptBo.java index 65f1772b4..1723c13cc 100644 --- a/klp-flow/src/main/java/com/klp/flow/domain/bo/TsComplaintAcceptBo.java +++ b/klp-flow/src/main/java/com/klp/flow/domain/bo/TsComplaintAcceptBo.java @@ -48,6 +48,36 @@ public class TsComplaintAcceptBo extends BaseEntity { */ private String customerDemand; + /** + * 关联客户ID + */ + private Long customerId; + + /** + * 下游使用用户名称 + */ + private String downstreamUserName; + + /** + * 电话 + */ + private String phone; + + /** + * 使用的工程名称 + */ + private String projectName; + + /** + * 工程使用地点 + */ + private String projectLocation; + + /** + * 产品用途 + */ + private String productUsage; + /** * 客户照片凭证等 */ @@ -75,7 +105,7 @@ public class TsComplaintAcceptBo extends BaseEntity { /** * 流程阶段: -1=待审核 2=部门意见填写中 3=待总负责人汇总方案 4=方案下发执行反馈中 5=全部办结 +1=待审核 2=部门意见填写中 3=待总负责人汇总方案 4=全部办结 */ private Long flowStatus; diff --git a/klp-flow/src/main/java/com/klp/flow/domain/vo/TsComplaintAcceptVo.java b/klp-flow/src/main/java/com/klp/flow/domain/vo/TsComplaintAcceptVo.java index 4519b5253..7957c68b7 100644 --- a/klp-flow/src/main/java/com/klp/flow/domain/vo/TsComplaintAcceptVo.java +++ b/klp-flow/src/main/java/com/klp/flow/domain/vo/TsComplaintAcceptVo.java @@ -52,6 +52,42 @@ public class TsComplaintAcceptVo extends BaseEntity { @ExcelProperty(value = "客户诉求") private String customerDemand; + /** + * 关联客户ID + */ + @ExcelProperty(value = "关联客户ID") + private Long customerId; + + /** + * 下游使用用户名称 + */ + @ExcelProperty(value = "下游使用用户名称") + private String downstreamUserName; + + /** + * 电话 + */ + @ExcelProperty(value = "电话") + private String phone; + + /** + * 使用的工程名称 + */ + @ExcelProperty(value = "使用的工程名称") + private String projectName; + + /** + * 工程使用地点 + */ + @ExcelProperty(value = "工程使用地点") + private String projectLocation; + + /** + * 产品用途 + */ + @ExcelProperty(value = "产品用途") + private String productUsage; + /** * 客户照片凭证等 */ @@ -84,7 +120,7 @@ public class TsComplaintAcceptVo extends BaseEntity { /** * 流程阶段: -1=待审核 2=部门意见填写中 3=待总负责人汇总方案 4=方案下发执行反馈中 5=全部办结 +1=待审核 2=部门意见填写中 3=待总负责人汇总方案 4=全部办结 */ @ExcelProperty(value = "流程阶段") private Long flowStatus; diff --git a/klp-flow/src/main/java/com/klp/flow/service/impl/TsComplaintAcceptServiceImpl.java b/klp-flow/src/main/java/com/klp/flow/service/impl/TsComplaintAcceptServiceImpl.java index f40bb00f0..fed46981b 100644 --- a/klp-flow/src/main/java/com/klp/flow/service/impl/TsComplaintAcceptServiceImpl.java +++ b/klp-flow/src/main/java/com/klp/flow/service/impl/TsComplaintAcceptServiceImpl.java @@ -268,13 +268,27 @@ public class TsComplaintAcceptServiceImpl implements ITsComplaintAcceptService { } /** - * 批量删除投诉受理单主 + * 批量删除投诉受理单主(级联删除关联的部门任务和执行反馈) */ @Override public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { if(isValid){ //TODO 做一些业务上的校验,判断是否需要校验 } + if (ids == null || ids.isEmpty()) { + return false; + } + // 级联逻辑删除关联的部门意见任务 + tsComplaintTaskMapper.delete( + Wrappers.lambdaQuery() + .in(TsComplaintTask::getAcceptId, ids) + ); + // 级联逻辑删除关联的执行反馈记录 + tsPlanExecuteRelMapper.delete( + Wrappers.lambdaQuery() + .in(TsPlanExecuteRel::getAcceptId, ids) + ); + // 删除受理单本身 return baseMapper.deleteBatchIds(ids) > 0; } } diff --git a/klp-flow/src/main/java/com/klp/flow/service/impl/TsComplaintTaskServiceImpl.java b/klp-flow/src/main/java/com/klp/flow/service/impl/TsComplaintTaskServiceImpl.java index a7983e0e1..0df328de4 100644 --- a/klp-flow/src/main/java/com/klp/flow/service/impl/TsComplaintTaskServiceImpl.java +++ b/klp-flow/src/main/java/com/klp/flow/service/impl/TsComplaintTaskServiceImpl.java @@ -47,6 +47,13 @@ public class TsComplaintTaskServiceImpl implements ITsComplaintTaskService { public TsComplaintTaskVo queryById(Long taskId){ TsComplaintTaskVo vo = baseMapper.selectVoById(taskId); if (vo != null) { + // 过滤已逻辑删除的售后单关联任务 + if (vo.getAcceptId() != null) { + TsComplaintAcceptVo acceptVo = tsComplaintAcceptMapper.selectVoById(vo.getAcceptId()); + if (acceptVo == null) { + return null; + } + } enrichWithAcceptInfo(Collections.singletonList(vo)); } return vo; @@ -115,6 +122,7 @@ public class TsComplaintTaskServiceImpl implements ITsComplaintTaskService { lqw.eq(bo.getFillTime() != null, TsComplaintTask::getFillTime, bo.getFillTime()); lqw.eq(StringUtils.isNotBlank(bo.getFillFile()), TsComplaintTask::getFillFile, bo.getFillFile()); lqw.eq(bo.getRejectMark() != null, TsComplaintTask::getRejectMark, bo.getRejectMark()); + lqw.apply("accept_id IN (SELECT accept_id FROM ts_complaint_accept WHERE del_flag = 0)"); return lqw; } diff --git a/klp-flow/src/main/resources/mapper/flow/TsComplaintAcceptMapper.xml b/klp-flow/src/main/resources/mapper/flow/TsComplaintAcceptMapper.xml index 5334e58e0..5735dd487 100644 --- a/klp-flow/src/main/resources/mapper/flow/TsComplaintAcceptMapper.xml +++ b/klp-flow/src/main/resources/mapper/flow/TsComplaintAcceptMapper.xml @@ -10,6 +10,12 @@ + + + + + + diff --git a/klp-ui/src/views/crm/contract/components/ContractList.vue b/klp-ui/src/views/crm/contract/components/ContractList.vue index 67e0643e4..209c6ff33 100644 --- a/klp-ui/src/views/crm/contract/components/ContractList.vue +++ b/klp-ui/src/views/crm/contract/components/ContractList.vue @@ -7,6 +7,7 @@ 筛选 + 重置 @@ -213,6 +214,7 @@ export default { }, /** 重置按钮操作 */ resetQuery() { + this.queryParams.keyword = undefined; this.$refs["queryForm"].resetFields(); this.queryParams.signDateStart = undefined; this.queryParams.signDateEnd = undefined; diff --git a/klp-ui/src/views/crm/contract/components/ProductContent.vue b/klp-ui/src/views/crm/contract/components/ProductContent.vue index 1768a3b32..0525b001d 100644 --- a/klp-ui/src/views/crm/contract/components/ProductContent.vue +++ b/klp-ui/src/views/crm/contract/components/ProductContent.vue @@ -298,7 +298,7 @@ export default { Object.assign(item, calculateProductFields(item, 'quantity')); }); this.products = products; - this.remark = data.remark || '净边料/毛边料、简包/裸包、卷重结算'; + this.remark = data.remark !== undefined ? data.remark : '净边料/毛边料、简包/裸包、卷重结算'; this.productName = data.productName || ''; } catch (error) { console.error('解析content失败:', error); diff --git a/klp-ui/src/views/crm/contract/index.vue b/klp-ui/src/views/crm/contract/index.vue index d3b8e116e..cab3c1a2d 100644 --- a/klp-ui/src/views/crm/contract/index.vue +++ b/klp-ui/src/views/crm/contract/index.vue @@ -227,11 +227,10 @@ - + @@ -59,4 +131,38 @@ export default { padding-bottom: 12px; border-bottom: 1px solid #eeeae4; } + +/* ===== 客户信息卡片 ===== */ +.customer-info-card { + padding: 10px 14px; + background: #faf8f5; + border: 1px solid #e8e4de; + border-radius: 2px; + margin-bottom: 6px; +} + +.customer-row { + display: flex; + gap: 14px; + padding: 3px 0; +} + +.customer-row + .customer-row { + border-top: 1px solid #f0ece6; +} + +.customer-row-label { + flex-shrink: 0; + width: 70px; + font-family: 'Georgia', 'Times New Roman', serif; + font-size: 11px; + color: #8c8c8c; + letter-spacing: 0.3px; +} + +.customer-row-value { + flex: 1; + font-size: 13px; + color: #1a1a1a; +} diff --git a/klp-ui/src/views/wms/post/objection/components/CoilInfoSection.vue b/klp-ui/src/views/wms/post/objection/components/CoilInfoSection.vue index 36f8168d1..19348a41d 100644 --- a/klp-ui/src/views/wms/post/objection/components/CoilInfoSection.vue +++ b/klp-ui/src/views/wms/post/objection/components/CoilInfoSection.vue @@ -11,15 +11,18 @@ + + + - + - + - + + + @@ -92,8 +94,6 @@ - - @@ -114,8 +114,11 @@
+
+
@@ -131,10 +134,25 @@ placeholder="请选择投诉日期" style="width:100%" /> - + - - + + + + + + + + + + + + + + + + + @@ -170,6 +188,8 @@ 确 定 + + @@ -183,6 +203,7 @@ import jsPDF from 'jspdf'; import CoilSelector from "@/components/CoilSelector/index.vue"; import CurrentCoilNo from "@/components/KLPService/Renderer/CurrentCoilNo.vue"; import DragResizePanel from "@/components/DragResizePanel/index.vue"; +import CustomerSelect from "@/components/KLPService/CustomerSelect/index.vue"; import HeaderControlSection from "./components/HeaderControlSection.vue"; import BasicInfoSection from "./components/BasicInfoSection.vue"; import ContractInfoSection from "./components/ContractInfoSection.vue"; @@ -191,13 +212,15 @@ import DepartmentOpinionSection from "./components/DepartmentOpinionSection.vue" import HandlingSchemeSection from "./components/HandlingSchemeSection.vue"; import ExecutionFeedbackSection from "./components/ExecutionFeedbackSection.vue"; import FlowOverviewSection from "./components/FlowOverviewSection.vue"; +import ExportPdfDialog from "./components/ExportPdfDialog.vue"; export default { name: "AftermarketObjection", components: { - CoilSelector, CurrentCoilNo, DragResizePanel, + CoilSelector, CurrentCoilNo, DragResizePanel, CustomerSelect, HeaderControlSection, BasicInfoSection, ContractInfoSection, - CoilInfoSection, DepartmentOpinionSection, HandlingSchemeSection, ExecutionFeedbackSection, FlowOverviewSection + CoilInfoSection, DepartmentOpinionSection, HandlingSchemeSection, ExecutionFeedbackSection, FlowOverviewSection, + ExportPdfDialog }, dicts: ['coil_quality_status'], data() { @@ -235,8 +258,7 @@ export default { rules: { complaintNo: [{ required: true, message: "请输入售后编号", trigger: "blur" }], complaintDate: [{ required: true, message: "请选择投诉日期", trigger: "blur" }], - complaintContent: [{ required: true, message: "请输入投诉情况", trigger: "blur" }], - customerDemand: [{ required: true, message: "请输入客户诉求", trigger: "blur" }] + complaintContent: [{ required: true, message: "请输入投诉情况", trigger: "blur" }] } }; }, @@ -329,7 +351,12 @@ export default { complaintNo: undefined, complaintDate: undefined, complaintContent: undefined, - customerDemand: undefined, + customerId: undefined, + downstreamUserName: undefined, + phone: undefined, + projectName: undefined, + projectLocation: undefined, + productUsage: undefined, file: undefined, auditStatus: undefined, auditOpinion: undefined, @@ -523,6 +550,9 @@ export default { this.$modal.msgSuccess("移除成功"); this.loadCoilList(this.currentRow.acceptId); }).catch(() => { }); + }, + handleExportPdf(row) { + this.$refs.exportPdfDialog.open(row.acceptId); } } }; diff --git a/klp-ui/src/views/wms/post/objection/opinion.vue b/klp-ui/src/views/wms/post/objection/opinion.vue index f1b5afdb4..868b06b57 100644 --- a/klp-ui/src/views/wms/post/objection/opinion.vue +++ b/klp-ui/src/views/wms/post/objection/opinion.vue @@ -73,6 +73,10 @@ + + @@ -80,20 +84,27 @@ - - +
+
+
+ 已提交意见 · Submitted Opinion +
+ +
+ +
+
+
- 填写处理意见 · Fill in Opinion + {{ currentTask.taskStatus === 1 ? '修改处理意见' : '填写处理意见' }} · {{ currentTask.taskStatus === 1 ? 'Edit Opinion' : 'Fill in Opinion' }}
- - - + @@ -121,10 +132,13 @@ import BasicInfoSection from "./components/BasicInfoSection.vue"; import CoilInfoSection from "./components/CoilInfoSection.vue"; import ContractInfoSection from "./components/ContractInfoSection.vue"; import FlowOverviewSection from "./components/FlowOverviewSection.vue"; +import DeptOpinionForm from "./components/DeptOpinionForm.vue"; +import DeptOpinionPreview from "./components/DeptOpinionPreview.vue"; +import FileList from "@/components/FileList/index.vue"; export default { name: "AftermarketOpinion", - components: { DragResizePanel, HeaderControlSection, BasicInfoSection, CoilInfoSection, ContractInfoSection, FlowOverviewSection }, + components: { DragResizePanel, HeaderControlSection, BasicInfoSection, CoilInfoSection, ContractInfoSection, FlowOverviewSection, DeptOpinionForm, DeptOpinionPreview, FileList }, data() { return { loading: false, @@ -212,7 +226,7 @@ export default { }, canEdit(row) { const status = (row.acceptInfo || {}).flowStatus; - return (status === 2 || status === 3) && row.taskStatus === 0; + return status === 2; }, confirmCancel() { this.$modal.confirm('确认取消?已填写的内容将不会保存。').then(() => { @@ -235,7 +249,14 @@ export default { }).catch(() => { }).finally(() => { this.rejectLoading = false; }); }, submitOpinion() { - if (!this.opinionForm.deptOpinion) { + try { + const data = JSON.parse(this.opinionForm.deptOpinion || '{}'); + const hasContent = Object.values(data).some(v => v); + if (!hasContent) { + this.$modal.msgWarning("请至少填写一项处理意见"); + return; + } + } catch (e) { this.$modal.msgWarning("请填写处理意见"); return; } @@ -457,6 +478,10 @@ export default { padding-top: 4px; } +.opinion-preview-wrapper { + padding-top: 4px; +} + .opinion-form-section { margin-bottom: 0; } diff --git a/klp-ui/src/views/wms/post/objection/summary.vue b/klp-ui/src/views/wms/post/objection/summary.vue new file mode 100644 index 000000000..89e60a42b --- /dev/null +++ b/klp-ui/src/views/wms/post/objection/summary.vue @@ -0,0 +1,464 @@ + + + + + diff --git a/klp-ui/src/views/wms/post/objection/todo.vue b/klp-ui/src/views/wms/post/objection/todo.vue index 92a8bfbd3..f22fca9d8 100644 --- a/klp-ui/src/views/wms/post/objection/todo.vue +++ b/klp-ui/src/views/wms/post/objection/todo.vue @@ -72,12 +72,14 @@ + + - -