From 53ed09e6bebad554bac6aae32eacb109f7689144 Mon Sep 17 00:00:00 2001 From: daiyb <570956418@qq.com> Date: Thu, 23 Oct 2025 16:51:27 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AE=9A=E6=97=B6=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/cast/cast.pb.go | 7 +- cmd/app.go | 9 ++- cmd/config/config.go | 1 + docs/dev/conf.ini | 1 + docs/prod/conf.ini | 1 + docs/test/conf.ini | 1 + pkg/cron/cron_manager.go | 134 +++++++++++++++++++++++++++++++++++ pkg/cron/task.go | 36 ++++++++++ pkg/service/cast/approval.go | 3 + pkg/service/cast/user.go | 11 ++- pkg/service/cast/work.go | 15 ++-- 11 files changed, 210 insertions(+), 9 deletions(-) create mode 100644 pkg/cron/cron_manager.go create mode 100644 pkg/cron/task.go diff --git a/api/cast/cast.pb.go b/api/cast/cast.pb.go index a2cf8ff..54fb5d5 100644 --- a/api/cast/cast.pb.go +++ b/api/cast/cast.pb.go @@ -7,15 +7,16 @@ package cast import ( + reflect "reflect" + sync "sync" + unsafe "unsafe" + _ "github.com/envoyproxy/protoc-gen-validate/validate" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" _ "google.golang.org/protobuf/types/descriptorpb" emptypb "google.golang.org/protobuf/types/known/emptypb" _ "google.golang.org/protobuf/types/known/wrapperspb" - reflect "reflect" - sync "sync" - unsafe "unsafe" ) const ( diff --git a/cmd/app.go b/cmd/app.go index 18d5b1b..96456f0 100644 --- a/cmd/app.go +++ b/cmd/app.go @@ -22,6 +22,7 @@ import ( "fonchain-fiee/cmd/config" "fonchain-fiee/pkg/cache" "fonchain-fiee/pkg/common" + cronpkg "fonchain-fiee/pkg/cron" "fonchain-fiee/pkg/logger" "fonchain-fiee/pkg/router" ) @@ -32,6 +33,7 @@ func main() { if err := bootstrap(); err != nil { panic(err) } + r := router.NewRouter() _ = r.Run(config.AppConfig.System.HttpPort) select {} @@ -57,7 +59,12 @@ func bootstrap() (err error) { cache.LoadRedis(redisConfig) common.Init() - // + if configEnv.System.CronOpen { + fmt.Println("启动定时任务管理器...") + if err = cronpkg.InitTasks(); err != nil { + fmt.Printf("定时任务启动失败: %v\n", err) + } + } //gpt.InitSet(configEnv.Ai.Host, configEnv.Ai.TelNum, configEnv.Ai.Password) return nil } diff --git a/cmd/config/config.go b/cmd/config/config.go index 66e64dd..a4aee58 100644 --- a/cmd/config/config.go +++ b/cmd/config/config.go @@ -119,6 +119,7 @@ type System struct { ErpHost string FieeHost string AuthRedirectUrl string + CronOpen bool } type Oss struct { AccessKeyId string diff --git a/docs/dev/conf.ini b/docs/dev/conf.ini index 64aa993..c3cb770 100644 --- a/docs/dev/conf.ini +++ b/docs/dev/conf.ini @@ -7,6 +7,7 @@ RedirectUri = "/api/redirect/url" ErpHost = "http://114.218.158.24:9020" FieeHost = "http://114.218.158.24:9020" AuthRedirectUrl = "http://121.229.45.214:9028/media_account" +CronOpen = false [bos] Ak = "ALTAKxrqOQHnAN525Tb2GX4Bhe" Sk = "d2ecaa9d75114d3b9f42b99014198306" diff --git a/docs/prod/conf.ini b/docs/prod/conf.ini index 47621f7..c139f40 100644 --- a/docs/prod/conf.ini +++ b/docs/prod/conf.ini @@ -7,6 +7,7 @@ RedirectUri = "/api/redirect/url" ErpHost = "https://erpapi.fontree.cn" FieeHost = "https://erpapi.fiee.com" AuthRedirectUrl = "https://erp.fiee.com/media_account" +CronOpen = true [bos] Ak = "ALTAKxrqOQHnAN525Tb2GX4Bhe" Sk = "d2ecaa9d75114d3b9f42b99014198306" diff --git a/docs/test/conf.ini b/docs/test/conf.ini index 8a57902..e79bc26 100644 --- a/docs/test/conf.ini +++ b/docs/test/conf.ini @@ -8,6 +8,7 @@ ErpHost = "http://114.218.158.24:9020" FieeHost = "http://114.218.158.24:9020" FieeApiHost = "https://saas-test.szjixun.cn" AuthRedirectUrl = "http://121.229.45.214:9028/media_account" +CronOpen = true [bos] Ak = "ALTAKxrqOQHnAN525Tb2GX4Bhe" Sk = "d2ecaa9d75114d3b9f42b99014198306" diff --git a/pkg/cron/cron_manager.go b/pkg/cron/cron_manager.go new file mode 100644 index 0000000..d8dbfb6 --- /dev/null +++ b/pkg/cron/cron_manager.go @@ -0,0 +1,134 @@ +package cron + +import ( + "fmt" + "log" + "sync" + + "github.com/robfig/cron/v3" +) + +var ( + cronManager *CronManager + once sync.Once +) + +// CronManager 定时任务管理器 +type CronManager struct { + cron *cron.Cron + tasks map[string]cron.EntryID + mu sync.RWMutex + isRunning bool +} + +// GetCronManager 获取定时任务管理器单例 +func GetCronManager() *CronManager { + once.Do(func() { + cronManager = &CronManager{ + cron: cron.New(cron.WithSeconds()), // 支持秒级定时 + tasks: make(map[string]cron.EntryID), + } + }) + return cronManager +} + +// AddTask 添加定时任务 +// name: 任务名称,用于标识任务 +// spec: cron表达式,例如: +func (cm *CronManager) AddTask(name string, spec string, job func()) error { + cm.mu.Lock() + defer cm.mu.Unlock() + if _, exists := cm.tasks[name]; exists { + return fmt.Errorf("任务 %s 已存在", name) + } + // 添加任务 + entryID, err := cm.cron.AddFunc(spec, func() { + defer func() { + if r := recover(); r != nil { + log.Printf("定时任务 [%s] 执行panic: %v", name, r) + } + }() + log.Printf("定时任务 [%s] 开始执行", name) + job() + log.Printf("定时任务 [%s] 执行完成", name) + }) + + if err != nil { + return fmt.Errorf("添加任务失败: %v", err) + } + cm.tasks[name] = entryID + log.Printf("定时任务 [%s] 添加成功, cron表达式: %s", name, spec) + return nil +} + +// RemoveTask 移除定时任务 +func (cm *CronManager) RemoveTask(name string) error { + cm.mu.Lock() + defer cm.mu.Unlock() + + entryID, exists := cm.tasks[name] + if !exists { + return fmt.Errorf("任务 %s 不存在", name) + } + + cm.cron.Remove(entryID) + delete(cm.tasks, name) + log.Printf("定时任务 [%s] 已移除", name) + return nil +} + +// Start 启动定时任务管理器 +func (cm *CronManager) Start() { + cm.mu.Lock() + defer cm.mu.Unlock() + + if cm.isRunning { + log.Println("定时任务管理器已经在运行中") + return + } + + cm.cron.Start() + cm.isRunning = true + log.Printf("定时任务管理器已启动,当前任务数: %d", len(cm.tasks)) +} + +// Stop 停止定时任务管理器 +func (cm *CronManager) Stop() { + cm.mu.Lock() + defer cm.mu.Unlock() + + if !cm.isRunning { + return + } + + ctx := cm.cron.Stop() + <-ctx.Done() + cm.isRunning = false + log.Println("定时任务管理器已停止") +} + +// IsRunning 检查是否在运行 +func (cm *CronManager) IsRunning() bool { + cm.mu.RLock() + defer cm.mu.RUnlock() + return cm.isRunning +} + +// GetTaskCount 获取任务数量 +func (cm *CronManager) GetTaskCount() int { + cm.mu.RLock() + defer cm.mu.RUnlock() + return len(cm.tasks) +} + +// ListTasks 列出所有任务名称 +func (cm *CronManager) ListTasks() []string { + cm.mu.RLock() + defer cm.mu.RUnlock() + + taskNames := make([]string, 0, len(cm.tasks)) + for name := range cm.tasks { + taskNames = append(taskNames, name) + } + return taskNames +} diff --git a/pkg/cron/task.go b/pkg/cron/task.go new file mode 100644 index 0000000..b4bbad5 --- /dev/null +++ b/pkg/cron/task.go @@ -0,0 +1,36 @@ +package cron + +import ( + "context" + "fonchain-fiee/api/cast" + "fonchain-fiee/pkg/service" + serverCast "fonchain-fiee/pkg/service/cast" + "log" +) + +// InitTasks 初始化定时任务 +func InitTasks() error { + cm := GetCronManager() + err := cm.AddTask("refreshWorkApprovalStatus", "0 */5 * * * *", RefreshWorkApprovalStatusTask) + if err != nil { + log.Printf("添加测试任务失败: %v", err) + } + cm.Start() + return nil +} + +func RefreshWorkApprovalStatusTask() { + resp, err := service.CastProvider.WorkList(context.Background(), &cast.WorkListReq{ + Page: 1, + WorkStatus: uint32(cast.WorkActionENUM_APPROVAL), + PageSize: 9999, + }) + if err != nil { + log.Printf("获取工作列表失败: %v", err) + return + } + if resp.Data == nil || len(resp.Data) == 0 { + return + } + serverCast.RefreshWorkApproval(nil, resp.Data) +} diff --git a/pkg/service/cast/approval.go b/pkg/service/cast/approval.go index 67ec517..1d3e232 100644 --- a/pkg/service/cast/approval.go +++ b/pkg/service/cast/approval.go @@ -8,6 +8,8 @@ import ( "fonchain-fiee/pkg/e" modelCast "fonchain-fiee/pkg/model/cast" "fonchain-fiee/pkg/utils" + + "go.uber.org/zap" ) type CastService struct { @@ -25,6 +27,7 @@ func (c *CastService) ApprovalDetail(approvalIds []int) (data map[int]modelCast. url := fmt.Sprintf(config.AppConfig.System.FieeHost + "/approval/list/ex") respBody, err = utils.Post(url, string(idsBytes)) if err != nil { + zap.L().Error("ApprovalDetail error", zap.Error(err)) return } var respDetail modelCast.ApprovalDetailResponse diff --git a/pkg/service/cast/user.go b/pkg/service/cast/user.go index 59a228b..71bcb8a 100644 --- a/pkg/service/cast/user.go +++ b/pkg/service/cast/user.go @@ -13,7 +13,16 @@ import ( func NewCtxWithUserInfo(ctx *gin.Context) (newCtx context.Context) { var userInfo = login.Info{} if config.AppConfig.System.AppMode == "prod" { - userInfo = login.GetUserInfoFromC(ctx) + //_, ok := ctx.Get("jwtInfo") + if ctx == nil { + userInfo = login.Info{ + ID: 0, + Name: "系统", + TelNum: "", + } + } else { + userInfo = login.GetUserInfoFromC(ctx) + } } else { userInfo = login.Info{ ID: 61, diff --git a/pkg/service/cast/work.go b/pkg/service/cast/work.go index b527a12..801dce2 100644 --- a/pkg/service/cast/work.go +++ b/pkg/service/cast/work.go @@ -146,9 +146,15 @@ func WorkList(ctx *gin.Context) { service.Error(ctx, err) return } - if len(resp.Data) > 0 { + RefreshWorkApproval(ctx, resp.Data) + service.Success(ctx, resp) + return +} + +func RefreshWorkApproval(ctx *gin.Context, data []*cast.WorkListResp_Info) { + if len(data) > 0 { var workUuidApprovalIDMap = make(map[int]string) - for _, v := range resp.Data { + for _, v := range data { if v.WorkStatus == 2 && v.ApprovalID != "" { approvalID, _ := strconv.ParseUint(v.ApprovalID, 10, 64) workUuidApprovalIDMap[int(approvalID)] = v.WorkUuid @@ -166,8 +172,6 @@ func WorkList(ctx *gin.Context) { _ = RefreshWorkApprovalStatus(ctx, workUuidApprovalIDMap) } } - service.Success(ctx, resp) - return } func WorkDetail(ctx *gin.Context) { @@ -305,6 +309,9 @@ func RefreshWorkApprovalStatus(ctx *gin.Context, approvalIDWorkUuidMap map[int]s return } data, err = castS.ApprovalDetail(approvalIDs) + if err != nil { + return + } // status: 1待审批 2审批通过 3审批不通过 6撤销发其中 7撤销完成 var newData = make(map[int]modelCast.Item, len(approvalIDs)) for _, v := range approvalIDs {