feat(审批流程): 优化审批逻辑并添加抄送功能

重构审批条件判断逻辑,统一使用canApprove和canWithdraw计算属性控制按钮显示
为所有审批详情页添加撤回按钮功能
在审批列表页新增抄送功能,支持多选抄送人
调整提交成功后的跳转路由为/hrm/apply
仅在approverMode为template时设置tplId参数
This commit is contained in:
砂糖
2026-01-05 11:42:53 +08:00
parent a0f03c374a
commit 78b5af5143
10 changed files with 141 additions and 36 deletions

View File

@@ -295,11 +295,11 @@ export default {
],
approverRuleOptions: [
{ label: '固定人员(选择)', value: 'fixed_user' },
{ label: '角色(选择/输入编码)', value: 'role' },
{ label: '岗位(选择)', value: 'position' },
{ label: '部门负责人(自动)', value: 'dept_leader' },
{ label: '发起人本人(自动)', value: 'initiator' },
{ label: '表单字段指定(字段名)', value: 'form_field' }
// { label: '角色(选择/输入编码)', value: 'role' },
// { label: '岗位(选择)', value: 'position' },
// { label: '部门负责人(自动)', value: 'dept_leader' },
// { label: '发起人本人(自动)', value: 'initiator' },
// { label: '表单字段指定(字段名)', value: 'form_field' }
],
rules: {
tplId: [{ required: true, message: '请选择模板', trigger: 'change' }],

View File

@@ -85,6 +85,7 @@
<el-button size="mini" type="text" @click="handleApprove(scope.row)">通过</el-button>
<el-button size="mini" type="text" @click="handleReject(scope.row)">驳回</el-button>
<el-button size="mini" type="text" @click="handleTransfer(scope.row)">转发</el-button>
<el-button size="mini" type="text" @click="handleCc(scope.row)">抄送</el-button>
</template>
</el-table-column>
</el-table>
@@ -114,20 +115,55 @@
</div>
</el-dialog>
<!-- 抄送弹窗 -->
<el-dialog
title="抄送"
:visible.sync="ccDialogVisible"
width="720px"
append-to-body
>
<el-form :model="ccForm" label-width="90px" size="small">
<el-form-item label="抄送人" required>
<el-button size="mini" type="primary" plain icon="el-icon-user" @click="openUserMultiSelect">选择抄送人</el-button>
<div class="selected-users" v-if="ccForm.selectedUsers && ccForm.selectedUsers.length">
<el-tag
v-for="u in ccForm.selectedUsers"
:key="u.userId"
size="mini"
closable
@close="removeCcUser(u)"
>
{{ u.nickName || u.userName || ('ID:' + u.userId) }}
</el-tag>
</div>
<div v-else class="muted" style="margin-top:6px;">未选择抄送人</div>
</el-form-item>
<el-form-item label="说明">
<el-input v-model="ccForm.remark" type="textarea" :rows="3" placeholder="可选:抄送说明" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="ccDialogVisible = false">取消</el-button>
<el-button type="primary" :loading="actionSubmitting" @click="submitCc">确定抄送</el-button>
</div>
</el-dialog>
<!-- 转发功能复用 UserSelect 组件 -->
<UserSelect ref="userSelect" @onSelected="onManualApproverConfirmed" />
<UserMultiSelect ref="userMultiSelect" @onSelected="onCcUsersSelected" />
</div>
</template>
<script>
import { listTodoFlowTask, approveFlowTask, rejectFlowTask, transferFlowTask } from '@/api/hrm/flow'
import { listTodoFlowTask, approveFlowTask, rejectFlowTask, transferFlowTask, ccFlowTask } from '@/api/hrm/flow'
import { listEmployee } from '@/api/hrm'
import UserSelect from '@/components/userSelect/single.vue'
import UserMultiSelect from '@/components/userSelect/multi.vue'
export default {
name: 'HrmApproval',
components: { UserSelect },
components: { UserSelect, UserMultiSelect },
data() {
return {
employees: [],
@@ -148,7 +184,13 @@ export default {
remark: ''
},
actionSubmitting: false,
transferTask: null
transferTask: null,
ccTask: null,
ccForm: {
selectedUsers: []
},
ccDialogVisible: false,
actionSubmitting: false
}
},
created() {
@@ -330,7 +372,34 @@ export default {
this.$message.success('已转发')
this.transferTask = null
this.loadTodoList()
}
},
handleCc(task) {
this.ccTask = task
// this.$refs.userMultiSelect.open()
this.ccDialogVisible = true
},
openUserMultiSelect() { this.$refs.userMultiSelect.open() },
onCcUsersSelected(users) { this.ccForm.selectedUsers = users || [] },
removeCcUser(user) { this.ccForm.selectedUsers = this.ccForm.selectedUsers.filter(u => u.userId !== user.userId) },
submitCc() {
console.log(this.ccForm.selectedUsers, '抄送')
const userIds = this.ccForm.selectedUsers.map(u => u.userId)
if (!this.ccTask || userIds.length === 0) return this.$message.warning('请选择至少一个抄送人')
const fromUserId = this.$store?.state?.user?.id
ccFlowTask({
instId: this.ccTask.instId,
bizType: this.ccTask.bizType,
bizId: this.ccTask.bizId,
nodeId: this.ccTask.nodeId,
nodeName: `节点#${this.ccTask.nodeId}`,
fromUserId,
ccUserIds: userIds,
readFlag: 0,
remark: this.ccForm.remark || '手动抄送'
})
.then(() => { this.$message.success('抄送成功'); this.ccDialogVisible = false })
.catch(() => { this.$message.error('抄送失败') })
},
}
}
</script>

View File

@@ -381,13 +381,16 @@ export default {
const payload = {
...this.form,
status: 'pending',
tplId: this.tplId,
// tplId: this.tplId,
manualAssigneeUserId: this.assigneeUserId
}
if (this.approverMode === 'template') {
payload.tplId = this.tplId
}
try {
await addLeaveReq(payload)
this.$message.success('提交成功')
this.$router.push('/hrm/requests')
this.$router.push('/hrm/apply')
} finally {
this.submitting = false
}

View File

@@ -9,7 +9,7 @@
<!-- 审批操作按钮 -->
<el-button
v-if="currentTask"
v-if="canApprove"
type="success"
size="mini"
:loading="actionLoading"
@@ -18,7 +18,7 @@
通过
</el-button>
<el-button
v-if="currentTask"
v-if="canApprove"
type="danger"
size="mini"
:loading="actionLoading"
@@ -26,14 +26,14 @@
>
驳回
</el-button>
<!-- <el-button
<el-button
v-if="canWithdraw"
size="mini"
:loading="actionLoading"
@click="handleWithdraw"
>
撤回
</el-button> -->
</el-button>
</div>
</div>
@@ -233,6 +233,11 @@ export default {
canWithdraw() {
// 只有待审批状态且是当前用户提交的才能撤回
return this.detail.status === 'pending' && this.detail.createBy === this.$store.getters.name
},
canApprove() {
// 只有待审批状态且是当前用户待审批的才能审批
console.log(this.currentTask, this.$store.getters.name, this.$store.getters.id)
return this.detail.status === 'pending' && (this.currentTask?.assigneeUserName === this.$store.getters.name || this.currentTask?.assigneeUserId === this.$store.getters.id)
}
},
created() {

View File

@@ -342,12 +342,15 @@ export default {
accessoryReceiptIds: this.normalizeOssIds(this.form.accessoryReceiptIds),
remark: this.form.remark,
status: 'pending',
tplId: this.tplId,
// tplId: this.tplId,
manualAssigneeUserId: this.assigneeUserId
}
if (this.approverMode === 'template') {
payload.tplId = this.tplId
}
await addReimburseReq(payload)
this.$message.success('提交成功')
this.$router.push('/hrm/requests')
this.$router.push('/hrm/apply')
} catch (err) {
// no-op
} finally {

View File

@@ -9,7 +9,7 @@
<!-- 审批操作按钮 -->
<el-button
v-if="currentTask"
v-if="canApprove"
type="success"
size="mini"
:loading="actionLoading"
@@ -18,7 +18,7 @@
通过
</el-button>
<el-button
v-if="currentTask"
v-if="canApprove"
type="danger"
size="mini"
:loading="actionLoading"
@@ -26,14 +26,14 @@
>
驳回
</el-button>
<!-- <el-button
<el-button
v-if="canWithdraw"
size="mini"
:loading="actionLoading"
@click="handleWithdraw"
>
撤回
</el-button> -->
</el-button>
</div>
</div>
@@ -236,8 +236,13 @@ export default {
}
return empId ? `员工ID:${empId}` : '-'
},
canApprove() {
// 只有待审批状态且是当前用户待审批的才能审批
console.log(this.currentTask, this.$store.getters.name, this.$store.getters.id)
return this.detail.status === 'pending' && (this.currentTask?.assigneeUserName === this.$store.getters.name || this.currentTask?.assigneeUserId === this.$store.getters.id)
},
canWithdraw() {
return this.detail.status === 'pending' && this.detail.createBy === this.$store.getters.userId
return this.detail.status === 'pending' && this.detail.createBy === this.$store.getters.name
}
},
created() {

View File

@@ -386,13 +386,15 @@ export default {
urgentLevel: this.form.urgentLevel,
remark,
status: 'pending',
tplId: this.tplId,
// tplId: this.tplId,
manualAssigneeUserId: this.normalizeUserId(this.assigneeUserId)
}
if (this.approverMode === 'template') {
payload.tplId = this.tplId
}
await addSealReq(payload)
this.$message.success('提交成功')
this.$router.push('/hrm/requests')
this.$router.push('/hrm/apply')
} finally {
this.submitting = false
}

View File

@@ -244,9 +244,9 @@
<div v-if="currentTask" class="btn-row">
<el-input v-model="actionRemark" type="textarea" :rows="3" placeholder="填写审批意见(可选)" />
<div class="btn-row mt10">
<el-button type="success" :loading="actionSubmitting" @click="submitTaskAction('approve')">通过</el-button>
<el-button type="danger" :loading="actionSubmitting" @click="submitTaskAction('reject')">驳回</el-button>
<el-button :loading="actionSubmitting" @click="submitTaskAction('withdraw')">撤回</el-button>
<el-button type="success" v-if="canApprove" :loading="actionSubmitting" @click="submitTaskAction('approve')">通过</el-button>
<el-button type="danger" v-if="canApprove" :loading="actionSubmitting" @click="submitTaskAction('reject')">驳回</el-button>
<el-button v-if="canWithdraw" :loading="actionSubmitting" @click="submitTaskAction('withdraw')">撤回</el-button>
</div>
</div>
<div v-else class="empty">当前无待办任务可能已处理完成或你不是当前审批人</div>
@@ -361,10 +361,18 @@ export default {
}
return empId ? `员工ID:${empId}` : '-'
},
canApprove() {
// 只有待审批状态且是当前用户待审批的才能审批
return this.seal.status === 'pending' && (this.currentTask?.assigneeUserName === this.$store.getters.name || this.currentTask?.assigneeUserId === this.$store.getters.id)
},
canStamp() {
// 审批通过后,且尚未生成回执时,可以盖章
return this.seal.status === 'approved' && !this.seal.receiptFileIds && this.targetPdfFile && this.attachmentList.length > 0
}
},
canWithdraw() {
console.log(this.seal.createBy, this.$store.getters.name)
return this.seal.status === 'running' && this.seal.createBy === this.$store.getters.name
},
},
created() {
this.loadEmployees()

View File

@@ -408,13 +408,16 @@ export default {
bankName: this.form.bankName,
bankAccount: this.form.bankAccount,
remark: this.form.remark,
tplId: this.tplId,
// tplId: this.tplId,
manualAssigneeUserId: this.assigneeUserId
}
if (this.approverMode === 'template') {
payload.tplId = this.tplId
}
try {
await addTravelReq(payload)
this.$message.success('提交成功')
this.$router.push('/hrm/requests')
this.$router.push('/hrm/apply')
} catch (e) {
this.$message.error('提交失败,请稍后重试')
} finally {

View File

@@ -160,9 +160,9 @@
<div v-if="currentTask" class="btn-row">
<el-input v-model="actionRemark" type="textarea" :rows="3" placeholder="填写审批意见(可选)" />
<div class="btn-row mt10">
<el-button type="success" :loading="actionSubmitting" @click="submitTaskAction('approve')">通过</el-button>
<el-button type="danger" :loading="actionSubmitting" @click="submitTaskAction('reject')">驳回</el-button>
<el-button :loading="actionSubmitting" @click="submitTaskAction('withdraw')">撤回</el-button>
<el-button type="success" v-if="canApprove" :loading="actionSubmitting" @click="submitTaskAction('approve')">通过</el-button>
<el-button type="danger" v-if="canApprove" :loading="actionSubmitting" @click="submitTaskAction('reject')">驳回</el-button>
<el-button v-if="canWithdraw" :loading="actionSubmitting" @click="submitTaskAction('withdraw')">撤回</el-button>
</div>
</div>
<div v-else class="empty">当前无待办任务可能已处理完成或你不是当前审批人</div>
@@ -225,7 +225,14 @@ export default {
return `${name || '员工'}${no}${dept}`.trim()
}
return empId ? `员工ID:${empId}` : '-'
}
},
canApprove() {
// 只有待审批状态且是当前用户待审批的才能审批
return this.travel.status === 'pending' && (this.currentTask?.assigneeUserName === this.$store.getters.name || this.currentTask?.assigneeUserId === this.$store.getters.id)
},
canWithdraw() {
return this.travel.status === 'pending' && this.travel.createBy === this.$store.getters.name
},
},
created() {
this.loadEmployees()