增加任务管理模块

This commit is contained in:
2025-11-12 17:32:03 +08:00
parent 12a0ff8afc
commit db16ee70de
54 changed files with 3638 additions and 672 deletions
+2 -2
View File
@@ -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",
+103
View File
@@ -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()
}
+191
View File
@@ -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(&params); err != nil {
// 如果ParseForm失败,尝试解析JSON
c.Ctx.Input.Bind(&params, "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()
}
+306
View File
@@ -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() {
// 获取租户IDJWT中间件写入)
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()
}