ea8ffb6c74
- 修复订阅模式登录时错误检查余额的问题 - 区分无限余额和永久订阅两种永久会员类型 - 修复动态代码HTTP请求返回值在JS中无法正确访问的问题 - 添加侧边栏滚动位置保持功能 - 移除developer角色相关代码,统一使用admin - 添加缺失的i18n翻译key
978 lines
32 KiB
Go
978 lines
32 KiB
Go
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=== 删除旧的云端函数文档 ===")
|
||
|
||
if err := database.DB.Where("slug = ?", "dynamic-code").Delete(&model.Doc{}).Error; err != nil {
|
||
log.Printf("删除文档失败: %v", err)
|
||
}
|
||
|
||
if err := database.DB.Where("slug = ?", "cloud-function").Delete(&model.Doc{}).Error; err != nil {
|
||
log.Printf("删除文档失败: %v", err)
|
||
}
|
||
|
||
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
|
||
}
|
||
|
||
cloudFunctionContent := "# 云端函数接口\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/cloud-function`\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/cloud-function/: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/cloud-function/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/cloud-function/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/cloud-function/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/cloud-function/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/cloud-function/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"
|
||
|
||
cloudFunctionDoc := model.Doc{
|
||
Title: "云端函数接口",
|
||
CategoryID: &apiCat.ID,
|
||
Slug: "cloud-function",
|
||
Content: cloudFunctionContent,
|
||
Summary: "云端函数允许开发者为应用创建自定义的业务逻辑,通过JavaScript代码实现灵活的数据处理和业务规则",
|
||
Icon: "⚡",
|
||
Sort: 1,
|
||
Status: "published",
|
||
}
|
||
|
||
if err := database.DB.Create(&cloudFunctionDoc).Error; err != nil {
|
||
log.Printf("创建云端函数文档失败: %v", err)
|
||
return
|
||
}
|
||
|
||
log.Println("云端函数文档创建成功")
|
||
}
|