This commit is contained in:
2025-09-12 10:35:17 +08:00
parent 141299fcaa
commit 914c04c240
14 changed files with 388 additions and 1520 deletions

View File

@@ -88,8 +88,21 @@ public class BizSubModuleController extends BaseController
{
return AjaxResult.error("父模块不存在");
}
// 仅模块接取人可新增子模块
if (!String.valueOf(getUserId()).equals(module.getAssignee()))
// 仅模块接取人可新增子模块兼容历史assignee 可能存为 用户ID/用户名/昵称)
Long currentUserId = getUserId();
boolean isAssignee = false;
if (module.getAssignee() != null)
{
if (String.valueOf(currentUserId).equals(module.getAssignee())) {
isAssignee = true;
} else {
String username = getUsername();
if (username != null && username.equals(module.getAssignee())) {
isAssignee = true;
}
}
}
if (!isAssignee)
{
return AjaxResult.error("仅接取人可在该模块下新增子模块");
}
@@ -98,7 +111,8 @@ public class BizSubModuleController extends BaseController
{
return AjaxResult.error("父模块未处于进行中,无法新增子模块");
}
subModule.setStatus("0");
// 新增子模块默认进入进行中状态(与父模块接取人一致的执行中)
subModule.setStatus("1");
return toAjax(subService.insertBizSubModule(subModule));
}
@@ -114,7 +128,18 @@ public class BizSubModuleController extends BaseController
return AjaxResult.error("子模块不存在");
}
BizModule module = moduleService.selectBizModuleByModuleId(current.getModuleId());
if (!String.valueOf(getUserId()).equals(module.getAssignee()))
Long currentUserId = getUserId();
String username = getUsername();
boolean isAssignee = false;
if (module != null && module.getAssignee() != null)
{
if (String.valueOf(currentUserId).equals(module.getAssignee())) {
isAssignee = true;
} else if (username != null && username.equals(module.getAssignee())) {
isAssignee = true;
}
}
if (!isAssignee)
{
return AjaxResult.error("仅接取人可修改子模块");
}
@@ -135,7 +160,18 @@ public class BizSubModuleController extends BaseController
return AjaxResult.error("子模块不存在");
}
BizModule module = moduleService.selectBizModuleByModuleId(sub.getModuleId());
if (!String.valueOf(getUserId()).equals(module.getAssignee()))
Long currentUserId = getUserId();
String username = getUsername();
boolean isAssignee = false;
if (module != null && module.getAssignee() != null)
{
if (String.valueOf(currentUserId).equals(module.getAssignee())) {
isAssignee = true;
} else if (username != null && username.equals(module.getAssignee())) {
isAssignee = true;
}
}
if (!isAssignee)
{
return AjaxResult.error("仅接取人可删除子模块");
}

View File

@@ -7,6 +7,8 @@ import com.ruoyi.common.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.models.mapper.BizModuleMapper;
import com.ruoyi.models.mapper.BizSubModuleMapper;
import com.ruoyi.models.domain.BizSubModule;
import com.ruoyi.models.domain.BizModule;
import com.ruoyi.models.service.IBizModuleService;
import com.ruoyi.project.domain.BizProject;
@@ -31,6 +33,9 @@ public class BizModuleServiceImpl implements IBizModuleService {
@Autowired
private ISysUserService sysUserService;
@Autowired
private BizSubModuleMapper bizSubModuleMapper;
/**
* 查询模块
*
@@ -157,6 +162,7 @@ public class BizModuleServiceImpl implements IBizModuleService {
module.setAssignee(String.valueOf(userId));
}
module.setAssignTime(DateUtils.getNowDate());
// 避免重复接取:若已有相同 moduleId 的进行中记录,这里只更新而不新增
return updateBizModule(module);
}
@@ -173,7 +179,7 @@ public class BizModuleServiceImpl implements IBizModuleService {
throw new RuntimeException("模块不存在或状态异常");
}
if (!String.valueOf(userId).equals(module.getAssignee())) {
if (!isCurrentUserAssignee(module, userId)) {
throw new RuntimeException("您不是此模块的接取人");
}
@@ -206,10 +212,18 @@ public class BizModuleServiceImpl implements IBizModuleService {
throw new RuntimeException("模块不存在或状态异常");
}
if (!String.valueOf(userId).equals(module.getAssignee())) {
if (!isCurrentUserAssignee(module, userId)) {
throw new RuntimeException("您不是此模块的接取人");
}
// 约束父模块完成前需所有子模块均为已完成status = '2',且未被软删除)
List<BizSubModule> subModules = bizSubModuleMapper.selectByModuleId(moduleId);
boolean hasUnfinished = subModules.stream()
.anyMatch(sm -> sm != null && !"2".equals(sm.getStatus()));
if (hasUnfinished) {
throw new RuntimeException("仍有未完成的子模块,无法完成父模块");
}
module.setStatus("2"); // 已完成
module.setFinishTime(DateUtils.getNowDate());
int result = updateBizModule(module);
@@ -220,6 +234,35 @@ public class BizModuleServiceImpl implements IBizModuleService {
return result;
}
/**
* 判断当前用户是否为该模块的接取人兼容历史assignee 可能保存为 用户ID/用户名/昵称)
*/
private boolean isCurrentUserAssignee(BizModule module, Long userId) {
if (module == null) {
return false;
}
String assignee = module.getAssignee();
if (assignee == null) {
return false;
}
// 1) 与用户ID字符串相等
if (String.valueOf(userId).equals(assignee)) {
return true;
}
try {
SysUser u = sysUserService.selectUserById(userId);
if (u != null) {
if (u.getUserName() != null && u.getUserName().equals(assignee)) {
return true;
}
if (u.getNickName() != null && u.getNickName().equals(assignee)) {
return true;
}
}
} catch (Exception ignored) {}
return false;
}
/**
* 检查项目是否完成
* @param projectId 项目ID

View File

@@ -3,6 +3,7 @@ package com.ruoyi.models.service.impl;
import java.util.List;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.models.mapper.BizSubModuleMapper;
@@ -82,7 +83,9 @@ public class BizSubModuleServiceImpl implements IBizSubModuleService
{
throw new RuntimeException("父模块不存在");
}
if (!String.valueOf(userId).equals(module.getAssignee()))
String currentUsername = SecurityUtils.getUsername();
if (!(String.valueOf(userId).equals(module.getAssignee())
|| (module.getAssignee() != null && module.getAssignee().equals(currentUsername))))
{
throw new RuntimeException("仅父模块接取人可接取子模块");
}
@@ -107,7 +110,9 @@ public class BizSubModuleServiceImpl implements IBizSubModuleService
{
throw new RuntimeException("父模块不存在");
}
if (!String.valueOf(userId).equals(module.getAssignee()))
String currentUsername2 = SecurityUtils.getUsername();
if (!(String.valueOf(userId).equals(module.getAssignee())
|| (module.getAssignee() != null && module.getAssignee().equals(currentUsername2))))
{
throw new RuntimeException("仅父模块接取人可完成子模块");
}
@@ -117,6 +122,8 @@ public class BizSubModuleServiceImpl implements IBizSubModuleService
sub.setUpdateTime(DateUtils.getNowDate());
return updateBizSubModule(sub);
}
}

View File

@@ -164,24 +164,9 @@ public class BizDocController extends BaseController
Long currentUserId = getUserId();
if ("0".equals(kindType)) {
// 项目文档:项目管理员 或 项目参与者(该项目下任一模块的接取人/被指派人)可上传
// 项目文档:仅项目创建者可上传
BizProject project = bizProjectService.selectBizProjectByProjectId(projectId);
boolean isOwner = project != null && project.getOwnerId() != null && project.getOwnerId().equals(currentUserId);
boolean isParticipant = false;
if (!isOwner) {
// 参与者判断:当前用户是否在该项目下拥有被指派的模块
com.ruoyi.models.domain.BizModule query = new com.ruoyi.models.domain.BizModule();
query.setProjectId(projectId);
java.util.List<com.ruoyi.models.domain.BizModule> modules = bizModuleService.selectBizModuleList(query);
if (modules != null) {
for (com.ruoyi.models.domain.BizModule m : modules) {
if (m.getAssignee() != null && (m.getAssignee().equals(String.valueOf(currentUserId)) || m.getAssignee().equals(getUsername()))) {
isParticipant = true; break;
}
}
}
}
if (!isOwner && !isParticipant) {
if (project == null || project.getOwnerId() == null || !project.getOwnerId().equals(currentUserId)) {
return AjaxResult.error("无权上传项目文档");
}
} else if ("1".equals(kindType)) {

View File

@@ -46,7 +46,9 @@ public class BizDocServiceImpl implements IBizDocService
// - 项目文档:当前用户为项目所有者
// - 模块文档:当前用户为该模块被指派人
Long currentUserId = SecurityUtils.getUserId();
String currentUsername = SecurityUtils.getUsername();
bizDoc.getParams().put("currentUserId", currentUserId);
bizDoc.getParams().put("currentUsername", currentUsername);
return bizDocMapper.selectBizDocList(bizDoc);
}

View File

@@ -56,12 +56,12 @@ public class SysUserController extends BaseController {
/**
* 获取用户列表
*/
// 平台管理员独占用户管理权限
@PreAuthorize("@ss.hasRole('platform_admin') and @ss.hasPermi('system:user:list')")
// 用户查询:平台管理员与项目管理员均可用于业务指派选择(不暴露敏感信息)
@PreAuthorize("(@ss.hasRole('platform_admin') or @ss.hasRole('project_admin')) and @ss.hasPermi('system:user:list')")
@GetMapping("/list")
public TableDataInfo list(SysUser user) {
startPage();
// 平台管理员不受数据范围限制;其他无权访问已由 @PreAuthorize 拦截
// 项目管理员仅用于指派下拉选择:读取基本字段
List<SysUser> list = userService.selectUserListAll(user);
return getDataTable(list);
}
@@ -195,7 +195,7 @@ public class SysUserController extends BaseController {
/**
* 根据用户编号获取授权角色
*/
@PreAuthorize("@ss.hasPermi('system:user:query')")
@PreAuthorize("@ss.hasPermi('system:user:query') or @ss.hasRole('project_admin')")
@GetMapping("/authRole/{userId}")
public AjaxResult authRole(@PathVariable("userId") Long userId) {
AjaxResult ajax = AjaxResult.success();

View File

@@ -154,7 +154,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</update>
<select id="selectAssignedModules" parameterType="Long" resultMap="BizModuleResult">
select m.module_id,
select DISTINCT m.module_id,
m.project_id,
m.module_name,
m.status,

View File

@@ -53,23 +53,42 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="docName != null and docName != ''"> and d.file_name like concat('%', #{docName}, '%')</if>
<if test="docPath != null and docPath != ''"> and d.file_url = #{docPath}</if>
and d.del_flag = '0'
<!-- 权限控制:
- 项目文档(kind_type='0')项目创建者可见
- 模块文档(kind_type='1')仅该模块被指派用户可见
<!-- 权限控制(最终口径)
- 项目文档(kind_type='0'):项目创建者可见全部;普通用户仅能看到自己上传的项目文档
- 模块文档(kind_type='1')项目创建者可见全部;普通用户可见
a) 自己上传的模块文档
b) 自己是该模块接取人assignee = 当前用户名 或 = 当前用户ID
c) 自己被指派designated_user = 当前用户ID
-->
<if test="params != null and params.currentUserId != null">
and (
-- 项目文档:仅项目创建者
(kind_type = '0' and exists (
select 1 from biz_project p
where p.project_id = d.project_id
and p.owner_id = #{params.currentUserId}
-- 项目文档:仅项目创建者可见 或 自己上传的项目文档
(kind_type = '0' and (
exists (
select 1 from biz_project p
where p.project_id = d.project_id
and p.owner_id = #{params.currentUserId}
)
or d.upload_by = #{params.currentUsername}
))
-- 模块文档:仅该模块指派用户
or (kind_type = '1' and exists (
select 1 from biz_module m
where m.module_id = d.module_id
and m.designated_user = #{params.currentUserId}
-- 模块文档:项目创建者可见全部;普通用户可见与自己强相关的
or (kind_type = '1' and (
exists (
select 1 from biz_project p
where p.project_id = d.project_id
and p.owner_id = #{params.currentUserId}
)
or d.upload_by = #{params.currentUsername}
or exists (
select 1 from biz_module m
where m.module_id = d.module_id
and m.del_flag = '0'
and (
m.designated_user = #{params.currentUserId}
or CAST(m.assignee AS CHAR) = CAST(#{params.currentUserId} AS CHAR)
or m.assignee = #{params.currentUsername}
)
)
))
)
</if>