增加任务管理模块
This commit is contained in:
@@ -194,9 +194,9 @@ func (c *AuthController) Login() {
|
||||
TenantId: tenantId,
|
||||
UserId: userId,
|
||||
Username: usernameForToken,
|
||||
Module: "auth",
|
||||
Module: "登录模块",
|
||||
ResourceType: "user",
|
||||
Operation: "LOGIN",
|
||||
Operation: "登录",
|
||||
IpAddress: clientIP,
|
||||
UserAgent: c.Ctx.Input.Header("User-Agent"),
|
||||
RequestMethod: "POST",
|
||||
|
||||
@@ -2,6 +2,8 @@ package controllers
|
||||
|
||||
import (
|
||||
"server/models"
|
||||
"server/services"
|
||||
"time"
|
||||
|
||||
"github.com/beego/beego/v2/client/orm"
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
@@ -106,3 +108,104 @@ func (c *DashboardController) GetTenantStats() {
|
||||
}
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// GetUserActivityLogs 获取当前用户的最新活动日志(包含操作日志和登录日志)
|
||||
// @router /api/dashboard/user-activity-logs [get]
|
||||
func (c *DashboardController) GetUserActivityLogs() {
|
||||
// 获取当前用户ID和租户ID
|
||||
userId := 0
|
||||
if userIdVal, ok := c.Ctx.Input.GetData("userId").(int); ok {
|
||||
userId = userIdVal
|
||||
}
|
||||
|
||||
tenantId := 0
|
||||
if tenantIdVal, ok := c.Ctx.Input.GetData("tenantId").(int); ok {
|
||||
tenantId = tenantIdVal
|
||||
}
|
||||
|
||||
if userId <= 0 {
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 1,
|
||||
"message": "无法获取用户信息",
|
||||
"data": nil,
|
||||
}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
// 获取查询参数
|
||||
pageNum, _ := c.GetInt("page_num", 1)
|
||||
pageSize, _ := c.GetInt("page_size", 10)
|
||||
logType := c.GetString("type") // "operation" 或 "access" 或 "all"
|
||||
operation := c.GetString("operation") // 操作类型过滤
|
||||
|
||||
if logType == "" {
|
||||
logType = "all"
|
||||
}
|
||||
|
||||
type ActivityLog struct {
|
||||
Id int64 `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Username string `json:"username"`
|
||||
Module string `json:"module"`
|
||||
Operation string `json:"operation"`
|
||||
Action string `json:"action"`
|
||||
Description string `json:"description"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
var logs []ActivityLog
|
||||
|
||||
// 获取操作日志
|
||||
if logType == "operation" || logType == "all" {
|
||||
operationLogs, _, err := services.GetOperationLogs(tenantId, userId, "", operation, nil, nil, pageNum, pageSize)
|
||||
if err == nil && operationLogs != nil {
|
||||
for _, log := range operationLogs {
|
||||
logs = append(logs, ActivityLog{
|
||||
Id: log.Id,
|
||||
Type: "operation",
|
||||
Username: log.Username,
|
||||
Module: log.Module,
|
||||
Operation: log.Operation,
|
||||
Action: log.Operation,
|
||||
Description: log.Description,
|
||||
Timestamp: log.CreateTime,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取访问/登录日志
|
||||
if logType == "access" || logType == "all" {
|
||||
accessLogs, _, err := services.GetAccessLogs(tenantId, userId, "", "", nil, nil, pageNum, pageSize)
|
||||
if err == nil && accessLogs != nil {
|
||||
for _, log := range accessLogs {
|
||||
logs = append(logs, ActivityLog{
|
||||
Id: log.Id,
|
||||
Type: "access",
|
||||
Username: log.Username,
|
||||
Module: log.Module,
|
||||
Operation: log.RequestMethod,
|
||||
Action: "访问",
|
||||
Description: "访问 " + log.Module,
|
||||
Timestamp: log.CreateTime,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 按时间戳排序(最新的在前)
|
||||
if len(logs) > pageSize {
|
||||
logs = logs[:pageSize]
|
||||
}
|
||||
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": map[string]interface{}{
|
||||
"logs": logs,
|
||||
"total": len(logs),
|
||||
},
|
||||
}
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"server/models"
|
||||
"server/services"
|
||||
"strconv"
|
||||
@@ -245,3 +246,193 @@ func (c *OperationLogController) ClearOldLogs() {
|
||||
}
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// GetAccessLogs 获取访问日志列表
|
||||
func (c *OperationLogController) GetAccessLogs() {
|
||||
// 获取租户ID和用户ID
|
||||
tenantIdData := c.Ctx.Input.GetData("tenantId")
|
||||
tenantId := 0
|
||||
if tenantIdData != nil {
|
||||
if tid, ok := tenantIdData.(int); ok {
|
||||
tenantId = tid
|
||||
}
|
||||
}
|
||||
|
||||
userIdData := c.Ctx.Input.GetData("userId")
|
||||
userId := 0
|
||||
if userIdData != nil {
|
||||
if uid, ok := userIdData.(int); ok {
|
||||
userId = uid
|
||||
}
|
||||
}
|
||||
|
||||
// 获取查询参数
|
||||
pageNum, _ := c.GetInt("page_num", 1)
|
||||
pageSize, _ := c.GetInt("page_size", 20)
|
||||
module := c.GetString("module")
|
||||
resourceType := c.GetString("resource_type")
|
||||
startTimeStr := c.GetString("start_time")
|
||||
endTimeStr := c.GetString("end_time")
|
||||
|
||||
var startTime, endTime *time.Time
|
||||
|
||||
if startTimeStr != "" {
|
||||
if t, err := time.Parse("2006-01-02", startTimeStr); err == nil {
|
||||
startTime = &t
|
||||
}
|
||||
}
|
||||
|
||||
if endTimeStr != "" {
|
||||
if t, err := time.Parse("2006-01-02", endTimeStr); err == nil {
|
||||
endTime = &t
|
||||
}
|
||||
}
|
||||
|
||||
// 查询访问日志
|
||||
logs, total, err := services.GetAccessLogs(tenantId, userId, module, resourceType, startTime, endTime, pageNum, pageSize)
|
||||
if err != nil {
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"success": false,
|
||||
"message": "查询访问日志失败: " + err.Error(),
|
||||
}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"success": true,
|
||||
"data": map[string]interface{}{
|
||||
"logs": logs,
|
||||
"total": total,
|
||||
},
|
||||
}
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// GetAccessLogById 根据ID获取访问日志详情
|
||||
func (c *OperationLogController) GetAccessLogById() {
|
||||
idStr := c.Ctx.Input.Param(":id")
|
||||
id, err := strconv.ParseInt(idStr, 10, 64)
|
||||
if err != nil {
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"success": false,
|
||||
"message": "无效的日志ID",
|
||||
}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
log, err := services.GetAccessLogById(id)
|
||||
if err != nil {
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"success": false,
|
||||
"message": "查询日志详情失败: " + err.Error(),
|
||||
}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
var user *models.User
|
||||
if log.UserId > 0 {
|
||||
user, _ = models.GetUserById(log.UserId)
|
||||
}
|
||||
|
||||
// 构造返回数据
|
||||
result := map[string]interface{}{
|
||||
"id": log.Id,
|
||||
"tenant_id": log.TenantId,
|
||||
"user_id": log.UserId,
|
||||
"username": log.Username,
|
||||
"module": log.Module,
|
||||
"resource_type": log.ResourceType,
|
||||
"resource_id": log.ResourceId,
|
||||
"request_url": log.RequestUrl,
|
||||
"query_string": log.QueryString,
|
||||
"ip_address": log.IpAddress,
|
||||
"user_agent": log.UserAgent,
|
||||
"request_method": log.RequestMethod,
|
||||
"duration": log.Duration,
|
||||
"create_time": log.CreateTime,
|
||||
}
|
||||
|
||||
// 如果有用户信息,添加到结果中
|
||||
if user != nil {
|
||||
result["user_nickname"] = user.Nickname
|
||||
result["user_email"] = user.Email
|
||||
}
|
||||
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"success": true,
|
||||
"data": result,
|
||||
}
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// GetUserAccessStats 获取用户访问统计
|
||||
func (c *OperationLogController) GetUserAccessStats() {
|
||||
userIdData := c.Ctx.Input.GetData("userId")
|
||||
userId := 0
|
||||
if userIdData != nil {
|
||||
if uid, ok := userIdData.(int); ok {
|
||||
userId = uid
|
||||
}
|
||||
}
|
||||
|
||||
tenantIdData := c.Ctx.Input.GetData("tenantId")
|
||||
tenantId := 0
|
||||
if tenantIdData != nil {
|
||||
if tid, ok := tenantIdData.(int); ok {
|
||||
tenantId = tid
|
||||
}
|
||||
}
|
||||
|
||||
days, _ := c.GetInt("days", 7)
|
||||
|
||||
stats, err := services.GetUserAccessStats(tenantId, userId, days)
|
||||
if err != nil {
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"success": false,
|
||||
"message": "查询统计失败: " + err.Error(),
|
||||
}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"success": true,
|
||||
"data": stats,
|
||||
}
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// ClearOldAccessLogs 清空旧访问日志
|
||||
func (c *OperationLogController) ClearOldAccessLogs() {
|
||||
// 获取参数
|
||||
var params map[string]interface{}
|
||||
if err := c.ParseForm(¶ms); err != nil {
|
||||
// 如果ParseForm失败,尝试解析JSON
|
||||
c.Ctx.Input.Bind(¶ms, "json")
|
||||
}
|
||||
|
||||
keepDays := 90 // 默认保留90天
|
||||
if kd, ok := params["keep_days"].(float64); ok {
|
||||
keepDays = int(kd)
|
||||
}
|
||||
|
||||
rowsAffected, err := services.ClearOldAccessLogs(keepDays)
|
||||
if err != nil {
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"success": false,
|
||||
"message": "清空旧日志失败: " + err.Error(),
|
||||
}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"success": true,
|
||||
"message": fmt.Sprintf("清空旧日志成功,共删除 %d 条记录", rowsAffected),
|
||||
}
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,306 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"server/models"
|
||||
"server/services"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
)
|
||||
|
||||
// TaskController OA任务管理控制器
|
||||
type TaskController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
// GetTasks 列表查询
|
||||
// @router /api/oa/tasks [get]
|
||||
func (c *TaskController) GetTasks() {
|
||||
// 获取租户ID(JWT中间件写入)
|
||||
tenantId := 0
|
||||
if v := c.Ctx.Input.GetData("tenantId"); v != nil {
|
||||
if tid, ok := v.(int); ok {
|
||||
tenantId = tid
|
||||
}
|
||||
}
|
||||
// 允许请求参数覆盖(如有)
|
||||
if reqTenantId, err := c.GetInt("tenant_id"); err == nil && reqTenantId > 0 {
|
||||
tenantId = reqTenantId
|
||||
}
|
||||
if tenantId <= 0 {
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 1,
|
||||
"message": "租户ID无效",
|
||||
"data": nil,
|
||||
}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
keyword := c.GetString("keyword")
|
||||
status := c.GetString("status")
|
||||
priority := c.GetString("priority")
|
||||
page, _ := c.GetInt("page", 1)
|
||||
pageSize, _ := c.GetInt("pageSize", 10)
|
||||
|
||||
items, total, err := services.ListOATasks(tenantId, keyword, status, priority, page, pageSize)
|
||||
if err != nil {
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 1,
|
||||
"message": "获取任务列表失败: " + err.Error(),
|
||||
"data": nil,
|
||||
}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 0,
|
||||
"message": "获取成功",
|
||||
"data": map[string]interface{}{
|
||||
"list": items,
|
||||
"total": total,
|
||||
},
|
||||
}
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// GetTaskById 详情
|
||||
// @router /api/oa/tasks/:id [get]
|
||||
func (c *TaskController) GetTaskById() {
|
||||
id, err := c.GetInt(":id")
|
||||
if err != nil || id <= 0 {
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 1,
|
||||
"message": "任务ID无效",
|
||||
"data": nil,
|
||||
}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
t, err := services.GetOATaskById(id)
|
||||
if err != nil {
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 1,
|
||||
"message": "获取任务详情失败: " + err.Error(),
|
||||
"data": nil,
|
||||
}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 0,
|
||||
"message": "获取成功",
|
||||
"data": t,
|
||||
}
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// CreateTask 新增
|
||||
// @router /api/oa/tasks [post]
|
||||
func (c *TaskController) CreateTask() {
|
||||
var t models.Task
|
||||
body := c.Ctx.Input.RequestBody
|
||||
|
||||
// 先解析 team_employee_ids
|
||||
var extra struct {
|
||||
TeamEmployeeIds []int64 `json:"team_employee_ids"`
|
||||
}
|
||||
_ = json.Unmarshal(body, &extra)
|
||||
|
||||
// 去除 team_employee_ids 字段后再解析为 Task,避免 array->string 报错
|
||||
clean := map[string]interface{}{}
|
||||
if err := json.Unmarshal(body, &clean); err != nil {
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 1,
|
||||
"message": "参数解析失败: " + err.Error(),
|
||||
"data": nil,
|
||||
}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
delete(clean, "team_employee_ids")
|
||||
buf, _ := json.Marshal(clean)
|
||||
if err := json.Unmarshal(buf, &t); err != nil {
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 1,
|
||||
"message": "参数解析失败: " + err.Error(),
|
||||
"data": nil,
|
||||
}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
if len(extra.TeamEmployeeIds) > 0 {
|
||||
ids := make([]string, 0, len(extra.TeamEmployeeIds))
|
||||
for _, id := range extra.TeamEmployeeIds {
|
||||
ids = append(ids, strconv.FormatInt(id, 10))
|
||||
}
|
||||
t.TeamEmployeeIds = strings.Join(ids, ",")
|
||||
}
|
||||
|
||||
// 从上下文取租户和用户名交给服务层处理默认值
|
||||
tenantId := 0
|
||||
if v := c.Ctx.Input.GetData("tenantId"); v != nil {
|
||||
if tid, ok := v.(int); ok {
|
||||
tenantId = tid
|
||||
}
|
||||
}
|
||||
username := ""
|
||||
if u, ok := c.Ctx.Input.GetData("username").(string); ok {
|
||||
username = u
|
||||
}
|
||||
|
||||
if err := services.CreateOATask(&t, tenantId, username); err != nil {
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 1,
|
||||
"message": "创建任务失败: " + err.Error(),
|
||||
"data": nil,
|
||||
}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 0,
|
||||
"message": "创建成功",
|
||||
"data": map[string]interface{}{
|
||||
"id": t.Id,
|
||||
},
|
||||
}
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// UpdateTask 更新
|
||||
// @router /api/oa/tasks/:id [put]
|
||||
func (c *TaskController) UpdateTask() {
|
||||
id, err := c.GetInt(":id")
|
||||
if err != nil || id <= 0 {
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 1,
|
||||
"message": "任务ID无效",
|
||||
"data": nil,
|
||||
}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
// 保证存在
|
||||
if _, err := services.GetOATaskById(id); err != nil {
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 1,
|
||||
"message": "任务不存在: " + err.Error(),
|
||||
"data": nil,
|
||||
}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
var t models.Task
|
||||
body := c.Ctx.Input.RequestBody
|
||||
|
||||
// 先解析 team_employee_ids
|
||||
var extra struct {
|
||||
TeamEmployeeIds []int64 `json:"team_employee_ids"`
|
||||
}
|
||||
_ = json.Unmarshal(body, &extra)
|
||||
|
||||
// 去除 team_employee_ids 字段后再解析为 Task,避免 array->string 报错
|
||||
clean := map[string]interface{}{}
|
||||
if err := json.Unmarshal(body, &clean); err != nil {
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 1,
|
||||
"message": "参数解析失败: " + err.Error(),
|
||||
"data": nil,
|
||||
}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
delete(clean, "team_employee_ids")
|
||||
buf, _ := json.Marshal(clean)
|
||||
if err := json.Unmarshal(buf, &t); err != nil {
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 1,
|
||||
"message": "参数解析失败: " + err.Error(),
|
||||
"data": nil,
|
||||
}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
t.Id = id
|
||||
|
||||
ids := make([]string, 0, len(extra.TeamEmployeeIds))
|
||||
for _, eid := range extra.TeamEmployeeIds {
|
||||
ids = append(ids, strconv.FormatInt(eid, 10))
|
||||
}
|
||||
if len(ids) > 0 {
|
||||
t.TeamEmployeeIds = strings.Join(ids, ",")
|
||||
} else {
|
||||
// 明确传空时,清空关联人
|
||||
t.TeamEmployeeIds = ""
|
||||
}
|
||||
|
||||
// 操作人交由服务层设置
|
||||
username := ""
|
||||
if u, ok := c.Ctx.Input.GetData("username").(string); ok {
|
||||
username = u
|
||||
}
|
||||
|
||||
if err := services.UpdateOATask(&t, username); err != nil {
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 1,
|
||||
"message": "更新任务失败: " + err.Error(),
|
||||
"data": nil,
|
||||
}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 0,
|
||||
"message": "更新成功",
|
||||
"data": nil,
|
||||
}
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// DeleteTask 删除(软删除)
|
||||
// @router /api/oa/tasks/:id [delete]
|
||||
func (c *TaskController) DeleteTask() {
|
||||
id, err := c.GetInt(":id")
|
||||
if err != nil || id <= 0 {
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 1,
|
||||
"message": "任务ID无效",
|
||||
"data": nil,
|
||||
}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
operatorName := "system"
|
||||
operatorId := 0
|
||||
if username, ok := c.Ctx.Input.GetData("username").(string); ok && username != "" {
|
||||
operatorName = username
|
||||
}
|
||||
if uid, ok := c.Ctx.Input.GetData("userId").(int); ok && uid > 0 {
|
||||
operatorId = uid
|
||||
}
|
||||
|
||||
if err := services.DeleteOATask(id, operatorName, operatorId); err != nil {
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 1,
|
||||
"message": "删除任务失败: " + err.Error(),
|
||||
"data": nil,
|
||||
}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 0,
|
||||
"message": "删除成功",
|
||||
"data": nil,
|
||||
}
|
||||
c.ServeJSON()
|
||||
}
|
||||
Reference in New Issue
Block a user