From e581f6e6b410a6406a86c6743d43b8d450cd3d50 Mon Sep 17 00:00:00 2001
From: zhangqian <zhangqian@123.com>
Date: 星期六, 05 八月 2023 18:31:57 +0800
Subject: [PATCH] 文件管理

---
 service/file.go          |   65 ++
 constvar/file.go         |   12 
 model/request/file.go    |   23 +
 pkg/httpx/httpx.go       |   14 
 go.mod                   |   16 
 docs/swagger.yaml        |  209 +++++++++
 model/file.go            |  152 ++++++
 docs/docs.go             |  314 +++++++++++++
 pkg/contextx/contextx.go |    4 
 router/file.go           |   15 
 docs/swagger.json        |  314 +++++++++++++
 api/v1/file.go           |  157 ++++++
 go.sum                   |   44 +
 router/index.go          |    1 
 14 files changed, 1,340 insertions(+), 0 deletions(-)

diff --git a/api/v1/file.go b/api/v1/file.go
new file mode 100644
index 0000000..1edb6b9
--- /dev/null
+++ b/api/v1/file.go
@@ -0,0 +1,157 @@
+package v1
+
+import (
+	"aps_crm/model"
+	"aps_crm/model/request"
+	"aps_crm/model/response"
+	"aps_crm/pkg/contextx"
+	"aps_crm/pkg/ecode"
+	"aps_crm/pkg/httpx"
+	"aps_crm/service"
+	"github.com/flipped-aurora/gin-vue-admin/server/utils/upload"
+	"github.com/gin-gonic/gin"
+	"os"
+	"path/filepath"
+	"strconv"
+)
+
+type FileApi struct{}
+
+// Add
+// @Tags		闄勪欢绠$悊
+// @Summary	娣诲姞闄勪欢
+// @Produce	application/json
+// @Param		object	body		request.AddFile	true	"鏌ヨ鍙傛暟"
+// @Success	200		{object}	contextx.Response{}
+// @Router		/api/file/add [post]
+func (s *FileApi) Add(c *gin.Context) {
+	var params request.AddFile
+	ctx, ok := contextx.NewContext(c, &params)
+	if !ok {
+		return
+	}
+
+	_, header, err := c.Request.FormFile("file")
+	if err != nil {
+		ctx.Fail(ecode.ParamsErr)
+		return
+	}
+
+	oss := upload.NewOss()
+	filePath, key, uploadErr := oss.UploadFile(header)
+	if uploadErr != nil {
+		ctx.Fail(ecode.ParamsErr)
+		return
+	}
+
+	_, filename := filepath.Split(filePath)
+
+	fileRecord := &model.File{
+		Name:          filename,
+		Size:          header.Size,
+		FilePath:      filePath,
+		Key:           key,
+		DownloadCount: 0,
+		PreviewCount:  0,
+		FileType:      httpx.GetMimeType(filePath),
+		SourceType:    params.SourceType,
+		SourceId:      params.SourceId,
+	}
+
+	errCode := service.NewFileService().AddFile(fileRecord)
+	if errCode != ecode.OK {
+		ctx.Fail(errCode)
+		return
+	}
+
+	ctx.Ok()
+}
+
+// Delete
+// @Tags		闄勪欢绠$悊
+// @Summary	鍒犻櫎闄勪欢
+// @Produce	application/json
+// @Param		id	path		int	true	"鏌ヨ鍙傛暟"
+// @Success	200	{object}	contextx.Response{}
+// @Router		/api/file/delete/{id} [delete]
+func (s *FileApi) Delete(c *gin.Context) {
+	ctx, ok := contextx.NewContext(c, nil)
+	if !ok {
+		return
+	}
+
+	id, _ := strconv.Atoi(c.Param("id"))
+
+	file, err := model.NewFileSearch().SetId(id).First()
+	if err != nil {
+		ctx.FailWithMsg(ecode.ParamsErr, "鏌ユ壘鏂囦欢澶辫触")
+		return
+	}
+
+	err = os.Remove(file.FilePath)
+	if err != nil {
+		ctx.FailWithMsg(ecode.ParamsErr, "鍒犻櫎鏂囦欢澶辫触")
+		return
+	}
+
+	errCode := service.NewFileService().DeleteFile(id)
+	if errCode != ecode.OK {
+		ctx.Fail(errCode)
+		return
+	}
+
+	ctx.Ok()
+}
+
+// Update
+// @Tags		闄勪欢绠$悊
+// @Summary	鏇存柊闄勪欢
+// @Produce	application/json
+// @Param		object	body		request.UpdateFile	true	"鏌ヨ鍙傛暟"
+// @Success	200		{object}	contextx.Response{}
+// @Router		/api/file/update [put]
+func (s *FileApi) Update(c *gin.Context) {
+	var params request.UpdateFile
+	ctx, ok := contextx.NewContext(c, &params)
+	if !ok {
+		return
+	}
+	if params.Id == 0 {
+		ctx.Fail(ecode.ParamsErr)
+	}
+	params.File.Id = params.Id
+
+	errCode := service.NewFileService().UpdateFile(&params.File)
+	if errCode != ecode.OK {
+		ctx.Fail(errCode)
+		return
+	}
+
+	ctx.Ok()
+}
+
+// List
+// @Tags		闄勪欢绠$悊
+// @Summary	鑾峰彇闄勪欢鍒楄〃
+// @Produce	application/json
+// @Param		object	query		request.GetFileList	true	"鍙傛暟"
+// @Success	200	{object}	response.ListResponse{data=[]model.File}
+// @Router		/api/file/list [get]
+func (s *FileApi) List(c *gin.Context) {
+	var params request.GetFileList
+	ctx, ok := contextx.NewContext(c, &params)
+	if !ok {
+		return
+	}
+
+	file, total, errCode := service.NewFileService().GetFileList()
+	if errCode != ecode.OK {
+		ctx.Fail(errCode)
+		return
+	}
+
+	ctx.OkWithDetailed(response.ListResponse{
+		Data:  file,
+		Count: total,
+	})
+}
diff --git a/constvar/file.go b/constvar/file.go
new file mode 100644
index 0000000..042bbf4
--- /dev/null
+++ b/constvar/file.go
@@ -0,0 +1,12 @@
+package constvar
+type FileQueryClass string
+
+const (
+	FileQueryClassExpireLessThen60Days FileQueryClass = ""
+)
+
+type FileKeywordType string
+
+const (
+	FileKeywordCustomerName   FileKeywordType = ""
+)
diff --git a/docs/docs.go b/docs/docs.go
index 4b55d3a..a31ad29 100644
--- a/docs/docs.go
+++ b/docs/docs.go
@@ -2492,6 +2492,169 @@
                 }
             }
         },
+        "/api/file/add": {
+            "post": {
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "闄勪欢绠$悊"
+                ],
+                "summary": "娣诲姞闄勪欢",
+                "parameters": [
+                    {
+                        "description": "鏌ヨ鍙傛暟",
+                        "name": "object",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/request.AddFile"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/contextx.Response"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/file/delete/{id}": {
+            "delete": {
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "闄勪欢绠$悊"
+                ],
+                "summary": "鍒犻櫎闄勪欢",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "鏌ヨ鍙傛暟",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/contextx.Response"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/file/list": {
+            "get": {
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "闄勪欢绠$悊"
+                ],
+                "summary": "鑾峰彇闄勪欢鍒楄〃",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "name": "keyword",
+                        "in": "query"
+                    },
+                    {
+                        "enum": [
+                            ""
+                        ],
+                        "type": "string",
+                        "x-enum-varnames": [
+                            "FileKeywordCustomerName"
+                        ],
+                        "name": "keywordType",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "椤电爜",
+                        "name": "page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "姣忛〉澶у皬",
+                        "name": "pageSize",
+                        "in": "query"
+                    },
+                    {
+                        "enum": [
+                            ""
+                        ],
+                        "type": "string",
+                        "x-enum-varnames": [
+                            "FileQueryClassExpireLessThen60Days"
+                        ],
+                        "name": "queryClass",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/response.ListResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/model.File"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/file/update": {
+            "put": {
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "闄勪欢绠$悊"
+                ],
+                "summary": "鏇存柊闄勪欢",
+                "parameters": [
+                    {
+                        "description": "鏌ヨ鍙傛暟",
+                        "name": "object",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/request.UpdateFile"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/contextx.Response"
+                        }
+                    }
+                }
+            }
+        },
         "/api/followRecord/add": {
             "post": {
                 "produces": [
@@ -8596,6 +8759,24 @@
                 "FaqQueryClassExpireLessThen60Days"
             ]
         },
+        "constvar.FileKeywordType": {
+            "type": "string",
+            "enum": [
+                ""
+            ],
+            "x-enum-varnames": [
+                "FileKeywordCustomerName"
+            ]
+        },
+        "constvar.FileQueryClass": {
+            "type": "string",
+            "enum": [
+                ""
+            ],
+            "x-enum-varnames": [
+                "FileQueryClassExpireLessThen60Days"
+            ]
+        },
         "constvar.PaymentTypeKeywordType": {
             "type": "string",
             "enum": [
@@ -9297,6 +9478,64 @@
                     "type": "integer"
                 },
                 "name": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.File": {
+            "type": "object",
+            "properties": {
+                "bucket": {
+                    "description": "瀵硅薄瀛樺偍bucket",
+                    "type": "string"
+                },
+                "content": {
+                    "description": "鏂囦欢鍐呭",
+                    "type": "string"
+                },
+                "createTime": {
+                    "description": "鍒涘缓鏃堕棿",
+                    "type": "string"
+                },
+                "downloadCount": {
+                    "description": "涓嬫娆℃暟",
+                    "type": "integer"
+                },
+                "filePath": {
+                    "description": "鏂囦欢璺緞",
+                    "type": "string"
+                },
+                "fileType": {
+                    "description": "鏂囦欢绫诲瀷",
+                    "type": "string"
+                },
+                "id": {
+                    "type": "integer"
+                },
+                "key": {
+                    "description": "瀵硅薄瀛樺偍key",
+                    "type": "string"
+                },
+                "name": {
+                    "type": "string"
+                },
+                "previewCount": {
+                    "description": "棰勮娆℃暟",
+                    "type": "integer"
+                },
+                "size": {
+                    "description": "鏂囦欢澶у皬",
+                    "type": "integer"
+                },
+                "sourceId": {
+                    "description": "鏉ユ簮id",
+                    "type": "integer"
+                },
+                "sourceType": {
+                    "description": "闄勪欢鏉ユ簮",
+                    "type": "string"
+                },
+                "updateTime": {
                     "type": "string"
                 }
             }
@@ -11027,6 +11266,23 @@
                     "type": "integer"
                 },
                 "name": {
+                    "type": "string"
+                }
+            }
+        },
+        "request.AddFile": {
+            "type": "object",
+            "required": [
+                "sourceId",
+                "sourceType"
+            ],
+            "properties": {
+                "sourceId": {
+                    "description": "鏉ユ簮id",
+                    "type": "integer"
+                },
+                "sourceType": {
+                    "description": "闄勪欢鏉ユ簮",
                     "type": "string"
                 }
             }
@@ -13402,6 +13658,64 @@
                 }
             }
         },
+        "request.UpdateFile": {
+            "type": "object",
+            "properties": {
+                "bucket": {
+                    "description": "瀵硅薄瀛樺偍bucket",
+                    "type": "string"
+                },
+                "content": {
+                    "description": "鏂囦欢鍐呭",
+                    "type": "string"
+                },
+                "createTime": {
+                    "description": "鍒涘缓鏃堕棿",
+                    "type": "string"
+                },
+                "downloadCount": {
+                    "description": "涓嬫娆℃暟",
+                    "type": "integer"
+                },
+                "filePath": {
+                    "description": "鏂囦欢璺緞",
+                    "type": "string"
+                },
+                "fileType": {
+                    "description": "鏂囦欢绫诲瀷",
+                    "type": "string"
+                },
+                "id": {
+                    "type": "integer"
+                },
+                "key": {
+                    "description": "瀵硅薄瀛樺偍key",
+                    "type": "string"
+                },
+                "name": {
+                    "type": "string"
+                },
+                "previewCount": {
+                    "description": "棰勮娆℃暟",
+                    "type": "integer"
+                },
+                "size": {
+                    "description": "鏂囦欢澶у皬",
+                    "type": "integer"
+                },
+                "sourceId": {
+                    "description": "鏉ユ簮id",
+                    "type": "integer"
+                },
+                "sourceType": {
+                    "description": "闄勪欢鏉ユ簮",
+                    "type": "string"
+                },
+                "updateTime": {
+                    "type": "string"
+                }
+            }
+        },
         "request.UpdateFollowRecord": {
             "type": "object",
             "required": [
diff --git a/docs/swagger.json b/docs/swagger.json
index 67562ee..7209ba5 100644
--- a/docs/swagger.json
+++ b/docs/swagger.json
@@ -2480,6 +2480,169 @@
                 }
             }
         },
+        "/api/file/add": {
+            "post": {
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "闄勪欢绠$悊"
+                ],
+                "summary": "娣诲姞闄勪欢",
+                "parameters": [
+                    {
+                        "description": "鏌ヨ鍙傛暟",
+                        "name": "object",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/request.AddFile"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/contextx.Response"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/file/delete/{id}": {
+            "delete": {
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "闄勪欢绠$悊"
+                ],
+                "summary": "鍒犻櫎闄勪欢",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "鏌ヨ鍙傛暟",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/contextx.Response"
+                        }
+                    }
+                }
+            }
+        },
+        "/api/file/list": {
+            "get": {
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "闄勪欢绠$悊"
+                ],
+                "summary": "鑾峰彇闄勪欢鍒楄〃",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "name": "keyword",
+                        "in": "query"
+                    },
+                    {
+                        "enum": [
+                            ""
+                        ],
+                        "type": "string",
+                        "x-enum-varnames": [
+                            "FileKeywordCustomerName"
+                        ],
+                        "name": "keywordType",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "椤电爜",
+                        "name": "page",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "姣忛〉澶у皬",
+                        "name": "pageSize",
+                        "in": "query"
+                    },
+                    {
+                        "enum": [
+                            ""
+                        ],
+                        "type": "string",
+                        "x-enum-varnames": [
+                            "FileQueryClassExpireLessThen60Days"
+                        ],
+                        "name": "queryClass",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/response.ListResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/model.File"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/api/file/update": {
+            "put": {
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "闄勪欢绠$悊"
+                ],
+                "summary": "鏇存柊闄勪欢",
+                "parameters": [
+                    {
+                        "description": "鏌ヨ鍙傛暟",
+                        "name": "object",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/request.UpdateFile"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/contextx.Response"
+                        }
+                    }
+                }
+            }
+        },
         "/api/followRecord/add": {
             "post": {
                 "produces": [
@@ -8584,6 +8747,24 @@
                 "FaqQueryClassExpireLessThen60Days"
             ]
         },
+        "constvar.FileKeywordType": {
+            "type": "string",
+            "enum": [
+                ""
+            ],
+            "x-enum-varnames": [
+                "FileKeywordCustomerName"
+            ]
+        },
+        "constvar.FileQueryClass": {
+            "type": "string",
+            "enum": [
+                ""
+            ],
+            "x-enum-varnames": [
+                "FileQueryClassExpireLessThen60Days"
+            ]
+        },
         "constvar.PaymentTypeKeywordType": {
             "type": "string",
             "enum": [
@@ -9285,6 +9466,64 @@
                     "type": "integer"
                 },
                 "name": {
+                    "type": "string"
+                }
+            }
+        },
+        "model.File": {
+            "type": "object",
+            "properties": {
+                "bucket": {
+                    "description": "瀵硅薄瀛樺偍bucket",
+                    "type": "string"
+                },
+                "content": {
+                    "description": "鏂囦欢鍐呭",
+                    "type": "string"
+                },
+                "createTime": {
+                    "description": "鍒涘缓鏃堕棿",
+                    "type": "string"
+                },
+                "downloadCount": {
+                    "description": "涓嬫娆℃暟",
+                    "type": "integer"
+                },
+                "filePath": {
+                    "description": "鏂囦欢璺緞",
+                    "type": "string"
+                },
+                "fileType": {
+                    "description": "鏂囦欢绫诲瀷",
+                    "type": "string"
+                },
+                "id": {
+                    "type": "integer"
+                },
+                "key": {
+                    "description": "瀵硅薄瀛樺偍key",
+                    "type": "string"
+                },
+                "name": {
+                    "type": "string"
+                },
+                "previewCount": {
+                    "description": "棰勮娆℃暟",
+                    "type": "integer"
+                },
+                "size": {
+                    "description": "鏂囦欢澶у皬",
+                    "type": "integer"
+                },
+                "sourceId": {
+                    "description": "鏉ユ簮id",
+                    "type": "integer"
+                },
+                "sourceType": {
+                    "description": "闄勪欢鏉ユ簮",
+                    "type": "string"
+                },
+                "updateTime": {
                     "type": "string"
                 }
             }
@@ -11015,6 +11254,23 @@
                     "type": "integer"
                 },
                 "name": {
+                    "type": "string"
+                }
+            }
+        },
+        "request.AddFile": {
+            "type": "object",
+            "required": [
+                "sourceId",
+                "sourceType"
+            ],
+            "properties": {
+                "sourceId": {
+                    "description": "鏉ユ簮id",
+                    "type": "integer"
+                },
+                "sourceType": {
+                    "description": "闄勪欢鏉ユ簮",
                     "type": "string"
                 }
             }
@@ -13390,6 +13646,64 @@
                 }
             }
         },
+        "request.UpdateFile": {
+            "type": "object",
+            "properties": {
+                "bucket": {
+                    "description": "瀵硅薄瀛樺偍bucket",
+                    "type": "string"
+                },
+                "content": {
+                    "description": "鏂囦欢鍐呭",
+                    "type": "string"
+                },
+                "createTime": {
+                    "description": "鍒涘缓鏃堕棿",
+                    "type": "string"
+                },
+                "downloadCount": {
+                    "description": "涓嬫娆℃暟",
+                    "type": "integer"
+                },
+                "filePath": {
+                    "description": "鏂囦欢璺緞",
+                    "type": "string"
+                },
+                "fileType": {
+                    "description": "鏂囦欢绫诲瀷",
+                    "type": "string"
+                },
+                "id": {
+                    "type": "integer"
+                },
+                "key": {
+                    "description": "瀵硅薄瀛樺偍key",
+                    "type": "string"
+                },
+                "name": {
+                    "type": "string"
+                },
+                "previewCount": {
+                    "description": "棰勮娆℃暟",
+                    "type": "integer"
+                },
+                "size": {
+                    "description": "鏂囦欢澶у皬",
+                    "type": "integer"
+                },
+                "sourceId": {
+                    "description": "鏉ユ簮id",
+                    "type": "integer"
+                },
+                "sourceType": {
+                    "description": "闄勪欢鏉ユ簮",
+                    "type": "string"
+                },
+                "updateTime": {
+                    "type": "string"
+                }
+            }
+        },
         "request.UpdateFollowRecord": {
             "type": "object",
             "required": [
diff --git a/docs/swagger.yaml b/docs/swagger.yaml
index c8dcd43..5bb4c66 100644
--- a/docs/swagger.yaml
+++ b/docs/swagger.yaml
@@ -23,6 +23,18 @@
     type: string
     x-enum-varnames:
     - FaqQueryClassExpireLessThen60Days
+  constvar.FileKeywordType:
+    enum:
+    - ""
+    type: string
+    x-enum-varnames:
+    - FileKeywordCustomerName
+  constvar.FileQueryClass:
+    enum:
+    - ""
+    type: string
+    x-enum-varnames:
+    - FileQueryClassExpireLessThen60Days
   constvar.PaymentTypeKeywordType:
     enum:
     - ""
@@ -512,6 +524,48 @@
       id:
         type: integer
       name:
+        type: string
+    type: object
+  model.File:
+    properties:
+      bucket:
+        description: 瀵硅薄瀛樺偍bucket
+        type: string
+      content:
+        description: 鏂囦欢鍐呭
+        type: string
+      createTime:
+        description: 鍒涘缓鏃堕棿
+        type: string
+      downloadCount:
+        description: 涓嬫娆℃暟
+        type: integer
+      filePath:
+        description: 鏂囦欢璺緞
+        type: string
+      fileType:
+        description: 鏂囦欢绫诲瀷
+        type: string
+      id:
+        type: integer
+      key:
+        description: 瀵硅薄瀛樺偍key
+        type: string
+      name:
+        type: string
+      previewCount:
+        description: 棰勮娆℃暟
+        type: integer
+      size:
+        description: 鏂囦欢澶у皬
+        type: integer
+      sourceId:
+        description: 鏉ユ簮id
+        type: integer
+      sourceType:
+        description: 闄勪欢鏉ユ簮
+        type: string
+      updateTime:
         type: string
     type: object
   model.FollowRecord:
@@ -1673,6 +1727,18 @@
         type: integer
       name:
         type: string
+    type: object
+  request.AddFile:
+    properties:
+      sourceId:
+        description: 鏉ユ簮id
+        type: integer
+      sourceType:
+        description: 闄勪欢鏉ユ簮
+        type: string
+    required:
+    - sourceId
+    - sourceType
     type: object
   request.AddFollowRecord:
     properties:
@@ -3281,6 +3347,48 @@
       id:
         type: integer
       name:
+        type: string
+    type: object
+  request.UpdateFile:
+    properties:
+      bucket:
+        description: 瀵硅薄瀛樺偍bucket
+        type: string
+      content:
+        description: 鏂囦欢鍐呭
+        type: string
+      createTime:
+        description: 鍒涘缓鏃堕棿
+        type: string
+      downloadCount:
+        description: 涓嬫娆℃暟
+        type: integer
+      filePath:
+        description: 鏂囦欢璺緞
+        type: string
+      fileType:
+        description: 鏂囦欢绫诲瀷
+        type: string
+      id:
+        type: integer
+      key:
+        description: 瀵硅薄瀛樺偍key
+        type: string
+      name:
+        type: string
+      previewCount:
+        description: 棰勮娆℃暟
+        type: integer
+      size:
+        description: 鏂囦欢澶у皬
+        type: integer
+      sourceId:
+        description: 鏉ユ簮id
+        type: integer
+      sourceType:
+        description: 闄勪欢鏉ユ簮
+        type: string
+      updateTime:
         type: string
     type: object
   request.UpdateFollowRecord:
@@ -6401,6 +6509,107 @@
       summary: 鏇存柊鏁呴殰绫诲埆
       tags:
       - 鏁呴殰绫诲埆绠$悊
+  /api/file/add:
+    post:
+      parameters:
+      - description: 鏌ヨ鍙傛暟
+        in: body
+        name: object
+        required: true
+        schema:
+          $ref: '#/definitions/request.AddFile'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/contextx.Response'
+      summary: 娣诲姞闄勪欢
+      tags:
+      - 闄勪欢绠$悊
+  /api/file/delete/{id}:
+    delete:
+      parameters:
+      - description: 鏌ヨ鍙傛暟
+        in: path
+        name: id
+        required: true
+        type: integer
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/contextx.Response'
+      summary: 鍒犻櫎闄勪欢
+      tags:
+      - 闄勪欢绠$悊
+  /api/file/list:
+    get:
+      parameters:
+      - in: query
+        name: keyword
+        type: string
+      - enum:
+        - ""
+        in: query
+        name: keywordType
+        type: string
+        x-enum-varnames:
+        - FileKeywordCustomerName
+      - description: 椤电爜
+        in: query
+        name: page
+        type: integer
+      - description: 姣忛〉澶у皬
+        in: query
+        name: pageSize
+        type: integer
+      - enum:
+        - ""
+        in: query
+        name: queryClass
+        type: string
+        x-enum-varnames:
+        - FileQueryClassExpireLessThen60Days
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/response.ListResponse'
+            - properties:
+                data:
+                  items:
+                    $ref: '#/definitions/model.File'
+                  type: array
+              type: object
+      summary: 鑾峰彇闄勪欢鍒楄〃
+      tags:
+      - 闄勪欢绠$悊
+  /api/file/update:
+    put:
+      parameters:
+      - description: 鏌ヨ鍙傛暟
+        in: body
+        name: object
+        required: true
+        schema:
+          $ref: '#/definitions/request.UpdateFile'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/contextx.Response'
+      summary: 鏇存柊闄勪欢
+      tags:
+      - 闄勪欢绠$悊
   /api/followRecord/add:
     post:
       parameters:
diff --git a/go.mod b/go.mod
index 4cd97d5..99e593f 100644
--- a/go.mod
+++ b/go.mod
@@ -36,6 +36,8 @@
 require (
 	github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect
 	github.com/KyleBanks/depth v1.2.1 // indirect
+	github.com/aliyun/aliyun-oss-go-sdk v2.1.6+incompatible // indirect
+	github.com/aws/aws-sdk-go v1.42.27 // indirect
 	github.com/bytedance/sonic v1.9.1 // indirect
 	github.com/cespare/xxhash/v2 v2.2.0 // indirect
 	github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
@@ -49,6 +51,7 @@
 	github.com/gin-contrib/sse v0.1.0 // indirect
 	github.com/glebarez/go-sqlite v1.21.1 // indirect
 	github.com/glebarez/sqlite v1.8.0 // indirect
+	github.com/go-ole/go-ole v1.2.6 // indirect
 	github.com/go-openapi/jsonpointer v0.19.6 // indirect
 	github.com/go-openapi/jsonreference v0.20.2 // indirect
 	github.com/go-openapi/spec v0.20.9 // indirect
@@ -62,17 +65,21 @@
 	github.com/golang-sql/sqlexp v0.1.0 // indirect
 	github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
 	github.com/golang/protobuf v1.5.3 // indirect
+	github.com/google/go-querystring v1.0.0 // indirect
 	github.com/google/uuid v1.3.0 // indirect
 	github.com/hashicorp/hcl v1.0.0 // indirect
+	github.com/huaweicloud/huaweicloud-sdk-go-obs v3.21.8+incompatible // indirect
 	github.com/jackc/pgpassfile v1.0.0 // indirect
 	github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
 	github.com/jackc/pgx/v5 v5.3.1 // indirect
 	github.com/jinzhu/inflection v1.0.0 // indirect
 	github.com/jinzhu/now v1.1.5 // indirect
+	github.com/jmespath/go-jmespath v0.4.0 // indirect
 	github.com/josharian/intern v1.0.0 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
 	github.com/klauspost/cpuid/v2 v2.2.4 // indirect
 	github.com/leodido/go-urn v1.2.4 // indirect
+	github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
 	github.com/magiconair/properties v1.8.7 // indirect
 	github.com/mailru/easyjson v0.7.7 // indirect
 	github.com/mattn/go-isatty v0.0.19 // indirect
@@ -80,18 +87,26 @@
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
+	github.com/mozillazg/go-httpheader v0.2.1 // indirect
 	github.com/onsi/gomega v1.27.4 // indirect
 	github.com/pelletier/go-toml/v2 v2.0.8 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
+	github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
+	github.com/qiniu/api.v7/v7 v7.4.1 // indirect
 	github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
 	github.com/rogpeppe/go-internal v1.10.0 // indirect
+	github.com/shirou/gopsutil/v3 v3.22.5 // indirect
 	github.com/spf13/afero v1.9.5 // indirect
 	github.com/spf13/cast v1.5.1 // indirect
 	github.com/spf13/jwalterweatherman v1.1.0 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
 	github.com/subosito/gotenv v1.4.2 // indirect
+	github.com/tencentyun/cos-go-sdk-v5 v0.7.19 // indirect
+	github.com/tklauser/go-sysconf v0.3.10 // indirect
+	github.com/tklauser/numcpus v0.4.0 // indirect
 	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
 	github.com/ugorji/go/codec v1.2.11 // indirect
+	github.com/yusufpapurcu/wmi v1.2.2 // indirect
 	go.etcd.io/etcd/api/v3 v3.5.9 // indirect
 	go.uber.org/atomic v1.9.0 // indirect
 	go.uber.org/multierr v1.8.0 // indirect
@@ -100,6 +115,7 @@
 	golang.org/x/net v0.10.0 // indirect
 	golang.org/x/sys v0.9.0 // indirect
 	golang.org/x/text v0.10.0 // indirect
+	golang.org/x/time v0.1.0 // indirect
 	golang.org/x/tools v0.9.1 // indirect
 	google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
 	google.golang.org/grpc v1.55.0 // indirect
diff --git a/go.sum b/go.sum
index f066a4c..9a0e61d 100644
--- a/go.sum
+++ b/go.sum
@@ -50,6 +50,12 @@
 github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
 github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
 github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
+github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM=
+github.com/aliyun/aliyun-oss-go-sdk v2.1.6+incompatible h1:Ft+KeWIJxFP76LqgJbvtOA1qBIoC8vGkTV3QeCOeJC4=
+github.com/aliyun/aliyun-oss-go-sdk v2.1.6+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
+github.com/aws/aws-sdk-go v1.42.27 h1:kxsBXQg3ee6LLbqjp5/oUeDgG7TENFrWYDmEVnd7spU=
+github.com/aws/aws-sdk-go v1.42.27/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc=
+github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA=
 github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
 github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
 github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
@@ -125,6 +131,8 @@
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
 github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
+github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
+github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
 github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
 github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
 github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
@@ -219,7 +227,11 @@
 github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
+github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
 github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@@ -236,6 +248,7 @@
 github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
 github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -252,6 +265,8 @@
 github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/huaweicloud/huaweicloud-sdk-go-obs v3.21.8+incompatible h1:3kDd8PIWAdU+qGs/+0QUgsMI2ZSiJPt45Xn0su+x/Q0=
+github.com/huaweicloud/huaweicloud-sdk-go-obs v3.21.8+incompatible/go.mod h1:l7VUhRbTKCzdOacdT4oWCwATKyvZqUOlOqr0Ous3k4s=
 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
@@ -309,6 +324,10 @@
 github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
 github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
 github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
+github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
 github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
 github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
 github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
@@ -342,6 +361,8 @@
 github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
 github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
 github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
+github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
 github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
 github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
 github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@@ -371,6 +392,8 @@
 github.com/mojocn/base64Captcha v1.3.5 h1:Qeilr7Ta6eDtG4S+tQuZ5+hO+QHbiGAJdi4PfoagaA0=
 github.com/mojocn/base64Captcha v1.3.5/go.mod h1:/tTTXn4WTpX9CfrmipqRytCpJ27Uw3G6I7NcP2WwcmY=
 github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
+github.com/mozillazg/go-httpheader v0.2.1 h1:geV7TrjbL8KXSyvghnFm+NyTux/hxwueTSrwhe88TQQ=
+github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
 github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
@@ -388,7 +411,11 @@
 github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
+github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/qiniu/api.v7/v7 v7.4.1 h1:BnNUBimLk6nrA/mIwsww9yJRupmViSsb1ndLMC7a9OY=
+github.com/qiniu/api.v7/v7 v7.4.1/go.mod h1:VE5oC5rkE1xul0u1S2N0b2Uxq9/6hZzhyqjgK25XDcM=
 github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
 github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
 github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
@@ -402,7 +429,10 @@
 github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
 github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
 github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
+github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
 github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/shirou/gopsutil/v3 v3.22.5 h1:atX36I/IXgFiB81687vSiBI5zrMsxcIBkP9cQMJQoJA=
+github.com/shirou/gopsutil/v3 v3.22.5/go.mod h1:so9G9VzeHt/hsd0YwqprnjHnfARAUktauykSbr+y2gA=
 github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
 github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
 github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
@@ -445,6 +475,12 @@
 github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo=
 github.com/swaggo/swag v1.16.1 h1:fTNRhKstPKxcnoKsytm4sahr8FaYzUcT7i1/3nd/fBg=
 github.com/swaggo/swag v1.16.1/go.mod h1:9/LMvHycG3NFHfR6LwvikHv5iFvmPADQ359cKikGxto=
+github.com/tencentyun/cos-go-sdk-v5 v0.7.19 h1:janAfTO4MglOrUFuKGTQJBuMc66+F7TgtEIt1wPsJ+k=
+github.com/tencentyun/cos-go-sdk-v5 v0.7.19/go.mod h1:wQBO5HdAkLjj2q6XQiIfDSP8DXDNrppDRw2Kp/1BODA=
+github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw=
+github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
+github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o=
+github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
 github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
 github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
 github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
@@ -457,6 +493,8 @@
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
+github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
 github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
 go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs=
 go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k=
@@ -591,6 +629,7 @@
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
@@ -635,6 +674,7 @@
 golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -658,6 +698,7 @@
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -671,6 +712,7 @@
 golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -704,6 +746,8 @@
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
+golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
diff --git a/model/file.go b/model/file.go
new file mode 100644
index 0000000..3b919f3
--- /dev/null
+++ b/model/file.go
@@ -0,0 +1,152 @@
+package model
+
+import (
+	"aps_crm/constvar"
+	"aps_crm/pkg/mysqlx"
+	"errors"
+	"fmt"
+	"gorm.io/gorm"
+)
+
+type (
+	// File 闄勪欢
+	File struct {
+		Id            int    `json:"id" gorm:"column:id;primary_key;AUTO_INCREMENT"`
+		Name          string `gorm:"name" json:"name"`
+		Size          int64  `gorm:"size" json:"size"`                    // 鏂囦欢澶у皬
+		FilePath      string `gorm:"file_path" json:"filePath"`           // 鏂囦欢璺緞
+		Key           string `gorm:"key" json:"key"`                      // 瀵硅薄瀛樺偍key
+		Bucket        string `gorm:"bucket" json:"bucket"`                // 瀵硅薄瀛樺偍bucket
+		DownloadCount int    `gorm:"download_count" json:"downloadCount"` // 涓嬫娆℃暟
+		PreviewCount  int    `gorm:"preview_count" json:"previewCount"`   // 棰勮娆℃暟
+		FileType      string `gorm:"file_type" json:"fileType"`           // 鏂囦欢绫诲瀷
+		SourceType    string `gorm:"source_type" json:"sourceType"`       // 闄勪欢鏉ユ簮
+		SourceId      int    `gorm:"source_id" json:"sourceId"`           // 鏉ユ簮id
+		CreateTime    string `gorm:"create_time" json:"createTime"`       // 鍒涘缓鏃堕棿
+		UpdateTime    string `gorm:"update_time" json:"updateTime"`
+		Content       string `gorm:"content" json:"content"` // 鏂囦欢鍐呭
+	}
+
+	// FileSearch 闄勪欢鎼滅储鏉′欢
+	FileSearch struct {
+		File
+		Orm         *gorm.DB
+		QueryClass  constvar.FileQueryClass
+		KeywordType constvar.FileKeywordType
+		Keyword     string
+		PageNum     int
+		PageSize    int
+	}
+)
+
+func (File) TableName() string {
+	return "file"
+}
+
+func NewFileSearch() *FileSearch {
+	return &FileSearch{
+		Orm: mysqlx.GetDB(),
+	}
+}
+
+func (slf *FileSearch) build() *gorm.DB {
+	var db = slf.Orm.Model(&File{})
+	if slf.Id != 0 {
+		db = db.Where("id = ?", slf.Id)
+	}
+
+	return db
+}
+
+func (slf *FileSearch) Create(record *File) error {
+	var db = slf.build()
+	return db.Create(record).Error
+}
+
+func (slf *FileSearch) CreateBatch(records []*File) error {
+	var db = slf.build()
+	return db.Create(records).Error
+}
+
+func (slf *FileSearch) Delete() error {
+	var db = slf.build()
+	return db.Delete(&File{}).Error
+}
+
+func (slf *FileSearch) Update(record *File) error {
+	var db = slf.build()
+	return db.Updates(record).Error
+}
+
+func (slf *FileSearch) FindAll() ([]*File, error) {
+	var db = slf.build()
+	var record = make([]*File, 0)
+	err := db.Find(&record).Error
+	return record, err
+}
+
+func (slf *FileSearch) SetId(id int) *FileSearch {
+	slf.Id = id
+	return slf
+}
+
+func (slf *FileSearch) SetOrm(tx *gorm.DB) *FileSearch {
+	slf.Orm = tx
+	return slf
+}
+
+func (slf *FileSearch) First() (*File, error) {
+	var db = slf.build()
+	var record = new(File)
+	err := db.First(record).Error
+	return record, err
+}
+
+func (slf *FileSearch) Updates(values interface{}) error {
+	var db = slf.build()
+	return db.Updates(values).Error
+}
+
+func (slf *FileSearch) Save(record *File) error {
+	if record.Id == 0 {
+		return errors.New("id涓虹┖")
+	}
+	var db = slf.build()
+
+	if err := db.Save(record).Error; err != nil {
+		return fmt.Errorf("save err: %v, record: %+v", err, record)
+	}
+
+	return nil
+}
+
+func (slf *FileSearch) Find() ([]*File, int64, error) {
+	var db = slf.build()
+	var records = make([]*File, 0)
+	var total int64
+	if err := db.Count(&total).Error; err != nil {
+		return records, total, err
+	}
+	if slf.PageNum > 0 && slf.PageSize > 0 {
+		db = db.Limit(slf.PageSize).Offset((slf.PageNum - 1) * slf.PageSize)
+	}
+
+	err := db.Find(&records).Error
+	return records, total, err
+}
+
+// InitDefaultData 鍒濆鍖栨暟鎹�
+func (slf *FileSearch) InitDefaultData() error {
+	var (
+		db          = slf.Orm.Table(slf.TableName())
+		total int64 = 0
+	)
+	if err := db.Count(&total).Error; err != nil {
+		return err
+	}
+	if total != 0 {
+		return nil
+	}
+	records := []*File{}
+	return slf.CreateBatch(records)
+}
diff --git a/model/request/file.go b/model/request/file.go
new file mode 100644
index 0000000..5b17b6b
--- /dev/null
+++ b/model/request/file.go
@@ -0,0 +1,23 @@
+package request
+
+import (
+	"aps_crm/constvar"
+	"aps_crm/model"
+)
+
+type AddFile struct {
+	SourceType string `gorm:"source_type" json:"sourceType" form:"sourceType" binding:"required"` // 闄勪欢鏉ユ簮
+	SourceId   int    `gorm:"source_id" json:"sourceId" form:"sourceId"  binding:"required"`      // 鏉ユ簮id
+}
+
+type UpdateFile struct {
+	Id int `json:"id"`
+	model.File
+}
+
+type GetFileList struct {
+	PageInfo
+	QueryClass  constvar.FileQueryClass  `json:"queryClass" form:"queryClass"`
+	KeywordType constvar.FileKeywordType `json:"keywordType"  form:"keywordType"`
+	Keyword     string                   `json:"keyword" form:"keyword"`
+}
diff --git a/pkg/contextx/contextx.go b/pkg/contextx/contextx.go
index b338e79..adc828f 100644
--- a/pkg/contextx/contextx.go
+++ b/pkg/contextx/contextx.go
@@ -83,6 +83,10 @@
 	slf.Result(errCode, map[string]interface{}{}, ecode.GetMsg(errCode))
 }
 
+func (slf *Context) FailWithMsg(errCode int, msg string) {
+	slf.Result(errCode, map[string]interface{}{}, msg)
+}
+
 func (slf *Context) FailWithDetailed(errCode int, data interface{}) {
 	slf.Result(errCode, data, ecode.GetMsg(errCode))
 }
diff --git a/pkg/httpx/httpx.go b/pkg/httpx/httpx.go
index 4e286fe..c62d52e 100644
--- a/pkg/httpx/httpx.go
+++ b/pkg/httpx/httpx.go
@@ -5,6 +5,7 @@
 	"encoding/json"
 	"io/ioutil"
 	"net/http"
+	"os"
 	"time"
 )
 
@@ -39,3 +40,16 @@
 	}
 	return respBytes, nil
 }
+
+func GetMimeType(filePath string) string {
+	file, err := os.Open(filePath)
+	if err != nil {
+		return ""
+	}
+	buffer := make([]byte, 512)
+	_, _ = file.Read(buffer)
+	if len(buffer) == 0 {
+		return ""
+	}
+	return http.DetectContentType(buffer)
+}
diff --git a/router/file.go b/router/file.go
new file mode 100644
index 0000000..60757b4
--- /dev/null
+++ b/router/file.go
@@ -0,0 +1,15 @@
+package router
+
+import (
+	v1 "aps_crm/api/v1"
+	"github.com/gin-gonic/gin"
+)
+
+func InitFileRouter(router *gin.RouterGroup) {
+	FileRouter := router.Group("file")
+	FileApi := v1.FileApi{}
+	{
+		FileRouter.POST("add", FileApi.Add)             // 娣诲姞闄勪欢
+		FileRouter.DELETE("delete/:id", FileApi.Delete) // 鍒犻櫎闄勪欢
+	}
+}
diff --git a/router/index.go b/router/index.go
index 386f3c8..001dd00 100644
--- a/router/index.go
+++ b/router/index.go
@@ -170,6 +170,7 @@
 		InitReceiptRouter(PrivateGroup)
 		InitBankAccountRouter(PrivateGroup)
 		InitPaymentTypeRouter(PrivateGroup)
+		InitFileRouter(PrivateGroup)
 	}
 	return Router
 }
diff --git a/service/file.go b/service/file.go
new file mode 100644
index 0000000..af78875
--- /dev/null
+++ b/service/file.go
@@ -0,0 +1,65 @@
+package service
+
+import (
+	"aps_crm/model"
+	"aps_crm/model/request"
+	"aps_crm/pkg/ecode"
+)
+
+type FileService struct{}
+
+func NewFileService() FileService {
+	return FileService{}
+}
+
+func (FileService) AddFile(fileRecord *model.File) int {
+
+	err := model.NewFileSearch().Create(fileRecord)
+	if err != nil {
+		return ecode.DBErr
+	}
+
+	return ecode.OK
+}
+
+func (FileService) DeleteFile(id int) int {
+	err := model.NewFileSearch().SetId(id).Delete()
+	if err != nil {
+		return ecode.DBErr
+	}
+	return ecode.OK
+}
+
+func (FileService) GetFileList() ([]*model.File, int64, int) {
+	list, total, err := model.NewFileSearch().Find()
+	if err != nil {
+		return nil, 0, ecode.DBErr
+	}
+
+	return list, total, ecode.OK
+}
+
+func (FileService) UpdateFiles(Files []*request.UpdateFile) int {
+	for _, v := range Files {
+		// check File exist
+		_, err := model.NewFileSearch().SetId(v.Id).First()
+		if err != nil {
+			return ecode.DBErr
+		}
+
+		err = model.NewFileSearch().SetId(v.Id).Updates(map[string]interface{}{})
+		if err != nil {
+			return ecode.DBErr
+		}
+	}
+
+	return ecode.OK
+}
+
+func (FileService) UpdateFile(file *model.File) int {
+	err := model.NewFileSearch().SetId(file.Id).Save(file)
+	if err != nil {
+		return ecode.DBErr
+	}
+	return ecode.OK
+}

--
Gitblit v1.8.0