v0.1
This commit is contained in:
319
docs/API调用记录和钱包交易记录功能说明.md
Normal file
319
docs/API调用记录和钱包交易记录功能说明.md
Normal file
@@ -0,0 +1,319 @@
|
||||
# API调用记录和钱包交易记录功能说明
|
||||
|
||||
## 概述
|
||||
|
||||
本文档描述了新增的API调用记录和钱包交易记录功能,包括后端API接口和前端页面。
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 1. API调用记录功能
|
||||
|
||||
#### 后端API接口
|
||||
|
||||
**获取用户API调用记录**
|
||||
- **接口地址**: `GET /api/v1/my/api-calls`
|
||||
- **认证要求**: 需要JWT认证
|
||||
- **功能**: 获取当前用户的API调用历史记录,支持分页和筛选
|
||||
|
||||
**请求参数**:
|
||||
```json
|
||||
{
|
||||
"page": 1, // 页码,默认1
|
||||
"page_size": 10, // 每页数量,默认10
|
||||
"start_time": "2024-01-01 00:00:00", // 开始时间(可选)
|
||||
"end_time": "2024-01-31 23:59:59", // 结束时间(可选)
|
||||
"transaction_id": "1234567890", // 交易ID(可选)
|
||||
"product_id": "product_123", // 产品ID(可选)
|
||||
"status": "success" // 状态筛选:success/failed/pending(可选)
|
||||
}
|
||||
```
|
||||
|
||||
**响应格式**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取API调用记录成功",
|
||||
"data": {
|
||||
"items": [
|
||||
{
|
||||
"id": "api_call_123",
|
||||
"access_id": "access_456",
|
||||
"user_id": "user_789",
|
||||
"product_id": "product_123",
|
||||
"product_name": "身份证识别",
|
||||
"transaction_id": "1234567890",
|
||||
"client_ip": "192.168.1.1",
|
||||
"request_params": "{\"image\": \"base64...\"}",
|
||||
"response_data": "{\"result\": \"success\"}",
|
||||
"status": "success",
|
||||
"start_at": "2024-01-15 10:30:00",
|
||||
"end_at": "2024-01-15 10:30:05",
|
||||
"cost": "0.10",
|
||||
"error_type": null,
|
||||
"error_msg": null,
|
||||
"created_at": "2024-01-15 10:30:00",
|
||||
"updated_at": "2024-01-15 10:30:05"
|
||||
}
|
||||
],
|
||||
"total": 100,
|
||||
"page": 1,
|
||||
"size": 10
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 前端页面
|
||||
|
||||
**页面路径**: `/api/usage`
|
||||
**功能特性**:
|
||||
- 显示API调用统计信息(总调用次数、成功率)
|
||||
- 支持按时间范围、交易ID、产品名称、状态筛选
|
||||
- 分页显示调用记录列表
|
||||
- 查看调用详情(请求参数、响应数据、错误信息)
|
||||
- 响应式设计,支持移动端访问
|
||||
|
||||
### 2. 钱包交易记录功能
|
||||
|
||||
#### 后端API接口
|
||||
|
||||
**获取用户钱包交易记录**
|
||||
- **接口地址**: `GET /api/v1/finance/wallet/transactions`
|
||||
- **认证要求**: 需要JWT认证
|
||||
- **功能**: 获取当前用户的钱包消费记录,支持分页和筛选
|
||||
|
||||
**请求参数**:
|
||||
```json
|
||||
{
|
||||
"page": 1, // 页码,默认1
|
||||
"page_size": 10, // 每页数量,默认10
|
||||
"start_time": "2024-01-01 00:00:00", // 开始时间(可选)
|
||||
"end_time": "2024-01-31 23:59:59", // 结束时间(可选)
|
||||
"api_call_id": "api_call_123", // API调用ID(可选)
|
||||
"min_amount": "0.01", // 最小金额(可选)
|
||||
"max_amount": "100.00" // 最大金额(可选)
|
||||
}
|
||||
```
|
||||
|
||||
**响应格式**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取钱包交易记录成功",
|
||||
"data": {
|
||||
"items": [
|
||||
{
|
||||
"id": "transaction_123",
|
||||
"user_id": "user_789",
|
||||
"api_call_id": "api_call_456",
|
||||
"amount": "0.10",
|
||||
"created_at": "2024-01-15 10:30:05",
|
||||
"updated_at": "2024-01-15 10:30:05"
|
||||
}
|
||||
],
|
||||
"total": 50,
|
||||
"page": 1,
|
||||
"size": 10
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 前端页面
|
||||
|
||||
**页面路径**: `/finance/transactions`
|
||||
**功能特性**:
|
||||
- 显示消费统计信息(总消费次数、总消费金额)
|
||||
- 支持按时间范围、API调用ID、金额范围筛选
|
||||
- 分页显示交易记录列表
|
||||
- 查看交易详情
|
||||
- 响应式设计,支持移动端访问
|
||||
|
||||
## 技术实现
|
||||
|
||||
### 后端架构
|
||||
|
||||
#### 1. 数据层
|
||||
- **实体**: `ApiCall`、`WalletTransaction`
|
||||
- **仓储**: `ApiCallRepository`、`WalletTransactionRepository`
|
||||
- **GORM实现**: `GormApiCallRepository`、`GormWalletTransactionRepository`
|
||||
|
||||
#### 2. 领域层
|
||||
- **聚合服务**: `ApiCallAggregateService`、`WalletAggregateService`
|
||||
- **业务逻辑**: 分页查询、条件筛选、数据统计
|
||||
|
||||
#### 3. 应用层
|
||||
- **应用服务**: `ApiApplicationService`、`FinanceApplicationService`
|
||||
- **DTO转换**: 实体到响应DTO的映射
|
||||
- **业务编排**: 调用领域服务,处理应用级逻辑
|
||||
|
||||
#### 4. 接口层
|
||||
- **HTTP处理器**: `ApiHandler`、`FinanceHandler`
|
||||
- **路由配置**: API路由和财务路由
|
||||
- **中间件**: JWT认证、请求验证、响应构建
|
||||
|
||||
### 前端架构
|
||||
|
||||
#### 1. 页面组件
|
||||
- **API调用记录**: `Usage.vue`
|
||||
- **钱包交易记录**: `Transactions.vue`
|
||||
- **通用组件**: `ListPageLayout`、`FilterSection`、`FilterItem`
|
||||
|
||||
#### 2. API接口
|
||||
- **API模块**: `apiApi.getUserApiCalls()`
|
||||
- **财务模块**: `financeApi.getUserWalletTransactions()`
|
||||
|
||||
#### 3. 功能特性
|
||||
- **筛选功能**: 时间范围、关键词搜索、状态筛选
|
||||
- **分页功能**: 支持自定义每页数量
|
||||
- **详情弹窗**: 查看完整记录信息
|
||||
- **响应式设计**: 适配不同屏幕尺寸
|
||||
|
||||
## 数据库设计
|
||||
|
||||
### API调用记录表 (api_calls)
|
||||
```sql
|
||||
CREATE TABLE api_calls (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
access_id VARCHAR(64) NOT NULL,
|
||||
user_id VARCHAR(36),
|
||||
product_id VARCHAR(64),
|
||||
transaction_id VARCHAR(64) NOT NULL,
|
||||
client_ip VARCHAR(64) NOT NULL,
|
||||
request_params TEXT,
|
||||
response_data TEXT,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'pending',
|
||||
start_at TIMESTAMP NOT NULL,
|
||||
end_at TIMESTAMP,
|
||||
cost DECIMAL(20,8),
|
||||
error_type VARCHAR(32),
|
||||
error_msg VARCHAR(256),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX idx_user_id (user_id),
|
||||
INDEX idx_transaction_id (transaction_id),
|
||||
INDEX idx_status (status),
|
||||
INDEX idx_created_at (created_at)
|
||||
);
|
||||
```
|
||||
|
||||
### 钱包交易记录表 (wallet_transactions)
|
||||
```sql
|
||||
CREATE TABLE wallet_transactions (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
user_id VARCHAR(36) NOT NULL,
|
||||
api_call_id VARCHAR(64) NOT NULL,
|
||||
amount DECIMAL(20,8) NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP NULL,
|
||||
INDEX idx_user_id (user_id),
|
||||
INDEX idx_api_call_id (api_call_id),
|
||||
INDEX idx_created_at (created_at)
|
||||
);
|
||||
```
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 1. 获取API调用记录
|
||||
|
||||
**请求示例**:
|
||||
```bash
|
||||
curl -X GET "http://localhost:8080/api/v1/my/api-calls?page=1&page_size=10&status=success" \
|
||||
-H "Authorization: Bearer YOUR_JWT_TOKEN"
|
||||
```
|
||||
|
||||
**响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取API调用记录成功",
|
||||
"data": {
|
||||
"items": [...],
|
||||
"total": 100,
|
||||
"page": 1,
|
||||
"size": 10
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 获取钱包交易记录
|
||||
|
||||
**请求示例**:
|
||||
```bash
|
||||
curl -X GET "http://localhost:8080/api/v1/finance/wallet/transactions?page=1&page_size=10" \
|
||||
-H "Authorization: Bearer YOUR_JWT_TOKEN"
|
||||
```
|
||||
|
||||
**响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取钱包交易记录成功",
|
||||
"data": {
|
||||
"items": [...],
|
||||
"total": 50,
|
||||
"page": 1,
|
||||
"size": 10
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 错误处理
|
||||
|
||||
### 常见错误码
|
||||
- `400`: 请求参数错误
|
||||
- `401`: 未认证或认证失败
|
||||
- `500`: 服务器内部错误
|
||||
|
||||
### 错误响应格式
|
||||
```json
|
||||
{
|
||||
"code": 400,
|
||||
"message": "请求参数错误",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 1. 数据库优化
|
||||
- 合理设置索引
|
||||
- 使用分页查询避免大量数据查询
|
||||
- 缓存热点数据
|
||||
|
||||
### 2. 前端优化
|
||||
- 防抖搜索,避免频繁请求
|
||||
- 分页加载,减少数据传输
|
||||
- 响应式设计,提升用户体验
|
||||
|
||||
## 安全考虑
|
||||
|
||||
### 1. 认证授权
|
||||
- 所有接口都需要JWT认证
|
||||
- 用户只能查看自己的记录
|
||||
- 接口权限验证
|
||||
|
||||
### 2. 数据安全
|
||||
- 敏感信息脱敏处理
|
||||
- SQL注入防护
|
||||
- XSS攻击防护
|
||||
|
||||
## 扩展功能
|
||||
|
||||
### 1. 统计报表
|
||||
- 调用量趋势分析
|
||||
- 费用统计报表
|
||||
- 成功率分析
|
||||
|
||||
### 2. 导出功能
|
||||
- 支持Excel导出
|
||||
- 支持PDF报表
|
||||
- 自定义导出格式
|
||||
|
||||
### 3. 实时监控
|
||||
- WebSocket实时推送
|
||||
- 调用状态实时更新
|
||||
- 异常告警通知
|
||||
|
||||
## 总结
|
||||
|
||||
API调用记录和钱包交易记录功能为用户提供了完整的API使用追踪和费用管理能力,通过合理的架构设计和功能实现,确保了系统的可扩展性和可维护性。
|
||||
177
docs/API调用错误处理规范.md
Normal file
177
docs/API调用错误处理规范.md
Normal file
@@ -0,0 +1,177 @@
|
||||
# API调用错误处理规范
|
||||
|
||||
## 概述
|
||||
|
||||
本文档定义了API调用接口的统一错误处理规范,包括错误码定义、响应结构、错误处理流程等。
|
||||
|
||||
## 响应结构
|
||||
|
||||
### 成功响应
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "业务成功",
|
||||
"transaction_id": "api_call_123456",
|
||||
"data": "加密的响应数据"
|
||||
}
|
||||
```
|
||||
|
||||
### 错误响应
|
||||
```json
|
||||
{
|
||||
"code": 1001,
|
||||
"message": "接口异常",
|
||||
"transaction_id": "api_call_123456"
|
||||
}
|
||||
```
|
||||
|
||||
## 错误码定义
|
||||
|
||||
| 错误码 | 错误类型 | 说明 |
|
||||
|--------|----------|------|
|
||||
| 0 | 业务成功 | 调用成功 |
|
||||
| 1000 | 查询为空 | 查询结果为空 |
|
||||
| 1001 | 接口异常 | 系统异常、数据源异常等 |
|
||||
| 1002 | 参数解密失败 | 请求参数解密失败 |
|
||||
| 1003 | 基础参数校验不正确 | 请求参数格式错误 |
|
||||
| 1004 | 未经授权的IP | IP不在白名单内 |
|
||||
| 1005 | 缺少Access-Id | 请求头中缺少Access-Id |
|
||||
| 1006 | 未经授权的AccessId | AccessId无效或账户已冻结 |
|
||||
| 1007 | 账户余额不足,无法请求 | 钱包余额不足 |
|
||||
| 1008 | 未开通此产品 | 产品不存在、已停用或未订阅 |
|
||||
| 2001 | 业务失败 | 第三方API业务逻辑失败 |
|
||||
|
||||
## 实现架构
|
||||
|
||||
### 1. 错误类型定义
|
||||
- 位置:`internal/application/api/errors.go`
|
||||
- 功能:定义具体的错误类型常量和错误码映射
|
||||
|
||||
### 2. 响应结构定义
|
||||
- 位置:`internal/application/api/dto/api_response.go`
|
||||
- 功能:定义统一的响应结构体和工厂方法
|
||||
|
||||
### 3. 应用层错误处理
|
||||
- 位置:`internal/application/api/api_application_service.go`
|
||||
- 功能:在业务逻辑中返回具体的错误类型
|
||||
|
||||
### 4. Handler层统一处理
|
||||
- 位置:`internal/infrastructure/http/handlers/api_handler.go`
|
||||
- 功能:根据错误类型返回对应的错误码和响应
|
||||
|
||||
## 错误处理流程
|
||||
|
||||
### 1. 基础参数校验(Handler层)
|
||||
```go
|
||||
// 检查Access-Id
|
||||
accessId := c.GetHeader("Access-Id")
|
||||
if accessId == "" {
|
||||
response := dto.NewErrorResponse(1005, "缺少Access-Id", "")
|
||||
c.JSON(400, response)
|
||||
return
|
||||
}
|
||||
|
||||
// 参数绑定和校验
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
response := dto.NewErrorResponse(1003, "基础参数校验不正确", "")
|
||||
c.JSON(400, response)
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 业务逻辑错误处理(应用层)
|
||||
```go
|
||||
// 用户不存在
|
||||
if err != nil {
|
||||
return ErrInvalidAccessId
|
||||
}
|
||||
|
||||
// 账户已冻结
|
||||
if apiUser.IsFrozen() {
|
||||
return ErrFrozenAccount
|
||||
}
|
||||
|
||||
// IP不在白名单
|
||||
if !apiUser.IsWhiteListed(cmd.ClientIP) {
|
||||
return ErrInvalidIP
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 统一错误响应(Handler层)
|
||||
```go
|
||||
// 调用应用服务
|
||||
transactionId, encryptedResp, err := h.appService.CallApi(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
// 根据错误类型返回对应的错误码
|
||||
errorCode := api.GetErrorCode(err)
|
||||
response := dto.NewErrorResponse(errorCode, err.Error(), transactionId)
|
||||
c.JSON(200, response) // API调用接口统一返回200状态码
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
## 中间件简化
|
||||
|
||||
原来的API认证中间件已经简化,只保留IP获取功能:
|
||||
- 认证逻辑移到Handler层处理
|
||||
- 保持中间件职责单一
|
||||
- 便于错误码的统一管理
|
||||
|
||||
## 测试
|
||||
|
||||
错误处理逻辑包含完整的单元测试:
|
||||
```bash
|
||||
go test ./internal/application/api -v
|
||||
```
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 成功调用
|
||||
```bash
|
||||
curl -X POST "http://localhost:8080/api/v1/test_api" \
|
||||
-H "Access-Id: your_access_id" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"data": "encrypted_request_data"}'
|
||||
```
|
||||
|
||||
响应:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "业务成功",
|
||||
"transaction_id": "api_call_123456",
|
||||
"data": "encrypted_response_data"
|
||||
}
|
||||
```
|
||||
|
||||
### 错误调用示例
|
||||
```bash
|
||||
# 缺少Access-Id
|
||||
curl -X POST "http://localhost:8080/api/v1/test_api" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"data": "encrypted_request_data"}'
|
||||
```
|
||||
|
||||
响应:
|
||||
```json
|
||||
{
|
||||
"code": 1005,
|
||||
"message": "缺少Access-Id",
|
||||
"transaction_id": ""
|
||||
}
|
||||
```
|
||||
|
||||
## 扩展说明
|
||||
|
||||
1. **新增错误类型**:在`errors.go`中添加新的错误常量和错误码映射
|
||||
2. **错误码调整**:修改`ErrorCodeMap`中的映射关系
|
||||
3. **响应结构扩展**:在`api_response.go`中添加新的响应字段或方法
|
||||
4. **国际化支持**:可以在错误消息中添加多语言支持
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. API调用接口统一返回HTTP 200状态码,错误通过响应体中的code字段区分
|
||||
2. 所有错误响应都包含transaction_id,便于问题追踪
|
||||
3. 错误消息使用中文,符合项目规范
|
||||
4. 错误处理遵循DDD分层架构,错误类型定义在应用层
|
||||
5. 错误码严格按照规范定义,不能多不能少
|
||||
1039
docs/swagger/docs.go
1039
docs/swagger/docs.go
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
192
docs/充值功能说明.md
Normal file
192
docs/充值功能说明.md
Normal file
@@ -0,0 +1,192 @@
|
||||
# 充值功能说明
|
||||
|
||||
## 概述
|
||||
|
||||
本系统支持三种充值方式:
|
||||
1. **支付宝充值** - 通过支付宝进行在线充值(待实现)
|
||||
2. **对公转账** - 通过银行转账进行充值
|
||||
3. **赠送充值** - 管理员为用户进行赠送充值
|
||||
|
||||
## 功能架构
|
||||
|
||||
### 实体层 (Entities)
|
||||
- `RechargeRecord` - 充值记录实体
|
||||
- `Wallet` - 钱包实体
|
||||
- `WalletTransaction` - 钱包交易记录实体
|
||||
|
||||
### 领域服务层 (Domain Services)
|
||||
- `WalletAggregateService` - 钱包聚合服务,处理充值业务逻辑
|
||||
|
||||
### 应用服务层 (Application Services)
|
||||
- `FinanceApplicationService` - 财务应用服务,协调充值操作
|
||||
|
||||
### HTTP层 (HTTP Handlers)
|
||||
- `FinanceHandler` - 财务HTTP处理器,提供REST API接口
|
||||
|
||||
## API接口
|
||||
|
||||
### 1. 对公转账充值
|
||||
|
||||
**接口地址:** `POST /api/v1/finance/wallet/transfer-recharge`
|
||||
|
||||
**请求参数:**
|
||||
```json
|
||||
{
|
||||
"amount": "100.00",
|
||||
"transfer_order_id": "TR202412010001",
|
||||
"bank_account": "6222021234567890123",
|
||||
"bank_name": "中国工商银行",
|
||||
"notes": "转账备注"
|
||||
}
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "对公转账充值成功",
|
||||
"data": {
|
||||
"id": "uuid",
|
||||
"user_id": "user_uuid",
|
||||
"amount": "100.00",
|
||||
"recharge_type": "transfer",
|
||||
"status": "success",
|
||||
"transfer_order_id": "TR202412010001",
|
||||
"bank_account": "6222021234567890123",
|
||||
"bank_name": "中国工商银行",
|
||||
"notes": "转账备注",
|
||||
"created_at": "2024-12-01T10:00:00Z",
|
||||
"updated_at": "2024-12-01T10:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 赠送充值
|
||||
|
||||
**接口地址:** `POST /api/v1/finance/wallet/gift-recharge`
|
||||
|
||||
**请求参数:**
|
||||
```json
|
||||
{
|
||||
"amount": "50.00",
|
||||
"gift_reason": "新用户注册奖励",
|
||||
"notes": "系统自动赠送"
|
||||
}
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "赠送充值成功",
|
||||
"data": {
|
||||
"id": "uuid",
|
||||
"user_id": "user_uuid",
|
||||
"amount": "50.00",
|
||||
"recharge_type": "gift",
|
||||
"status": "success",
|
||||
"gift_reason": "新用户注册奖励",
|
||||
"operator_id": "system",
|
||||
"notes": "系统自动赠送",
|
||||
"created_at": "2024-12-01T10:00:00Z",
|
||||
"updated_at": "2024-12-01T10:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 通用充值(保留接口)
|
||||
|
||||
**接口地址:** `POST /api/v1/finance/wallet/recharge`
|
||||
|
||||
**请求参数:**
|
||||
```json
|
||||
{
|
||||
"amount": "200.00"
|
||||
}
|
||||
```
|
||||
|
||||
## 业务规则
|
||||
|
||||
### 对公转账充值
|
||||
1. 转账订单号必须唯一,不能重复使用
|
||||
2. 充值成功后立即更新钱包余额
|
||||
3. 充值记录状态标记为成功
|
||||
|
||||
### 赠送充值
|
||||
1. 赠送充值直接标记为成功状态
|
||||
2. 立即更新钱包余额
|
||||
3. 记录操作员ID(当前为"system")
|
||||
|
||||
### 通用规则
|
||||
1. 充值金额必须大于0
|
||||
2. 用户必须存在钱包
|
||||
3. 使用乐观锁防止并发问题
|
||||
4. 所有操作都有详细的日志记录
|
||||
|
||||
## 数据库表结构
|
||||
|
||||
### recharge_records 表
|
||||
```sql
|
||||
CREATE TABLE recharge_records (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
user_id VARCHAR(36) NOT NULL,
|
||||
amount DECIMAL(20,8) NOT NULL,
|
||||
recharge_type VARCHAR(20) NOT NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'pending',
|
||||
alipay_order_id VARCHAR(64),
|
||||
transfer_order_id VARCHAR(64),
|
||||
bank_account VARCHAR(100),
|
||||
bank_name VARCHAR(100),
|
||||
gift_reason VARCHAR(200),
|
||||
notes TEXT,
|
||||
operator_id VARCHAR(36),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP NULL,
|
||||
INDEX idx_user_id (user_id),
|
||||
INDEX idx_recharge_type (recharge_type),
|
||||
INDEX idx_status (status),
|
||||
INDEX idx_alipay_order_id (alipay_order_id),
|
||||
INDEX idx_transfer_order_id (transfer_order_id)
|
||||
);
|
||||
```
|
||||
|
||||
## 错误处理
|
||||
|
||||
### 常见错误码
|
||||
- `400` - 请求参数错误
|
||||
- `401` - 用户未登录
|
||||
- `409` - 转账订单号已存在
|
||||
- `500` - 服务器内部错误
|
||||
|
||||
### 错误消息示例
|
||||
```json
|
||||
{
|
||||
"code": 409,
|
||||
"message": "转账订单号已存在",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
## 后续开发计划
|
||||
|
||||
1. **支付宝充值功能**
|
||||
- 集成支付宝支付接口
|
||||
- 实现支付回调处理
|
||||
- 添加支付状态查询接口
|
||||
|
||||
2. **充值记录查询**
|
||||
- 添加充值记录列表查询接口
|
||||
- 支持按用户、类型、状态等条件筛选
|
||||
|
||||
3. **充值统计功能**
|
||||
- 添加充值金额统计
|
||||
- 支持按时间段统计充值情况
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 所有金额计算使用 `decimal.Decimal` 类型,确保精度
|
||||
2. 使用乐观锁机制防止并发充值问题
|
||||
3. 充值操作都有完整的日志记录
|
||||
4. 对公转账充值需要人工审核确认
|
||||
5. 赠送充值需要管理员权限
|
||||
302
docs/充值记录服务优化说明.md
Normal file
302
docs/充值记录服务优化说明.md
Normal file
@@ -0,0 +1,302 @@
|
||||
# 充值记录服务优化说明
|
||||
|
||||
## 优化概述
|
||||
|
||||
本次优化主要针对充值记录服务进行了两个重要改进:
|
||||
|
||||
1. **统一钱包余额更新逻辑** - 使用钱包聚合服务的充值方法
|
||||
2. **添加事务支持** - 为所有充值相关方法添加事务保护
|
||||
|
||||
## 优化内容
|
||||
|
||||
### 1. 统一钱包余额更新逻辑
|
||||
|
||||
#### 问题分析
|
||||
之前的充值记录服务直接操作钱包仓储来更新余额,存在以下问题:
|
||||
- 代码重复:钱包余额更新逻辑在多个地方重复实现
|
||||
- 维护困难:余额更新逻辑变更需要在多个地方修改
|
||||
- 一致性风险:不同服务可能使用不同的余额更新逻辑
|
||||
|
||||
#### 解决方案
|
||||
修改充值记录服务,使用钱包聚合服务的 `Recharge` 方法来更新钱包余额:
|
||||
|
||||
**修改的方法:**
|
||||
- `TransferRecharge` - 对公转账充值
|
||||
- `GiftRecharge` - 赠送充值
|
||||
- `HandleAlipayPaymentSuccess` - 支付宝支付成功回调处理
|
||||
|
||||
**修改前:**
|
||||
```go
|
||||
// 直接操作钱包仓储
|
||||
w.AddBalance(amount)
|
||||
ok, err := s.walletRepo.UpdateBalanceWithVersion(ctx, w.ID, w.Balance.String(), w.Version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("高并发下充值失败,请重试")
|
||||
}
|
||||
```
|
||||
|
||||
**修改后:**
|
||||
```go
|
||||
// 使用钱包聚合服务
|
||||
err = s.walletService.Recharge(ctx, userID, amount)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
```
|
||||
|
||||
#### 优势
|
||||
- **代码复用**:统一使用钱包聚合服务的余额更新逻辑
|
||||
- **维护性**:余额更新逻辑变更只需在一个地方修改
|
||||
- **一致性**:确保所有充值方式使用相同的余额更新逻辑
|
||||
- **可测试性**:可以独立测试钱包聚合服务的余额更新逻辑
|
||||
|
||||
### 2. 添加事务支持
|
||||
|
||||
#### 问题分析
|
||||
充值相关方法执行多个数据库操作:
|
||||
|
||||
**TransferRecharge 方法:**
|
||||
1. 创建充值记录
|
||||
2. 更新钱包余额
|
||||
3. 更新充值记录状态为成功
|
||||
|
||||
**GiftRecharge 方法:**
|
||||
1. 创建充值记录
|
||||
2. 更新钱包余额
|
||||
|
||||
**HandleAlipayPaymentSuccess 方法:**
|
||||
1. 更新支付宝订单状态
|
||||
2. 更新充值记录状态
|
||||
3. 更新钱包余额
|
||||
|
||||
如果任何一步失败,可能导致数据不一致:
|
||||
- 充值记录已创建,但钱包余额未更新
|
||||
- 支付宝订单已更新,但充值记录未更新
|
||||
- 充值记录已更新,但钱包余额未更新
|
||||
- 重复处理导致数据异常
|
||||
|
||||
#### 解决方案
|
||||
为所有充值相关方法添加事务支持:
|
||||
|
||||
**添加事务的方法:**
|
||||
- `TransferRecharge` - 对公转账充值
|
||||
- `GiftRecharge` - 赠送充值
|
||||
- `HandleAlipayPaymentSuccess` - 支付宝支付成功回调处理
|
||||
|
||||
**修改前:**
|
||||
```go
|
||||
// 逐个执行更新操作,无事务保护
|
||||
// TransferRecharge 示例
|
||||
createdRecord, err := s.rechargeRecordRepo.Create(ctx, *rechargeRecord)
|
||||
err = s.walletService.Recharge(ctx, userID, amount)
|
||||
err = s.rechargeRecordRepo.Update(ctx, createdRecord)
|
||||
|
||||
// GiftRecharge 示例
|
||||
createdRecord, err := s.rechargeRecordRepo.Create(ctx, *rechargeRecord)
|
||||
err = s.walletService.Recharge(ctx, userID, amount)
|
||||
|
||||
// HandleAlipayPaymentSuccess 示例
|
||||
alipayOrder.MarkSuccess(tradeNo, "", "", amount, amount)
|
||||
err = s.alipayOrderRepo.Update(ctx, *alipayOrder)
|
||||
// ... 其他更新操作
|
||||
```
|
||||
|
||||
**修改后:**
|
||||
```go
|
||||
// 在事务中执行所有更新操作
|
||||
// TransferRecharge 示例
|
||||
err = s.txManager.ExecuteInTx(ctx, func(txCtx context.Context) error {
|
||||
record, err := s.rechargeRecordRepo.Create(txCtx, *rechargeRecord)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
createdRecord = record
|
||||
|
||||
err = s.walletService.Recharge(txCtx, userID, amount)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
createdRecord.MarkSuccess()
|
||||
err = s.rechargeRecordRepo.Update(txCtx, createdRecord)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
// GiftRecharge 示例
|
||||
err = s.txManager.ExecuteInTx(ctx, func(txCtx context.Context) error {
|
||||
record, err := s.rechargeRecordRepo.Create(txCtx, *rechargeRecord)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
createdRecord = record
|
||||
|
||||
err = s.walletService.Recharge(txCtx, userID, amount)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
// HandleAlipayPaymentSuccess 示例
|
||||
err = s.txManager.ExecuteInTx(ctx, func(txCtx context.Context) error {
|
||||
// 更新支付宝订单状态为成功
|
||||
alipayOrder.MarkSuccess(tradeNo, "", "", amount, amount)
|
||||
err := s.alipayOrderRepo.Update(txCtx, *alipayOrder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 更新充值记录状态为成功
|
||||
rechargeRecord.MarkSuccess()
|
||||
err = s.rechargeRecordRepo.Update(txCtx, rechargeRecord)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 使用钱包聚合服务更新钱包余额
|
||||
err = s.walletService.Recharge(txCtx, rechargeRecord.UserID, amount)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
```
|
||||
|
||||
#### 优势
|
||||
- **数据一致性**:确保所有操作要么全部成功,要么全部回滚
|
||||
- **幂等性**:防止重复处理导致的数据不一致
|
||||
- **错误处理**:统一的错误处理和回滚机制
|
||||
- **业务完整性**:保证充值记录和钱包余额状态一致
|
||||
- **原子性**:所有相关操作作为一个原子单元执行
|
||||
|
||||
## 技术实现
|
||||
|
||||
### 1. 依赖注入更新
|
||||
|
||||
**充值记录服务构造函数:**
|
||||
```go
|
||||
func NewRechargeRecordService(
|
||||
rechargeRecordRepo repositories.RechargeRecordRepository,
|
||||
alipayOrderRepo repositories.AlipayOrderRepository,
|
||||
walletRepo repositories.WalletRepository,
|
||||
walletService WalletAggregateService, // 新增
|
||||
txManager *database.TransactionManager, // 新增
|
||||
logger *zap.Logger,
|
||||
) RechargeRecordService
|
||||
```
|
||||
|
||||
**服务结构体:**
|
||||
```go
|
||||
type RechargeRecordServiceImpl struct {
|
||||
rechargeRecordRepo repositories.RechargeRecordRepository
|
||||
alipayOrderRepo repositories.AlipayOrderRepository
|
||||
walletRepo repositories.WalletRepository
|
||||
walletService WalletAggregateService // 新增
|
||||
txManager *database.TransactionManager // 新增
|
||||
logger *zap.Logger
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 事务管理
|
||||
|
||||
使用 `shared/database.TransactionManager` 进行事务管理:
|
||||
- 自动事务开始和提交
|
||||
- 异常时自动回滚
|
||||
- 支持事务超时和重试
|
||||
- 提供事务统计和监控
|
||||
|
||||
### 3. 错误处理
|
||||
|
||||
- 保持原有的错误处理机制
|
||||
- 事务失败时自动回滚所有更改
|
||||
- 详细的错误日志记录
|
||||
- 幂等性检查防止重复处理
|
||||
|
||||
## 影响评估
|
||||
|
||||
### 1. 向后兼容性
|
||||
- ✅ 应用服务层接口保持不变
|
||||
- ✅ 对调用方完全透明
|
||||
- ✅ 保持原有的错误处理机制
|
||||
|
||||
### 2. 性能影响
|
||||
- ✅ 事务开销可控,仅在支付宝回调时使用
|
||||
- ✅ 减少代码重复,提高执行效率
|
||||
- ✅ 统一余额更新逻辑,减少数据库操作
|
||||
|
||||
### 3. 数据一致性
|
||||
- ✅ 显著提高数据一致性
|
||||
- ✅ 防止部分更新导致的数据不一致
|
||||
- ✅ 支持幂等性处理
|
||||
|
||||
### 4. 维护性
|
||||
- ✅ 代码更加清晰和易于维护
|
||||
- ✅ 减少重复代码
|
||||
- ✅ 统一的错误处理机制
|
||||
|
||||
## 测试建议
|
||||
|
||||
### 1. 单元测试
|
||||
- 测试钱包聚合服务的 `Recharge` 方法
|
||||
- 测试充值记录服务的各个方法
|
||||
- 测试事务回滚机制
|
||||
|
||||
### 2. 集成测试
|
||||
- 测试完整的支付宝充值流程
|
||||
- 测试事务失败时的回滚机制
|
||||
- 测试重复回调的处理
|
||||
|
||||
### 3. 压力测试
|
||||
- 测试高并发下的充值处理
|
||||
- 测试事务超时和重试机制
|
||||
- 测试数据库连接池的使用
|
||||
|
||||
## 监控建议
|
||||
|
||||
### 1. 业务监控
|
||||
- 监控充值成功率
|
||||
- 监控事务执行时间
|
||||
- 监控事务回滚次数
|
||||
|
||||
### 2. 技术监控
|
||||
- 监控数据库连接池使用情况
|
||||
- 监控事务超时情况
|
||||
- 监控错误率和异常情况
|
||||
|
||||
## 后续优化
|
||||
|
||||
### 1. 事件驱动
|
||||
考虑使用事件驱动架构来处理充值成功后的业务逻辑:
|
||||
- 充值成功事件
|
||||
- 余额变更事件
|
||||
- 通知事件
|
||||
|
||||
### 2. 缓存优化
|
||||
- 对频繁查询的充值记录添加缓存
|
||||
- 对钱包余额添加缓存
|
||||
- 实现缓存一致性机制
|
||||
|
||||
### 3. 异步处理
|
||||
- 将非关键操作异步化
|
||||
- 使用消息队列处理充值回调
|
||||
- 实现重试机制
|
||||
|
||||
## 总结
|
||||
|
||||
本次优化通过统一钱包余额更新逻辑和添加事务支持,显著提高了充值记录服务的:
|
||||
|
||||
1. **代码质量** - 减少重复代码,提高可维护性
|
||||
2. **数据一致性** - 确保业务操作的原子性
|
||||
3. **错误处理** - 统一的错误处理和回滚机制
|
||||
4. **可测试性** - 更好的单元测试和集成测试支持
|
||||
|
||||
这些改进为后续的功能扩展和维护奠定了良好的基础。
|
||||
210
docs/智能缓存机制说明.md
Normal file
210
docs/智能缓存机制说明.md
Normal file
@@ -0,0 +1,210 @@
|
||||
# 智能缓存机制说明
|
||||
|
||||
## 概述
|
||||
|
||||
为了解决 `EnabledTables` 配置问题,我们实现了一个智能缓存决策机制。该机制允许您:
|
||||
|
||||
1. **精确控制缓存表**:通过 `EnabledTables` 和 `DisabledTables` 精确控制哪些表使用缓存
|
||||
2. **智能决策**:`CachedBaseRepositoryImpl` 会自动根据配置决定是否使用缓存
|
||||
3. **无需修改代码**:钱包Repository等代码无需修改,自动适应配置
|
||||
|
||||
## 核心组件
|
||||
|
||||
### 1. 全局缓存配置管理器 (`CacheConfigManager`)
|
||||
|
||||
```go
|
||||
// 全局实例
|
||||
var GlobalCacheConfigManager *CacheConfigManager
|
||||
|
||||
// 主要方法
|
||||
func (m *CacheConfigManager) IsTableCacheEnabled(tableName string) bool
|
||||
func (m *CacheConfigManager) IsTableCacheDisabled(tableName string) bool
|
||||
func (m *CacheConfigManager) AddEnabledTable(tableName string)
|
||||
func (m *CacheConfigManager) AddDisabledTable(tableName string)
|
||||
```
|
||||
|
||||
### 2. 智能缓存Repository (`CachedBaseRepositoryImpl`)
|
||||
|
||||
```go
|
||||
// 智能决策方法
|
||||
func (r *CachedBaseRepositoryImpl) shouldUseCacheForTable() bool
|
||||
func (r *CachedBaseRepositoryImpl) isTableCacheEnabled() bool
|
||||
|
||||
// 智能缓存方法
|
||||
func (r *CachedBaseRepositoryImpl) GetWithCache(ctx context.Context, dest interface{}, ttl time.Duration, where string, args ...interface{}) error
|
||||
func (r *CachedBaseRepositoryImpl) FindWithCache(ctx context.Context, dest interface{}, ttl time.Duration, where string, args ...interface{}) error
|
||||
```
|
||||
|
||||
### 3. 智能GORM插件 (`GormCachePlugin`)
|
||||
|
||||
```go
|
||||
// 智能缓存决策
|
||||
func (p *GormCachePlugin) shouldCache(db *gorm.DB) bool
|
||||
func (p *GormCachePlugin) shouldInvalidateTable(table string) bool
|
||||
```
|
||||
|
||||
## 工作原理
|
||||
|
||||
### 1. 配置初始化
|
||||
|
||||
```go
|
||||
// 在 cache_setup.go 中
|
||||
cacheConfig := cache.CacheConfig{
|
||||
EnabledTables: []string{
|
||||
"users",
|
||||
"product",
|
||||
"product_category",
|
||||
// 注意:这里没有 "wallets"
|
||||
},
|
||||
DisabledTables: []string{
|
||||
"audit_logs",
|
||||
"system_logs",
|
||||
},
|
||||
}
|
||||
|
||||
// 初始化全局管理器
|
||||
cache.InitCacheConfigManager(cacheConfig)
|
||||
```
|
||||
|
||||
### 2. 智能决策流程
|
||||
|
||||
当钱包Repository调用缓存方法时:
|
||||
|
||||
```go
|
||||
// 钱包Repository代码(无需修改)
|
||||
func (r *GormWalletRepository) GetByUserID(ctx context.Context, userID string) (*Wallet, error) {
|
||||
var wallet Wallet
|
||||
err := r.CachedBaseRepositoryImpl.GetWithCache(ctx, &wallet, 5*time.Minute, "user_id = ?", userID)
|
||||
return &wallet, err
|
||||
}
|
||||
```
|
||||
|
||||
**决策流程:**
|
||||
|
||||
1. **Repository层**:调用 `GetWithCache` 方法
|
||||
2. **智能决策**:`shouldUseCacheForTable()` 检查 `wallets` 表是否启用缓存
|
||||
3. **配置检查**:通过 `GlobalCacheConfigManager.IsTableCacheEnabled("wallets")` 检查
|
||||
4. **结果处理**:
|
||||
- 如果启用缓存:设置 `cache:enabled=true`,正常使用缓存
|
||||
- 如果禁用缓存:设置 `cache:disabled=true`,跳过缓存,直接查询数据库
|
||||
|
||||
### 3. 缓存失效智能控制
|
||||
|
||||
```go
|
||||
// GORM回调中的智能失效
|
||||
func (p *GormCachePlugin) afterCreate(db *gorm.DB) {
|
||||
if !p.config.AutoInvalidate || db.Error != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 只对启用缓存的表执行失效操作
|
||||
if p.shouldInvalidateTable(db.Statement.Table) {
|
||||
p.invalidateTableCache(db.Statement.Context, db.Statement.Table)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 使用场景
|
||||
|
||||
### 场景1:钱包表不启用缓存
|
||||
|
||||
```go
|
||||
// 配置中不包含 wallets
|
||||
EnabledTables: []string{
|
||||
"users",
|
||||
"product",
|
||||
// 没有 "wallets"
|
||||
}
|
||||
|
||||
// 结果:钱包查询不使用缓存,直接查询数据库
|
||||
// 不会触发缓存失效操作,避免 "context canceled" 错误
|
||||
```
|
||||
|
||||
### 场景2:钱包表启用缓存
|
||||
|
||||
```go
|
||||
// 配置中包含 wallets
|
||||
EnabledTables: []string{
|
||||
"users",
|
||||
"product",
|
||||
"wallets", // 添加钱包表
|
||||
}
|
||||
|
||||
// 结果:钱包查询正常使用缓存
|
||||
// 缓存失效操作正常执行
|
||||
```
|
||||
|
||||
### 场景3:动态调整
|
||||
|
||||
```go
|
||||
// 运行时动态启用钱包缓存
|
||||
cache.GlobalCacheConfigManager.AddEnabledTable("wallets")
|
||||
|
||||
// 运行时动态禁用钱包缓存
|
||||
cache.GlobalCacheConfigManager.AddDisabledTable("wallets")
|
||||
```
|
||||
|
||||
## 优势
|
||||
|
||||
### 1. **精确控制**
|
||||
- 通过配置精确控制哪些表使用缓存
|
||||
- 避免对不需要缓存的表执行无效操作
|
||||
|
||||
### 2. **代码无需修改**
|
||||
- Repository层代码无需修改
|
||||
- 自动适应配置变化
|
||||
|
||||
### 3. **性能优化**
|
||||
- 避免对未启用缓存的表执行缓存失效操作
|
||||
- 减少Redis无效操作,提高性能
|
||||
|
||||
### 4. **错误消除**
|
||||
- 彻底解决 `"context canceled"` 错误
|
||||
- 避免对不存在缓存数据的表执行失效操作
|
||||
|
||||
### 5. **灵活配置**
|
||||
- 支持运行时动态调整
|
||||
- 支持环境级别的配置差异
|
||||
|
||||
## 监控和调试
|
||||
|
||||
### 1. 查看表缓存状态
|
||||
|
||||
```go
|
||||
// 获取单个表状态
|
||||
status := cache.GlobalCacheConfigManager.GetTableCacheStatus("wallets")
|
||||
// 返回:{"table_name": "wallets", "enabled": false, "disabled": true, ...}
|
||||
|
||||
// 获取所有表状态
|
||||
allStatus := cache.GlobalCacheConfigManager.GetAllTableStatus()
|
||||
```
|
||||
|
||||
### 2. 日志监控
|
||||
|
||||
```go
|
||||
// 启用缓存的查询
|
||||
"执行带缓存查询" {"table": "users", "ttl": "5m0s", "where": "id = ?"}
|
||||
|
||||
// 禁用缓存的查询
|
||||
"执行无缓存查询" {"table": "wallets", "where": "user_id = ?"}
|
||||
|
||||
// 表未启用缓存的提示
|
||||
"表未启用缓存,跳过缓存操作" {"table": "wallets"}
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. **配置原则**
|
||||
- 只对查询频繁、数据变化不频繁的表启用缓存
|
||||
- 对实时性要求高的表(如钱包余额)谨慎使用缓存
|
||||
- 对日志表等大数据量表禁用缓存
|
||||
|
||||
### 2. **性能考虑**
|
||||
- 合理设置TTL,平衡缓存命中率和数据一致性
|
||||
- 监控缓存命中率和失效频率
|
||||
- 根据业务特点调整缓存策略
|
||||
|
||||
### 3. **运维建议**
|
||||
- 定期检查缓存配置的合理性
|
||||
- 监控Redis内存使用情况
|
||||
- 根据业务增长调整缓存容量
|
||||
138
docs/服务重构说明.md
Normal file
138
docs/服务重构说明.md
Normal file
@@ -0,0 +1,138 @@
|
||||
# 钱包聚合服务重构说明
|
||||
|
||||
## 重构概述
|
||||
|
||||
本次重构将钱包聚合服务中的充值记录相关功能提取到独立的充值记录服务中,实现了更好的职责分离和代码组织。
|
||||
|
||||
## 重构内容
|
||||
|
||||
### 1. 新增服务
|
||||
|
||||
#### RechargeRecordService (充值记录服务)
|
||||
- **文件位置**: `internal/domains/finance/services/recharge_record_service.go`
|
||||
- **职责**: 专门处理所有充值记录相关的业务逻辑
|
||||
|
||||
**主要功能**:
|
||||
- 对公转账充值 (`TransferRecharge`)
|
||||
- 赠送充值 (`GiftRecharge`)
|
||||
- 支付宝充值记录创建 (`CreateAlipayRecharge`)
|
||||
- 支付宝订单管理 (`CreateAlipayOrder`)
|
||||
- 支付宝支付成功回调处理 (`HandleAlipayPaymentSuccess`)
|
||||
- 充值记录查询 (`GetByID`, `GetByUserID`, `GetByTransferOrderID`)
|
||||
|
||||
### 2. 重构的服务
|
||||
|
||||
#### WalletAggregateService (钱包聚合服务)
|
||||
- **文件位置**: `internal/domains/finance/services/wallet_aggregate_service.go`
|
||||
- **重构后职责**: 专注于钱包核心功能
|
||||
|
||||
**保留功能**:
|
||||
- 钱包创建 (`CreateWallet`)
|
||||
- 通用充值 (`Recharge`)
|
||||
- 扣款 (`Deduct`)
|
||||
- 余额查询 (`GetBalance`)
|
||||
- 钱包加载 (`LoadWalletByUserId`)
|
||||
|
||||
**移除功能**:
|
||||
- 对公转账充值
|
||||
- 赠送充值
|
||||
- 支付宝充值记录管理
|
||||
- 支付宝订单管理
|
||||
- 支付宝回调处理
|
||||
|
||||
### 3. 应用服务层更新
|
||||
|
||||
#### FinanceApplicationService
|
||||
- **文件位置**: `internal/application/finance/finance_application_service_impl.go`
|
||||
- **更新内容**: 添加对 `RechargeRecordService` 的依赖
|
||||
|
||||
**修改的方法**:
|
||||
- `TransferRecharge`: 改为调用 `rechargeRecordService.TransferRecharge`
|
||||
- `GiftRecharge`: 改为调用 `rechargeRecordService.GiftRecharge`
|
||||
- `CreateAlipayRechargeOrder`: 改为调用 `rechargeRecordService.CreateAlipayRecharge`
|
||||
- `CreateAlipayOrderRecord`: 改为调用 `rechargeRecordService.CreateAlipayOrder`
|
||||
- `GetRechargeRecordByAlipayOrderID`: 改为调用 `rechargeRecordService.GetRechargeRecordByAlipayOrderID`
|
||||
- `HandleAlipayPaymentSuccess`: 改为调用 `rechargeRecordService.HandleAlipayPaymentSuccess`
|
||||
|
||||
### 4. 依赖注入更新
|
||||
|
||||
#### Container
|
||||
- **文件位置**: `internal/container/container.go`
|
||||
- **更新内容**: 添加 `finance_service.NewRechargeRecordService` 的依赖注入
|
||||
|
||||
## 重构优势
|
||||
|
||||
### 1. 职责分离
|
||||
- **钱包聚合服务**: 专注于钱包核心功能(创建、充值、扣款、查询)
|
||||
- **充值记录服务**: 专注于充值记录管理(各种充值方式、订单管理)
|
||||
|
||||
### 2. 代码组织
|
||||
- 相关功能聚合在一起,提高代码可读性
|
||||
- 减少单个服务的复杂度
|
||||
- 便于维护和测试
|
||||
|
||||
### 3. 扩展性
|
||||
- 新增充值方式时,只需要在充值记录服务中添加
|
||||
- 钱包核心功能与充值方式解耦
|
||||
|
||||
### 4. 测试友好
|
||||
- 可以独立测试钱包功能和充值记录功能
|
||||
- 减少测试的复杂度
|
||||
|
||||
## 接口变更
|
||||
|
||||
### 钱包聚合服务接口变更
|
||||
```go
|
||||
// 移除的方法
|
||||
TransferRecharge(ctx context.Context, userID string, amount decimal.Decimal, transferOrderID, notes string) (*entities.RechargeRecord, error)
|
||||
GiftRecharge(ctx context.Context, userID string, amount decimal.Decimal, giftReason, operatorID, notes string) (*entities.RechargeRecord, error)
|
||||
CreateAlipayRecharge(ctx context.Context, userID string, amount decimal.Decimal, alipayOrderID string) (*entities.RechargeRecord, error)
|
||||
CreateAlipayOrder(ctx context.Context, rechargeID, outTradeNo, subject string, amount decimal.Decimal, platform string) error
|
||||
GetRechargeRecordByAlipayOrderID(ctx context.Context, alipayOrderID string) (*entities.RechargeRecord, error)
|
||||
HandleAlipayPaymentSuccess(ctx context.Context, outTradeNo string, amount decimal.Decimal, tradeNo string) error
|
||||
|
||||
// 保留的方法
|
||||
CreateWallet(ctx context.Context, userID string) (*entities.Wallet, error)
|
||||
Recharge(ctx context.Context, userID string, amount decimal.Decimal) error
|
||||
Deduct(ctx context.Context, userID string, amount decimal.Decimal, apiCallID, transactionID, productID string) error
|
||||
GetBalance(ctx context.Context, userID string) (decimal.Decimal, error)
|
||||
LoadWalletByUserId(ctx context.Context, userID string) (*entities.Wallet, error)
|
||||
```
|
||||
|
||||
### 新增充值记录服务接口
|
||||
```go
|
||||
type RechargeRecordService interface {
|
||||
// 对公转账充值
|
||||
TransferRecharge(ctx context.Context, userID string, amount decimal.Decimal, transferOrderID, notes string) (*entities.RechargeRecord, error)
|
||||
|
||||
// 赠送充值
|
||||
GiftRecharge(ctx context.Context, userID string, amount decimal.Decimal, giftReason, operatorID, notes string) (*entities.RechargeRecord, error)
|
||||
|
||||
// 支付宝充值
|
||||
CreateAlipayRecharge(ctx context.Context, userID string, amount decimal.Decimal, alipayOrderID string) (*entities.RechargeRecord, error)
|
||||
GetRechargeRecordByAlipayOrderID(ctx context.Context, alipayOrderID string) (*entities.RechargeRecord, error)
|
||||
|
||||
// 支付宝订单管理
|
||||
CreateAlipayOrder(ctx context.Context, rechargeID, outTradeNo, subject string, amount decimal.Decimal, platform string) error
|
||||
HandleAlipayPaymentSuccess(ctx context.Context, outTradeNo string, amount decimal.Decimal, tradeNo string) error
|
||||
|
||||
// 通用查询
|
||||
GetByID(ctx context.Context, id string) (*entities.RechargeRecord, error)
|
||||
GetByUserID(ctx context.Context, userID string) ([]entities.RechargeRecord, error)
|
||||
GetByTransferOrderID(ctx context.Context, transferOrderID string) (*entities.RechargeRecord, error)
|
||||
}
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **向后兼容性**: 应用服务层的公共接口保持不变,对调用方透明
|
||||
2. **事务处理**: 充值记录服务中的方法仍然保持原有的事务处理逻辑
|
||||
3. **错误处理**: 保持原有的错误处理机制和日志记录
|
||||
4. **依赖关系**: 充值记录服务依赖钱包仓储来更新钱包余额
|
||||
|
||||
## 后续优化建议
|
||||
|
||||
1. **实体扩展**: 考虑在 `RechargeRecord` 实体中添加 `GiftReason` 和 `OperatorID` 字段
|
||||
2. **事件驱动**: 考虑使用事件驱动架构来处理充值成功后的业务逻辑
|
||||
3. **缓存优化**: 对频繁查询的充值记录添加缓存机制
|
||||
4. **监控指标**: 添加充值相关的业务监控指标
|
||||
117
docs/钱包交易记录功能说明.md
Normal file
117
docs/钱包交易记录功能说明.md
Normal file
@@ -0,0 +1,117 @@
|
||||
# 钱包扣款记录功能说明
|
||||
|
||||
## 功能概述
|
||||
|
||||
为钱包系统添加了简单的扣款记录功能,记录API调用产生的扣款操作,包含扣款金额、用户ID和关联的ApiCallID。
|
||||
|
||||
## 新增功能
|
||||
|
||||
### 1. 钱包扣款记录实体 (WalletTransaction)
|
||||
|
||||
**位置**: `internal/domains/finance/entities/wallet_transaction.go`
|
||||
|
||||
**主要字段**:
|
||||
- `ID`: 扣款记录唯一标识
|
||||
- `UserID`: 扣款用户ID
|
||||
- `ApiCallID`: 关联API调用ID
|
||||
- `Amount`: 扣款金额
|
||||
- `CreatedAt`: 创建时间
|
||||
|
||||
### 2. 钱包扣款记录仓储
|
||||
|
||||
**接口**: `internal/domains/finance/repositories/wallet_transaction_repository_interface.go`
|
||||
**实现**: `internal/infrastructure/database/repositories/finance/gorm_wallet_transaction_repository.go`
|
||||
|
||||
**主要方法**:
|
||||
- `Create`: 创建扣款记录
|
||||
- `GetByUserID`: 根据用户ID获取扣款记录
|
||||
- `GetByApiCallID`: 根据API调用ID获取扣款记录
|
||||
|
||||
### 3. 钱包聚合服务更新
|
||||
|
||||
**位置**: `internal/domains/finance/services/wallet_aggregate_service.go`
|
||||
|
||||
**更新内容**:
|
||||
- 添加了交易记录仓储依赖
|
||||
- 更新了`Deduct`方法,支持记录扣款并关联ApiCall
|
||||
|
||||
**方法签名**:
|
||||
```go
|
||||
// 扣款方法
|
||||
Deduct(ctx context.Context, userID string, amount decimal.Decimal, apiCallID string) error
|
||||
```
|
||||
|
||||
### 4. API应用服务更新
|
||||
|
||||
**位置**: `internal/application/api/api_application_service.go`
|
||||
|
||||
**更新内容**:
|
||||
- 更新了API调用中的扣款逻辑,现在会记录扣款并关联ApiCall
|
||||
|
||||
## 数据库变更
|
||||
|
||||
### 新增表: wallet_transactions
|
||||
|
||||
```sql
|
||||
CREATE TABLE wallet_transactions (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
user_id VARCHAR(36) NOT NULL,
|
||||
api_call_id VARCHAR(64) NOT NULL,
|
||||
amount DECIMAL(20,8) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL,
|
||||
updated_at TIMESTAMP NOT NULL,
|
||||
deleted_at TIMESTAMP,
|
||||
INDEX idx_user_id (user_id),
|
||||
INDEX idx_api_call_id (api_call_id),
|
||||
INDEX idx_created_at (created_at)
|
||||
);
|
||||
```
|
||||
|
||||
## 使用示例
|
||||
|
||||
### API调用扣款
|
||||
|
||||
当用户调用API时,系统会自动:
|
||||
1. 验证用户钱包余额
|
||||
2. 扣减相应费用
|
||||
3. 创建扣款记录,关联ApiCall
|
||||
|
||||
```go
|
||||
// 在API应用服务中
|
||||
err = s.walletService.Deduct(ctx, apiUser.UserId, subscription.Price, apiCall.ID)
|
||||
```
|
||||
|
||||
### 查询扣款记录
|
||||
|
||||
```go
|
||||
// 查询用户扣款记录
|
||||
transactions, err := transactionRepo.GetByUserID(ctx, userID, 10, 0)
|
||||
|
||||
// 根据API调用ID查询扣款记录
|
||||
transaction, err := transactionRepo.GetByApiCallID(ctx, apiCallID)
|
||||
```
|
||||
|
||||
## 依赖注入配置
|
||||
|
||||
在容器配置中已添加钱包扣款记录仓储的依赖注入:
|
||||
|
||||
```go
|
||||
// 钱包扣款记录仓储
|
||||
fx.Annotate(
|
||||
finance_repo.NewGormWalletTransactionRepository,
|
||||
fx.As(new(domain_finance_repo.WalletTransactionRepository)),
|
||||
),
|
||||
```
|
||||
|
||||
## 优势
|
||||
|
||||
1. **简单实用**: 只记录必要的信息
|
||||
2. **API调用关联**: 可以追踪每个API调用产生的费用
|
||||
3. **用户追踪**: 可以查看用户的扣款历史
|
||||
4. **轻量级**: 不增加系统复杂度
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 扣款记录创建失败不会影响钱包余额更新,确保核心业务不受影响
|
||||
2. 所有金额计算使用decimal类型,确保精度
|
||||
3. 支持软删除,便于数据恢复
|
||||
Reference in New Issue
Block a user