package controllers import ( "Cold_Api/conf" "Cold_Api/controllers/lib" "Cold_Api/models/Account" "Cold_Api/models/FileManager" "encoding/json" "fmt" "math" "path/filepath" "strings" "github.com/beego/beego/v2/adapter/orm" beego "github.com/beego/beego/v2/server/web" ) type FileManagerController struct { beego.Controller Admin_r Account.Admin // 登陆的用户 T_pid int // 公司id } func (c *FileManagerController) Prepare() { GetCookie := c.Ctx.GetCookie("User_tokey") GetString := c.GetString("User_tokey") User_tokey := GetString if len(User_tokey) == 0 { User_tokey = GetCookie } if Account.Admin_r == nil { return } c.Admin_r = *Account.Admin_r T_pid := c.T_pid EntryPid, _ := Account.Redis_Tokey_T_pid_Get(User_tokey) if EntryPid > 0 { T_pid = EntryPid } c.T_pid = T_pid } // AddFileManager 添加文件记录(使用form-data格式) func (c *FileManagerController) AddFileManager() { // 获取form-data参数 filesParam := c.GetString("files") overwriteParam := c.GetString("overwrite") pathParam := c.GetString("path") // 定义文件信息结构体 type FileInfo struct { Name string `json:"name"` // 文件名 Url string `json:"url"` // 文件URL Size int64 `json:"size"` // 文件大小 } // 参数验证 if len(filesParam) == 0 { c.Data["json"] = lib.JSONS{Code: 202, Msg: "文件参数不能为空"} c.ServeJSON() return } // 解析文件列表JSON var files []FileInfo err := json.Unmarshal([]byte(filesParam), &files) if err != nil { c.Data["json"] = lib.JSONS{Code: 202, Msg: "文件参数格式错误"} c.ServeJSON() return } // 验证文件列表 if len(files) == 0 { c.Data["json"] = lib.JSONS{Code: 202, Msg: "文件列表不能为空"} c.ServeJSON() return } // 解析覆盖参数 overwrite := false if overwriteParam == "true" || overwriteParam == "1" { overwrite = true } // 验证每个文件的参数 var totalSize int64 for i, file := range files { if len(file.Name) == 0 { c.Data["json"] = lib.JSONS{Code: 202, Msg: fmt.Sprintf("第%d个文件名不能为空", i+1)} c.ServeJSON() return } if len(file.Url) == 0 { c.Data["json"] = lib.JSONS{Code: 202, Msg: fmt.Sprintf("第%d个文件链接不能为空", i+1)} c.ServeJSON() return } if file.Size <= 0 { c.Data["json"] = lib.JSONS{Code: 202, Msg: fmt.Sprintf("第%d个文件大小必须大于0", i+1)} c.ServeJSON() return } totalSize += file.Size } // 检查公司存储空间是否足够 if c.T_pid > 0 { available, usedStorage, storageLimit, err := FileManager.Check_Company_Storage_Available(c.T_pid, totalSize) if err != nil { c.Data["json"] = lib.JSONS{Code: 202, Msg: fmt.Sprintf("检查存储空间失败: %v", err)} c.ServeJSON() return } if !available { c.Data["json"] = lib.JSONS{ Code: 202, Msg: fmt.Sprintf("存储空间不足,已使用: %s,限制: %s,当前批量文件: %s", FileManager.FormatFileSize(usedStorage), FileManager.FormatFileSize(storageLimit), FileManager.FormatFileSize(totalSize)), } c.ServeJSON() return } } // 处理上传路径 T_path := pathParam if len(T_path) == 0 { T_path = "/" } if !strings.HasSuffix(T_path, "/") { T_path += "/" } // 自动创建路径中不存在的文件夹 if T_path != "/" { err := FileManager.Auto_Create_Folders(c.T_pid, T_path, c.Admin_r.T_uuid) if err != nil { c.Data["json"] = lib.JSONS{Code: 202, Msg: fmt.Sprintf("创建路径失败: %v", err)} c.ServeJSON() return } } // 批量处理文件 var successFiles []FileManager.FileManager_R var failedFiles []map[string]interface{} var successCount int for _, fileInfo := range files { // 构建完整路径 fullPath := T_path + fileInfo.Name // 检查是否存在同名文件 if !overwrite && FileManager.Check_FileManager_Name_Exists(c.T_pid, T_path, fileInfo.Name, 0) { failedFiles = append(failedFiles, map[string]interface{}{ "name": fileInfo.Name, "reason": "文件已存在", }) continue } // 如果覆盖模式,先删除旧文件 if overwrite { o := orm.NewOrm() var existingFile FileManager.FileManager err := o.QueryTable(new(FileManager.FileManager)).Filter("T_pid", c.T_pid).Filter("T_path", fullPath).Filter("T_state", 1).One(&existingFile) if err == nil { FileManager.Delete_FileManager_ByUuid(existingFile.T_uuid) } } // 保存文件信息到数据库 fileManager := FileManager.FileManager{ T_pid: c.T_pid, T_name: fileInfo.Name, T_path: fullPath, T_url: fileInfo.Url, T_size: fileInfo.Size, T_type: FileManager.GenerateFileType(fileInfo.Name, fullPath), // 生成文件类型 T_uploaded_by: c.Admin_r.T_uuid, T_state: 1, } id, err := FileManager.Add_FileManager(fileManager) if err != nil { failedFiles = append(failedFiles, map[string]interface{}{ "name": fileInfo.Name, "reason": fmt.Sprintf("保存失败: %v", err), }) continue } fileManager.Id = int(id) uploadedFile := FileManager.FileManagerToFileManager_R(fileManager) successFiles = append(successFiles, uploadedFile) successCount++ } // 构建返回结果 response := map[string]interface{}{ "success_count": successCount, "failed_count": len(failedFiles), "total_count": len(files), "success_files": successFiles, "failed_files": failedFiles, } // 根据结果返回不同的消息 if len(failedFiles) == 0 { c.Data["json"] = lib.JSONS{Code: 200, Msg: fmt.Sprintf("所有文件添加成功,共%d个文件", successCount), Data: response} } else if successCount == 0 { c.Data["json"] = lib.JSONS{Code: 202, Msg: "所有文件添加失败", Data: response} } else { c.Data["json"] = lib.JSONS{Code: 200, Msg: fmt.Sprintf("部分文件添加成功,成功%d个,失败%d个", successCount, len(failedFiles)), Data: response} } c.ServeJSON() return } // DeleteFileManager 删除文件(支持递归删除文件夹及其子文件) func (c *FileManagerController) DeleteFileManager() { T_path := c.GetString("path") if len(T_path) == 0 { c.Data["json"] = lib.JSONS{Code: 202, Msg: "文件路径不能为空"} c.ServeJSON() return } // 使用递归删除方法(基于路径) deletedCount, err := FileManager.Delete_FileManager_Recursive_ByPath(c.T_pid, T_path) if err != nil { c.Data["json"] = lib.JSONS{Code: 202, Msg: fmt.Sprintf("删除失败: %v", err)} c.ServeJSON() return } // 根据删除数量返回不同的成功消息 var msg string if deletedCount > 1 { msg = fmt.Sprintf("删除成功,共删除 %d 个文件/文件夹", deletedCount) } else { msg = "删除成功" } c.Data["json"] = lib.JSONS{Code: 200, Msg: msg, Data: map[string]interface{}{"deletedCount": deletedCount}} c.ServeJSON() return } // CheckFileExists 检查文件列表是否存在 func (c *FileManagerController) CheckFileExists() { // 获取路径列表参数 pathsParam := c.GetString("paths") if len(pathsParam) == 0 { c.Data["json"] = lib.JSONS{Code: 202, Msg: "路径列表参数不能为空"} c.ServeJSON() return } // 解析路径列表(支持JSON数组格式) var paths []string if err := json.Unmarshal([]byte(pathsParam), &paths); err != nil { // 如果不是JSON格式,按逗号分割 paths = strings.Split(pathsParam, ",") } // 存储已存在的路径信息 var existingFiles []map[string]interface{} // 检查每个路径 for _, path := range paths { path = strings.TrimSpace(path) if len(path) == 0 { continue } // 检查路径是否存在 if exists := FileManager.Check_FileManager_Exists_ByPath(c.T_pid, path); exists { // 获取文件详细信息 if file, err := FileManager.Read_FileManager_ByPath(c.T_pid, path); err == nil { // 构建返回格式 fileInfo := map[string]interface{}{ "name": file.T_name, "path": file.T_path, "size": file.T_size, // 使用实际文件大小 "modTime": file.CreateTime.Format("2006-01-02 15:04:05"), "isDir": strings.HasSuffix(file.T_path, "/"), } existingFiles = append(existingFiles, fileInfo) } } } // 返回已存在的文件列表 c.Data["json"] = lib.JSONS{Code: 200, Msg: "success", Data: existingFiles} c.ServeJSON() return } // GetFileManagerList 获取文件列表 func (c *FileManagerController) GetFileManagerList() { page, _ := c.GetInt("page") if page < 1 { page = 1 } page_z, _ := c.GetInt("page_z") if page_z < 1 || page_z > 1000 { page_z = conf.Page_size } // 获取查询参数 path := c.GetString("path", "/") search := c.GetString("search", "") // 搜索关键词 sortBy := c.GetString("sortBy", "name") // 排序字段 sortOrder := c.GetString("sortOrder", "ascending") // 排序方向 // 使用简化版查询方法(只查询当前路径直接子项) files, total := FileManager.Read_FileManager_List_Simple( c.T_pid, path, search, sortBy, sortOrder, page, page_z, ) // 计算分页信息 totalPages := int(math.Ceil(float64(total) / float64(page_z))) // 构建响应数据 response := map[string]interface{}{ "Data": files, "Num": total, "page": page, "Page_size": page_z, "totalPages": totalPages, "path": path, "sortBy": sortBy, "sortOrder": sortOrder, "breadcrumb": FileManager.Get_FileManager_Breadcrumb(path), } c.Data["json"] = lib.JSONS{Code: 200, Msg: "success", Data: response} c.ServeJSON() return } // ------------ 文件夹相关接口 ------------ // AddFolder 创建文件夹 func (c *FileManagerController) AddFolder() { T_name := c.GetString("T_name") if len(T_name) == 0 { c.Data["json"] = lib.JSONS{Code: 202, Msg: "文件夹名称不能为空"} c.ServeJSON() return } T_path := c.GetString("path", "/") if !strings.HasSuffix(T_path, "/") { T_path += "/" } // 自动创建父级路径中不存在的文件夹 if T_path != "/" { err := FileManager.Auto_Create_Folders(c.T_pid, T_path, c.Admin_r.T_uuid) if err != nil { c.Data["json"] = lib.JSONS{Code: 202, Msg: fmt.Sprintf("创建父级路径失败: %v", err)} c.ServeJSON() return } } // 检查同级目录下是否存在同名文件夹 if FileManager.Check_FileManager_Name_Exists(c.T_pid, T_path, T_name, 0) { c.Data["json"] = lib.JSONS{Code: 202, Msg: "该目录下已存在同名文件夹"} c.ServeJSON() return } // 构建文件夹完整路径 folderPath := T_path + T_name + "/" // 创建文件夹 id, err := FileManager.Add_FileManager_Folder(c.T_pid, T_name, folderPath, c.Admin_r.T_uuid) if err != nil { c.Data["json"] = lib.JSONS{Code: 202, Msg: "创建文件夹失败"} c.ServeJSON() return } c.Data["json"] = lib.JSONS{Code: 200, Msg: "创建成功", Data: map[string]interface{}{"id": id, "path": folderPath}} c.ServeJSON() return } // GetBreadcrumb 获取路径面包屑 func (c *FileManagerController) GetBreadcrumb() { T_path := c.GetString("path", "/") breadcrumb := FileManager.Get_FileManager_Breadcrumb(T_path) c.Data["json"] = lib.JSONS{Code: 200, Msg: "success", Data: breadcrumb} c.ServeJSON() return } // RenameFile 重命名文件或文件夹 func (c *FileManagerController) RenameFile() { // 支持两种参数格式: // 1. 传统的id + T_name格式 // 2. 新的oldName + newName格式(参考API) oldName := c.GetString("oldName") newName := c.GetString("newName") path := c.GetString("path") // 如果使用新格式 if len(oldName) > 0 && len(newName) > 0 { c.renameByPath(oldName, newName, path) return } } // renameByPath 基于路径的重命名方法 func (c *FileManagerController) renameByPath(oldPath, newPath, parentPath string) { // 参数验证 if len(oldPath) == 0 || len(newPath) == 0 { c.Data["json"] = lib.JSONS{Code: 202, Msg: "路径参数不能为空"} c.ServeJSON() return } // 从完整路径中提取文件名 newName := filepath.Base(newPath) // 确保路径以/开头 if !strings.HasPrefix(oldPath, "/") { oldPath = "/" + oldPath } if !strings.HasPrefix(newPath, "/") { newPath = "/" + newPath } // 查找要重命名的文件/文件夹 file, err := FileManager.Read_FileManager_ByPath(c.T_pid, oldPath) if err != nil { // 如果是文件夹,尝试添加/后缀 if !strings.HasSuffix(oldPath, "/") { file, err = FileManager.Read_FileManager_ByPath(c.T_pid, oldPath+"/") if err != nil { c.Data["json"] = lib.JSONS{Code: 202, Msg: "文件或文件夹不存在"} c.ServeJSON() return } oldPath += "/" newPath += "/" } else { c.Data["json"] = lib.JSONS{Code: 202, Msg: "文件或文件夹不存在"} c.ServeJSON() return } } // 验证权限 if file.T_pid != c.T_pid { c.Data["json"] = lib.JSONS{Code: 202, Msg: "权限不足"} c.ServeJSON() return } // 检查新路径是否已存在 exists := FileManager.Check_FileManager_Exists_ByPath(c.T_pid, newPath) if exists { c.Data["json"] = lib.JSONS{Code: 202, Msg: "目标路径已存在"} c.ServeJSON() return } // 执行重命名 if strings.HasSuffix(oldPath, "/") { // 文件夹 err = FileManager.Update_Folder_And_Children_Path(c.T_pid, oldPath, newPath, newName) if err != nil { c.Data["json"] = lib.JSONS{Code: 202, Msg: fmt.Sprintf("重命名文件夹失败: %v", err)} c.ServeJSON() return } } else { // 文件 file.T_name = newName file.T_path = newPath success := FileManager.Update_FileManager(file, "T_name", "T_path", "UpdateTime") if !success { c.Data["json"] = lib.JSONS{Code: 202, Msg: "重命名失败"} c.ServeJSON() return } } c.Data["json"] = lib.JSONS{Code: 200, Msg: "重命名成功"} c.ServeJSON() return } // GetStorageInfo 获取公司存储使用情况 func (c *FileManagerController) GetStorageInfo() { // 获取存储信息 storageInfo, err := FileManager.Get_Company_Storage_Info(c.T_pid) if err != nil { c.Data["json"] = lib.JSONS{Code: 202, Msg: fmt.Sprintf("获取存储信息失败: %v", err)} c.ServeJSON() return } c.Data["json"] = lib.JSONS{Code: 200, Msg: "success", Data: storageInfo} c.ServeJSON() return } // GetUploadToken 获取七牛云上传Token func (c *FileManagerController) GetUploadToken() { // 获取文件后缀参数 fileSuffix := c.GetString("suffix", "") // 生成上传Token uploadToken := lib.UploadToken(fileSuffix) c.Data["json"] = lib.JSONS{ Code: 200, Msg: "success", Data: map[string]interface{}{ "token": uploadToken, "domain": "", // 七牛云访问域名(如需要可从配置获取) }, } c.ServeJSON() return }