From bdc6ba524f46318574e5f3b675688be264318d13 Mon Sep 17 00:00:00 2001 From: hailin Date: Mon, 5 Jan 2026 05:56:30 -0800 Subject: [PATCH] =?UTF-8?q?fix(authorization):=20=E7=81=AB=E6=9F=B4?= =?UTF-8?q?=E4=BA=BA=E6=8E=92=E5=90=8D=E6=94=B9=E4=B8=BA=E6=8C=89=E5=8C=BA?= =?UTF-8?q?=E5=9F=9F=E8=BF=87=E6=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修改排名逻辑,只显示获得相同省/市公司授权的用户排名。 - 后端 getStickmanRanking 改用 findRankingsByMonthAndRegion - 简化实时创建评估逻辑,只为当前区域创建 - 更新前端注释说明 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .claude/settings.local.json | 3 +- .../authorization-application.service.ts | 96 +++++++------------ .../presentation/pages/profile_page.dart | 4 +- 3 files changed, 36 insertions(+), 67 deletions(-) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 2ba28fc2..3ddc4cea 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -588,7 +588,8 @@ "Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(mobile-app\\): improve empty state display for offline settlement deduction\n\nWhen there are no settlement records to deduct, show a more informative message:\n- If user has balance from deposits/transfers: explain it''s not from earnings\n- If user has no balance: explain there are no settlement records\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")", "Bash(xargs:*)", "Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(wallet/blockchain\\): 热钱包余额预检查及接收方钱包自动创建\n\n1. blockchain-service: 新增热钱包 dUSDT 余额定时更新调度器\n - 每 5 秒查询热钱包在 KAVA 链上的 dUSDT 余额\n - 更新到 Redis DB 0,key 格式: hot_wallet:dusdt_balance:{chainType}\n - TTL 30 秒,服务故障时缓存自动过期\n\n2. wallet-service: 新增热钱包余额缓存服务\n - 从 Redis DB 0 读取热钱包余额缓存\n - 严格模式:无法获取余额或余额不足时拒绝转账\n - 提示信息:\"财务系统审计中,请稍后再试\"\n\n3. wallet-service: 转账确认时自动创建接收方钱包\n - 解决接收方钱包不存在导致入账失败的问题\n - 使用 upsert 避免并发创建冲突\n - 在同一事务中完成创建和入账\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")", - "Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(wallet-service\\): 添加内部转账入账修复脚本\n\n新增一次性修复脚本用于补录因接收方钱包未创建导致入账失败的内部转账。\n\n脚本特性:\n- DRY_RUN 模式:默认只检查不执行,需手动改为 false 才真正修复\n- 完整验证:订单状态、类型、接收方信息、txHash\n- 幂等性检查:确认接收方没有 TRANSFER_IN 流水\n- 转出方验证:确认转出方有 TRANSFER_OUT 流水(已扣款)\n- 乐观锁:使用 version 字段防止并发修改\n- 审计追踪:payloadJson.dataFix=true 标记修复操作\n- 详细日志:每步操作都有时间戳和日志级别\n\n使用方法:\n1. 在 wallet-service 容器内执行 DRY_RUN 检查\n2. 确认无误后将 DRY_RUN 改为 false 再次执行\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")" + "Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(wallet-service\\): 添加内部转账入账修复脚本\n\n新增一次性修复脚本用于补录因接收方钱包未创建导致入账失败的内部转账。\n\n脚本特性:\n- DRY_RUN 模式:默认只检查不执行,需手动改为 false 才真正修复\n- 完整验证:订单状态、类型、接收方信息、txHash\n- 幂等性检查:确认接收方没有 TRANSFER_IN 流水\n- 转出方验证:确认转出方有 TRANSFER_OUT 流水(已扣款)\n- 乐观锁:使用 version 字段防止并发修改\n- 审计追踪:payloadJson.dataFix=true 标记修复操作\n- 详细日志:每步操作都有时间戳和日志级别\n\n使用方法:\n1. 在 wallet-service 容器内执行 DRY_RUN 检查\n2. 确认无误后将 DRY_RUN 改为 false 再次执行\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")", + "Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(mobile-app\\): 添加待办操作轮询机制\n\n解决老版本 App 升级后不重启导致无法激活待办事项的问题。\n\n- 新增 PendingActionPollingService 定时轮询服务(每4秒检查)\n- App启动时无待办则启动轮询,有待办则直接进入待办页面\n- 轮询检测到待办后自动停止并跳转,防止重入问题\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")" ], "deny": [], "ask": [] diff --git a/backend/services/authorization-service/src/application/services/authorization-application.service.ts b/backend/services/authorization-service/src/application/services/authorization-application.service.ts index b338a93d..6a7a987a 100644 --- a/backend/services/authorization-service/src/application/services/authorization-application.service.ts +++ b/backend/services/authorization-service/src/application/services/authorization-application.service.ts @@ -575,8 +575,8 @@ export class AuthorizationApplicationService { /** * 查询火柴人排名数据 * - * 业务规则:查询全系统该角色类型的所有排名数据(不按区域过滤) - * 只要有任何一个用户达标,所有申请了该角色类型授权的用户都能看到排名 + * 业务规则:查询同一区域内该角色类型的所有排名数据 + * 只显示与当前用户相同省/市的授权用户排名 */ async getStickmanRanking( month: string, @@ -589,87 +589,55 @@ export class AuthorizationApplicationService { ) const monthVO = Month.create(month) + const regionCodeVO = RegionCode.create(regionCode) - // 查询全系统该角色类型的所有评估记录(不按区域过滤) - let assessments = await this.assessmentRepository.findRankingsByMonthAndRoleType( + // 查询同一区域内该角色类型的所有评估记录 + let assessments = await this.assessmentRepository.findRankingsByMonthAndRegion( monthVO, roleType, + regionCodeVO, ) this.logger.log( `[getStickmanRanking] 查询到 ${assessments.length} 条评估记录`, ) - // 如果没有评估记录,尝试实时创建 + // 如果没有评估记录,尝试实时创建(只为当前区域创建) if (assessments.length === 0) { this.logger.log( - `[getStickmanRanking] 没有评估记录,尝试实时创建: month=${month}, roleType=${roleType}`, + `[getStickmanRanking] 没有评估记录,尝试实时创建: month=${month}, roleType=${roleType}, regionCode=${regionCode}`, ) - // 获取所有该角色类型的激活授权 - const activeAuths = await this.authorizationRepository.findAllActive(roleType) - this.logger.log( - `[getStickmanRanking] 找到 ${activeAuths.length} 个激活的 ${roleType} 授权`, - ) - - if (activeAuths.length === 0) { - this.logger.warn( - `[getStickmanRanking] 没有找到任何激活的授权,month=${month}, roleType=${roleType}`, - ) - return [] - } - - // 按区域分组并创建评估记录 - const regionGroups = new Map() - for (const auth of activeAuths) { - const region = auth.regionCode.value - if (!regionGroups.has(region)) { - regionGroups.set(region, []) - } - regionGroups.get(region)!.push(auth) - } - - this.logger.log( - `[getStickmanRanking] 按区域分组: ${regionGroups.size} 个区域`, - ) - - // 使用 AssessmentCalculatorService 为每个区域创建评估 + // 使用 AssessmentCalculatorService 为当前区域创建评估 const calculatorService = new AssessmentCalculatorService() - const allNewAssessments: MonthlyAssessment[] = [] - - for (const [region, auths] of regionGroups) { - this.logger.log( - `[getStickmanRanking] 为区域 ${region} 创建评估,包含 ${auths.length} 个授权`, - ) - - const regionAssessments = await calculatorService.assessAndRankRegion( - roleType, - RegionCode.create(region), - monthVO, - this.authorizationRepository, - this.statsRepository, - this.assessmentRepository, - ) - - this.logger.log( - `[getStickmanRanking] 区域 ${region} 创建了 ${regionAssessments.length} 条评估记录`, - ) - - // 保存评估记录 - if (regionAssessments.length > 0) { - await this.assessmentRepository.saveAll(regionAssessments) - allNewAssessments.push(...regionAssessments) - } - } this.logger.log( - `[getStickmanRanking] 共创建 ${allNewAssessments.length} 条评估记录`, + `[getStickmanRanking] 为区域 ${regionCode} 创建评估`, ) - // 重新查询 - assessments = await this.assessmentRepository.findRankingsByMonthAndRoleType( + const regionAssessments = await calculatorService.assessAndRankRegion( + roleType, + regionCodeVO, + monthVO, + this.authorizationRepository, + this.statsRepository, + this.assessmentRepository, + ) + + this.logger.log( + `[getStickmanRanking] 区域 ${regionCode} 创建了 ${regionAssessments.length} 条评估记录`, + ) + + // 保存评估记录 + if (regionAssessments.length > 0) { + await this.assessmentRepository.saveAll(regionAssessments) + } + + // 重新查询当前区域的评估记录 + assessments = await this.assessmentRepository.findRankingsByMonthAndRegion( monthVO, roleType, + regionCodeVO, ) this.logger.log( @@ -678,7 +646,7 @@ export class AuthorizationApplicationService { if (assessments.length === 0) { this.logger.warn( - `[getStickmanRanking] 创建评估后仍然没有记录,month=${month}, roleType=${roleType}`, + `[getStickmanRanking] 创建评估后仍然没有记录,month=${month}, roleType=${roleType}, regionCode=${regionCode}`, ) return [] } diff --git a/frontend/mobile-app/lib/features/profile/presentation/pages/profile_page.dart b/frontend/mobile-app/lib/features/profile/presentation/pages/profile_page.dart index 28282347..1ba1c693 100644 --- a/frontend/mobile-app/lib/features/profile/presentation/pages/profile_page.dart +++ b/frontend/mobile-app/lib/features/profile/presentation/pages/profile_page.dart @@ -595,7 +595,7 @@ class _ProfilePageState extends ConsumerState { final now = DateTime.now(); final month = '${now.year}-${now.month.toString().padLeft(2, '0')}'; - // 如果有省团队授权,加载省排名(全系统所有省团队的排名) + // 如果有省团队授权,加载省排名(同省的所有省团队授权用户排名) if (_hasAuthProvinceCompanyAuth) { try { _provinceRegionName = _authProvinceCompany; @@ -629,7 +629,7 @@ class _ProfilePageState extends ConsumerState { } } - // 如果有市团队授权,加载市排名(全系统所有市团队的排名) + // 如果有市团队授权,加载市排名(同市的所有市团队授权用户排名) if (_hasAuthCityCompanyAuth) { try { _cityRegionName = _authCityCompany;