Initial commit: 网络验证平台
This commit is contained in:
@@ -0,0 +1,349 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"verification-platform-backend/internal/database"
|
||||
"verification-platform-backend/internal/model"
|
||||
)
|
||||
|
||||
func main() {
|
||||
database.Init()
|
||||
|
||||
docContent := `# 手动扣费 API
|
||||
|
||||
## 概述
|
||||
|
||||
手动扣费功能允许开发者在余额模式下,通过 API 自行控制扣费时机和金额。这为开发者提供了最大的灵活性,可以根据业务需求实现自定义的计费逻辑。
|
||||
|
||||
## 前提条件
|
||||
|
||||
1. 应用的运营模式必须设置为**余额模式**
|
||||
2. 扣费方式必须设置为**手动扣费**
|
||||
|
||||
## 扣费方式说明
|
||||
|
||||
扣费方式分为两级选择:
|
||||
|
||||
### 第一级:扣费方式
|
||||
|
||||
| 方式 | 说明 |
|
||||
|------|------|
|
||||
| 自动扣费 | 系统自动触发扣费 |
|
||||
| 手动扣费 | 通过 API 自行控制扣费 |
|
||||
|
||||
### 第二级:自动扣费类型(仅自动扣费时显示)
|
||||
|
||||
| 类型 | 说明 |
|
||||
|------|------|
|
||||
| 登录扣费 | 每次登录验证时扣费 |
|
||||
| 计时扣费 | 按设定的时间间隔自动扣费 |
|
||||
|
||||
### 计时扣费配置
|
||||
|
||||
选择计时扣费后,可自定义扣费间隔:
|
||||
|
||||
- **间隔值**:1-9999 之间的整数
|
||||
- **时间单位**:分钟、小时、天
|
||||
|
||||
例如:设置为 "每 30 分钟扣费一次" 或 "每 2 小时扣费一次"
|
||||
|
||||
## 接口详情
|
||||
|
||||
### 请求地址
|
||||
|
||||
POST /api/v1/dev/applications/:id/deduct
|
||||
|
||||
### 请求头
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| Authorization | string | 是 | Bearer {token},开发者登录后获取的令牌 |
|
||||
| Content-Type | string | 是 | application/json |
|
||||
|
||||
### 路径参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| id | integer | 是 | 应用ID |
|
||||
|
||||
### 请求参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| user_id | integer | 是 | 要扣费的用户ID |
|
||||
| amount | number | 是 | 扣费金额,必须大于0 |
|
||||
| description | string | 否 | 扣费描述/原因 |
|
||||
|
||||
### 请求示例
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"user_id": 123,
|
||||
"amount": 10.5,
|
||||
"description": "使用高级功能扣费"
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
### 响应示例
|
||||
|
||||
#### 成功响应
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"user_id": 123,
|
||||
"username": "testuser",
|
||||
"amount": 10.5,
|
||||
"balance_before": 100.5,
|
||||
"balance_after": 90.0,
|
||||
"description": "使用高级功能扣费",
|
||||
"message": "扣费成功"
|
||||
}
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
#### 错误响应
|
||||
|
||||
**应用不存在**
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"code": 404,
|
||||
"message": "应用不存在"
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
**非余额模式**
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"code": 400,
|
||||
"message": "只有余额模式的应用才支持手动扣费"
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
**未开启手动扣费**
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"code": 400,
|
||||
"message": "该应用未开启手动扣费模式,请先在设置中修改扣费频率为手动扣费"
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
**用户不存在**
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"code": 404,
|
||||
"message": "用户不存在"
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
**余额不足**
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"code": 400,
|
||||
"message": "用户余额不足,当前余额: 5.00,需扣除: 10.50"
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
**永久会员**
|
||||
|
||||
` + "```json" + `
|
||||
{
|
||||
"code": 400,
|
||||
"message": "该用户为永久会员,无法扣费"
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
## 使用场景
|
||||
|
||||
### 1. 按次计费
|
||||
|
||||
用户每次使用特定功能时扣费:
|
||||
|
||||
` + "```javascript" + `
|
||||
// 用户使用高级分析功能
|
||||
async function useAdvancedAnalysis(userId) {
|
||||
const response = await fetch('/api/v1/dev/applications/1/deduct', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + token,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
user_id: userId,
|
||||
amount: 5.0,
|
||||
description: '使用高级分析功能'
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
if (result.code === 200) {
|
||||
// 扣费成功,执行功能
|
||||
return true;
|
||||
} else {
|
||||
// 扣费失败,提示用户
|
||||
alert(result.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
### 2. 阶梯计费
|
||||
|
||||
根据使用量阶梯定价:
|
||||
|
||||
` + "```javascript" + `
|
||||
function calculatePrice(usage) {
|
||||
if (usage <= 100) {
|
||||
return 1.0; // 前100次,每次1元
|
||||
} else if (usage <= 500) {
|
||||
return 0.8; // 101-500次,每次0.8元
|
||||
} else {
|
||||
return 0.5; // 500次以上,每次0.5元
|
||||
}
|
||||
}
|
||||
|
||||
async function chargeUser(userId, currentUsage) {
|
||||
const price = calculatePrice(currentUsage);
|
||||
// 调用扣费API...
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
### 3. 动态定价
|
||||
|
||||
根据时间段或活动动态调整价格:
|
||||
|
||||
` + "```javascript" + `
|
||||
function getDynamicPrice() {
|
||||
const hour = new Date().getHours();
|
||||
const dayOfWeek = new Date().getDay();
|
||||
|
||||
// 周末打折
|
||||
if (dayOfWeek === 0 || dayOfWeek === 6) {
|
||||
return 5.0 * 0.8;
|
||||
}
|
||||
|
||||
// 深夜时段打折
|
||||
if (hour >= 22 || hour < 6) {
|
||||
return 5.0 * 0.5;
|
||||
}
|
||||
|
||||
return 5.0;
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
### 4. 批量扣费
|
||||
|
||||
对多个用户批量扣费:
|
||||
|
||||
` + "```javascript" + `
|
||||
async function batchDeduct(users) {
|
||||
const results = [];
|
||||
|
||||
for (const user of users) {
|
||||
try {
|
||||
const response = await fetch('/api/v1/dev/applications/1/deduct', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + token,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
user_id: user.id,
|
||||
amount: user.amount,
|
||||
description: user.description
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
results.push({
|
||||
user_id: user.id,
|
||||
success: result.code === 200,
|
||||
message: result.message
|
||||
});
|
||||
} catch (error) {
|
||||
results.push({
|
||||
user_id: user.id,
|
||||
success: false,
|
||||
message: error.message
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
` + "```" + `
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **余额检查**: 调用扣费接口前,建议先检查用户余额是否充足
|
||||
2. **幂等性**: 如果业务需要保证幂等性,请在业务层实现去重逻辑
|
||||
3. **并发控制**: 高并发场景下,建议使用锁机制防止余额扣成负数
|
||||
4. **记录保存**: 每次扣费都会自动创建消费记录,可在后台查看
|
||||
5. **错误处理**: 请妥善处理各种错误情况,给用户友好的提示
|
||||
|
||||
## 与自动扣费的区别
|
||||
|
||||
| 特性 | 手动扣费 | 自动扣费 |
|
||||
|------|----------|----------|
|
||||
| 扣费时机 | 开发者自行控制 | 系统自动执行 |
|
||||
| 扣费金额 | 每次可不同 | 固定金额 |
|
||||
| 灵活性 | 高 | 低 |
|
||||
| 实现复杂度 | 需要开发者实现 | 无需开发 |
|
||||
| 适用场景 | 复杂计费逻辑 | 简单按时/按次计费 |
|
||||
|
||||
## 相关接口
|
||||
|
||||
- [获取用户信息](/docs/app-api-docs#获取账户信息) - 查询用户当前余额
|
||||
- [用户充值](/docs/app-api-docs#卡密充值) - 用户通过卡密充值
|
||||
- [消费记录](/docs/finance) - 查看扣费记录`
|
||||
|
||||
var devCategory model.DocCategory
|
||||
if err := database.DB.Where("slug = ?", "dev-docs").First(&devCategory).Error; err != nil {
|
||||
devCategory = model.DocCategory{
|
||||
Name: "开发者文档",
|
||||
Slug: "dev-docs",
|
||||
Description: "开发者API接口文档",
|
||||
Sort: 90,
|
||||
}
|
||||
if err := database.DB.Create(&devCategory).Error; err != nil {
|
||||
log.Printf("创建开发者文档分类失败: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var existingDoc model.Doc
|
||||
if err := database.DB.Where("slug = ?", "manual-deduct-api").First(&existingDoc).Error; err == nil {
|
||||
existingDoc.Content = docContent
|
||||
if err := database.DB.Save(&existingDoc).Error; err != nil {
|
||||
log.Printf("更新手动扣费文档失败: %v", err)
|
||||
} else {
|
||||
log.Println("手动扣费文档更新成功")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
doc := model.Doc{
|
||||
Title: "手动扣费 API",
|
||||
CategoryID: &devCategory.ID,
|
||||
Slug: "manual-deduct-api",
|
||||
Content: docContent,
|
||||
Summary: "余额模式下通过API自行控制扣费时机和金额,支持按次计费、阶梯计费、动态定价等场景",
|
||||
Icon: "💳",
|
||||
Sort: 10,
|
||||
Status: "published",
|
||||
}
|
||||
|
||||
if err := database.DB.Create(&doc).Error; err != nil {
|
||||
log.Printf("创建手动扣费文档失败: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Println("手动扣费文档创建成功")
|
||||
}
|
||||
Reference in New Issue
Block a user