Files
verify/backend/scripts/create_manual_deduct_doc.go
T
admin ea8ffb6c74 fix: 订阅模式登录验证、永久会员类型区分、动态代码HTTP返回值修复、侧边栏滚动位置保持
- 修复订阅模式登录时错误检查余额的问题
- 区分无限余额和永久订阅两种永久会员类型
- 修复动态代码HTTP请求返回值在JS中无法正确访问的问题
- 添加侧边栏滚动位置保持功能
- 移除developer角色相关代码,统一使用admin
- 添加缺失的i18n翻译key
2026-05-01 16:39:31 +08:00

350 lines
7.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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("手动扣费文档创建成功")
}