package controllers import ( "archive/zip" "bufio" "bytes" "encoding/json" "fmt" service "gitlab.fjmaimaimai.com/allied-creation/performance/pkg/application/evaluation_template" templateCommand "gitlab.fjmaimaimai.com/allied-creation/performance/pkg/application/evaluation_template/command" "gitlab.fjmaimaimai.com/allied-creation/performance/pkg/application/import/command" "gitlab.fjmaimaimai.com/allied-creation/performance/pkg/constant" "gitlab.fjmaimaimai.com/allied-creation/performance/pkg/infrastructure/xredis" "gitlab.fjmaimaimai.com/allied-creation/performance/pkg/utils" "golang.org/x/text/encoding/simplifiedchinese" "golang.org/x/text/transform" "io" "io/ioutil" "mime/multipart" "os" "path" "path/filepath" "strconv" "strings" "time" "github.com/linmadan/egglib-go/core/application" "github.com/linmadan/egglib-go/utils/tool_funs" "github.com/linmadan/egglib-go/web/beego" "github.com/xuri/excelize/v2" "gitlab.fjmaimaimai.com/allied-creation/performance/pkg/application/factory" "gitlab.fjmaimaimai.com/allied-creation/performance/pkg/domain" "gitlab.fjmaimaimai.com/allied-creation/performance/pkg/port/beego/middlewares" ) type ImportController struct { beego.BaseController } func (controller *ImportController) Import() { _, header, err := controller.GetFile("file") if err != nil { controller.Response(nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "上传错误:"+err.Error())) return } file, err := header.Open() if err != nil { controller.Response(nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "上传错误:"+err.Error())) return } reader, err := excelize.OpenReader(file) if err != nil { controller.Response(nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "上传错误:"+err.Error())) return } index := reader.GetActiveSheetIndex() rows, err := reader.GetRows(reader.GetSheetName(index)) if err != nil { controller.Response(nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "读取excel错误:"+err.Error())) return } formType := controller.GetString("type") switch formType { case "PerformanceDimension": dimensions, err := domain.LoadPerformanceDimensions(rows) if err != nil { controller.Response(nil, application.ThrowError(application.ARG_ERROR, err.Error())) } if err, list := controller.parseTemplateNodeContent(dimensions); err != nil { controller.Response(nil, application.ThrowError(application.ARG_ERROR, err.Error())) } else { controller.Response(tool_funs.SimpleWrapGridMap(int64(len(list)), list), nil) } default: controller.Response(nil, application.ThrowError(application.ARG_ERROR, "请确认您导入的表单类型")) } } func (controller *ImportController) parseTemplateNodeContent(data []*domain.PerformanceDimension) (error, []*domain.NodeContent) { nodeContents := make([]*domain.NodeContent, 0) transactionContext, err := factory.StartTransaction() if err != nil { return err, nodeContents } defer func() { transactionContext.RollbackTransaction() }() // 获取当前公司下的默认规则 ua := middlewares.GetUser(controller.Ctx) // 系统默认规则确认 ruleRepository := factory.CreateEvaluationRuleRepository(map[string]interface{}{"transactionContext": transactionContext}) _, rules, err := ruleRepository.Find(map[string]interface{}{"companyId": ua.CompanyId, "sysType": domain.EvaluationSysTypeSystem, "limit": 1}) if err != nil { return err, nodeContents } var ruleId = int64(0) if len(rules) == 0 { newRule := domain.GenerateSysRule(ua.CompanyId) // 生成一个系统默认规则 if rule, err := ruleRepository.Insert(newRule); err != nil { return err, nodeContents } else { ruleId = rule.Id } if err := transactionContext.CommitTransaction(); err != nil { return err, nodeContents } } else { ruleId = rules[0].Id } // 评估内容主导人名称 evaluatorNames := make([]string, 0) evaluatorMap := map[string]string{} weightTotal := 0.0 for i := range data { dimension := data[i] for i2 := range dimension.PerformanceModule { nc := &domain.NodeContent{} nc.Category = dimension.Name // 类别 module := dimension.PerformanceModule[i2] nc.Name = module.ModuleName // 名称 nc.RuleId = ruleId // 规则ID sIndex := strings.Index(module.Weight, "%") // 权重 if sIndex != -1 { iWeight, _ := strconv.ParseFloat(module.Weight[:sIndex], 64) nc.Weight = iWeight } else { nc.Weight = 0 } weightTotal += nc.Weight // 总权重 nc.PromptTitle = "" // 提示项标题 nc.PromptText = module.Standard // 提示项内容 nc.EntryItems = make([]*domain.EntryItem, 0) // 输入项 for i3 := range module.Target { target := module.Target[i3] nc.EntryItems = append(nc.EntryItems, &domain.EntryItem{ Title: target.Task, // 输入型标题 HintText: "", // 输入项提示文本 Definition: target.Definition, //定义 }) } // 没有任何输入项时,默认1个 if len(nc.EntryItems) == 0 { nc.EntryItems = append(nc.EntryItems, &domain.EntryItem{ Title: "填写反馈", HintText: "", }) } // 必填项 nc.Required = module.Required // 项目评估人 if module.Evaluator == "HRBP" { nc.EvaluatorId = -1 } else { if len(module.Evaluator) > 0 { evaluatorNames = append(evaluatorNames, module.Evaluator) // 项目评估人名称数组 evaluatorMap[nc.Category+nc.Name] = module.Evaluator // k,v = (类别+名称, 项目评估人名称) } } // 指标类型(0指标、1任务) nc.IndicatorType = module.IndicatorType nodeContents = append(nodeContents, nc) } } // 权重总数不等于100%,提示报错 if weightTotal != 100 { sprintf := fmt.Sprintf("当前导入的总权重值为:%s%%(必须等于100%%)", utils.FormatFloatDecimal(weightTotal, 2)) return application.ThrowError(application.INTERNAL_SERVER_ERROR, sprintf), nodeContents } if len(evaluatorNames) > 0 { userRepository := factory.CreateUserRepository(map[string]interface{}{"transactionContext": transactionContext}) _, users, err := userRepository.Find(map[string]interface{}{"companyId": ua.CompanyId, "names": evaluatorNames}) if err != nil { return err, nodeContents } nameIdMap := map[string]int64{} for i := range users { nameIdMap[users[i].Name] = users[i].Id } // 名称 -> ID var nc *domain.NodeContent for i := range nodeContents { nc = nodeContents[i] if nc.EvaluatorId == -1 { // HRBP continue } if evaluatorName, ok := evaluatorMap[nc.Category+nc.Name]; ok { if userId, ok := nameIdMap[evaluatorName]; ok { nc.EvaluatorId = userId } } } } return nil, nodeContents } func (controller *ImportController) ZipVerify() { in := &command.VerifyKeyCommand{} if err := controller.Unmarshal(in); err != nil { controller.Response(nil, application.ThrowError(application.ARG_ERROR, err.Error())) } else { bytes, err := xredis.GetBytes(in.VerifyKey) if err == nil { out := &command.OutResult{} err = json.Unmarshal(bytes, out) if err == nil { controller.Response(out, nil) return } } // 有异常直接返回完成标记 if err != nil { out := &command.OutResult{} out.Status = "completed" controller.Response(out, nil) } } } func (controller *ImportController) ZipImport() { _, header, err := controller.GetFile("file") if err != nil { controller.Response(nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "上传错误:"+err.Error())) return } file, err := header.Open() if err != nil { controller.Response(nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "文件错误:"+err.Error())) return } // 写入本地 zipPath, day, id, err := controller.writeLocal(file) if err != nil { controller.Response(nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())) return } out := command.OutResult{ Status: "uncompleted", Success: make([]command.ErrorI, 0), Failure: make([]command.ErrorI, 0), } key := xredis.CreateUploadZipKey(id) _ = xredis.Set(key, out, 2*time.Hour) controller.Response(map[string]string{"key": key}, nil) go func() { // 解压目标文件夹 dstDir := constant.UPLOAD_ZIP_PATH + "/" + day + "-" + id fileNames, err := controller.Unzip(zipPath, dstDir) if err != nil { _ = xredis.Remove(key) _ = os.RemoveAll(dstDir) } else { success := make([]command.ErrorI, 0) failure := make([]command.ErrorI, 0) for i := range fileNames { fn := fileNames[i] f, err := os.Open(path.Join(dstDir, fn)) if err != nil { failure = append(failure, command.ErrorI{ FileName: fn, Message: err.Error(), }) continue } if err = controller.parserAndInsert(f, fn); err != nil { failure = append(failure, command.ErrorI{ FileName: fn, Message: err.Error(), }) } else { success = append(success, command.ErrorI{ FileName: fn, Message: "", }) } } // 解析完成 out = command.OutResult{ Status: "completed", Success: success, Failure: failure, } // 30分钟后失效 _ = xredis.Set(key, out, 30*time.Minute) // 删除临时文件夹 _ = os.RemoveAll(dstDir) } }() } func (controller *ImportController) writeLocal(file multipart.File) (string, string, string, error) { var err error id, err := utils.NewSnowflakeId() if err != nil { return "", "", "", err } id2 := fmt.Sprintf("%v", id) day := time.Now().Format("2006-01-02") zipPath := constant.UPLOAD_ZIP_PATH + "/" + day + "-" + id2 + "/" + "temp" var fd *os.File dir := filepath.Dir(zipPath) err = os.MkdirAll(dir, os.ModePerm) if err != nil { return "", "", "", err } fd, err = os.OpenFile(zipPath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666) if err != nil { return "", "", "", err } defer func(fd *os.File) { if err = fd.Close(); err != nil { } }(fd) wt := bufio.NewWriter(fd) _, err = file.Seek(0, io.SeekStart) if err != nil { return "", "", "", err } _, err = io.Copy(wt, file) if err != nil { return "", "", "", err } err = wt.Flush() if err != nil { return "", "", "", err } return zipPath, day, id2, err } func (controller *ImportController) Unzip(zipPath, dstDir string) ([]string, error) { // 文件名称 fileNames := make([]string, 0) // open zip file reader, err := zip.OpenReader(zipPath) if err != nil { return fileNames, err } defer reader.Close() var decodeName string for _, f := range reader.File { if f.Flags == 0 { // 如果标致位是0,则是默认的本地编码(默认为gbk),如果标志为是 1 << 11也就是 2048(则是utf-8编码) r := bytes.NewReader([]byte(f.Name)) decoder := transform.NewReader(r, simplifiedchinese.GB18030.NewDecoder()) content, _ := ioutil.ReadAll(decoder) decodeName = string(content) } else { decodeName = f.Name } if err := controller.unzipFile(f, decodeName, dstDir); err != nil { return fileNames, err } else { if !(f.FileInfo().IsDir()) { fileNames = append(fileNames, decodeName) } } } return fileNames, nil } // 解析文件并插入数据 func (controller *ImportController) parserAndInsert(file *os.File, fileName string) error { defer func() { err := file.Close() if err != nil { return } }() reader, err := excelize.OpenReader(file) if err != nil { return application.ThrowError(application.INTERNAL_SERVER_ERROR, "上传错误:"+err.Error()) } index := reader.GetActiveSheetIndex() rows, err := reader.GetRows(reader.GetSheetName(index)) if err != nil { return application.ThrowError(application.INTERNAL_SERVER_ERROR, "读取excel错误:"+err.Error()) } dimensions, err := domain.LoadPerformanceDimensions(rows) if err != nil { return application.ThrowError(application.ARG_ERROR, err.Error()) } if err, list := controller.parseTemplateNodeContent(dimensions); err != nil { return application.ThrowError(application.ARG_ERROR, err.Error()) } else { if len(list) == 0 { return application.ThrowError(application.ARG_ERROR, "没有数据内容") } var nameWithSuffix = path.Base(fileName) var suffix = path.Ext(nameWithSuffix) var nameOnly = strings.TrimSuffix(nameWithSuffix, suffix) ruService := service.NewEvaluationTemplateService() in := &templateCommand.CreateTemplateCommand{} ua := middlewares.GetUser(controller.Ctx) in.CompanyId = ua.CompanyId in.CreatorId = ua.UserId in.Name = nameOnly in.Describe = "" in.NodeContents = list in.State = domain.TemplateStateWaitActive if _, err := ruService.Create(in); err != nil { return application.ThrowError(application.ARG_ERROR, err.Error()) } } return nil } func (controller *ImportController) unzipFile(f *zip.File, fName string, dstDir string) error { // create the directory of file filePath := path.Join(dstDir, fName) if f.FileInfo().IsDir() { if err := os.MkdirAll(filePath, os.ModePerm); err != nil { return err } return nil } if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil { return err } // open the file rc, err := f.Open() if err != nil { return err } defer rc.Close() // create the file w, err := os.Create(filePath) if err != nil { return err } defer w.Close() // save the decompressed file content _, err = io.Copy(w, rc) return err }