895 lines
27 KiB
Markdown
895 lines
27 KiB
Markdown
# Mining Admin Service (挖矿管理服务) 开发指导
|
||
|
||
## 1. 服务概述
|
||
|
||
### 1.1 核心职责
|
||
Mining Admin Service 是挖矿系统的管理中枢,负责配置管理、系统监控、数据报表等后台管理功能。
|
||
|
||
**主要功能:**
|
||
- 系统参数配置(贡献值递增比例、分配比例等)
|
||
- 系统开关控制(转账开关等)
|
||
- 系统账户管理(运营/省/市/总部账户)
|
||
- 全局状态监控与报表
|
||
- 用户算力/积分股查询
|
||
- 历史数据初始化(老用户算力计算)
|
||
- 操作日志与审计
|
||
|
||
### 1.2 技术栈
|
||
- **框架**: NestJS + TypeScript
|
||
- **数据库**: PostgreSQL (CRUD为主)
|
||
- **ORM**: Prisma
|
||
- **消息队列**: Kafka (接收其他服务事件)
|
||
- **缓存**: Redis
|
||
|
||
### 1.3 端口分配
|
||
- HTTP: 3023
|
||
- 数据库: rwa_mining_admin
|
||
|
||
---
|
||
|
||
## 2. 架构设计
|
||
|
||
### 2.1 目录结构
|
||
|
||
```
|
||
mining-admin-service/
|
||
├── src/
|
||
│ ├── api/
|
||
│ │ ├── controllers/
|
||
│ │ │ ├── config.controller.ts # 配置管理API
|
||
│ │ │ ├── system-account.controller.ts # 系统账户API
|
||
│ │ │ ├── user-query.controller.ts # 用户查询API
|
||
│ │ │ ├── dashboard.controller.ts # 仪表盘API
|
||
│ │ │ ├── report.controller.ts # 报表API
|
||
│ │ │ ├── initialization.controller.ts # 初始化API
|
||
│ │ │ ├── audit-log.controller.ts # 审计日志API
|
||
│ │ │ └── health.controller.ts
|
||
│ │ └── dto/
|
||
│ │ ├── request/
|
||
│ │ │ ├── update-config.request.ts
|
||
│ │ │ ├── query-user.request.ts
|
||
│ │ │ └── initialize-users.request.ts
|
||
│ │ └── response/
|
||
│ │ ├── config.response.ts
|
||
│ │ ├── dashboard.response.ts
|
||
│ │ ├── user-detail.response.ts
|
||
│ │ └── report.response.ts
|
||
│ │
|
||
│ ├── application/
|
||
│ │ ├── commands/
|
||
│ │ │ ├── update-contribution-config.command.ts
|
||
│ │ │ ├── update-distribution-config.command.ts
|
||
│ │ │ ├── toggle-transfer.command.ts
|
||
│ │ │ ├── initialize-legacy-users.command.ts
|
||
│ │ │ ├── create-system-account.command.ts
|
||
│ │ │ └── manual-adjustment.command.ts
|
||
│ │ ├── queries/
|
||
│ │ │ ├── get-dashboard-stats.query.ts
|
||
│ │ │ ├── get-user-contribution-detail.query.ts
|
||
│ │ │ ├── get-user-mining-detail.query.ts
|
||
│ │ │ ├── get-global-state.query.ts
|
||
│ │ │ ├── get-system-accounts.query.ts
|
||
│ │ │ ├── get-audit-logs.query.ts
|
||
│ │ │ └── generate-report.query.ts
|
||
│ │ ├── services/
|
||
│ │ │ ├── config-management.service.ts
|
||
│ │ │ ├── initialization.service.ts
|
||
│ │ │ ├── report-generator.service.ts
|
||
│ │ │ └── audit.service.ts
|
||
│ │ └── event-handlers/
|
||
│ │ ├── contribution-calculated.handler.ts
|
||
│ │ ├── shares-distributed.handler.ts
|
||
│ │ ├── trade-completed.handler.ts
|
||
│ │ └── price-updated.handler.ts
|
||
│ │
|
||
│ ├── domain/
|
||
│ │ ├── aggregates/
|
||
│ │ │ ├── system-config.aggregate.ts
|
||
│ │ │ ├── system-account.aggregate.ts
|
||
│ │ │ └── audit-log.aggregate.ts
|
||
│ │ ├── repositories/
|
||
│ │ │ ├── system-config.repository.interface.ts
|
||
│ │ │ ├── system-account.repository.interface.ts
|
||
│ │ │ ├── audit-log.repository.interface.ts
|
||
│ │ │ └── synced-data.repository.interface.ts
|
||
│ │ ├── value-objects/
|
||
│ │ │ ├── config-key.vo.ts
|
||
│ │ │ └── audit-action.vo.ts
|
||
│ │ └── events/
|
||
│ │ ├── config-updated.event.ts
|
||
│ │ └── initialization-completed.event.ts
|
||
│ │
|
||
│ ├── infrastructure/
|
||
│ │ ├── persistence/
|
||
│ │ │ ├── prisma/
|
||
│ │ │ │ └── prisma.service.ts
|
||
│ │ │ ├── repositories/
|
||
│ │ │ │ ├── system-config.repository.impl.ts
|
||
│ │ │ │ ├── system-account.repository.impl.ts
|
||
│ │ │ │ ├── audit-log.repository.impl.ts
|
||
│ │ │ │ └── synced-data.repository.impl.ts
|
||
│ │ │ └── unit-of-work/
|
||
│ │ │ └── unit-of-work.service.ts
|
||
│ │ ├── kafka/
|
||
│ │ │ ├── contribution-event-consumer.service.ts
|
||
│ │ │ ├── mining-event-consumer.service.ts
|
||
│ │ │ ├── trading-event-consumer.service.ts
|
||
│ │ │ ├── event-publisher.service.ts
|
||
│ │ │ └── kafka.module.ts
|
||
│ │ ├── redis/
|
||
│ │ │ ├── config-cache.service.ts
|
||
│ │ │ └── stats-cache.service.ts
|
||
│ │ ├── external/
|
||
│ │ │ ├── contribution-client.service.ts
|
||
│ │ │ ├── mining-client.service.ts
|
||
│ │ │ └── trading-client.service.ts
|
||
│ │ └── infrastructure.module.ts
|
||
│ │
|
||
│ ├── shared/
|
||
│ │ ├── guards/
|
||
│ │ │ └── admin-auth.guard.ts
|
||
│ │ └── decorators/
|
||
│ │ └── audit-log.decorator.ts
|
||
│ ├── config/
|
||
│ ├── app.module.ts
|
||
│ └── main.ts
|
||
│
|
||
├── prisma/
|
||
│ ├── schema.prisma
|
||
│ └── migrations/
|
||
├── package.json
|
||
├── tsconfig.json
|
||
├── Dockerfile
|
||
└── docker-compose.yml
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 数据库设计
|
||
|
||
### 3.1 数据库类型
|
||
Mining Admin Service 以**查询和配置管理**为主,使用 PostgreSQL 作为主数据库,大部分表为 CRUD 操作。
|
||
|
||
### 3.2 核心表结构
|
||
|
||
```sql
|
||
-- ============================================
|
||
-- 系统配置表
|
||
-- ============================================
|
||
|
||
-- 通用配置表(Key-Value)
|
||
CREATE TABLE system_configs (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
|
||
config_key VARCHAR(100) NOT NULL UNIQUE,
|
||
config_value TEXT NOT NULL,
|
||
config_type VARCHAR(20) NOT NULL, -- STRING / NUMBER / BOOLEAN / JSON
|
||
description VARCHAR(200),
|
||
|
||
is_active BOOLEAN DEFAULT TRUE,
|
||
version INT DEFAULT 1,
|
||
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||
updated_by VARCHAR(50) -- 操作人
|
||
);
|
||
|
||
-- 初始化配置数据
|
||
INSERT INTO system_configs (config_key, config_value, config_type, description) VALUES
|
||
('contribution.base_value', '22617', 'NUMBER', '基础贡献值'),
|
||
('contribution.increment_percentage', '0.003', 'NUMBER', '递增百分比 0.3%'),
|
||
('contribution.unit_size', '100', 'NUMBER', '单位大小(100棵)'),
|
||
('contribution.start_tree_number', '1000', 'NUMBER', '起始树编号'),
|
||
('distribution.personal_rate', '0.70', 'NUMBER', '个人分配比例 70%'),
|
||
('distribution.operation_rate', '0.12', 'NUMBER', '运营账户比例 12%'),
|
||
('distribution.province_rate', '0.01', 'NUMBER', '省公司比例 1%'),
|
||
('distribution.city_rate', '0.02', 'NUMBER', '市公司比例 2%'),
|
||
('distribution.team_rate', '0.15', 'NUMBER', '团队比例 15%'),
|
||
('distribution.level_rate_per', '0.005', 'NUMBER', '每级比例 0.5%'),
|
||
('distribution.bonus_rate_per', '0.025', 'NUMBER', '每档奖励比例 2.5%'),
|
||
('mining.transfer_enabled', 'false', 'BOOLEAN', '转账功能开关'),
|
||
('trading.buy_fee_rate', '0.10', 'NUMBER', '买入手续费率 10%'),
|
||
('trading.sell_fee_rate', '0.10', 'NUMBER', '卖出手续费率 10%');
|
||
|
||
-- 贡献值递增配置表(历史记录)
|
||
CREATE TABLE contribution_increment_configs (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
|
||
base_contribution DECIMAL(20,10) NOT NULL,
|
||
increment_percentage DECIMAL(10,6) NOT NULL,
|
||
unit_size INT NOT NULL,
|
||
start_tree_number INT NOT NULL,
|
||
|
||
effective_from DATE NOT NULL,
|
||
effective_to DATE,
|
||
is_active BOOLEAN DEFAULT TRUE,
|
||
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||
created_by VARCHAR(50)
|
||
);
|
||
|
||
-- 分配比例配置表(历史记录)
|
||
CREATE TABLE distribution_rate_configs (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
|
||
rate_type VARCHAR(30) NOT NULL, -- PERSONAL/OPERATION/PROVINCE/CITY/TEAM_LEVEL/TEAM_BONUS
|
||
rate_value DECIMAL(10,6) NOT NULL,
|
||
level_depth INT, -- TEAM_LEVEL时使用
|
||
bonus_tier INT, -- TEAM_BONUS时使用
|
||
|
||
effective_from DATE NOT NULL,
|
||
effective_to DATE,
|
||
is_active BOOLEAN DEFAULT TRUE,
|
||
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||
created_by VARCHAR(50)
|
||
);
|
||
|
||
-- ============================================
|
||
-- 系统账户表
|
||
-- ============================================
|
||
|
||
CREATE TABLE system_accounts (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
|
||
account_type VARCHAR(20) NOT NULL, -- OPERATION / PROVINCE / CITY / HEADQUARTERS
|
||
account_name VARCHAR(100) NOT NULL,
|
||
account_code VARCHAR(50) UNIQUE, -- 账户编码
|
||
|
||
-- 关联信息(省/市公司时使用)
|
||
region_code VARCHAR(20),
|
||
region_name VARCHAR(100),
|
||
|
||
-- 余额(从其他服务同步)
|
||
contribution_balance DECIMAL(30,10) DEFAULT 0,
|
||
share_balance DECIMAL(30,10) DEFAULT 0,
|
||
green_points_balance DECIMAL(30,10) DEFAULT 0,
|
||
|
||
-- 特殊标记
|
||
contribution_never_expires BOOLEAN DEFAULT FALSE,
|
||
|
||
is_active BOOLEAN DEFAULT TRUE,
|
||
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||
);
|
||
|
||
-- 初始化数据
|
||
INSERT INTO system_accounts (account_type, account_name, account_code, contribution_never_expires) VALUES
|
||
('OPERATION', '运营账户', 'SYS_OPERATION', TRUE),
|
||
('HEADQUARTERS', '总部账户', 'SYS_HEADQUARTERS', TRUE),
|
||
('PROVINCE', '省公司账户', 'SYS_PROVINCE', FALSE),
|
||
('CITY', '市公司账户', 'SYS_CITY', FALSE);
|
||
|
||
-- ============================================
|
||
-- 仪表盘统计快照表
|
||
-- ============================================
|
||
|
||
CREATE TABLE dashboard_snapshots (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
snapshot_time TIMESTAMP WITH TIME ZONE NOT NULL,
|
||
|
||
-- 全局状态
|
||
total_users INT DEFAULT 0,
|
||
total_adopted_users INT DEFAULT 0,
|
||
total_trees INT DEFAULT 0,
|
||
|
||
-- 算力统计
|
||
total_contribution DECIMAL(30,10) DEFAULT 0,
|
||
effective_contribution DECIMAL(30,10) DEFAULT 0,
|
||
|
||
-- 积分股统计
|
||
total_supply DECIMAL(30,10),
|
||
black_hole_amount DECIMAL(30,10),
|
||
circulation_pool DECIMAL(30,10),
|
||
current_price DECIMAL(30,18),
|
||
|
||
-- 交易统计
|
||
total_trade_volume DECIMAL(30,10) DEFAULT 0,
|
||
today_trade_volume DECIMAL(30,10) DEFAULT 0,
|
||
total_trade_count INT DEFAULT 0,
|
||
today_trade_count INT DEFAULT 0,
|
||
|
||
-- 分配统计
|
||
total_distributed DECIMAL(30,10) DEFAULT 0,
|
||
today_distributed DECIMAL(30,10) DEFAULT 0,
|
||
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||
);
|
||
CREATE INDEX idx_dashboard_snapshots_time ON dashboard_snapshots(snapshot_time);
|
||
|
||
-- ============================================
|
||
-- 同步数据表(从其他服务汇总)
|
||
-- ============================================
|
||
|
||
-- 用户汇总视图表(定期同步)
|
||
CREATE TABLE synced_user_summaries (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
account_sequence VARCHAR(20) NOT NULL UNIQUE,
|
||
|
||
-- 基本信息
|
||
phone VARCHAR(20),
|
||
status VARCHAR(20),
|
||
|
||
-- 认种信息
|
||
total_trees INT DEFAULT 0,
|
||
first_adoption_date DATE,
|
||
last_adoption_date DATE,
|
||
|
||
-- 推荐信息
|
||
referrer_account_sequence VARCHAR(20),
|
||
direct_referral_count INT DEFAULT 0,
|
||
direct_referral_adopted_count INT DEFAULT 0,
|
||
total_team_size INT DEFAULT 0,
|
||
|
||
-- 算力信息
|
||
personal_contribution DECIMAL(30,10) DEFAULT 0,
|
||
team_level_contribution DECIMAL(30,10) DEFAULT 0,
|
||
team_bonus_contribution DECIMAL(30,10) DEFAULT 0,
|
||
total_contribution DECIMAL(30,10) DEFAULT 0,
|
||
effective_contribution DECIMAL(30,10) DEFAULT 0,
|
||
|
||
-- 积分股信息
|
||
share_balance DECIMAL(30,10) DEFAULT 0,
|
||
total_mined DECIMAL(30,10) DEFAULT 0,
|
||
total_sold DECIMAL(30,10) DEFAULT 0,
|
||
total_bought DECIMAL(30,10) DEFAULT 0,
|
||
|
||
-- 同步状态
|
||
last_synced_at TIMESTAMP WITH TIME ZONE,
|
||
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||
);
|
||
CREATE INDEX idx_synced_user_summaries_phone ON synced_user_summaries(phone);
|
||
|
||
-- ============================================
|
||
-- 审计日志表
|
||
-- ============================================
|
||
|
||
CREATE TABLE audit_logs (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
|
||
-- 操作信息
|
||
action_type VARCHAR(50) NOT NULL, -- CONFIG_UPDATE / ACCOUNT_CREATE / MANUAL_ADJUST / INIT_USERS / TOGGLE_SWITCH
|
||
action_target VARCHAR(100), -- 操作目标(如配置key、账户ID等)
|
||
action_detail JSONB, -- 操作详情
|
||
|
||
-- 操作前后值
|
||
before_value JSONB,
|
||
after_value JSONB,
|
||
|
||
-- 操作人
|
||
operator_id VARCHAR(50) NOT NULL,
|
||
operator_name VARCHAR(100),
|
||
operator_ip VARCHAR(50),
|
||
|
||
-- 操作结果
|
||
result VARCHAR(20) NOT NULL, -- SUCCESS / FAILED
|
||
error_message TEXT,
|
||
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||
);
|
||
CREATE INDEX idx_audit_logs_action ON audit_logs(action_type);
|
||
CREATE INDEX idx_audit_logs_time ON audit_logs(created_at);
|
||
CREATE INDEX idx_audit_logs_operator ON audit_logs(operator_id);
|
||
|
||
-- ============================================
|
||
-- 初始化任务表
|
||
-- ============================================
|
||
|
||
CREATE TABLE initialization_tasks (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
|
||
task_type VARCHAR(50) NOT NULL, -- LEGACY_USER_CONTRIBUTION / GLOBAL_STATE / SYSTEM_ACCOUNTS
|
||
task_status VARCHAR(20) NOT NULL, -- PENDING / RUNNING / COMPLETED / FAILED
|
||
|
||
-- 进度
|
||
total_count INT DEFAULT 0,
|
||
processed_count INT DEFAULT 0,
|
||
failed_count INT DEFAULT 0,
|
||
|
||
-- 参数
|
||
task_params JSONB,
|
||
|
||
-- 结果
|
||
result_summary JSONB,
|
||
error_message TEXT,
|
||
|
||
started_at TIMESTAMP WITH TIME ZONE,
|
||
completed_at TIMESTAMP WITH TIME ZONE,
|
||
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||
created_by VARCHAR(50)
|
||
);
|
||
|
||
-- ============================================
|
||
-- 已处理事件(幂等性)
|
||
-- ============================================
|
||
|
||
CREATE TABLE processed_events (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
event_id VARCHAR(100) NOT NULL UNIQUE,
|
||
event_type VARCHAR(50) NOT NULL,
|
||
source_service VARCHAR(50),
|
||
processed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 核心业务逻辑
|
||
|
||
### 4.1 老用户算力初始化
|
||
|
||
```typescript
|
||
/**
|
||
* 初始化老用户算力
|
||
* 这是系统上线时的一次性任务
|
||
*/
|
||
async initializeLegacyUserContributions(): Promise<InitializationResult> {
|
||
// 创建初始化任务
|
||
const task = await this.initTaskRepo.create({
|
||
taskType: 'LEGACY_USER_CONTRIBUTION',
|
||
taskStatus: 'RUNNING',
|
||
startedAt: new Date(),
|
||
});
|
||
|
||
try {
|
||
// 1. 获取所有已认种用户
|
||
const adoptedUsers = await this.userRepo.findAllAdoptedUsers();
|
||
|
||
await this.initTaskRepo.updateProgress(task.id, {
|
||
totalCount: adoptedUsers.length,
|
||
});
|
||
|
||
let processedCount = 0;
|
||
let failedCount = 0;
|
||
|
||
// 2. 批量处理用户
|
||
for (const user of adoptedUsers) {
|
||
try {
|
||
// 调用 contribution-service 计算算力
|
||
await this.contributionClient.calculateUserContribution(user.accountSequence);
|
||
processedCount++;
|
||
} catch (error) {
|
||
this.logger.error(`Failed to initialize user ${user.accountSequence}`, error);
|
||
failedCount++;
|
||
}
|
||
|
||
// 更新进度
|
||
if ((processedCount + failedCount) % 100 === 0) {
|
||
await this.initTaskRepo.updateProgress(task.id, {
|
||
processedCount,
|
||
failedCount,
|
||
});
|
||
}
|
||
}
|
||
|
||
// 3. 完成任务
|
||
await this.initTaskRepo.complete(task.id, {
|
||
processedCount,
|
||
failedCount,
|
||
resultSummary: {
|
||
totalUsers: adoptedUsers.length,
|
||
successCount: processedCount,
|
||
failedCount,
|
||
},
|
||
});
|
||
|
||
// 4. 记录审计日志
|
||
await this.auditService.log({
|
||
actionType: 'INIT_USERS',
|
||
actionDetail: { taskId: task.id },
|
||
afterValue: { processedCount, failedCount },
|
||
result: 'SUCCESS',
|
||
});
|
||
|
||
return { taskId: task.id, processedCount, failedCount };
|
||
|
||
} catch (error) {
|
||
await this.initTaskRepo.fail(task.id, error.message);
|
||
throw error;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.2 配置管理
|
||
|
||
```typescript
|
||
/**
|
||
* 更新系统配置
|
||
* 所有配置更新都需要记录审计日志
|
||
*/
|
||
@AuditLog('CONFIG_UPDATE')
|
||
async updateConfig(key: string, value: string, operatorId: string): Promise<void> {
|
||
const existing = await this.configRepo.findByKey(key);
|
||
|
||
if (!existing) {
|
||
throw new ConfigNotFoundException(key);
|
||
}
|
||
|
||
const beforeValue = existing.configValue;
|
||
|
||
// 验证值格式
|
||
this.validateConfigValue(key, value, existing.configType);
|
||
|
||
// 更新配置
|
||
await this.configRepo.update(key, {
|
||
configValue: value,
|
||
updatedBy: operatorId,
|
||
version: existing.version + 1,
|
||
});
|
||
|
||
// 清除缓存
|
||
await this.configCache.invalidate(key);
|
||
|
||
// 发布配置更新事件
|
||
await this.eventPublisher.publish('mining-admin.config-updated', {
|
||
eventId: uuid(),
|
||
configKey: key,
|
||
beforeValue,
|
||
afterValue: value,
|
||
updatedBy: operatorId,
|
||
updatedAt: new Date().toISOString(),
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 切换转账开关
|
||
*/
|
||
@AuditLog('TOGGLE_SWITCH')
|
||
async toggleTransfer(enabled: boolean, operatorId: string): Promise<void> {
|
||
const key = 'mining.transfer_enabled';
|
||
|
||
await this.updateConfig(key, String(enabled), operatorId);
|
||
|
||
// 通知 mining-service
|
||
await this.miningClient.updateTransferSwitch(enabled);
|
||
}
|
||
```
|
||
|
||
### 4.3 仪表盘统计
|
||
|
||
```typescript
|
||
/**
|
||
* 获取仪表盘统计数据
|
||
*/
|
||
async getDashboardStats(): Promise<DashboardStatsDto> {
|
||
// 优先从缓存获取
|
||
const cached = await this.statsCache.get('dashboard');
|
||
if (cached) {
|
||
return cached;
|
||
}
|
||
|
||
// 聚合各服务数据
|
||
const [
|
||
globalState,
|
||
contributionStats,
|
||
tradingStats,
|
||
userStats,
|
||
] = await Promise.all([
|
||
this.miningClient.getGlobalState(),
|
||
this.contributionClient.getNetworkStats(),
|
||
this.tradingClient.getTodayStats(),
|
||
this.getUserStats(),
|
||
]);
|
||
|
||
const stats: DashboardStatsDto = {
|
||
// 全局状态
|
||
currentPrice: globalState.currentPrice,
|
||
blackHoleAmount: globalState.blackHoleAmount,
|
||
circulationPool: globalState.circulationPool,
|
||
minuteBurnRate: globalState.minuteBurnRate,
|
||
|
||
// 算力统计
|
||
networkTotalContribution: contributionStats.totalContribution,
|
||
networkEffectiveContribution: contributionStats.effectiveContribution,
|
||
|
||
// 用户统计
|
||
totalUsers: userStats.totalUsers,
|
||
adoptedUsers: userStats.adoptedUsers,
|
||
totalTrees: userStats.totalTrees,
|
||
|
||
// 交易统计
|
||
todayTradeVolume: tradingStats.volume,
|
||
todayTradeCount: tradingStats.count,
|
||
|
||
// 分配统计
|
||
totalDistributed: globalState.totalDistributed,
|
||
distributionPhase: globalState.distributionPhase,
|
||
dailyDistribution: globalState.dailyDistribution,
|
||
|
||
updatedAt: new Date().toISOString(),
|
||
};
|
||
|
||
// 缓存 30 秒
|
||
await this.statsCache.set('dashboard', stats, 30);
|
||
|
||
// 保存快照
|
||
await this.dashboardSnapshotRepo.create(stats);
|
||
|
||
return stats;
|
||
}
|
||
```
|
||
|
||
### 4.4 用户详情查询
|
||
|
||
```typescript
|
||
/**
|
||
* 查询用户算力和挖矿详情
|
||
*/
|
||
async getUserDetail(accountSequence: string): Promise<UserDetailDto> {
|
||
const [
|
||
contribution,
|
||
shareAccount,
|
||
miningRecords,
|
||
tradeOrders,
|
||
referralInfo,
|
||
] = await Promise.all([
|
||
this.contributionClient.getUserContribution(accountSequence),
|
||
this.miningClient.getUserShareAccount(accountSequence),
|
||
this.miningClient.getUserMiningRecords(accountSequence, { limit: 30 }),
|
||
this.tradingClient.getUserOrders(accountSequence, { limit: 30 }),
|
||
this.getUserReferralInfo(accountSequence),
|
||
]);
|
||
|
||
return {
|
||
accountSequence,
|
||
|
||
// 算力信息
|
||
contribution: {
|
||
personal: contribution.personalContribution,
|
||
teamLevel: contribution.teamLevelContribution,
|
||
teamBonus: contribution.teamBonusContribution,
|
||
total: contribution.totalContribution,
|
||
effective: contribution.effectiveContribution,
|
||
hasAdopted: contribution.hasAdopted,
|
||
directReferralAdoptedCount: contribution.directReferralAdoptedCount,
|
||
unlockedLevelDepth: contribution.unlockedLevelDepth,
|
||
unlockedBonusTiers: contribution.unlockedBonusTiers,
|
||
},
|
||
|
||
// 积分股信息
|
||
shares: {
|
||
available: shareAccount.availableBalance,
|
||
frozen: shareAccount.frozenBalance,
|
||
totalMined: shareAccount.totalMined,
|
||
totalSold: shareAccount.totalSold,
|
||
totalBought: shareAccount.totalBought,
|
||
perSecondEarning: shareAccount.perSecondEarning,
|
||
},
|
||
|
||
// 推荐信息
|
||
referral: referralInfo,
|
||
|
||
// 最近挖矿记录
|
||
recentMiningRecords: miningRecords,
|
||
|
||
// 最近交易记录
|
||
recentTradeOrders: tradeOrders,
|
||
};
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 服务间通信
|
||
|
||
### 5.1 订阅的事件
|
||
|
||
| Topic | 来源服务 | 数据内容 | 处理方式 |
|
||
|-------|---------|---------|---------|
|
||
| `contribution.contribution-calculated` | contribution-service | 用户算力计算完成 | 更新本地用户汇总 |
|
||
| `mining.shares-distributed` | mining-service | 积分股分配完成 | 更新分配统计 |
|
||
| `mining.price-updated` | mining-service | 价格更新 | 更新仪表盘 |
|
||
| `trading.trade-completed` | trading-service | 交易完成 | 更新交易统计 |
|
||
|
||
### 5.2 发布的事件
|
||
|
||
| Topic | 事件类型 | 订阅者 |
|
||
|-------|---------|-------|
|
||
| `mining-admin.config-updated` | ConfigUpdated | contribution/mining/trading |
|
||
|
||
### 5.3 调用其他服务
|
||
|
||
```typescript
|
||
// 调用 contribution-service
|
||
this.contributionClient.getUserContribution(accountSequence);
|
||
this.contributionClient.calculateUserContribution(accountSequence);
|
||
this.contributionClient.getNetworkStats();
|
||
|
||
// 调用 mining-service
|
||
this.miningClient.getGlobalState();
|
||
this.miningClient.getUserShareAccount(accountSequence);
|
||
this.miningClient.getUserMiningRecords(accountSequence);
|
||
this.miningClient.updateTransferSwitch(enabled);
|
||
|
||
// 调用 trading-service
|
||
this.tradingClient.getUserOrders(accountSequence);
|
||
this.tradingClient.getTodayStats();
|
||
this.tradingClient.getKlineData(period);
|
||
```
|
||
|
||
---
|
||
|
||
## 6. API 设计
|
||
|
||
### 6.1 配置管理 API
|
||
|
||
```
|
||
GET /api/admin/configs # 获取所有配置
|
||
GET /api/admin/configs/:key # 获取单个配置
|
||
PUT /api/admin/configs/:key # 更新配置
|
||
POST /api/admin/configs/toggle-transfer # 切换转账开关
|
||
```
|
||
|
||
### 6.2 系统账户 API
|
||
|
||
```
|
||
GET /api/admin/system-accounts # 获取所有系统账户
|
||
GET /api/admin/system-accounts/:id # 获取单个账户详情
|
||
POST /api/admin/system-accounts # 创建系统账户
|
||
PUT /api/admin/system-accounts/:id # 更新系统账户
|
||
```
|
||
|
||
### 6.3 用户查询 API
|
||
|
||
```
|
||
GET /api/admin/users # 用户列表(分页)
|
||
GET /api/admin/users/:accountSequence # 用户详情
|
||
GET /api/admin/users/:accountSequence/contribution-records # 算力明细
|
||
GET /api/admin/users/:accountSequence/mining-records # 挖矿明细
|
||
GET /api/admin/users/:accountSequence/trade-orders # 交易记录
|
||
```
|
||
|
||
### 6.4 仪表盘 API
|
||
|
||
```
|
||
GET /api/admin/dashboard # 仪表盘统计
|
||
GET /api/admin/dashboard/realtime # 实时数据(WebSocket推送)
|
||
GET /api/admin/dashboard/charts # 图表数据
|
||
```
|
||
|
||
### 6.5 报表 API
|
||
|
||
```
|
||
GET /api/admin/reports/daily # 日报表
|
||
GET /api/admin/reports/contribution # 算力报表
|
||
GET /api/admin/reports/mining # 挖矿报表
|
||
GET /api/admin/reports/trading # 交易报表
|
||
POST /api/admin/reports/export # 导出报表
|
||
```
|
||
|
||
### 6.6 初始化 API
|
||
|
||
```
|
||
POST /api/admin/initialization/legacy-users # 初始化老用户算力
|
||
POST /api/admin/initialization/global-state # 初始化全局状态
|
||
GET /api/admin/initialization/tasks # 获取初始化任务列表
|
||
GET /api/admin/initialization/tasks/:id # 获取任务详情
|
||
```
|
||
|
||
### 6.7 审计日志 API
|
||
|
||
```
|
||
GET /api/admin/audit-logs # 审计日志列表
|
||
GET /api/admin/audit-logs/:id # 审计日志详情
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 审计日志装饰器
|
||
|
||
```typescript
|
||
/**
|
||
* 审计日志装饰器
|
||
* 自动记录操作前后的值变化
|
||
*/
|
||
export function AuditLog(actionType: string) {
|
||
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
|
||
const originalMethod = descriptor.value;
|
||
|
||
descriptor.value = async function (...args: any[]) {
|
||
const auditService = this.auditService;
|
||
const operatorId = this.getCurrentOperatorId();
|
||
|
||
// 记录操作前状态(如果需要)
|
||
let beforeValue = null;
|
||
if (actionType === 'CONFIG_UPDATE') {
|
||
beforeValue = await this.getBeforeValue(args);
|
||
}
|
||
|
||
try {
|
||
const result = await originalMethod.apply(this, args);
|
||
|
||
// 记录成功日志
|
||
await auditService.log({
|
||
actionType,
|
||
actionTarget: this.getActionTarget(args),
|
||
actionDetail: this.getActionDetail(args),
|
||
beforeValue,
|
||
afterValue: this.getAfterValue(args, result),
|
||
operatorId,
|
||
result: 'SUCCESS',
|
||
});
|
||
|
||
return result;
|
||
} catch (error) {
|
||
// 记录失败日志
|
||
await auditService.log({
|
||
actionType,
|
||
actionTarget: this.getActionTarget(args),
|
||
actionDetail: this.getActionDetail(args),
|
||
beforeValue,
|
||
operatorId,
|
||
result: 'FAILED',
|
||
errorMessage: error.message,
|
||
});
|
||
|
||
throw error;
|
||
}
|
||
};
|
||
|
||
return descriptor;
|
||
};
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 8. 关键注意事项
|
||
|
||
### 8.1 权限控制
|
||
- 所有 API 需要管理员认证
|
||
- 敏感操作需要二次确认
|
||
- 配置修改需要记录操作人
|
||
|
||
### 8.2 数据一致性
|
||
- 本地汇总数据定期与源服务同步
|
||
- 仪表盘数据缓存有 TTL
|
||
- 重要操作使用事务
|
||
|
||
### 8.3 审计要求
|
||
- 所有配置变更记录审计日志
|
||
- 记录操作前后值
|
||
- 保留操作人信息和 IP
|
||
|
||
### 8.4 性能优化
|
||
- 使用 Redis 缓存频繁查询的数据
|
||
- 仪表盘统计定期快照
|
||
- 用户列表查询分页
|
||
|
||
---
|
||
|
||
## 9. 开发检查清单
|
||
|
||
- [ ] 实现配置管理 API
|
||
- [ ] 实现系统账户管理
|
||
- [ ] 实现用户查询 API
|
||
- [ ] 实现仪表盘统计
|
||
- [ ] 实现老用户初始化功能
|
||
- [ ] 实现审计日志记录
|
||
- [ ] 配置与其他服务的 HTTP 客户端
|
||
- [ ] 配置 Kafka Consumer
|
||
- [ ] 实现管理员认证
|
||
- [ ] 编写测试
|
||
|
||
---
|
||
|
||
## 10. 启动命令
|
||
|
||
```bash
|
||
# 开发环境
|
||
npm run start:dev
|
||
|
||
# 生成 Prisma Client
|
||
npx prisma generate
|
||
|
||
# 运行迁移
|
||
npx prisma migrate dev
|
||
|
||
# 生产环境
|
||
npm run build && npm run start:prod
|
||
```
|