|
@@ -0,0 +1,889 @@
|
|
|
|
|
+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:"size(1000);index"` // 文件绝对路径
|
|
|
|
|
+ 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
|
|
|
|
|
+}
|