| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889 |
- 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
- }
|