diff --git a/backend/internal/router/agent/agent.go b/backend/internal/router/agent/agent.go index 961e8e9..504d1f7 100644 --- a/backend/internal/router/agent/agent.go +++ b/backend/internal/router/agent/agent.go @@ -1,6 +1,7 @@ package agent import ( + "encoding/json" "fmt" "math/rand" "sort" @@ -26,7 +27,7 @@ func SetupAgentRoutes(r *gin.RouterGroup) { r.PUT("/profile", handleUpdateProfile) r.GET("/cards/export", handleExportCards) r.GET("/cloud-variables", handleGetCloudVariables) - r.GET("/cloud-constants", handleGetCloudConstants) + r.GET("/cloud-variables/:id/records", handleGetCloudVariableRecords) } func handleGetStats(c *gin.Context) { @@ -778,7 +779,7 @@ func handleGetCloudVariables(c *gin.Context) { } if !agent.CanViewCloudData { - response.Error(c, 403, "无权查看云端数据") + response.Error(c, 403, "无权查看云端变量") return } @@ -821,14 +822,18 @@ func handleGetCloudVariables(c *gin.Context) { appName = appMap[*v.AppID] } result = append(result, gin.H{ - "id": v.ID, - "name": v.Key, - "app_id": v.AppID, - "app_name": appName, - "scope": v.Scope, - "status": v.Status, - "description": v.Description, - "created_at": v.CreatedAt.Format("2006-01-02T15:04:05Z07:00"), + "id": v.ID, + "key": v.Key, + "app_id": v.AppID, + "application_name": appName, + "default_value": v.DefaultValue, + "var_type": v.VarType, + "max_records": v.MaxRecords, + "scope": v.Scope, + "write_permission": v.WritePermission, + "status": v.Status, + "description": v.Description, + "created_at": v.CreatedAt.Format("2006-01-02T15:04:05Z07:00"), }) } @@ -838,7 +843,7 @@ func handleGetCloudVariables(c *gin.Context) { }) } -func handleGetCloudConstants(c *gin.Context) { +func handleGetCloudVariableRecords(c *gin.Context) { userID := c.GetUint("user_id") var agent model.User @@ -848,62 +853,95 @@ func handleGetCloudConstants(c *gin.Context) { } if !agent.CanViewCloudData { - response.Error(c, 403, "无权查看云端数据") + response.Error(c, 403, "无权查看云端变量") + return + } + + variableID := c.Param("id") + var variable model.CloudVariable + if err := database.DB.First(&variable, variableID).Error; err != nil { + response.Error(c, 404, "云端变量不存在") return } var agentApps []model.AgentApplication database.DB.Where("agent_id = ?", userID).Find(&agentApps) - appIDs := make([]uint, 0) + appIDs := make(map[uint]bool) for _, app := range agentApps { - appIDs = append(appIDs, app.ApplicationID) + appIDs[app.ApplicationID] = true } - if len(appIDs) == 0 { - response.Success(c, gin.H{ - "constants": []interface{}{}, - "total": 0, - }) + if variable.AppID == nil || !appIDs[*variable.AppID] { + response.Error(c, 403, "无权查看该变量的记录") return } - appIDFilter := c.Query("app_id") - var constants []model.CloudConstant - query := database.DB.Where("app_id IN ?", appIDs) - if appIDFilter != "" { - if aid, err := strconv.ParseUint(appIDFilter, 10, 32); err == nil { - query = database.DB.Where("app_id = ?", uint(aid)) - } - } - query.Find(&constants) - - appMap := make(map[uint]string) - var apps []model.Application - database.DB.Where("id IN ?", appIDs).Find(&apps) - for _, app := range apps { - appMap[app.ID] = app.Name + if variable.VarType != "stream" { + response.Error(c, 400, "该变量不是记录类型") + return } - result := make([]gin.H, 0) - for _, c := range constants { - appName := "" - if c.AppID != nil { - appName = appMap[*c.AppID] + page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) + pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20")) + if page < 1 { + page = 1 + } + if pageSize < 1 || pageSize > 100 { + pageSize = 20 + } + + startDate := c.Query("start_date") + endDate := c.Query("end_date") + + var total int64 + query := database.DB.Model(&model.CloudVariableRecord{}).Where("cloud_variable_id = ?", variable.ID) + if startDate != "" { + query = query.Where("created_at >= ?", startDate+" 00:00:00") + } + if endDate != "" { + query = query.Where("created_at <= ?", endDate+" 23:59:59") + } + query.Count(&total) + + var records []model.CloudVariableRecord + offset := (page - 1) * pageSize + if err := query.Order("created_at DESC").Limit(pageSize).Offset(offset).Find(&records).Error; err != nil { + response.Error(c, 500, "获取记录失败") + return + } + + result := make([]gin.H, len(records)) + for i, r := range records { + var parsedData interface{} + if r.Data != "" { + json.Unmarshal([]byte(r.Data), &parsedData) } - result = append(result, gin.H{ - "id": c.ID, - "name": c.Key, - "app_id": c.AppID, - "app_name": appName, - "value": c.Value, - "status": c.Status, - "description": c.Description, - "created_at": c.CreatedAt.Format("2006-01-02T15:04:05Z07:00"), - }) + if parsedData == nil && r.Data != "" { + parsedData = r.Data + } + record := gin.H{ + "id": r.ID, + "data": parsedData, + "created_at": r.CreatedAt, + } + if r.AppUserID != nil { + record["user_id"] = r.AppUserID + var appUser model.AppUser + if err := database.DB.Select("id, username").First(&appUser, *r.AppUserID).Error; err == nil { + record["user"] = gin.H{ + "id": appUser.ID, + "username": appUser.Username, + } + } + } + result[i] = record } response.Success(c, gin.H{ - "constants": result, - "total": len(result), + "records": result, + "total": total, + "page": page, + "page_size": pageSize, + "total_pages": (total + int64(pageSize) - 1) / int64(pageSize), }) } diff --git a/frontend/src/layouts/agent.vue b/frontend/src/layouts/agent.vue index 125b6f5..75ea8de 100644 --- a/frontend/src/layouts/agent.vue +++ b/frontend/src/layouts/agent.vue @@ -93,8 +93,8 @@ const navMain = computed(() => { if (user.can_view_cloud_data) { groups[0].items.push({ - title: '云端数据', - url: '/agent/cloud-data', + title: t('nav.cloudVariables'), + url: '/agent/cloud-variables', icon: Cloud, }) } @@ -122,7 +122,7 @@ const breadcrumbs = computed(() => { cards: t('nav.cards'), users: t('nav.users'), finance: t('nav.finance'), - 'cloud-data': '云端数据', + 'cloud-variables': t('nav.cloudVariables'), profile: t('nav.profile'), create: t('nav.create'), } diff --git a/frontend/src/pages/agent/cloud-data/index.vue b/frontend/src/pages/agent/cloud-data/index.vue deleted file mode 100644 index 740321d..0000000 --- a/frontend/src/pages/agent/cloud-data/index.vue +++ /dev/null @@ -1,314 +0,0 @@ - - - diff --git a/frontend/src/pages/agent/cloud-variables/[id]/records.vue b/frontend/src/pages/agent/cloud-variables/[id]/records.vue new file mode 100644 index 0000000..4d062e3 --- /dev/null +++ b/frontend/src/pages/agent/cloud-variables/[id]/records.vue @@ -0,0 +1,386 @@ + + + diff --git a/frontend/src/pages/agent/cloud-variables/index.vue b/frontend/src/pages/agent/cloud-variables/index.vue new file mode 100644 index 0000000..ef125f4 --- /dev/null +++ b/frontend/src/pages/agent/cloud-variables/index.vue @@ -0,0 +1,305 @@ + + + diff --git a/frontend/src/plugins/i18n/en.json b/frontend/src/plugins/i18n/en.json index 2bae076..580c788 100644 --- a/frontend/src/plugins/i18n/en.json +++ b/frontend/src/plugins/i18n/en.json @@ -923,7 +923,7 @@ "maxApiCalls": "API Calls/Month", "maxApiCallsPlaceholder": "-1 for unlimited", "allowAgent": "Agent Permission", - "allowCloudData": "Cloud Data", + "allowCloudData": "Cloud Variables", "allowDynamicCode": "Cloud Function", "allowEmail": "Email Feature", "allowExtension": "Extension API", @@ -1286,7 +1286,7 @@ "cardsCount": "Cards Generated", "childAgentsCount": "Child Agents", "canCreateAgent": "Create Agent Permission", - "canViewCloudData": "Cloud Data Permission", + "canViewCloudData": "View Cloud Variables Permission", "balance": "Balance", "createdAt": "Created At", "lastLoginAt": "Last Login" @@ -2887,27 +2887,49 @@ "generateNow": "Generate Now" } }, - "cloudData": { - "title": "Cloud Data", - "description": "View cloud variables and constants (read-only)", - "variables": "Cloud Variables", - "constants": "Cloud Constants", - "applications": "Applications", - "dataList": "Data List", - "readOnlyHint": "Read-only mode, data cannot be edited", - "allApps": "All Applications", + "cloudVariables": { + "title": "Cloud Variables", + "description": "View cloud variables (read-only)", + "totalVariables": "Total Variables", + "appScopeVariables": "App Scope Variables", + "userScopeVariables": "User Scope Variables", + "appCount": "Applications", "noVariables": "No cloud variables found", - "noConstants": "No cloud constants found", + "appScope": "App", + "userScope": "User", "statusActive": "Active", "statusInactive": "Inactive", - "readOnlyNote": "Read-only - Data is for viewing only, no editing allowed", + "viewRecords": "View Records", + "application": "Application", + "scope": "Scope", + "types": { + "integer": "Integer", + "decimal": "Decimal", + "string": "String", + "binary": "Binary", + "stream": "Stream" + }, "columns": { - "name": "Name", - "application": "Application", + "key": "Key", + "defaultValue": "Default Value", + "type": "Type", "scope": "Scope", - "value": "Value", + "application": "Application", "status": "Status", "createdAt": "Created At" + }, + "records": { + "title": "Variable Records", + "description": "Records for variable {key}", + "totalRecords": "Total Records", + "maxRecordsLabel": "Max Records", + "unlimited": "Unlimited", + "user": "User", + "data": "Data", + "createdAt": "Created At", + "searchPlaceholder": "Search records...", + "startDate": "Start Date", + "endDate": "End Date" } } }, @@ -2932,7 +2954,7 @@ "apiCalls": "{count} API calls/month", "unlimitedApiCalls": "Unlimited API calls", "agent": "Agent permission", - "cloudData": "Cloud data feature", + "cloudData": "Cloud Variables feature", "dynamicCode": "Dynamic code feature", "email": "Email feature", "extension": "Extension API", diff --git a/frontend/src/plugins/i18n/zh.json b/frontend/src/plugins/i18n/zh.json index 760b565..1ca32c4 100644 --- a/frontend/src/plugins/i18n/zh.json +++ b/frontend/src/plugins/i18n/zh.json @@ -924,7 +924,7 @@ "maxApiCalls": "API调用次数/月", "maxApiCallsPlaceholder": "-1表示不限", "allowAgent": "代理权限", - "allowCloudData": "云端数据", + "allowCloudData": "云端变量", "allowDynamicCode": "云端函数", "allowEmail": "邮件功能", "allowExtension": "扩展接口", @@ -1242,7 +1242,7 @@ "cardsCount": "生成卡密", "childAgentsCount": "下级代理", "canCreateAgent": "创建代理权限", - "canViewCloudData": "云端数据权限", + "canViewCloudData": "查看云端变量权限", "balance": "余额", "totalConsumption": "消费", "createdAt": "注册时间", @@ -2888,27 +2888,49 @@ "generateNow": "立即生成" } }, - "cloudData": { - "title": "云端数据", - "description": "查看云端变量和常量数据(只读)", - "variables": "云端变量", - "constants": "云端常量", - "applications": "应用数量", - "dataList": "数据列表", - "readOnlyHint": "只读模式,数据不可编辑", - "allApps": "全部应用", + "cloudVariables": { + "title": "云端变量", + "description": "查看云端变量数据(只读)", + "totalVariables": "变量总数", + "appScopeVariables": "应用级变量", + "userScopeVariables": "用户级变量", + "appCount": "应用数量", "noVariables": "暂无云端变量数据", - "noConstants": "暂无云端常量数据", + "appScope": "应用级", + "userScope": "用户级", "statusActive": "启用", "statusInactive": "禁用", - "readOnlyNote": "只读模式 - 当前数据仅供查看,无法进行编辑操作", + "viewRecords": "查看记录", + "application": "应用", + "scope": "作用域", + "types": { + "integer": "整数", + "decimal": "小数", + "string": "字符串", + "binary": "二进制", + "stream": "列表" + }, "columns": { - "name": "名称", - "application": "应用", + "key": "变量名", + "defaultValue": "默认值", + "type": "类型", "scope": "作用域", - "value": "值", + "application": "应用", "status": "状态", "createdAt": "创建时间" + }, + "records": { + "title": "变量记录", + "description": "变量 {key} 的记录列表", + "totalRecords": "记录总数", + "maxRecordsLabel": "最大记录数", + "unlimited": "无限制", + "user": "用户", + "data": "数据", + "createdAt": "创建时间", + "searchPlaceholder": "搜索记录...", + "startDate": "开始日期", + "endDate": "结束日期" } } }, @@ -2933,7 +2955,7 @@ "apiCalls": "{count}次/月 API调用", "unlimitedApiCalls": "无限API调用", "agent": "代理权限", - "cloudData": "云端数据功能", + "cloudData": "云端变量功能", "dynamicCode": "云端函数功能", "email": "邮件功能", "extension": "扩展接口功能", diff --git a/frontend/src/router/routes.ts b/frontend/src/router/routes.ts index 284d619..9905b54 100644 --- a/frontend/src/router/routes.ts +++ b/frontend/src/router/routes.ts @@ -451,10 +451,16 @@ const routes: RouteRecordRaw[] = [ meta: { title: '财务管理 - 代理商后台' }, }, { - path: 'cloud-data', - name: 'AgentCloudData', - component: () => import('@/pages/agent/cloud-data/index.vue'), - meta: { title: '云端数据 - 代理商后台' }, + path: 'cloud-variables', + name: 'AgentCloudVariables', + component: () => import('@/pages/agent/cloud-variables/index.vue'), + meta: { title: '云端变量 - 代理商后台' }, + }, + { + path: 'cloud-variables/:id/records', + name: 'AgentCloudVariableRecords', + component: () => import('@/pages/agent/cloud-variables/[id]/records.vue'), + meta: { title: '变量记录 - 代理商后台' }, }, { path: 'profile',