package handlers import ( "context" "net/http" "os" "path/filepath" "time" "go.mongodb.org/mongo-driver/v2/bson" "go.mongodb.org/mongo-driver/v2/mongo/options" "yh_web/server/config" "yh_web/server/models" "github.com/gin-gonic/gin" ) const uploadDir = "uploads" // ListSiteAssets 站点功能模块/上传文件列表 func ListSiteAssets(c *gin.Context) { siteID := c.Param("site_id") if siteID == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "请提供 site_id"}) return } ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() coll := config.GetDB(config.DBName).Collection("site_assets") opts := options.Find().SetSort(bson.D{{Key: "created_at", Value: -1}}) cursor, err := coll.Find(ctx, bson.M{"site_id": siteID}, opts) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } defer cursor.Close(ctx) var list []models.SiteAsset if err = cursor.All(ctx, &list); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } total, _ := coll.CountDocuments(ctx, bson.M{"site_id": siteID}) c.JSON(http.StatusOK, gin.H{"list": list, "total": total}) } // UploadSiteAsset 上传功能模块/文件 func UploadSiteAsset(c *gin.Context) { siteID := c.Param("site_id") if siteID == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "请提供 site_id"}) return } file, err := c.FormFile("file") if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "请选择要上传的文件"}) return } baseDir := filepath.Join(uploadDir, "sites", siteID) if err := os.MkdirAll(baseDir, 0755); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "创建目录失败"}) return } // 避免覆盖:加时间戳 name := file.Filename ext := filepath.Ext(name) nameNoExt := name[:len(name)-len(ext)] saveName := nameNoExt + "_" + time.Now().Format("20060102150405") + ext relPath := filepath.Join("sites", siteID, saveName) destPath := filepath.Join(uploadDir, relPath) if err := c.SaveUploadedFile(file, destPath); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "保存文件失败"}) return } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() doc := models.SiteAsset{ SiteID: siteID, Name: file.Filename, FilePath: relPath, Size: file.Size, ContentType: file.Header.Get("Content-Type"), CreatedAt: time.Now().Format(time.RFC3339), } res, err := config.GetDB(config.DBName).Collection("site_assets").InsertOne(ctx, bson.M{ "site_id": doc.SiteID, "name": doc.Name, "file_path": doc.FilePath, "size": doc.Size, "content_type": doc.ContentType, "created_at": doc.CreatedAt, }) if err != nil { os.Remove(destPath) c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"id": res.InsertedID, "file_path": doc.FilePath, "message": "上传成功"}) } // DeleteSiteAsset 删除站点资源 func DeleteSiteAsset(c *gin.Context) { siteID := c.Param("site_id") idStr := c.Param("asset_id") if siteID == "" || idStr == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "参数错误"}) return } oid, err := bson.ObjectIDFromHex(idStr) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "无效的ID"}) return } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() coll := config.GetDB(config.DBName).Collection("site_assets") var asset models.SiteAsset err = coll.FindOne(ctx, bson.M{"_id": oid, "site_id": siteID}).Decode(&asset) if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "资源不存在"}) return } fullPath := filepath.Join(uploadDir, asset.FilePath) os.Remove(fullPath) _, err = coll.DeleteOne(ctx, bson.M{"_id": oid}) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"message": "删除成功"}) }