Explorar o código

文件上传修复

xu hai 10 meses
pai
achega
1ece2b4dc4

+ 3 - 1
server/api/v1/enter.go

@@ -1,11 +1,13 @@
 package v1
 
 import (
+	"github.com/flipped-aurora/gin-vue-admin/server/api/v1/example"
 	"github.com/flipped-aurora/gin-vue-admin/server/api/v1/system"
 )
 
 type ApiGroup struct {
-	SystemApiGroup system.ApiGroup
+	SystemApiGroup  system.ApiGroup
+	ExampleApiGroup example.ApiGroup
 }
 
 var ApiGroupApp = new(ApiGroup)

+ 13 - 0
server/api/v1/example/enter.go

@@ -0,0 +1,13 @@
+package example
+
+import "github.com/flipped-aurora/gin-vue-admin/server/service"
+
+type ApiGroup struct {
+	CustomerApi
+	FileUploadAndDownloadApi
+}
+
+var (
+	customerService              = service.ServiceGroupApp.ExampleServiceGroup.CustomerService
+	fileUploadAndDownloadService = service.ServiceGroupApp.ExampleServiceGroup.FileUploadAndDownloadService
+)

+ 150 - 0
server/api/v1/example/exa_breakpoint_continue.go

@@ -0,0 +1,150 @@
+package example
+
+import (
+	"fmt"
+	"io"
+	"mime/multipart"
+	"strconv"
+
+	"github.com/flipped-aurora/gin-vue-admin/server/model/example"
+
+	"github.com/flipped-aurora/gin-vue-admin/server/global"
+	"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
+	exampleRes "github.com/flipped-aurora/gin-vue-admin/server/model/example/response"
+	"github.com/flipped-aurora/gin-vue-admin/server/utils"
+	"github.com/gin-gonic/gin"
+	"go.uber.org/zap"
+)
+
+// BreakpointContinue
+// @Tags      ExaFileUploadAndDownload
+// @Summary   断点续传到服务器
+// @Security  ApiKeyAuth
+// @accept    multipart/form-data
+// @Produce   application/json
+// @Param     file  formData  file                           true  "an example for breakpoint resume, 断点续传示例"
+// @Success   200   {object}  response.Response{msg=string}  "断点续传到服务器"
+// @Router    /fileUploadAndDownload/breakpointContinue [post]
+func (b *FileUploadAndDownloadApi) BreakpointContinue(c *gin.Context) {
+	fileMd5 := c.Request.FormValue("fileMd5")
+	fileName := c.Request.FormValue("fileName")
+	chunkMd5 := c.Request.FormValue("chunkMd5")
+	chunkNumber, _ := strconv.Atoi(c.Request.FormValue("chunkNumber"))
+	chunkTotal, _ := strconv.Atoi(c.Request.FormValue("chunkTotal"))
+	_, FileHeader, err := c.Request.FormFile("file")
+	if err != nil {
+		global.GVA_LOG.Error("接收文件失败!", zap.Error(err))
+		response.FailWithMessage("接收文件失败", c)
+		return
+	}
+	f, err := FileHeader.Open()
+	if err != nil {
+		global.GVA_LOG.Error("文件读取失败!", zap.Error(err))
+		response.FailWithMessage("文件读取失败", c)
+		return
+	}
+	defer func(f multipart.File) {
+		err := f.Close()
+		if err != nil {
+			fmt.Println(err)
+		}
+	}(f)
+	cen, _ := io.ReadAll(f)
+	if !utils.CheckMd5(cen, chunkMd5) {
+		global.GVA_LOG.Error("检查md5失败!", zap.Error(err))
+		response.FailWithMessage("检查md5失败", c)
+		return
+	}
+	file, err := fileUploadAndDownloadService.FindOrCreateFile(fileMd5, fileName, chunkTotal)
+	if err != nil {
+		global.GVA_LOG.Error("查找或创建记录失败!", zap.Error(err))
+		response.FailWithMessage("查找或创建记录失败", c)
+		return
+	}
+	pathC, err := utils.BreakPointContinue(cen, fileName, chunkNumber, chunkTotal, fileMd5)
+	if err != nil {
+		global.GVA_LOG.Error("断点续传失败!", zap.Error(err))
+		response.FailWithMessage("断点续传失败", c)
+		return
+	}
+
+	if err = fileUploadAndDownloadService.CreateFileChunk(file.ID, pathC, chunkNumber); err != nil {
+		global.GVA_LOG.Error("创建文件记录失败!", zap.Error(err))
+		response.FailWithMessage("创建文件记录失败", c)
+		return
+	}
+	response.OkWithMessage("切片创建成功", c)
+}
+
+// FindFile
+// @Tags      ExaFileUploadAndDownload
+// @Summary   查找文件
+// @Security  ApiKeyAuth
+// @accept    multipart/form-data
+// @Produce   application/json
+// @Param     file  formData  file                                                        true  "Find the file, 查找文件"
+// @Success   200   {object}  response.Response{data=exampleRes.FileResponse,msg=string}  "查找文件,返回包括文件详情"
+// @Router    /fileUploadAndDownload/findFile [post]
+func (b *FileUploadAndDownloadApi) FindFile(c *gin.Context) {
+	fileMd5 := c.Query("fileMd5")
+	fileName := c.Query("fileName")
+	chunkTotal, _ := strconv.Atoi(c.Query("chunkTotal"))
+	file, err := fileUploadAndDownloadService.FindOrCreateFile(fileMd5, fileName, chunkTotal)
+	if err != nil {
+		global.GVA_LOG.Error("查找失败!", zap.Error(err))
+		response.FailWithMessage("查找失败", c)
+	} else {
+		response.OkWithDetailed(exampleRes.FileResponse{File: file}, "查找成功", c)
+	}
+}
+
+// BreakpointContinueFinish
+// @Tags      ExaFileUploadAndDownload
+// @Summary   创建文件
+// @Security  ApiKeyAuth
+// @accept    multipart/form-data
+// @Produce   application/json
+// @Param     file  formData  file                                                            true  "上传文件完成"
+// @Success   200   {object}  response.Response{data=exampleRes.FilePathResponse,msg=string}  "创建文件,返回包括文件路径"
+// @Router    /fileUploadAndDownload/findFile [post]
+func (b *FileUploadAndDownloadApi) BreakpointContinueFinish(c *gin.Context) {
+	fileMd5 := c.Query("fileMd5")
+	fileName := c.Query("fileName")
+	filePath, err := utils.MakeFile(fileName, fileMd5)
+	if err != nil {
+		global.GVA_LOG.Error("文件创建失败!", zap.Error(err))
+		response.FailWithDetailed(exampleRes.FilePathResponse{FilePath: filePath}, "文件创建失败", c)
+	} else {
+		response.OkWithDetailed(exampleRes.FilePathResponse{FilePath: filePath}, "文件创建成功", c)
+	}
+}
+
+// RemoveChunk
+// @Tags      ExaFileUploadAndDownload
+// @Summary   删除切片
+// @Security  ApiKeyAuth
+// @accept    multipart/form-data
+// @Produce   application/json
+// @Param     file  formData  file                           true  "删除缓存切片"
+// @Success   200   {object}  response.Response{msg=string}  "删除切片"
+// @Router    /fileUploadAndDownload/removeChunk [post]
+func (b *FileUploadAndDownloadApi) RemoveChunk(c *gin.Context) {
+	var file example.ExaFile
+	err := c.ShouldBindJSON(&file)
+	if err != nil {
+		response.FailWithMessage(err.Error(), c)
+		return
+	}
+	err = utils.RemoveChunk(file.FileMd5)
+	if err != nil {
+		global.GVA_LOG.Error("缓存切片删除失败!", zap.Error(err))
+		return
+	}
+	err = fileUploadAndDownloadService.DeleteFileChunk(file.FileMd5, file.FilePath)
+	if err != nil {
+		global.GVA_LOG.Error(err.Error(), zap.Error(err))
+		response.FailWithMessage(err.Error(), c)
+		return
+	}
+	response.OkWithMessage("缓存切片删除成功", c)
+}

+ 176 - 0
server/api/v1/example/exa_customer.go

@@ -0,0 +1,176 @@
+package example
+
+import (
+	"github.com/flipped-aurora/gin-vue-admin/server/global"
+	"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
+	"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
+	"github.com/flipped-aurora/gin-vue-admin/server/model/example"
+	exampleRes "github.com/flipped-aurora/gin-vue-admin/server/model/example/response"
+	"github.com/flipped-aurora/gin-vue-admin/server/utils"
+	"github.com/gin-gonic/gin"
+	"go.uber.org/zap"
+)
+
+type CustomerApi struct{}
+
+// CreateExaCustomer
+// @Tags      ExaCustomer
+// @Summary   创建客户
+// @Security  ApiKeyAuth
+// @accept    application/json
+// @Produce   application/json
+// @Param     data  body      example.ExaCustomer            true  "客户用户名, 客户手机号码"
+// @Success   200   {object}  response.Response{msg=string}  "创建客户"
+// @Router    /customer/customer [post]
+func (e *CustomerApi) CreateExaCustomer(c *gin.Context) {
+	var customer example.ExaCustomer
+	err := c.ShouldBindJSON(&customer)
+	if err != nil {
+		response.FailWithMessage(err.Error(), c)
+		return
+	}
+	err = utils.Verify(customer, utils.CustomerVerify)
+	if err != nil {
+		response.FailWithMessage(err.Error(), c)
+		return
+	}
+	customer.SysUserID = utils.GetUserID(c)
+	customer.SysUserAuthorityID = utils.GetUserAuthorityId(c)
+	err = customerService.CreateExaCustomer(customer)
+	if err != nil {
+		global.GVA_LOG.Error("创建失败!", zap.Error(err))
+		response.FailWithMessage("创建失败", c)
+		return
+	}
+	response.OkWithMessage("创建成功", c)
+}
+
+// DeleteExaCustomer
+// @Tags      ExaCustomer
+// @Summary   删除客户
+// @Security  ApiKeyAuth
+// @accept    application/json
+// @Produce   application/json
+// @Param     data  body      example.ExaCustomer            true  "客户ID"
+// @Success   200   {object}  response.Response{msg=string}  "删除客户"
+// @Router    /customer/customer [delete]
+func (e *CustomerApi) DeleteExaCustomer(c *gin.Context) {
+	var customer example.ExaCustomer
+	err := c.ShouldBindJSON(&customer)
+	if err != nil {
+		response.FailWithMessage(err.Error(), c)
+		return
+	}
+	err = utils.Verify(customer.GVA_MODEL, utils.IdVerify)
+	if err != nil {
+		response.FailWithMessage(err.Error(), c)
+		return
+	}
+	err = customerService.DeleteExaCustomer(customer)
+	if err != nil {
+		global.GVA_LOG.Error("删除失败!", zap.Error(err))
+		response.FailWithMessage("删除失败", c)
+		return
+	}
+	response.OkWithMessage("删除成功", c)
+}
+
+// UpdateExaCustomer
+// @Tags      ExaCustomer
+// @Summary   更新客户信息
+// @Security  ApiKeyAuth
+// @accept    application/json
+// @Produce   application/json
+// @Param     data  body      example.ExaCustomer            true  "客户ID, 客户信息"
+// @Success   200   {object}  response.Response{msg=string}  "更新客户信息"
+// @Router    /customer/customer [put]
+func (e *CustomerApi) UpdateExaCustomer(c *gin.Context) {
+	var customer example.ExaCustomer
+	err := c.ShouldBindJSON(&customer)
+	if err != nil {
+		response.FailWithMessage(err.Error(), c)
+		return
+	}
+	err = utils.Verify(customer.GVA_MODEL, utils.IdVerify)
+	if err != nil {
+		response.FailWithMessage(err.Error(), c)
+		return
+	}
+	err = utils.Verify(customer, utils.CustomerVerify)
+	if err != nil {
+		response.FailWithMessage(err.Error(), c)
+		return
+	}
+	err = customerService.UpdateExaCustomer(&customer)
+	if err != nil {
+		global.GVA_LOG.Error("更新失败!", zap.Error(err))
+		response.FailWithMessage("更新失败", c)
+		return
+	}
+	response.OkWithMessage("更新成功", c)
+}
+
+// GetExaCustomer
+// @Tags      ExaCustomer
+// @Summary   获取单一客户信息
+// @Security  ApiKeyAuth
+// @accept    application/json
+// @Produce   application/json
+// @Param     data  query     example.ExaCustomer                                                true  "客户ID"
+// @Success   200   {object}  response.Response{data=exampleRes.ExaCustomerResponse,msg=string}  "获取单一客户信息,返回包括客户详情"
+// @Router    /customer/customer [get]
+func (e *CustomerApi) GetExaCustomer(c *gin.Context) {
+	var customer example.ExaCustomer
+	err := c.ShouldBindQuery(&customer)
+	if err != nil {
+		response.FailWithMessage(err.Error(), c)
+		return
+	}
+	err = utils.Verify(customer.GVA_MODEL, utils.IdVerify)
+	if err != nil {
+		response.FailWithMessage(err.Error(), c)
+		return
+	}
+	data, err := customerService.GetExaCustomer(customer.ID)
+	if err != nil {
+		global.GVA_LOG.Error("获取失败!", zap.Error(err))
+		response.FailWithMessage("获取失败", c)
+		return
+	}
+	response.OkWithDetailed(exampleRes.ExaCustomerResponse{Customer: data}, "获取成功", c)
+}
+
+// GetExaCustomerList
+// @Tags      ExaCustomer
+// @Summary   分页获取权限客户列表
+// @Security  ApiKeyAuth
+// @accept    application/json
+// @Produce   application/json
+// @Param     data  query     request.PageInfo                                        true  "页码, 每页大小"
+// @Success   200   {object}  response.Response{data=response.PageResult,msg=string}  "分页获取权限客户列表,返回包括列表,总数,页码,每页数量"
+// @Router    /customer/customerList [get]
+func (e *CustomerApi) GetExaCustomerList(c *gin.Context) {
+	var pageInfo request.PageInfo
+	err := c.ShouldBindQuery(&pageInfo)
+	if err != nil {
+		response.FailWithMessage(err.Error(), c)
+		return
+	}
+	err = utils.Verify(pageInfo, utils.PageInfoVerify)
+	if err != nil {
+		response.FailWithMessage(err.Error(), c)
+		return
+	}
+	customerList, total, err := customerService.GetCustomerInfoList(utils.GetUserAuthorityId(c), pageInfo)
+	if err != nil {
+		global.GVA_LOG.Error("获取失败!", zap.Error(err))
+		response.FailWithMessage("获取失败"+err.Error(), c)
+		return
+	}
+	response.OkWithDetailed(response.PageResult{
+		List:     customerList,
+		Total:    total,
+		Page:     pageInfo.Page,
+		PageSize: pageInfo.PageSize,
+	}, "获取成功", c)
+}

+ 110 - 0
server/api/v1/example/exa_file_upload_download.go

@@ -0,0 +1,110 @@
+package example
+
+import (
+	"github.com/flipped-aurora/gin-vue-admin/server/global"
+	"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
+	"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
+	"github.com/flipped-aurora/gin-vue-admin/server/model/example"
+	exampleRes "github.com/flipped-aurora/gin-vue-admin/server/model/example/response"
+	"github.com/gin-gonic/gin"
+	"go.uber.org/zap"
+)
+
+type FileUploadAndDownloadApi struct{}
+
+// UploadFile
+// @Tags      ExaFileUploadAndDownload
+// @Summary   上传文件示例
+// @Security  ApiKeyAuth
+// @accept    multipart/form-data
+// @Produce   application/json
+// @Param     file  formData  file                                                           true  "上传文件示例"
+// @Success   200   {object}  response.Response{data=exampleRes.ExaFileResponse,msg=string}  "上传文件示例,返回包括文件详情"
+// @Router    /fileUploadAndDownload/upload [post]
+func (b *FileUploadAndDownloadApi) UploadFile(c *gin.Context) {
+	var file example.ExaFileUploadAndDownload
+	noSave := c.DefaultQuery("noSave", "0")
+	_, header, err := c.Request.FormFile("file")
+	if err != nil {
+		global.GVA_LOG.Error("接收文件失败!", zap.Error(err))
+		response.FailWithMessage("接收文件失败", c)
+		return
+	}
+	file, err = fileUploadAndDownloadService.UploadFile(header, noSave) // 文件上传后拿到文件路径
+	if err != nil {
+		global.GVA_LOG.Error("修改数据库链接失败!", zap.Error(err))
+		response.FailWithMessage("修改数据库链接失败", c)
+		return
+	}
+	response.OkWithDetailed(exampleRes.ExaFileResponse{File: file}, "上传成功", c)
+}
+
+// EditFileName 编辑文件名或者备注
+func (b *FileUploadAndDownloadApi) EditFileName(c *gin.Context) {
+	var file example.ExaFileUploadAndDownload
+	err := c.ShouldBindJSON(&file)
+	if err != nil {
+		response.FailWithMessage(err.Error(), c)
+		return
+	}
+	err = fileUploadAndDownloadService.EditFileName(file)
+	if err != nil {
+		global.GVA_LOG.Error("编辑失败!", zap.Error(err))
+		response.FailWithMessage("编辑失败", c)
+		return
+	}
+	response.OkWithMessage("编辑成功", c)
+}
+
+// DeleteFile
+// @Tags      ExaFileUploadAndDownload
+// @Summary   删除文件
+// @Security  ApiKeyAuth
+// @Produce   application/json
+// @Param     data  body      example.ExaFileUploadAndDownload  true  "传入文件里面id即可"
+// @Success   200   {object}  response.Response{msg=string}     "删除文件"
+// @Router    /fileUploadAndDownload/deleteFile [post]
+func (b *FileUploadAndDownloadApi) DeleteFile(c *gin.Context) {
+	var file example.ExaFileUploadAndDownload
+	err := c.ShouldBindJSON(&file)
+	if err != nil {
+		response.FailWithMessage(err.Error(), c)
+		return
+	}
+	if err := fileUploadAndDownloadService.DeleteFile(file); err != nil {
+		global.GVA_LOG.Error("删除失败!", zap.Error(err))
+		response.FailWithMessage("删除失败", c)
+		return
+	}
+	response.OkWithMessage("删除成功", c)
+}
+
+// GetFileList
+// @Tags      ExaFileUploadAndDownload
+// @Summary   分页文件列表
+// @Security  ApiKeyAuth
+// @accept    application/json
+// @Produce   application/json
+// @Param     data  body      request.PageInfo                                        true  "页码, 每页大小"
+// @Success   200   {object}  response.Response{data=response.PageResult,msg=string}  "分页文件列表,返回包括列表,总数,页码,每页数量"
+// @Router    /fileUploadAndDownload/getFileList [post]
+func (b *FileUploadAndDownloadApi) GetFileList(c *gin.Context) {
+	var pageInfo request.PageInfo
+	err := c.ShouldBindJSON(&pageInfo)
+	if err != nil {
+		response.FailWithMessage(err.Error(), c)
+		return
+	}
+	list, total, err := fileUploadAndDownloadService.GetFileRecordInfoList(pageInfo)
+	if err != nil {
+		global.GVA_LOG.Error("获取失败!", zap.Error(err))
+		response.FailWithMessage("获取失败", c)
+		return
+	}
+	response.OkWithDetailed(response.PageResult{
+		List:     list,
+		Total:    total,
+		Page:     pageInfo.Page,
+		PageSize: pageInfo.PageSize,
+	}, "获取成功", c)
+}

+ 3 - 0
server/initialize/router.go

@@ -41,6 +41,7 @@ func Routers() *gin.Engine {
 
 	InstallPlugin(Router) // 安装插件
 	systemRouter := router.RouterGroupApp.System
+	exampleRouter := router.RouterGroupApp.Example
 	// 如果想要不使用nginx代理前端网页,可以修改 web/.env.production 下的
 	// VUE_APP_BASE_API = /
 	// VUE_APP_BASE_PATH = http://localhost
@@ -88,6 +89,8 @@ func Routers() *gin.Engine {
 		systemRouter.InitAuthorityBtnRouterRouter(PrivateGroup)  // 字典详情管理
 		systemRouter.InitSysExportTemplateRouter(PrivateGroup)   // 导出模板
 
+		exampleRouter.InitCustomerRouter(PrivateGroup)
+		exampleRouter.InitFileUploadAndDownloadRouter(PrivateGroup)
 	}
 
 	global.GVA_LOG.Info("router register success")

+ 3 - 1
server/router/enter.go

@@ -1,11 +1,13 @@
 package router
 
 import (
+	"github.com/flipped-aurora/gin-vue-admin/server/router/example"
 	"github.com/flipped-aurora/gin-vue-admin/server/router/system"
 )
 
 type RouterGroup struct {
-	System system.RouterGroup
+	System  system.RouterGroup
+	Example example.RouterGroup
 }
 
 var RouterGroupApp = new(RouterGroup)

+ 6 - 0
server/router/example/enter.go

@@ -0,0 +1,6 @@
+package example
+
+type RouterGroup struct {
+	CustomerRouter
+	FileUploadAndDownloadRouter
+}

+ 24 - 0
server/router/example/exa_customer.go

@@ -0,0 +1,24 @@
+package example
+
+import (
+	v1 "github.com/flipped-aurora/gin-vue-admin/server/api/v1"
+	"github.com/flipped-aurora/gin-vue-admin/server/middleware"
+	"github.com/gin-gonic/gin"
+)
+
+type CustomerRouter struct{}
+
+func (e *CustomerRouter) InitCustomerRouter(Router *gin.RouterGroup) {
+	customerRouter := Router.Group("customer").Use(middleware.OperationRecord())
+	customerRouterWithoutRecord := Router.Group("customer")
+	exaCustomerApi := v1.ApiGroupApp.ExampleApiGroup.CustomerApi
+	{
+		customerRouter.POST("customer", exaCustomerApi.CreateExaCustomer)   // 创建客户
+		customerRouter.PUT("customer", exaCustomerApi.UpdateExaCustomer)    // 更新客户
+		customerRouter.DELETE("customer", exaCustomerApi.DeleteExaCustomer) // 删除客户
+	}
+	{
+		customerRouterWithoutRecord.GET("customer", exaCustomerApi.GetExaCustomer)         // 获取单一客户信息
+		customerRouterWithoutRecord.GET("customerList", exaCustomerApi.GetExaCustomerList) // 获取客户列表
+	}
+}

+ 23 - 0
server/router/example/exa_file_upload_and_download.go

@@ -0,0 +1,23 @@
+package example
+
+import (
+	v1 "github.com/flipped-aurora/gin-vue-admin/server/api/v1"
+	"github.com/gin-gonic/gin"
+)
+
+type FileUploadAndDownloadRouter struct{}
+
+func (e *FileUploadAndDownloadRouter) InitFileUploadAndDownloadRouter(Router *gin.RouterGroup) {
+	fileUploadAndDownloadRouter := Router.Group("fileUploadAndDownload")
+	exaFileUploadAndDownloadApi := v1.ApiGroupApp.ExampleApiGroup.FileUploadAndDownloadApi
+	{
+		fileUploadAndDownloadRouter.POST("upload", exaFileUploadAndDownloadApi.UploadFile)                                 // 上传文件
+		fileUploadAndDownloadRouter.POST("getFileList", exaFileUploadAndDownloadApi.GetFileList)                           // 获取上传文件列表
+		fileUploadAndDownloadRouter.POST("deleteFile", exaFileUploadAndDownloadApi.DeleteFile)                             // 删除指定文件
+		fileUploadAndDownloadRouter.POST("editFileName", exaFileUploadAndDownloadApi.EditFileName)                         // 编辑文件名或者备注
+		fileUploadAndDownloadRouter.POST("breakpointContinue", exaFileUploadAndDownloadApi.BreakpointContinue)             // 断点续传
+		fileUploadAndDownloadRouter.GET("findFile", exaFileUploadAndDownloadApi.FindFile)                                  // 查询当前文件成功的切片
+		fileUploadAndDownloadRouter.POST("breakpointContinueFinish", exaFileUploadAndDownloadApi.BreakpointContinueFinish) // 切片传输完成
+		fileUploadAndDownloadRouter.POST("removeChunk", exaFileUploadAndDownloadApi.RemoveChunk)                           // 删除切片
+	}
+}

+ 3 - 1
server/service/enter.go

@@ -1,11 +1,13 @@
 package service
 
 import (
+	"github.com/flipped-aurora/gin-vue-admin/server/service/example"
 	"github.com/flipped-aurora/gin-vue-admin/server/service/system"
 )
 
 type ServiceGroup struct {
-	SystemServiceGroup system.ServiceGroup
+	SystemServiceGroup  system.ServiceGroup
+	ExampleServiceGroup example.ServiceGroup
 }
 
 var ServiceGroupApp = new(ServiceGroup)

+ 6 - 0
server/service/example/enter.go

@@ -0,0 +1,6 @@
+package example
+
+type ServiceGroup struct {
+	CustomerService
+	FileUploadAndDownloadService
+}

+ 69 - 0
server/service/example/exa_breakpoint_continue.go

@@ -0,0 +1,69 @@
+package example
+
+import (
+	"errors"
+
+	"github.com/flipped-aurora/gin-vue-admin/server/global"
+	"github.com/flipped-aurora/gin-vue-admin/server/model/example"
+	"gorm.io/gorm"
+)
+
+type FileUploadAndDownloadService struct{}
+
+//@author: [piexlmax](https://github.com/piexlmax)
+//@function: FindOrCreateFile
+//@description: 上传文件时检测当前文件属性,如果没有文件则创建,有则返回文件的当前切片
+//@param: fileMd5 string, fileName string, chunkTotal int
+//@return: file model.ExaFile, err error
+
+func (e *FileUploadAndDownloadService) FindOrCreateFile(fileMd5 string, fileName string, chunkTotal int) (file example.ExaFile, err error) {
+	var cfile example.ExaFile
+	cfile.FileMd5 = fileMd5
+	cfile.FileName = fileName
+	cfile.ChunkTotal = chunkTotal
+
+	if errors.Is(global.GVA_DB.Where("file_md5 = ? AND is_finish = ?", fileMd5, true).First(&file).Error, gorm.ErrRecordNotFound) {
+		err = global.GVA_DB.Where("file_md5 = ? AND file_name = ?", fileMd5, fileName).Preload("ExaFileChunk").FirstOrCreate(&file, cfile).Error
+		return file, err
+	}
+	cfile.IsFinish = true
+	cfile.FilePath = file.FilePath
+	err = global.GVA_DB.Create(&cfile).Error
+	return cfile, err
+}
+
+//@author: [piexlmax](https://github.com/piexlmax)
+//@function: CreateFileChunk
+//@description: 创建文件切片记录
+//@param: id uint, fileChunkPath string, fileChunkNumber int
+//@return: error
+
+func (e *FileUploadAndDownloadService) CreateFileChunk(id uint, fileChunkPath string, fileChunkNumber int) error {
+	var chunk example.ExaFileChunk
+	chunk.FileChunkPath = fileChunkPath
+	chunk.ExaFileID = id
+	chunk.FileChunkNumber = fileChunkNumber
+	err := global.GVA_DB.Create(&chunk).Error
+	return err
+}
+
+//@author: [piexlmax](https://github.com/piexlmax)
+//@function: DeleteFileChunk
+//@description: 删除文件切片记录
+//@param: fileMd5 string, fileName string, filePath string
+//@return: error
+
+func (e *FileUploadAndDownloadService) DeleteFileChunk(fileMd5 string, filePath string) error {
+	var chunks []example.ExaFileChunk
+	var file example.ExaFile
+	err := global.GVA_DB.Where("file_md5 = ? ", fileMd5).First(&file).
+		Updates(map[string]interface{}{
+			"IsFinish":  true,
+			"file_path": filePath,
+		}).Error
+	if err != nil {
+		return err
+	}
+	err = global.GVA_DB.Where("exa_file_id = ?", file.ID).Delete(&chunks).Unscoped().Error
+	return err
+}

+ 85 - 0
server/service/example/exa_customer.go

@@ -0,0 +1,85 @@
+package example
+
+import (
+	"github.com/flipped-aurora/gin-vue-admin/server/global"
+	"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
+	"github.com/flipped-aurora/gin-vue-admin/server/model/example"
+	"github.com/flipped-aurora/gin-vue-admin/server/model/system"
+	systemService "github.com/flipped-aurora/gin-vue-admin/server/service/system"
+)
+
+type CustomerService struct{}
+
+//@author: [piexlmax](https://github.com/piexlmax)
+//@function: CreateExaCustomer
+//@description: 创建客户
+//@param: e model.ExaCustomer
+//@return: err error
+
+func (exa *CustomerService) CreateExaCustomer(e example.ExaCustomer) (err error) {
+	err = global.GVA_DB.Create(&e).Error
+	return err
+}
+
+//@author: [piexlmax](https://github.com/piexlmax)
+//@function: DeleteFileChunk
+//@description: 删除客户
+//@param: e model.ExaCustomer
+//@return: err error
+
+func (exa *CustomerService) DeleteExaCustomer(e example.ExaCustomer) (err error) {
+	err = global.GVA_DB.Delete(&e).Error
+	return err
+}
+
+//@author: [piexlmax](https://github.com/piexlmax)
+//@function: UpdateExaCustomer
+//@description: 更新客户
+//@param: e *model.ExaCustomer
+//@return: err error
+
+func (exa *CustomerService) UpdateExaCustomer(e *example.ExaCustomer) (err error) {
+	err = global.GVA_DB.Save(e).Error
+	return err
+}
+
+//@author: [piexlmax](https://github.com/piexlmax)
+//@function: GetExaCustomer
+//@description: 获取客户信息
+//@param: id uint
+//@return: customer model.ExaCustomer, err error
+
+func (exa *CustomerService) GetExaCustomer(id uint) (customer example.ExaCustomer, err error) {
+	err = global.GVA_DB.Where("id = ?", id).First(&customer).Error
+	return
+}
+
+//@author: [piexlmax](https://github.com/piexlmax)
+//@function: GetCustomerInfoList
+//@description: 分页获取客户列表
+//@param: sysUserAuthorityID string, info request.PageInfo
+//@return: list interface{}, total int64, err error
+
+func (exa *CustomerService) GetCustomerInfoList(sysUserAuthorityID uint, info request.PageInfo) (list interface{}, total int64, err error) {
+	limit := info.PageSize
+	offset := info.PageSize * (info.Page - 1)
+	db := global.GVA_DB.Model(&example.ExaCustomer{})
+	var a system.SysAuthority
+	a.AuthorityId = sysUserAuthorityID
+	auth, err := systemService.AuthorityServiceApp.GetAuthorityInfo(a)
+	if err != nil {
+		return
+	}
+	var dataId []uint
+	for _, v := range auth.DataAuthorityId {
+		dataId = append(dataId, v.AuthorityId)
+	}
+	var CustomerList []example.ExaCustomer
+	err = db.Where("sys_user_authority_id in ?", dataId).Count(&total).Error
+	if err != nil {
+		return CustomerList, total, err
+	} else {
+		err = db.Limit(limit).Offset(offset).Preload("SysUser").Where("sys_user_authority_id in ?", dataId).Find(&CustomerList).Error
+	}
+	return CustomerList, total, err
+}

+ 108 - 0
server/service/example/exa_file_upload_download.go

@@ -0,0 +1,108 @@
+package example
+
+import (
+	"errors"
+	"mime/multipart"
+	"strings"
+
+	"github.com/flipped-aurora/gin-vue-admin/server/global"
+	"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
+	"github.com/flipped-aurora/gin-vue-admin/server/model/example"
+	"github.com/flipped-aurora/gin-vue-admin/server/utils/upload"
+)
+
+//@author: [piexlmax](https://github.com/piexlmax)
+//@function: Upload
+//@description: 创建文件上传记录
+//@param: file model.ExaFileUploadAndDownload
+//@return: error
+
+func (e *FileUploadAndDownloadService) Upload(file example.ExaFileUploadAndDownload) error {
+	return global.GVA_DB.Create(&file).Error
+}
+
+//@author: [piexlmax](https://github.com/piexlmax)
+//@function: FindFile
+//@description: 查询文件记录
+//@param: id uint
+//@return: model.ExaFileUploadAndDownload, error
+
+func (e *FileUploadAndDownloadService) FindFile(id uint) (example.ExaFileUploadAndDownload, error) {
+	var file example.ExaFileUploadAndDownload
+	err := global.GVA_DB.Where("id = ?", id).First(&file).Error
+	return file, err
+}
+
+//@author: [piexlmax](https://github.com/piexlmax)
+//@function: DeleteFile
+//@description: 删除文件记录
+//@param: file model.ExaFileUploadAndDownload
+//@return: err error
+
+func (e *FileUploadAndDownloadService) DeleteFile(file example.ExaFileUploadAndDownload) (err error) {
+	var fileFromDb example.ExaFileUploadAndDownload
+	fileFromDb, err = e.FindFile(file.ID)
+	if err != nil {
+		return
+	}
+	oss := upload.NewOss()
+	if err = oss.DeleteFile(fileFromDb.Key); err != nil {
+		return errors.New("文件删除失败")
+	}
+	err = global.GVA_DB.Where("id = ?", file.ID).Unscoped().Delete(&file).Error
+	return err
+}
+
+// EditFileName 编辑文件名或者备注
+func (e *FileUploadAndDownloadService) EditFileName(file example.ExaFileUploadAndDownload) (err error) {
+	var fileFromDb example.ExaFileUploadAndDownload
+	return global.GVA_DB.Where("id = ?", file.ID).First(&fileFromDb).Update("name", file.Name).Error
+}
+
+//@author: [piexlmax](https://github.com/piexlmax)
+//@function: GetFileRecordInfoList
+//@description: 分页获取数据
+//@param: info request.PageInfo
+//@return: list interface{}, total int64, err error
+
+func (e *FileUploadAndDownloadService) GetFileRecordInfoList(info request.PageInfo) (list interface{}, total int64, err error) {
+	limit := info.PageSize
+	offset := info.PageSize * (info.Page - 1)
+	keyword := info.Keyword
+	db := global.GVA_DB.Model(&example.ExaFileUploadAndDownload{})
+	var fileLists []example.ExaFileUploadAndDownload
+	if len(keyword) > 0 {
+		db = db.Where("name LIKE ?", "%"+keyword+"%")
+	}
+	err = db.Count(&total).Error
+	if err != nil {
+		return
+	}
+	err = db.Limit(limit).Offset(offset).Order("updated_at desc").Find(&fileLists).Error
+	return fileLists, total, err
+}
+
+//@author: [piexlmax](https://github.com/piexlmax)
+//@function: UploadFile
+//@description: 根据配置文件判断是文件上传到本地或者七牛云
+//@param: header *multipart.FileHeader, noSave string
+//@return: file model.ExaFileUploadAndDownload, err error
+
+func (e *FileUploadAndDownloadService) UploadFile(header *multipart.FileHeader, noSave string) (file example.ExaFileUploadAndDownload, err error) {
+	oss := upload.NewOss()
+	filePath, key, uploadErr := oss.UploadFile(header)
+	if uploadErr != nil {
+		panic(err)
+	}
+	if noSave == "0" {
+		s := strings.Split(header.Filename, ".")
+		f := example.ExaFileUploadAndDownload{
+			Url:  filePath,
+			Name: header.Filename,
+			Tag:  s[len(s)-1],
+			Key:  key,
+		}
+		return f, e.Upload(f)
+	}
+	return
+}