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 { .return-opinion-section {
margin-top: 16px; margin-top: 16px !important;
padding-top: 16px;
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,32 +2380,280 @@ 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 = ''
},
//
handleEditStep(stepIndex) {
const step = this.approvalWorkflowSteps[stepIndex]
if (!step) {
return
}
//
step.originalData = {
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
}
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) => ({
nodeName: step.name,
assignees: step.handlers,
nodeOrder: index + 1
}))
// nodeList, flowId, title, userId
const request = {
...api.EDIT_APPROVAL_PROCESS,
params: {
nodeList: nodeList,
flowId: flowId,
title: newTitle,
userId: getUserId()
},
disableSuccessMsg: true
}
this.$request(request)
.asyncThen(() => {
//
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({
type: 'success',
message: '保存成功'
})
//
if (flowId) {
// detail flowId
if (!this.detail) {
this.detail = {}
}
if (!this.detail.flowId) {
this.detail.flowId = flowId
}
this.getApprovalSpet()
}
})
.asyncErrorCatch((err) => {
console.error('保存失败:', err)
this.$message({
type: 'error',
message: err?.message || '保存失败,请重试'
})
})
},
//
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() { 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 // ID
const templateRowId = this.getDetailTemplateId() const templateRowId = this.getDetailTemplateId()
if (!templateRowId) { if (!templateRowId) {
@ -2395,6 +2711,7 @@ export default {
.finally(() => { .finally(() => {
this.approvalSubmitting = false 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>
@ -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,16 +1384,34 @@ export default {
type: 'warning' type: 'warning'
}) })
.then(() => { .then(() => {
let request = null
if (canSend) {
// 使 flowId
const continueFlowId = this.approvalFlowIdFromUsers || flowId
if (!continueFlowId) {
this.$message.error('缺少流程ID无法继续发起审批')
return
}
request = {
...api.CONTINUE_REPORT_APPROVAL,
params: {
flowId: continueFlowId,
userId: getUserId()
},
disableSuccessMsg: true
}
} else {
const submitData = { const submitData = {
reportId: reportId, reportId: reportId,
flowId: flowId, flowId: flowId,
userId: getUserId() userId: getUserId()
} }
const request = { request = {
...api.ADD_REPORT, ...api.ADD_REPORT,
params: submitData, params: submitData,
disableSuccessMsg: true disableSuccessMsg: true
} }
}
this.launching = true this.launching = true
this.$request(request) this.$request(request)
@ -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,20 +1913,73 @@ 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.hasAnyEditChange()) {
this.isEditMode = false
this.$message({
type: 'info',
message: '未修改,无需保存'
})
return
}
// //
if (this.selectedFile) { if (this.selectedFile) {
try {
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('文件上传失败,请重试')
return
}
} }
const reportId = this.reportDetail.reportId || this.reportDetail.id const reportId = this.reportDetail.reportId || this.reportDetail.id
@ -1884,54 +1988,119 @@ export default {
return return
} }
// 稿 const includeApprovalInSave = !this.canResend
const shouldUpdateApprovalProcess = this.canResend
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
} }
this.saving = true
// watch/change
const currentSnap = this.buildEditSnapshot()
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 = { const request = {
...api.EDIT_REPORT, ...api.EDIT_REPORT,
params: params, params: params,
disableSuccessMsg: true disableSuccessMsg: true
} }
await this.$request(request).asyncThen(() => {})
}
if (needUpdateApprovalProcess) {
console.log('needUpdateApprovalProcess', needUpdateApprovalProcess)
await this.updateApprovalProcess()
}
this.saving = true
this.$request(request)
.asyncThen((resp) => {
this.saving = false
this.isEditMode = false this.isEditMode = false
// // + 稿/ handleResatrtLaunch
this.loadReportDetailFromApi(reportId, this.detail.flowId) const currentFlowId = this.detail.flowId || this.reportDetail.flowId
this.loadReportDetailFromApi(reportId, currentFlowId)
if (this.reportDetail.status === 'DRAFT' && currentFlowId) {
//
this.loadApprovalUsers(currentFlowId)
}
//
this.originalEditSnapshot = this.buildEditSnapshot()
this.$message({ this.$message({
type: 'success', type: 'success',
message: '保存成功' message: '保存成功'
}) })
// //
this.$emit('refresh') this.$emit('refresh', { keepOpen: true })
}) } catch (err) {
.asyncErrorCatch((err) => {
console.error('保存失败:', err) console.error('保存失败:', err)
this.$message.error(err?.message || '保存失败,请重试')
} finally {
this.saving = false this.saving = false
this.$message.error('保存失败,请重试') }
})
} }
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: '',