package FileManager import ( "Cold_Api/conf" "Cold_Api/controllers/lib" "Cold_Api/models/Account" "fmt" "path/filepath" "sort" "strings" "time" "github.com/beego/beego/v2/adapter/orm" orm2 "github.com/beego/beego/v2/client/orm" "github.com/beego/beego/v2/core/logs" _ "github.com/go-sql-driver/mysql" "github.com/google/uuid" ) // 文件管理主表 type FileManager struct { Id int `orm:"column(ID);size(11);auto;pk"` T_uuid string `orm:"size(128);unique"` // 文件唯一标识 T_pid int `orm:"index;size(11);default(0)"` // 公司ID,同公司用户可互相查看 T_name string `orm:"size(255)"` // 文件名 T_path string `orm:"type(text)"` // 文件绝对路径 T_url string `orm:"size(500);null"` // 七牛云文件链接 T_size int64 `orm:"size(20);default(0)"` // 文件大小(字节) T_type string `orm:"size(50);null"` // 文件类型(文件夹/文件后缀+文件) T_uploaded_by string `orm:"size(128)"` // 上传者 T_state int `orm:"size(2);default(1)"` // 状态: 0删除 1正常 CreateTime time.Time `orm:"column(create_time);type(timestamp);auto_now_add"` // 创建时间 UpdateTime time.Time `orm:"column(update_time);type(timestamp);auto_now"` // 更新时间 } // 返回结构体 type FileManager_R struct { Id int `json:"id"` T_uuid string `json:"t_uuid"` // 文件唯一标识 T_pid int `json:"t_pid"` // 公司ID T_name string `json:"t_name"` // 文件名 T_path string `json:"t_path"` // 文件绝对路径 T_url string `json:"t_url"` // 七牛云文件链接 T_size int64 `json:"t_size"` // 文件大小(字节) T_size_format string `json:"t_size_format"` // 格式化后的文件大小(带单位) T_type string `json:"t_type"` // 文件类型 T_uploaded_by string `json:"T_uploaded_by"` // 上传者 T_state int `json:"t_state"` // 状态 CreateTime string `json:"create_time"` // 创建时间 UpdateTime string `json:"update_time"` // 更新时间 } // 简化返回结构体 type FileManager_Simple struct { Id int `json:"id"` T_uuid string `json:"t_uuid"` // 文件唯一标识 T_pid int `json:"t_pid"` // 公司ID T_name string `json:"t_name"` // 文件名 T_path string `json:"t_path"` // 文件绝对路径 T_url string `json:"t_url"` // 七牛云文件链接 T_size int64 `json:"t_size"` // 文件大小(字节) T_size_format string `json:"t_size_format"` // 格式化后的文件大小(带单位) T_type string `json:"t_type"` // 文件类型 T_uploaded_by string `json:"T_uploaded_by"` // 上传者 CreateTime string `json:"create_time"` // 创建时间 } func (t *FileManager) TableName() string { return "file_manager" } func init() { //注册模型 orm.RegisterModel(new(FileManager)) } // ---------------- 辅助函数 ------------------- // 格式化文件大小,显示带单位的大小 func FormatFileSize(size int64) string { if size == 0 { return "0 B" } const unit = 1024 if size < unit { return fmt.Sprintf("%d B", size) } div, exp := int64(unit), 0 for n := size / unit; n >= unit; n /= unit { div *= unit exp++ } units := []string{"KB", "MB", "GB", "TB", "PB"} return fmt.Sprintf("%.1f %s", float64(size)/float64(div), units[exp]) } // 生成文件类型标识 func GenerateFileType(fileName, filePath string) string { // 判断是否为文件夹(路径以/结尾) if strings.HasSuffix(filePath, "/") { return "文件夹" } // 获取文件扩展名 ext := filepath.Ext(fileName) if ext == "" { return "文件" // 无扩展名的文件 } // 移除点号并转为小写 ext = strings.ToLower(strings.TrimPrefix(ext, ".")) return ext + "文件" } // ---------------- 转换方法 ------------------- func FileManagerToFileManager_R(t FileManager) (r FileManager_R) { r.Id = t.Id r.T_uuid = t.T_uuid r.T_pid = t.T_pid r.T_name = t.T_name r.T_path = t.T_path r.T_url = t.T_url r.T_size_format = FormatFileSize(t.T_size) // 格式化文件大小 if t.T_type == "文件夹" { r.T_size_format = "-" } r.T_type = t.T_type // 文件类型 r.T_uploaded_by = t.T_uploaded_by r.T_state = t.T_state if !t.CreateTime.IsZero() { r.CreateTime = t.CreateTime.Format("2006-01-02 15:04:05") } if !t.UpdateTime.IsZero() { r.UpdateTime = t.UpdateTime.Format("2006-01-02 15:04:05") } return r } func FileManagerToFileManager_Simple(t FileManager) (r FileManager_Simple) { r.Id = t.Id r.T_uuid = t.T_uuid r.T_pid = t.T_pid r.T_name = t.T_name r.T_path = t.T_path r.T_url = t.T_url r.T_size = t.T_size r.T_size_format = FormatFileSize(t.T_size) // 格式化文件大小 r.T_type = t.T_type // 文件类型 r.T_uploaded_by = t.T_uploaded_by if !t.CreateTime.IsZero() { r.CreateTime = t.CreateTime.Format("2006-01-02 15:04:05") } return r } // ---------------- CRUD 方法 ------------------- // 添加文件记录 func Add_FileManager(m FileManager) (id int64, err error) { o := orm.NewOrm() // 如果没有UUID,自动生成一个 if m.T_uuid == "" { m.T_uuid = uuid.New().String() } id, err = o.Insert(&m) if err != nil { logs.Error(lib.FuncName(), err) return } m.Id = int(id) return } // 根据ID获取文件记录 func Read_FileManager_ById(id int) (r FileManager, err error) { o := orm.NewOrm() r = FileManager{Id: id, T_state: 1} err = o.Read(&r, "Id", "T_state") if err != nil { logs.Error(lib.FuncName(), err) return } return r, err } // 根据路径获取文件记录 func Read_FileManager_ByPath(T_pid int, T_path string) (r FileManager, err error) { o := orm.NewOrm() cond := orm.NewCondition() cond1 := cond.And("T_state", 1).And("T_pid", T_pid).And("T_path", T_path) err = o.QueryTable(new(FileManager)).SetCond((*orm2.Condition)(cond1)).One(&r) if err != nil { logs.Error(lib.FuncName(), err) return } return r, err } // 修改文件记录 func Update_FileManager(m FileManager, cols ...string) bool { o := orm.NewOrm() _, err := o.Update(&m, cols...) if err != nil { logs.Error(lib.FuncName(), err) return false } return true } // 删除文件记录(软删除) func Delete_FileManager_ByUuid(T_uuid string) bool { o := orm.NewOrm() v := FileManager{T_uuid: T_uuid} if err := o.Read(&v, "T_uuid"); err == nil { v.T_state = 0 if _, err = o.Update(&v, "T_state"); err == nil { return true } } return false } // 递归删除文件记录及其子文件和子文件夹(软删除) func Delete_FileManager_Recursive_ByUuid(T_pid int, T_uuid string) (deletedCount int, err error) { o := orm.NewOrm() // 获取要删除的文件/文件夹信息 var targetFile FileManager err = o.QueryTable(new(FileManager)).Filter("T_uuid", T_uuid).Filter("T_pid", T_pid).Filter("T_state", 1).One(&targetFile) if err != nil { return 0, fmt.Errorf("文件不存在或已删除") } // 如果是文件夹(路径以/结尾),需要递归删除所有子项 if strings.HasSuffix(targetFile.T_path, "/") { // 查询所有子文件和子文件夹 var allChildren []FileManager cond := orm.NewCondition() cond1 := cond.And("T_state", 1).And("T_pid", T_pid).And("T_path__startswith", targetFile.T_path) _, err = o.QueryTable(new(FileManager)).SetCond((*orm2.Condition)(cond1)).All(&allChildren) if err != nil { logs.Error(lib.FuncName(), err) return 0, fmt.Errorf("查询子文件失败: %v", err) } // 删除所有子项(包括目标文件夹本身) for _, child := range allChildren { child.T_state = 0 if _, updateErr := o.Update(&child, "T_state"); updateErr == nil { deletedCount++ } else { logs.Error("删除子文件失败:", child.T_path, updateErr) } } } else { // 如果是文件,直接删除 targetFile.T_state = 0 if _, updateErr := o.Update(&targetFile, "T_state"); updateErr == nil { deletedCount = 1 } else { return 0, fmt.Errorf("删除文件失败: %v", updateErr) } } return deletedCount, nil } // 递归删除文件记录及其子文件和子文件夹(基于路径,软删除) func Delete_FileManager_Recursive_ByPath(T_pid int, T_path string) (deletedCount int, err error) { o := orm.NewOrm() // 获取要删除的文件/文件夹信息 var targetFile FileManager err = o.QueryTable(new(FileManager)).Filter("T_path", T_path).Filter("T_pid", T_pid).Filter("T_state", 1).One(&targetFile) if err != nil { return 0, fmt.Errorf("文件不存在或已删除") } // 如果是文件夹(路径以/结尾),需要递归删除所有子项 if strings.HasSuffix(targetFile.T_path, "/") { // 查询所有子文件和子文件夹 var allChildren []FileManager cond := orm.NewCondition() cond1 := cond.And("T_state", 1).And("T_pid", T_pid).And("T_path__startswith", targetFile.T_path) _, err = o.QueryTable(new(FileManager)).SetCond((*orm2.Condition)(cond1)).All(&allChildren) if err != nil { logs.Error(lib.FuncName(), err) return 0, fmt.Errorf("查询子文件失败: %v", err) } // 删除所有子项(包括目标文件夹本身) for _, child := range allChildren { child.T_state = 0 if _, updateErr := o.Update(&child, "T_state"); updateErr == nil { deletedCount++ } else { logs.Error("删除子文件失败:", child.T_path, updateErr) } } } else { // 如果是文件,直接删除 targetFile.T_state = 0 if _, updateErr := o.Update(&targetFile, "T_state"); updateErr == nil { deletedCount = 1 } else { return 0, fmt.Errorf("删除文件失败: %v", updateErr) } } return deletedCount, nil } // 删除文件记录(根据ID) func Delete_FileManager_ById(id int) bool { o := orm.NewOrm() v := FileManager{Id: id} if err := o.Read(&v, "Id"); err == nil { v.T_state = 0 if _, err = o.Update(&v, "T_state"); err == nil { return true } } return false } // 获取文件列表(简化版,仅返回当前路径直接子项) func Read_FileManager_List_Simple(T_pid int, path string, search string, sortBy string, sortOrder string, page int, pageSize int) (FileManagerList []FileManager_R, cnt int64) { o := orm.NewOrm() qs := o.QueryTable(new(FileManager)) var allMaps []FileManager cond := orm.NewCondition() cond1 := cond.And("T_State", 1) if T_pid > 0 { cond1 = cond1.And("T_pid", T_pid) } // 路径处理(先查询所有以该路径开始的文件) if len(path) > 0 { if !strings.HasSuffix(path, "/") { path += "/" } cond1 = cond1.And("T_path__startswith", path).AndNot("T_path", path) } // 搜索条件 if len(search) > 0 { cond1 = cond1.And("T_name__icontains", search) } // 排序处理 var orderBy string switch sortBy { case "name": if sortOrder == "descending" { orderBy = "-T_name" } else { orderBy = "T_name" } case "time": if sortOrder == "descending" { orderBy = "-CreateTime" } else { orderBy = "CreateTime" } default: // 默认按名称排序 orderBy = "T_name" } // 首先查询所有符合条件的文件 var err error _, err = qs.SetCond((*orm2.Condition)(cond1)).OrderBy(orderBy).All(&allMaps) if err != nil { logs.Error(lib.FuncName(), err) } // 后处理:过滤出只属于当前路径直接子项的文件 var filteredMaps []FileManager if len(path) > 0 { for _, v := range allMaps { // 检查是否为直接子项 relativePath := strings.TrimPrefix(v.T_path, path) // 如果相对路径不包含更多的"/",则为直接子项 if !strings.Contains(strings.Trim(relativePath, "/"), "/") { filteredMaps = append(filteredMaps, v) } } } else { filteredMaps = allMaps } // 目录优先排序 + 组内二次排序(名称或时间,升/降序) sort.SliceStable(filteredMaps, func(i, j int) bool { iIsDir := strings.HasSuffix(filteredMaps[i].T_path, "/") jIsDir := strings.HasSuffix(filteredMaps[j].T_path, "/") if iIsDir != jIsDir { return iIsDir && !jIsDir } switch sortBy { case "time": if sortOrder == "descending" { return filteredMaps[i].CreateTime.After(filteredMaps[j].CreateTime) } return filteredMaps[i].CreateTime.Before(filteredMaps[j].CreateTime) default: // name iname := strings.ToLower(filteredMaps[i].T_name) jname := strings.ToLower(filteredMaps[j].T_name) if sortOrder == "descending" { return iname > jname } return iname < jname } }) // 计算总数 cnt = int64(len(filteredMaps)) // 分页处理 var offset int if page <= 1 { offset = 0 } else { offset = (page - 1) * pageSize } var maps []FileManager if offset < len(filteredMaps) { end := offset + pageSize if end > len(filteredMaps) { end = len(filteredMaps) } maps = filteredMaps[offset:end] } for _, v := range maps { FileManagerList = append(FileManagerList, FileManagerToFileManager_R(v)) } return FileManagerList, cnt } // 获取文件列表(根据公司ID和路径) func Read_FileManager_List(T_pid int, T_path string, T_name string, T_type int, page int, page_z int) (FileManagerList []FileManager_R, cnt int64) { o := orm.NewOrm() qs := o.QueryTable(new(FileManager)) var maps []FileManager var offset int64 if page <= 1 { offset = 0 } else { offset = int64((page - 1) * page_z) } cond := orm.NewCondition() cond1 := cond.And("T_state", 1) if T_pid > 0 { cond1 = cond1.And("T_pid", T_pid) } if len(T_path) > 0 { // 如果路径以/结尾,查询该路径下的直接子项(排除当前路径本身) if strings.HasSuffix(T_path, "/") { cond1 = cond1.And("T_path__startswith", T_path).AndNot("T_path", T_path) } else { // 精确匹配路径 cond1 = cond1.And("T_path", T_path) } } if len(T_name) > 0 { cond1 = cond1.And("T_name__icontains", T_name) } if T_type > 0 { cond1 = cond1.And("T_type", T_type) } var err error if page_z == 9999 { _, err = qs.SetCond((*orm2.Condition)(cond1)).OrderBy("T_type", "-CreateTime").All(&maps) } else { _, err = qs.Limit(page_z, offset).SetCond((*orm2.Condition)(cond1)).OrderBy("T_type", "-CreateTime").All(&maps) } if err != nil { logs.Error(lib.FuncName(), err) } cnt, err = qs.SetCond((*orm2.Condition)(cond1)).Count() if err != nil { logs.Error(lib.FuncName(), err) } for _, v := range maps { FileManagerList = append(FileManagerList, FileManagerToFileManager_R(v)) } return FileManagerList, cnt } // 根据公司ID获取文件列表 func Read_FileManager_List_ByPid(T_pid int) (FileManagerList []FileManager_Simple) { o := orm.NewOrm() qs := o.QueryTable(new(FileManager)) var maps []FileManager cond := orm.NewCondition() cond1 := cond.And("T_state", 1).And("T_pid", T_pid) _, err := qs.SetCond((*orm2.Condition)(cond1)).OrderBy("T_type", "-CreateTime").All(&maps) if err != nil { logs.Error(lib.FuncName(), err) return FileManagerList } for _, v := range maps { FileManagerList = append(FileManagerList, FileManagerToFileManager_Simple(v)) } return FileManagerList } // 批量删除文件(支持递归删除) func Batch_Delete_FileManager(T_pid int, uuids []string) error { for _, uuid := range uuids { _, err := Delete_FileManager_Recursive_ByUuid(T_pid, uuid) if err != nil { logs.Error("Batch_Delete_FileManager error:", uuid, err) return fmt.Errorf("删除文件失败: %s - %v", uuid, err) } } return nil } // ------------ 文件夹相关方法(改为基于路径) ------------ // 创建文件夹 func Add_FileManager_Folder(T_pid int, T_name string, T_path string, T_uploadedby string) (id int64, err error) { folder := FileManager{ T_pid: T_pid, T_name: T_name, T_path: T_path, T_url: "", // 文件夹没有URL T_size: 0, // 文件夹大小设置为0 T_type: GenerateFileType(T_name, T_path), // 生成文件类型 T_uploaded_by: T_uploadedby, T_state: 1, } return Add_FileManager(folder) } // 获取指定路径下的子项目 func Read_FileManager_Children(T_pid int, T_path string) (FileManagerList []FileManager_R) { o := orm.NewOrm() qs := o.QueryTable(new(FileManager)) var maps []FileManager cond := orm.NewCondition() // 确保路径以/结尾 if !strings.HasSuffix(T_path, "/") { T_path += "/" } cond1 := cond.And("T_state", 1).And("T_pid", T_pid).And("T_path__startswith", T_path) // 使用后续代码过滤来排除子目录中的文件 _, err := qs.SetCond((*orm2.Condition)(cond1)).OrderBy("-CreateTime").All(&maps) if err != nil { logs.Error(lib.FuncName(), err) return FileManagerList } // 后处理:过滤出只属于当前路径直接子项的文件 var filteredMaps []FileManager for _, v := range maps { // 检查是否为直接子项 relativePath := strings.TrimPrefix(v.T_path, T_path) // 如果相对路径不包含更多的"/",则为直接子项 if !strings.Contains(strings.Trim(relativePath, "/"), "/") { filteredMaps = append(filteredMaps, v) } } for _, v := range filteredMaps { FileManagerList = append(FileManagerList, FileManagerToFileManager_R(v)) } return FileManagerList } // 检查路径下是否存在同名文件或文件夹 func Check_FileManager_Name_Exists(T_pid int, T_path string, T_name string, excludeId int) bool { o := orm.NewOrm() qs := o.QueryTable(new(FileManager)) // 构建完整路径 fullPath := strings.TrimSuffix(T_path, "/") + "/" + T_name + "/" cond := orm.NewCondition() cond1 := cond.And("T_state", 1).And("T_pid", T_pid).And("T_path", fullPath) if excludeId > 0 { cond1 = cond1.AndNot("Id", excludeId) } cnt, err := qs.SetCond((*orm2.Condition)(cond1)).Count() if err != nil { logs.Error(lib.FuncName(), err) return false } return cnt > 0 } // 检查文件是否存在(根据完整路径) func Check_FileManager_Exists_ByPath(T_pid int, T_path string) bool { o := orm.NewOrm() qs := o.QueryTable(new(FileManager)) cond := orm.NewCondition() cond1 := cond.And("T_state", 1).And("T_pid", T_pid).And("T_path", T_path) cnt, err := qs.SetCond((*orm2.Condition)(cond1)).Count() if err != nil { logs.Error(lib.FuncName(), err) return false } return cnt > 0 } // 自动创建路径中不存在的文件夹 func Auto_Create_Folders(T_pid int, T_path string, T_uploadedby string) error { // 确保路径以/开始 if !strings.HasPrefix(T_path, "/") { T_path = "/" + T_path } // 分割路径 parts := strings.Split(strings.Trim(T_path, "/"), "/") currentPath := "/" for _, part := range parts { if part == "" { continue } // 构建当前文件夹路径 folderPath := currentPath + part // 当path是文件夹时,在currentPath后加一个/ if !strings.HasSuffix(folderPath, "/") { folderPath += "/" } // 检查文件夹是否存在 if !Check_FileManager_Exists_ByPath(T_pid, folderPath) { // 文件夹不存在,创建它 _, err := Add_FileManager_Folder(T_pid, part, folderPath, T_uploadedby) if err != nil { return fmt.Errorf("创建文件夹 %s 失败: %v", folderPath, err) } } // 更新当前路径,确保文件夹路径以/结尾 currentPath = folderPath } return nil } // 获取路径的面包屑导航 func Get_FileManager_Breadcrumb(T_path string) []map[string]string { var breadcrumb []map[string]string // 根目录 breadcrumb = append(breadcrumb, map[string]string{ "name": "根目录", "path": "/", }) if T_path == "/" || T_path == "" { return breadcrumb } // 分割路径 parts := strings.Split(strings.Trim(T_path, "/"), "/") currentPath := "" for _, part := range parts { if part != "" { currentPath += "/" + part // 当path是文件夹时,在currentPath后加一个/ pathForBreadcrumb := currentPath if !strings.HasSuffix(pathForBreadcrumb, "/") { pathForBreadcrumb += "/" } breadcrumb = append(breadcrumb, map[string]string{ "name": part, "path": pathForBreadcrumb, }) } } return breadcrumb } // 判断是否为文件夹 func Is_FileManager_Folder(id int) bool { folder, err := Read_FileManager_ById(id) if err != nil { return false } // 文件夹的判断需要根据路径是否以"/"结尾来判断 return strings.HasSuffix(folder.T_path, "/") } // 重命名文件夹并递归更新所有子文件和子文件夹的路径 func Update_Folder_And_Children_Path(T_pid int, oldPath, newPath, newName string) error { o := orm.NewOrm() o.Begin() // 1. 先更新文件夹本身 var folder FileManager err := o.QueryTable(new(FileManager)).Filter("T_pid", T_pid).Filter("T_path", oldPath).Filter("T_state", 1).One(&folder) if err != nil { o.Rollback() return fmt.Errorf("获取文件夹信息失败: %v", err) } folder.T_name = newName folder.T_path = newPath _, err = o.Update(&folder, "T_name", "T_path", "UpdateTime") if err != nil { o.Rollback() return fmt.Errorf("更新文件夹失败: %v", err) } // 2. 查询所有子文件和子文件夹 var children []FileManager cond := orm.NewCondition() cond1 := cond.And("T_state", 1).And("T_pid", T_pid).And("T_path__startswith", oldPath) _, err = o.QueryTable(new(FileManager)).SetCond((*orm2.Condition)(cond1)).All(&children) if err != nil { o.Rollback() return fmt.Errorf("查询子文件失败: %v", err) } // 3. 递归更新所有子文件和子文件夹的路径 for _, child := range children { // 跳过文件夹本身(已经更新过了) if child.T_path == oldPath { continue } // 替换路径前缀 if strings.HasPrefix(child.T_path, oldPath) { newChildPath := strings.Replace(child.T_path, oldPath, newPath, 1) child.T_path = newChildPath _, err = o.Update(&child, "T_path", "UpdateTime") if err != nil { o.Rollback() return fmt.Errorf("更新子文件 %s 路径失败: %v", child.T_name, err) } } } o.Commit() return nil } // ---------------- 存储空间管理 ------------------- // 获取公司已使用的存储空间(字节) func Get_Company_Used_Storage(T_pid int) (int64, error) { o := orm.NewOrm() qs := o.QueryTable(new(FileManager)) cond := orm.NewCondition() cond1 := cond.And("T_state", 1).And("T_pid", T_pid) var totalSize int64 var maps []FileManager _, err := qs.SetCond((*orm2.Condition)(cond1)).All(&maps) if err != nil { logs.Error(lib.FuncName(), err) return 0, err } for _, file := range maps { // 只统计文件大小,不统计文件夹(文件夹的T_size为0) if !strings.HasSuffix(file.T_path, "/") { totalSize += file.T_size } } return totalSize, nil } // 获取公司的文件大小限制(字节) // 如果公司配置的限制为0或未设置,则使用系统默认配置 func Get_Company_Storage_Limit(T_pid int) (int64, error) { // 导入配置包 company, err := Account.Read_Company_ById(T_pid) if err != nil { return 0, fmt.Errorf("获取公司信息失败: %v", err) } // 如果公司设置了存储限制,使用公司配置 if company.T_file_size_limit > 0 { return company.T_file_size_limit, nil } // 否则使用系统默认配置 return conf.DefaultFileSizeLimit, nil } // 检查公司是否还有足够的存储空间上传新文件 func Check_Company_Storage_Available(T_pid int, newFileSize int64) (bool, int64, int64, error) { // 获取已使用空间 usedStorage, err := Get_Company_Used_Storage(T_pid) if err != nil { return false, 0, 0, fmt.Errorf("获取已使用存储空间失败: %v", err) } // 获取存储限制 storageLimit, err := Get_Company_Storage_Limit(T_pid) if err != nil { return false, 0, 0, fmt.Errorf("获取存储限制失败: %v", err) } // 检查是否还有足够空间 available := (usedStorage + newFileSize) <= storageLimit return available, usedStorage, storageLimit, nil } // 获取公司存储使用情况统计 type CompanyStorageInfo struct { UsedStorage int64 `json:"used_storage"` // 已使用存储(字节) StorageLimit int64 `json:"storage_limit"` // 存储限制(字节) AvailableStorage int64 `json:"available_storage"` // 可用存储(字节) UsagePercentage float64 `json:"usage_percentage"` // 使用百分比 UsedStorageFormatted string `json:"used_storage_formatted"` // 格式化的已使用存储 StorageLimitFormatted string `json:"storage_limit_formatted"` // 格式化的存储限制 AvailableStorageFormatted string `json:"available_storage_formatted"` // 格式化的可用存储 } func Get_Company_Storage_Info(T_pid int) (CompanyStorageInfo, error) { var info CompanyStorageInfo // 获取已使用存储 usedStorage, err := Get_Company_Used_Storage(T_pid) if err != nil { return info, fmt.Errorf("获取已使用存储失败: %v", err) } // 获取存储限制 storageLimit, err := Get_Company_Storage_Limit(T_pid) if err != nil { return info, fmt.Errorf("获取存储限制失败: %v", err) } // 计算可用存储 availableStorage := storageLimit - usedStorage if availableStorage < 0 { availableStorage = 0 } // 计算使用百分比 usagePercentage := float64(0) if storageLimit > 0 { usagePercentage = float64(usedStorage) / float64(storageLimit) * 100 } // 填充结构体 info.UsedStorage = usedStorage info.StorageLimit = storageLimit info.AvailableStorage = availableStorage info.UsagePercentage = usagePercentage info.UsedStorageFormatted = FormatFileSize(usedStorage) info.StorageLimitFormatted = FormatFileSize(storageLimit) info.AvailableStorageFormatted = FormatFileSize(availableStorage) return info, nil }