Golang Excel導(dǎo)入數(shù)據(jù)并標(biāo)注此行背景色和異常數(shù)據(jù)提示暫時(shí)

項(xiàng)目架構(gòu):Echo+Gorm+excelize
依賴開源項(xiàng)目:github.com/360EntSecGroup-Skylar/excelize
開源項(xiàng)目中文文檔: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, "請(qǐng)上傳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錯(cuò)誤樣式,黃色背景
    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
        //模板錯(cuò)誤
    if len(rows) <= 2 {
        return utils.ErrorNull(c, "excel格式錯(cuò)誤或無有效數(shù)據(jù)")
    }
        //無有效數(shù)據(jù)
    if len(rows[2]) < 25 {
        return utils.ErrorNull(c, "excel格式錯(cuò)誤或無有效數(shù)據(jù)")
    }
    for rIndex, row := range rows {
        //跳過提示行蝴罪、標(biāo)題行
        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, "姓名字符過長(zhǎng)")
            }

            //性別
            account.Gender = utils.Trim(row[1])
            if account.Gender == "" {
                errorMsg = append(errorMsg, "性別為必填項(xiàng)")
            } else if account.Gender != enum.GENDER_MALE && account.Gender != enum.GENDER_FEMALE {
                errorMsg = append(errorMsg, "性別錯(cuò)誤疾渴,值范圍:男、女")
            }

            //手機(jī)號(hào)
            account.Mobile = utils.Trim(row[2])
            if account.Mobile == "" {
                errorMsg = append(errorMsg, "手機(jī)號(hào)碼為必填項(xiàng)")
            } else if !utils.IsMobile(account.Mobile) {
                errorMsg = append(errorMsg, "手機(jī)號(hào)碼格式錯(cuò)誤")
            }
            account.Name = account.Mobile
            
            //出生日期
            dateStr = utils.Trim(row[3])
            account.DateOfBirth, err = utils.ParseExcelDate(dateStr)
            if err != nil {
                errorMsg = append(errorMsg, "出生日期格式錯(cuò)誤")
            }

            //在崗狀態(tài)
            accountInfo.WorkStatus = utils.Trim(row[4])
            switch accountInfo.WorkStatus {
            case "在崗", "待聘人員", "農(nóng)民工", "停薪留職", "排休人員", "離退休", "其他", "":
                break
            default:
                errorMsg = append(errorMsg, "在崗狀態(tài)錯(cuò)誤,值范圍:在崗, 待聘人員, 農(nóng)民工, 停薪留職, 排休人員, 離退休, 其他")
                break
            }

            //民族
            accountInfo.Nation = utils.Trim(row[5])
            if len(accountInfo.Nation) > 50 {
                errorMsg = append(errorMsg, "民族字符串過長(zhǎng)")
            }

            //籍貫
            accountInfo.NativePlace = utils.Trim(row[6])
            if len(accountInfo.Nation) > 100 {
                errorMsg = append(errorMsg, "籍貫字符串過長(zhǎng)")
            }

            //身份證
            accountInfo.Idcard = utils.Trim(row[7])

            if accountInfo.Idcard != "" {
                if len(accountInfo.Idcard) != 15 && len(accountInfo.Idcard) != 18 {
                    errorMsg = append(errorMsg, "身份證格式錯(cuò)誤僅,支持15、18位")
                }
            }
            //學(xué)歷
            accountInfo.Education = utils.Trim(row[8])
            switch accountInfo.Education {
            case "博士", "碩士", "本科", "屃鲂洌科", "高中及以下", "":
                break
            default:
                errorMsg = append(errorMsg, "學(xué)歷錯(cuò)誤,值范圍:博士,碩士,本科,尠貉椋科,高中及以下")
                break
            }

            //人員類型
            accountInfo.PersonnelType = utils.Trim(row[9])
            if accountInfo.PersonnelType != "" {
                switch accountInfo.PersonnelType {
                case "正式黨員", "預(yù)備黨員", "":
                    break
                default:
                    errorMsg = append(errorMsg, "學(xué)歷錯(cuò)誤捂敌,值范圍:正式黨員,預(yù)備黨員")
                    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, "黨支部為必填項(xiàng)")
            }

            //黨內(nèi)職務(wù)
            tempStr = utils.Trim(row[11])
            if tempStr != "" {
                partyPost, err = GetPartyPostByName(partyId, tempStr)
                if err != nil {
                    errorMsg = append(errorMsg, "黨內(nèi)職務(wù)不存在")
                } else {
                    accountInfo.PartyPostId = partyPost.ID
                }
            }

            //轉(zhuǎn)為預(yù)備黨員日期
            dateStr = utils.Trim(row[12])
            accountInfo.TurnPreparePartyDate, err = utils.ParseExcelDate(dateStr)
            if err != nil {
                errorMsg = append(errorMsg, "轉(zhuǎn)為預(yù)備黨員日期格式錯(cuò)誤")
            }

            //轉(zhuǎn)為正式黨員日期
            dateStr = utils.Trim(row[13])
            accountInfo.TurnPartyDate, err = utils.ParseExcelDate(dateStr)
            if err != nil {
                errorMsg = append(errorMsg, "轉(zhuǎn)為正式黨員日期格式錯(cuò)誤")
            }

            //工作崗位
            accountInfo.Post = utils.Trim(row[14])
            if len(accountInfo.Post) >= 50 {
                errorMsg = append(errorMsg, "工作崗位字符過長(zhǎng)")
            }

            //稅后工資
            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, "稅后工資格式錯(cuò)誤")
                }
            }
            //固定電話
            accountInfo.Phone = utils.Trim(row[16])
            if len(accountInfo.Phone) >= 30 {
                errorMsg = append(errorMsg, "固定電話字符過長(zhǎng)")
            }

            //家庭地址
            accountInfo.HomeAddress = utils.Trim(row[17])
            if len(accountInfo.HomeAddress) >= 255 {
                errorMsg = append(errorMsg, "家庭地址字符過長(zhǎng)")
            }

            //黨籍狀態(tài)
            accountInfo.PartyStatus = utils.Trim(row[18])
            switch accountInfo.PartyStatus {
            case "正常", "異常", "":
                break
            default:
                errorMsg = append(errorMsg, "黨籍狀態(tài)錯(cuò)誤,值范圍:正常既琴、異常")
                break
            }

            //是否為失聯(lián)黨員
            accountInfo.PartyLostStatus = utils.Trim(row[19])
            switch accountInfo.PartyLostStatus {
            case "是", "否", "":
                break
            default:
                errorMsg = append(errorMsg, "是否為失聯(lián)黨員錯(cuò)誤黍匾,值范圍:是、否")
                break
            }

            //失去聯(lián)系的日期
            dateStr = utils.Trim(row[20])
            accountInfo.PartyLostDate, err = utils.ParseExcelDate(dateStr)
            if err != nil {
                errorMsg = append(errorMsg, "失去聯(lián)系的日期格式錯(cuò)誤")
            }

            //是否為流動(dòng)黨員
            accountInfo.PartyFlowStatus = utils.Trim(row[21])
            switch accountInfo.PartyFlowStatus {
            case "是", "否", "":
                break
            default:
                errorMsg = append(errorMsg, "是否為流動(dòng)黨員錯(cuò)誤呛梆,值范圍:是、否")
                break
            }

            //外出流向
            accountInfo.OutgoingFlow = utils.Trim(row[22])
            if len(accountInfo.OutgoingFlow) >= 500 {
                errorMsg = append(errorMsg, "外出流向字符過長(zhǎng)")
            }

            //申請(qǐng)入黨日期
            dateStr = utils.Trim(row[23])
            accountInfo.PartyApplyDate, err = utils.ParseExcelDate(dateStr)
            if err != nil {
                errorMsg = append(errorMsg, "申請(qǐng)入黨日期格式錯(cuò)誤")
            }

            //列為積極分子日期
            dateStr = utils.Trim(row[24])
            accountInfo.PartyActivistDate, err = utils.ParseExcelDate(dateStr)
            if err != nil {
                errorMsg = append(errorMsg, "列為積極分子日期格式錯(cuò)誤")
            }

            //列為發(fā)展對(duì)象日期
            dateStr = utils.Trim(row[25])
            accountInfo.PartyDevelopDate, err = utils.ParseExcelDate(dateStr)
            if err != nil {
                errorMsg = append(errorMsg, "列為發(fā)展對(duì)象日期格式錯(cuò)誤")
            }

            //判斷手機(jī)號(hào)碼是否存在
            acc, _ := GetAccountByMobile(account.Mobile)
            if acc.ID > 0 {
                errorMsg = append(errorMsg, "手機(jī)號(hào)碼已存在")
            }

            if len(errorMsg) > 0 {
                //錯(cuò)誤記錄
                xlsx.SetCellDefault(sheetName, fmt.Sprintf("AA%v", rIndex+1), strings.Join(errorMsg, ";\r\n"))
                errorMap[rIndex] = errorMsg
            } else {
                //添加的默認(rèn)數(shù)據(jù)
                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

                //數(shù)據(jù)保存 
                if err := saveImportAccount(account, accountInfo); err != nil {
                    //保存失敗錯(cuò)誤處理
                    errorMsg = append(errorMsg, err.Error())
                    xlsx.SetCellDefault(sheetName, fmt.Sprintf("AA%v", rIndex+1), strings.Join(errorMsg, ";\r\n"))
                    errorMap[rIndex] = errorMsg
                }
            }
            //如果有錯(cuò)誤磕诊,將背景設(shè)為警示顏色
            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 {
        //固定的標(biāo)題欄位置
        xlsx.SetCellDefault(sheetName, "AA2", "錯(cuò)誤說明")
        xlsx.Save()
        return utils.Confirm(c, "導(dǎo)入數(shù)據(jù)異常填物,請(qǐng)下載excel根據(jù)最后一列的錯(cuò)誤說明進(jìn)行修改調(diào)整", fmt.Sprintf("%s", path))
    }
    //需要自己處理返回
    return utils.SuccessNull(c, "導(dǎo)入成功")
}

func saveImportAccount(account *model.Account, accountInfo *model.AccountInfo) error {
    //保存事務(wù)
    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("初始化事務(wù)失敗:%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("導(dǎo)入黨員失旜铡:%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("導(dǎo)入黨員詳細(xì)信息失斨突恰:%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')))
}

//已處理數(shù)字型日期
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
}
 
//字符串日期轉(zhuǎn)換
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)
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子阅茶,更是在濱河造成了極大的恐慌蛛枚,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,561評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件脸哀,死亡現(xiàn)場(chǎng)離奇詭異蹦浦,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)撞蜂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門盲镶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蝌诡,你說我怎么就攤上這事溉贿。” “怎么了浦旱?”我有些...
    開封第一講書人閱讀 157,162評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵宇色,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我闽寡,道長(zhǎng)代兵,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,470評(píng)論 1 283
  • 正文 為了忘掉前任爷狈,我火速辦了婚禮植影,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘涎永。我一直安慰自己思币,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,550評(píng)論 6 385
  • 文/花漫 我一把揭開白布羡微。 她就那樣靜靜地躺著谷饿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪妈倔。 梳的紋絲不亂的頭發(fā)上博投,一...
    開封第一講書人閱讀 49,806評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音盯蝴,去河邊找鬼毅哗。 笑死,一個(gè)胖子當(dāng)著我的面吹牛捧挺,可吹牛的內(nèi)容都是我干的虑绵。 我是一名探鬼主播,決...
    沈念sama閱讀 38,951評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼闽烙,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼翅睛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,712評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤捕发,失蹤者是張志新(化名)和其女友劉穎疏旨,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體爬骤,經(jīng)...
    沈念sama閱讀 44,166評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡充石,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,510評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了霞玄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片骤铃。...
    茶點(diǎn)故事閱讀 38,643評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖坷剧,靈堂內(nèi)的尸體忽然破棺而出惰爬,到底是詐尸還是另有隱情,我是刑警寧澤惫企,帶...
    沈念sama閱讀 34,306評(píng)論 4 330
  • 正文 年R本政府宣布撕瞧,位于F島的核電站,受9級(jí)特大地震影響狞尔,放射性物質(zhì)發(fā)生泄漏丛版。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,930評(píng)論 3 313
  • 文/蒙蒙 一偏序、第九天 我趴在偏房一處隱蔽的房頂上張望页畦。 院中可真熱鬧,春花似錦研儒、人聲如沸豫缨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)好芭。三九已至,卻和暖如春冲呢,著一層夾襖步出監(jiān)牢的瞬間舍败,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工敬拓, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留邻薯,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,351評(píng)論 2 360
  • 正文 我出身青樓恩尾,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親挽懦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子翰意,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,509評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容