From ae928692d3029fcc0bfbdf12295637fd636feff6 Mon Sep 17 00:00:00 2001 From: jhd <1684074631@qq.com> Date: Wed, 8 Jul 2026 11:03:50 +0800 Subject: [PATCH] =?UTF-8?q?feat(erp):=20=E5=AE=9E=E7=8E=B0=E8=AF=B7?= =?UTF-8?q?=E8=B4=AD=E5=8D=95=E5=8F=8C=E5=B1=82=E5=AE=A1=E6=89=B9=E6=B5=81?= =?UTF-8?q?=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在提交审批接口中新增指定一审审批人的参数 - 实现一审和二审的两级审批逻辑,一审为管理层审批,二审固定为陈清鑫 - 添加审批人身份验证,确保只有指定审批人才能进行审批操作 - 在前端界面中增加提交审批选择审批人弹窗 - 更新请购单状态显示,新增一审通过待二审状态(状态值6) - 添加审批进度展示,显示一审人和二审人的审批情况 - 实现基于角色的审批权限控制,管理层可进行一审,特定人员可进行二审 - 新增查询审批人列表的API接口,支持按角色筛选审批人 - 优化审批按钮显示逻辑,根据不同状态和用户身份显示相应操作按钮 --- .../controller/system/SysUserController.java | 18 ++++ .../ErpPurchaseRequisitionController.java | 8 +- .../IErpPurchaseRequisitionService.java | 2 +- .../ErpPurchaseRequisitionServiceImpl.java | 53 ++++++++-- .../klp/system/service/ISysUserService.java | 8 ++ .../service/impl/SysUserServiceImpl.java | 16 +++ klp-ui/src/api/erp/purchaseRequisition.js | 15 ++- .../views/erp/purchaseRequisition/index.vue | 97 ++++++++++++++++--- 8 files changed, 190 insertions(+), 27 deletions(-) diff --git a/klp-admin/src/main/java/com/klp/web/controller/system/SysUserController.java b/klp-admin/src/main/java/com/klp/web/controller/system/SysUserController.java index 9709d53cc..4eb256263 100644 --- a/klp-admin/src/main/java/com/klp/web/controller/system/SysUserController.java +++ b/klp-admin/src/main/java/com/klp/web/controller/system/SysUserController.java @@ -74,6 +74,24 @@ public class SysUserController extends BaseController { return userService.selectPageUserList(user, pageQuery); } + /** + * 根据角色标识查询用户列表(用于选择审批人等场景) + */ + @SaCheckLogin + @GetMapping("/selectUserByRole/{roleKey}") + public R> selectUserByRoleKey(@PathVariable String roleKey) { + return R.ok(userService.selectUserByRoleKey(roleKey)); + } + + /** + * 查询请购审批人列表(角色标识 glc) + */ + @SaCheckLogin + @GetMapping("/approverUsers/list") + public R> approverUsers() { + return R.ok(userService.selectUserByRoleKey("glc")); + } + /** * 导出用户列表 */ diff --git a/klp-erp/src/main/java/com/klp/erp/controller/ErpPurchaseRequisitionController.java b/klp-erp/src/main/java/com/klp/erp/controller/ErpPurchaseRequisitionController.java index ce26fa03a..991173e3e 100644 --- a/klp-erp/src/main/java/com/klp/erp/controller/ErpPurchaseRequisitionController.java +++ b/klp-erp/src/main/java/com/klp/erp/controller/ErpPurchaseRequisitionController.java @@ -85,13 +85,14 @@ public class ErpPurchaseRequisitionController extends BaseController { @Log(title = "请购及采购单", businessType = BusinessType.UPDATE) @SaCheckPermission("erp:purchaseRequisition:approve") @PutMapping("/{reqId}/submit") - public R submitApproval(@NotNull(message = "主键不能为空") @PathVariable Long reqId) { - return toAjax(iErpPurchaseRequisitionService.submitApproval(reqId)); + public R submitApproval(@NotNull(message = "主键不能为空") @PathVariable Long reqId, + @NotNull(message = "审批人不能为空") @RequestParam Long firstApproverId, + @NotEmpty(message = "审批人姓名不能为空") @RequestParam String firstApproverName) { + return toAjax(iErpPurchaseRequisitionService.submitApproval(reqId, firstApproverId, firstApproverName)); } /** 审批通过(审批中 → 已通过) */ @Log(title = "请购及采购单", businessType = BusinessType.UPDATE) - @SaCheckPermission("erp:purchaseRequisition:approve") @PutMapping("/{reqId}/approve") public R approve(@NotNull(message = "主键不能为空") @PathVariable Long reqId) { return toAjax(iErpPurchaseRequisitionService.approve(reqId)); @@ -99,7 +100,6 @@ public class ErpPurchaseRequisitionController extends BaseController { /** 驳回(审批中 → 已驳回) */ @Log(title = "请购及采购单", businessType = BusinessType.UPDATE) - @SaCheckPermission("erp:purchaseRequisition:approve") @PutMapping("/{reqId}/reject") public R reject(@NotNull(message = "主键不能为空") @PathVariable Long reqId) { return toAjax(iErpPurchaseRequisitionService.reject(reqId)); diff --git a/klp-erp/src/main/java/com/klp/erp/service/IErpPurchaseRequisitionService.java b/klp-erp/src/main/java/com/klp/erp/service/IErpPurchaseRequisitionService.java index 1049f5f0c..362673704 100644 --- a/klp-erp/src/main/java/com/klp/erp/service/IErpPurchaseRequisitionService.java +++ b/klp-erp/src/main/java/com/klp/erp/service/IErpPurchaseRequisitionService.java @@ -35,7 +35,7 @@ public interface IErpPurchaseRequisitionService { Boolean deleteWithValidByIds(Collection ids, Boolean isValid); /** 提交审批(草稿 → 审批中) */ - Boolean submitApproval(Long reqId); + Boolean submitApproval(Long reqId, Long firstApproverId, String firstApproverName); /** 审批通过(审批中 → 已通过) */ Boolean approve(Long reqId); diff --git a/klp-erp/src/main/java/com/klp/erp/service/impl/ErpPurchaseRequisitionServiceImpl.java b/klp-erp/src/main/java/com/klp/erp/service/impl/ErpPurchaseRequisitionServiceImpl.java index ccf88c09b..187e748fa 100644 --- a/klp-erp/src/main/java/com/klp/erp/service/impl/ErpPurchaseRequisitionServiceImpl.java +++ b/klp-erp/src/main/java/com/klp/erp/service/impl/ErpPurchaseRequisitionServiceImpl.java @@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.klp.common.core.domain.PageQuery; import com.klp.common.core.page.TableDataInfo; +import com.klp.common.helper.LoginHelper; import com.klp.common.utils.StringUtils; import com.klp.erp.domain.ErpPurchaseRequisition; import com.klp.erp.domain.ErpPurchaseRequisitionItem; @@ -135,13 +136,14 @@ public class ErpPurchaseRequisitionServiceImpl implements IErpPurchaseRequisitio @Override @Transactional(rollbackFor = Exception.class) - public Boolean submitApproval(Long reqId) { + public Boolean submitApproval(Long reqId, Long firstApproverId, String firstApproverName) { ErpPurchaseRequisition entity = baseMapper.selectById(reqId); if (entity == null) return false; if (!"0".equals(entity.getFormStatus())) { throw new RuntimeException("仅草稿状态的请购单可提交审批"); } entity.setFormStatus("1"); + entity.setSignPurchaseHandler(firstApproverName); return baseMapper.updateById(entity) > 0; } @@ -150,11 +152,29 @@ public class ErpPurchaseRequisitionServiceImpl implements IErpPurchaseRequisitio public Boolean approve(Long reqId) { ErpPurchaseRequisition entity = baseMapper.selectById(reqId); if (entity == null) return false; - if (!"1".equals(entity.getFormStatus())) { - throw new RuntimeException("仅审批中状态的请购单可通过"); + String currentNickName = LoginHelper.getNickName(); + + if ("1".equals(entity.getFormStatus())) { + // 一审:校验是否指定的一审人 + String approverName = entity.getSignPurchaseHandler(); + if (approverName == null || !approverName.equals(currentNickName)) { + throw new RuntimeException("您不是该请购单指定的审批人"); + } + entity.setFormStatus("6"); + return baseMapper.updateById(entity) > 0; + + } else if ("6".equals(entity.getFormStatus())) { + // 二审:校验是否是陈清鑫 + if (!"陈清鑫".equals(currentNickName)) { + throw new RuntimeException("二审仅限指定审批人操作"); + } + entity.setFormStatus("2"); + entity.setSignRequestGm("陈清鑫"); + return baseMapper.updateById(entity) > 0; + + } else { + throw new RuntimeException("当前状态不允许审批通过"); } - entity.setFormStatus("2"); - return baseMapper.updateById(entity) > 0; } @Override @@ -162,11 +182,28 @@ public class ErpPurchaseRequisitionServiceImpl implements IErpPurchaseRequisitio public Boolean reject(Long reqId) { ErpPurchaseRequisition entity = baseMapper.selectById(reqId); if (entity == null) return false; - if (!"1".equals(entity.getFormStatus())) { + String currentNickName = LoginHelper.getNickName(); + + if ("1".equals(entity.getFormStatus())) { + // 一审期间驳回 + String approverName = entity.getSignPurchaseHandler(); + if (approverName == null || !approverName.equals(currentNickName)) { + throw new RuntimeException("您不是该请购单指定的审批人"); + } + entity.setFormStatus("5"); + return baseMapper.updateById(entity) > 0; + + } else if ("6".equals(entity.getFormStatus())) { + // 二审期间驳回:仅陈清鑫可驳回 + if (!"陈清鑫".equals(currentNickName)) { + throw new RuntimeException("二审仅限指定审批人操作"); + } + entity.setFormStatus("5"); + return baseMapper.updateById(entity) > 0; + + } else { throw new RuntimeException("仅审批中状态的请购单可驳回"); } - entity.setFormStatus("5"); - return baseMapper.updateById(entity) > 0; } } diff --git a/klp-system/src/main/java/com/klp/system/service/ISysUserService.java b/klp-system/src/main/java/com/klp/system/service/ISysUserService.java index 9eefe5473..63505c883 100644 --- a/klp-system/src/main/java/com/klp/system/service/ISysUserService.java +++ b/klp-system/src/main/java/com/klp/system/service/ISysUserService.java @@ -44,6 +44,14 @@ public interface ISysUserService { SysUser selectUserByUserName(String userName); Map selectNickNameMapByUserNames(List userNames); + /** + * 根据角色标识查询用户列表(用于选择审批人等场景) + * + * @param roleKey 角色标识 + * @return 用户列表 + */ + List selectUserByRoleKey(String roleKey); + /** * 通过手机号查询用户 * diff --git a/klp-system/src/main/java/com/klp/system/service/impl/SysUserServiceImpl.java b/klp-system/src/main/java/com/klp/system/service/impl/SysUserServiceImpl.java index f3909cfe5..b803182ec 100644 --- a/klp-system/src/main/java/com/klp/system/service/impl/SysUserServiceImpl.java +++ b/klp-system/src/main/java/com/klp/system/service/impl/SysUserServiceImpl.java @@ -34,6 +34,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.HashMap; @@ -168,6 +169,21 @@ public class SysUserServiceImpl implements ISysUserService, UserService { return nickMap; } + @Override + public List selectUserByRoleKey(String roleKey) { + // 查询角色 + SysRole role = roleMapper.selectOne(Wrappers.lambdaQuery() + .eq(SysRole::getRoleKey, roleKey)); + if (role == null) return Collections.emptyList(); + // 查询拥有该角色的用户ID列表 + List userIds = userRoleMapper.selectUserIdsByRoleId(role.getRoleId()); + if (CollUtil.isEmpty(userIds)) return Collections.emptyList(); + // 查询用户详情 + return baseMapper.selectUserList(Wrappers.query() + .in("u.user_id", userIds) + .eq("u.del_flag", UserConstants.USER_NORMAL)); + } + /** * 通过手机号查询用户 * diff --git a/klp-ui/src/api/erp/purchaseRequisition.js b/klp-ui/src/api/erp/purchaseRequisition.js index a3e88392d..add217ac9 100644 --- a/klp-ui/src/api/erp/purchaseRequisition.js +++ b/klp-ui/src/api/erp/purchaseRequisition.js @@ -35,11 +35,12 @@ export function updatePurchaseRequisition(data) { }) } -// 提交审批 -export function submitApproval(reqId) { +// 提交审批(指定一审人) +export function submitApproval(reqId, firstApproverId, firstApproverName) { return request({ url: '/erp/purchaseRequisition/' + reqId + '/submit', - method: 'put' + method: 'put', + params: { firstApproverId, firstApproverName } }) } @@ -76,3 +77,11 @@ export function exportPurchaseRequisition(query) { responseType: 'blob' }) } + +// 查询请购审批人列表(角色标识由后端配置) +export function selectApproverUsers() { + return request({ + url: '/system/user/approverUsers/list', + method: 'get' + }) +} diff --git a/klp-ui/src/views/erp/purchaseRequisition/index.vue b/klp-ui/src/views/erp/purchaseRequisition/index.vue index 0a80ec130..b0ee90e13 100644 --- a/klp-ui/src/views/erp/purchaseRequisition/index.vue +++ b/klp-ui/src/views/erp/purchaseRequisition/index.vue @@ -15,6 +15,7 @@ + @@ -62,11 +63,12 @@ @@ -225,6 +227,7 @@ + @@ -357,9 +360,17 @@
{{ viewForm.remark || '—' }}
+ + +
审批进度
+
+
{{ viewForm.signPurchaseHandler || '待审批' }}
+
{{ viewForm.signRequestGm || '待审批' }}
+
@@ -395,6 +406,26 @@ + + +
+ + + + + + +
+ 请选择管理层审批人进行一审 +
+
+
+ +
+
@@ -554,7 +585,8 @@ import { delPurchaseRequisition, submitApproval, approvePurchase, - rejectPurchase + rejectPurchase, + selectApproverUsers } from '@/api/erp/purchaseRequisition' export default { @@ -589,9 +621,30 @@ export default { approvalReq: {}, approvalRemark: '', approvalLoading: false, + // 提交审批选人 + submitDialogVisible: false, + submitLoading: false, + approverUsers: [], + selectedApproverId: null, + submittingReqId: null, rules: {} } }, + computed: { + currentNickName() { + return this.$store.getters.nickName || '' + }, + canView() { + const permissions = this.$store.getters.permissions || [] + const roles = this.$store.getters.roles || [] + const nickName = this.$store.getters.nickName || '' + // 有查看权限 或 有glc角色 或是陈清鑫 + if (permissions.some(p => p === '*:*:*' || p === 'erp:purchaseRequisition:query')) return true + if (roles.some(r => r === 'admin' || r === 'glc')) return true + if (nickName === '陈清鑫') return true + return false + } + }, created() { this.getList() }, @@ -674,14 +727,35 @@ export default { this.viewForm = res.data || {} }) }, - // 提交审批(单个操作列) + // 提交审批 — 打开选人弹窗 handleSubmitOne(row) { - this.$modal.confirm('确认提交该请购单进行审批?').then(() => { - return submitApproval(row.reqId) - }).then(() => { + this.submittingReqId = row.reqId + this.selectedApproverId = null + this.submitLoading = true + this.submitDialogVisible = true + // 加载管理层审批人(角色标识由后端 erp.approver.role-key 配置) + selectApproverUsers().then(res => { + this.approverUsers = res.data || [] + }).catch(() => { + this.approverUsers = [] + }).finally(() => { + this.submitLoading = false + }) + }, + // 确认提交审批 + doSubmitApproval() { + if (!this.selectedApproverId) return + this.submitLoading = true + // 获取选中的审批人昵称 + const user = this.approverUsers.find(u => u.userId === this.selectedApproverId) + const nickName = user ? user.nickName : '' + submitApproval(this.submittingReqId, this.selectedApproverId, nickName).then(() => { this.$modal.msgSuccess('已提交审批') + this.submitDialogVisible = false this.getList() - }).catch(() => {}) + }).catch(() => {}).finally(() => { + this.submitLoading = false + }) }, // 打开审批弹窗 openApproval(row) { @@ -804,11 +878,11 @@ export default { }, // 状态 statusText(s) { - const map = { '0': '请购草稿', '1': '审批中', '2': '已通过', '3': '采购处理中', '4': '已完成', '5': '已驳回' } + const map = { '0': '请购草稿', '1': '审批中', '6': '一审通过待二审', '2': '已通过', '3': '采购处理中', '4': '已完成', '5': '已驳回' } return map[s] || s || '—' }, statusType(s) { - const map = { '0': 'info', '1': 'warning', '2': 'success', '3': 'warning', '4': 'success', '5': 'danger' } + const map = { '0': 'info', '1': 'warning', '6': 'primary', '2': 'success', '3': 'warning', '4': 'success', '5': 'danger' } return map[s] || 'info' }, // 品检条件 — 数字代码 -> 可读描述(查看弹窗用) @@ -1047,6 +1121,7 @@ $sub: #909399; &.s3 { color: #d6a256; border-color: #ecd4a6; background: #fdf6ec; } &.s4 { color: $accent; border-color: #b9d2e6; background: #eef3f8; } &.s5 { color: #c45656; border-color: #e6c4c4; background: #fbf0f0; } + &.s6 { color: #5b8db8; border-color: #b9d2e6; background: #eef3f8; } } }