作者 郑周

1. 增加操作日志

... ... @@ -263,3 +263,11 @@ func CreateTaskAnomalyRepository(options map[string]interface{}) domain.TaskAnom
}
return repository.NewTaskAnomalyRepository(transactionContext)
}
func CreateLogOptRepository(options map[string]interface{}) domain.LogOptRepository {
var transactionContext *pg.TransactionContext
if value, ok := options["transactionContext"]; ok {
transactionContext = value.(*pg.TransactionContext)
}
return repository.NewLogOptRepository(transactionContext)
}
... ...
package command
import "github.com/beego/beego/v2/core/validation"
type QueryLogCommand struct {
CompanyId int64 `cname:"公司ID" json:"-"`
TaskId int `cname:"任务ID" json:"taskId,string" valid:"Required"`
PageNumber int64 `cname:"分页页码" json:"pageNumber" valid:"Required"`
PageSize int64 `cname:"分页数量" json:"pageSize" valid:"Required"`
}
func (in *QueryLogCommand) Valid(*validation.Validation) {
}
... ...
package log_opt
import (
"fmt"
"github.com/linmadan/egglib-go/core/application"
"gitlab.fjmaimaimai.com/allied-creation/performance/pkg/application/factory"
"gitlab.fjmaimaimai.com/allied-creation/performance/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/performance/pkg/log"
"strconv"
"time"
)
func CreateTask(u *domain.UserAuth, task domain.Task) error {
transactionContext, err := factory.StartTransaction()
if err != nil {
return err
}
defer func() {
_ = transactionContext.RollbackTransaction()
if err := recover(); err != nil {
log.Logger.Error(application.ThrowError(application.BUSINESS_ERROR, fmt.Sprintf("创建任务日志异常:%s", err)).Error())
}
}()
logOptRepo := factory.CreateLogOptRepository(map[string]interface{}{"transactionContext": transactionContext})
logOpt := createdLogOpt(u, strconv.Itoa(task.Id))
logOpt.OptMethod = domain.CREATE
logOpt.OptField = "创建了任务"
logOpt.OptValue = task.Alias
_, err = logOptRepo.Insert(logOpt)
if err != nil {
return application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
}
if err := transactionContext.CommitTransaction(); err != nil {
return application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
return nil
}
func UpdateTask(u *domain.UserAuth,
srcTask *domain.Task,
newTask *domain.Task,
srcStage []*domain.TaskStage,
newStage []*domain.TaskStage,
) error {
transactionContext, err := factory.StartTransaction()
if err != nil {
return err
}
defer func() {
_ = transactionContext.RollbackTransaction()
if err := recover(); err != nil {
log.Logger.Error(application.ThrowError(application.BUSINESS_ERROR, fmt.Sprintf("更新任务日志异常:%s", err)).Error())
}
}()
logOptRepo := factory.CreateLogOptRepository(map[string]interface{}{"transactionContext": transactionContext})
var logArray = compareTask(u, srcTask, newTask)
var logArray2 = compareStage(u, newTask.Id, srcStage, newStage)
logArray = append(logArray, logArray2...)
if len(logArray) == 0 {
return nil
}
for _, v := range logArray {
_, err = logOptRepo.Insert(v)
if err != nil {
return application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
}
}
if err := transactionContext.CommitTransaction(); err != nil {
return application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
return nil
}
func compareTask(u *domain.UserAuth, srcTask *domain.Task, newTask *domain.Task) []*domain.LogOpt {
var taskId = strconv.Itoa(newTask.Id)
logArray := make([]*domain.LogOpt, 0)
if srcTask.Alias != newTask.Alias {
logOpt := createdLogOpt(u, taskId)
logOpt.OptField = "修改了任务名称"
logOpt.OptValue = newTask.Alias
logArray = append(logArray, logOpt)
}
if srcTask.EndTime != newTask.EndTime {
logOpt := createdLogOpt(u, taskId)
logOpt.OptField = "修改了任务截止时间"
if newTask.EndTime == 0 {
logOpt.OptValue = "未设置时间"
} else {
logOpt.OptValue = time.Unix(newTask.EndTime, 0).Local().Format("2006-01-02 15:04:05")
}
logArray = append(logArray, logOpt)
}
if srcTask.UseEndTime != newTask.UseEndTime {
logOpt := createdLogOpt(u, taskId)
logOpt.OptField = "修改了任务截止时间应用到日评中"
if newTask.UseEndTime == 0 {
logOpt.OptValue = "不应用"
} else {
logOpt.OptValue = "应用"
}
logArray = append(logArray, logOpt)
}
if srcTask.LevelName != newTask.LevelName {
logOpt := createdLogOpt(u, taskId)
logOpt.OptField = "修改了任务类型"
logOpt.OptValue = newTask.LevelName
logArray = append(logArray, logOpt)
}
if srcTask.SortBy != newTask.SortBy {
logOpt := createdLogOpt(u, taskId)
logOpt.OptField = "修改了任务优先级"
logOpt.OptValue = newTask.SortBy.Named()
logArray = append(logArray, logOpt)
}
if srcTask.AssistFlagMax != newTask.AssistFlagMax {
logOpt := createdLogOpt(u, taskId)
logOpt.OptField = "修改了上级辅导时间"
logOpt.OptValue = strconv.Itoa(newTask.AssistFlagMax)
logArray = append(logArray, logOpt)
}
// 新的任务相关方
uidNewMap := map[int]int{}
for _, id := range newTask.RelatedUser {
uidNewMap[id] = id
}
// 被移除的任务相关方
removedIds := make([]int, 0)
for _, id := range srcTask.RelatedUser {
if _, ok := uidNewMap[id]; ok {
delete(uidNewMap, id) // 删除后,剩余的都是新增的
} else {
removedIds = append(removedIds, id)
}
}
// 变动的任务相关方
changeIds := make([]int, 0)
for _, v := range removedIds {
changeIds = append(changeIds, v)
}
for _, v := range uidNewMap {
changeIds = append(changeIds, v)
}
userMap, _ := getUserMap(changeIds)
for _, v := range removedIds {
logOpt := createdLogOpt(u, taskId)
logOpt.OptMethod = domain.DELETE
logOpt.OptField = "移除了任务相关方"
if v, ok := userMap[v]; ok {
logOpt.OptValue = v.Name
}
logArray = append(logArray, logOpt)
}
for _, v := range uidNewMap {
logOpt := createdLogOpt(u, taskId)
logOpt.OptMethod = domain.CREATE
logOpt.OptField = "添加了任务相关方"
if v, ok := userMap[v]; ok {
logOpt.OptValue = v.Name
}
logArray = append(logArray, logOpt)
}
return logArray
}
func compareStage(u *domain.UserAuth, id int, srcStage []*domain.TaskStage, newStage []*domain.TaskStage) []*domain.LogOpt {
taskId := strconv.Itoa(id)
logArray := make([]*domain.LogOpt, 0)
srcMap := map[int]*domain.TaskStage{}
for i := range srcStage {
it := srcStage[i]
srcMap[it.Id] = it
}
for i := range newStage {
it := newStage[i]
if it.DeletedAt != nil {
logOpt := createdLogOpt(u, taskId)
logOpt.OptMethod = domain.DELETE
logOpt.OptField = "删除了里程碑"
logOpt.OptValue = it.Name
logArray = append(logArray, logOpt)
continue
}
// 新旧比对
if v, ok := srcMap[it.Id]; ok {
if it.Name != v.Name {
logOpt := createdLogOpt(u, taskId)
logOpt.OptField = "修改了里程碑名称"
logOpt.OptValue = it.Name
logArray = append(logArray, logOpt)
}
if it.PlanCompletedAt != v.PlanCompletedAt {
logOpt := createdLogOpt(u, taskId)
logOpt.OptField = "修改了里程碑" + it.Name + "计划完成时间"
if it.PlanCompletedAt == 0 {
logOpt.OptValue = "未设置时间"
} else {
logOpt.OptValue = time.Unix(it.PlanCompletedAt, 0).Local().Format("2006-01-02 15:04:05")
}
logArray = append(logArray, logOpt)
}
} else {
logOpt := createdLogOpt(u, taskId)
logOpt.OptMethod = domain.CREATE
logOpt.OptField = "创建了里程碑"
logOpt.OptValue = it.Name
logArray = append(logArray, logOpt)
}
}
return logArray
}
func getUserMap(ids []int) (map[int]*domain.User, error) {
userMap := map[int]*domain.User{}
if len(ids) == 0 {
return userMap, nil
}
transactionContext, err := factory.CreateTransactionContext(nil)
if err != nil {
return userMap, err
}
userRepo := factory.CreateUserRepository(map[string]interface{}{"transactionContext": transactionContext})
_, users, err := userRepo.Find(map[string]interface{}{"ids": ids, "limit": len(ids)})
if err != nil {
return userMap, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
}
for i := range users {
user := users[i]
userMap[int(user.Id)] = user
}
return userMap, nil
}
func createdLogOpt(u *domain.UserAuth, taskId string) *domain.LogOpt {
var createdAt = time.Now()
var updatedAt = createdAt
operator := domain.StaffDesc{
UserId: int(u.UserId),
CompanyName: u.CompanyName,
Account: u.Phone,
UserName: u.Name,
}
return &domain.LogOpt{
Id: 0,
CompanyId: int(u.CompanyId),
Operator: operator,
OptMethod: domain.UPDATE,
OptTargetId: taskId,
OptField: "",
OptValue: "",
CreatedAt: createdAt,
UpdatedAt: updatedAt,
}
}
... ...
package log_opt
import (
"github.com/linmadan/egglib-go/core/application"
"github.com/linmadan/egglib-go/utils/tool_funs"
"gitlab.fjmaimaimai.com/allied-creation/performance/pkg/application/factory"
"gitlab.fjmaimaimai.com/allied-creation/performance/pkg/application/log_opt/command"
)
type LogOptService struct {
}
func NewLogOptService() *LogOptService {
newRoleService := &LogOptService{}
return newRoleService
}
func (rs *LogOptService) List(in *command.QueryLogCommand) (interface{}, error) {
transactionContext, err := factory.ValidateStartTransaction(in)
if err != nil {
return nil, err
}
defer func() {
transactionContext.RollbackTransaction()
}()
ssMap := tool_funs.SimpleStructToMap(in)
ssMap["companyId"] = in.CompanyId
ssMap["optTargetId"] = in.TaskId
logRepository := factory.CreateLogOptRepository(map[string]interface{}{"transactionContext": transactionContext})
total, logList, err := logRepository.Find(ssMap)
if err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
}
if err := transactionContext.CommitTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
return tool_funs.SimpleWrapGridMap(total, logList), nil
}
... ...
... ... @@ -9,7 +9,7 @@ type UpdateTaskCommand struct {
RelatedUserId []string `json:"relatedUserId"` // 相关人员id
SortBy int `json:"sortBy"` // 优先级排序;值越小优先级越高
EndTime int64 `json:"endTime"` // 任务截止的时间戳,单位:秒;等于0时表示未设置时间
UseEndtime int `json:"useEndTime"` // 是否应用任务截止的时间;默认值0:不应用,1:应用
UseEndTime int `json:"useEndTime"` // 是否应用任务截止的时间;默认值0:不应用,1:应用
StageList []struct {
Id int `json:"id,string"`
Name string `json:"name"` //里程碑名称
... ...
... ... @@ -2,6 +2,7 @@ package service
import (
"fmt"
"gitlab.fjmaimaimai.com/allied-creation/performance/pkg/application/log_opt"
"strconv"
"strings"
"time"
... ... @@ -116,8 +117,8 @@ func (srv TaskService) CreateTaskByProject(transactionContext application.Transa
return nil
}
// 创建任务
func (srv TaskService) CreateTask(param *command.CreateTaskCommand) (map[string]interface{}, error) {
// CreateTask 创建任务
func (srv TaskService) CreateTask(param *command.CreateTaskCommand, userReq *domain.UserAuth) (map[string]interface{}, error) {
sortNamed := domain.TaskSortBy(param.SortBy)
if sortNamed.Named() == "" {
return nil, application.ThrowError(application.TRANSACTION_ERROR, "优先级设置错误")
... ... @@ -220,11 +221,15 @@ func (srv TaskService) CreateTask(param *command.CreateTaskCommand) (map[string]
if err := transactionContext.CommitTransaction(); err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
}
// 生成创建日志
_ = log_opt.CreateTask(userReq, newTask)
return map[string]interface{}{"id": newTask.Id}, nil
}
// 更新任务
func (srv TaskService) UpdateTask(param *command.UpdateTaskCommand) (map[string]interface{}, error) {
// UpdateTask 更新任务
func (srv TaskService) UpdateTask(param *command.UpdateTaskCommand, userReq *domain.UserAuth) (map[string]interface{}, error) {
transactionContext, err := factory.CreateTransactionContext(nil)
if err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
... ... @@ -274,6 +279,14 @@ func (srv TaskService) UpdateTask(param *command.UpdateTaskCommand) (map[string]
if leaderList[0].CompanyId != int64(param.CompanyId) {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "负责人数据验证不通过")
}
// 拷贝数据
var copyTask = taskData.Copy()
var copyStageList = make([]*domain.TaskStage, 0)
for _, v := range stageList {
copyStageList = append(copyStageList, v)
}
//更新任务的相关人员
relatedUserIds := []int{}
for _, val := range param.RelatedUserId {
... ... @@ -382,7 +395,7 @@ func (srv TaskService) UpdateTask(param *command.UpdateTaskCommand) (map[string]
} else {
taskData.EndTime = dayEndTime(time.Unix(param.EndTime, 10)).Unix()
}
taskData.UseEndTime = param.UseEndtime
taskData.UseEndTime = param.UseEndTime
taskData.AssistFlagMax = param.AssistFlagMax
err = taskRepo.Save(taskData)
if err != nil {
... ... @@ -420,6 +433,10 @@ func (srv TaskService) UpdateTask(param *command.UpdateTaskCommand) (map[string]
if err := transactionContext.CommitTransaction(); err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
}
// 生成更新日志
_ = log_opt.UpdateTask(userReq, &copyTask, taskData, copyStageList, stageList)
return map[string]interface{}{
"id": param.Id,
}, nil
... ...
package domain
import "time"
type OptMethod int
const (
CREATE OptMethod = 1 // 创建
UPDATE OptMethod = 2 // 更新
DELETE OptMethod = 3 // 删除
)
// LogOpt 操作日志
type LogOpt struct {
//OptModule string `json:"optModule" comment:"操作模块"`
Id int `json:"id,string" comment:"ID" pg:"id,pk"`
CompanyId int `json:"companyId" comment:"公司ID"`
Operator StaffDesc `json:"operator" comment:"操作人"`
OptMethod OptMethod `json:"optMethod" comment:"操作方法"`
OptTargetId string `json:"optTargetId" comment:"操作目标ID"`
OptField string `json:"optField" comment:"操作字段"`
OptValue string `json:"optValue" comment:"操作字段值"`
CreatedAt time.Time `json:"createdAt" comment:"创建时间"`
UpdatedAt time.Time `json:"updatedAt" comment:"更新时间"`
DeletedAt *time.Time `json:"deletedAt" comment:"删除时间"`
}
type LogOptRepository interface {
Insert(opt *LogOpt) (*LogOpt, error)
Remove(opt *LogOpt) (*LogOpt, error)
FindOne(queryOptions map[string]interface{}) (*LogOpt, error)
Find(queryOptions map[string]interface{}) (int64, []*LogOpt, error)
Count(queryOptions map[string]interface{}) (int64, error)
}
... ...
package models
import (
"gitlab.fjmaimaimai.com/allied-creation/performance/pkg/domain"
"time"
)
// LogOpt 操作日志
type LogOpt struct {
//OptModule string `comment:"操作模块"`
tableName struct{} `comment:"操作日志" pg:"log_opt"`
Id int `comment:"ID" pg:"id,pk"`
CompanyId int `comment:"公司ID"`
Operator domain.StaffDesc `comment:"操作人"`
OptMethod domain.OptMethod `comment:"操作方法"`
OptTargetId string `comment:"操作目标ID"`
OptField string `comment:"操作字段"`
OptValue string `comment:"操作字段值"`
CreatedAt time.Time `comment:"创建时间"`
UpdatedAt time.Time `comment:"更新时间"`
DeletedAt *time.Time `comment:"删除时间"`
}
... ...
package repository
import (
"errors"
"fmt"
"time"
"github.com/go-pg/pg/v10"
"github.com/linmadan/egglib-go/persistent/pg/sqlbuilder"
pgTransaction "github.com/linmadan/egglib-go/transaction/pg"
"gitlab.fjmaimaimai.com/allied-creation/performance/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/performance/pkg/infrastructure/pg/models"
"gitlab.fjmaimaimai.com/allied-creation/performance/pkg/utils"
)
type LogOptRepository struct {
transactionContext *pgTransaction.TransactionContext
}
func NewLogOptRepository(transactionContext *pgTransaction.TransactionContext) *LogOptRepository {
return &LogOptRepository{transactionContext: transactionContext}
}
func (repo *LogOptRepository) TransformToDomain(m *models.LogOpt) domain.LogOpt {
return domain.LogOpt{
Id: m.Id,
CompanyId: m.CompanyId,
Operator: m.Operator,
OptMethod: m.OptMethod,
OptTargetId: m.OptTargetId,
OptField: m.OptField,
OptValue: m.OptValue,
CreatedAt: m.CreatedAt.Local(),
UpdatedAt: m.UpdatedAt.Local(),
DeletedAt: m.DeletedAt,
}
}
func (repo *LogOptRepository) TransformToModel(d *domain.LogOpt) models.LogOpt {
return models.LogOpt{
Id: d.Id,
CompanyId: d.CompanyId,
Operator: d.Operator,
OptMethod: d.OptMethod,
OptTargetId: d.OptTargetId,
OptField: d.OptField,
OptValue: d.OptValue,
CreatedAt: d.CreatedAt,
UpdatedAt: d.UpdatedAt,
DeletedAt: d.DeletedAt,
}
}
func (repo *LogOptRepository) Insert(d *domain.LogOpt) (*domain.LogOpt, error) {
var isCreate = d.Id == 0
if isCreate {
id, err := utils.NewSnowflakeId()
if err != nil {
return d, err
}
d.Id = int(id)
d.CreatedAt = time.Now()
d.UpdatedAt = d.CreatedAt
} else {
d.UpdatedAt = time.Now()
}
m := repo.TransformToModel(d)
tx := repo.transactionContext.PgTx
var err error
if isCreate {
_, err = tx.Model(&m).Returning("id").Insert()
} else {
_, err = tx.Model(&m).Returning("id").WherePK().Update() // 更新和删除必须增加条件
}
if err != nil {
return nil, err
}
d.Id = m.Id
return d, nil
}
func (repo *LogOptRepository) Remove(d *domain.LogOpt) (*domain.LogOpt, error) {
tx := repo.transactionContext.PgTx
nowTime := time.Now()
m := repo.TransformToModel(d)
m.DeletedAt = &nowTime
if _, err := tx.Model(&m).WherePK().Update(); err != nil {
return d, err
}
return d, nil
}
func (repo *LogOptRepository) FindOne(queryOptions map[string]interface{}) (*domain.LogOpt, error) {
tx := repo.transactionContext.PgTx
m := new(models.LogOpt)
query := tx.Model(m)
query.Where("deleted_at isnull")
if id, ok := queryOptions["id"]; ok {
query.Where("id=?", id)
}
if err := query.First(); err != nil {
if errors.Is(err, pg.ErrNoRows) {
return nil, fmt.Errorf("没有此资源")
} else {
return nil, err
}
}
u := repo.TransformToDomain(m)
return &u, nil
}
func (repo *LogOptRepository) Find(queryOptions map[string]interface{}) (int64, []*domain.LogOpt, error) {
tx := repo.transactionContext.PgTx
var m []*models.LogOpt
query := tx.Model(&m).Where("deleted_at isnull")
if v, ok := queryOptions["ids"]; ok {
query.Where("id in (?)", pg.In(v))
}
if v, ok := queryOptions["id"]; ok {
query.Where("id=?", v)
}
if v, ok := queryOptions["companyId"]; ok {
query.Where("company_id = ?", v)
}
if v, ok := queryOptions["optTargetId"]; ok {
query.Where("opt_target_id = ?", v)
}
if v, ok := queryOptions["limit"].(int64); ok {
query.Limit(int(v))
}
if v, ok := queryOptions["offset"].(int64); ok {
query.Offset(int(v))
}
// 按创建时间降序
query.Order("created_at DESC")
count, err := query.SelectAndCount()
if err != nil {
return 0, nil, err
}
var arrays []*domain.LogOpt
for _, v := range m {
d := repo.TransformToDomain(v)
arrays = append(arrays, &d)
}
return int64(count), arrays, nil
}
func (repo *LogOptRepository) Count(queryOptions map[string]interface{}) (int64, error) {
tx := repo.transactionContext.PgTx
m := new(models.LogOpt)
query := sqlbuilder.BuildQuery(tx.Model(m), queryOptions)
query.Where("deleted_at isnull")
if id, ok := queryOptions["id"]; ok {
query.Where("id = ?", id)
}
if notId, ok := queryOptions["notId"]; ok {
query.Where("id != ?", notId)
}
if v, ok := queryOptions["companyId"]; ok {
query.Where("company_id = ?", v)
}
count, err := query.Count()
if err != nil {
return 0, err
}
return int64(count), nil
}
... ...
package controllers
import (
"github.com/linmadan/egglib-go/core/application"
"github.com/linmadan/egglib-go/web/beego"
service "gitlab.fjmaimaimai.com/allied-creation/performance/pkg/application/log_opt"
"gitlab.fjmaimaimai.com/allied-creation/performance/pkg/application/log_opt/command"
"gitlab.fjmaimaimai.com/allied-creation/performance/pkg/port/beego/middlewares"
)
type LogOptController struct {
beego.BaseController
}
func (controller *LogOptController) ListLog() {
logService := service.NewLogOptService()
in := &command.QueryLogCommand{}
if err := controller.Unmarshal(in); err != nil {
controller.Response(nil, application.ThrowError(application.ARG_ERROR, err.Error()))
} else {
ua := middlewares.GetUser(controller.Ctx)
in.CompanyId = ua.CompanyId
controller.Response(logService.List(in))
}
}
... ...
... ... @@ -41,7 +41,7 @@ func (c *TaskController) UpdateTask() {
}
userReq := middlewares.GetUser(c.Ctx)
paramReq.CompanyId = int(userReq.CompanyId)
data, err := srv.UpdateTask(paramReq)
data, err := srv.UpdateTask(paramReq, userReq)
c.Response(data, err)
}
... ... @@ -55,8 +55,9 @@ func (c *TaskController) CreateTask() {
c.Response(nil, e)
return
}
resp, err := srv.CreateTask(paramReq)
userReq := middlewares.GetUser(c.Ctx)
paramReq.CompanyId = int(userReq.CompanyId)
resp, err := srv.CreateTask(paramReq, userReq)
c.Response(resp, err)
}
... ...
package routers
import (
"github.com/beego/beego/v2/server/web"
"github.com/linmadan/egglib-go/web/beego/filters"
"gitlab.fjmaimaimai.com/allied-creation/performance/pkg/port/beego/controllers"
"gitlab.fjmaimaimai.com/allied-creation/performance/pkg/port/beego/middlewares"
)
func init() {
ns := web.NewNamespace("/v1/log-opt",
web.NSBefore(filters.AllowCors(), middlewares.CheckAdminToken()),
web.NSRouter("/list", &controllers.LogOptController{}, "Post:ListLog"),
)
web.AddNamespace(ns)
}
... ...