Browse Source

导出文件

kobe6258 5 months ago
parent
commit
7127c68366
6 changed files with 308 additions and 7 deletions
  1. 2 2
      controllers/cutomer_product_risk_mapping.go
  2. 228 0
      controllers/user.go
  3. 10 4
      go.mod
  4. 12 1
      models/template_users.go
  5. 18 0
      routers/commentsRouter.go
  6. 38 0
      utils/excel_utils.go

+ 2 - 2
controllers/cutomer_product_risk_mapping.go

@@ -15,7 +15,7 @@ type CustomerProductRiskMappingController struct {
 	BaseAuthController
 }
 
-func sortStr(sort string) string {
+func sortStrFunc(sort string) string {
 	if sort == "desc" {
 		return "desc"
 	}
@@ -37,7 +37,7 @@ func (this *CustomerProductRiskMappingController) GetMappingList() {
 		this.ServeJSON()
 	}()
 	sort := this.GetString("Sort")
-	sort = sortStr(sort)
+	sort = sortStrFunc(sort)
 	list, err := models.GetMappingList(sort)
 	if err != nil {
 		br.Msg = "获取失败"

+ 228 - 0
controllers/user.go

@@ -7,6 +7,7 @@ import (
 	"eta/eta_mini_crm_ht/utils"
 	"fmt"
 	"github.com/rdlucklib/rdluck_tools/paging"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -371,3 +372,230 @@ func transSourceType(productType string) (sourceType models.SourceType) {
 		return ""
 	}
 }
+
+// ExportTemplateUsers
+// @Title 临时用户列表
+// @Description 临时用户列表
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Param   Keyword   query   string  false       "手机号"
+// @Param   SortParam   query   string  false       "排序字段参数,用来排序的字段, 枚举值:0:注册时间,1:阅读数,2:最近一次阅读时间"
+// @Param   SortType   query   string  true       "如何排序,是正序还是倒序,0:倒序,1:正序"
+// @Success 200 {object} response.TemplateUserListResp
+// @router /temporary/export [get]
+func (this *UserController) ExportTemplateUsers() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	keyword := this.GetString("Keyword")
+	sortParamInt, _ := this.GetInt("SortParam", 0)
+	sortTypeInt, _ := this.GetInt("SortType", 0)
+	var sortStr = ``
+	var condition string
+	var pars []interface{}
+
+	sortParamMap := map[int]string{0: "created_time", 1: "read_count", 2: "last_read_time"}
+	sortTypeMap := map[int]string{0: "desc", 1: "asc"}
+	sortParam, ok := sortParamMap[sortParamInt]
+	if !ok {
+		br.Msg = "错误的排序字段参数"
+		br.ErrMsg = fmt.Sprint("错误的排序字段:", sortParamInt)
+		return
+	}
+	sortType, ok := sortTypeMap[sortTypeInt]
+	if !ok {
+		br.Msg = "错误的排序字段"
+		br.ErrMsg = fmt.Sprint("错误的排序字段:", sortTypeInt)
+		return
+	}
+	sortStr = fmt.Sprintf("%s %s,updated_time desc ", sortParam, sortType)
+
+	if keyword != "" {
+		condition += ` AND mobile LIKE ? `
+		pars = utils.GetLikeKeywordPars(pars, keyword, 1)
+	}
+
+	userList, err := models.GetTemplateUserListByCondition(condition, pars, sortStr)
+	if err != nil {
+		br.Msg = "查询用户失败"
+		br.Msg = "查询用户失败,系统错误,Err:" + err.Error()
+		return
+	}
+	year, month, day := time.Now().Date()
+	yearStr := strconv.Itoa(year)[2:]
+	fileName := fmt.Sprintf("临时用户表%s.%d.%d.xlsx", yearStr, month, day)
+	encodedFilename := encodeChineseFilename(fileName)
+	this.Ctx.ResponseWriter.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
+	this.Ctx.ResponseWriter.Header().Set("Content-Disposition", encodedFilename)
+	this.Ctx.ResponseWriter.Header().Set("File-Name", fileName)
+	list := make([]models.TemplateUsersItem, 0)
+	for _, v := range userList {
+		list = append(list, v.ToItem())
+	}
+
+	file, err := utils.ExportExcel(fileName, "用户列表", map[string]string{"用户名": "UserName", "手机号": "Mobile"}, nil)
+	// 写入文件
+	if err = file.Write(this.Ctx.ResponseWriter); err != nil {
+		utils.FileLog.Error("导出excel文件失败:", err)
+		http.Error(this.Ctx.ResponseWriter, "导出excel文件失败", http.StatusInternalServerError)
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// encodeChineseFilename 将中文文件名编码为 ISO-8859-1
+func encodeChineseFilename(filename string) string {
+	// 对文件名进行 ISO-8859-1 编码
+	encodedFilename := fmt.Sprintf("attachment; filename=%s", filename)
+	return encodedFilename
+}
+
+// ExportOfficialUsers
+// @Title 正式用户列表
+// @Description 正式用户列表
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Param   Keyword   query   string  false       "手机号"
+// @Param   SortParam   query   string  false       "排序字段参数,用来排序的字段, 枚举值:0:注册时间,1:阅读数,2:最近一次阅读时间"
+// @Param   SortType   query   string  true       "如何排序,是正序还是倒序,0:倒序,1:正序"
+// @Success 200 {object} response.TemplateUserListResp
+// @router /official/export [get]
+func (this *UserController) ExportOfficialUsers() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+	keyword := this.GetString("Keyword")
+	FollowingGzh := this.GetString("FollowingGzh")
+	RegisterBeginDate := this.GetString("RegisterBeginDate")
+	RegisterEndDate := this.GetString("RegisterEndDate")
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	} else if pageSize > utils.PageSize100 {
+		pageSize = utils.PageSize100
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	} else if pageSize > utils.PageSize100 {
+		pageSize = utils.PageSize100
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	startSize := utils.StartIndex(currentIndex, pageSize)
+
+	sortParamInt, _ := this.GetInt("SortParam", 0)
+	sortTypeInt, _ := this.GetInt("SortType", 0)
+
+	var sortStr = ``
+	var condition string
+	var pars []interface{}
+
+	sortParamMap := map[int]string{0: "created_time", 1: "read_count", 2: "last_read_time"}
+	sortTypeMap := map[int]string{0: "desc", 1: "asc"}
+	sortParam, ok := sortParamMap[sortParamInt]
+	if !ok {
+		br.Msg = "错误的排序字段参数"
+		br.ErrMsg = fmt.Sprint("错误的排序字段:", sortParamInt)
+		return
+	}
+	sortType, ok := sortTypeMap[sortTypeInt]
+	if !ok {
+		br.Msg = "错误的排序字段"
+		br.ErrMsg = fmt.Sprintf("错误的排序字段:%v", sortTypeInt)
+		return
+	}
+	sortStr = fmt.Sprintf("%s %s,updated_time desc ", sortParam, sortType)
+	if FollowingGzh != "" {
+		switch FollowingGzh {
+		case "true":
+			condition += ` AND following_gzh=1 `
+		case "false":
+			condition += ` AND following_gzh=0 `
+		default:
+			br.Msg = "关注公众号字段非法字段"
+			br.ErrMsg = fmt.Sprintf("错误的关注公众号字段:%s", FollowingGzh)
+			return
+		}
+	}
+	if RegisterBeginDate != "" || RegisterEndDate != "" {
+		var beginDate, endDate time.Time
+		var parseErr error
+		if RegisterBeginDate != "" {
+			beginDate, parseErr = time.Parse(time.DateOnly, RegisterBeginDate)
+			if parseErr != nil {
+				br.Msg = "注册时间开始字段非法字段"
+				br.ErrMsg = fmt.Sprintf("错误的注册时间开始字段:%s", RegisterBeginDate)
+				return
+			}
+		}
+		if RegisterEndDate != "" {
+			endDate, parseErr = time.Parse(time.DateOnly, RegisterEndDate)
+			if parseErr != nil {
+				br.Msg = "注册时间结束字段非法字段"
+				br.ErrMsg = fmt.Sprintf("错误的注册时间结束字段:%s", RegisterEndDate)
+
+				return
+			}
+		}
+
+		if RegisterBeginDate != "" {
+			if RegisterEndDate != "" {
+				if beginDate.After(endDate) {
+					br.Msg = "结束时间不能早于开始时间"
+					br.ErrMsg = fmt.Sprintf("错误的注册时间结束字段:开始时间:%s,结束时间:%s", RegisterBeginDate, RegisterEndDate)
+					return
+				}
+				condition += ` AND DATE_FORMAT(created_time,'%Y-%m-%d') BETWEEN ? AND ?`
+				pars = append(pars, RegisterBeginDate, RegisterEndDate)
+			} else {
+				condition += ` AND DATE_FORMAT(created_time,'%Y-%m-%d') >= ?`
+				pars = append(pars, RegisterBeginDate)
+			}
+		} else {
+			condition += ` AND DATE_FORMAT(created_time,'%Y-%m-%d') <= ?`
+			pars = append(pars, RegisterEndDate)
+		}
+	}
+	if keyword != "" {
+		condition += ` AND ( mobile LIKE ? or real_name like ?)`
+		pars = utils.GetLikeKeywordPars(pars, keyword, 2)
+	}
+
+	resp := new(response.UserListResp)
+	total, userList, err := models.GetPageOfficialUserList(condition, pars, sortStr, startSize, pageSize)
+	if err != nil {
+		br.Msg = "查询用户失败"
+		br.Msg = "查询用户失败,系统错误,Err:" + err.Error()
+		return
+	}
+
+	//list := make([]*models.UserView, 0)
+	//var wg sync.WaitGroup
+	//wg.Add(len(userList))
+	//for _, v := range userList {
+	//	go func(v *models.User) {
+	//		defer wg.Done()
+	//		tempUser, _ := models.GetTemplateUser(v.TemplateUserId)
+	//		userView := v.FillUserInfo(tempUser)
+	//		list = append(list, &userView)
+	//	}(&v)
+	//}
+	//wg.Wait()
+	page := paging.GetPaging(currentIndex, pageSize, total)
+	resp.Paging = page
+	resp.List = userList
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}

+ 10 - 4
go.mod

@@ -17,6 +17,7 @@ require (
 	github.com/shopspring/decimal v1.3.1
 	github.com/silenceper/wechat/v2 v2.1.6
 	github.com/tcolgate/mp3 v0.0.0-20170426193717-e79c5a46d300
+	github.com/xuri/excelize/v2 v2.9.0
 	google.golang.org/grpc v1.65.0
 	google.golang.org/protobuf v1.34.2
 )
@@ -43,12 +44,15 @@ require (
 	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/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
 	github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/prometheus/client_golang v1.19.0 // indirect
 	github.com/prometheus/client_model v0.5.0 // indirect
 	github.com/prometheus/common v0.48.0 // indirect
 	github.com/prometheus/procfs v0.12.0 // indirect
+	github.com/richardlehane/mscfb v1.0.4 // indirect
+	github.com/richardlehane/msoleps v1.0.4 // indirect
 	github.com/rs/xid v1.5.0 // indirect
 	github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
 	github.com/sirupsen/logrus v1.9.0 // indirect
@@ -57,10 +61,12 @@ require (
 	github.com/tidwall/match v1.1.1 // indirect
 	github.com/tidwall/pretty v1.2.0 // indirect
 	github.com/valyala/bytebufferpool v1.0.0 // indirect
-	golang.org/x/crypto v0.26.0 // indirect
-	golang.org/x/net v0.28.0 // indirect
-	golang.org/x/sys v0.24.0 // indirect
-	golang.org/x/text v0.17.0 // indirect
+	github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d // indirect
+	github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 // indirect
+	golang.org/x/crypto v0.28.0 // indirect
+	golang.org/x/net v0.30.0 // indirect
+	golang.org/x/sys v0.26.0 // indirect
+	golang.org/x/text v0.19.0 // indirect
 	golang.org/x/time v0.6.0 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20240820151423-278611b39280 // indirect
 	gopkg.in/ini.v1 v1.67.0 // indirect

+ 12 - 1
models/template_users.go

@@ -100,7 +100,18 @@ func GetTemplateUserList() (items []*TemplateUser, err error) {
 	_, err = o.Raw(sql).QueryRows(&items)
 	return
 }
-
+func GetTemplateUserListByCondition(condition string, pars []interface{}, sortStr string) (items []*TemplateUser, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM template_users AS a WHERE  is_deleted = 0 `
+	if condition != "" {
+		sql += condition
+	}
+	if sortStr != `` {
+		sql += ` ORDER BY ` + sortStr
+	}
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
 func GetTemplateUser(id int) (item *TemplateUser, err error) {
 	o := orm.NewOrm()
 	sql := `SELECT * FROM template_users WHERE id=? and  is_deleted = 0 `

+ 18 - 0
routers/commentsRouter.go

@@ -621,6 +621,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mini_crm_ht/controllers:UserController"] = append(beego.GlobalControllerRouter["eta/eta_mini_crm_ht/controllers:UserController"],
+        beego.ControllerComments{
+            Method: "ExportOfficialUsers",
+            Router: `/official/export`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mini_crm_ht/controllers:UserController"] = append(beego.GlobalControllerRouter["eta/eta_mini_crm_ht/controllers:UserController"],
         beego.ControllerComments{
             Method: "OfficialList",
@@ -639,6 +648,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mini_crm_ht/controllers:UserController"] = append(beego.GlobalControllerRouter["eta/eta_mini_crm_ht/controllers:UserController"],
+        beego.ControllerComments{
+            Method: "ExportTemplateUsers",
+            Router: `/temporary/export`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mini_crm_ht/controllers:UserController"] = append(beego.GlobalControllerRouter["eta/eta_mini_crm_ht/controllers:UserController"],
         beego.ControllerComments{
             Method: "TemplateList",

+ 38 - 0
utils/excel_utils.go

@@ -0,0 +1,38 @@
+package utils
+
+import (
+	"github.com/xuri/excelize/v2"
+)
+
+func ExportExcel(fileName, sheetName string, cols map[string]string, dataList []interface{}) (file *excelize.File, err error) {
+	// 创建一个新的 Excel 文件
+	file = excelize.NewFile()
+
+	// 创建一个工作表
+	index, err := file.NewSheet(sheetName)
+	if err != nil {
+		FileLog.Error("创建工作表失败:", err)
+	}
+	// 设置工作表的标题行
+	for k, v := range cols {
+		err = file.SetCellValue(sheetName, k, v)
+		if err != nil {
+			FileLog.Error("创建column失败:", err)
+			return
+		}
+	}
+	// 添加一些示例数据
+	// 将数据写入工作表
+	//row := 2
+	//for _, item := range dataList {
+	//	file.SetCellValue("Sheet1", fmt.Sprintf("A%d", row), item.ID)
+	//	file.SetCellValue("Sheet1", fmt.Sprintf("B%d", row), item.Name)
+	//	file.SetCellValue("Sheet1", fmt.Sprintf("C%d", row), item.Age)
+	//	file.SetCellValue("Sheet1", fmt.Sprintf("D%d", row), item.CreatedAt.Format("2006-01-02 15:04:05"))
+	//	row++
+	//}
+
+	// 设置活动工作表
+	file.SetActiveSheet(index)
+	return
+}