refactor(wms/flow): 调整客诉流程为串行模式并替换质量部为技术部
1. 将原并行的质量部+生产部流程改为技术部→生产部→陈总→吴部长的串行流程 2. 替换所有质量部相关描述为技术部,更新部门映射配置 3. 重构流程状态推进逻辑,新增getNextDept方法简化流程推进 4. 新增表单本地暂存功能,优化列表项UI布局 5. 更新流程步骤展示、状态文案和标签颜色配置
This commit is contained in:
@@ -99,7 +99,7 @@ public class TsComplaintAcceptController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发起流程:创建质量部+生产部并行任务
|
* 发起流程(串行):创建技术部任务
|
||||||
*
|
*
|
||||||
* @param acceptId 受理单ID
|
* @param acceptId 受理单ID
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public interface ITsComplaintAcceptService {
|
|||||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发起流程:创建质量部+生产部并行任务,更新flowStatus=1
|
* 发起流程(串行):创建技术部任务,更新flowStatus=1
|
||||||
*/
|
*/
|
||||||
Boolean opinionDispatch(Long acceptId);
|
Boolean opinionDispatch(Long acceptId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ public class TsComplaintAcceptServiceImpl implements ITsComplaintAcceptService {
|
|||||||
}).collect(java.util.stream.Collectors.toList());
|
}).collect(java.util.stream.Collectors.toList());
|
||||||
tsAcceptCoilRelMapper.insertBatch(relList);
|
tsAcceptCoilRelMapper.insertBatch(relList);
|
||||||
}
|
}
|
||||||
// 自动创建质量部+生产部并行任务,发起流程
|
// 自动创建技术部任务,发起串行流程
|
||||||
opinionDispatch(add.getAcceptId());
|
opinionDispatch(add.getAcceptId());
|
||||||
}
|
}
|
||||||
return flag;
|
return flag;
|
||||||
@@ -132,30 +132,23 @@ public class TsComplaintAcceptServiceImpl implements ITsComplaintAcceptService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发起流程
|
* 发起流程(串行)
|
||||||
* 创建质量部(deptId=2) + 生产部(deptId=1) 两个并行代办任务
|
* 创建技术部(deptId=2) 代办任务
|
||||||
* 更新受理单flow_status=1(质量部·生产部处理中)
|
* 更新受理单flow_status=1(技术部处理中)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Boolean opinionDispatch(Long acceptId) {
|
public Boolean opinionDispatch(Long acceptId) {
|
||||||
if (acceptId == null) {
|
if (acceptId == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// 1. 创建质量部task deptId=2
|
// 1. 创建技术部task deptId=2
|
||||||
TsComplaintTask qaTask = new TsComplaintTask();
|
TsComplaintTask techTask = new TsComplaintTask();
|
||||||
qaTask.setAcceptId(acceptId);
|
techTask.setAcceptId(acceptId);
|
||||||
qaTask.setDeptId(2L);
|
techTask.setDeptId(2L);
|
||||||
qaTask.setTaskStatus(0L);
|
techTask.setTaskStatus(0L);
|
||||||
qaTask.setRejectMark(0L);
|
techTask.setRejectMark(0L);
|
||||||
tsComplaintTaskMapper.insert(qaTask);
|
tsComplaintTaskMapper.insert(techTask);
|
||||||
// 2. 创建生产部task deptId=1
|
// 2. 更新受理单流程状态为1(技术部处理中)
|
||||||
TsComplaintTask prodTask = new TsComplaintTask();
|
|
||||||
prodTask.setAcceptId(acceptId);
|
|
||||||
prodTask.setDeptId(1L);
|
|
||||||
prodTask.setTaskStatus(0L);
|
|
||||||
prodTask.setRejectMark(0L);
|
|
||||||
tsComplaintTaskMapper.insert(prodTask);
|
|
||||||
// 3. 更新受理单流程状态为1(质量部·生产部处理中)
|
|
||||||
LambdaUpdateWrapper<TsComplaintAccept> uw = Wrappers.lambdaUpdate();
|
LambdaUpdateWrapper<TsComplaintAccept> uw = Wrappers.lambdaUpdate();
|
||||||
uw.eq(TsComplaintAccept::getAcceptId, acceptId)
|
uw.eq(TsComplaintAccept::getAcceptId, acceptId)
|
||||||
.set(TsComplaintAccept::getFlowStatus, 1L);
|
.set(TsComplaintAccept::getFlowStatus, 1L);
|
||||||
|
|||||||
@@ -157,10 +157,11 @@ public class TsComplaintTaskServiceImpl implements ITsComplaintTaskService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步受理单流程状态 — 串行推进逻辑
|
* 同步受理单流程状态 — 严格串行推进逻辑
|
||||||
* Step 1: 质量部(deptId=2) + 生产部(deptId=1) 都完成 → 创建陈总task(deptId=4), flowStatus=2
|
* Step 1: 技术部(deptId=2)完成 → 创建生产部task(deptId=1), flowStatus=2
|
||||||
* Step 2: 陈总完成 → 创建吴部长task(deptId=3), flowStatus=3
|
* Step 2: 生产部(deptId=1)完成 → 创建陈总task(deptId=4), flowStatus=3
|
||||||
* Step 3: 吴部长完成 → flowStatus=4 已办结
|
* Step 3: 陈总(deptId=4)完成 → 创建吴部长task(deptId=3), flowStatus=4
|
||||||
|
* Step 4: 吴部长(deptId=3)完成 → flowStatus=5 已办结
|
||||||
*/
|
*/
|
||||||
private void syncAcceptFlowStatus(Long acceptId) {
|
private void syncAcceptFlowStatus(Long acceptId) {
|
||||||
if (acceptId == null) {
|
if (acceptId == null) {
|
||||||
@@ -178,52 +179,49 @@ public class TsComplaintTaskServiceImpl implements ITsComplaintTaskService {
|
|||||||
Map<Long, List<TsComplaintTask>> taskByDept = taskList.stream()
|
Map<Long, List<TsComplaintTask>> taskByDept = taskList.stream()
|
||||||
.collect(Collectors.groupingBy(TsComplaintTask::getDeptId));
|
.collect(Collectors.groupingBy(TsComplaintTask::getDeptId));
|
||||||
|
|
||||||
// Step 1: 质量部(deptId=2) 和 生产部(deptId=1) 是否都完成
|
// 辅助方法:检查某部门的所有任务是否都已完成
|
||||||
boolean qaDone = taskByDept.containsKey(2L) &&
|
java.util.function.BiFunction<Long, Long, Boolean> isDeptDone = (deptId, nextFlowStatus) -> {
|
||||||
taskByDept.get(2L).stream().allMatch(t -> t.getTaskStatus() != null && t.getTaskStatus() == 1L);
|
if (!taskByDept.containsKey(deptId)) {
|
||||||
boolean prodDone = taskByDept.containsKey(1L) &&
|
return false;
|
||||||
taskByDept.get(1L).stream().allMatch(t -> t.getTaskStatus() != null && t.getTaskStatus() == 1L);
|
}
|
||||||
|
boolean done = taskByDept.get(deptId).stream()
|
||||||
if (qaDone && prodDone) {
|
.allMatch(t -> t.getTaskStatus() != null && t.getTaskStatus() == 1L);
|
||||||
// 两者都完成 → 检查陈总节点(deptId=4)是否存在
|
if (done) {
|
||||||
boolean chenExists = taskByDept.containsKey(4L);
|
// 检查是否已存在下一节点,若不存在则创建
|
||||||
if (!chenExists) {
|
Long nextDeptId = getNextDept(deptId);
|
||||||
// 创建陈总task deptId=4
|
if (nextDeptId != null && !taskByDept.containsKey(nextDeptId)) {
|
||||||
TsComplaintTask chenTask = new TsComplaintTask();
|
TsComplaintTask nextTask = new TsComplaintTask();
|
||||||
chenTask.setAcceptId(acceptId);
|
nextTask.setAcceptId(acceptId);
|
||||||
chenTask.setDeptId(4L);
|
nextTask.setDeptId(nextDeptId);
|
||||||
chenTask.setRejectMark(0L);
|
nextTask.setRejectMark(0L);
|
||||||
chenTask.setTaskStatus(0L);
|
nextTask.setTaskStatus(0L);
|
||||||
baseMapper.insert(chenTask);
|
baseMapper.insert(nextTask);
|
||||||
updateFlowStatus(acceptId, 2L); // 待陈总审批
|
updateFlowStatus(acceptId, nextFlowStatus);
|
||||||
} else {
|
} else if (nextDeptId == null) {
|
||||||
// 陈总节点已存在,检查是否完成
|
// 最后一步(吴部长完成)→ 办结
|
||||||
boolean chenDone = taskByDept.get(4L).stream()
|
updateFlowStatus(acceptId, 5L);
|
||||||
.allMatch(t -> t.getTaskStatus() != null && t.getTaskStatus() == 1L);
|
|
||||||
if (chenDone) {
|
|
||||||
// 陈总完成 → 检查吴部长节点(deptId=3)是否存在
|
|
||||||
boolean wuExists = taskByDept.containsKey(3L);
|
|
||||||
if (!wuExists) {
|
|
||||||
// 创建吴部长task deptId=3
|
|
||||||
TsComplaintTask wuTask = new TsComplaintTask();
|
|
||||||
wuTask.setAcceptId(acceptId);
|
|
||||||
wuTask.setDeptId(3L);
|
|
||||||
wuTask.setRejectMark(0L);
|
|
||||||
wuTask.setTaskStatus(0L);
|
|
||||||
baseMapper.insert(wuTask);
|
|
||||||
updateFlowStatus(acceptId, 3L); // 待吴部长处理
|
|
||||||
} else {
|
|
||||||
// 吴部长已完成 → 办结
|
|
||||||
boolean wuDone = taskByDept.get(3L).stream()
|
|
||||||
.allMatch(t -> t.getTaskStatus() != null && t.getTaskStatus() == 1L);
|
|
||||||
if (wuDone) {
|
|
||||||
updateFlowStatus(acceptId, 4L); // 已办结
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return done;
|
||||||
// 质/产未全部完成时不做任何事,等待
|
};
|
||||||
|
|
||||||
|
// 按串行顺序依次推进:技术部→生产部→陈总→吴部长→办结
|
||||||
|
// flowStatus: 1→2→3→4→5
|
||||||
|
isDeptDone.apply(2L, 2L); // 技术部完成 → 生产部, flowStatus=2
|
||||||
|
isDeptDone.apply(1L, 3L); // 生产部完成 → 陈总, flowStatus=3
|
||||||
|
isDeptDone.apply(4L, 4L); // 陈总完成 → 吴部长, flowStatus=4
|
||||||
|
isDeptDone.apply(3L, 5L); // 吴部长完成 → 办结, flowStatus=5
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取串行流程中当前部门完成后应创建的下一个部门
|
||||||
|
* 2(技术部) → 1(生产部) → 4(陈总) → 3(吴部长) → null(办结)
|
||||||
|
*/
|
||||||
|
private Long getNextDept(Long deptId) {
|
||||||
|
if (deptId == 2L) return 1L; // 技术部 → 生产部
|
||||||
|
if (deptId == 1L) return 4L; // 生产部 → 陈总
|
||||||
|
if (deptId == 4L) return 3L; // 陈总 → 吴部长
|
||||||
|
return null; // 吴部长 → 办结
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -104,10 +104,10 @@ const NODE_EVENT_CONFIG = {
|
|||||||
],
|
],
|
||||||
afterSales: [
|
afterSales: [
|
||||||
{ id: 'A', label: '创建售后单', handler: 'handleOpen', params: { componentPath: 'wms/post/objection/index' } },
|
{ id: 'A', label: '创建售后单', handler: 'handleOpen', params: { componentPath: 'wms/post/objection/index' } },
|
||||||
{ id: 'C', label: '质量部处理', handler: 'handleOpen', params: { componentPath: 'wms/post/objection/opinion' } },
|
{ id: 'B', label: '技术部处理', handler: 'handleOpen', params: { componentPath: 'wms/post/objection/opinion' } },
|
||||||
{ id: 'D', label: '生产部处理', handler: 'handleOpen', params: { componentPath: 'wms/post/objection/opinion' } },
|
{ id: 'C', label: '生产部处理', handler: 'handleOpen', params: { componentPath: 'wms/post/objection/opinion' } },
|
||||||
{ id: 'G', label: '陈总审批', handler: 'handleOpen', params: { componentPath: 'wms/post/objection/summary' } },
|
{ id: 'D', label: '陈总审批', handler: 'handleOpen', params: { componentPath: 'wms/post/objection/summary' } },
|
||||||
{ id: 'H', label: '吴部长(销售部)处理', handler: 'handleOpen', params: { componentPath: 'wms/post/objection/opinion' } },
|
{ id: 'E', label: '吴部长(销售部)处理', handler: 'handleOpen', params: { componentPath: 'wms/post/objection/opinion' } },
|
||||||
],
|
],
|
||||||
inventoryCheck: [
|
inventoryCheck: [
|
||||||
{ id: 'A', label: '创建盘库计划', handler: 'handleOpen', params: { componentPath: 'wms/post/InvCount/index' } },
|
{ id: 'A', label: '创建盘库计划', handler: 'handleOpen', params: { componentPath: 'wms/post/InvCount/index' } },
|
||||||
@@ -246,21 +246,16 @@ graph TD
|
|||||||
afterSales: `
|
afterSales: `
|
||||||
graph TD
|
graph TD
|
||||||
A["<b>创建售后单</b><br/>销售内勤发起"]:::step
|
A["<b>创建售后单</b><br/>销售内勤发起"]:::step
|
||||||
A --> B["<b>质量部·生产部</b><br/>并行处理"]:::fork
|
A --> B["<b>技术部处理</b><br/>出具技术意见"]:::dept1
|
||||||
B --> C["<b>质量部</b><br/>出具处理意见"]:::dept1
|
B --> C["<b>生产部处理</b><br/>出具处理意见"]:::dept2
|
||||||
B --> D["<b>生产部</b><br/>出具处理意见"]:::dept2
|
C --> D["<b>陈总审批</b><br/>审阅意见并审批"]:::dept3
|
||||||
C --> F{"两部门<br/>均已完成?"}:::decision
|
D --> E["<b>吴部长</b><br/>(销售部)<br/>根据审批意见处理客诉"]:::approve
|
||||||
D --> F
|
E --> F(["<b>售后单办结</b><br/>流程结束"]):::end
|
||||||
F -->|是| G["<b>陈总审批</b>"]:::dept3
|
|
||||||
G --> H["<b>吴部长</b><br/>(销售部)<br/>处理客诉"]:::approve
|
|
||||||
H --> J(["<b>售后单封存</b><br/>流程结束"]):::end
|
|
||||||
|
|
||||||
classDef step fill:#409eff,stroke:#337ecc,color:#fff,stroke-width:2px
|
classDef step fill:#409eff,stroke:#337ecc,color:#fff,stroke-width:2px
|
||||||
classDef fork fill:#f0f5ff,stroke:#409eff,color:#303133,stroke-width:2px
|
|
||||||
classDef dept1 fill:#e6fffa,stroke:#00b4a0,color:#303133,stroke-width:2px
|
classDef dept1 fill:#e6fffa,stroke:#00b4a0,color:#303133,stroke-width:2px
|
||||||
classDef dept2 fill:#fff7e6,stroke:#fa8c16,color:#303133,stroke-width:2px
|
classDef dept2 fill:#fff7e6,stroke:#fa8c16,color:#303133,stroke-width:2px
|
||||||
classDef dept3 fill:#fff0f6,stroke:#eb2f96,color:#303133,stroke-width:2px
|
classDef dept3 fill:#fff0f6,stroke:#eb2f96,color:#303133,stroke-width:2px
|
||||||
classDef decision fill:#f9f0ff,stroke:#722ed1,color:#303133,stroke-width:2px
|
|
||||||
classDef approve fill:#e6f7ff,stroke:#1890ff,color:#303133,stroke-width:2px
|
classDef approve fill:#e6f7ff,stroke:#1890ff,color:#303133,stroke-width:2px
|
||||||
classDef end fill:#dcf7e8,stroke:#52c41a,color:#303133,stroke-width:2px,rx:10,ry:10
|
classDef end fill:#dcf7e8,stroke:#52c41a,color:#303133,stroke-width:2px,rx:10,ry:10
|
||||||
linkStyle default stroke:#bfbfbf,stroke-width:2px
|
linkStyle default stroke:#bfbfbf,stroke-width:2px
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
getDeptName(deptId) {
|
getDeptName(deptId) {
|
||||||
const map = { 1: '生产部', 2: '质量部', 3: '销售部(吴部长)', 4: '陈总审批' };
|
const map = { 1: '生产部', 2: '技术部', 3: '销售部(吴部长)', 4: '陈总审批' };
|
||||||
return map[deptId] || '部门' + deptId;
|
return map[deptId] || '部门' + deptId;
|
||||||
},
|
},
|
||||||
parseTime(time, option) {
|
parseTime(time, option) {
|
||||||
|
|||||||
@@ -49,7 +49,7 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 质量部 deptId=2 -->
|
<!-- 技术部 deptId=2 -->
|
||||||
<template v-else-if="deptId === 2">
|
<template v-else-if="deptId === 2">
|
||||||
<el-form-item label="产生原因" prop="cause">
|
<el-form-item label="产生原因" prop="cause">
|
||||||
<el-input v-model="formData.cause" type="textarea" :rows="3" placeholder="请描述产生原因" @input="emitJson" />
|
<el-input v-model="formData.cause" type="textarea" :rows="3" placeholder="请描述产生原因" @input="emitJson" />
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
<template v-else-if="deptId === 4">
|
<template v-else-if="deptId === 4">
|
||||||
<el-form-item label="审阅意见" prop="reviewOpinion">
|
<el-form-item label="审阅意见" prop="reviewOpinion">
|
||||||
<el-input v-model="formData.reviewOpinion" type="textarea" :rows="4"
|
<el-input v-model="formData.reviewOpinion" type="textarea" :rows="4"
|
||||||
placeholder="请审阅质量部、生产部意见后填写审批意见" @input="emitJson" />
|
placeholder="请审阅技术部、生产部意见后填写审批意见" @input="emitJson" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="审批结论" prop="approvalResult">
|
<el-form-item label="审批结论" prop="approvalResult">
|
||||||
<el-radio-group v-model="formData.approvalResult" @change="emitJson">
|
<el-radio-group v-model="formData.approvalResult" @change="emitJson">
|
||||||
@@ -91,8 +91,8 @@
|
|||||||
<el-form-item label="处理意见" prop="handlingOpinion">
|
<el-form-item label="处理意见" prop="handlingOpinion">
|
||||||
<el-input v-model="formData.handlingOpinion" type="textarea" :rows="4" placeholder="请输入处理意见" @input="emitJson" />
|
<el-input v-model="formData.handlingOpinion" type="textarea" :rows="4" placeholder="请输入处理意见" @input="emitJson" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="领导意见" prop="leaderOpinion">
|
<el-form-item label="处理方案" prop="leaderOpinion">
|
||||||
<el-input v-model="formData.leaderOpinion" type="textarea" :rows="3" placeholder="请输入领导意见" @input="emitJson" />
|
<el-input v-model="formData.leaderOpinion" type="textarea" :rows="3" placeholder="请输入处理方案" @input="emitJson" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 质量部 deptId=2 -->
|
<!-- 技术部 deptId=2 -->
|
||||||
<template v-else-if="deptId === 2">
|
<template v-else-if="deptId === 2">
|
||||||
<div class="preview-row" v-if="parsedData.cause">
|
<div class="preview-row" v-if="parsedData.cause">
|
||||||
<span class="preview-label">产生原因</span>
|
<span class="preview-label">产生原因</span>
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getDeptName(deptId) {
|
getDeptName(deptId) {
|
||||||
const map = { 1: '生产部', 2: '质量部', 3: '销售部' };
|
const map = { 1: '生产部', 2: '技术部', 3: '销售部' };
|
||||||
return map[deptId] || '部门' + deptId;
|
return map[deptId] || '部门' + deptId;
|
||||||
},
|
},
|
||||||
parseTime(time, option) {
|
parseTime(time, option) {
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
<span>流程总览 <span class="en-sub">· Process Overview</span></span>
|
<span>流程总览 <span class="en-sub">· Process Overview</span></span>
|
||||||
</div>
|
</div>
|
||||||
<el-steps :active="activeStep" align-center class="flow-steps">
|
<el-steps :active="activeStep" align-center class="flow-steps">
|
||||||
<el-step title="质量部·生产部" icon="el-icon-s-operation" />
|
<el-step title="技术部处理" icon="el-icon-s-operation" />
|
||||||
|
<el-step title="生产部处理" icon="el-icon-s-operation" />
|
||||||
<el-step title="陈总审批" icon="el-icon-s-check" />
|
<el-step title="陈总审批" icon="el-icon-s-check" />
|
||||||
<el-step title="吴部长处理" icon="el-icon-s-custom" />
|
<el-step title="吴部长处理" icon="el-icon-s-custom" />
|
||||||
<el-step title="已办结" icon="el-icon-circle-check" />
|
<el-step title="已办结" icon="el-icon-circle-check" />
|
||||||
@@ -33,29 +34,31 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
/**
|
/**
|
||||||
* el-steps active 从 0 开始。
|
* el-steps active 从 0 开始。
|
||||||
* 1=技术部·生产部→0, 2=陈总审批→1, 3=吴部长处理→2, 4=已办结→3
|
* 1=技术部处理→0, 2=生产部处理→1, 3=陈总审批→2, 4=吴部长处理→3, 5=已办结→4
|
||||||
*/
|
*/
|
||||||
activeStep() {
|
activeStep() {
|
||||||
if (this.flowStatus == null) return -1;
|
if (this.flowStatus == null) return -1;
|
||||||
const v = Number(this.flowStatus);
|
const v = Number(this.flowStatus);
|
||||||
if (v >= 4) return 3;
|
if (v >= 5) return 4;
|
||||||
return v - 1;
|
return v - 1;
|
||||||
},
|
},
|
||||||
flowStatusText() {
|
flowStatusText() {
|
||||||
const map = {
|
const map = {
|
||||||
1: '质量部·生产部处理中',
|
1: '技术部处理中',
|
||||||
2: '待陈总审批',
|
2: '生产部处理中',
|
||||||
3: '待吴部长处理',
|
3: '待陈总审批',
|
||||||
4: '已办结'
|
4: '待吴部长处理',
|
||||||
|
5: '已办结'
|
||||||
};
|
};
|
||||||
return map[this.flowStatus] || '未知';
|
return map[this.flowStatus] || '未知';
|
||||||
},
|
},
|
||||||
tagType() {
|
tagType() {
|
||||||
const map = {
|
const map = {
|
||||||
1: 'warning',
|
1: 'warning',
|
||||||
2: 'primary',
|
2: 'warning',
|
||||||
3: 'warning',
|
3: 'primary',
|
||||||
4: 'success'
|
4: 'warning',
|
||||||
|
5: 'success'
|
||||||
};
|
};
|
||||||
return map[this.flowStatus] || '';
|
return map[this.flowStatus] || '';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,10 +57,11 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
flowStatusText() {
|
flowStatusText() {
|
||||||
const map = {
|
const map = {
|
||||||
1: '待审核',
|
1: '技术部处理中',
|
||||||
2: '意见填写中',
|
2: '生产部处理中',
|
||||||
3: '待汇总方案',
|
3: '待陈总审批',
|
||||||
4: '全部办结'
|
4: '待吴部长处理',
|
||||||
|
5: '已办结'
|
||||||
};
|
};
|
||||||
return map[this.flowStatus] || '未知';
|
return map[this.flowStatus] || '未知';
|
||||||
},
|
},
|
||||||
@@ -68,8 +69,9 @@ export default {
|
|||||||
const map = {
|
const map = {
|
||||||
1: 'info',
|
1: 'info',
|
||||||
2: 'warning',
|
2: 'warning',
|
||||||
3: '',
|
3: 'warning',
|
||||||
4: 'success'
|
4: '',
|
||||||
|
5: 'success'
|
||||||
};
|
};
|
||||||
return map[this.flowStatus] || '';
|
return map[this.flowStatus] || '';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,10 +12,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<el-select v-model="queryParams.flowStatus" placeholder="全部阶段" clearable size="mini" @change="handleQuery"
|
<el-select v-model="queryParams.flowStatus" placeholder="全部阶段" clearable size="mini" @change="handleQuery"
|
||||||
class="header-filter">
|
class="header-filter">
|
||||||
<el-option label="质量部·生产部处理" :value="1" />
|
<el-option label="技术部处理中" :value="1" />
|
||||||
<el-option label="待陈总审批" :value="2" />
|
<el-option label="生产部处理中" :value="2" />
|
||||||
<el-option label="待吴部长处理" :value="3" />
|
<el-option label="待陈总审批" :value="3" />
|
||||||
<el-option label="已办结" :value="4" />
|
<el-option label="待吴部长处理" :value="4" />
|
||||||
|
<el-option label="已办结" :value="5" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -30,21 +31,22 @@
|
|||||||
<div v-loading="loading" class="list-body">
|
<div v-loading="loading" class="list-body">
|
||||||
<div v-for="item in dataList" :key="item.acceptId" class="list-item"
|
<div v-for="item in dataList" :key="item.acceptId" class="list-item"
|
||||||
:class="{ active: currentRow && currentRow.acceptId === item.acceptId }" @click="handleRowClick(item)">
|
:class="{ active: currentRow && currentRow.acceptId === item.acceptId }" @click="handleRowClick(item)">
|
||||||
<div class="item-main">
|
<div class="item-row-top">
|
||||||
<span class="item-title">{{ item.complaintNo }}</span>
|
<span class="item-title">{{ item.complaintNo }}</span>
|
||||||
|
<el-tag v-if="item.flowStatus === 1" type="warning" size="mini">技术部处理中</el-tag>
|
||||||
|
<el-tag v-else-if="item.flowStatus === 2" type="warning" size="mini">生产部处理中</el-tag>
|
||||||
|
<el-tag v-else-if="item.flowStatus === 3" type="primary" size="mini">待陈总审批</el-tag>
|
||||||
|
<el-tag v-else-if="item.flowStatus === 4" type="warning" size="mini">待吴部长处理</el-tag>
|
||||||
|
<el-tag v-else-if="item.flowStatus === 5" type="success" size="mini">已办结</el-tag>
|
||||||
|
</div>
|
||||||
|
<div class="item-row-bottom">
|
||||||
<span class="item-sub">{{ parseTime(item.complaintDate, '{y}-{m}-{d}') }}</span>
|
<span class="item-sub">{{ parseTime(item.complaintDate, '{y}-{m}-{d}') }}</span>
|
||||||
</div>
|
<div class="item-actions">
|
||||||
<div class="item-meta">
|
<el-button size="mini" type="text" icon="el-icon-download"
|
||||||
<el-tag v-if="item.flowStatus === 1" type="warning" size="mini">质量部·生产部处理中</el-tag>
|
@click.stop="handleExportPdf(item)" title="导出PDF"></el-button>
|
||||||
<el-tag v-else-if="item.flowStatus === 2" type="primary" size="mini">待陈总审批</el-tag>
|
<el-button size="mini" type="text" icon="el-icon-edit" @click.stop="handleUpdate(item)"></el-button>
|
||||||
<el-tag v-else-if="item.flowStatus === 3" type="warning" size="mini">待吴部长处理</el-tag>
|
<el-button size="mini" type="text" icon="el-icon-delete" @click.stop="handleDelete(item)"></el-button>
|
||||||
<el-tag v-else-if="item.flowStatus === 4" type="success" size="mini">已办结</el-tag>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="item-actions">
|
|
||||||
<el-button size="mini" type="text" icon="el-icon-download"
|
|
||||||
@click.stop="handleExportPdf(item)" title="导出PDF"></el-button>
|
|
||||||
<el-button size="mini" type="text" icon="el-icon-edit" @click.stop="handleUpdate(item)"></el-button>
|
|
||||||
<el-button size="mini" type="text" icon="el-icon-delete" @click.stop="handleDelete(item)"></el-button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="dataList.length === 0 && !loading" class="list-empty">
|
<div v-if="dataList.length === 0 && !loading" class="list-empty">
|
||||||
@@ -108,7 +110,7 @@
|
|||||||
<DepartmentOpinionSection :taskList="taskList" @refresh="refreshTaskList" />
|
<DepartmentOpinionSection :taskList="taskList" @refresh="refreshTaskList" />
|
||||||
|
|
||||||
<div class="section-gap" />
|
<div class="section-gap" />
|
||||||
<HandlingSchemeSection :content="currentRow.planContent" :editable="currentRow.flowStatus === 3" @save="handleSavePlan" />
|
<HandlingSchemeSection :content="currentRow.planContent" :editable="currentRow.flowStatus === 4" @save="handleSavePlan" />
|
||||||
|
|
||||||
<div class="section-gap" />
|
<div class="section-gap" />
|
||||||
<template v-if="false">
|
<template v-if="false">
|
||||||
@@ -170,8 +172,9 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<div slot="footer" class="dialog-footer">
|
<div slot="footer" class="dialog-footer">
|
||||||
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
|
||||||
<el-button @click="cancel">取 消</el-button>
|
<el-button @click="cancel">取 消</el-button>
|
||||||
|
<el-button v-if="form.acceptId" :loading="draftLoading" @click="saveDraft">暂 存</el-button>
|
||||||
|
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
@@ -222,6 +225,7 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
buttonLoading: false,
|
buttonLoading: false,
|
||||||
|
draftLoading: false,
|
||||||
pdfLoading: false,
|
pdfLoading: false,
|
||||||
loading: true,
|
loading: true,
|
||||||
detailLoading: false,
|
detailLoading: false,
|
||||||
@@ -248,7 +252,7 @@ export default {
|
|||||||
selectedDeptIds: [],
|
selectedDeptIds: [],
|
||||||
deptOptions: [
|
deptOptions: [
|
||||||
{ deptId: 1, deptName: '生产部' },
|
{ deptId: 1, deptName: '生产部' },
|
||||||
{ deptId: 2, deptName: '质量部' },
|
{ deptId: 2, deptName: '技术部' },
|
||||||
{ deptId: 3, deptName: '销售部' }
|
{ deptId: 3, deptName: '销售部' }
|
||||||
],
|
],
|
||||||
rules: {
|
rules: {
|
||||||
@@ -306,7 +310,7 @@ export default {
|
|||||||
}).finally(() => { this.coilLoading = false; });
|
}).finally(() => { this.coilLoading = false; });
|
||||||
},
|
},
|
||||||
getDeptName(deptId) {
|
getDeptName(deptId) {
|
||||||
const map = { 1: '生产部', 2: '质量部', 3: '销售部' };
|
const map = { 1: '生产部', 2: '技术部', 3: '销售部' };
|
||||||
return map[deptId] || '部门' + deptId;
|
return map[deptId] || '部门' + deptId;
|
||||||
},
|
},
|
||||||
handleAdd() {
|
handleAdd() {
|
||||||
@@ -332,6 +336,19 @@ export default {
|
|||||||
handleUpdate(row) {
|
handleUpdate(row) {
|
||||||
this.reset();
|
this.reset();
|
||||||
const acceptId = row.acceptId;
|
const acceptId = row.acceptId;
|
||||||
|
// 检查是否有本地暂存
|
||||||
|
const draftKey = 'draft_' + acceptId;
|
||||||
|
const cached = localStorage.getItem(draftKey);
|
||||||
|
if (cached) {
|
||||||
|
try {
|
||||||
|
const draft = JSON.parse(cached);
|
||||||
|
this.form = draft.form;
|
||||||
|
this.formCoilList = draft.formCoilList || [];
|
||||||
|
this.open = true;
|
||||||
|
this.title = "修改售后单(已恢复未保存内容)";
|
||||||
|
return;
|
||||||
|
} catch (e) { /* ignore */ }
|
||||||
|
}
|
||||||
getComplaintAccept(acceptId).then(response => {
|
getComplaintAccept(acceptId).then(response => {
|
||||||
this.form = response.data;
|
this.form = response.data;
|
||||||
listAcceptCoilRel({ acceptId, pageNum: 1, pageSize: 999 }).then(r => {
|
listAcceptCoilRel({ acceptId, pageNum: 1, pageSize: 999 }).then(r => {
|
||||||
@@ -370,6 +387,21 @@ export default {
|
|||||||
this.open = false;
|
this.open = false;
|
||||||
this.reset();
|
this.reset();
|
||||||
},
|
},
|
||||||
|
saveDraft() {
|
||||||
|
this.draftLoading = true;
|
||||||
|
const draftKey = 'draft_' + this.form.acceptId;
|
||||||
|
localStorage.setItem(draftKey, JSON.stringify({
|
||||||
|
form: this.form,
|
||||||
|
formCoilList: this.formCoilList
|
||||||
|
}));
|
||||||
|
this.$modal.msgSuccess("已暂存");
|
||||||
|
this.draftLoading = false;
|
||||||
|
this.open = false;
|
||||||
|
},
|
||||||
|
clearDraft(acceptId) {
|
||||||
|
const draftKey = 'draft_' + acceptId;
|
||||||
|
localStorage.removeItem(draftKey);
|
||||||
|
},
|
||||||
submitForm() {
|
submitForm() {
|
||||||
this.$refs["form"].validate(valid => {
|
this.$refs["form"].validate(valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
@@ -377,6 +409,7 @@ export default {
|
|||||||
const formData = { ...this.form, coilIds: this.formCoilList.map(c => c.coilId) };
|
const formData = { ...this.form, coilIds: this.formCoilList.map(c => c.coilId) };
|
||||||
if (this.form.acceptId != null) {
|
if (this.form.acceptId != null) {
|
||||||
updateComplaintAccept(formData).then(() => {
|
updateComplaintAccept(formData).then(() => {
|
||||||
|
this.clearDraft(this.form.acceptId);
|
||||||
this.$modal.msgSuccess("修改成功");
|
this.$modal.msgSuccess("修改成功");
|
||||||
this.open = false;
|
this.open = false;
|
||||||
this.getList();
|
this.getList();
|
||||||
@@ -610,8 +643,8 @@ export default {
|
|||||||
|
|
||||||
.list-item {
|
.list-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-direction: column;
|
||||||
padding: 10px 12px;
|
padding: 8px 12px;
|
||||||
margin-bottom: 2px;
|
margin-bottom: 2px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
@@ -631,15 +664,23 @@ export default {
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-main {
|
.item-row-top {
|
||||||
flex: 1;
|
|
||||||
min-width: 0;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
align-items: center;
|
||||||
gap: 2px;
|
justify-content: space-between;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-row-bottom {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-title {
|
.item-title {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: #303133;
|
color: #303133;
|
||||||
@@ -654,8 +695,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.item-meta {
|
.item-meta {
|
||||||
flex-shrink: 0;
|
display: none;
|
||||||
margin: 0 8px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-actions {
|
.item-actions {
|
||||||
|
|||||||
@@ -25,19 +25,19 @@
|
|||||||
<div v-loading="loading" class="list-body">
|
<div v-loading="loading" class="list-body">
|
||||||
<div v-for="item in taskList" :key="item.taskId" class="list-item"
|
<div v-for="item in taskList" :key="item.taskId" class="list-item"
|
||||||
:class="{ active: currentTask && currentTask.taskId === item.taskId }" @click="handleRowClick(item)">
|
:class="{ active: currentTask && currentTask.taskId === item.taskId }" @click="handleRowClick(item)">
|
||||||
<div class="item-main">
|
<div class="item-row-top">
|
||||||
<span class="item-title">{{ (item.acceptInfo || {}).complaintNo || '' }}</span>
|
<span class="item-title">{{ (item.acceptInfo || {}).complaintNo || '' }}</span>
|
||||||
<span class="item-sub">{{ parseTime((item.acceptInfo || {}).complaintDate, '{y}-{m}-{d}') }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="item-meta">
|
|
||||||
<el-tag v-if="item.rejectMark === 1" type="danger" size="mini">已驳回</el-tag>
|
<el-tag v-if="item.rejectMark === 1" type="danger" size="mini">已驳回</el-tag>
|
||||||
<el-tag v-else-if="item.rejectMark === 2" type="info" size="mini">已隐藏</el-tag>
|
<el-tag v-else-if="item.rejectMark === 2" type="info" size="mini">已隐藏</el-tag>
|
||||||
<el-tag v-else-if="item.taskStatus === 0" type="warning" size="mini">待填写</el-tag>
|
<el-tag v-else-if="item.taskStatus === 0" type="warning" size="mini">待填写</el-tag>
|
||||||
<el-tag v-else-if="item.taskStatus === 1" type="success" size="mini">已完成</el-tag>
|
<el-tag v-else-if="item.taskStatus === 1" type="success" size="mini">已完成</el-tag>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-actions">
|
<div class="item-row-bottom">
|
||||||
<el-button v-if="canEdit(item)" size="mini" type="text" icon="el-icon-edit" @click.stop="handleRowClick(item)"></el-button>
|
<span class="item-sub">{{ parseTime((item.acceptInfo || {}).complaintDate, '{y}-{m}-{d}') }}</span>
|
||||||
<el-button v-else size="mini" type="text" icon="el-icon-view" @click.stop="handleRowClick(item)"></el-button>
|
<div class="item-actions">
|
||||||
|
<el-button v-if="canEdit(item)" size="mini" type="text" icon="el-icon-edit" @click.stop="handleRowClick(item)"></el-button>
|
||||||
|
<el-button v-else size="mini" type="text" icon="el-icon-view" @click.stop="handleRowClick(item)"></el-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="taskList.length === 0 && !loading" class="list-empty">
|
<div v-if="taskList.length === 0 && !loading" class="list-empty">
|
||||||
@@ -116,6 +116,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
|
<el-button :loading="draftLoading" @click="saveDraft">暂 存</el-button>
|
||||||
<el-button :loading="submitLoading" type="primary" @click="submitOpinion">提 交</el-button>
|
<el-button :loading="submitLoading" type="primary" @click="submitOpinion">提 交</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -151,6 +152,7 @@ export default {
|
|||||||
detailLoading: false,
|
detailLoading: false,
|
||||||
coilLoading: false,
|
coilLoading: false,
|
||||||
submitLoading: false,
|
submitLoading: false,
|
||||||
|
draftLoading: false,
|
||||||
total: 0,
|
total: 0,
|
||||||
|
|
||||||
queryParams: {
|
queryParams: {
|
||||||
@@ -211,6 +213,17 @@ export default {
|
|||||||
this.dialogCoilList = r.rows || [];
|
this.dialogCoilList = r.rows || [];
|
||||||
}).finally(() => { this.coilLoading = false; this.detailLoading = false; });
|
}).finally(() => { this.coilLoading = false; this.detailLoading = false; });
|
||||||
|
|
||||||
|
// 检查本地暂存
|
||||||
|
const draftKey = 'draft_opinion_' + row.taskId;
|
||||||
|
const cached = localStorage.getItem(draftKey);
|
||||||
|
if (cached) {
|
||||||
|
try {
|
||||||
|
const draft = JSON.parse(cached);
|
||||||
|
this.opinionForm = { deptOpinion: draft.deptOpinion || '', fillFile: draft.fillFile || '' };
|
||||||
|
return;
|
||||||
|
} catch (e) { /* ignore */ }
|
||||||
|
}
|
||||||
|
|
||||||
getComplaintTask(row.taskId).then(response => {
|
getComplaintTask(row.taskId).then(response => {
|
||||||
const task = response.data || {};
|
const task = response.data || {};
|
||||||
this.opinionForm = {
|
this.opinionForm = {
|
||||||
@@ -236,13 +249,19 @@ export default {
|
|||||||
}).finally(() => { this.coilLoading = false; });
|
}).finally(() => { this.coilLoading = false; });
|
||||||
},
|
},
|
||||||
getDeptLabel() {
|
getDeptLabel() {
|
||||||
const map = { 1: '生产部', 2: '质量部', 3: '销售部(吴部长)', 4: '陈总审批' };
|
const map = { 1: '生产部', 2: '技术部', 3: '销售部(吴部长)', 4: '陈总审批' };
|
||||||
return map[this.queryParams.deptId] || '';
|
return map[this.queryParams.deptId] || '';
|
||||||
},
|
},
|
||||||
canEdit(row) {
|
canEdit(row) {
|
||||||
const status = (row.acceptInfo || {}).flowStatus;
|
const status = (row.acceptInfo || {}).flowStatus;
|
||||||
// 只要节点task状态为待处理(0)就可编辑
|
const deptId = row.deptId;
|
||||||
return status >= 1 && status <= 3;
|
// 技术部(deptId=2) 仅在 flowStatus=1 时可编辑
|
||||||
|
// 生产部(deptId=1) 仅在 flowStatus=2 时可编辑
|
||||||
|
// 吴部长(deptId=3) 仅在 flowStatus=4 时可编辑
|
||||||
|
if (deptId === 2 && status === 1) return true;
|
||||||
|
if (deptId === 1 && status === 2) return true;
|
||||||
|
if (deptId === 3 && status === 4) return true;
|
||||||
|
return false;
|
||||||
},
|
},
|
||||||
loadAllTasks() {
|
loadAllTasks() {
|
||||||
if (!this.currentTask.acceptId) return;
|
if (!this.currentTask.acceptId) return;
|
||||||
@@ -252,7 +271,7 @@ export default {
|
|||||||
pageSize: 999
|
pageSize: 999
|
||||||
}).then(r => {
|
}).then(r => {
|
||||||
const tasks = r.rows || [];
|
const tasks = r.rows || [];
|
||||||
// 按 deptId 排序: 质量部(2)→生产部(1)→陈总(4)
|
// 按 deptId 排序: 技术部(2)→生产部(1)→陈总(4)
|
||||||
const order = { 2: 1, 1: 2, 4: 3 };
|
const order = { 2: 1, 1: 2, 4: 3 };
|
||||||
tasks.sort((a, b) => (order[a.deptId] || 99) - (order[b.deptId] || 99));
|
tasks.sort((a, b) => (order[a.deptId] || 99) - (order[b.deptId] || 99));
|
||||||
this.allTaskList = tasks;
|
this.allTaskList = tasks;
|
||||||
@@ -285,11 +304,29 @@ export default {
|
|||||||
taskStatus: 1,
|
taskStatus: 1,
|
||||||
fillTime: this.parseTime(new Date(), '{y}-{m}-{d} {h}:{i}:{s}')
|
fillTime: this.parseTime(new Date(), '{y}-{m}-{d} {h}:{i}:{s}')
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
this.clearDraft(this.currentTask.taskId);
|
||||||
this.$modal.msgSuccess("已提交,流程已流转至下一节点");
|
this.$modal.msgSuccess("已提交,流程已流转至下一节点");
|
||||||
this.getList();
|
this.getList();
|
||||||
this.currentTask = {};
|
this.currentTask = {};
|
||||||
}).finally(() => { this.submitLoading = false; });
|
}).finally(() => { this.submitLoading = false; });
|
||||||
}
|
},
|
||||||
|
saveDraft() {
|
||||||
|
if (!this.currentTask.taskId) {
|
||||||
|
this.$modal.msgWarning("请先在左侧选择一条任务");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.draftLoading = true;
|
||||||
|
const draftKey = 'draft_opinion_' + this.currentTask.taskId;
|
||||||
|
localStorage.setItem(draftKey, JSON.stringify({
|
||||||
|
deptOpinion: this.opinionForm.deptOpinion,
|
||||||
|
fillFile: this.opinionForm.fillFile
|
||||||
|
}));
|
||||||
|
this.$modal.msgSuccess("已暂存");
|
||||||
|
this.draftLoading = false;
|
||||||
|
},
|
||||||
|
clearDraft(taskId) {
|
||||||
|
localStorage.removeItem('draft_opinion_' + taskId);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -350,8 +387,8 @@ export default {
|
|||||||
|
|
||||||
.list-item {
|
.list-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-direction: column;
|
||||||
padding: 10px 12px;
|
padding: 8px 12px;
|
||||||
margin-bottom: 2px;
|
margin-bottom: 2px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
@@ -371,15 +408,23 @@ export default {
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-main {
|
.item-row-top {
|
||||||
flex: 1;
|
|
||||||
min-width: 0;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
align-items: center;
|
||||||
gap: 3px;
|
justify-content: space-between;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-row-bottom {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-title {
|
.item-title {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: #303133;
|
color: #303133;
|
||||||
@@ -393,9 +438,12 @@ export default {
|
|||||||
color: #909399;
|
color: #909399;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item-main {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.item-meta {
|
.item-meta {
|
||||||
flex-shrink: 0;
|
display: none;
|
||||||
margin: 0 8px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-actions {
|
.item-actions {
|
||||||
|
|||||||
@@ -12,8 +12,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<el-select v-model="queryParams.flowStatus" placeholder="全部阶段" clearable size="mini" @change="handleQuery"
|
<el-select v-model="queryParams.flowStatus" placeholder="全部阶段" clearable size="mini" @change="handleQuery"
|
||||||
class="header-filter">
|
class="header-filter">
|
||||||
<el-option label="待审批" :value="2" />
|
<el-option label="待审批" :value="3" />
|
||||||
<el-option label="已办结" :value="4" />
|
<el-option label="已办结" :value="5" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -25,13 +25,13 @@
|
|||||||
<div v-loading="loading" class="list-body">
|
<div v-loading="loading" class="list-body">
|
||||||
<div v-for="item in dataList" :key="item.acceptId" class="list-item"
|
<div v-for="item in dataList" :key="item.acceptId" class="list-item"
|
||||||
:class="{ active: currentRow && currentRow.acceptId === item.acceptId }" @click="handleRowClick(item)">
|
:class="{ active: currentRow && currentRow.acceptId === item.acceptId }" @click="handleRowClick(item)">
|
||||||
<div class="item-main">
|
<div class="item-row-top">
|
||||||
<span class="item-title">{{ item.complaintNo }}</span>
|
<span class="item-title">{{ item.complaintNo }}</span>
|
||||||
<span class="item-sub">{{ parseTime(item.complaintDate, '{y}-{m}-{d}') }}</span>
|
<el-tag v-if="item.flowStatus === 3" type="primary" size="mini">待陈总审批</el-tag>
|
||||||
|
<el-tag v-else-if="item.flowStatus === 5" type="success" size="mini">已办结</el-tag>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-meta">
|
<div class="item-row-bottom">
|
||||||
<el-tag v-if="item.flowStatus === 2" type="primary" size="mini">待陈总审批</el-tag>
|
<span class="item-sub">{{ parseTime(item.complaintDate, '{y}-{m}-{d}') }}</span>
|
||||||
<el-tag v-else-if="item.flowStatus === 4" type="success" size="mini">已办结</el-tag>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="dataList.length === 0 && !loading" class="list-empty">
|
<div v-if="dataList.length === 0 && !loading" class="list-empty">
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
<HeaderControlSection :complaintNo="currentRow.complaintNo" :flowStatus="currentRow.flowStatus"
|
<HeaderControlSection :complaintNo="currentRow.complaintNo" :flowStatus="currentRow.flowStatus"
|
||||||
:meta="currentRow">
|
:meta="currentRow">
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<el-button v-if="currentRow.flowStatus === 4" size="mini" type="primary" plain
|
<el-button v-if="currentRow.flowStatus === 5" size="mini" type="primary" plain
|
||||||
icon="el-icon-download" @click="handleExportPdf">导出</el-button>
|
icon="el-icon-download" @click="handleExportPdf">导出</el-button>
|
||||||
<el-button size="mini" type="text" icon="el-icon-refresh" @click="handleRefreshDetail"
|
<el-button size="mini" type="text" icon="el-icon-refresh" @click="handleRefreshDetail"
|
||||||
title="刷新详情">刷新</el-button>
|
title="刷新详情">刷新</el-button>
|
||||||
@@ -83,14 +83,15 @@
|
|||||||
<div class="section-gap" />
|
<div class="section-gap" />
|
||||||
<DepartmentOpinionSection :taskList="taskList" @refresh="refreshTaskList" />
|
<DepartmentOpinionSection :taskList="taskList" @refresh="refreshTaskList" />
|
||||||
|
|
||||||
<div v-if="currentRow.flowStatus === 2" class="section-gap" />
|
<div v-if="currentRow.flowStatus === 3" class="section-gap" />
|
||||||
<div v-if="currentRow.flowStatus === 2" class="approval-section">
|
<div v-if="currentRow.flowStatus === 3" class="approval-section">
|
||||||
<div class="section-title">
|
<div class="section-title">
|
||||||
<span>审批意见 <span class="en-sub">· Approval Opinion</span></span>
|
<span>审批意见 <span class="en-sub">· Approval Opinion</span></span>
|
||||||
</div>
|
</div>
|
||||||
<el-input v-model="approvalOpinion" type="textarea" :rows="4"
|
<el-input v-model="approvalOpinion" type="textarea" :rows="4"
|
||||||
placeholder="请填写审批意见(审阅质量部、生产部意见后)" />
|
placeholder="请填写审批意见(审阅技术部、生产部意见后)" />
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
|
<el-button :loading="draftLoading" @click="saveDraft">暂 存</el-button>
|
||||||
<el-button type="primary" plain icon="el-icon-circle-check" :loading="completeLoading"
|
<el-button type="primary" plain icon="el-icon-circle-check" :loading="completeLoading"
|
||||||
@click="handleComplete">提交审批</el-button>
|
@click="handleComplete">提交审批</el-button>
|
||||||
</div>
|
</div>
|
||||||
@@ -132,6 +133,7 @@ export default {
|
|||||||
detailLoading: false,
|
detailLoading: false,
|
||||||
coilLoading: false,
|
coilLoading: false,
|
||||||
completeLoading: false,
|
completeLoading: false,
|
||||||
|
draftLoading: false,
|
||||||
total: 0,
|
total: 0,
|
||||||
dataList: [],
|
dataList: [],
|
||||||
currentRow: null,
|
currentRow: null,
|
||||||
@@ -139,7 +141,7 @@ export default {
|
|||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
complaintNo: undefined,
|
complaintNo: undefined,
|
||||||
flowStatus: 2
|
flowStatus: 3
|
||||||
},
|
},
|
||||||
coilList: [],
|
coilList: [],
|
||||||
taskList: [],
|
taskList: [],
|
||||||
@@ -168,6 +170,16 @@ export default {
|
|||||||
},
|
},
|
||||||
loadDetail(acceptId) {
|
loadDetail(acceptId) {
|
||||||
this.detailLoading = true;
|
this.detailLoading = true;
|
||||||
|
// 检查本地暂存
|
||||||
|
const draftKey = 'draft_summary_' + acceptId;
|
||||||
|
const cached = localStorage.getItem(draftKey);
|
||||||
|
if (cached) {
|
||||||
|
try {
|
||||||
|
this.approvalOpinion = cached;
|
||||||
|
} catch (e) { /* ignore */ }
|
||||||
|
} else {
|
||||||
|
this.approvalOpinion = '';
|
||||||
|
}
|
||||||
getComplaintAccept(acceptId).then(response => {
|
getComplaintAccept(acceptId).then(response => {
|
||||||
this.currentRow = response.data;
|
this.currentRow = response.data;
|
||||||
this.loadRelData(acceptId);
|
this.loadRelData(acceptId);
|
||||||
@@ -223,6 +235,7 @@ export default {
|
|||||||
throw new Error('no chen task');
|
throw new Error('no chen task');
|
||||||
}
|
}
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
this.clearDraft(this.currentRow.acceptId);
|
||||||
this.$modal.msgSuccess("审批已提交,已流转至吴部长处理");
|
this.$modal.msgSuccess("审批已提交,已流转至吴部长处理");
|
||||||
this.completeLoading = false;
|
this.completeLoading = false;
|
||||||
this.approvalOpinion = '';
|
this.approvalOpinion = '';
|
||||||
@@ -230,6 +243,23 @@ export default {
|
|||||||
this.getList();
|
this.getList();
|
||||||
}).catch(() => { this.completeLoading = false; });
|
}).catch(() => { this.completeLoading = false; });
|
||||||
},
|
},
|
||||||
|
saveDraft() {
|
||||||
|
if (!this.currentRow || !this.currentRow.acceptId) {
|
||||||
|
this.$modal.msgWarning("请先在左侧选择一条售后单");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this.approvalOpinion) {
|
||||||
|
this.$modal.msgWarning("请先填写审批意见再暂存");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.draftLoading = true;
|
||||||
|
localStorage.setItem('draft_summary_' + this.currentRow.acceptId, this.approvalOpinion);
|
||||||
|
this.$modal.msgSuccess("已暂存");
|
||||||
|
this.draftLoading = false;
|
||||||
|
},
|
||||||
|
clearDraft(acceptId) {
|
||||||
|
localStorage.removeItem('draft_summary_' + acceptId);
|
||||||
|
},
|
||||||
handleExportPdf() {
|
handleExportPdf() {
|
||||||
this.$refs.exportPdfDialog.open(this.currentRow.acceptId);
|
this.$refs.exportPdfDialog.open(this.currentRow.acceptId);
|
||||||
}
|
}
|
||||||
@@ -292,8 +322,8 @@ export default {
|
|||||||
|
|
||||||
.list-item {
|
.list-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-direction: column;
|
||||||
padding: 10px 12px;
|
padding: 8px 12px;
|
||||||
margin-bottom: 2px;
|
margin-bottom: 2px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
@@ -313,15 +343,23 @@ export default {
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-main {
|
.item-row-top {
|
||||||
flex: 1;
|
|
||||||
min-width: 0;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
align-items: center;
|
||||||
gap: 3px;
|
justify-content: space-between;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-row-bottom {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-title {
|
.item-title {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: #303133;
|
color: #303133;
|
||||||
@@ -335,9 +373,12 @@ export default {
|
|||||||
color: #909399;
|
color: #909399;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item-main {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.item-meta {
|
.item-meta {
|
||||||
flex-shrink: 0;
|
display: none;
|
||||||
margin: 0 8px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-empty {
|
.list-empty {
|
||||||
|
|||||||
@@ -25,19 +25,19 @@
|
|||||||
<div v-loading="loading" class="list-body">
|
<div v-loading="loading" class="list-body">
|
||||||
<div v-for="item in dataList" :key="item.relId" class="list-item"
|
<div v-for="item in dataList" :key="item.relId" class="list-item"
|
||||||
:class="{ active: currentRel && currentRel.relId === item.relId }" @click="handleRowClick(item)">
|
:class="{ active: currentRel && currentRel.relId === item.relId }" @click="handleRowClick(item)">
|
||||||
<div class="item-main">
|
<div class="item-row-top">
|
||||||
<span class="item-title">{{ (item.acceptInfo || {}).complaintNo || '' }}</span>
|
<span class="item-title">{{ (item.acceptInfo || {}).complaintNo || '' }}</span>
|
||||||
<span class="item-sub">{{ getDeptName(item.deptId) }} · {{ parseTime((item.acceptInfo || {}).complaintDate, '{y}-{m}-{d}') }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="item-meta">
|
|
||||||
<el-tag v-if="item.rejectMark === 1" type="danger" size="mini">已驳回</el-tag>
|
<el-tag v-if="item.rejectMark === 1" type="danger" size="mini">已驳回</el-tag>
|
||||||
<el-tag v-else-if="item.rejectMark === 2" type="info" size="mini">已隐藏</el-tag>
|
<el-tag v-else-if="item.rejectMark === 2" type="info" size="mini">已隐藏</el-tag>
|
||||||
<el-tag v-else-if="item.executeStatus === 0" type="warning" size="mini">待执行</el-tag>
|
<el-tag v-else-if="item.executeStatus === 0" type="warning" size="mini">待执行</el-tag>
|
||||||
<el-tag v-else-if="item.executeStatus === 1" type="success" size="mini">已反馈</el-tag>
|
<el-tag v-else-if="item.executeStatus === 1" type="success" size="mini">已反馈</el-tag>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-actions">
|
<div class="item-row-bottom">
|
||||||
<el-button v-if="item.executeStatus === 0" size="mini" type="text" icon="el-icon-edit" @click.stop="handleRowClick(item)"></el-button>
|
<span class="item-sub">{{ getDeptName(item.deptId) }} · {{ parseTime((item.acceptInfo || {}).complaintDate, '{y}-{m}-{d}') }}</span>
|
||||||
<el-button v-else size="mini" type="text" icon="el-icon-view" @click.stop="handleRowClick(item)"></el-button>
|
<div class="item-actions">
|
||||||
|
<el-button v-if="item.executeStatus === 0" size="mini" type="text" icon="el-icon-edit" @click.stop="handleRowClick(item)"></el-button>
|
||||||
|
<el-button v-else size="mini" type="text" icon="el-icon-view" @click.stop="handleRowClick(item)"></el-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="dataList.length === 0 && !loading" class="list-empty">
|
<div v-if="dataList.length === 0 && !loading" class="list-empty">
|
||||||
@@ -183,11 +183,11 @@ export default {
|
|||||||
}).finally(() => { this.loading = false; });
|
}).finally(() => { this.loading = false; });
|
||||||
},
|
},
|
||||||
getDeptName(deptId) {
|
getDeptName(deptId) {
|
||||||
const map = { 1: '生产部', 2: '质量部', 3: '销售部' };
|
const map = { 1: '生产部', 2: '技术部', 3: '销售部' };
|
||||||
return map[deptId] || '部门' + deptId;
|
return map[deptId] || '部门' + deptId;
|
||||||
},
|
},
|
||||||
getDeptLabel() {
|
getDeptLabel() {
|
||||||
const map = { 1: '生产部', 2: '质量部', 3: '销售部' };
|
const map = { 1: '生产部', 2: '技术部', 3: '销售部' };
|
||||||
return map[this.currentRel.deptId] || '';
|
return map[this.currentRel.deptId] || '';
|
||||||
},
|
},
|
||||||
handleQuery() {
|
handleQuery() {
|
||||||
@@ -326,8 +326,8 @@ export default {
|
|||||||
|
|
||||||
.list-item {
|
.list-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-direction: column;
|
||||||
padding: 10px 12px;
|
padding: 8px 12px;
|
||||||
margin-bottom: 2px;
|
margin-bottom: 2px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
@@ -347,15 +347,23 @@ export default {
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-main {
|
.item-row-top {
|
||||||
flex: 1;
|
|
||||||
min-width: 0;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
align-items: center;
|
||||||
gap: 3px;
|
justify-content: space-between;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-row-bottom {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-title {
|
.item-title {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: #303133;
|
color: #303133;
|
||||||
@@ -369,9 +377,12 @@ export default {
|
|||||||
color: #909399;
|
color: #909399;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item-main {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.item-meta {
|
.item-meta {
|
||||||
flex-shrink: 0;
|
display: none;
|
||||||
margin: 0 8px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-actions {
|
.item-actions {
|
||||||
|
|||||||
Reference in New Issue
Block a user