Browse Source

Add 添加定时任务的文件日志功能

YueYunyun 2 năm trước cách đây
mục cha
commit
da687ebd80

+ 1 - 1
SERVER/IotAdmin/app/iot/models/meter_calc.go

@@ -5,7 +5,7 @@ type IotMeterCalc struct {
 	Time int    `gorm:"type:int;not null;comment:更新时间"`
 	Data string `json:"data" gorm:"type:varchar(500);not null;comment:计算数据"`
 	//DataJson interface{} `json:"data" gorm:"type:varchar(500);not null;comment:计算数据"`
-	Device *IotDevice `json:"-" gorm:"foreignKey:Id;references:id"`
+	Device *IotDevice `json:"-" gorm:"foreignKey:Id;references:id;joinForeignKey:Sn;references:sn"`
 }
 
 func (*IotMeterCalc) TableName() string {

+ 5 - 5
SERVER/IotAdmin/app/iot/service/dto/device.go

@@ -32,11 +32,11 @@ type IotDeviceOrder struct {
 	Sn             string `form:"snOrder"  search:"type:order;column:sn;table:iot_device"`
 	Name           string `form:"nameOrder"  search:"type:order;column:name;table:iot_device"`
 	Protocol       string `form:"protocolOrder"  search:"type:order;column:protocol;table:iot_device"`
-	Type           int    `form:"typeOrder"  search:"type:order;column:type;table:iot_device"`
-	Mode           int    `form:"modeOrder"  search:"type:order;column:mode;table:iot_device"`
-	Address        int    `form:"addressOrder"  search:"type:order;column:address;table:iot_device"`
-	Status         int    `form:"statusOrder"  search:"type:order;column:status;table:iot_device"`
-	OnlineStatus   int    `form:"onlineStatusOrder"  search:"type:order;column:online_status;table:iot_device"`
+	Type           string `form:"typeOrder"  search:"type:order;column:type;table:iot_device"`
+	Mode           string `form:"modeOrder"  search:"type:order;column:mode;table:iot_device"`
+	Address        string `form:"addressOrder"  search:"type:order;column:address;table:iot_device"`
+	Status         string `form:"statusOrder"  search:"type:order;column:status;table:iot_device"`
+	OnlineStatus   string `form:"onlineStatusOrder"  search:"type:order;column:online_status;table:iot_device"`
 	TimeOnline     string `form:"timeOnlineOrder" search:"type:order;column:time_online;table:iot_device"`
 	TimeOffline    string `form:"timeOfflineOrder" search:"type:order;column:time_offline;table:iot_device"`
 	CreatedAtOrder string `form:"createdAtOrder" search:"type:order;column:created_at;table:iot_device"`

+ 22 - 6
SERVER/IotAdmin/app/schedule/jobs/clean-log.go

@@ -1,6 +1,7 @@
 package jobs
 
 import (
+	"IotAdmin/common"
 	"IotAdmin/core/logger"
 	iotLog "IotAdmin/iot/log"
 	"strconv"
@@ -14,7 +15,17 @@ type CleanLog struct {
 }
 
 func (t *CleanLog) Exec(arg interface{}) error {
-	logger.Info(time.Now().Format(timeFormat) + " [INFO] JobCore CleanLog exec START")
+	jobLogger.Infof("【CleanLog】 EXEC START")
+	err := common.CleanSysLog()
+	if err != nil {
+		jobLogger.Errorf("CleanSysLog EXEC ERROR:%s", err.Error())
+		return err
+	}
+	err = CleanJobLog(7)
+	if err != nil {
+		jobLogger.Errorf("CleanJobLog EXEC ERROR:%s", err.Error())
+		return err
+	}
 	switch arg.(type) {
 	case string:
 		if arg.(string) != "" {
@@ -22,29 +33,29 @@ func (t *CleanLog) Exec(arg interface{}) error {
 			arr := strings.Split(str, ",")
 			p1, err := strconv.Atoi(arr[0])
 			if err != nil {
-				logger.Error(time.Now().Format(timeFormat) + " [ERROR] JobCore CleanLog exec error:" + err.Error())
+				jobLogger.Errorf("CleanLog EXEC ERROR:%s", err.Error())
 				return err
 			}
 			if len(arr) > 1 {
 				p2, err := strconv.Atoi(arr[1])
 				if err != nil {
-					logger.Error(time.Now().Format(timeFormat) + " [ERROR] JobCore CleanLog exec error:" + err.Error())
+					jobLogger.Errorf("CleanLog EXEC ERROR:%s", err.Error())
 					return err
 				}
 				err = iotLog.Clean(p1, p2)
 				if err != nil {
-					logger.Error(time.Now().Format(timeFormat) + " [ERROR] JobCore CleanLog exec error:" + err.Error())
+					jobLogger.Errorf("CleanLog EXEC ERROR:%s", err.Error())
 					return err
 				}
 			} else {
 				err = iotLog.Clean(p1, p1)
 				if err != nil {
-					logger.Error(time.Now().Format(timeFormat) + " [ERROR] JobCore CleanLog exec error:" + err.Error())
+					jobLogger.Errorf("CleanLog EXEC ERROR:%s", err.Error())
 					return err
 				}
 			}
 		} else {
-			logger.Errorf(time.Now().Format(timeFormat) + " [ERROR] JobCore CleanLog exec error: arg is empty")
+			jobLogger.Errorf("CleanLog EXEC ERROR: arg is empty")
 		}
 		break
 	case int:
@@ -59,6 +70,11 @@ func (t *CleanLog) Exec(arg interface{}) error {
 		break
 	default:
 	}
+	jobLogger.Infof("【CleanLog】 EXEC END\r\n")
 
 	return nil
 }
+
+func (t *CleanLog) GetName() string {
+	return "清理日志"
+}

+ 4 - 0
SERVER/IotAdmin/app/schedule/jobs/examples.go

@@ -27,3 +27,7 @@ func (t *ExamplesOne) Exec(arg interface{}) error {
 
 	return nil
 }
+
+func (t *ExamplesOne) GetName() string {
+	return "函数测试"
+}

+ 11 - 14
SERVER/IotAdmin/app/schedule/jobs/init.go

@@ -4,8 +4,6 @@ import (
 	"IotAdmin/app/schedule/models"
 	"IotAdmin/core/sdk"
 	"IotAdmin/core/sdk/pkg/cronjob"
-	"fmt"
-	"time"
 
 	"gorm.io/gorm"
 )
@@ -27,15 +25,14 @@ func initJobList() {
 	jobList = map[string]JobExec{
 		"CleanLog":    &CleanLog{},
 		"ExamplesOne": &ExamplesOne{},
-		// ...
 	}
 }
 
 // Setup 初始化
 func Setup(dbs map[string]*gorm.DB) {
-	fmt.Println(time.Now().Format(timeFormat), " [INFO] JobCore Starting...")
+	jobLogger.Infof("STARTING...")
 	for k, db := range dbs {
-		sdk.Runtime.SetCrontab(k, cronjob.NewWithSeconds())
+		sdk.Runtime.SetCrontab(k, cronjob.NewWithSecondsLogger(jobLogger))
 		setup(k, db)
 	}
 }
@@ -46,15 +43,15 @@ func setup(key string, db *gorm.DB) {
 	jobList := make([]models.SysJob, 0)
 	err := sysJob.GetList(db, &jobList)
 	if err != nil {
-		fmt.Println(time.Now().Format(timeFormat), " [ERROR] JobCore init error", err)
+		jobLogger.Errorf("INIT ERROR:%s", err.Error())
 	}
 	if len(jobList) == 0 {
-		fmt.Println(time.Now().Format(timeFormat), " [INFO] JobCore total:0")
+		jobLogger.Infof("TOTAL:0")
 	}
 
 	_, err = sysJob.RemoveAllEntryID(db)
 	if err != nil {
-		fmt.Println(time.Now().Format(timeFormat), " [ERROR] JobCore remove entry_id error", err)
+		jobLogger.Errorf("REMOVE ALL ENTRY ERROR ERROR: %s", err.Error())
 	}
 
 	for i := 0; i < len(jobList); i++ {
@@ -80,17 +77,17 @@ func setup(key string, db *gorm.DB) {
 
 	// 其中任务
 	crontab.Start()
-	fmt.Println(time.Now().Format(timeFormat), " [INFO] JobCore start success.")
+	jobLogger.Infof("START SUCCESS")
 	// 关闭任务
 	defer crontab.Stop()
 	select {}
 }
 
 // GetJobKeys 获取job key列表
-func GetJobKeys() []string {
-	var list []string
-	for k := range jobList {
-		list = append(list, k)
+func GetJobKeys() map[string]string {
+	var mp = make(map[string]string)
+	for k, v := range jobList {
+		mp[k] = v.GetName()
 	}
-	return list
+	return mp
 }

+ 3 - 4
SERVER/IotAdmin/app/schedule/jobs/job_http.go

@@ -1,7 +1,6 @@
 package jobs
 
 import (
-	log "IotAdmin/core/logger"
 	"IotAdmin/core/sdk/pkg"
 	"fmt"
 	"time"
@@ -28,8 +27,8 @@ LOOP:
 		str, err = pkg.Get(h.InvokeTarget)
 		if err != nil {
 			// 如果失败暂停一段时间重试
-			fmt.Println(time.Now().Format(timeFormat), " [ERROR] mission failed! ", err)
-			fmt.Printf(time.Now().Format(timeFormat)+" [INFO] Retry after the task fails %d seconds! %s \n", (count+1)*5, str)
+			jobLogger.Errorf("[%s] EXEC FAILED! ERROR: %s", h.Name, err.Error())
+			jobLogger.Infof("[%s]  Retry after the task fails %d seconds! %s ", h.Name, (count+1)*5, str)
 			time.Sleep(time.Duration(count+1) * 5 * time.Second)
 			count = count + 1
 			goto LOOP
@@ -42,7 +41,7 @@ LOOP:
 	latencyTime := endTime.Sub(startTime)
 	//TODO: 待完善部分
 
-	log.Infof("[Job] JobCore %s exec success , spend :%v", h.Name, latencyTime)
+	jobLogger.Infof("%s EXEC SUCCESS , SPEND :%v", h.Name, latencyTime)
 	return
 }
 

+ 3 - 4
SERVER/IotAdmin/app/schedule/jobs/job_sys.go

@@ -1,7 +1,6 @@
 package jobs
 
 import (
-	log "IotAdmin/core/logger"
 	"fmt"
 	"time"
 
@@ -16,7 +15,7 @@ func (e *ExecJob) Run() {
 	startTime := time.Now()
 	var obj = jobList[e.InvokeTarget]
 	if obj == nil {
-		log.Warn("[Job] ExecJob Run jobs nil")
+		jobLogger.Warnf("[Job] ExecJob Run jobs nil [%s]", e.Name)
 		return
 	}
 	err := CallExec(obj.(JobExec), e.Args)
@@ -32,14 +31,14 @@ func (e *ExecJob) Run() {
 	//TODO: 待完善部分
 	//str := time.Now().Format(timeFormat) + " [INFO] JobCore " + string(e.EntryId) + "exec success , spend :" + latencyTime.String()
 	//ws.SendAll(str)
-	log.Infof("[Job] JobCore %s exec success , spend :%v", e.Name, latencyTime)
+	jobLogger.Infof("[%s] EXEC SUCCESS , SPEND :%v", e.Name, latencyTime)
 	return
 }
 
 func (e *ExecJob) addJob(c *cron.Cron) (int, error) {
 	id, err := c.AddJob(e.CronExpression, e)
 	if err != nil {
-		fmt.Println(time.Now().Format(timeFormat), " [ERROR] JobCore AddJob error", err)
+		jobLogger.Errorf("AddJob ERROR: %s", err.Error())
 		return 0, err
 	}
 	EntryId := int(id)

+ 2 - 5
SERVER/IotAdmin/app/schedule/jobs/jobbase.go

@@ -1,9 +1,6 @@
 package jobs
 
 import (
-	"fmt"
-	"time"
-
 	"github.com/robfig/cron/v3"
 )
 
@@ -13,7 +10,7 @@ var retryCount = 3
 // AddJob 添加任务 AddJob(invokeTarget string, jobId int, jobName string, cronExpression string)
 func AddJob(c *cron.Cron, job Job) (int, error) {
 	if job == nil {
-		fmt.Println("unknown")
+		jobLogger.Errorf("Job Is Nil")
 		return 0, nil
 	}
 	return job.addJob(c)
@@ -24,7 +21,7 @@ func Remove(c *cron.Cron, entryID int) chan bool {
 	ch := make(chan bool)
 	go func() {
 		c.Remove(cron.EntryID(entryID))
-		fmt.Println(time.Now().Format(timeFormat), " [INFO] JobCore Remove success ,info entryID :", entryID)
+		jobLogger.Infof("Remove SUCCESS ,INFO entryID :%d", entryID)
 		ch <- true
 	}()
 	return ch

+ 98 - 0
SERVER/IotAdmin/app/schedule/jobs/logger.go

@@ -0,0 +1,98 @@
+package jobs
+
+import (
+	"IotAdmin/core/logger"
+	"IotAdmin/core/sdk/config"
+	cLog "IotAdmin/core/sdk/pkg/logger"
+	"IotAdmin/core/tools/writer"
+	"fmt"
+	"log"
+	"sync"
+)
+
+var jobLogger *JobLogger
+var once sync.Once
+
+type JobLogger struct {
+	*logger.Helper
+}
+
+func init() {
+	GetJobLogger()
+}
+
+func GetJobLogger() *JobLogger {
+	once.Do(func() {
+		loggerHelper := setupJobLogger()
+		jobLogger = &JobLogger{
+			loggerHelper,
+		}
+	})
+	return jobLogger
+}
+
+// setupJobLogger 设置设备日志组件
+func setupJobLogger() *logger.Helper {
+	path := getJobLogPath()
+	logCap := config.LoggerConfig.Cap
+	if logCap == 0 {
+		logCap = 1024
+	}
+	output, err := writer.NewFileWriter(
+		writer.WithPath(path),
+		writer.WithCap(logCap<<10),
+		writer.WithSuffix("log"),
+	)
+	if err != nil {
+		log.Printf("job logger setup error: %s \r\n", err.Error())
+	}
+	level := logger.DebugLevel
+	if config.ApplicationConfig.Mode == "prod" {
+		level = logger.InfoLevel
+	}
+	return logger.NewHelper(logger.NewLogger(logger.WithLevel(level), logger.WithOutput(output), logger.WithName("JOB")))
+}
+
+func getJobLogPath() string {
+	path := config.LoggerConfig.Path
+	if path == "" {
+		path = "_logs/"
+	} else if path[len(path)-1] != '/' {
+		path += "/"
+	}
+	path += "jobs"
+	return path
+}
+
+func CleanJobLog(days int) error {
+	path := getJobLogPath()
+	return cLog.DeleteLogsOlderThan(path, "log", days)
+}
+func (j *JobLogger) Info(msg string, args ...interface{}) {
+	msg = "[CRON]" + msg
+	if len(args) > 0 {
+		for _, v := range args {
+			msg += fmt.Sprintf(" %v", v)
+		}
+	}
+	j.Helper.Info(msg)
+}
+func (j *JobLogger) Infof(msg string, args ...interface{}) {
+	msg = "[JobCore]" + msg
+	j.Helper.Infof(msg, args...)
+}
+
+func (j *JobLogger) Error(err error, msg string, args ...interface{}) {
+	msg = "[CRON]" + msg
+	if len(args) > 0 {
+		for _, v := range args {
+			msg += fmt.Sprintf("%v ", v)
+		}
+	}
+	j.Helper.Errorf("%s; ERROR: %s", msg, err.Error())
+}
+
+func (j *JobLogger) Errorf(msg string, args ...interface{}) {
+	msg = "[JobCore]" + msg
+	j.Helper.Errorf(msg, args...)
+}

+ 1 - 0
SERVER/IotAdmin/app/schedule/jobs/type.go

@@ -18,6 +18,7 @@ type Job interface {
 
 type JobExec interface {
 	Exec(arg interface{}) error
+	GetName() string
 }
 
 func CallExec(e JobExec, arg interface{}) error {

+ 16 - 0
SERVER/IotAdmin/common/clean.go

@@ -0,0 +1,16 @@
+package common
+
+import (
+	"IotAdmin/core/sdk/config"
+	"IotAdmin/core/sdk/pkg/logger"
+)
+
+// CleanSysLog 清理系统日志文件
+func CleanSysLog() error {
+	days := config.LoggerConfig.SaveDays
+	if days <= 0 {
+		return nil
+	}
+	path := config.LoggerConfig.Path
+	return logger.DeleteLogsOlderThan(path, "log", days)
+}

+ 1 - 0
SERVER/IotAdmin/config/settings.yml

@@ -54,6 +54,7 @@ settings:
     level: trace
     # 数据库日志开关 (登录日志,操作日志)
     enabledDb: true
+    saveDays: 10
   extend:
     aMap:
       key: 2a53817d8ccbbfe0e653a462ffc64548

+ 9 - 16
SERVER/IotAdmin/core/logger/default.go

@@ -88,31 +88,31 @@ func (l *defaultLogger) logf(level Level, format string, v ...interface{}) {
 	fields := copyFields(l.opts.Fields)
 	l.RUnlock()
 
-	//fields["level"] = "[" + level.String() + "]"
-
-	if _, file, line, ok := runtime.Caller(l.opts.CallerSkipCount); ok && level.String() == "error" {
-		fields["file"] = fmt.Sprintf("%s:%d", logCallerFilePath(file), line)
-	}
-
 	rec := dlog.Record{
 		Timestamp: time.Now(),
 		Metadata:  make(map[string]string, len(fields)),
 	}
+	//s := "[" + rec.Timestamp.Format("2006-01-02 15:04:05.000Z0700")
+	str := "[" + rec.Timestamp.Format("2006-01-02 15:04:05.000")
+	if l.opts.Name != "" {
+		str += " " + l.opts.Name
+	}
+	str += "][" + strings.ToUpper(level.String()) + "]"
+	if _, file, line, ok := runtime.Caller(l.opts.CallerSkipCount); ok && level.String() == "error" {
+		str += "[ERR:" + fmt.Sprintf("%s:%d", logCallerFilePath(file), line) + "]"
+	}
 	if format == "" {
 		rec.Message = fmt.Sprint(v...)
 	} else {
 		rec.Message = fmt.Sprintf(format, v...)
 	}
-
 	keys := make([]string, 0, len(fields))
 	for k, v := range fields {
 		keys = append(keys, k)
 		rec.Metadata[k] = fmt.Sprintf("%v", v)
 	}
-
 	sort.Strings(keys)
 	metadata := ""
-
 	for i, k := range keys {
 		if i == 0 {
 			metadata += fmt.Sprintf("%v", fields[k])
@@ -121,14 +121,7 @@ func (l *defaultLogger) logf(level Level, format string, v ...interface{}) {
 		}
 	}
 
-	//s := "[" + rec.Timestamp.Format("2006-01-02 15:04:05.000Z0700")
-	str := "[" + rec.Timestamp.Format("2006-01-02 15:04:05.000")
-	if l.opts.Name != "" {
-		str += " - " + l.opts.Name
-	}
-	str += " - " + level.String() + "]"
 	logStr := fmt.Sprintf("%s %s %v\n", str, metadata, rec.Message)
-
 	_, err := l.opts.Out.Write([]byte(logStr))
 	if err != nil {
 		log.Printf("log [Logf] write error: %s \n", err.Error())

+ 1 - 0
SERVER/IotAdmin/core/sdk/config/logger.go

@@ -13,6 +13,7 @@ type Logger struct {
 	Stdout    string
 	EnabledDB bool
 	Cap       uint
+	SaveDays  int
 }
 
 // Setup 设置logger

+ 6 - 0
SERVER/IotAdmin/core/sdk/pkg/cronjob/gadmjob.go

@@ -10,3 +10,9 @@ func NewWithSeconds() *cron.Cron {
 		cron.Hour | cron.Dom | cron.Month | cron.DowOptional | cron.Descriptor)
 	return cron.New(cron.WithParser(secondParser), cron.WithChain())
 }
+
+func NewWithSecondsLogger(logger cron.Logger) *cron.Cron {
+	secondParser := cron.NewParser(cron.Second | cron.Minute |
+		cron.Hour | cron.Dom | cron.Month | cron.DowOptional | cron.Descriptor)
+	return cron.New(cron.WithParser(secondParser), cron.WithChain(), cron.WithLogger(logger))
+}

+ 92 - 0
SERVER/IotAdmin/core/sdk/pkg/logger/clean.go

@@ -0,0 +1,92 @@
+package logger
+
+import (
+	"IotAdmin/core/logger"
+	"fmt"
+	"os"
+	"path/filepath"
+	"strings"
+	"time"
+)
+
+// DeleteLogsOlderThan 删除比指定日期早的日志文件。
+// days 参数表示需要删除的日志文件是几天前的。
+func DeleteLogsOlderThan(path, suffix string, days int) error {
+	threshold := time.Now().AddDate(0, 0, -days)
+
+	files, err := filepath.Glob(filepath.Join(path, "*."+suffix)) // 假设日志文件以.log结尾
+	if err != nil {
+		return fmt.Errorf("failed to list files in %s: %w", path, err)
+	}
+
+	for _, file := range files {
+		err2 := deleteFile(file, threshold)
+		if err2 != nil {
+			return err2
+		}
+	}
+
+	return nil
+}
+
+// DeleteAllLogsOlderThan 删除比指定日期早的日志文件(包括子目录下)。
+// days 参数表示需要删除的日志文件是几天前的。
+func DeleteAllLogsOlderThan(path, suffix string, days int) error {
+	threshold := time.Now().AddDate(0, 0, 0)
+
+	files, err := recursivelyFindFiles(path, suffix)
+	if err != nil {
+		return fmt.Errorf("failed to list files in %s: %w", path, err)
+	}
+
+	for _, file := range files {
+		err2 := deleteFile(file, threshold)
+		if err2 != nil {
+			return err2
+		}
+	}
+
+	return nil
+}
+
+func deleteFile(file string, threshold time.Time) error {
+	fileInfo, err := os.Stat(file)
+	if err != nil {
+		if os.IsNotExist(err) {
+			logger.Errorf("File %s does not exist\n", file)
+		} else {
+			return fmt.Errorf("failed to get info for %s: %w", file, err)
+		}
+	}
+
+	// 检查文件修改时间是否早于阈值
+	if fileInfo.ModTime().Before(threshold) {
+		err = os.Remove(file)
+		if err != nil {
+			return fmt.Errorf("failed to delete %s: %w", file, err)
+		}
+		logger.Infof("删除日志文件: %s\n", file)
+	}
+	return nil
+}
+
+// recursivelyFindFiles walks the given directory tree and returns a slice of paths for files with the specified suffix.
+func recursivelyFindFiles(dirPath string, suffix string) ([]string, error) {
+	var files []string
+
+	err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
+		if err != nil {
+			return err
+		}
+		if !info.IsDir() && strings.HasSuffix(info.Name(), suffix) {
+			files = append(files, path)
+		}
+		return nil
+	})
+
+	if err != nil {
+		return nil, err
+	}
+
+	return files, nil
+}

+ 1 - 1
SERVER/IotAdmin/iot/db/meter_calc.go

@@ -14,6 +14,7 @@ import (
 
 // LoadMeterCalcMap 加载表计计算配置
 func LoadMeterCalcMap() error {
+	iotMap.MapMeterCalc.Clean()
 	calcArr := make([]models.IotMeterCalc, 0)
 	if len(dbMap) == 0 {
 		return errors.New("dbMap is empty")
@@ -31,7 +32,6 @@ func LoadMeterCalcMap() error {
 }
 
 func loadMeterCalcMap(arr *[]models.IotMeterCalc) error {
-	iotMap.MapMeterCalc.Clean()
 	for _, v := range *arr {
 		if v.Device == nil || v.Device.Protocol == "" {
 			continue

+ 6 - 45
SERVER/IotAdmin/iot/log/clean.go

@@ -1,20 +1,16 @@
 package iotLog
 
 import (
-	"fmt"
-	"os"
-	"path/filepath"
-	"time"
+	"IotAdmin/core/sdk/pkg/logger"
 )
 
 // Clean 清理日志文件
 func Clean(dataDays, deviceDays int) (err error) {
-	err = cleanDataLog(dataDays)
-	if err != nil {
+
+	if err = cleanDataLog(dataDays); err != nil {
 		return err
 	}
-	err = cleanDeviceLog(deviceDays)
-	if err != nil {
+	if err = cleanDeviceLog(deviceDays); err != nil {
 		return err
 	}
 	return
@@ -22,44 +18,9 @@ func Clean(dataDays, deviceDays int) (err error) {
 
 func cleanDataLog(days int) error {
 	path := getDataLogPath()
-	//删除30天前的日志文件
-	return deleteLogsOlderThan(path, "data", days)
+	return logger.DeleteAllLogsOlderThan(path, "data", days)
 }
 func cleanDeviceLog(days int) error {
 	path := getDeviceLogPath()
-	//删除30天前的日志文件
-	return deleteLogsOlderThan(path, "log", days)
-}
-
-// deleteLogsOlderThan 删除比指定日期早的日志文件。
-// days 参数表示需要删除的日志文件是几天前的。
-func deleteLogsOlderThan(path, suffix string, days int) error {
-	threshold := time.Now().AddDate(0, 0, -days)
-
-	files, err := filepath.Glob(filepath.Join(path, "*."+suffix)) // 假设日志文件以.log结尾
-	if err != nil {
-		return fmt.Errorf("failed to list files in %s: %w", path, err)
-	}
-
-	for _, file := range files {
-		fileInfo, err := os.Stat(file)
-		if err != nil {
-			if os.IsNotExist(err) {
-				fmt.Printf("File %s does not exist\n", file)
-			} else {
-				return fmt.Errorf("failed to get info for %s: %w", file, err)
-			}
-		}
-
-		// 检查文件修改时间是否早于阈值
-		if fileInfo.ModTime().Before(threshold) {
-			err = os.Remove(file)
-			if err != nil {
-				return fmt.Errorf("failed to delete %s: %w", file, err)
-			}
-			fmt.Printf("Deleted log file: %s\n", file)
-		}
-	}
-
-	return nil
+	return logger.DeleteAllLogsOlderThan(path, "log", days)
 }

+ 1 - 1
SERVER/IotAdmin/iot/protocol/report/el-hj212.go

@@ -110,7 +110,7 @@ func packHj212(d *iotStruct.CollectData, cfg *iotStruct.ReportConfig) (string, b
 		fmt.Sprintf("&%s=%s", cfg.GetBmYzKey("hib"), packYcHj212Hx(d.Hib, d.HarIb, d.BaseIb, "basei")) +
 		fmt.Sprintf("&%s=%s", cfg.GetBmYzKey("hic"), packYcHj212Hx(d.Hic, d.HarIc, d.BaseIc, "basei"))
 
-	str := fmt.Sprintf("st=%s;cn=4;datatime=%s;cphh=&&tid=%s&%s&", cfg.ST, nt, cfg.MN, body)
+	str := fmt.Sprintf("st=%s;cn=1;datatime=%s;cphh=&&tid=%s&%s&", cfg.ST, nt, cfg.MN, body)
 	crc16 := utils.CalCRC16HJ212([]byte(str))
 	str1 := fmt.Sprintf("##00%04d", len(str)) + str + fmt.Sprintf("%04X", crc16) + "\r\n"
 

+ 1 - 1
SERVER/IotAdmin/iot/struct/electric/adw300.go

@@ -61,11 +61,11 @@ func NewMeterADW300(id string, time int, calc, cfg string) (iotInterface.MeterCa
 			Tq: 0,
 			Fp: 0,
 		}
+		meter.ClearDayEnergy()
 	} else if err := json.Unmarshal([]byte(calc), meter); err != nil {
 		err = fmt.Errorf("ADW300计算参数解析失败: %s", err)
 		return nil, err
 	}
-	meter.ClearDayEnergy()
 	return meter, nil
 }
 

+ 1 - 1
SERVER/IotAdmin/iot/struct/electric/pmc350B.go

@@ -69,11 +69,11 @@ func NewMeterPMC350B(id string, time int, calc, cfg string) (iotInterface.MeterC
 			Tq: 0,
 			Fp: 0,
 		}
+		meter.ClearDayEnergy()
 	} else if err := json.Unmarshal([]byte(calc), meter); err != nil {
 		err = fmt.Errorf("PMC350B计算参数解析失败: %s", err)
 		return nil, err
 	}
-	meter.ClearDayEnergy()
 	return meter, nil
 }
 

+ 2 - 0
SERVER/IotAdmin/server/api.go

@@ -17,6 +17,7 @@ import (
 	"IotAdmin/core/sdk/pkg"
 	"IotAdmin/iot"
 	iotDb "IotAdmin/iot/db"
+	iotLog "IotAdmin/iot/log"
 	"context"
 	"errors"
 	"fmt"
@@ -54,6 +55,7 @@ func init() {
 	queue.Register(global.UpdateMeterCalc, iotDb.UpdateMeterCalc)
 	go queue.Run()
 
+	iotLog.Clean(1, 1)
 	//3. 注册路由
 	// 在app/router目录下新建文件 放在init方法 参考system
 

+ 4 - 0
UI/IOTADMIN.VUE/src/assets/sass/_common.scss

@@ -59,3 +59,7 @@ dl {
 		}
 	}
 }
+
+.el-button.btn {
+	display: inline-flex !important;
+}

+ 4 - 1
UI/IOTADMIN.VUE/src/components/modal/VbModal.vue

@@ -232,7 +232,10 @@ defineExpose({ show, resetForm, validateForm, changePrefixTitle, modalFormRef })
 			:id="id">
 			<div class="modal-dialog" :class="modalDialogClass" :style="modalDialogStyle">
 				<div class="modal-content" :class="modalContentClass" :style="modalContentStyle">
-					<div class="modal-header py-3" :class="modalHeaderClass" :style="modalHeaderStyle">
+					<div
+						class="modal-header justify-content-between py-3"
+						:class="modalHeaderClass"
+						:style="modalHeaderStyle">
 						<template v-if="$slots.title">
 							<slot name="title" />
 						</template>

+ 6 - 3
UI/IOTADMIN.VUE/src/views/schedule/job/index.vue

@@ -307,9 +307,12 @@ function handleStop(row: any) {
 
 function init() {
 	apis.schedule.jobApi.getJobKeys().then((res: any) => {
-		if (res.data && res.data.length > 0) {
-			jobKeysOptions.value = res.data.map((v) => {
-				return { label: v, value: v }
+		if (res.data) {
+			jobKeysOptions.value = Object.keys(res.data).map((key: any) => {
+				return {
+					value: key,
+					label: res.data[key]
+				}
 			})
 		}
 	})