fix:重新发起

This commit is contained in:
大黑 2026-01-21 15:32:52 +08:00
parent 3d7ee782b1
commit d53901e00a
14 changed files with 5207 additions and 1598 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -220,7 +220,10 @@ export default {
url: '/custom/responsible/getImportTemplate', url: '/custom/responsible/getImportTemplate',
method: 'get' method: 'get'
}, },
GET_MODEL_BY_ID: {
url: '/custom/template/getTemplateById',
method: 'get'
},
// 修改流程主题 // 修改流程主题
EDIT_DATA_PROCESS_TITLE: { EDIT_DATA_PROCESS_TITLE: {
url: '/custom/activiti/updateFlowTitle', url: '/custom/activiti/updateFlowTitle',

View File

@ -105,10 +105,7 @@ export default {
url: '/custom/approval/directSendingApproval', url: '/custom/approval/directSendingApproval',
method: 'get' method: 'get'
}, },
GET_MODEL_BY_ID: {
url: '/custom/template/getTemplateById',
method: 'get'
},
GET_CAN_RETURN_NODE: { GET_CAN_RETURN_NODE: {
url: '/custom/approval/getReturnNodes', url: '/custom/approval/getReturnNodes',
method: 'get' method: 'get'
@ -124,5 +121,13 @@ export default {
EDIT_APPROVAL_PROCESS_TITLE: { EDIT_APPROVAL_PROCESS_TITLE: {
url: '/custom/approval/updateFlowTitle', url: '/custom/approval/updateFlowTitle',
method: 'get' method: 'get'
},
EDIT_APPROVAL_PROCESS: {
url: '/custom/approval/updateNode',
method: 'post'
},
CONTINUE_APPROVAL_PROCESS: {
url: '/custom/approval/continueApproval',
method: 'get'
} }
} }

View File

@ -62,5 +62,9 @@ export default {
GET_REPORT_APPROVAL_USERS: { GET_REPORT_APPROVAL_USERS: {
url: '/custom/benchmark/getApprovalUsers', url: '/custom/benchmark/getApprovalUsers',
method: 'get' method: 'get'
},
CONTINUE_REPORT_APPROVAL: {
url: '/custom/benchmark/continueApproval',
method: 'get'
} }
} }

View File

@ -1557,22 +1557,21 @@ export default {
} }
} }
.return-opinion-section {
margin-top: 16px; }
padding-top: 16px; }
.return-opinion-section {
margin-top: 16px !important;
border-top: 1px solid #ebeef5; border-top: 1px solid #ebeef5;
.opinion-label { .opinion-label {
margin-bottom: 8px; margin-bottom: 5px !important;
margin-top: 8px; margin-top: 5px !important;
font-size: 14px; font-size: 14px;
color: #606266; color: #606266;
font-weight: 500; font-weight: 500;
} }
} }
}
}
.approval-progress-fade-enter-active, .approval-progress-fade-enter-active,
.approval-progress-fade-leave-active { .approval-progress-fade-leave-active {
transition: opacity 0.2s ease; transition: opacity 0.2s ease;

File diff suppressed because it is too large Load Diff

View File

@ -2841,11 +2841,10 @@ export default {
// fromTodo flowId canResend true GET_DATA_APPROVAL_USERS // fromTodo flowId canResend true GET_DATA_APPROVAL_USERS
if (this.shouldShowResendButton) { if (this.shouldShowResendButton) {
this.isResendMode = true this.isResendMode = true
const flowId = this.engineModelID
const request = { const request = {
...api.GET_DATA_APPROVAL_USERS, ...api.GET_DATA_APPROVAL_USERS,
params: { params: {
templateId: flowId templateId: this.flowId
}, },
disableSuccessMsg: true disableSuccessMsg: true
} }

View File

@ -77,7 +77,7 @@
type="primary" type="primary"
@click="handleResendApproval" @click="handleResendApproval"
> >
重新发起 发起
</el-button> </el-button>
</template> </template>
<template v-else-if="isMaintainMode"> <template v-else-if="isMaintainMode">
@ -323,12 +323,41 @@
<div class="approval-process-title"> <div class="approval-process-title">
<div class="description-label"> <div class="description-label">
流程主题 <span class="required-mark">*</span> 流程主题 <span class="required-mark">*</span>
<div v-if="isResendModeFilled && !isProcessTitleEditing" class="step-actions">
<el-button
type="text"
size="small"
class="edit-step-btn"
@click="handleEditProcessTitle"
>
修改
</el-button>
</div>
<div v-else-if="isResendModeFilled && isProcessTitleEditing" class="step-actions">
<el-button
type="text"
size="small"
class="save-step-btn"
@click="handleSaveProcessTitle"
>
保存
</el-button>
<el-button
type="text"
size="small"
class="cancel-step-btn"
@click="handleCancelEditProcessTitle"
>
返回
</el-button>
</div>
</div> </div>
<el-input <el-input
v-model="approvalFormData.processTitle" v-model="approvalFormData.processTitle"
maxlength="100" maxlength="100"
show-word-limit show-word-limit
placeholder="请输入流程主题" placeholder="请输入流程主题"
:disabled="isResendModeFilled && !isProcessTitleEditing"
/> />
</div> </div>
</div> </div>
@ -365,6 +394,7 @@
placeholder="请选择" placeholder="请选择"
:remote-method="(query) => handleRemoteSearch(query, index)" :remote-method="(query) => handleRemoteSearch(query, index)"
:loading="step.loading" :loading="step.loading"
:disabled="isResendModeFilled && !isProcessTitleEditing"
class="handler-select" class="handler-select"
@change="(value) => handleHandlerChange(index, value)" @change="(value) => handleHandlerChange(index, value)"
> >
@ -680,35 +710,47 @@ export default {
approvalSubmitting: false, // loading approvalSubmitting: false, // loading
resending: false, // loading resending: false, // loading
isResendMode: false, // isResendMode: false, //
isResendModeFilled: false, //
resendApprovalData: null, // resendApprovalData: null, //
resendFlowId: null, // ID resendApprovalData
isProcessTitleEditing: false, //
originalProcessTitle: '', //
approvalWorkflowSteps: [ approvalWorkflowSteps: [
{ {
name: '校对', name: '校对',
required: true, required: true,
handlers: [], handlers: [],
options: [], options: [],
loading: false loading: false,
isEditing: false, //
originalData: null //
}, },
{ {
name: '审核', name: '审核',
required: true, required: true,
handlers: [], handlers: [],
options: [], options: [],
loading: false loading: false,
isEditing: false,
originalData: null
}, },
{ {
name: '会签', name: '会签',
required: false, required: false,
handlers: [], handlers: [],
options: [], options: [],
loading: false loading: false,
isEditing: false,
originalData: null
}, },
{ {
name: '批准', name: '批准',
required: true, required: true,
handlers: [], handlers: [],
options: [], options: [],
loading: false loading: false,
isEditing: false,
originalData: null
} }
], ],
nextLocalId: 1, nextLocalId: 1,
@ -1416,7 +1458,6 @@ export default {
console.log('获取审批流程信息:', resp) console.log('获取审批流程信息:', resp)
// fillResendApprovalData // fillResendApprovalData
this.resendApprovalData = resp this.resendApprovalData = resp
// getApprovalChange // getApprovalChange
this.getApprovalChange() this.getApprovalChange()
}) })
@ -2076,28 +2117,36 @@ export default {
required: true, required: true,
handlers: [], handlers: [],
options: [], options: [],
loading: false loading: false,
isEditing: false,
originalData: null
}, },
{ {
name: '审核', name: '审核',
required: true, required: true,
handlers: [], handlers: [],
options: [], options: [],
loading: false loading: false,
isEditing: false,
originalData: null
}, },
{ {
name: '会签', name: '会签',
required: false, required: false,
handlers: [], handlers: [],
options: [], options: [],
loading: false loading: false,
isEditing: false,
originalData: null
}, },
{ {
name: '批准', name: '批准',
required: true, required: true,
handlers: [], handlers: [],
options: [], options: [],
loading: false loading: false,
isEditing: false,
originalData: null
} }
] ]
@ -2282,6 +2331,25 @@ export default {
} else { } else {
console.log('节点列表为空,无法填充人员信息') console.log('节点列表为空,无法填充人员信息')
} }
// flowId dataObj
if (dataObj && !Array.isArray(dataObj)) {
this.resendFlowId = dataObj.flowId || dataObj.id || null
console.log('提取的 flowId:', this.resendFlowId)
}
//
this.isResendModeFilled = true
//
this.originalProcessTitle = this.approvalFormData.processTitle || ''
//
this.approvalWorkflowSteps.forEach((step) => {
step.originalData = {
handlers: JSON.parse(JSON.stringify(step.handlers || [])),
options: JSON.parse(JSON.stringify(step.options || []))
}
step.isEditing = false
})
}, },
handleApprovalCancel() { handleApprovalCancel() {
// 退 // 退
@ -2312,89 +2380,338 @@ export default {
required: true, required: true,
handlers: [], handlers: [],
options: [], options: [],
loading: false loading: false,
isEditing: false,
originalData: null
}, },
{ {
name: '审核', name: '审核',
required: true, required: true,
handlers: [], handlers: [],
options: [], options: [],
loading: false loading: false,
isEditing: false,
originalData: null
}, },
{ {
name: '会签', name: '会签',
required: false, required: false,
handlers: [], handlers: [],
options: [], options: [],
loading: false loading: false,
isEditing: false,
originalData: null
}, },
{ {
name: '批准', name: '批准',
required: true, required: true,
handlers: [], handlers: [],
options: [], options: [],
loading: false loading: false,
isEditing: false,
originalData: null
} }
] ]
//
this.isResendModeFilled = false
this.resendFlowId = null
this.isProcessTitleEditing = false
this.originalProcessTitle = ''
}, },
handleApprovalFormSubmit() { //
// ID handleEditStep(stepIndex) {
const templateRowId = this.getDetailTemplateId() const step = this.approvalWorkflowSteps[stepIndex]
if (!templateRowId) { if (!step) {
this.$message.error('缺少模板ID无法发起审批')
return return
} }
const processTitle = (this.approvalFormData.processTitle || '').trim() //
if (!processTitle) { step.originalData = {
this.$message.warning('请填写流程主题') handlers: JSON.parse(JSON.stringify(step.handlers || [])),
options: JSON.parse(JSON.stringify(step.options || []))
}
//
step.isEditing = true
},
//
handleSaveStep(stepIndex) {
const step = this.approvalWorkflowSteps[stepIndex]
if (!step) {
return return
} }
// nodeList engineDetail.vue const userIds = (step.handlers || []).filter(Boolean)
if (userIds.length === 0) {
this.$message.warning('请至少选择一位处理人')
return
}
// flowId detail resendFlowId
let flowId = null
if (this.detail && this.detail.flowId) {
flowId = this.detail.flowId
} else if (this.resendFlowId) {
flowId = this.resendFlowId
}
if (!flowId) {
this.$message.error('缺少流程ID无法保存')
return
}
const request = {
...api.EDIT_APPROVAL_PROCESS,
params: {
flowId: flowId,
nodeName: step.name,
userIds
},
disableSuccessMsg: true
}
step.loading = true
this.$request(request)
.asyncThen(() => {
//
step.originalData = {
handlers: JSON.parse(JSON.stringify(step.handlers || [])),
options: JSON.parse(JSON.stringify(step.options || []))
}
// 退
step.isEditing = false
this.$message({
type: 'success',
message: '保存成功'
})
})
.asyncErrorCatch((err) => {
console.error('保存环节编辑失败:', err)
this.$message({
type: 'error',
message: err?.message || '保存失败,请重试'
})
})
.finally(() => {
step.loading = false
})
},
//
handleCancelEditStep(stepIndex) {
const step = this.approvalWorkflowSteps[stepIndex]
if (!step || !step.originalData) {
return
}
//
step.handlers = JSON.parse(JSON.stringify(step.originalData.handlers || []))
step.options = JSON.parse(JSON.stringify(step.originalData.options || []))
// 退
step.isEditing = false
},
//
handleEditProcessTitle() {
//
this.originalProcessTitle = this.approvalFormData.processTitle || ''
//
this.approvalWorkflowSteps.forEach((step) => {
step.originalData = {
handlers: JSON.parse(JSON.stringify(step.handlers || [])),
options: JSON.parse(JSON.stringify(step.options || []))
}
})
//
this.isProcessTitleEditing = true
},
//
handleSaveProcessTitle() {
const newTitle = (this.approvalFormData.processTitle || '').trim()
if (!newTitle) {
this.$message.warning('流程主题不能为空')
return
}
// flowId detail resendFlowId
let flowId = null
if (this.detail && this.detail.flowId) {
flowId = this.detail.flowId
} else if (this.resendFlowId) {
flowId = this.resendFlowId
}
if (!flowId) {
this.$message.error('缺少流程ID无法保存')
return
}
// nodeList
const nodeList = this.approvalWorkflowSteps.map((step, index) => ({ const nodeList = this.approvalWorkflowSteps.map((step, index) => ({
nodeName: step.name, nodeName: step.name,
assignees: step.handlers, assignees: step.handlers,
nodeOrder: index + 1 nodeOrder: index + 1
})) }))
const submitData = {
templateRowId: templateRowId,
nodeList: nodeList,
processTitle: processTitle,
createBy: getUserId(),
userId: getUserId()
}
// // nodeList, flowId, title, userId
const request = { const request = {
...api.START_APPROVAL, ...api.EDIT_APPROVAL_PROCESS,
params: submitData, params: {
nodeList: nodeList,
flowId: flowId,
title: newTitle,
userId: getUserId()
},
disableSuccessMsg: true disableSuccessMsg: true
} }
this.approvalSubmitting = true
this.$request(request) this.$request(request)
.asyncThen((resp) => { .asyncThen(() => {
console.log('审批提交成功') //
this.originalProcessTitle = newTitle
//
this.approvalWorkflowSteps.forEach((step) => {
step.originalData = {
handlers: JSON.parse(JSON.stringify(step.handlers || [])),
options: JSON.parse(JSON.stringify(step.options || []))
}
})
// 退
this.isProcessTitleEditing = false
this.$message({ this.$message({
type: 'success', type: 'success',
message: '审批提交成功' message: '保存成功'
}) })
this.isApprovalMode = false //
this.approvalSubmitting = false if (flowId) {
// // detail flowId
this.originalTableDataForApproval = [] if (!this.detail) {
this.originalPaginationForApproval = null this.detail = {}
this.handleBack() }
if (!this.detail.flowId) {
this.detail.flowId = flowId
}
this.getApprovalSpet()
}
}) })
.asyncErrorCatch((err) => { .asyncErrorCatch((err) => {
console.error('审批提交失败:', err) console.error('保存失败:', err)
this.$message({ this.$message({
type: 'error', type: 'error',
message: '审批提交失败,请重试' message: err?.message || '保存失败,请重试'
}) })
}) })
.finally(() => { },
this.approvalSubmitting = false //
}) handleCancelEditProcessTitle() {
//
this.approvalFormData.processTitle = this.originalProcessTitle || ''
//
this.approvalWorkflowSteps.forEach((step) => {
if (step.originalData) {
step.handlers = JSON.parse(JSON.stringify(step.originalData.handlers || []))
step.options = JSON.parse(JSON.stringify(step.originalData.options || []))
}
})
// 退
this.isProcessTitleEditing = false
},
handleApprovalFormSubmit() {
//
if (this.isResendModeFilled) {
// CONTINUE_APPROVAL_PROCESS
// resendFlowId flowId
const flowId = this.resendFlowId
if (!flowId) {
this.$message.error('缺少流程ID无法继续审批')
return
}
const request = {
...api.CONTINUE_APPROVAL_PROCESS,
params: {
flowId: flowId,
userId: getUserId()
},
disableSuccessMsg: true
}
this.approvalSubmitting = true
this.$request(request)
.asyncThen((resp) => {
console.log('审批提交成功')
this.$message({
type: 'success',
message: '审批提交成功'
})
this.isApprovalMode = false
this.isResendModeFilled = false
this.resendFlowId = null
this.approvalSubmitting = false
//
this.originalTableDataForApproval = []
this.originalPaginationForApproval = null
this.handleBack()
})
.asyncErrorCatch((err) => {
console.error('审批提交失败:', err)
this.$message({
type: 'error',
message: err?.message || '审批提交失败,请重试'
})
})
.finally(() => {
this.approvalSubmitting = false
})
} else {
// START_APPROVAL
// ID
const templateRowId = this.getDetailTemplateId()
if (!templateRowId) {
this.$message.error('缺少模板ID无法发起审批')
return
}
const processTitle = (this.approvalFormData.processTitle || '').trim()
if (!processTitle) {
this.$message.warning('请填写流程主题')
return
}
// nodeList engineDetail.vue
const nodeList = this.approvalWorkflowSteps.map((step, index) => ({
nodeName: step.name,
assignees: step.handlers,
nodeOrder: index + 1
}))
const submitData = {
templateRowId: templateRowId,
nodeList: nodeList,
processTitle: processTitle,
createBy: getUserId(),
userId: getUserId()
}
//
const request = {
...api.START_APPROVAL,
params: submitData,
disableSuccessMsg: true
}
this.approvalSubmitting = true
this.$request(request)
.asyncThen((resp) => {
console.log('审批提交成功')
this.$message({
type: 'success',
message: '审批提交成功'
})
this.isApprovalMode = false
this.approvalSubmitting = false
//
this.originalTableDataForApproval = []
this.originalPaginationForApproval = null
this.handleBack()
})
.asyncErrorCatch((err) => {
console.error('审批提交失败:', err)
this.$message({
type: 'error',
message: '审批提交失败,请重试'
})
})
.finally(() => {
this.approvalSubmitting = false
})
}
}, },
handleRemoteSearch(query, stepIndex) { handleRemoteSearch(query, stepIndex) {
const step = this.approvalWorkflowSteps[stepIndex] const step = this.approvalWorkflowSteps[stepIndex]
@ -3793,11 +4110,57 @@ export default {
font-size: 16px; font-size: 16px;
line-height: 24px; line-height: 24px;
font-weight: bolder; font-weight: bolder;
margin-bottom: 8px; margin-bottom: 8px !important;
color: #303133; color: #303133;
} }
} }
.approval-process-title {
display: flex;
flex-direction: column;
gap: 8px;
margin-bottom: 16px;
.description-label {
font-size: 16px;
line-height: 24px;
font-weight: bolder;
margin-bottom: 8px !important;
color: #303133;
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
.step-actions {
display: flex;
align-items: center;
gap: 8px;
flex-shrink: 0;
.edit-step-btn,
.save-step-btn,
.cancel-step-btn {
padding: 0;
font-size: 12px;
color: #409eff;
&:hover {
color: #66b1ff;
}
}
.cancel-step-btn {
color: #909399;
&:hover {
color: #a6a9ad;
}
}
}
}
}
.approval-workflow { .approval-workflow {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -3807,7 +4170,6 @@ export default {
font-size: 14px; font-size: 14px;
font-weight: 600; font-weight: 600;
color: #303133; color: #303133;
margin-bottom: 8px;
} }
.workflow-table { .workflow-table {

View File

@ -110,7 +110,9 @@
v-for="(colConfig, index) in tableConfig.colConfigs" v-for="(colConfig, index) in tableConfig.colConfigs"
v-slot:[colConfig.customHeadSlot]="{ column }" v-slot:[colConfig.customHeadSlot]="{ column }"
> >
<div v-if="colConfig.customHeadSlot" :key="index"> {{ column }} {{ colConfig }} </div> <div v-if="colConfig.customHeadSlot" :key="index">
{{ column }} {{ colConfig }}
</div>
</template> </template>
<template <template
@ -166,16 +168,7 @@
> >
修改 修改
</a> </a>
<span style="width: 6px; display: inline-block"></span> <span v-if="row.status === 'DRAFT' && hasReportEditPermission() && row.returnNum === 0" style="width: 6px; display: inline-block"></span>
<a
v-if="row.status === 'DRAFT' && hasReportEditPermission() && row.returnNum > 0"
href="javascript:void(0)"
class="el-link el-link--primary"
@click.stop="handleEdit(row)"
>
重新发起
</a>
<span style="width: 6px; display: inline-block"></span>
<!-- <a <!-- <a
v-if="row.status === 'APPROVING'" v-if="row.status === 'APPROVING'"
href="javascript:void(0)" href="javascript:void(0)"
@ -464,7 +457,9 @@
> >
<div class="dialog-body-wrapper"> <div class="dialog-body-wrapper">
<div class="approval-process-title"> <div class="approval-process-title">
<div class="description-label"> 流程主题 <span class="required-mark">*</span> </div> <div class="description-label">
流程主题 <span class="required-mark">*</span>
</div>
<el-input <el-input
v-model="launchProcessTitle" v-model="launchProcessTitle"
maxlength="100" maxlength="100"
@ -1858,10 +1853,13 @@ export default {
this.showReportDetail = false this.showReportDetail = false
this.currentReportDetail = null this.currentReportDetail = null
}, },
handleReportDetailRefresh() { handleReportDetailRefresh(payload) {
// //
this.loadData() this.loadData()
// //
if (payload && payload.keepOpen) {
return
}
this.closeReportDetail() this.closeReportDetail()
}, },
currentChange(currentPage) { currentChange(currentPage) {

View File

@ -26,7 +26,7 @@
> >
直送 直送
</el-button> </el-button>
<el-button v-else @click="handleLaunch"> <el-button @click="handleLaunch">
发起 发起
</el-button> </el-button>
<el-button type="primary" @click="handleEdit"> <el-button type="primary" @click="handleEdit">
@ -42,7 +42,7 @@
直送 直送
</el-button> </el-button>
<el-button @click="handleResendApproval"> <el-button @click="handleResendApproval">
重新发起 发起
</el-button> </el-button>
<el-button type="primary" @click="handleEdit"> <el-button type="primary" @click="handleEdit">
修改 修改
@ -53,10 +53,7 @@
<el-button @click="handleCancelEdit"> <el-button @click="handleCancelEdit">
返回 返回
</el-button> </el-button>
<el-button v-if="canResend" type="primary" @click="handleResendApproval"> <el-button type="primary" :loading="saving" @click="handleSave">
重新发起
</el-button>
<el-button v-else type="primary" :loading="saving" @click="handleSave">
保存 保存
</el-button> </el-button>
</template> </template>
@ -68,7 +65,7 @@
退回 退回
</el-button> </el-button>
<el-button <el-button
v-if="canResend" v-if="canResend"
:loading="resending" :loading="resending"
@click="handleResend" @click="handleResend"
> >
@ -331,7 +328,7 @@
</section> </section>
<!-- 审批流程 --> <!-- 审批流程 -->
<section v-if="reportDetail.status && reportDetail.status !== 'DRAFT' && detail.flowId" class="block-section"> <section v-if="reportDetail.status && reportDetail.status !== 'DRAFT' && detail.flowId && !isEditMode" class="block-section">
<div class="section-title"> <div class="section-title">
审批流程 审批流程
</div> </div>
@ -372,7 +369,7 @@
</section> </section>
<!-- 审批环节草稿状态下显示 --> <!-- 审批环节草稿状态下显示 -->
<section v-if="reportDetail.status === 'DRAFT'" class="block-section"> <section v-if="reportDetail.status === 'DRAFT' || reportDetail.status === 'REJECTED'" class="block-section">
<div class="section-title"> <div class="section-title">
审批环节 审批环节
</div> </div>
@ -395,6 +392,7 @@
maxlength="100" maxlength="100"
show-word-limit show-word-limit
placeholder="请输入流程主题" placeholder="请输入流程主题"
@change="handleProcessTitleChange"
/> />
</div> </div>
<div class="workflow-table"> <div class="workflow-table">
@ -629,6 +627,10 @@ export default {
saving: false, // saving: false, //
isEditingProcessTitle: false, // isEditingProcessTitle: false, //
editingProcessTitle: '', // editingProcessTitle: '', //
approvalFlowIdFromUsers: '', // ID
approvalCanSend: false, //
// watch/change
originalEditSnapshot: null, //
approvalWorkflowSteps: [ approvalWorkflowSteps: [
{ {
name: '校对', name: '校对',
@ -684,7 +686,7 @@ export default {
let processedNodes = this.flowNodes let processedNodes = this.flowNodes
if (rejectIndex !== -1) { if (rejectIndex !== -1) {
// REJECT // REJECT
processedNodes = this.flowNodes.slice(0, rejectIndex + 1) // processedNodes = this.flowNodes.slice(0, rejectIndex + 1)
} else { } else {
// REJECT result "" APPROVING // REJECT result "" APPROVING
const stayIndex = processedNodes.findIndex((node) => node.result === '待审批') const stayIndex = processedNodes.findIndex((node) => node.result === '待审批')
@ -745,22 +747,6 @@ export default {
opinion: opinion opinion: opinion
}) })
}) })
} else if (this.progress && this.progress.length > 0) {
// flowNodes使 progress
this.progress.forEach((stage) => {
if (stage.steps && stage.steps.length > 0) {
stage.steps.forEach((step) => {
nodes.push({
title: stage.title || '审批节点',
userName: step.userName,
operateTime: step.approvalTime || step.handleTime || step.createTime,
result: step.result || step.status,
status: step.result || step.status,
opinion: step.opinion || step.remark || step.comment || null
})
})
}
})
} }
return nodes return nodes
@ -981,11 +967,16 @@ export default {
templateVersion: data.templateVersion || '', templateVersion: data.templateVersion || '',
contentName: data.contentName || '' contentName: data.contentName || ''
} }
this.reportDetail.processTitle = data.progressTitle
// flowStatus REJECTED"稿" // flowStatus REJECTED"稿"
const flowStatus = data.flowStatus || '' const flowStatus = data.flowStatus || ''
const createBy = data.createBy || '' const createBy = data.createBy || ''
if (flowStatus) {
//
this.$set(this.reportDetail, 'status', flowStatus)
}
this.showTopDetail = { this.showTopDetail = {
processTitle: data.progressTitle || '', processTitle: data.progressTitle,
createBy: createBy, createBy: createBy,
createTime: data.createTime || '', createTime: data.createTime || '',
currentNode: flowStatus === 'REJECTED' ? '编制' : (data.currentNode || ''), currentNode: flowStatus === 'REJECTED' ? '编制' : (data.currentNode || ''),
@ -1374,7 +1365,8 @@ export default {
// report.vue // report.vue
handleLaunch() { handleLaunch() {
const reportId = this.reportDetail.reportId || this.reportDetail.id || this.detail.reportId || this.detail.id const reportId = this.reportDetail.reportId || this.reportDetail.id || this.detail.reportId || this.detail.id
const flowId = this.detail.flowId || this.reportDetail.flowId const flowId = this.approvalFlowIdFromUsers || this.detail.flowId || this.reportDetail.flowId
const canSend = this.canResend
if (!reportId) { if (!reportId) {
this.$message.error('缺少报告ID无法发起审批') this.$message.error('缺少报告ID无法发起审批')
@ -1392,15 +1384,33 @@ export default {
type: 'warning' type: 'warning'
}) })
.then(() => { .then(() => {
const submitData = { let request = null
reportId: reportId, if (canSend) {
flowId: flowId, // 使 flowId
userId: getUserId() const continueFlowId = this.approvalFlowIdFromUsers || flowId
} if (!continueFlowId) {
const request = { this.$message.error('缺少流程ID无法继续发起审批')
...api.ADD_REPORT, return
params: submitData, }
disableSuccessMsg: true request = {
...api.CONTINUE_REPORT_APPROVAL,
params: {
flowId: continueFlowId,
userId: getUserId()
},
disableSuccessMsg: true
}
} else {
const submitData = {
reportId: reportId,
flowId: flowId,
userId: getUserId()
}
request = {
...api.ADD_REPORT,
params: submitData,
disableSuccessMsg: true
}
} }
this.launching = true this.launching = true
@ -1499,7 +1509,7 @@ export default {
// 稿 // 稿
loadApprovalUsers(flowId) { loadApprovalUsers(flowId) {
if (!flowId) { if (!flowId) {
return return Promise.resolve()
} }
const request = { const request = {
...api.GET_REPORT_APPROVAL_USERS, ...api.GET_REPORT_APPROVAL_USERS,
@ -1508,15 +1518,47 @@ export default {
}, },
disableSuccessMsg: true disableSuccessMsg: true
} }
this.$request(request) return this.$request(request)
.asyncThen((resp) => { .asyncThen((resp) => {
console.log('获取审批流程信息:', resp) console.log('获取审批流程信息:', resp)
// ID
const meta = this.parseApprovalUsersMeta(resp)
this.approvalCanSend = !!meta.canSend
this.approvalFlowIdFromUsers = meta.flowId || flowId || ''
//
if (meta.title) {
this.reportDetail.processTitle = meta.title
this.showTopDetail.processTitle = meta.title
//
if (this.isEditMode) {
this.editFormData.processTitle = meta.title
}
}
this.fillApprovalUsersData(resp, this.approvalWorkflowSteps) this.fillApprovalUsersData(resp, this.approvalWorkflowSteps)
}) })
.asyncErrorCatch((err) => { .asyncErrorCatch((err) => {
console.error('获取审批流程信息失败:', err) console.error('获取审批流程信息失败:', err)
throw err
}) })
}, },
// ID/
parseApprovalUsersMeta(resp) {
const meta = { flowId: '', canSend: false, title: '' }
const candidate = resp?.data ?? resp
const pickFrom = (obj) => {
if (!obj || Array.isArray(obj)) return
meta.flowId = meta.flowId || obj.flowId || obj.id || obj.flowid || ''
meta.canSend = meta.canSend || obj.canSend || obj.canResend || false
meta.title = meta.title || obj.progressTitle || obj.processTitle || obj.title || ''
}
if (candidate && !Array.isArray(candidate)) {
pickFrom(candidate)
if (candidate.data && !Array.isArray(candidate.data)) {
pickFrom(candidate.data)
}
}
return meta
},
// report.vue // report.vue
fillApprovalUsersData(resp, workflowSteps) { fillApprovalUsersData(resp, workflowSteps) {
// //
@ -1669,13 +1711,16 @@ export default {
}, },
// //
handleHandlerChange(stepIndex, selectedIds) { handleHandlerChange(stepIndex, selectedIds) {
// //
}, },
// //
handleResendApproval() { handleResendApproval() {
// //
this.handleResatrtLaunch() this.handleResatrtLaunch()
}, },
handleProcessTitleChange() {
//
},
// 稿 // 稿
loadLaunchApprovalUsers(flowId) { loadLaunchApprovalUsers(flowId) {
if (!flowId) { if (!flowId) {
@ -1700,7 +1745,7 @@ export default {
}) })
}, },
// //
handleEdit() { async handleEdit() {
// //
this.originalReportDetail = JSON.parse(JSON.stringify(this.reportDetail)) this.originalReportDetail = JSON.parse(JSON.stringify(this.reportDetail))
// //
@ -1735,14 +1780,19 @@ export default {
this.fileList = [] this.fileList = []
} }
this.selectedFile = null this.selectedFile = null
// 稿 this.isEditMode = true
// 稿/
if (this.reportDetail.status === 'DRAFT') { if (this.reportDetail.status === 'DRAFT') {
const flowId = this.detail.flowId || this.reportDetail.flowId const flowId = this.detail.flowId || this.reportDetail.flowId
if (flowId && (!this.approvalWorkflowSteps[0].handlers || this.approvalWorkflowSteps[0].handlers.length === 0)) { if (flowId) {
this.loadApprovalUsers(flowId) try {
await this.loadApprovalUsers(flowId)
} catch (e) {
// ignore
}
} }
} }
this.isEditMode = true this.originalEditSnapshot = this.buildEditSnapshot()
}, },
// //
handleCancelEdit() { handleCancelEdit() {
@ -1770,6 +1820,7 @@ export default {
} }
this.fileList = [] this.fileList = []
this.selectedFile = null this.selectedFile = null
this.originalEditSnapshot = null
this.isEditMode = false this.isEditMode = false
// //
if (this.$refs.editForm) { if (this.$refs.editForm) {
@ -1862,76 +1913,194 @@ export default {
this.submitEdit() this.submitEdit()
} }
}, },
buildEditSnapshot() {
const normalize = (v) => (v == null ? '' : v)
const normalizeSteps = (steps) =>
(steps || []).map((s) => ({
name: s.name,
handlers: (s.handlers || []).filter(Boolean).slice().sort()
}))
//
return {
form: {
title: normalize(this.editFormData?.title),
manufacturerName: normalize(this.editFormData?.manufacturerName),
modelName: normalize(this.editFormData?.modelName),
manufacturerAbbreviation: normalize(this.editFormData?.manufacturerAbbreviation),
modelAbbreviation: normalize(this.editFormData?.modelAbbreviation),
productNumber: normalize(this.editFormData?.productNumber),
module: normalize(this.editFormData?.module),
plate: normalize(this.editFormData?.plate),
platform: normalize(this.editFormData?.platform),
series: normalize(this.editFormData?.series),
marketSegment: normalize(this.editFormData?.marketSegment),
projectName: normalize(this.editFormData?.projectName),
projectNumber: normalize(this.editFormData?.projectNumber),
explanation: normalize(this.editFormData?.explanation),
fileUrl: normalize(this.editFormData?.fileUrl),
fileName: normalize(this.editFormData?.fileName)
},
processTitle: (this.editFormData?.processTitle || '').trim(),
steps: normalizeSteps(this.approvalWorkflowSteps)
}
},
diffEditSnapshot(original, current) {
const isSame = (a, b) => JSON.stringify(a) === JSON.stringify(b)
const baseChanged =
!original ||
!isSame(original.form, current.form) ||
!!this.selectedFile //
const approvalChanged =
!original ||
original.processTitle !== current.processTitle ||
!isSame(original.steps, current.steps)
return { baseChanged, approvalChanged }
},
hasAnyEditChange() {
const current = this.buildEditSnapshot()
const { baseChanged, approvalChanged } = this.diffEditSnapshot(this.originalEditSnapshot, current)
return baseChanged || approvalChanged
},
// //
submitEdit() { submitEdit() {
const submitData = async () => { const submitData = async () => {
// try {
if (this.selectedFile) { //
try { if (!this.hasAnyEditChange()) {
this.isEditMode = false
this.$message({
type: 'info',
message: '未修改,无需保存'
})
return
}
//
if (this.selectedFile) {
const fileUrl = await this.handleFileUpload() const fileUrl = await this.handleFileUpload()
this.editFormData.fileUrl = fileUrl || '' this.editFormData.fileUrl = fileUrl || ''
this.editFormData.fileName = this.selectedFile.name this.editFormData.fileName = this.selectedFile.name
} catch (err) { }
console.error('文件上传失败:', err)
this.$message.error('文件上传失败,请重试') const reportId = this.reportDetail.reportId || this.reportDetail.id
if (!reportId) {
this.$message.error('缺少报告ID')
return return
} }
}
const reportId = this.reportDetail.reportId || this.reportDetail.id const includeApprovalInSave = !this.canResend
if (!reportId) { const shouldUpdateApprovalProcess = this.canResend
this.$message.error('缺少报告ID')
return
}
// 稿 const { processTitle, ...restForm } = this.editFormData
const params = { const params = {
reportId: reportId, reportId: reportId,
flowId: this.detail.flowId, flowId: this.detail.flowId,
...this.editFormData, ...restForm,
createBy: getUserId(), createBy: getUserId(),
userId: getUserId() userId: getUserId()
} }
// 稿 if (includeApprovalInSave) {
if (this.reportDetail.status === 'DRAFT') { params.processTitle = processTitle || ''
const nodeList = this.approvalWorkflowSteps.map((step, index) => ({ params.nodeList = this.approvalWorkflowSteps.map((step, index) => ({
nodeName: step.name, nodeName: step.name,
assignees: step.handlers, assignees: step.handlers,
nodeOrder: index + 1 nodeOrder: index + 1
})) }))
params.nodeList = nodeList }
}
const request = { this.saving = true
...api.EDIT_REPORT, // watch/change
params: params, const currentSnap = this.buildEditSnapshot()
disableSuccessMsg: true const { baseChanged, approvalChanged } = this.diffEditSnapshot(this.originalEditSnapshot, currentSnap)
} // canResend true shouldUpdateApprovalProcess true updateApprovalProcess
// canResend false includeApprovalInSave true EDIT_REPORT
const needUpdateApprovalProcess =
shouldUpdateApprovalProcess && approvalChanged
// EDIT_REPORT
// 1. EDIT_REPORT
// 2. includeApprovalInSave true EDIT_REPORT
// 3. shouldUpdateApprovalProcess true EDIT_REPORT
const shouldOnlyUpdateApprovalProcess = shouldUpdateApprovalProcess && approvalChanged && !baseChanged
const needUpdateReportBase =
!shouldOnlyUpdateApprovalProcess && (
baseChanged ||
(includeApprovalInSave && approvalChanged)
)
if (needUpdateReportBase) {
console.log('needUpdateReportBase', needUpdateReportBase)
const request = {
...api.EDIT_REPORT,
params: params,
disableSuccessMsg: true
}
await this.$request(request).asyncThen(() => {})
}
this.saving = true if (needUpdateApprovalProcess) {
this.$request(request) console.log('needUpdateApprovalProcess', needUpdateApprovalProcess)
.asyncThen((resp) => { await this.updateApprovalProcess()
this.saving = false }
this.isEditMode = false
// this.isEditMode = false
this.loadReportDetailFromApi(reportId, this.detail.flowId) // + 稿/ handleResatrtLaunch
this.$message({ const currentFlowId = this.detail.flowId || this.reportDetail.flowId
type: 'success', this.loadReportDetailFromApi(reportId, currentFlowId)
message: '保存成功' if (this.reportDetail.status === 'DRAFT' && currentFlowId) {
}) //
// this.loadApprovalUsers(currentFlowId)
this.$emit('refresh') }
}) //
.asyncErrorCatch((err) => { this.originalEditSnapshot = this.buildEditSnapshot()
console.error('保存失败:', err) this.$message({
this.saving = false type: 'success',
this.$message.error('保存失败,请重试') message: '保存成功'
}) })
//
this.$emit('refresh', { keepOpen: true })
} catch (err) {
console.error('保存失败:', err)
this.$message.error(err?.message || '保存失败,请重试')
} finally {
this.saving = false
}
} }
submitData() submitData()
}, },
//
updateApprovalProcess() {
const flowId = this.detail.flowId || this.reportDetail.flowId
if (!flowId) {
this.$message.error('缺少流程ID无法保存审批环节')
return Promise.reject(new Error('缺少流程ID'))
}
const nodeList = this.approvalWorkflowSteps.map((step, index) => ({
nodeName: step.name,
assignees: step.handlers,
nodeOrder: index + 1
}))
const request = {
...api.EDIT_APPROVAL_PROCESS,
params: {
nodeList: nodeList,
flowId: flowId,
title: this.editFormData.processTitle || '',
userId: getUserId()
},
disableSuccessMsg: true
}
return this.$request(request)
.asyncThen(() => {})
.asyncErrorCatch((err) => {
console.error('更新审批环节失败:', err)
this.$message.error(err?.message || '更新审批环节失败,请重试')
throw err
})
},
// //
handleEditProcessTitle() { handleEditProcessTitle() {
this.isEditingProcessTitle = true this.isEditingProcessTitle = true

View File

@ -43,24 +43,6 @@
v-for="(colConfig, index) in tableConfig.colConfigs" v-for="(colConfig, index) in tableConfig.colConfigs"
v-slot:[colConfig.customSlot]="{ row, rowIndex }" v-slot:[colConfig.customSlot]="{ row, rowIndex }"
> >
<div v-if="colConfig.customSlot === 'options'" :key="'op' + index + '' + rowIndex">
<a
href="javascript:void(0)"
class="el-link el-link--primary"
@click.stop="handleRowView(row)"
>查看</a
>
<!-- <span
v-if="row.dataType === '数据维护'"
style="width: 6px; display: inline-block"
></span>
<a
href="javascript:void(0)"
class="el-link el-link--primary"
@click.stop="handleRowBack(row)"
>退回</a
> -->
</div>
<div v-if="colConfig.customSlot === 'processTitle'" :key="'pt' + index + '' + rowIndex"> <div v-if="colConfig.customSlot === 'processTitle'" :key="'pt' + index + '' + rowIndex">
<a <a
href="javascript:void(0)" href="javascript:void(0)"
@ -157,7 +139,7 @@ import ApprovalProgressDetail from './approvalProgressDetail.vue'
import ReportDetail from './reportDetail.vue' import ReportDetail from './reportDetail.vue'
import ModelDetail from './modelDetail.vue' import ModelDetail from './modelDetail.vue'
import { getUserId } from '@/utils' import { getUserId } from '@/utils'
import api from '@/api/demo' import api from '@/api'
export default { export default {
name: 'TodoPage', name: 'TodoPage',
components: { components: {
@ -229,14 +211,6 @@ export default {
minWidth: '150', minWidth: '150',
align: 'center', align: 'center',
formatter: this.formatDateTime formatter: this.formatDateTime
},
{
prop: 'options',
label: '操作',
customSlot: 'options',
align: 'center',
width: '100',
fixed: 'right'
} }
], ],
seqType: '', seqType: '',