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

承诺一时的华丽 · · 2014 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

项目架构: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导入数据并标注此行背景色和异常数据提示暂时

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2014 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传