package service import ( "context" "dubbo.apache.org/dubbo-go/v3/common/logger" "dubbo.apache.org/dubbo-go/v3/config" "errors" "fmt" "github.com/fonchain_enterprise/fonchain-main/api/account" "github.com/fonchain_enterprise/fonchain-main/api/artwork" "github.com/fonchain_enterprise/fonchain-main/api/collections" "github.com/fonchain_enterprise/fonchain-main/api/employee" "github.com/fonchain_enterprise/fonchain-main/api/oa" "github.com/fonchain_enterprise/fonchain-main/api/order" backendSeries "github.com/fonchain_enterprise/fonchain-main/api/series" "github.com/fonchain_enterprise/fonchain-main/api/shopbrand" config1 "github.com/fonchain_enterprise/fonchain-main/pkg/config" "github.com/fonchain_enterprise/fonchain-main/pkg/e" "github.com/fonchain_enterprise/fonchain-main/pkg/model" "github.com/fonchain_enterprise/fonchain-main/pkg/model/vo/turnstile" "github.com/fonchain_enterprise/fonchain-main/pkg/utils" "github.com/google/uuid" "github.com/robfig/cron/v3" "os" "path" "strconv" "strings" "sync" "time" ) func Task(c *cron.Cron) { /*if config.GetConsumerService("ArtworkClientImpl") != nil { _, _ = c.AddFunc("@every 5m", CheckCopyright) }*/ //发送周报短信 if config.GetConsumerService("OrderClientImpl") != nil { _, _ = c.AddFunc("0 15 * * 0", SendAReportToBoss) } //重启打卡机设备 if config.GetConsumerService("AccountClientImpl") != nil { _, _ = c.AddFunc("0 0 4 * *", RebootClockDevice) } //更新考勤组绑定 //if config.GetConsumerService("EmployeeClientImpl") != nil { // _, _ = c.AddFunc("1 4 * * *", UpdateAttendanceRegularly) //} //更新在职状态 if config.GetConsumerService("EmployeeClientImpl") != nil { _, _ = c.AddFunc("0 23 * * *", UpdateWorkingStatus) } //创建到期消息提醒 if config.GetConsumerService("EmployeeClientImpl") != nil { _, _ = c.AddFunc("0 1 * * *", CreateAReminderMessage) } //创建假期余额 if config.GetConsumerService("EmployeeClientImpl") != nil { _, _ = c.AddFunc("0 0 1 1 *", CreateLeaveBalance) //_, _ = c.AddFunc("10 10 * * *", CreateLeaveBalance) } //添加补充年假 if config.GetConsumerService("EmployeeClientImpl") != nil { _, _ = c.AddFunc("1 0 * * *", AddSupplementaryAnnualLeave) } /*if config.GetConsumerService("SeriesClientImpl") != nil && config.GetConsumerService("BrandClientImpl") != nil && config.GetConsumerService("CollectionsClientImpl") != nil { _, _ = c.AddFunc("@every 5m", CheckSeries) }*/ if err := DelayDeleteFileTask.AddTimerTask(c); err != nil { panic("添加定时任务失败,错误:" + err.Error()) } if config.GetConsumerService("AccountClientImpl") != nil && config.GetConsumerService("ApprovalClientImpl") != nil { _, _ = c.AddFunc("* 9 * * *", SendPromotionMsg) // 23:50 执行 } //更新打卡机用户状态 if config.GetConsumerService("AccountClientImpl") != nil { _, _ = c.AddFunc("0 12 * * 1", UpdateClockUserStatus) } } func UpdateClockUserStatus() { fmt.Println("更新打卡机用户状态") list, err := AccountProvider.ClockDeviceBatchList(context.Background(), &account.ClockBatchBindRequest{}) if err != nil { fmt.Println("查询打卡机用户失败") return } userList := []*account.ClockUserDeviceBatch{} //整合数据 if len(list.Data) == 0 { return } for _, i := range list.Data { if i.WorkStatus == "notactive" { continue } userList = append(userList, &account.ClockUserDeviceBatch{ UserId: i.UserId, DeviceId: i.DeviceId, JobNum: i.JobNum, DeviceNum: i.DeviceNum, DeviceName: i.DeviceName, WorkStatus: i.WorkStatus, }) } data, clockDeviceBatchUntie := DeviceNumToJobNums(userList) //下发数据 err = DelBatchDeviceAccount(data) if err != nil { fmt.Println("下发数据失败", err) } //删除关联 _, err = AccountProvider.ClockDeviceBatchUntie(context.Background(), clockDeviceBatchUntie) if err != nil { return } return } func DelBatchDeviceAccount(req map[string][]uint64) (err error) { for deviceNum, jobNums := range req { uuidObj := uuid.New() stringSlice := make([]string, len(jobNums)) for i, num := range jobNums { stringSlice[i] = strconv.FormatUint(num, 10) } synReq := turnstile.TurnStile{ Cmd: "to_device", From: "Message1", To: deviceNum, Extra: uuidObj.String(), Data: turnstile.TurnData{ Cmd: e.DelMultiUser, UserIds: stringSlice, UserType: 0, }, } err, _ = utils.IssueTheCardPunchData(synReq, deviceNum, uuidObj) if err != nil { return errors.New("下发数据失败") } } return err } func DeviceNumToJobNums(data []*account.ClockUserDeviceBatch) (deviceNum map[string][]uint64, ClockDeviceBatchUntie *account.ClockBatchBindRequest) { deviceNumToJobNums := make(map[string][]uint64) ClockDeviceBatchUntie = &account.ClockBatchBindRequest{} for _, batch := range data { ClockDeviceBatchUntie.UserId = append(ClockDeviceBatchUntie.UserId, batch.UserId) if _, exists := deviceNumToJobNums[batch.DeviceNum]; exists { deviceNumToJobNums[batch.DeviceNum] = append(deviceNumToJobNums[batch.DeviceNum], batch.UserId) } else { deviceNumToJobNums[batch.DeviceNum] = []uint64{batch.UserId} } } // 提取所有设备号并去重 deviceIdSet := make(map[uint64]bool) for _, batch := range data { // 检查设备 ID 是否已存在,去重 if !deviceIdSet[batch.DeviceId] { ClockDeviceBatchUntie.DeviceId = append(ClockDeviceBatchUntie.DeviceId, batch.DeviceId) deviceIdSet[batch.DeviceId] = true } } return deviceNumToJobNums, ClockDeviceBatchUntie } // AddSupplementaryAnnualLeave 添加补充年假 func AddSupplementaryAnnualLeave() { if time.Now().Month() == time.January && time.Now().Day() == 1 { return } WorkingConditionId, err := GrpcEmployeeProvider.SearchDictionaryList(context.Background(), &employee.SearchDictionaryRequest{ Name: "在职", Tag: "workingCondition", }) if err != nil || WorkingConditionId.WorkingCondition == nil { fmt.Println("查询工作状态失败!") return } currentMonthDay := time.Now().Format("01-02") // 根据在职状态和入职日期模糊查询员工档案 employeeFileList, err := GrpcEmployeeProvider.FindEmployeeFileList(context.Background(), &employee.FindEmployeeFileListRequest{ WorkingConditionId: WorkingConditionId.WorkingCondition[0].Id, BlurDateOfEntry: currentMonthDay, }) if err != nil || len(employeeFileList.EmployeeFileList) == 0 { fmt.Println("无人员需要添加假期余额") return } for _, i := range employeeFileList.EmployeeFileList { replenishment := supplementaryLeave(i.DateOfEntry) if replenishment == 0 { continue } fmt.Printf("用户 %v 的入职日期为 %v,需要补充年假 %v 天\n", i.UserId, i.DateOfEntry, replenishment) _, err = GrpcOAImpl.ModifyTheLeaveBalance(context.Background(), &oa.ModifyTheLeaveBalanceReq{ StaffUid: i.UserId, LeaveType: "annualLeave", Movement: 1, Year: int32(time.Now().Year()), Days: float32(replenishment), }) if err != nil { fmt.Printf("更新用户 %v 的假期余额失败: %v\n", i.UserId, err) } } } // CreateLeaveBalance 创建假期余额 func CreateLeaveBalance() { WorkingConditionId, err := GrpcEmployeeProvider.SearchDictionaryList(context.Background(), &employee.SearchDictionaryRequest{ Name: "在职", Tag: "workingCondition", }) if err != nil || WorkingConditionId.WorkingCondition == nil { fmt.Println("查询工作状态失败!") return } employeeFileList, err := GrpcEmployeeProvider.FindEmployeeFileList(context.Background(), &employee.FindEmployeeFileListRequest{ WorkingConditionId: WorkingConditionId.WorkingCondition[0].Id, }) if err != nil || len(employeeFileList.EmployeeFileList) == 0 { fmt.Println("定时创建假期余额失败!") return } for _, i := range employeeFileList.EmployeeFileList { departmentPosition := []*oa.LeaveBalancePosition{} if i.DepartmentPostList != nil { for _, s := range i.DepartmentPostList { departmentPosition = append(departmentPosition, &oa.LeaveBalancePosition{ DepartmentUID: strconv.FormatUint(s.DepartmentId, 10), DepartmentName: s.DepartmentName, PositionUID: strconv.FormatUint(s.PostId, 10), PositionName: s.PostName, }) } } annualLeave := AnnualLeaveByYearsOfService(i.DateOfEntry) _, err = GrpcOAImpl.SaveLeaveBalance(context.Background(), &oa.LeaveBalance{ StaffUID: i.UserId, StaffNum: i.JobNumber, StaffName: i.Name, Year: int32(time.Now().Year()), Positions: departmentPosition, AnnualLeave: float32(annualLeave), HasParentalLeave: 1, HasNursingLeave: 1, EmployeeFileId: i.Id, }) } return } // 补充年假天数 func supplementaryLeave(DateOfEntry string) int { joinDate, err := time.Parse("2006-01-02", DateOfEntry) if err != nil { fmt.Println("入职日期解析错误:", err) return 0 } currentDate := time.Now() yearsOfService := int(currentDate.Sub(joinDate).Hours() / 24 / 365) //if !isEligibleForSupplementaryLeave(joinDate, currentDate) { // return 0 //} supplementaryLeaveDays := 0 switch yearsOfService { case 1: supplementaryLeaveDays = 5 case 5: supplementaryLeaveDays = 2 case 10: supplementaryLeaveDays = 3 case 20: supplementaryLeaveDays = 5 default: return 0 } // 计算补充年假 endOfYear := time.Date(currentDate.Year(), 12, 31, 0, 0, 0, 0, currentDate.Location()) daysUntilEndOfYear := endOfYear.Sub(currentDate).Hours() / 24 supplementaryLeave := (daysUntilEndOfYear / 365) * float64(supplementaryLeaveDays) return int(supplementaryLeave) } // 工龄年假天数 func AnnualLeaveByYearsOfService(DateOfEntry string) int { joinDate, err := time.Parse("2006-01-02", DateOfEntry) if err != nil { fmt.Println("入职日期解析错误:", err) return 0 } currentDate := time.Now() yearsOfService := int(currentDate.Sub(joinDate).Hours() / 24 / 365) switch { case yearsOfService < 1: return 0 case yearsOfService < 5: return 5 case yearsOfService < 10: return 7 case yearsOfService < 20: return 10 default: return 15 } } // 检查是否符合补充年假的条件 func isEligibleForSupplementaryLeave(joinDate, currentDate time.Time) bool { yearsOfService := int(currentDate.Sub(joinDate).Hours() / 24 / 365) anniversaryDate := joinDate.AddDate(yearsOfService, 0, 0) return currentDate.Equal(anniversaryDate) } func UpdateAttendanceRegularly() { _, err := GrpcEmployeeProvider.UpdateAttendanceRegularly(context.Background(), &employee.EmptyStructure{}) if err != nil { fmt.Println("定时更新考勤组失败!") return } return } func UpdateWorkingStatus() { _, err := GrpcEmployeeProvider.UpdateWorkingStatus(context.Background(), &employee.EmptyStructure{}) if err != nil { fmt.Println("定时更新员工工作状态失败!") return } return } func CreateAReminderMessage() { _, err := GrpcEmployeeProvider.CreateAReminderMessage(context.Background(), &employee.IdUnifiedReturn{}) if err != nil { fmt.Println("创建到期消息提醒失败!") return } fmt.Println("----------------创建到期消息提醒成功-------------------") return } func RebootClockDevice() { var batch account.ClockBatchBindRequest devRes, err := AccountProvider.ClockDeviceBatchList(context.Background(), &batch) //获取设备列表 if err != nil { return } for _, i := range devRes.Data { uuidObj := uuid.New() fmt.Println(uuidObj.String()) synReq := turnstile.TurnStile{ Cmd: "to_device", From: "Message1", To: i.DeviceNum, Extra: uuidObj.String(), Data: turnstile.TurnData{ Cmd: e.Reboot, }, } err, _ := utils.IssueTheCardPunchData(synReq, i.DeviceNum, uuidObj) if err != nil { return } } } func SendAReportToBoss() { now := time.Now() weekday := now.Weekday() lastMonday := now.AddDate(0, 0, -int(weekday)+1-6) lastSunday := now.AddDate(0, 0, -int(weekday)+7-6) host := "" if config1.Env == "prod" { host = "https://sale.fontree.cn" } else { host = "https://sellertest.szjixun.cn" } lastStart := lastMonday.Format("2006-01-02") lastEnd := lastSunday.Format("2006-01-02") telList, err := OrderProvider.GetSmsConfig(context.Background(), &order.SmsConfigRequest{ Position: "boss", }) if err != nil || len(telList.SmsConfig) == 0 { fmt.Println("获取手机号失败!") return } for _, i := range telList.SmsConfig { infoUrl := fmt.Sprintf("%v/#/pages/examine/examine?startDate=%v&endDate=%v&uid=%v&", host, lastStart, lastEnd, i.Id) url := lastStart + "||" + lastEnd + "||" + infoUrl _, err1 := AccountProvider.SendExCustomMsg(context.Background(), &account.SendCustomMsgRequest{ TelNum: i.TelNum, Url: url, MId: 145217, //模板Id SigNo: 159789, //签名id }) if err1 != nil { fmt.Println("短信发送失败!") return } } return } // CheckCopyright 检验版权文件 func CheckCopyright() { logger.Error("MoveCopyrightFile start", time.Now().Format("2006-01-02 15:04:05")) files, err := os.ReadDir(model.CopyrightDir) if err != nil { logger.Error("MoveCopyrightFile err", err) return } //utils.CheckDirPath(model.CopyrightDir+"/old", true) var lock sync.RWMutex lock.Lock() defer lock.Unlock() for _, v := range files { if !v.IsDir() { if path.Ext(v.Name()) == ".psb" { var req artwork.UpdateCrHashByTfnumRequest var temp artwork.UpdateCrHashByTfnumRequest_Info filePath := model.CopyrightDir + "/" + v.Name() temp.Tfnum = strings.TrimSuffix(v.Name(), path.Ext(v.Name())) temp.CopyrightHash, _ = utils.GenerateSHA256Hash(filePath) if temp.Tfnum != "" && temp.CopyrightHash != "" { req.Data = append(req.Data, &temp) } _, err = GrpcArtworkImpl.UpdateCrHashByTfnum(context.Background(), &req) if err != nil { logger.Errorf("GrpcArtworkImpl UpdateCopyrightHash err", err) _ = os.Rename(filePath, filePath+"_err") return } _ = os.Rename(filePath, filePath+"_use") logger.Error("MoveCopyrightFile end", &temp) } } } //if len(req.Data) > 0 { // _, err = GrpcArtworkImpl.UpdateCrHashByTfnum(context.Background(), &req) // if err != nil { // logger.Errorf("GrpcArtworkImpl UpdateCopyrightHash err", err) // return // } //} } // CheckSeries 检测系列 func CheckSeries() { var req backendSeries.CheckSeriesReq resp, err := GrpcBackendSeriesImpl.CheckSeries(context.Background(), &req) if err != nil { fmt.Println(err.Error()) return } if len(resp.Data) > 0 { // 请求brand var brandReq shopbrand.BrandListreq for _, v := range resp.Data { brandReq.BrandUid = append(brandReq.BrandUid, v.BrandId) } brandList, err := GrpcShopBrandImpl.BrandList(context.Background(), &brandReq) logger.Info("brandList CheckSeries", brandList, "ntfReq", brandList.Data) if err != nil { logger.Error("brandList err", err) return } var brandDataMap map[string]shopbrand.BrandListres_Info = map[string]shopbrand.BrandListres_Info{} if len(brandList.Data) > 0 { for _, v := range brandList.Data { brandDataMap[v.BrandUid] = shopbrand.BrandListres_Info{ BrandUid: v.BrandUid, Address: v.Address, } } } //得到hash 请求藏品服,上链 var ntfReq collections.StoreNFTList for _, v := range resp.Data { var ntfInfo collections.StoreNFTInfo ntfInfo.SeriesUID = v.SeriesUuid ntfInfo.BrandHash = brandDataMap[v.BrandId].Address ntfReq.NFT = append(ntfReq.NFT, &ntfInfo) } ntfResp, err := GrpcCollectionImpl.StoreNFT(context.Background(), &ntfReq) logger.Info("ntfResp CheckSeries", ntfResp, "ntfReq", ntfReq.NFT) if err != nil { logger.Errorf("HandShelf StoreNFT err", err) err = errors.New(e.GetMsg(e.ErrorStoreNTF)) return } if len(ntfResp.SeriesUID) == len(ntfReq.NFT) { return } failSeriesUuid := make(map[string]struct{}, len(ntfResp.SeriesUID)) if len(ntfResp.SeriesUID) > 0 { for _, seriesUuid := range ntfResp.SeriesUID { failSeriesUuid[seriesUuid] = struct{}{} } } for _, v := range ntfReq.NFT { _, ok := failSeriesUuid[v.SeriesUID] if !ok { var seriesReq backendSeries.UpdateSeriesChainReq seriesReq.SeriesUuid = v.SeriesUID seriesReq.ChainStatus = 1 _, _ = GrpcBackendSeriesImpl.UpdateSeriesChain(context.Background(), &seriesReq) } } } return }