Browse Source

add user excel

sun-pc-linux 4 months ago
parent
commit
b97e24c748
7 changed files with 350 additions and 26 deletions
  1. 197 0
      src/api/user-excel.go
  2. 147 0
      src/api/user.go
  3. 1 1
      src/db/db.go
  4. 3 2
      src/db/model/examHistory.go
  5. 1 0
      src/db/model/user.go
  6. 0 22
      src/db/model/versions.go
  7. 1 1
      src/db/redis.go

+ 197 - 0
src/api/user-excel.go

@@ -0,0 +1,197 @@
+package api
+
+import (
+	"fmt"
+	"nrhe-train/db/model"
+	"strings"
+
+	"github.com/xuri/excelize/v2"
+)
+
+type UserExcel struct {
+	Offset           int
+	Row              int
+	Title            string //标题
+	Excel            *excelize.File
+	SheetName        string
+	AlignCenterStyle int
+	Content          []*model.User
+	RowMap           map[string]int
+	RowWidthArray    []float64
+	RowsHeightArray  []map[int]float64
+}
+
+// 批量设置行高
+func (b *UserExcel) setRowsHeight() {
+	for _, rowHeight := range b.RowsHeightArray {
+		for row, height := range rowHeight {
+			b.Excel.SetRowHeight(b.SheetName, row, height)
+		}
+	}
+
+}
+
+// 获取范围内单元格的宽度 A:F
+func (b *UserExcel) getRangeWidth(r string) float64 {
+	rg := strings.Split(r, ":")
+
+	if len(rg) == 1 {
+		start := b.RowMap[rg[0]]
+		return b.RowWidthArray[start]
+	} else if len(rg) == 2 {
+		start := b.RowMap[rg[0]]
+		end := b.RowMap[rg[1]]
+		rowr := b.RowWidthArray[start : end+1]
+		width := 0.0
+		for _, v := range rowr {
+			width += v
+		}
+		return width
+	}
+	return 0.0
+}
+
+func (b *UserExcel) drawTitle() error {
+	b.Row++
+	startCell := fmt.Sprintf("A%d", b.Row)
+	endCell := fmt.Sprintf("D%d", b.Row)
+
+	b.RowMap = map[string]int{"A": 0, "B": 1, "C": 2, "D": 3}
+
+	b.RowWidthArray = []float64{12, 12, 12, 36}
+	b.Excel.SetColWidth(b.SheetName, "A", "A", 12)
+	b.Excel.SetColWidth(b.SheetName, "B", "B", 12)
+	b.Excel.SetColWidth(b.SheetName, "C", "C", 12)
+	b.Excel.SetColWidth(b.SheetName, "D", "D", 36)
+
+	err := b.Excel.MergeCell(b.SheetName, startCell, endCell)
+	if err != nil {
+		return err
+	}
+
+	style, err := b.Excel.NewStyle(&excelize.Style{
+		Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center"},
+		Font:      &excelize.Font{Bold: true, Size: 18}})
+	if err != nil {
+		return err
+	}
+	err = b.Excel.SetCellStyle(b.SheetName, startCell, startCell, style)
+	if err != nil {
+		return err
+	}
+	b.Excel.SetRowHeight(b.SheetName, b.Row, 26)
+
+	b.Excel.SetCellValue(b.SheetName, startCell, b.Title)
+	return nil
+}
+
+func (b *UserExcel) drawTableTitle() error {
+	b.Row++
+	var drawCol = func(prefix string, value string) error {
+		cell := fmt.Sprintf("%s%d", prefix, b.Row)
+		err := b.Excel.SetCellStyle(b.SheetName, cell, cell, b.AlignCenterStyle)
+		if err != nil {
+			return err
+		}
+
+		return b.Excel.SetCellValue(b.SheetName, cell, value)
+	}
+
+	drawCol("A", "用户名")
+	drawCol("B", "编号")
+	drawCol("C", "角色")
+	drawCol("D", "密码")
+	b.Excel.SetRowHeight(b.SheetName, b.Row, 22)
+
+	return nil
+}
+
+func (b *UserExcel) drawTableContent() error {
+	b.Row++
+	var DrawRow = func(rowIndex int, values ...string) float64 {
+		charas := []string{"A", "B", "C", "D"}
+		// 获取该行最大行高
+		max := getRowHeight(values[0], b.getRangeWidth(charas[0]))
+		for i, c := range charas {
+			v := ""
+			if i < len(values) {
+				v = values[i]
+			}
+			b.Excel.SetCellValue(b.SheetName, fmt.Sprintf("%s%d", c, rowIndex), v)
+			val2Cel := fmt.Sprintf("%s%d", c, rowIndex)
+			b.Excel.SetCellStyle(b.SheetName, val2Cel, val2Cel, b.AlignCenterStyle)
+
+			if getRowHeight(v, b.getRangeWidth(c)) > max {
+				max = getRowHeight(v, b.getRangeWidth(c))
+			}
+		}
+		return max
+	}
+
+	users := b.Content
+	if len(users) > 0 {
+		for _, user := range users {
+			role := ""
+			if user.Roles[0] == "admin" {
+				role = "管理员"
+			}
+			if user.Roles[0] == "teacher" {
+				role = "教员"
+			}
+			if user.Roles[0] == "student" {
+				role = "学员"
+			}
+			rowMaxHeight := DrawRow(b.Row, user.LoginName, user.Nid, role, user.Password)
+			b.RowsHeightArray = append(b.RowsHeightArray, map[int]float64{b.Row: rowMaxHeight})
+			b.Row++
+		}
+	}
+
+	return nil
+}
+
+func (b *UserExcel) Draws() {
+	b.drawTitle()
+
+	b.drawTableTitle()
+	b.drawTableContent()
+	// 设置行高
+	b.setRowsHeight()
+}
+
+func NewUserExcel(f *excelize.File) *UserExcel {
+
+	border := []excelize.Border{
+		{Type: "top", Style: 1, Color: "000000"},
+		{Type: "left", Style: 1, Color: "000000"},
+		{Type: "right", Style: 1, Color: "000000"},
+		{Type: "bottom", Style: 1, Color: "000000"},
+	}
+
+	styleLeft, _ := f.NewStyle(&excelize.Style{
+		Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
+		Border:    border,
+	})
+
+	b := &UserExcel{
+		Title:            "用户信息",
+		SheetName:        "Sheet1",
+		Excel:            f,
+		Offset:           0,
+		AlignCenterStyle: styleLeft,
+		RowMap:           map[string]int{"A": 0, "B": 1, "C": 2, "D": 3},
+		RowWidthArray:    []float64{12, 12, 12, 20},
+		RowsHeightArray:  make([]map[int]float64, 0),
+	}
+
+	// f.SetPageMargins(b.SheetName, excelize.PageMarginTop(1), excelize.PageMarginLeft(0), excelize.PageMarginRight(0))
+
+	return b
+}
+
+func (b *UserExcel) FormatToEmpty(str *string) {
+	if *str == "0" || *str == "0.000" {
+		*str = "-"
+	}
+
+}

+ 147 - 0
src/api/user.go

@@ -3,6 +3,7 @@ package api
 import (
 	"errors"
 	"fmt"
+	"net/url"
 	"nrhe-train/log"
 	"strconv"
 	"time"
@@ -12,6 +13,7 @@ import (
 	"nrhe-train/utils"
 
 	"github.com/gin-gonic/gin"
+	"github.com/xuri/excelize/v2"
 	"go.mongodb.org/mongo-driver/bson"
 	"go.mongodb.org/mongo-driver/bson/primitive"
 )
@@ -312,3 +314,148 @@ func IsStudent(c *gin.Context, apictx *ApiSession) (bool, error) {
 	}
 	return false, nil
 }
+
+// 导入用户
+func ImportUser(c *gin.Context, apictx *ApiSession) (interface{}, error) {
+	isAdmin, err := IsAdmin(c, apictx)
+	if err != nil {
+		return nil, err
+	}
+	if !isAdmin {
+		return nil, errors.New("没有权限")
+	}
+	file, _, err := c.Request.FormFile("file")
+	if err != nil {
+		return nil, errors.New("文件错误")
+	}
+	excel, err := excelize.OpenReader(file)
+	if err != nil {
+		return nil, err
+	}
+	excelIndex := excel.GetActiveSheetIndex()
+	sheetName := excel.GetSheetName(excelIndex)
+	users, err := excel.GetRows(sheetName)
+	if err != nil {
+		return nil, err
+	}
+	errors := []string{}
+
+	if len(users) > 0 {
+		for index, us := range users {
+			rowNum := index + 1
+			// 标题行
+			if index == 0 {
+				continue
+			}
+			// 表头
+			if index == 1 {
+				continue
+			}
+			// 去除可能的空行
+			if len(us) == 0 {
+				continue
+			}
+			// 用户名name 编号nid 密码password 角色roles
+			user := &model.User{}
+			user.LoginName = us[0]
+			user.Nid = us[1]
+			if len(us[0]) == 0 {
+				errors = append(errors, fmt.Sprintf("第%d行错误: %s", rowNum, "用户名不能为空"))
+				continue
+			}
+			if len(us[1]) == 0 {
+				errors = append(errors, fmt.Sprintf("第%d行错误: %s", rowNum, "编号不能为空"))
+				continue
+			}
+			roles := []string{}
+			if us[2] == "管理员" {
+				roles = []string{"admin"}
+			}
+			if us[2] == "教员" {
+				roles = []string{"teacher"}
+			}
+			if us[2] == "学员" {
+				roles = []string{"student"}
+			}
+			user.Roles = roles
+			user.Password = UtilMd5(us[3])
+			if len(us[3]) == 0 {
+				user.Password = UtilMd5("123456")
+			} else if len(us[3]) == 32 {
+				user.Password = us[3]
+			}
+			user.LoginName = fmt.Sprintf("%s_%s", user.LoginName, user.Nid)
+
+			user.CreateTime = time.Now()
+			user.UpdateTime = time.Now()
+
+			_, err = repo.RepoAddDoc(apictx.CreateRepoCtx(), repo.CollectionUser, user)
+			if err != nil {
+				errors = append(errors, fmt.Sprintf("第%d行错误: %s", rowNum, "保存数据失败, 请检查数据格式是否正确/编号是否重复"))
+				log.Error(err)
+			}
+
+		}
+	}
+
+	return errors, nil
+}
+
+// 导出用户
+func ExportUser(c *gin.Context, apictx *ApiSession) (interface{}, error) {
+	isAdmin, err := IsAdmin(c, apictx)
+	if err != nil {
+		return nil, err
+	}
+	if !isAdmin {
+		return nil, errors.New("没有权限")
+	}
+	f := excelize.NewFile()
+	index, _ := f.NewSheet("Sheet1")
+	f.SetActiveSheet(index)
+	f.SetDefaultFont("宋体")
+
+	testExcel := NewUserExcel(f)
+	testExcel.Title = "用户信息"
+
+	_, _, query := UtilQueryPageSize(c)
+	// 获取试题列表
+	users := make([]*model.User, 0)
+	err = repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
+		CollectName: repo.CollectionUser,
+		Query:       query,
+		Sort:        bson.M{"createTime": 1},
+	}, &users)
+	if err != nil {
+		return nil, err
+	}
+	testExcel.Content = users
+	testExcel.Draws()
+	fileName := url.PathEscape("用户信息.xlsx")
+	c.Header("Content-Type", "application/octet-stream")
+	c.Header("Content-Disposition", "attachment; filename="+fileName)
+	c.Header("Content-Transfer-Encoding", "binary")
+
+	err = f.Write(c.Writer)
+	if err != nil {
+		return nil, err
+	}
+
+	return nil, nil
+}
+
+// 下载用户模板
+func UserTmplate(c *gin.Context, apictx *ApiSession) (interface{}, error) {
+	filename := "用户信息模板.xlsx"
+	// url.PathEscape将字符串中的特殊字符进行编码,使其符合URL规范
+	filename = url.PathEscape(filename)
+
+	// 设置下载的文件名
+	c.Writer.Header().Add("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))
+
+	// 设置文件类型
+	c.Writer.Header().Add("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
+
+	c.File("./template/xxx.xlsx")
+	return nil, nil
+}

+ 1 - 1
src/db/db.go

@@ -36,7 +36,7 @@ func (db *MongoDB) GetOrCreateDatabase(name string) *mongo.Database {
 
 func NewMongoDB(bus *comm.NatsBus) *MongoDB {
 
-	inst, err := bus.NewMongoDBFromConfig("cr-mongo")
+	inst, err := bus.NewMongoDBFromConfig("nrhe-mongo")
 
 	if err != nil {
 		panic(err)

+ 3 - 2
src/db/model/examHistory.go

@@ -19,6 +19,7 @@ type ExamHistory struct {
 }
 
 type Record struct {
-	Title  string `bson:"title,omitempty" json:"title"`
-	Result string `bson:"result,omitempty" json:"result"`
+	Title     string `bson:"title,omitempty" json:"title"`
+	Result    string `bson:"result,omitempty" json:"result"`
+	IsCorrect bool   `bson:"isCorrect,omitempty" json:"isCorrect"`
 }

+ 1 - 0
src/db/model/user.go

@@ -8,6 +8,7 @@ import (
 
 type User struct {
 	Id        primitive.ObjectID `bson:"_id,omitempty" json:"_id,omitempty"`
+	Nid       string             `bson:"nid,omitempty" json:"nid,omitempty"`
 	LoginName string             `bson:"loginName,omitempty" json:"loginName,omitempty"`
 	Password  string             `bson:"password,omitempty" json:"password,omitempty"`
 	Avatar    string             `bson:"avatar,omitempty" json:"avatar,omitempty"`

+ 0 - 22
src/db/model/versions.go

@@ -1,22 +0,0 @@
-package model
-
-import (
-	"time"
-
-	"go.mongodb.org/mongo-driver/bson/primitive"
-)
-
-// 版本管理
-type Versions struct {
-	Id       primitive.ObjectID `bson:"_id,omitempty" json:"_id"`
-	UserId   primitive.ObjectID `bson:"userId,omitempty" json:"userId"`
-	UserName string             `bson:"userName,omitempty" json:"userName"`
-
-	Name    string `bson:"name,omitempty" json:"name"`       // 名字
-	Size    string `bson:"size,omitempty" json:"size"`       // 大小 2000M
-	Url     string `bson:"url,omitempty" json:"url"`         // 安装包地址
-	Version string `bson:"version,omitempty" json:"version"` // 版本 1.0.0
-
-	CreateTime time.Time `bson:"createTime,omitempty" json:"createTime"`
-	UpdateTime time.Time `bson:"updateTime,omitempty" json:"updateTime"`
-}

+ 1 - 1
src/db/redis.go

@@ -6,7 +6,7 @@ import (
 )
 
 func NewRedisClient(bus *comm.NatsBus) *redis.Client {
-	client, err := bus.NewRedisFromConfig("cr-redis")
+	client, err := bus.NewRedisFromConfig("nrhe-redis")
 
 	if err != nil {
 		return nil