package upload import ( "context" "encoding/json" "fmt" "io" "log/slog" "net/http" "os" "path/filepath" "time" "bj_power_mes/constants" "bj_power_mes/ent/equipmentslot" "bj_power_mes/ent/inspectionimage" "bj_power_mes/ent/job" "bj_power_mes/internal/svc" "github.com/dromara/carbon/v2" "github.com/google/uuid" ) // HandleInspectionUpload 内窥镜检测图片上传,自动绑定当前检测工件 func HandleInspectionUpload(svcCtx *svc.ServiceContext, w http.ResponseWriter, r *http.Request) { if r.ContentLength == 0 { slog.Info("内窥镜URL测试") w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]any{ "code": 200, "msg": "success", }) return } deviceId := r.FormValue("deviceId") file, handler, err := r.FormFile("file") if err != nil { slog.Error("读取文件失败", "error", err) http.Error(w, fmt.Sprintf("读取文件失败:%s", err.Error()), http.StatusBadRequest) return } defer file.Close() // 先查当前检测工件,避免无工件时产生孤儿文件 var jobId int var workpieceNo string var workOrderId int var workOrderNo string var palletCode string slot, err := svcCtx.EntClient.EquipmentSlot.Query(). Where( equipmentslot.EquipmentIdEQ(6), equipmentslot.StatusEQ(constants.SlotStatus_Occupied), ). Only(r.Context()) if err == nil && slot.CurrentJobId != nil && *slot.CurrentJobId > 0 { j, err := svcCtx.EntClient.Job.Query(). Where(job.IDEQ(*slot.CurrentJobId)). WithWorkOrder(). WithPallet(). Only(r.Context()) if err == nil { jobId = j.ID workpieceNo = j.WorkpieceNo if j.Edges.WorkOrder != nil { workOrderId = j.Edges.WorkOrder.ID workOrderNo = j.Edges.WorkOrder.WorkOrderNo } if j.Edges.Pallet != nil { palletCode = j.Edges.Pallet.PalletCode } } } if jobId <= 0 { slog.Error("当前没有检测工件,无法绑定检测图片") http.Error(w, "当前没有检测工件,无法绑定检测图片", http.StatusBadRequest) return } now := carbon.Now() dir := filepath.Join(svcCtx.Config.Upload.Dir, "inspection", fmt.Sprintf("%04d", now.Year()), fmt.Sprintf("%02d", now.Month()), fmt.Sprintf("%02d", now.Day())) if err := os.MkdirAll(dir, 0755); err != nil { slog.Error("创建上传目录失败", "dir", dir, "error", err) http.Error(w, "创建目录失败", http.StatusInternalServerError) return } ext := filepath.Ext(handler.Filename) if ext == "" { ext = ".jpg" } fileName := uuid.New().String() + ext filePath := filepath.Join(dir, fileName) relPath := filepath.Join("inspection", fmt.Sprintf("%04d", now.Year()), fmt.Sprintf("%02d", now.Month()), fmt.Sprintf("%02d", now.Day()), fileName) dst, err := os.Create(filePath) if err != nil { slog.Error("创建文件失败", "path", filePath, "error", err) http.Error(w, "保存文件失败", http.StatusInternalServerError) return } defer dst.Close() written, err := io.Copy(dst, file) if err != nil { slog.Error("写入文件失败", "path", filePath, "error", err) http.Error(w, "保存文件失败", http.StatusInternalServerError) return } _, err = svcCtx.EntClient.InspectionImage.Create(). SetJobId(jobId). SetWorkpieceNo(workpieceNo). SetWorkOrderId(workOrderId). SetWorkOrderNo(workOrderNo). SetPalletCode(palletCode). SetDeviceId(deviceId). SetFileName(handler.Filename). SetFilePath(filepath.ToSlash(relPath)). SetFileSize(written). Save(r.Context()) if err != nil { slog.Error("创建检测图片记录失败", "jobId", jobId, "error", err) w.Header().Set("Content-Type", "application/json") http.Error(w, "创建检测图片记录失败", http.StatusBadRequest) return } slog.Info("检测图片上传", "file", handler.Filename, "size", written, "jobId", jobId, "deviceId", deviceId) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]any{ "code": 200, "data": map[string]any{ // 必须返回data字段(内容无所谓),否则内窥镜会卡死 "createTime": now.Format("2006-01-02 15:04:05"), "deviceId": deviceId, "name": fileName, "dirStatus": 0, "dmCode": "", "docPath": filePath, //"id": 619, "level": 2, "parentDir": dir, "remark": "", "size": written, "type": ext, }, "msg": "success", }) } // StartCleanup 定期清理过期检测图片(每天一次),RetentionDays=-1 跳过 func StartCleanup(svcCtx *svc.ServiceContext) { if svcCtx.Config.Upload.RetentionDays == -1 { return } retention := svcCtx.Config.Upload.RetentionDays if retention <= 0 { retention = 30 } go func() { ticker := time.NewTicker(24 * time.Hour) defer ticker.Stop() for range ticker.C { cutoff := time.Now().AddDate(0, 0, -retention) images, err := svcCtx.EntClient.InspectionImage.Query(). Where(inspectionimage.CreatedAtLT(cutoff)). All(context.Background()) if err != nil { slog.Error("inspection cleanup: query failed", "error", err) continue } for _, img := range images { absPath := filepath.Join(svcCtx.Config.Upload.Dir, filepath.FromSlash(img.FilePath)) os.Remove(absPath) _ = svcCtx.EntClient.InspectionImage.DeleteOneID(img.ID).Exec(context.Background()) } if len(images) > 0 { slog.Info("inspection cleanup: removed expired images", "count", len(images), "before", cutoff) } } }() }