作者 郑周

1. 获取zip文件 ->临时保存到本地 ->解压 ->解析xml ->创建模板

2. 返回key, 前端通过访问key验证数据处理结果
@@ -2,6 +2,7 @@ package command @@ -2,6 +2,7 @@ package command
2 2
3 import ( 3 import (
4 "github.com/beego/beego/v2/core/validation" 4 "github.com/beego/beego/v2/core/validation"
  5 + "gitlab.fjmaimaimai.com/allied-creation/performance/pkg/domain"
5 "unicode/utf8" 6 "unicode/utf8"
6 ) 7 )
7 8
@@ -10,6 +11,7 @@ type CreateTemplateCommand struct { @@ -10,6 +11,7 @@ type CreateTemplateCommand struct {
10 CreatorId int64 `cname:"创建人ID" json:"creatorId"` 11 CreatorId int64 `cname:"创建人ID" json:"creatorId"`
11 Name string `cname:"模板名称" json:"name" valid:"Required"` 12 Name string `cname:"模板名称" json:"name" valid:"Required"`
12 Describe string `cname:"模板描述" json:"describe"` 13 Describe string `cname:"模板描述" json:"describe"`
  14 + NodeContents []*domain.NodeContent `cname:"环节-评估内容" json:"nodeContents"`
13 } 15 }
14 16
15 func (in *CreateTemplateCommand) Valid(validation *validation.Validation) { 17 func (in *CreateTemplateCommand) Valid(validation *validation.Validation) {
@@ -40,13 +40,21 @@ func (rs *EvaluationTemplateService) Create(in *command.CreateTemplateCommand) ( @@ -40,13 +40,21 @@ func (rs *EvaluationTemplateService) Create(in *command.CreateTemplateCommand) (
40 linkNodes := make([]*domain.LinkNode, 0) 40 linkNodes := make([]*domain.LinkNode, 0)
41 41
42 sid, _ := utils.NewSnowflakeId() 42 sid, _ := utils.NewSnowflakeId()
43 - linkNodes = append(linkNodes, &domain.LinkNode{ 43 +
  44 + // 自评反馈
  45 + selfLinkNode := &domain.LinkNode{
44 Id: sid + 1, 46 Id: sid + 1,
45 Type: domain.LinkNodeSelfAssessment, 47 Type: domain.LinkNodeSelfAssessment,
46 Name: "填写自评反馈", 48 Name: "填写自评反馈",
47 NodeContents: make([]*domain.NodeContent, 0), 49 NodeContents: make([]*domain.NodeContent, 0),
48 KpiCycle: domain.KpiCycleDay, 50 KpiCycle: domain.KpiCycleDay,
49 - }) 51 + }
  52 + // 有环节自评评估内容,则直接使用
  53 + if len(in.NodeContents) > 0 {
  54 + selfLinkNode.NodeContents = in.NodeContents
  55 + }
  56 +
  57 + linkNodes = append(linkNodes, selfLinkNode)
50 linkNodes = append(linkNodes, &domain.LinkNode{ 58 linkNodes = append(linkNodes, &domain.LinkNode{
51 Id: sid + 2, 59 Id: sid + 2,
52 Type: domain.LinkNodeAllInvite, 60 Type: domain.LinkNodeAllInvite,
@@ -17,6 +17,9 @@ var AdminJwtExpiresIn = int64(3600 * 24 * 7) @@ -17,6 +17,9 @@ var AdminJwtExpiresIn = int64(3600 * 24 * 7)
17 17
18 var AdminJWTSecretKey = "sg-storage" 18 var AdminJWTSecretKey = "sg-storage"
19 19
  20 +// 上传临时Zip文件
  21 +var UPLOAD_ZIP_PATH = "./uploads/zip"
  22 +
20 // Env 判断当前环境变量 23 // Env 判断当前环境变量
21 var Env = "dev" 24 var Env = "dev"
22 25
  1 +package xredis
  2 +
  3 +import "fmt"
  4 +
  5 +const UploadZipKey = "performance:zip:%s" // 上传ZIP文件
  6 +
  7 +func CreateUploadZipKey(v string) string {
  8 + return fmt.Sprintf(UploadZipKey, v)
  9 +}
@@ -2,8 +2,12 @@ package xredis @@ -2,8 +2,12 @@ package xredis
2 2
3 import ( 3 import (
4 "context" 4 "context"
  5 + "encoding/json"
5 "fmt" 6 "fmt"
  7 + "reflect"
6 "strconv" 8 "strconv"
  9 + "strings"
  10 + "time"
7 11
8 "github.com/go-redis/redis/v8" 12 "github.com/go-redis/redis/v8"
9 "github.com/go-redsync/redsync/v4" 13 "github.com/go-redsync/redsync/v4"
@@ -35,3 +39,37 @@ func init() { @@ -35,3 +39,37 @@ func init() {
35 pool := goredis.NewPool(rdb) 39 pool := goredis.NewPool(rdb)
36 rsync = redsync.New(pool) 40 rsync = redsync.New(pool)
37 } 41 }
  42 +
  43 +func Set(key string, value interface{}, timeout time.Duration) error {
  44 + valueOf := reflect.ValueOf(value)
  45 + typeName := strings.ToLower(valueOf.Type().Name())
  46 + var newValue interface{}
  47 + if typeName == "string" || typeName == "int" || typeName == "int64" || typeName == "float64" {
  48 + newValue = value
  49 + } else {
  50 + mBytes, err := json.Marshal(value)
  51 + if err != nil {
  52 + return err
  53 + }
  54 + newValue = string(mBytes)
  55 + }
  56 +
  57 + err := rdb.Set(rdb.Context(), key, newValue, timeout*time.Second).Err()
  58 + return err
  59 +}
  60 +
  61 +func Get(key string) string {
  62 + value, err := rdb.Get(rdb.Context(), key).Result()
  63 + if err != nil {
  64 + return ""
  65 + }
  66 + return value
  67 +}
  68 +
  69 +func GetBytes(key string) ([]byte, error) {
  70 + return rdb.Get(rdb.Context(), key).Bytes()
  71 +}
  72 +
  73 +func Remove(key string) error {
  74 + return rdb.Del(rdb.Context(), key).Err()
  75 +}
1 package controllers 1 package controllers
2 2
3 import ( 3 import (
  4 + "archive/zip"
  5 + "bufio"
  6 + "encoding/json"
4 "fmt" 7 "fmt"
  8 + service "gitlab.fjmaimaimai.com/allied-creation/performance/pkg/application/evaluation_template"
  9 + templateCommand "gitlab.fjmaimaimai.com/allied-creation/performance/pkg/application/evaluation_template/command"
  10 + "gitlab.fjmaimaimai.com/allied-creation/performance/pkg/application/import/command"
  11 + "gitlab.fjmaimaimai.com/allied-creation/performance/pkg/constant"
  12 + "gitlab.fjmaimaimai.com/allied-creation/performance/pkg/infrastructure/xredis"
5 "gitlab.fjmaimaimai.com/allied-creation/performance/pkg/utils" 13 "gitlab.fjmaimaimai.com/allied-creation/performance/pkg/utils"
  14 + "io"
  15 + "mime/multipart"
  16 + "os"
  17 + "path"
  18 + "path/filepath"
6 "strconv" 19 "strconv"
7 "strings" 20 "strings"
  21 + "time"
8 22
9 "github.com/linmadan/egglib-go/core/application" 23 "github.com/linmadan/egglib-go/core/application"
10 "github.com/linmadan/egglib-go/utils/tool_funs" 24 "github.com/linmadan/egglib-go/utils/tool_funs"
@@ -183,3 +197,233 @@ func (controller *ImportController) parseTemplateNodeContent(data []*domain.Perf @@ -183,3 +197,233 @@ func (controller *ImportController) parseTemplateNodeContent(data []*domain.Perf
183 197
184 return nil, nodeContents 198 return nil, nodeContents
185 } 199 }
  200 +
  201 +func (controller *ImportController) ZipVerify() {
  202 + in := &command.VerifyKeyCommand{}
  203 + if err := controller.Unmarshal(in); err != nil {
  204 + controller.Response(nil, application.ThrowError(application.ARG_ERROR, err.Error()))
  205 + } else {
  206 + bytes, err := xredis.GetBytes(in.VerifyKey)
  207 + if err != nil {
  208 + controller.Response(nil, application.ThrowError(application.ARG_ERROR, err.Error()))
  209 + } else {
  210 + out := &command.OutResult{}
  211 + err := json.Unmarshal(bytes, out)
  212 + if err != nil {
  213 + controller.Response(nil, application.ThrowError(application.ARG_ERROR, err.Error()))
  214 + } else {
  215 + controller.Response(out, nil)
  216 + }
  217 + }
  218 + }
  219 +}
  220 +
  221 +func (controller *ImportController) ZipImport() {
  222 + _, header, err := controller.GetFile("file")
  223 + if err != nil {
  224 + controller.Response(nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "上传错误:"+err.Error()))
  225 + return
  226 + }
  227 + file, err := header.Open()
  228 + if err != nil {
  229 + controller.Response(nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "文件错误:"+err.Error()))
  230 + return
  231 + }
  232 +
  233 + // 写入本地
  234 + zipPath, day, id, err := controller.writeLocal(file)
  235 + if err != nil {
  236 + controller.Response(nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()))
  237 + return
  238 + }
  239 +
  240 + out := command.OutResult{
  241 + Status: "uncompleted",
  242 + Success: make([]command.ErrorI, 0),
  243 + Failure: make([]command.ErrorI, 0),
  244 + }
  245 + key := xredis.CreateUploadZipKey(id)
  246 + _ = xredis.Set(key, out, 2*time.Hour)
  247 + controller.Response(map[string]string{"key": key}, nil)
  248 + go func() {
  249 + // 解压目标文件夹
  250 + dstDir := constant.UPLOAD_ZIP_PATH + "/" + day + "/" + id
  251 + fileNames, err := controller.Unzip(zipPath, dstDir)
  252 + if err != nil {
  253 + _ = xredis.Remove(key)
  254 + } else {
  255 +
  256 + success := make([]command.ErrorI, 0)
  257 + failure := make([]command.ErrorI, 0)
  258 +
  259 + for i := range fileNames {
  260 + fn := fileNames[i]
  261 + f, err := os.Open(path.Join(dstDir, fn))
  262 + if err != nil {
  263 + failure = append(failure, command.ErrorI{
  264 + FileName: fn,
  265 + Message: err.Error(),
  266 + })
  267 + continue
  268 + }
  269 + if err := controller.parserAndInsert(f); err != nil {
  270 + failure = append(failure, command.ErrorI{
  271 + FileName: fn,
  272 + Message: err.Error(),
  273 + })
  274 + continue
  275 + }
  276 +
  277 + success = append(success, command.ErrorI{
  278 + FileName: fn,
  279 + Message: "",
  280 + })
  281 + }
  282 + out = command.OutResult{
  283 + Status: "completed",
  284 + Success: success,
  285 + Failure: failure,
  286 + }
  287 + _ = xredis.Set(key, out, 1*time.Hour)
  288 + }
  289 +
  290 + }()
  291 +
  292 +}
  293 +
  294 +func (controller *ImportController) writeLocal(file multipart.File) (string, string, string, error) {
  295 + var err error
  296 + id, err := utils.NewSnowflakeId()
  297 + if err != nil {
  298 + return "", "", "", err
  299 + }
  300 + id2 := fmt.Sprintf("%v", id)
  301 + day := time.Now().Format("2006-01-02")
  302 + zipPath := constant.UPLOAD_ZIP_PATH + "/" + day + "/" + id2 + "/" + "temp"
  303 +
  304 + var fd *os.File
  305 +
  306 + dir := filepath.Dir(zipPath)
  307 + err = os.MkdirAll(dir, os.ModePerm)
  308 + if err != nil {
  309 + return "", "", "", err
  310 + }
  311 +
  312 + fd, err = os.OpenFile(zipPath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
  313 + if err != nil {
  314 + return "", "", "", err
  315 + }
  316 + defer func(fd *os.File) {
  317 + if err = fd.Close(); err != nil {
  318 +
  319 + }
  320 + }(fd)
  321 +
  322 + wt := bufio.NewWriter(fd)
  323 + _, err = file.Seek(0, io.SeekStart)
  324 + if err != nil {
  325 + return "", "", "", err
  326 + }
  327 + _, err = io.Copy(wt, file)
  328 + if err != nil {
  329 + return "", "", "", err
  330 + }
  331 +
  332 + err = wt.Flush()
  333 + if err != nil {
  334 + return "", "", "", err
  335 + }
  336 +
  337 + return zipPath, day, id2, err
  338 +}
  339 +
  340 +func (controller *ImportController) Unzip(zipPath, dstDir string) ([]string, error) {
  341 + // 文件名称
  342 + fileNames := make([]string, 0)
  343 + // open zip file
  344 + reader, err := zip.OpenReader(zipPath)
  345 + if err != nil {
  346 + return fileNames, err
  347 + }
  348 + defer reader.Close()
  349 +
  350 + for _, file := range reader.File {
  351 + if err := controller.unzipFile(file, dstDir); err != nil {
  352 + return fileNames, err
  353 + } else {
  354 + fileNames = append(fileNames, file.Name)
  355 + }
  356 + }
  357 + return fileNames, nil
  358 +}
  359 +
  360 +// 解析文件并插入数据
  361 +func (controller *ImportController) parserAndInsert(file *os.File) error {
  362 + reader, err := excelize.OpenReader(file)
  363 + if err != nil {
  364 + return application.ThrowError(application.INTERNAL_SERVER_ERROR, "上传错误:"+err.Error())
  365 + }
  366 + index := reader.GetActiveSheetIndex()
  367 + rows, err := reader.GetRows(reader.GetSheetName(index))
  368 + if err != nil {
  369 + return application.ThrowError(application.INTERNAL_SERVER_ERROR, "读取excel错误:"+err.Error())
  370 + }
  371 + dimensions, err := domain.LoadPerformanceDimensions(rows)
  372 + if err != nil {
  373 + return application.ThrowError(application.ARG_ERROR, err.Error())
  374 + }
  375 + if err, list := controller.parseTemplateNodeContent(dimensions); err != nil {
  376 + return application.ThrowError(application.ARG_ERROR, err.Error())
  377 + } else {
  378 + if len(list) == 0 {
  379 + return application.ThrowError(application.ARG_ERROR, "没有数据内容")
  380 + }
  381 +
  382 + ruService := service.NewEvaluationTemplateService()
  383 + in := &templateCommand.CreateTemplateCommand{}
  384 +
  385 + ua := middlewares.GetUser(controller.Ctx)
  386 + in.CompanyId = ua.CompanyId
  387 + in.CreatorId = ua.UserId
  388 + in.Name = file.Name()
  389 + in.Describe = ""
  390 + in.NodeContents = list
  391 +
  392 + if _, err := ruService.Create(in); err != nil {
  393 + return application.ThrowError(application.ARG_ERROR, "数据创建错误")
  394 + }
  395 + }
  396 + return nil
  397 +}
  398 +
  399 +func (controller *ImportController) unzipFile(file *zip.File, dstDir string) error {
  400 + // create the directory of file
  401 + filePath := path.Join(dstDir, file.Name)
  402 + if file.FileInfo().IsDir() {
  403 + if err := os.MkdirAll(filePath, os.ModePerm); err != nil {
  404 + return err
  405 + }
  406 + return nil
  407 + }
  408 + if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
  409 + return err
  410 + }
  411 +
  412 + // open the file
  413 + rc, err := file.Open()
  414 + if err != nil {
  415 + return err
  416 + }
  417 + defer rc.Close()
  418 +
  419 + // create the file
  420 + w, err := os.Create(filePath)
  421 + if err != nil {
  422 + return err
  423 + }
  424 + defer w.Close()
  425 +
  426 + // save the decompressed file content
  427 + _, err = io.Copy(w, rc)
  428 + return err
  429 +}
@@ -11,6 +11,8 @@ func init() { @@ -11,6 +11,8 @@ func init() {
11 ns := web.NewNamespace("/v1/import", 11 ns := web.NewNamespace("/v1/import",
12 web.NSBefore(filters.AllowCors(), middlewares.CheckAdminToken()), 12 web.NSBefore(filters.AllowCors(), middlewares.CheckAdminToken()),
13 web.NSRouter("/", &controllers.ImportController{}, "Post:Import"), 13 web.NSRouter("/", &controllers.ImportController{}, "Post:Import"),
  14 + web.NSRouter("/zip", &controllers.ImportController{}, "Post:ZipImport"),
  15 + web.NSRouter("/zip-verify", &controllers.ImportController{}, "Post:ZipVerify"),
14 ) 16 )
15 web.AddNamespace(ns) 17 web.AddNamespace(ns)
16 } 18 }