美文网首页
Golang Excel导入数据并标注此行背景色和异常数据提示暂

Golang Excel导入数据并标注此行背景色和异常数据提示暂

作者: 承诺一时的华丽 | 来源:发表于2018-09-14 17:57 被阅读133次

    项目架构:Echo+Gorm+excelize
    依赖开源项目:github.com/360EntSecGroup-Skylar/excelize
    开源项目中文文档:https://xuri.me/excelize/zh-hans/

    excel模板

    image.png
    func ImportAccountByExcel(c echo.Context) error {
        //文件地址
        path := c.FormValue("path")
        if path == "" {
            return utils.ErrorNull(c, "请上传excel文件")
        }
        path = strings.TrimLeft(path, "/")
        if flag, _ := utils.PathExists(path); !flag {
            return utils.ErrorNull(c, "未找到excel文件")
        }
        //path := "files/excel/account_template_test.xlsx"
        //excel表
        sheetName := "Sheet1"
        xlsx, err := excelize.OpenFile(path)
        if err != nil {
            return utils.ErrorNull(c, fmt.Sprintf("打开excel失败,error:%s", err.Error()))
        }
            
        //excel错误样式,黄色背景
        style, _ := xlsx.NewStyle(`{"border":[{"type":"left","color":"000000","style":1},{"type":"top","color":"000000","style":1},{"type":"bottom","color":"000000","style":1},{"type":"right","color":"000000","style":1}],"fill":{"type":"pattern","color":["#ffeb00"],"pattern":1},"alignment":{"horizontal":"left","ident":1,"vertical":"center","wrap_text":true}}`)
            //sheet名称
        rows := xlsx.GetRows(sheetName)
    
        var ip = c.RealIP()
        var now = time.Now()
        var partyId int64 = 1
        var account *model.Account
        var accountInfo *model.AccountInfo
        var dateStr, tempStr string
        var errorMap = map[int]interface{}{}
        var errorMsg []string
        var org model.PartyOrg
        var partyPost model.PartyPost
            //模板错误
        if len(rows) <= 2 {
            return utils.ErrorNull(c, "excel格式错误或无有效数据")
        }
            //无有效数据
        if len(rows[2]) < 25 {
            return utils.ErrorNull(c, "excel格式错误或无有效数据")
        }
        for rIndex, row := range rows {
            //跳过提示行、标题行
            if rIndex != 0 && rIndex != 1 {
                errorMsg = []string{}
                accountInfo = new(model.AccountInfo)
                account = new(model.Account)
                //姓名
                account.FullName = utils.Trim(row[0])
                if account.FullName == "" {
                    errorMsg = append(errorMsg, "姓名不能为空")
                } else if len(account.FullName) >= 50 {
                    errorMsg = append(errorMsg, "姓名字符过长")
                }
    
                //性别
                account.Gender = utils.Trim(row[1])
                if account.Gender == "" {
                    errorMsg = append(errorMsg, "性别为必填项")
                } else if account.Gender != enum.GENDER_MALE && account.Gender != enum.GENDER_FEMALE {
                    errorMsg = append(errorMsg, "性别错误,值范围:男、女")
                }
    
                //手机号
                account.Mobile = utils.Trim(row[2])
                if account.Mobile == "" {
                    errorMsg = append(errorMsg, "手机号码为必填项")
                } else if !utils.IsMobile(account.Mobile) {
                    errorMsg = append(errorMsg, "手机号码格式错误")
                }
                account.Name = account.Mobile
                
                //出生日期
                dateStr = utils.Trim(row[3])
                account.DateOfBirth, err = utils.ParseExcelDate(dateStr)
                if err != nil {
                    errorMsg = append(errorMsg, "出生日期格式错误")
                }
    
                //在岗状态
                accountInfo.WorkStatus = utils.Trim(row[4])
                switch accountInfo.WorkStatus {
                case "在岗", "待聘人员", "农民工", "停薪留职", "排休人员", "离退休", "其他", "":
                    break
                default:
                    errorMsg = append(errorMsg, "在岗状态错误,值范围:在岗, 待聘人员, 农民工, 停薪留职, 排休人员, 离退休, 其他")
                    break
                }
    
                //民族
                accountInfo.Nation = utils.Trim(row[5])
                if len(accountInfo.Nation) > 50 {
                    errorMsg = append(errorMsg, "民族字符串过长")
                }
    
                //籍贯
                accountInfo.NativePlace = utils.Trim(row[6])
                if len(accountInfo.Nation) > 100 {
                    errorMsg = append(errorMsg, "籍贯字符串过长")
                }
    
                //身份证
                accountInfo.Idcard = utils.Trim(row[7])
    
                if accountInfo.Idcard != "" {
                    if len(accountInfo.Idcard) != 15 && len(accountInfo.Idcard) != 18 {
                        errorMsg = append(errorMsg, "身份证格式错误仅,支持15、18位")
                    }
                }
                //学历
                accountInfo.Education = utils.Trim(row[8])
                switch accountInfo.Education {
                case "博士", "硕士", "本科", "专科", "高中及以下", "":
                    break
                default:
                    errorMsg = append(errorMsg, "学历错误,值范围:博士,硕士,本科,专科,高中及以下")
                    break
                }
    
                //人员类型
                accountInfo.PersonnelType = utils.Trim(row[9])
                if accountInfo.PersonnelType != "" {
                    switch accountInfo.PersonnelType {
                    case "正式党员", "预备党员", "":
                        break
                    default:
                        errorMsg = append(errorMsg, "学历错误,值范围:正式党员,预备党员")
                        break
                    }
                }
    
                //党支部
                tempStr = utils.Trim(row[10])
                if tempStr != "" {
                    org, err = GetPartyOrgByName(partyId, tempStr)
                    if err != nil {
                        errorMsg = append(errorMsg, "党支部不存在")
                    } else {
                        account.OrgId = org.ID
                    }
                } else {
                    errorMsg = append(errorMsg, "党支部为必填项")
                }
    
                //党内职务
                tempStr = utils.Trim(row[11])
                if tempStr != "" {
                    partyPost, err = GetPartyPostByName(partyId, tempStr)
                    if err != nil {
                        errorMsg = append(errorMsg, "党内职务不存在")
                    } else {
                        accountInfo.PartyPostId = partyPost.ID
                    }
                }
    
                //转为预备党员日期
                dateStr = utils.Trim(row[12])
                accountInfo.TurnPreparePartyDate, err = utils.ParseExcelDate(dateStr)
                if err != nil {
                    errorMsg = append(errorMsg, "转为预备党员日期格式错误")
                }
    
                //转为正式党员日期
                dateStr = utils.Trim(row[13])
                accountInfo.TurnPartyDate, err = utils.ParseExcelDate(dateStr)
                if err != nil {
                    errorMsg = append(errorMsg, "转为正式党员日期格式错误")
                }
    
                //工作岗位
                accountInfo.Post = utils.Trim(row[14])
                if len(accountInfo.Post) >= 50 {
                    errorMsg = append(errorMsg, "工作岗位字符过长")
                }
    
                //税后工资
                tempStr = utils.Trim(row[15])
                if tempStr != "" {
                    accountInfo.AfterTaxWages, err = convert.ToFloat64(utils.Trim(row[15]))
                    if err != nil || accountInfo.AfterTaxWages < 0 {
                        errorMsg = append(errorMsg, "税后工资格式错误")
                    }
                }
                //固定电话
                accountInfo.Phone = utils.Trim(row[16])
                if len(accountInfo.Phone) >= 30 {
                    errorMsg = append(errorMsg, "固定电话字符过长")
                }
    
                //家庭地址
                accountInfo.HomeAddress = utils.Trim(row[17])
                if len(accountInfo.HomeAddress) >= 255 {
                    errorMsg = append(errorMsg, "家庭地址字符过长")
                }
    
                //党籍状态
                accountInfo.PartyStatus = utils.Trim(row[18])
                switch accountInfo.PartyStatus {
                case "正常", "异常", "":
                    break
                default:
                    errorMsg = append(errorMsg, "党籍状态错误,值范围:正常、异常")
                    break
                }
    
                //是否为失联党员
                accountInfo.PartyLostStatus = utils.Trim(row[19])
                switch accountInfo.PartyLostStatus {
                case "是", "否", "":
                    break
                default:
                    errorMsg = append(errorMsg, "是否为失联党员错误,值范围:是、否")
                    break
                }
    
                //失去联系的日期
                dateStr = utils.Trim(row[20])
                accountInfo.PartyLostDate, err = utils.ParseExcelDate(dateStr)
                if err != nil {
                    errorMsg = append(errorMsg, "失去联系的日期格式错误")
                }
    
                //是否为流动党员
                accountInfo.PartyFlowStatus = utils.Trim(row[21])
                switch accountInfo.PartyFlowStatus {
                case "是", "否", "":
                    break
                default:
                    errorMsg = append(errorMsg, "是否为流动党员错误,值范围:是、否")
                    break
                }
    
                //外出流向
                accountInfo.OutgoingFlow = utils.Trim(row[22])
                if len(accountInfo.OutgoingFlow) >= 500 {
                    errorMsg = append(errorMsg, "外出流向字符过长")
                }
    
                //申请入党日期
                dateStr = utils.Trim(row[23])
                accountInfo.PartyApplyDate, err = utils.ParseExcelDate(dateStr)
                if err != nil {
                    errorMsg = append(errorMsg, "申请入党日期格式错误")
                }
    
                //列为积极分子日期
                dateStr = utils.Trim(row[24])
                accountInfo.PartyActivistDate, err = utils.ParseExcelDate(dateStr)
                if err != nil {
                    errorMsg = append(errorMsg, "列为积极分子日期格式错误")
                }
    
                //列为发展对象日期
                dateStr = utils.Trim(row[25])
                accountInfo.PartyDevelopDate, err = utils.ParseExcelDate(dateStr)
                if err != nil {
                    errorMsg = append(errorMsg, "列为发展对象日期格式错误")
                }
    
                //判断手机号码是否存在
                acc, _ := GetAccountByMobile(account.Mobile)
                if acc.ID > 0 {
                    errorMsg = append(errorMsg, "手机号码已存在")
                }
    
                if len(errorMsg) > 0 {
                    //错误记录
                    xlsx.SetCellDefault(sheetName, fmt.Sprintf("AA%v", rIndex+1), strings.Join(errorMsg, ";\r\n"))
                    errorMap[rIndex] = errorMsg
                } else {
                    //添加的默认数据
                    account.ID = utils.ID()
                    account.Status = enum.NORMAL
                    account.CTime = &now
                    account.UTime = account.CTime
                    account.PartyId = partyId
                    account.Ip = ip 
    
                    accountInfo.ID = utils.ID()
                    accountInfo.AccountId = account.ID
    
                    //数据保存 
                    if err := saveImportAccount(account, accountInfo); err != nil {
                        //保存失败错误处理
                        errorMsg = append(errorMsg, err.Error())
                        xlsx.SetCellDefault(sheetName, fmt.Sprintf("AA%v", rIndex+1), strings.Join(errorMsg, ";\r\n"))
                        errorMap[rIndex] = errorMsg
                    }
                }
                //如果有错误,将背景设为警示颜色
                if len(errorMsg) > 0 {
                    xlsx.SetCellStyle(sheetName, fmt.Sprintf("A%v", rIndex+1), fmt.Sprintf("AA%v", rIndex+1), style)
                }
                fmt.Println("-------------------------------------------------------------------------------------------")
            }
        }
    
        if len(errorMap) > 0 {
            //固定的标题栏位置
            xlsx.SetCellDefault(sheetName, "AA2", "错误说明")
            xlsx.Save()
            return utils.Confirm(c, "导入数据异常,请下载excel根据最后一列的错误说明进行修改调整", fmt.Sprintf("%s", path))
        }
        //需要自己处理返回
        return utils.SuccessNull(c, "导入成功")
    }
    
    func saveImportAccount(account *model.Account, accountInfo *model.AccountInfo) error {
        //保存事务
        tx := global.DB.Begin()
        defer func() {
            if r := recover(); r != nil {
                tx.Rollback()
            }
        }()
        if tx.Error != nil {
            global.Log.Error("tx error:%v", tx.Error.Error())
            return errors.New(fmt.Sprintf("初始化事务失败:%s", tx.Error.Error()))
        }
        if err := tx.Create(&account).Error; err != nil {
            tx.Rollback()
            global.Log.Error("tx create account error:%v", err)
            return errors.New(fmt.Sprintf("导入党员失败:%s", err.Error()))
        }
        if err := tx.Create(&accountInfo).Error; err != nil {
            tx.Rollback()
            global.Log.Error("tx create accountInfo error:%v", err)
            return errors.New(fmt.Sprintf("导入党员详细信息失败:%s", err.Error()))
        }
    
        if err := tx.Commit().Error; err != nil {
            global.Log.Error("commit error:%v", err)
            return errors.New(fmt.Sprintf("保存党员失败:%s", err.Error()))
        }
        return nil
    }
    
    //去除前后所有空格、空字符串、制表符
    func Trim(str string) string {
        if str == "" {
            return ""
        }
        return strings.TrimSpace(strings.TrimPrefix(str, string('\uFEFF')))
    }
    
    //已处理数字型日期
    func ParseExcelDate(date string) (d *time.Time, err error) {
        if date != "" {
            var date2 time.Time
            if !IsValidNumber(date) {
                date2, err = ParseDate(date)
                if err != nil {
                    return
                }
                d = &date2
                return
            } else {
                date2, err = ParseDate("1900-1-1")
                if err != nil {
                    return
                }
                days := convert.MustInt(date)
                date2 = date2.AddDate(0, 0, days-2)
                d = &date2
                return
            }
        }
        return
    }
     
    //字符串日期转换
    func ParseDate(date string) (time.Time, error) {
        date = strings.Replace(date, "/", "-", -1)
        date = strings.Replace(date, ".", "-", -1)
        date = strings.Replace(date, "-0", "-", -1)
        local, _ := time.LoadLocation("Local")
        return time.ParseInLocation("2006-1-2", date, local)
    }
    

    相关文章

      网友评论

          本文标题:Golang Excel导入数据并标注此行背景色和异常数据提示暂

          本文链接:https://www.haomeiwen.com/subject/oizogftx.html