新需求更新 同步更新

This commit is contained in:
supernijia
2026-08-06 01:11:54 +08:00
parent 9048bbb7f8
commit 28e7fce11c
112 changed files with 7739 additions and 637 deletions
@@ -128,6 +128,23 @@ public class PermissionMenuController {
return ApiResponse.success("视频任务权限已更新", grantedCount);
}
@GetMapping("/shop-data-crawl-task-permissions")
@Operation(summary = "查询店铺数据任务数据权限用户")
public ApiResponse<List<ImageVideoDataPermissionUserVo>> listShopDataCrawlDataPermissionUsers(
HttpServletRequest request) {
return ApiResponse.success(permissionMenuService.listShopDataCrawlDataPermissionUsers(requireAdmin(request)));
}
@PutMapping("/shop-data-crawl-task-permissions")
@Operation(summary = "更新店铺数据任务数据权限用户")
public ApiResponse<Integer> updateShopDataCrawlDataPermissionUsers(
HttpServletRequest request,
@RequestBody(required = false) ImageVideoDataPermissionUpdateRequest body) {
int grantedCount = permissionMenuService.updateShopDataCrawlDataPermissionUsers(
requireAdmin(request), body == null ? List.of() : body.getUserIds());
return ApiResponse.success("店铺数据任务权限已更新", grantedCount);
}
private AdminUserEntity requireAdmin(HttpServletRequest request) {
try {
return adminAuthSupport.requireAdmin(request);
@@ -86,6 +86,7 @@ public class PermissionMenuSchemaInitializer {
executeQuietly("UPDATE columns SET sort_order = id WHERE sort_order IS NULL OR sort_order = 0");
executeQuietly("ALTER TABLE columns ADD UNIQUE KEY uk_menu_type_route_path (menu_type, route_path)");
ensureDefaultAdminMenus();
boolean shopDataCrawlDataPermissionCreated = ensureShopDataCrawlAdminDefaults();
ensureDefaultAppMenus();
ensureDefaultAppChildMenus();
ensureInternalDataPermissions();
@@ -98,6 +99,9 @@ public class PermissionMenuSchemaInitializer {
FOREIGN KEY (column_id) REFERENCES columns(id) ON DELETE CASCADE
)
""");
if (shopDataCrawlDataPermissionCreated) {
grantInitialShopDataCrawlDataPermissions();
}
}
private void ensureDefaultAdminMenus() {
@@ -172,6 +176,38 @@ public class PermissionMenuSchemaInitializer {
""");
}
private boolean ensureShopDataCrawlAdminDefaults() {
executeQuietly("""
INSERT INTO columns (name, column_key, menu_type, route_path, sort_order)
SELECT '店铺数据任务管理', 'admin_shop_data_crawl_tasks', 'admin', 'shop-data-crawl-tasks', 82
WHERE NOT EXISTS (
SELECT 1 FROM columns WHERE column_key = 'admin_shop_data_crawl_tasks'
)
""");
return executeUpdateQuietly("""
INSERT INTO columns (name, column_key, menu_type, route_path, sort_order)
SELECT '店铺数据任务数据查看', 'admin_shop_data_crawl_task_data', 'internal', 'shop-data-crawl-task-data', 0
WHERE NOT EXISTS (
SELECT 1 FROM columns WHERE column_key = 'admin_shop_data_crawl_task_data'
)
""") > 0;
}
private void grantInitialShopDataCrawlDataPermissions() {
executeQuietly("""
INSERT IGNORE INTO user_column_permission (user_id, column_id)
SELECT old_perm.user_id, data_col.id
FROM user_column_permission old_perm
INNER JOIN columns old_col ON old_col.id = old_perm.column_id
INNER JOIN columns data_col ON data_col.column_key = 'admin_shop_data_crawl_task_data'
LEFT JOIN user_column_permission existing
ON existing.user_id = old_perm.user_id
AND existing.column_id = data_col.id
WHERE old_col.column_key = 'admin_shop_data_crawl_tasks'
AND existing.user_id IS NULL
""");
}
private void executeQuietly(String sql) {
try {
jdbcTemplate.execute(sql);
@@ -180,6 +216,15 @@ public class PermissionMenuSchemaInitializer {
}
}
private int executeUpdateQuietly(String sql) {
try {
return jdbcTemplate.update(sql);
} catch (Exception ex) {
log.debug("[permission-menu] schema init skipped: {}", ex.getMessage());
return 0;
}
}
private record DefaultAdminMenu(String name, String columnKey, String routePath, int sortOrder) {
}
@@ -47,6 +47,7 @@ public class PermissionMenuService {
public static final String MENU_TYPE_APP = "app";
public static final String MENU_TYPE_ADMIN = "admin";
private static final String IMAGE_VIDEO_DATA_PERMISSION_KEY = "admin_image_video_task_data";
private static final String SHOP_DATA_CRAWL_DATA_PERMISSION_KEY = "admin_shop_data_crawl_task_data";
private final PermissionMenuMapper permissionMenuMapper;
private final UserColumnPermissionMapper userColumnPermissionMapper;
@@ -243,9 +244,8 @@ public class PermissionMenuService {
.filter(user -> user.getId() != null && !isSuperAdmin(user))
.collect(Collectors.toMap(AdminUserEntity::getId, Function.identity(), (left, right) -> left));
if (requestedIds.stream().anyMatch(id -> !grantableUsers.containsKey(id))) {
throw new BusinessException("包含不存在或不可授权的用户");
throw new BusinessException("contains unknown or non-grantable user");
}
userColumnPermissionMapper.deleteByMap(Map.of("column_id", dataPermission.getId()));
for (Long userId : requestedIds) {
UserColumnPermissionEntity grant = new UserColumnPermissionEntity();
@@ -256,6 +256,68 @@ public class PermissionMenuService {
return requestedIds.size();
}
public List<ImageVideoDataPermissionUserVo> listShopDataCrawlDataPermissionUsers(AdminUserEntity operator) {
ensureSuperAdminOperator(operator, "店铺数据任务");
PermissionMenuEntity dataPermission = requireDataPermission(
SHOP_DATA_CRAWL_DATA_PERMISSION_KEY, "店铺数据任务数据");
Set<Long> grantedUserIds = userColumnPermissionMapper.selectList(
new LambdaQueryWrapper<UserColumnPermissionEntity>()
.eq(UserColumnPermissionEntity::getColumnId, dataPermission.getId()))
.stream()
.map(UserColumnPermissionEntity::getUserId)
.filter(id -> id != null && id > 0)
.collect(Collectors.toSet());
return adminUserMapper.selectList(new LambdaQueryWrapper<AdminUserEntity>()
.orderByAsc(AdminUserEntity::getUsername)
.orderByAsc(AdminUserEntity::getId))
.stream()
.filter(user -> !isSuperAdmin(user))
.map(user -> toImageVideoDataPermissionUserVo(user, grantedUserIds.contains(user.getId())))
.toList();
}
@Transactional
public int updateShopDataCrawlDataPermissionUsers(AdminUserEntity operator, List<Long> userIds) {
ensureSuperAdminOperator(operator, "店铺数据任务");
PermissionMenuEntity dataPermission = requireDataPermission(
SHOP_DATA_CRAWL_DATA_PERMISSION_KEY, "店铺数据任务数据");
List<Long> requestedIds = normalizeColumnIds(userIds);
List<AdminUserEntity> users = adminUserMapper.selectList(new LambdaQueryWrapper<AdminUserEntity>());
Map<Long, AdminUserEntity> grantableUsers = users.stream()
.filter(user -> user.getId() != null && !isSuperAdmin(user))
.collect(Collectors.toMap(AdminUserEntity::getId, Function.identity(), (left, right) -> left));
if (requestedIds.stream().anyMatch(id -> !grantableUsers.containsKey(id))) {
throw new BusinessException("contains unknown or non-grantable user");
}
userColumnPermissionMapper.deleteByMap(Map.of("column_id", dataPermission.getId()));
for (Long userId : requestedIds) {
UserColumnPermissionEntity grant = new UserColumnPermissionEntity();
grant.setUserId(userId);
grant.setColumnId(dataPermission.getId());
userColumnPermissionMapper.insert(grant);
}
return requestedIds.size();
}
/** Verifies both the visible admin menu and its separately managed data grant. */
public void requireShopDataCrawlTaskAccess(AdminUserEntity operator) {
ensureAdminOperatorIfPresent(operator);
if (operator == null || operator.getId() == null || operator.getId() <= 0) {
throw new BusinessException(403, "需要管理员权限");
}
if (isSuperAdmin(operator)) {
return;
}
PermissionMenuEntity taskMenu = requireDataPermission(
"admin_shop_data_crawl_tasks", "店铺数据任务管理菜单");
PermissionMenuEntity dataPermission = requireDataPermission(
SHOP_DATA_CRAWL_DATA_PERMISSION_KEY, "店铺数据任务数据");
if (!hasEffectiveColumnPermission(operator.getId(), taskMenu.getId())
|| !hasEffectiveColumnPermission(operator.getId(), dataPermission.getId())) {
throw new BusinessException(403, "无权查看店铺数据任务");
}
}
@Transactional
public void updateUserColumnPermissions(Long userId, UserColumnPermissionUpdateRequest request) {
updateUserColumnPermissions(null, userId, request);
@@ -304,26 +366,36 @@ public class PermissionMenuService {
}
}
PermissionMenuEntity imageVideoDataPermission = normalizedType == null
? findImageVideoDataPermission()
: null;
Long protectedId = imageVideoDataPermission == null ? null : imageVideoDataPermission.getId();
Set<Long> protectedIds = new LinkedHashSet<>();
if (normalizedType == null) {
PermissionMenuEntity imageVideoDataPermission = findImageVideoDataPermission();
PermissionMenuEntity shopDataCrawlDataPermission =
findDataPermission(SHOP_DATA_CRAWL_DATA_PERMISSION_KEY);
if (imageVideoDataPermission != null && imageVideoDataPermission.getId() != null) {
protectedIds.add(imageVideoDataPermission.getId());
}
if (shopDataCrawlDataPermission != null && shopDataCrawlDataPermission.getId() != null) {
protectedIds.add(shopDataCrawlDataPermission.getId());
}
}
List<Long> grantIds = requestedIds;
if (normalizedType == null && protectedId != null) {
if (!protectedIds.isEmpty()) {
grantIds = requestedIds.stream()
.filter(id -> !protectedId.equals(id))
.filter(id -> !protectedIds.contains(id))
.toList();
}
Set<Long> operatorEffectiveIds = ensureGrantable(operator, grantIds);
LinkedHashSet<Long> finalGrantIds = new LinkedHashSet<>(grantIds);
if (normalizedType == null && protectedId != null) {
Long existingCount = userColumnPermissionMapper.selectCount(
new LambdaQueryWrapper<UserColumnPermissionEntity>()
.eq(UserColumnPermissionEntity::getUserId, userId)
.eq(UserColumnPermissionEntity::getColumnId, protectedId));
if (existingCount != null && existingCount > 0) {
finalGrantIds.add(protectedId);
if (!protectedIds.isEmpty()) {
for (Long protectedId : protectedIds) {
Long existingCount = userColumnPermissionMapper.selectCount(
new LambdaQueryWrapper<UserColumnPermissionEntity>()
.eq(UserColumnPermissionEntity::getUserId, userId)
.eq(UserColumnPermissionEntity::getColumnId, protectedId));
if (existingCount != null && existingCount > 0) {
finalGrantIds.add(protectedId);
}
}
}
if (operatorEffectiveIds != null) {
@@ -526,9 +598,7 @@ public class PermissionMenuService {
}
private PermissionMenuEntity findImageVideoDataPermission() {
return permissionMenuMapper.selectOne(new LambdaQueryWrapper<PermissionMenuEntity>()
.eq(PermissionMenuEntity::getColumnKey, IMAGE_VIDEO_DATA_PERMISSION_KEY)
.last("LIMIT 1"));
return findDataPermission(IMAGE_VIDEO_DATA_PERMISSION_KEY);
}
private PermissionMenuEntity requireImageVideoDataPermission() {
@@ -546,6 +616,27 @@ public class PermissionMenuService {
}
}
private void ensureSuperAdminOperator(AdminUserEntity operator, String resourceName) {
ensureAdminOperatorIfPresent(operator);
if (operator == null || !isSuperAdmin(operator)) {
throw new BusinessException(403, "仅超级管理员可以配置" + resourceName + "权限");
}
}
private PermissionMenuEntity findDataPermission(String columnKey) {
return permissionMenuMapper.selectOne(new LambdaQueryWrapper<PermissionMenuEntity>()
.eq(PermissionMenuEntity::getColumnKey, columnKey)
.last("LIMIT 1"));
}
private PermissionMenuEntity requireDataPermission(String columnKey, String displayName) {
PermissionMenuEntity permission = findDataPermission(columnKey);
if (permission == null || permission.getId() == null) {
throw new BusinessException(displayName + "权限尚未初始化");
}
return permission;
}
private ImageVideoDataPermissionUserVo toImageVideoDataPermissionUserVo(AdminUserEntity user,
boolean granted) {
ImageVideoDataPermissionUserVo vo = new ImageVideoDataPermissionUserVo();