You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
155 lines
3.5 KiB
155 lines
3.5 KiB
package middleware
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"laic-backend/common"
|
|
"laic-backend/model"
|
|
"laic-backend/service"
|
|
)
|
|
|
|
// OperationLogMiddleware 记录设备控制写操作(POST/PUT/DELETE)到 operation_log
|
|
func OperationLogMiddleware() gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
if !isMutating(c.Request.Method) {
|
|
c.Next()
|
|
return
|
|
}
|
|
path := c.Request.URL.Path
|
|
if !isDeviceOperation(path) {
|
|
c.Next()
|
|
return
|
|
}
|
|
c.Next()
|
|
|
|
userID := c.GetInt64("user_id")
|
|
if userID == 0 {
|
|
return
|
|
}
|
|
result := "success"
|
|
if c.Writer.Status() >= http.StatusBadRequest {
|
|
result = "failed"
|
|
}
|
|
userName := c.GetString("username")
|
|
if name := resolveUserName(userID); name != "" {
|
|
userName = name
|
|
}
|
|
service.DefaultOperationLogService.Record(
|
|
userID, userName,
|
|
resolveModule(path), resolveAction(c.Request.Method, path),
|
|
path, result, c.ClientIP(),
|
|
)
|
|
}
|
|
}
|
|
|
|
func isMutating(method string) bool {
|
|
return method == http.MethodPost || method == http.MethodPut || method == http.MethodDelete
|
|
}
|
|
|
|
func isDeviceOperation(path string) bool {
|
|
parts := strings.Split(strings.Trim(path, "/"), "/")
|
|
if len(parts) < 3 || parts[0] != "v1" {
|
|
return false
|
|
}
|
|
switch parts[1] {
|
|
case "docks":
|
|
return len(parts) >= 4 && (parts[3] == "command" || parts[3] == "firmware")
|
|
case "tasks":
|
|
return len(parts) >= 4 && parts[3] == "execute"
|
|
case "alarms":
|
|
return len(parts) >= 4 && (parts[3] == "acknowledge" || parts[3] == "resolve")
|
|
case "live":
|
|
return len(parts) >= 4 && (parts[3] == "start" || parts[3] == "stop")
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// resolveUserName 从 DB 读取用户显示名(快照),失败回退为空(由调用方回退 phone)
|
|
func resolveUserName(userID int64) string {
|
|
var u model.User
|
|
if err := common.DB.Select("name").First(&u, userID).Error; err == nil {
|
|
return u.Name
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// resolveModule 将路径首个资源段映射为中文模块名
|
|
func resolveModule(path string) string {
|
|
parts := strings.Split(strings.Trim(path, "/"), "/")
|
|
if len(parts) < 2 {
|
|
return "系统"
|
|
}
|
|
switch parts[1] {
|
|
case "users":
|
|
return "用户管理"
|
|
case "roles":
|
|
return "角色管理"
|
|
case "docks":
|
|
return "机巢管理"
|
|
case "drones":
|
|
return "无人机管理"
|
|
case "alarms":
|
|
return "告警管理"
|
|
case "commands":
|
|
return "指令管理"
|
|
case "routes":
|
|
return "航线管理"
|
|
case "tasks":
|
|
return "任务管理"
|
|
case "executions":
|
|
return "执行记录"
|
|
case "firmwares":
|
|
return "固件管理"
|
|
case "live":
|
|
return "直播管理"
|
|
case "videos":
|
|
return "视频管理"
|
|
case "account":
|
|
return "账户中心"
|
|
case "logs":
|
|
return "系统管理"
|
|
case "auth":
|
|
return "认证"
|
|
default:
|
|
return "系统"
|
|
}
|
|
}
|
|
|
|
// resolveAction 将 HTTP 方法 + 路径末尾段映射为中文动作
|
|
func resolveAction(method, path string) string {
|
|
seg := path
|
|
if i := strings.LastIndex(seg, "/"); i >= 0 {
|
|
seg = seg[i+1:]
|
|
}
|
|
special := map[string]string{
|
|
"execute": "执行任务",
|
|
"command": "下发指令",
|
|
"upgrade": "下发升级",
|
|
"pay": "支付订单",
|
|
"download": "下载视频",
|
|
"start": "开始直播",
|
|
"stop": "停止直播",
|
|
"complete": "确认上传",
|
|
"recharge": "充值",
|
|
"resolve": "处理告警",
|
|
"acknowledge": "确认告警",
|
|
"logout": "退出登录",
|
|
}
|
|
if a, ok := special[seg]; ok {
|
|
return a
|
|
}
|
|
switch method {
|
|
case http.MethodPost:
|
|
return "新增"
|
|
case http.MethodPut:
|
|
return "修改"
|
|
case http.MethodDelete:
|
|
return "删除"
|
|
default:
|
|
return method
|
|
}
|
|
}
|
|
|