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

1001 lines
32 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()
log.Println("=== 查看当前所有文档 ===")
var docs []model.Doc
if err := database.DB.Find(&docs).Error; err != nil {
log.Printf("查询文档失败: %v", err)
return
}
for _, doc := range docs {
log.Printf("ID: %d, Slug: %s, Title: %s", doc.ID, doc.Slug, doc.Title)
}
log.Println("\n=== 删除平台API文档 ===")
platformAPISlugs := []string{
"api-auth",
"api-verify",
"api-card",
"api-user",
"api-constant",
"api-constants",
"api-variable",
"api-variables",
"api-function",
"api-functions",
"api-check-update",
"api-announcements",
"api-get-dynamic-code",
"api-update-dynamic-code",
}
for _, slug := range platformAPISlugs {
if err := database.DB.Where("slug = ?", slug).Delete(&model.Doc{}).Error; err != nil {
log.Printf("删除文档 %s 失败: %v", slug, err)
} else {
log.Printf("已删除文档: %s", slug)
}
}
log.Println("\n=== 创建动态函数文档 ===")
var apiCat model.DocCategory
if err := database.DB.Where("slug = ?", "api").First(&apiCat).Error; err != nil {
log.Printf("未找到API分类: %v", err)
return
}
dynamicCodeContent := "# 动态函数接口\n\n" +
"动态函数允许开发者为应用创建自定义的业务逻辑,通过JavaScript代码实现灵活的数据处理和业务规则。\n\n" +
"---\n\n" +
"## 概述\n\n" +
"动态函数是基于JavaScript的自定义代码,可以在应用运行时动态执行。开发者可以通过动态函数实现:\n\n" +
"- 动态定价计算\n" +
"- 权限验证逻辑\n" +
"- 业务规则判断\n" +
"- 用户数据处理\n" +
"- 自动化操作指令\n\n" +
"---\n\n" +
"## 获取动态函数列表\n\n" +
"### 接口地址\n\n" +
"`GET /api/v1/app/:appKey/dynamic-code`\n\n" +
"### 请求头\n\n" +
"```\n" +
"Authorization: Bearer {token}\n" +
"```\n\n" +
"### 路径参数\n\n" +
"| 参数名 | 类型 | 必填 | 说明 |\n" +
"|--------|------|------|------|\n" +
"| appKey | string | 是 | 应用密钥 |\n\n" +
"### 响应示例\n\n" +
"```json\n" +
"{\n" +
" \"code\": 200,\n" +
" \"message\": \"操作成功\",\n" +
" \"data\": [\n" +
" {\n" +
" \"id\": 1,\n" +
" \"name\": \"加法函数\",\n" +
" \"key\": \"add\",\n" +
" \"description\": \"实现数字加法运算\",\n" +
" \"status\": \"active\",\n" +
" \"created_at\": \"2024-01-01T00:00:00Z\"\n" +
" }\n" +
" ]\n" +
"}\n" +
"```\n\n" +
"### 字段说明\n\n" +
"| 字段名 | 类型 | 说明 |\n" +
"|--------|------|------|\n" +
"| id | number | 动态函数ID |\n" +
"| name | string | 动态函数名称 |\n" +
"| key | string | 动态函数唯一标识 |\n" +
"| description | string | 描述 |\n" +
"| status | string | 状态(active、inactive |\n" +
"| created_at | string | 创建时间 |\n\n" +
"---\n\n" +
"## 执行动态函数\n\n" +
"### 接口地址\n\n" +
"`POST /api/v1/app/:appKey/dynamic-code/:key/execute`\n\n" +
"### 请求头\n\n" +
"```\n" +
"Authorization: Bearer {token}\n" +
"Content-Type: application/json\n" +
"```\n\n" +
"### 路径参数\n\n" +
"| 参数名 | 类型 | 必填 | 说明 |\n" +
"|--------|------|------|------|\n" +
"| appKey | string | 是 | 应用密钥 |\n" +
"| key | string | 是 | 动态函数标识 |\n\n" +
"### 请求体\n\n" +
"```json\n" +
"{\n" +
" \"params\": {\n" +
" \"param1\": \"value1\",\n" +
" \"param2\": \"value2\"\n" +
" },\n" +
" \"user_id\": 123\n" +
"}\n" +
"```\n\n" +
"### 参数说明\n\n" +
"| 参数名 | 类型 | 必填 | 说明 |\n" +
"|--------|------|------|------|\n" +
"| params | object | 否 | 自定义参数对象,键值对形式传递 |\n" +
"| user_id | number | 否 | 用户ID,提供后会注入当前用户信息 |\n\n" +
"### 响应示例\n\n" +
"```json\n" +
"{\n" +
" \"code\": 200,\n" +
" \"message\": \"操作成功\",\n" +
" \"data\": {\n" +
" \"result\": \"执行结果\",\n" +
" \"execution_time\": 1\n" +
" }\n" +
"}\n" +
"```\n\n" +
"### 字段说明\n\n" +
"| 字段名 | 类型 | 说明 |\n" +
"|--------|------|------|\n" +
"| result | any | 代码执行结果,可以是任意类型 |\n" +
"| execution_time | number | 执行时间(毫秒) |\n\n" +
"---\n\n" +
"## 注入的数据\n\n" +
"### 1. 应用配置数据 (app)\n\n" +
"动态函数可以访问应用的完整配置信息:\n\n" +
"```javascript\n" +
"app.name\n" +
"app.description\n" +
"app.app_key\n" +
"app.status\n" +
"app.billing_type\n" +
"app.point_price\n" +
"app.points_per_cycle\n" +
"app.point_deduction_cycle\n" +
"app.enable_trial\n" +
"app.trial_type\n" +
"app.trial_duration\n" +
"app.trial_points\n" +
"app.enable_free_period\n" +
"app.free_period_type\n" +
"app.free_period_start\n" +
"app.free_period_end\n" +
"app.free_period_weekdays\n" +
"app.free_period_start_time\n" +
"app.free_period_end_time\n" +
"app.max_devices\n" +
"app.bind_type\n" +
"app.multi_open\n" +
"app.multi_open_mode\n" +
"app.max_instances\n" +
"app.login_policy\n" +
"app.max_attempts\n" +
"app.lock_duration\n" +
"app.heartbeat_interval\n" +
"app.heartbeat_timeout\n" +
"app.change_limit\n" +
"app.change_interval\n" +
"app.change_exceed_action\n" +
"app.change_deduct_amount\n" +
"```\n\n" +
"#### 应用配置字段说明\n\n" +
"| 字段名 | 类型 | 说明 |\n" +
"|--------|------|------|\n" +
"| name | string | 应用名称 |\n" +
"| description | string | 应用描述 |\n" +
"| app_key | string | 应用密钥 |\n" +
"| status | string | 应用状态 |\n" +
"| billing_type | string | 计费方式 |\n" +
"| point_price | number | 点数价格 |\n" +
"| points_per_cycle | number | 每周期扣点数 |\n" +
"| point_deduction_cycle | string | 扣点周期 |\n" +
"| enable_trial | boolean | 是否启用试用 |\n" +
"| trial_type | string | 试用类型 |\n" +
"| trial_duration | number | 试用时长 |\n" +
"| trial_points | number | 试用点数 |\n" +
"| enable_free_period | boolean | 是否启用免费时段 |\n" +
"| free_period_type | string | 免费时段类型 |\n" +
"| free_period_start | string | 免费时段开始 |\n" +
"| free_period_end | string | 免费时段结束 |\n" +
"| free_period_weekdays | string | 免费时段星期 |\n" +
"| free_period_start_time | string | 免费时段开始时间 |\n" +
"| free_period_end_time | string | 免费时段结束时间 |\n" +
"| max_devices | number | 最大设备数 |\n" +
"| bind_type | string | 绑定方式 |\n" +
"| multi_open | boolean | 是否允许多开 |\n" +
"| multi_open_mode | string | 多开模式 |\n" +
"| max_instances | number | 最大实例数 |\n" +
"| login_policy | string | 登录策略 |\n" +
"| max_attempts | number | 最大尝试次数 |\n" +
"| lock_duration | number | 锁定时长 |\n" +
"| heartbeat_interval | number | 心跳间隔 |\n" +
"| heartbeat_timeout | number | 心跳超时 |\n" +
"| change_limit | number | 变更限制 |\n" +
"| change_interval | number | 变更间隔 |\n" +
"| change_exceed_action | string | 超限操作 |\n" +
"| change_deduct_amount | number | 超限扣点数 |\n\n" +
"### 2. 用户信息 (user)\n\n" +
"如果请求中提供了 `user_id`,会自动注入当前用户的信息:\n\n" +
"```javascript\n" +
"user.id\n" +
"user.username\n" +
"user.email\n" +
"user.status\n" +
"user.points\n" +
"user.is_trial_user\n" +
"user.expiry_at\n" +
"user.last_login_at\n" +
"```\n\n" +
"#### 用户信息字段说明\n\n" +
"| 字段名 | 类型 | 说明 |\n" +
"|--------|------|------|\n" +
"| id | number | 用户ID |\n" +
"| username | string | 用户名 |\n" +
"| email | string | 邮箱 |\n" +
"| status | string | 用户状态 |\n" +
"| points | number | 积分 |\n" +
"| is_trial_user | boolean | 是否试用用户 |\n" +
"| expiry_at | string | 到期时间 |\n" +
"| last_login_at | string | 最后登录时间 |\n\n" +
"### 3. 自定义参数\n\n" +
"通过请求的 `params` 参数传递的自定义数据,可以直接在代码中使用:\n\n" +
"```javascript\n" +
"// 请求参数: {\"params\": {\"a\": 10, \"b\": 20, \"name\": \"张三\"}}\n\n" +
"a + b\n" +
"name.toUpperCase()\n" +
"```\n\n" +
"---\n\n" +
"## JavaScript代码编写规范\n\n" +
"### 1. 参数使用\n\n" +
"动态函数可以直接使用请求参数中传递的变量,无需额外定义:\n\n" +
"```javascript\n" +
"a + b\n" +
"```\n\n" +
"**请求参数**`{\"params\": {\"a\": 10, \"b\": 20}}`\n\n" +
"**返回结果**`30`\n\n" +
"---\n\n" +
"### 2. 函数定义与调用\n\n" +
"可以定义函数并在最后一行调用:\n\n" +
"```javascript\n" +
"function calculate(x, y) {\n" +
" return Math.sqrt(x * x + y * y);\n" +
"}\n\n" +
"calculate(x, y)\n" +
"```\n\n" +
"**请求参数**`{\"params\": {\"x\": 3, \"y\": 4}}`\n\n" +
"**返回结果**`5`\n\n" +
"---\n\n" +
"### 3. 复杂逻辑\n\n" +
"支持完整的JavaScript语法,包括控制流、循环、对象操作等:\n\n" +
"```javascript\n" +
"function processScore(score) {\n" +
" if (score >= 90) {\n" +
" return \"优秀\";\n" +
" } else if (score >= 60) {\n" +
" return \"及格\";\n" +
" } else {\n" +
" return \"不及格\";\n" +
" }\n" +
"}\n\n" +
"processScore(score)\n" +
"```\n\n" +
"---\n\n" +
"### 4. 返回值规则\n\n" +
"- **最后一个表达式的值即为返回值**\n" +
"- **不要在全局作用域使用return语句**\n" +
"- 可以返回任意类型:数字、字符串、布尔值、对象、数组等\n\n" +
"---\n\n" +
"### 5. 使用注入数据\n\n" +
"#### 使用应用配置\n\n" +
"```javascript\n" +
"function getAppInfo() {\n" +
" return {\n" +
" name: app.name,\n" +
" status: app.status,\n" +
" billing_type: app.billing_type,\n" +
" max_devices: app.max_devices,\n" +
" enable_trial: app.enable_trial\n" +
" };\n" +
"}\n\n" +
"getAppInfo()\n" +
"```\n\n" +
"#### 使用用户信息\n\n" +
"```javascript\n" +
"function getUserInfo() {\n" +
" if (!user) {\n" +
" return { error: \"用户不存在\" };\n" +
" }\n" +
" \n" +
" return {\n" +
" username: user.username,\n" +
" points: user.points,\n" +
" is_trial_user: user.is_trial_user,\n" +
" status: user.status\n" +
" };\n" +
"}\n\n" +
"getUserInfo()\n" +
"```\n\n" +
"#### 组合使用\n\n" +
"```javascript\n" +
"function checkUserPermission() {\n" +
" if (!user) {\n" +
" return { error: \"用户不存在\" };\n" +
" }\n" +
" \n" +
" if (user.status !== \"active\") {\n" +
" return { error: \"用户状态异常\" };\n" +
" }\n" +
" \n" +
" if (app.max_devices > 0) {\n" +
" return {\n" +
" allowed: true,\n" +
" max_devices: app.max_devices,\n" +
" user_status: user.status\n" +
" };\n" +
" }\n" +
" \n" +
" return { allowed: false, reason: \"应用未设置设备限制\" };\n" +
"}\n\n" +
"checkUserPermission()\n" +
"```\n\n" +
"---\n\n" +
"### 6. 常见示例\n\n" +
"#### 简单计算\n\n" +
"```javascript\n" +
"price * quantity\n" +
"```\n\n" +
"#### 字符串拼接\n\n" +
"```javascript\n" +
"name + \"的年龄是\" + age + \"岁\"\n" +
"```\n\n" +
"#### 条件判断\n\n" +
"```javascript\n" +
"score >= 60 ? \"及格\" : \"不及格\"\n" +
"```\n\n" +
"#### 对象返回\n\n" +
"```javascript\n" +
"{\n" +
" sum: a + b,\n" +
" product: a * b,\n" +
" difference: a - b\n" +
"}\n" +
"```\n\n" +
"#### 数组操作\n\n" +
"```javascript\n" +
"function sumArray(numbers) {\n" +
" let total = 0;\n" +
" for (let i = 0; i < numbers.length; i++) {\n" +
" total += numbers[i];\n" +
" }\n" +
" return total;\n" +
"}\n\n" +
"sumArray([1, 2, 3, 4, 5])\n" +
"```\n\n" +
"---\n\n" +
"### 7. 注意事项\n\n" +
"1. **全局作用域不能使用return**return只能在函数内部使用\n" +
"2. **参数变量直接使用**:无需重新定义\n" +
"3. **最后一行是返回值**:确保最后一行是需要返回的表达式\n" +
"4. **支持ES6语法**:可以使用let、const、箭头函数等\n" +
"5. **内置对象可用**Math、Date、JSON等JavaScript内置对象都可以使用\n\n" +
"---\n\n" +
"## 操作指令\n\n" +
"动态函数可以返回操作指令,后端会安全地执行这些指令。\n\n" +
"### 1. 加时指令\n\n" +
"为用户延长使用时间。\n\n" +
"#### 指令格式\n\n" +
"```javascript\n" +
"{\n" +
" action: \"extend_time\",\n" +
" user_id: 123,\n" +
" days: 7,\n" +
" reason: \"用户申请延期\"\n" +
"}\n" +
"```\n\n" +
"#### 字段说明\n\n" +
"| 字段名 | 类型 | 必填 | 说明 |\n" +
"|--------|------|------|------|\n" +
"| action | string | 是 | 固定值:\"extend_time\" |\n" +
"| user_id | number | 是 | 用户ID |\n" +
"| days | number | 是 | 延长天数 |\n" +
"| reason | string | 否 | 延长原因 |\n\n" +
"#### 示例\n\n" +
"```javascript\n" +
"function autoExtendTime(userId, userLevel) {\n" +
" let days = 0;\n" +
" \n" +
" if (userLevel === \"vip\") {\n" +
" days = 30;\n" +
" } else if (userLevel === \"premium\") {\n" +
" days = 15;\n" +
" } else if (userLevel === \"normal\") {\n" +
" days = 7;\n" +
" }\n" +
" \n" +
" return {\n" +
" action: \"extend_time\",\n" +
" user_id: userId,\n" +
" days: days,\n" +
" reason: \"根据用户等级自动加时\"\n" +
" };\n" +
"}\n\n" +
"autoExtendTime(123, \"vip\")\n" +
"```\n\n" +
"---\n\n" +
"### 2. 扣点指令\n\n" +
"扣除用户积分。\n\n" +
"#### 指令格式\n\n" +
"```javascript\n" +
"{\n" +
" action: \"deduct_points\",\n" +
" user_id: 123,\n" +
" points: 100,\n" +
" reason: \"使用功能扣点\"\n" +
"}\n" +
"```\n\n" +
"#### 字段说明\n\n" +
"| 字段名 | 类型 | 必填 | 说明 |\n" +
"|--------|------|------|------|\n" +
"| action | string | 是 | 固定值:\"deduct_points\" |\n" +
"| user_id | number | 是 | 用户ID |\n" +
"| points | number | 是 | 扣除点数 |\n" +
"| reason | string | 否 | 扣点原因 |\n\n" +
"#### 示例\n\n" +
"```javascript\n" +
"function autoDeductPoints(userId, usage) {\n" +
" if (!user || user.points < usage) {\n" +
" return { error: \"积分不足\" };\n" +
" }\n" +
" \n" +
" return {\n" +
" action: \"deduct_points\",\n" +
" user_id: userId,\n" +
" points: usage,\n" +
" reason: \"功能使用扣点\"\n" +
" };\n" +
"}\n\n" +
"autoDeductPoints(123, 50)\n" +
"```\n\n" +
"---\n\n" +
"## 完整示例\n\n" +
"### 示例1:动态定价\n\n" +
"#### 场景\n" +
"根据用户等级和应用设置,动态计算价格。\n\n" +
"#### 请求\n\n" +
"```json\n" +
"POST /api/v1/app/your-app-key/dynamic-code/calculate-price/execute\n" +
"{\n" +
" \"params\": {\n" +
" \"basePrice\": 100,\n" +
" \"userType\": \"new\"\n" +
" }\n" +
"}\n" +
"```\n\n" +
"#### 动态函数代码\n\n" +
"```javascript\n" +
"function calculatePrice(basePrice, userType) {\n" +
" let finalPrice = basePrice;\n" +
" \n" +
" if (app.enable_trial && userType === \"new\") {\n" +
" finalPrice = finalPrice * 0.5;\n" +
" }\n" +
" \n" +
" if (userType === \"vip\") {\n" +
" finalPrice = finalPrice * 0.8;\n" +
" }\n" +
" \n" +
" return {\n" +
" original_price: basePrice,\n" +
" user_type: userType,\n" +
" enable_trial: app.enable_trial,\n" +
" final_price: finalPrice,\n" +
" discount: basePrice - finalPrice\n" +
" };\n" +
"}\n\n" +
"calculatePrice(basePrice, userType)\n" +
"```\n\n" +
"#### 响应\n\n" +
"```json\n" +
"{\n" +
" \"code\": 200,\n" +
" \"message\": \"操作成功\",\n" +
" \"data\": {\n" +
" \"result\": {\n" +
" \"original_price\": 100,\n" +
" \"user_type\": \"new\",\n" +
" \"enable_trial\": true,\n" +
" \"final_price\": 50,\n" +
" \"discount\": 50\n" +
" },\n" +
" \"execution_time\": 1\n" +
" }\n" +
"}\n" +
"```\n\n" +
"---\n\n" +
"### 示例2:权限验证\n\n" +
"#### 场景\n" +
"检查用户设备数量是否超过限制。\n\n" +
"#### 请求\n\n" +
"```json\n" +
"POST /api/v1/app/your-app-key/dynamic-code/check-permission/execute\n" +
"{\n" +
" \"params\": {\n" +
" \"deviceCount\": 2\n" +
" },\n" +
" \"user_id\": 123\n" +
"}\n" +
"```\n\n" +
"#### 动态函数代码\n\n" +
"```javascript\n" +
"function checkPermission(deviceCount) {\n" +
" if (!user) {\n" +
" return { allowed: false, reason: \"用户不存在\" };\n" +
" }\n" +
" \n" +
" if (user.status !== \"active\") {\n" +
" return { allowed: false, reason: \"用户状态异常\" };\n" +
" }\n" +
" \n" +
" if (deviceCount > app.max_devices) {\n" +
" return { \n" +
" allowed: false, \n" +
" reason: \"设备数量超过限制\",\n" +
" current: deviceCount,\n" +
" max: app.max_devices\n" +
" };\n" +
" }\n" +
" \n" +
" return { \n" +
" allowed: true, \n" +
" reason: \"权限验证通过\",\n" +
" user: user.username\n" +
" };\n" +
"}\n\n" +
"checkPermission(deviceCount)\n" +
"```\n\n" +
"#### 响应\n\n" +
"```json\n" +
"{\n" +
" \"code\": 200,\n" +
" \"message\": \"操作成功\",\n" +
" \"data\": {\n" +
" \"result\": {\n" +
" \"allowed\": true,\n" +
" \"reason\": \"权限验证通过\",\n" +
" \"user\": \"testuser\"\n" +
" },\n" +
" \"execution_time\": 1\n" +
" }\n" +
"}\n" +
"```\n\n" +
"---\n\n" +
"### 示例3:每日登录自动加时\n\n" +
"#### 场景\n" +
"试用用户每日登录自动延长1天。\n\n" +
"#### 请求\n\n" +
"```json\n" +
"POST /api/v1/app/your-app-key/dynamic-code/daily-login/execute\n" +
"{\n" +
" \"params\": {\n" +
" \"userId\": 123\n" +
" },\n" +
" \"user_id\": 123\n" +
"}\n" +
"```\n\n" +
"#### 动态函数代码\n\n" +
"```javascript\n" +
"function processDailyLogin(userId) {\n" +
" if (!user) {\n" +
" return { error: \"用户不存在\" };\n" +
" }\n" +
" \n" +
" if (user.status !== \"active\") {\n" +
" return { error: \"用户状态异常\" };\n" +
" }\n" +
" \n" +
" if (user.is_trial_user) {\n" +
" return {\n" +
" action: \"extend_time\",\n" +
" user_id: userId,\n" +
" days: 1,\n" +
" reason: \"试用用户每日登录加时\",\n" +
" timestamp: new Date().toISOString()\n" +
" };\n" +
" }\n" +
" \n" +
" return {\n" +
" message: \"登录成功\",\n" +
" user_points: user.points,\n" +
" app_name: app.name\n" +
" };\n" +
"}\n\n" +
"processDailyLogin(userId)\n" +
"```\n\n" +
"#### 响应\n\n" +
"```json\n" +
"{\n" +
" \"code\": 200,\n" +
" \"message\": \"操作成功\",\n" +
" \"data\": {\n" +
" \"result\": {\n" +
" \"action\": \"extend_time\",\n" +
" \"user_id\": 123,\n" +
" \"days\": 1,\n" +
" \"reason\": \"试用用户每日登录加时\",\n" +
" \"timestamp\": \"2026-03-11T00:57:55.123Z\"\n" +
" },\n" +
" \"execution_time\": 2\n" +
" }\n" +
"}\n" +
"```\n\n" +
"---\n\n" +
"### 示例4:功能使用自动扣点\n\n" +
"#### 场景\n" +
"用户使用功能时自动扣除相应积分。\n\n" +
"#### 请求\n\n" +
"```json\n" +
"POST /api/v1/app/your-app-key/dynamic-code/use-feature/execute\n" +
"{\n" +
" \"params\": {\n" +
" \"userId\": 123,\n" +
" \"featureType\": \"advanced\"\n" +
" },\n" +
" \"user_id\": 123\n" +
"}\n" +
"```\n\n" +
"#### 动态函数代码\n\n" +
"```javascript\n" +
"function processFeatureUsage(userId, featureType) {\n" +
" if (!user) {\n" +
" return { error: \"用户不存在\" };\n" +
" }\n" +
" \n" +
" if (user.status !== \"active\") {\n" +
" return { error: \"用户状态异常\" };\n" +
" }\n" +
" \n" +
" let cost = app.points_per_cycle;\n" +
" \n" +
" if (featureType === \"advanced\") {\n" +
" cost = cost * 2;\n" +
" } else if (featureType === \"premium\") {\n" +
" cost = cost * 5;\n" +
" }\n" +
" \n" +
" if (user.points < cost) {\n" +
" return { \n" +
" error: \"积分不足\",\n" +
" required: cost,\n" +
" current: user.points\n" +
" };\n" +
" }\n" +
" \n" +
" return {\n" +
" action: \"deduct_points\",\n" +
" user_id: userId,\n" +
" points: cost,\n" +
" reason: \"使用功能扣点: \" + featureType,\n" +
" feature_type: featureType\n" +
" };\n" +
"}\n\n" +
"processFeatureUsage(userId, featureType)\n" +
"```\n\n" +
"#### 响应\n\n" +
"```json\n" +
"{\n" +
" \"code\": 200,\n" +
" \"message\": \"操作成功\",\n" +
" \"data\": {\n" +
" \"result\": {\n" +
" \"action\": \"deduct_points\",\n" +
" \"user_id\": 123,\n" +
" \"points\": 2,\n" +
" \"reason\": \"使用功能扣点: advanced\",\n" +
" \"feature_type\": \"advanced\"\n" +
" },\n" +
" \"execution_time\": 1\n" +
" }\n" +
"}\n" +
"```\n\n" +
"---\n\n" +
"### 示例5:业务规则获取\n\n" +
"#### 场景\n" +
"获取应用的所有业务规则,用于前端展示。\n\n" +
"#### 请求\n\n" +
"```json\n" +
"POST /api/v1/app/your-app-key/dynamic-code/get-rules/execute\n" +
"{\n" +
" \"params\": {}\n" +
"}\n" +
"```\n\n" +
"#### 动态函数代码\n\n" +
"```javascript\n" +
"function getBusinessRules() {\n" +
" const rules = [];\n" +
" \n" +
" if (app.enable_trial) {\n" +
" rules.push({\n" +
" type: \"trial\",\n" +
" title: \"试用功能\",\n" +
" description: \"支持试用,试用时长:\" + app.trial_duration + \"天\"\n" +
" });\n" +
" }\n" +
" \n" +
" if (app.max_devices > 1) {\n" +
" rules.push({\n" +
" type: \"multi_device\",\n" +
" title: \"多设备支持\",\n" +
" description: \"支持多设备,最多\" + app.max_devices + \"台\"\n" +
" });\n" +
" }\n" +
" \n" +
" if (app.enable_free_period) {\n" +
" rules.push({\n" +
" type: \"free_period\",\n" +
" title: \"免费时段\",\n" +
" description: \"支持免费时段:\" + app.free_period_start + \" - \" + app.free_period_end\n" +
" });\n" +
" }\n" +
" \n" +
" if (app.point_price > 0) {\n" +
" rules.push({\n" +
" type: \"points\",\n" +
" title: \"积分系统\",\n" +
" description: \"点数价格:\" + app.point_price + \",每周期扣点:\" + app.points_per_cycle\n" +
" });\n" +
" }\n" +
" \n" +
" return {\n" +
" app_name: app.name,\n" +
" total_rules: rules.length,\n" +
" rules: rules\n" +
" };\n" +
"}\n\n" +
"getBusinessRules()\n" +
"```\n\n" +
"#### 响应\n\n" +
"```json\n" +
"{\n" +
" \"code\": 200,\n" +
" \"message\": \"操作成功\",\n" +
" \"data\": {\n" +
" \"result\": {\n" +
" \"app_name\": \"我的应用\",\n" +
" \"total_rules\": 4,\n" +
" \"rules\": [\n" +
" {\n" +
" \"type\": \"trial\",\n" +
" \"title\": \"试用功能\",\n" +
" \"description\": \"支持试用,试用时长:7天\"\n" +
" },\n" +
" {\n" +
" \"type\": \"multi_device\",\n" +
" \"title\": \"多设备支持\",\n" +
" \"description\": \"支持多设备,最多3台\"\n" +
" },\n" +
" {\n" +
" \"type\": \"free_period\",\n" +
" \"title\": \"免费时段\",\n" +
" \"description\": \"支持免费时段:20:00 - 08:00\"\n" +
" },\n" +
" {\n" +
" \"type\": \"points\",\n" +
" \"title\": \"积分系统\",\n" +
" \"description\": \"点数价格:0.1,每周期扣点:1\"\n" +
" }\n" +
" ]\n" +
" },\n" +
" \"execution_time\": 1\n" +
" }\n" +
"}\n" +
"```\n\n" +
"---\n\n" +
"## 错误处理\n\n" +
"### 常见错误\n\n" +
"#### 1. 语法错误\n\n" +
"```json\n" +
"{\n" +
" \"code\": 400,\n" +
" \"message\": \"代码执行错误: SyntaxError: Unexpected token\"\n" +
"}\n" +
"```\n\n" +
"**原因**JavaScript代码语法错误\n\n" +
"**解决**:检查代码语法,确保括号、引号等匹配正确\n\n" +
"---\n\n" +
"#### 2. 运行时错误\n\n" +
"```json\n" +
"{\n" +
" \"code\": 400,\n" +
" \"message\": \"代码执行错误: ReferenceError: x is not defined\"\n" +
"}\n" +
"```\n\n" +
"**原因**:使用了未定义的变量\n\n" +
"**解决**:检查变量名是否正确,或确保已通过参数传入\n\n" +
"---\n\n" +
"#### 3. 全局return错误\n\n" +
"```json\n" +
"{\n" +
" \"code\": 400,\n" +
" \"message\": \"代码执行错误: SyntaxError: Illegal return statement\"\n" +
"}\n" +
"```\n\n" +
"**原因**:在全局作用域使用了return语句\n\n" +
"**解决**:将return语句放在函数内部,或直接返回表达式\n\n" +
"---\n\n" +
"#### 4. 操作执行失败\n\n" +
"```json\n" +
"{\n" +
" \"code\": 500,\n" +
" \"message\": \"执行加时操作失败: user not found\"\n" +
"}\n" +
"```\n\n" +
"**原因**:操作指令中的用户不存在\n\n" +
"**解决**:检查user_id是否正确,或用户是否属于当前应用\n\n" +
"---\n\n" +
"## 性能建议\n\n" +
"1. **避免死循环**:确保循环有明确的退出条件\n" +
"2. **合理使用缓存**:对于重复计算,可以考虑缓存结果\n" +
"3. **控制代码复杂度**:过复杂的代码可能影响执行效率\n" +
"4. **使用内置函数**:优先使用JavaScript内置函数,性能更好\n" +
"5. **避免频繁操作**:操作指令会修改数据库,避免频繁调用\n\n" +
"---\n\n" +
"## 安全建议\n\n" +
"1. **不要执行危险操作**:避免访问文件系统、网络请求等\n" +
"2. **参数验证**:在代码中对参数进行必要的验证\n" +
"3. **避免敏感信息**:不要在代码中硬编码密钥、密码等敏感信息\n" +
"4. **限制执行时间**:设置合理的超时时间,防止长时间运行\n" +
"5. **操作指令谨慎**:操作指令会修改数据库,确保逻辑正确\n" +
"6. **用户数据保护**:不要在代码中泄露用户敏感信息\n\n" +
"---\n\n" +
"## 最佳实践\n\n" +
"### 1. 代码组织\n\n" +
"将复杂逻辑封装成函数,提高代码可读性:\n\n" +
"```javascript\n" +
"function validateUser() {\n" +
" if (!user) {\n" +
" return { valid: false, reason: \"用户不存在\" };\n" +
" }\n" +
" \n" +
" if (user.status !== \"active\") {\n" +
" return { valid: false, reason: \"用户状态异常\" };\n" +
" }\n" +
" \n" +
" return { valid: true };\n" +
"}\n\n" +
"function calculatePrice(basePrice, discount) {\n" +
" return basePrice * (1 - discount / 100);\n" +
"}\n\n" +
"function mainProcess() {\n" +
" const validation = validateUser();\n" +
" if (!validation.valid) {\n" +
" return validation;\n" +
" }\n" +
" \n" +
" const price = calculatePrice(100, 20);\n" +
" return { success: true, price: price };\n" +
"}\n\n" +
"mainProcess()\n" +
"```\n\n" +
"---\n\n" +
"### 2. 错误处理\n\n" +
"在代码中添加适当的错误处理:\n\n" +
"```javascript\n" +
"function safeCalculate(a, b) {\n" +
" if (typeof a !== \"number\" || typeof b !== \"number\") {\n" +
" return { error: \"参数必须是数字\" };\n" +
" }\n" +
" \n" +
" try {\n" +
" return { result: a + b };\n" +
" } catch (e) {\n" +
" return { error: \"计算失败: \" + e.message };\n" +
" }\n" +
"}\n\n" +
"safeCalculate(a, b)\n" +
"```\n\n" +
"---\n\n" +
"### 3. 使用现代JavaScript\n\n" +
"利用ES6+特性提高代码质量:\n\n" +
"```javascript\n" +
"// 使用箭头函数\n" +
"const calculate = (x, y) => x + y;\n\n" +
"// 使用解构赋值\n" +
"const { name, age } = userInfo;\n\n" +
"// 使用模板字符串\n" +
"const message = `用户${name}的年龄是${age}岁`;\n\n" +
"// 使用数组方法\n" +
"const sum = numbers.reduce((a, b) => a + b, 0);\n\n" +
"// 使用对象简写\n" +
"const result = { name, age, status };\n" +
"```\n\n" +
"---\n\n" +
"### 4. 日志记录\n\n" +
"在返回结果中包含调试信息:\n\n" +
"```javascript\n" +
"function processWithLog(userId) {\n" +
" const startTime = new Date();\n" +
" \n" +
" if (!user) {\n" +
" return { \n" +
" error: \"用户不存在\",\n" +
" timestamp: startTime.toISOString(),\n" +
" debug: { userId }\n" +
" };\n" +
" }\n" +
" \n" +
" const result = {\n" +
" user_id: userId,\n" +
" username: user.username,\n" +
" status: user.status\n" +
" };\n" +
" \n" +
" return {\n" +
" success: true,\n" +
" data: result,\n" +
" timestamp: startTime.toISOString(),\n" +
" execution_time: new Date() - startTime\n" +
" };\n" +
"}\n\n" +
"processWithLog(userId)\n" +
"```\n\n" +
"---\n\n" +
"## 常见问题\n\n" +
"### Q1: 动态函数可以访问数据库吗?\n\n" +
"**A**: 不能直接访问数据库。动态函数只能使用注入的数据(app、user)和请求参数。如果需要修改数据,应该返回操作指令(extend_time、deduct_points),由后端安全地执行。\n\n" +
"---\n\n" +
"### Q2: 动态函数可以调用外部API吗?\n\n" +
"**A**: 不能。动态函数在沙箱环境中执行,不支持网络请求。如果需要调用外部API,应该通过后端接口实现。\n\n" +
"---\n\n" +
"### Q3: 动态函数的执行时间有限制吗?\n\n" +
"**A**: 有。动态函数有执行时间限制,超时会被终止。建议避免死循环和长时间运行的操作。\n\n" +
"---\n\n" +
"### Q4: 如何调试动态函数?\n\n" +
"**A**: 可以在返回结果中包含调试信息,或者使用简单的测试参数验证逻辑是否正确。\n\n" +
"---\n\n" +
"### Q5: 动态函数可以修改应用配置吗?\n\n" +
"**A**: 不能。app对象是只读的,不能修改。如果需要修改应用配置,应该使用专门的管理接口。\n\n" +
"---\n\n" +
"## 更新日志\n\n" +
"### v1.0.0 (2026-03-11)\n" +
"- 初始版本发布\n" +
"- 支持应用配置数据注入\n" +
"- 支持用户信息注入\n" +
"- 支持操作指令(加时、扣点)\n" +
"- 支持完整的JavaScript语法\n" +
"- 提供丰富的使用示例\n"
var existingDoc model.Doc
if err := database.DB.Where("slug = ?", "dynamic-code").First(&existingDoc).Error; err == nil {
log.Println("动态函数文档已存在,删除旧文档")
database.DB.Delete(&existingDoc)
}
dynamicCodeDoc := model.Doc{
Title: "动态函数接口",
CategoryID: &apiCat.ID,
Slug: "dynamic-code",
Content: dynamicCodeContent,
Summary: "动态函数允许开发者为应用创建自定义的业务逻辑,通过JavaScript代码实现灵活的数据处理和业务规则",
Icon: "⚡",
Sort: 1,
Status: "published",
}
if err := database.DB.Create(&dynamicCodeDoc).Error; err != nil {
log.Printf("创建动态函数文档失败: %v", err)
return
}
log.Println("动态函数文档创建成功")
}