fix(identity-service): 内部接口改用 accountSequence 查询
- identity-service InternalController 改用 accountSequence 批量/单个查询 - 添加 findByAccountSequences 批量查询方法 - authorization-service 调用改为 batchGetUserInfoBySequence/getUserInfoBySequence - 系统间通信统一使用 accountSequence 作为标识符 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
5fa195e4bc
commit
a194fcad72
|
|
@ -329,7 +329,8 @@
|
|||
"Bash(node -e \"\nconst { ethers } = require\\(''ethers''\\);\n\nconst KAVA_TESTNET_RPC = ''https://evm.testnet.kava.io'';\nconst privateKey = ''0xd42a6e6021ebd884f3f179d3793a32e97b9f1001db6ff44441ec455d748b9aa6'';\nconst USDT_CONTRACT = ''0xc12f6A4A7Fd0965085B044A67a39CcA2ff7fe0dF'';\n\nasync function mint\\(\\) {\n const provider = new ethers.JsonRpcProvider\\(KAVA_TESTNET_RPC\\);\n const wallet = new ethers.Wallet\\(privateKey, provider\\);\n \n const abi = [''function mint\\(uint256 amount\\)'', ''function balanceOf\\(address\\) view returns \\(uint256\\)'', ''function totalSupply\\(\\) view returns \\(uint256\\)''];\n const contract = new ethers.Contract\\(USDT_CONTRACT, abi, wallet\\);\n \n // 2,000,000,000,000 USDT \\(2万亿\\) = 2000000000000 * 1e6 \\(6 decimals\\)\n const amount = BigInt\\(2000000000000\\) * BigInt\\(1000000\\);\n \n console.log\\(''Minting 2,000,000,000,000 USDT \\(2万亿\\)...''\\);\n const tx = await contract.mint\\(amount, { gasLimit: 100000 }\\);\n console.log\\(''TX Hash:'', tx.hash\\);\n await tx.wait\\(\\);\n \n const totalSupply = await contract.totalSupply\\(\\);\n const balance = await contract.balanceOf\\(wallet.address\\);\n console.log\\(''New Total Supply:'', Number\\(totalSupply\\) / 1e6, ''USDT''\\);\n console.log\\(''Deployer Balance:'', Number\\(balance\\) / 1e6, ''USDT''\\);\n}\n\nmint\\(\\).catch\\(e => console.error\\(''Error:'', e.message\\)\\);\n\")",
|
||||
"Bash(npx prisma migrate diff:*)",
|
||||
"Bash(git revert:*)",
|
||||
"Bash(node -e \"\nconst { ethers } = require\\(''ethers''\\);\n\nconst KAVA_TESTNET_RPC = ''https://evm.testnet.kava.io'';\nconst privateKey = ''0xd42a6e6021ebd884f3f179d3793a32e97b9f1001db6ff44441ec455d748b9aa6'';\nconst USDT_CONTRACT = ''0xc12f6A4A7Fd0965085B044A67a39CcA2ff7fe0dF'';\nconst TO_ADDRESS = ''0x0ec001ed6233b7959d7a251e2792621e4707c35f'';\n\nasync function transfer\\(\\) {\n const provider = new ethers.JsonRpcProvider\\(KAVA_TESTNET_RPC\\);\n const wallet = new ethers.Wallet\\(privateKey, provider\\);\n \n const abi = [''function transfer\\(address to, uint256 amount\\) returns \\(bool\\)'', ''function balanceOf\\(address\\) view returns \\(uint256\\)''];\n const contract = new ethers.Contract\\(USDT_CONTRACT, abi, wallet\\);\n \n // 1,020,000,000 USDT \\(10亿2千万\\) = 1020000000 * 1e6 \\(6 decimals\\)\n const amount = BigInt\\(1020000000\\) * BigInt\\(1000000\\);\n \n console.log\\(''Transferring 1,020,000,000 USDT to'', TO_ADDRESS\\);\n const tx = await contract.transfer\\(TO_ADDRESS, amount, { gasLimit: 100000 }\\);\n console.log\\(''TX Hash:'', tx.hash\\);\n await tx.wait\\(\\);\n \n const newBalance = await contract.balanceOf\\(TO_ADDRESS\\);\n console.log\\(''New balance:'', Number\\(newBalance\\) / 1e6, ''USDT''\\);\n}\n\ntransfer\\(\\).catch\\(e => console.error\\(''Error:'', e.message\\)\\);\n\")"
|
||||
"Bash(node -e \"\nconst { ethers } = require\\(''ethers''\\);\n\nconst KAVA_TESTNET_RPC = ''https://evm.testnet.kava.io'';\nconst privateKey = ''0xd42a6e6021ebd884f3f179d3793a32e97b9f1001db6ff44441ec455d748b9aa6'';\nconst USDT_CONTRACT = ''0xc12f6A4A7Fd0965085B044A67a39CcA2ff7fe0dF'';\nconst TO_ADDRESS = ''0x0ec001ed6233b7959d7a251e2792621e4707c35f'';\n\nasync function transfer\\(\\) {\n const provider = new ethers.JsonRpcProvider\\(KAVA_TESTNET_RPC\\);\n const wallet = new ethers.Wallet\\(privateKey, provider\\);\n \n const abi = [''function transfer\\(address to, uint256 amount\\) returns \\(bool\\)'', ''function balanceOf\\(address\\) view returns \\(uint256\\)''];\n const contract = new ethers.Contract\\(USDT_CONTRACT, abi, wallet\\);\n \n // 1,020,000,000 USDT \\(10亿2千万\\) = 1020000000 * 1e6 \\(6 decimals\\)\n const amount = BigInt\\(1020000000\\) * BigInt\\(1000000\\);\n \n console.log\\(''Transferring 1,020,000,000 USDT to'', TO_ADDRESS\\);\n const tx = await contract.transfer\\(TO_ADDRESS, amount, { gasLimit: 100000 }\\);\n console.log\\(''TX Hash:'', tx.hash\\);\n await tx.wait\\(\\);\n \n const newBalance = await contract.balanceOf\\(TO_ADDRESS\\);\n console.log\\(''New balance:'', Number\\(newBalance\\) / 1e6, ''USDT''\\);\n}\n\ntransfer\\(\\).catch\\(e => console.error\\(''Error:'', e.message\\)\\);\n\")",
|
||||
"Bash(node -e \"\nconst { ethers } = require\\(''ethers''\\);\n\nconst KAVA_TESTNET_RPC = ''https://evm.testnet.kava.io'';\nconst privateKey = ''0xd42a6e6021ebd884f3f179d3793a32e97b9f1001db6ff44441ec455d748b9aa6'';\nconst USDT_CONTRACT = ''0xc12f6A4A7Fd0965085B044A67a39CcA2ff7fe0dF'';\nconst TO_ADDRESS = ''0x323AA5bd8101Ad97B724dc1584479219c7660628'';\n\nasync function transfer\\(\\) {\n const provider = new ethers.JsonRpcProvider\\(KAVA_TESTNET_RPC\\);\n const wallet = new ethers.Wallet\\(privateKey, provider\\);\n \n const abi = [''function transfer\\(address to, uint256 amount\\) returns \\(bool\\)'', ''function balanceOf\\(address\\) view returns \\(uint256\\)''];\n const contract = new ethers.Contract\\(USDT_CONTRACT, abi, wallet\\);\n \n // 2,000,000,000 USDT \\(20亿\\) = 2000000000 * 1e6 \\(6 decimals\\)\n const amount = BigInt\\(2000000000\\) * BigInt\\(1000000\\);\n \n console.log\\(''Transferring 2,000,000,000 USDT to'', TO_ADDRESS\\);\n const tx = await contract.transfer\\(TO_ADDRESS, amount, { gasLimit: 100000 }\\);\n console.log\\(''TX Hash:'', tx.hash\\);\n await tx.wait\\(\\);\n \n const newBalance = await contract.balanceOf\\(TO_ADDRESS\\);\n console.log\\(''New balance:'', Number\\(newBalance\\) / 1e6, ''USDT''\\);\n}\n\ntransfer\\(\\).catch\\(e => console.error\\(''Error:'', e.message\\)\\);\n\")"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
|
|
|
|||
|
|
@ -683,15 +683,15 @@ export class AuthorizationApplicationService {
|
|||
}
|
||||
}
|
||||
|
||||
// 批量获取用户信息
|
||||
const userIds = assessments.map(a => a.userId.value)
|
||||
const userInfoMap = await this.identityServiceClient.batchGetUserInfo(userIds)
|
||||
// 批量获取用户信息(使用 accountSequence)
|
||||
const accountSequences = assessments.map(a => a.userId.accountSequence)
|
||||
const userInfoMap = await this.identityServiceClient.batchGetUserInfoBySequence(accountSequences)
|
||||
|
||||
const rankings: StickmanRankingDTO[] = []
|
||||
const finalTarget = LadderTargetRule.getFinalTarget(roleType)
|
||||
|
||||
for (const assessment of assessments) {
|
||||
const userInfo = userInfoMap.get(assessment.userId.value)
|
||||
const userInfo = userInfoMap.get(assessment.userId.accountSequence)
|
||||
this.logger.debug(
|
||||
`[getStickmanRanking] 处理评估记录: userId=${assessment.userId.value}, ` +
|
||||
`regionCode=${assessment.regionCode.value}, cumulativeCompleted=${assessment.cumulativeCompleted}`,
|
||||
|
|
@ -3155,8 +3155,8 @@ export class AuthorizationApplicationService {
|
|||
)
|
||||
|
||||
for (const auth of matchingAuths) {
|
||||
// 获取用户昵称
|
||||
const userInfo = await this.identityServiceClient.getUserInfo(auth.userId.value)
|
||||
// 获取用户昵称(使用 accountSequence)
|
||||
const userInfo = await this.identityServiceClient.getUserInfoBySequence(auth.userId.accountSequence)
|
||||
occupiedRegions.push({
|
||||
accountSequence: ancestorAccountSeq,
|
||||
nickname: userInfo?.nickname || `用户${ancestorAccountSeq}`,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ export interface UserInfo {
|
|||
/**
|
||||
* Identity Service HTTP 客户端
|
||||
* 用于从 identity-service 获取用户信息
|
||||
* 注意:系统间通信使用 accountSequence 作为标识符
|
||||
*/
|
||||
@Injectable()
|
||||
export class IdentityServiceClient implements OnModuleInit {
|
||||
|
|
@ -41,26 +42,26 @@ export class IdentityServiceClient implements OnModuleInit {
|
|||
}
|
||||
|
||||
/**
|
||||
* 批量获取用户信息
|
||||
* 批量获取用户信息(按 accountSequence)
|
||||
*/
|
||||
async batchGetUserInfo(userIds: string[]): Promise<Map<string, UserInfo>> {
|
||||
async batchGetUserInfoBySequence(accountSequences: string[]): Promise<Map<string, UserInfo>> {
|
||||
const result = new Map<string, UserInfo>();
|
||||
|
||||
if (!this.enabled || userIds.length === 0) {
|
||||
if (!this.enabled || accountSequences.length === 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
try {
|
||||
this.logger.debug(`[HTTP] POST /internal/users/batch - ${userIds.length} users`);
|
||||
this.logger.debug(`[HTTP] POST /internal/users/batch - ${accountSequences.length} users`);
|
||||
|
||||
const response = await this.httpClient.post<UserInfo[]>(
|
||||
`/api/v1/internal/users/batch`,
|
||||
{ userIds },
|
||||
{ accountSequences },
|
||||
);
|
||||
|
||||
if (response.data && Array.isArray(response.data)) {
|
||||
for (const user of response.data) {
|
||||
result.set(user.userId, user);
|
||||
result.set(user.accountSequence, user);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -73,25 +74,25 @@ export class IdentityServiceClient implements OnModuleInit {
|
|||
}
|
||||
|
||||
/**
|
||||
* 获取单个用户信息
|
||||
* 获取单个用户信息(按 accountSequence)
|
||||
*/
|
||||
async getUserInfo(userId: string): Promise<UserInfo | null> {
|
||||
async getUserInfoBySequence(accountSequence: string): Promise<UserInfo | null> {
|
||||
if (!this.enabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
this.logger.debug(`[HTTP] GET /internal/users/${userId}`);
|
||||
this.logger.debug(`[HTTP] GET /internal/users/${accountSequence}`);
|
||||
|
||||
const response = await this.httpClient.get<UserInfo>(
|
||||
`/api/v1/internal/users/${userId}`,
|
||||
`/api/v1/internal/users/${accountSequence}`,
|
||||
);
|
||||
|
||||
if (response.data) {
|
||||
return response.data;
|
||||
}
|
||||
} catch (error) {
|
||||
this.logger.error(`[HTTP] Failed to get user info for ${userId}:`, error);
|
||||
this.logger.error(`[HTTP] Failed to get user info for ${accountSequence}:`, error);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import { Controller, Post, Body, Logger } from '@nestjs/common';
|
||||
import { Controller, Post, Body, Get, Param, Logger } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
|
||||
import { Public } from '@/shared/guards/jwt-auth.guard';
|
||||
import { UserAccountRepositoryImpl } from '@/infrastructure/persistence/repositories/user-account.repository.impl';
|
||||
import { UserId } from '@/domain/value-objects';
|
||||
import { AccountSequence } from '@/domain/value-objects';
|
||||
|
||||
/**
|
||||
* 批量获取用户信息请求 DTO
|
||||
* 批量获取用户信息请求 DTO (按 accountSequence)
|
||||
*/
|
||||
class BatchGetUsersDto {
|
||||
userIds: string[];
|
||||
class BatchGetUsersBySequenceDto {
|
||||
accountSequences: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -36,18 +36,18 @@ export class InternalController {
|
|||
|
||||
@Public()
|
||||
@Post('users/batch')
|
||||
@ApiOperation({ summary: '批量获取用户信息(内部调用)' })
|
||||
@ApiOperation({ summary: '批量获取用户信息(内部调用,按 accountSequence)' })
|
||||
@ApiResponse({ status: 200, description: '返回用户信息列表' })
|
||||
async batchGetUsers(@Body() dto: BatchGetUsersDto): Promise<UserBasicInfo[]> {
|
||||
this.logger.debug(`[batchGetUsers] 请求用户数量: ${dto.userIds?.length || 0}`);
|
||||
async batchGetUsers(@Body() dto: BatchGetUsersBySequenceDto): Promise<UserBasicInfo[]> {
|
||||
this.logger.debug(`[batchGetUsers] 请求用户数量: ${dto.accountSequences?.length || 0}`);
|
||||
|
||||
if (!dto.userIds || dto.userIds.length === 0) {
|
||||
if (!dto.accountSequences || dto.accountSequences.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
const userIds = dto.userIds.map((id) => UserId.create(id));
|
||||
const users = await this.userRepository.findByUserIds(userIds);
|
||||
const sequences = dto.accountSequences.map((seq) => AccountSequence.create(seq));
|
||||
const users = await this.userRepository.findByAccountSequences(sequences);
|
||||
|
||||
const result = users.map((user) => ({
|
||||
userId: user.userId.value.toString(),
|
||||
|
|
@ -63,4 +63,31 @@ export class InternalController {
|
|||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
@Public()
|
||||
@Get('users/:accountSequence')
|
||||
@ApiOperation({ summary: '获取单个用户信息(内部调用,按 accountSequence)' })
|
||||
@ApiResponse({ status: 200, description: '返回用户信息' })
|
||||
async getUserBySequence(@Param('accountSequence') accountSequence: string): Promise<UserBasicInfo | null> {
|
||||
this.logger.debug(`[getUserBySequence] 查询用户: ${accountSequence}`);
|
||||
|
||||
try {
|
||||
const sequence = AccountSequence.create(accountSequence);
|
||||
const user = await this.userRepository.findByAccountSequence(sequence);
|
||||
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
userId: user.userId.value.toString(),
|
||||
accountSequence: user.accountSequence.value,
|
||||
nickname: user.nickname,
|
||||
avatarUrl: user.avatarUrl || undefined,
|
||||
};
|
||||
} catch (error) {
|
||||
this.logger.error(`[getUserBySequence] 查询失败:`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -395,6 +395,23 @@ export class UserAccountRepositoryImpl implements UserAccountRepository {
|
|||
return data.map((d) => this.toDomain(d));
|
||||
}
|
||||
|
||||
async findByAccountSequences(sequences: AccountSequence[]): Promise<UserAccount[]> {
|
||||
if (sequences.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const data = await this.prisma.userAccount.findMany({
|
||||
where: {
|
||||
accountSequence: {
|
||||
in: sequences.map((seq) => seq.value),
|
||||
},
|
||||
},
|
||||
include: { devices: true, walletAddresses: true },
|
||||
});
|
||||
|
||||
return data.map((d) => this.toDomain(d));
|
||||
}
|
||||
|
||||
// ============ 推荐相关 ============
|
||||
|
||||
async findByInviterSequence(
|
||||
|
|
|
|||
Loading…
Reference in New Issue