From 2235516232a60cd3ef2890df3dce63030909e32e Mon Sep 17 00:00:00 2001 From: zchengo <1933757688@qq.com> Date: Tue, 27 Dec 2022 19:18:58 +0800 Subject: [PATCH] feat: export excel file --- server/api/contract.go | 15 +++++++++ server/api/customer.go | 15 +++++++++ server/api/product.go | 15 +++++++++ server/common/excel.go | 41 ++++++++++++++++++++++++ server/initialize/router.go | 7 +++-- server/models/contract.go | 12 +++++++ server/models/customer.go | 16 ++++++++++ server/models/product.go | 12 +++++++ server/response/errcode.go | 3 ++ server/service/contract.go | 44 +++++++++++++++++++++++++- server/service/customer.go | 43 +++++++++++++++++++++++++ server/service/product.go | 42 +++++++++++++++++++++++++ web/src/api/contract.js | 10 ++++++ web/src/api/customer.js | 10 ++++++ web/src/api/product.js | 10 ++++++ web/src/views/Contract.vue | 62 +++++++++++++++++++++++++++---------- web/src/views/Customer.vue | 55 +++++++++++++++++++++++--------- web/src/views/Product.vue | 52 ++++++++++++++++++++++++------- 18 files changed, 418 insertions(+), 46 deletions(-) create mode 100644 server/common/excel.go diff --git a/server/api/contract.go b/server/api/contract.go index c3ff03d..357fe33 100644 --- a/server/api/contract.go +++ b/server/api/contract.go @@ -91,3 +91,18 @@ func (p *ContractApi) QueryPlist(context *gin.Context) { productList, errCode := p.contractService.QueryPlist(¶m) response.Result(errCode, productList, context) } + +// 导出Excel文件 +func (c *ContractApi) Export(context *gin.Context) { + uid, _ := strconv.Atoi(context.Request.Header.Get("uid")) + if uid <= 0 { + response.Result(response.ErrCodeParamInvalid, nil, context) + return + } + file, errCode := c.contractService.Export(int64(uid)) + if len(file) >= 0 && errCode != 0 { + response.Result(errCode, nil, context) + return + } + context.File(file) +} diff --git a/server/api/customer.go b/server/api/customer.go index 8127062..68d13fa 100644 --- a/server/api/customer.go +++ b/server/api/customer.go @@ -91,3 +91,18 @@ func (c *CustomerApi) QueryOption(context *gin.Context) { customerOption, errCode := c.customerService.QueryOption(int64(uid)) response.Result(errCode, customerOption, context) } + +// 导出Excel文件 +func (c *CustomerApi) Export(context *gin.Context) { + uid, _ := strconv.Atoi(context.Request.Header.Get("uid")) + if uid <= 0 { + response.Result(response.ErrCodeParamInvalid, nil, context) + return + } + file, errCode := c.customerService.Export(int64(uid)) + if len(file) >= 0 && errCode != 0 { + response.Result(errCode, nil, context) + return + } + context.File(file) +} diff --git a/server/api/product.go b/server/api/product.go index f4e4e4d..97e0bac 100644 --- a/server/api/product.go +++ b/server/api/product.go @@ -80,3 +80,18 @@ func (p *ProductApi) QueryInfo(context *gin.Context) { productInfo, errCode := p.productService.QueryInfo(¶m) response.Result(errCode, productInfo, context) } + +// 导出Excel文件 +func (p *ProductApi) Export(context *gin.Context) { + uid, _ := strconv.Atoi(context.Request.Header.Get("uid")) + if uid <= 0 { + response.Result(response.ErrCodeParamInvalid, nil, context) + return + } + file, errCode := p.productService.Export(int64(uid)) + if len(file) >= 0 && errCode != 0 { + response.Result(errCode, nil, context) + return + } + context.File(file) +} diff --git a/server/common/excel.go b/server/common/excel.go new file mode 100644 index 0000000..41af002 --- /dev/null +++ b/server/common/excel.go @@ -0,0 +1,41 @@ +package common + +import ( + "crm/global" + "log" + "reflect" + "strconv" + + "github.com/xuri/excelize/v2" +) + +const ( + letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +) + +func GenExcelFile[T any](sheet string, columns []string, rowValue []T, filename string) (string, error) { + f := excelize.NewFile() + index := f.NewSheet(sheet) + for i := 0; i < len(columns); i++ { + axis := string(letter[i]) + strconv.Itoa(1) + f.SetCellValue(sheet, axis, columns[i]) + } + + num := 2 + for r := 0; r < len(rowValue); r++ { + v := reflect.ValueOf(rowValue[r]) + for i := 0; i < v.NumField(); i++ { + axis := string(letter[i]) + strconv.Itoa(num) + f.SetCellValue(sheet, axis, v.Field(i)) + } + num++ + } + f.SetActiveSheet(index) + path := global.Config.File.Path + filename + ".xlsx" + + if err := f.SaveAs(path); err != nil { + log.Printf("[ERROR] file save error: %s", err) + return "", err + } + return path, nil +} diff --git a/server/initialize/router.go b/server/initialize/router.go index 497b224..639194a 100644 --- a/server/initialize/router.go +++ b/server/initialize/router.go @@ -17,7 +17,7 @@ func Router() { route := engine.Group("/api") - { + { // 用户模块,订阅模块 route.GET("/user/verifycode", api.NewUserApi().GetVerifyCode) route.GET("/user/info", api.NewUserApi().GetInfo) @@ -37,6 +37,7 @@ func Router() { route.GET("/customer/list", api.NewCustomerApi().QueryList) route.GET("/customer/info", api.NewCustomerApi().QueryInfo) route.GET("/customer/option", api.NewCustomerApi().QueryOption) + route.GET("/customer/export", api.NewCustomerApi().Export) route.POST("/customer/create", api.NewCustomerApi().Create) route.PUT("/customer/update", api.NewCustomerApi().Update) route.DELETE("/customer/delete", api.NewCustomerApi().Delete) @@ -44,6 +45,7 @@ func Router() { // 合同模块 route.GET("/contract/list", api.NewContractApi().QueryList) route.GET("/contract/info", api.NewContractApi().QueryInfo) + route.GET("/contract/export", api.NewContractApi().Export) route.POST("/contract/plist", api.NewContractApi().QueryPlist) route.PUT("/contract/update", api.NewContractApi().Update) route.POST("/contract/create", api.NewContractApi().Create) @@ -52,6 +54,7 @@ func Router() { // 产品模块 route.GET("/product/list", api.NewProductApi().QueryList) route.GET("/product/info", api.NewProductApi().QueryInfo) + route.GET("/product/export", api.NewProductApi().Export) route.POST("/product/create", api.NewProductApi().Create) route.PUT("/product/update", api.NewProductApi().Update) route.DELETE("/product/delete", api.NewProductApi().Delete) @@ -62,7 +65,7 @@ func Router() { // 订阅模块 route.GET("/subscribe/info", api.NewSubscribeApi().GetInfo) route.POST("/subscribe/pay", api.NewSubscribeApi().Pay) - route.POST("/subscribe/notify", api.NewSubscribeApi().Notify) + route.POST("/subscribe/notify", api.NewSubscribeApi().Notify) } // 启动、监听端口 diff --git a/server/models/contract.go b/server/models/contract.go index a90d058..0c596b8 100644 --- a/server/models/contract.go +++ b/server/models/contract.go @@ -91,6 +91,18 @@ type Products struct { Total float64 `json:"total"` } +type ContractExcelRow struct { + Name string `json:"name"` + Cname string `json:"cname"` + Amount float64 `json:"amount"` + BeginTime string `json:"beginTime"` + OverTime string `json:"overTime"` + Remarks string `json:"remarks"` + Status string `json:"status"` + Created string `json:"created"` + Updated string `json:"updated"` +} + type Productlist []*Products func (p *Productlist) Value() (driver.Value, error) { diff --git a/server/models/customer.go b/server/models/customer.go index 796318b..260b080 100644 --- a/server/models/customer.go +++ b/server/models/customer.go @@ -91,3 +91,19 @@ type CustomerOption struct { Id int64 `json:"id"` Name string `json:"name"` } + +type CustomerExcelRow struct { + Name string `json:"name"` + Source string `json:"source"` + Phone string `json:"phone"` + Email string `json:"email"` + Industry string `json:"industry"` + Level string `json:"level"` + Remarks string `json:"remarks"` + Region string `json:"region"` + Address string `json:"address"` + Status string `json:"status"` + Creator int64 `json:"creator"` + Created string `json:"created"` + Updated string `json:"updated"` +} diff --git a/server/models/product.go b/server/models/product.go index e78a74b..a41cebb 100644 --- a/server/models/product.go +++ b/server/models/product.go @@ -73,3 +73,15 @@ type ProductInfo struct { Description string `json:"description"` Status int `json:"status"` } + +type ProductExcelRow struct { + Name string `json:"name"` + Type string `json:"type"` + Unit string `json:"unit"` + Code string `json:"code"` + Price float64 `json:"price"` + Description string `json:"description"` + Status string `json:"status"` + Created string `json:"created"` + Updated string `json:"updated"` +} diff --git a/server/response/errcode.go b/server/response/errcode.go index b74362a..47174c0 100644 --- a/server/response/errcode.go +++ b/server/response/errcode.go @@ -21,6 +21,8 @@ const ( ErrCodeUserPassResetFailed = 10009 // 用户密码重置失败 ErrCodePayFailed = 20001 // 支付宝支付失败 + + ErrCodeFileExportFailed = 30001 // 文件导出失败 ) var msg = map[int]string{ @@ -39,4 +41,5 @@ var msg = map[int]string{ ErrCodeCompanyCreateFailed: "company create failed", ErrCodeEmailFormatInvalid: "email format invalid", ErrCodeUserPassResetFailed: "user password reset failed", + ErrCodeFileExportFailed: "file export failed", } diff --git a/server/service/contract.go b/server/service/contract.go index ca8bb8f..92946f8 100644 --- a/server/service/contract.go +++ b/server/service/contract.go @@ -1,9 +1,11 @@ package service import ( + "crm/common" "crm/global" "crm/models" "crm/response" + "strconv" "time" ) @@ -97,7 +99,7 @@ func (c *ContractService) QueryInfo(param *models.ContractQueryParam) (*models.C } // 在编辑合同中,添加产品后,返回已添加的产品列表 -func (p *ContractService) QueryPlist(param *models.ContractQueryParam) ([]*models.Products, int) { +func (c *ContractService) QueryPlist(param *models.ContractQueryParam) ([]*models.Products, int) { if param.Id == 0 { products := make([]*models.Products, 0) if err := global.Db.Table(PRODUCT).Find(&products, param.Pids).Error; err != nil { @@ -141,3 +143,43 @@ func (p *ContractService) QueryPlist(param *models.ContractQueryParam) ([]*model addedProductList = append(addedProductList, products...) return addedProductList, response.ErrCodeSuccess } + +// 导出Excel文件 +func (c *ContractService) Export(uid int64) (string, int) { + contracts := make([]models.ContractList, 0) + s := "contract.id, contract.name, contract.amount, contract.begin_time, contract.over_time, customer.name as cname, contract.remarks, contract.status, contract.created, contract.updated" + j := "left join customer on contract.cid = customer.id and contract.creator = ?" + err := global.Db.Table(CONTRACT).Select(s).Joins(j, uid).Scan(&contracts).Error + if err != nil { + return StringNull, response.ErrCodeFailed + } + excelRows := make([]models.ContractExcelRow, 0) + var row models.ContractExcelRow + for _, c := range contracts { + row.Name = c.Name + row.Cname = c.Cname + row.Amount = c.Amount + row.BeginTime = c.BeginTime + row.OverTime = c.OverTime + row.Remarks = c.Remarks + if c.Status == 1 { + row.Status = "已签约" + } + if c.Status == 2 { + row.Status = "未签约" + } + row.Created = time.Unix(c.Created, 0).Format("2006-01-02") + if c.Updated != 0 { + row.Updated = time.Unix(c.Updated, 0).Format("2006-01-02") + } + excelRows = append(excelRows, row) + } + sheet := "合同信息" + columns := []string{"合同名称", "客户名称", "合同金额", "合同开始时间", "合同结束时间", "备注", "签约状态", "创建时间", "更新时间"} + fileName := "contract_" + strconv.FormatInt(uid, 10) + file, err := common.GenExcelFile(sheet, columns, excelRows, fileName) + if err != nil { + return StringNull, response.ErrCodeFailed + } + return file, response.ErrCodeSuccess +} diff --git a/server/service/customer.go b/server/service/customer.go index ed6b862..23ad506 100644 --- a/server/service/customer.go +++ b/server/service/customer.go @@ -1,9 +1,11 @@ package service import ( + "crm/common" "crm/global" "crm/models" "crm/response" + "strconv" "time" ) @@ -102,3 +104,44 @@ func (c *CustomerService) QueryOption(uid int64) ([]*models.CustomerOption, int) } return option, response.ErrCodeSuccess } + +// 导出Excel文件 +func (c *CustomerService) Export(uid int64) (string, int) { + customers := make([]models.Customer, 0) + err := global.Db.Where("creator = ?", uid).Find(&customers).Error + if err != nil { + return StringNull, response.ErrCodeFailed + } + excelRows := make([]models.CustomerExcelRow, 0) + var row models.CustomerExcelRow + for _, c := range customers { + row.Name = c.Name + row.Source = c.Source + row.Phone = c.Phone + row.Email = c.Email + row.Industry = c.Industry + row.Level = c.Level + row.Remarks = c.Remarks + row.Region = c.Region + row.Address = c.Address + if c.Status == 1 { + row.Status = "已签约" + } + if c.Status == 2 { + row.Status = "未签约" + } + row.Created = time.Unix(c.Created, 0).Format("2006-01-02") + if c.Updated != 0 { + row.Updated = time.Unix(c.Updated, 0).Format("2006-01-02") + } + excelRows = append(excelRows, row) + } + sheet := "客户信息" + columns := []string{"名称", "客户来源", "手机号", "邮箱", "客户行业", "客户级别", "备注", "地区", "详细地址", "成交状态", "创建时间", "更新时间"} + fileName := "customer_" + strconv.FormatInt(uid, 10) + file, err := common.GenExcelFile(sheet, columns, excelRows, fileName) + if err != nil { + return StringNull, response.ErrCodeFailed + } + return file, response.ErrCodeSuccess +} diff --git a/server/service/product.go b/server/service/product.go index 8d80fef..18b152e 100644 --- a/server/service/product.go +++ b/server/service/product.go @@ -1,9 +1,11 @@ package service import ( + "crm/common" "crm/global" "crm/models" "crm/response" + "strconv" "time" ) @@ -85,3 +87,43 @@ func (p *ProductService) QueryInfo(param *models.ProductQueryParam) (*models.Pro } return &productInfo, response.ErrCodeSuccess } + +// 导出Excel文件 +func (p *ProductService) Export(uid int64) (string, int) { + products := make([]models.Product, 0) + err := global.Db.Where("creator = ?", uid).Find(&products).Error + if err != nil { + return StringNull, response.ErrCodeFileExportFailed + } + excelRows := make([]models.ProductExcelRow, 0) + var row models.ProductExcelRow + for _, p := range products { + row.Name = p.Name + if p.Status == 1 { + row.Status = "已上架" + } + if p.Status == 2 { + row.Status = "已下架" + } + if p.Type == 1 { + row.Type = "默认" + } + row.Unit = p.Unit + row.Code = p.Code + row.Price = p.Price + row.Description = p.Description + row.Created = time.Unix(p.Created, 0).Format("2006-01-02") + if p.Updated != 0 { + row.Updated = time.Unix(p.Updated, 0).Format("2006-01-02") + } + excelRows = append(excelRows, row) + } + sheet := "产品信息" + columns := []string{"名称", "是否上下架", "类型", "单位", "编码", "价格", "描述", "创建时间", "更新时间"} + fileName := "product_" + strconv.FormatInt(uid, 10) + file, err := common.GenExcelFile(sheet, columns, excelRows, fileName) + if err != nil { + return StringNull, response.ErrCodeFileExportFailed + } + return file, response.ErrCodeSuccess +} diff --git a/web/src/api/contract.js b/web/src/api/contract.js index 0c82261..71ad540 100644 --- a/web/src/api/contract.js +++ b/web/src/api/contract.js @@ -52,4 +52,14 @@ export function queryContractPlist(param) { method: 'post', data: param, }) +} + +// 导出Excel表格 +export function contractExport(param) { + return request({ + url: '/contract/export', + method: 'get', + responseType: 'blob', + params: param, + }) } \ No newline at end of file diff --git a/web/src/api/customer.js b/web/src/api/customer.js index 317d2b7..5bfad00 100644 --- a/web/src/api/customer.js +++ b/web/src/api/customer.js @@ -52,4 +52,14 @@ export function queryCustomerOption(param) { method: 'get', params: param, }) +} + +// 导出Excel表格 +export function customerExport(param) { + return request({ + url: '/customer/export', + method: 'get', + responseType: 'blob', + params: param, + }) } \ No newline at end of file diff --git a/web/src/api/product.js b/web/src/api/product.js index db4a326..30b8f1e 100644 --- a/web/src/api/product.js +++ b/web/src/api/product.js @@ -43,4 +43,14 @@ export function queryProductList(param) { method: 'get', params: param, }) +} + +// 导出Excel表格 +export function productExport(param) { + return request({ + url: '/product/export', + method: 'get', + responseType: 'blob', + params: param, + }) } \ No newline at end of file diff --git a/web/src/views/Contract.vue b/web/src/views/Contract.vue index 73d0292..b1f640b 100644 --- a/web/src/views/Contract.vue +++ b/web/src/views/Contract.vue @@ -1,15 +1,23 @@