package models import ( "errors" "fmt" "github.com/go-admin-team/go-admin-core/logger" "github.com/xuri/excelize/v2" "gorm.io/gorm" "math/rand" "strings" "time" ) const ( QueryTimeFormat = "2006-01-02T15:04:05+08:00" TimeFormat = "2006-01-02 15-04-05" ExportUrl = "https://admin.go2switch.cn/load/export/" ExportExcelFlag = 1 ExportPath = "/www/server/images/export/" ) var certMap = map[int]string{ 1: "电工证", 2: "焊工证", 3: "叉车证", 4: "制冷与空调作业证", 5: "高空作业证", 6: "危化品作业证", 7: "安全员证", 8: "其他工种上岗证", } var WhiteList = map[string]int{ "15019230751": 1, "18025373706": 2, } type SendDataReq struct { Url string `json:"url"` Uid string `json:"uid"` } type OppoSendDataReq struct { PageId int64 `json:"pageId"` OwnerId int64 `json:"ownerId"` Ip string `json:"ip"` Tid string `json:"tid"` Lbid string `json:"lbid"` Items []ClueDataItem `json:"items"` TransformType int `json:"transformType"` PageType int `json:"pageType,omitempty"` PayId string `json:"payId,omitempty"` PayAmount string `json:"payAmount,omitempty"` RefundId string `json:"refundId,omitempty"` Amount string `json:"amount,omitempty"` CustomId string `json:"customId,omitempty"` } type ClueDataItem struct { Column string `json:"column"` Type string `json:"type"` IfNeed bool `json:"ifNeed"` Desc string `json:"desc"` Value string `json:"value"` Options []string `json:"options,omitempty"` } type OppoSendDataResp struct { Code int `json:"code"` Msg string `json:"msg"` } type NewSendDataReq struct { Url string `json:"url" binding:"required"` // 页面url路径 Name string `json:"name" binding:"required"` // 姓名 Tel string `json:"tel" binding:"required"` // 电话 Type int `json:"type" binding:"required"` // 广告页类型 1-八大员;2-旅游 CertList []int `json:"cert_list"` // 证书列表:1-电工证,2-焊工证,3-叉车证,4-制冷与空调作业证,5-高空作业证,6-危化品作业证,7-安全员证,8-其他工种上岗证 Data interface{} `json:"data"` // 其他选择内容 } // TravelData 旅游广告页其他参数 type TravelData struct { TravelCount int `json:"travel_count"` // 出行人数 } type ClueUser struct { Model Name string `json:"name"` // 姓名 Tel string `json:"tel" gorm:"index"` // 电话 Cert string `json:"cert" gorm:"index"` // 证书列表 } type ClueUserTravel struct { Model Name string `json:"name"` // 姓名 Tel string `json:"tel" gorm:"index"` // 电话 } type GetUserDataReq struct { Name string `json:"name"` // 姓名 Tel string `json:"tel"` // 电话 StartTime string `json:"start_time"` // 开始时间 EndTime string `json:"end_time"` // 结束时间 Type int `json:"type"` // 广告页类型 1-八大员;2-旅游 IsExport uint32 `json:"is_export"` // 1-导出 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 页面条数 } type GetUserDataResp struct { Total int64 `json:"total"` // 总条数 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 页面条数 ExportUrl string `json:"export_url"` // 导出excel地址 List []ClueUser `json:"list"` } type ClueCode struct { Model Phone string `json:"phone" gorm:"index"` // 电话 Code int `json:"code"` // 验证码 Expiry time.Time `json:"expiry"` // 过期时间 } type GetCodeReq struct { Tel string `json:"tel" binding:"required"` // 电话 Type int `json:"type" binding:"required"` // 广告页类型 1-八大员;2-旅游 } type GetCodeResp struct { Code int `json:"code"` // 验证码 } type VerifyCodeReq struct { Tel string `json:"tel" binding:"required"` // 电话 Code int `json:"code" binding:"required"` // 验证码 } type GetPhoneWithTokenReq struct { SpToken string `json:"SpToken" binding:"required"` // JSSDK 获取的号码认证 Token } type RecordLog struct { Data interface{} `json:"data"` } func GetUserDataList(req *GetUserDataReq, Db *gorm.DB) (*GetUserDataResp, error) { page := req.PageIndex - 1 if page < 0 { page = 0 } if req.PageSize == 0 { req.PageSize = 10 } resp := &GetUserDataResp{ PageIndex: req.PageIndex, PageSize: req.PageSize, } var qs *gorm.DB if req.Type == 2 { // 旅游 qs = Db.Table("clue_user_travel") } else { qs = Db.Table("clue_user") } if req.Name != "" { qs = qs.Where("name=?", req.Name) } if req.Tel != "" { qs = qs.Where("tel=?", req.Tel) } if req.StartTime != "" { startTime := req.StartTime loc, _ := time.LoadLocation("Asia/Shanghai") // 以东八区为例 start, err := time.ParseInLocation(QueryTimeFormat, startTime, loc) if err != nil { logger.Errorf("Error parsing start time: %v", err) return resp, err } qs = qs.Where("created_at >= ?", start) } if req.EndTime != "" { endTime := req.EndTime loc, _ := time.LoadLocation("Asia/Shanghai") // 以东八区为例 end, err := time.ParseInLocation(QueryTimeFormat, endTime, loc) if err != nil { logger.Errorf("Error parsing end time: %v", err) return resp, err } qs = qs.Where("created_at <= ?", end) } fmt.Printf("Start Time: %v, End Time: %v", req.StartTime, req.EndTime) var count int64 err := qs.Count(&count).Error if err != nil { logger.Error("count err:", err) return resp, err } var orders []ClueUser if req.IsExport == ExportExcelFlag { // 导出excel err := qs.Order("id DESC").Find(&orders).Error if err != nil && err != RecordNotFound { logger.Error("erp commodity list err:", err) return resp, err } var filePath string if req.Type == 2 { // 旅游 filePath, err = travelUserDataExport(orders) } else { filePath, err = userDataExport(orders) } if err != nil { return nil, nil } resp.ExportUrl = filePath } else { err := qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&orders).Error if err != nil && err != RecordNotFound { logger.Error("erp commodity list err:", err) return resp, err } resp.List = orders resp.Total = count } return resp, nil } // userDataExport 导出用户数据-八大员 func userDataExport(req []ClueUser) (string, error) { file := excelize.NewFile() streamWriter, err := file.NewStreamWriter("Sheet1") if err != nil { fmt.Println(err) } url := ExportUrl //url := "/Users/max/Documents/" fileName := time.Now().Format(TimeFormat) + "-八大员操作证-用户数据" + ".xlsx" fmt.Println("url fileName:", url+fileName) title := []interface{}{"姓名", "电话", "工种操作证", "提交时间"} cell, _ := excelize.CoordinatesToCellName(1, 1) if err = streamWriter.SetRow(cell, title); err != nil { fmt.Println(err) } var row []interface{} nExcelStartRow := 0 for rowId := 0; rowId < len(req); rowId++ { row = []interface{}{ req[rowId].Name, req[rowId].Tel, req[rowId].Cert, req[rowId].CreatedAt, } cell, _ = excelize.CoordinatesToCellName(1, nExcelStartRow+2) if err = streamWriter.SetRow(cell, row); err != nil { fmt.Println(err) } nExcelStartRow++ } if err := streamWriter.Flush(); err != nil { fmt.Println(err) } fmt.Println("save fileName:", url+fileName) if err := file.SaveAs(ExportPath + fileName); err != nil { fmt.Println(err) } return url + fileName, nil } // userDataExport 导出用户数据-旅游 func travelUserDataExport(req []ClueUser) (string, error) { file := excelize.NewFile() streamWriter, err := file.NewStreamWriter("Sheet1") if err != nil { fmt.Println(err) } url := ExportUrl //url := "/Users/max/Documents/" fileName := time.Now().Format(TimeFormat) + "-重庆旅游-用户数据" + ".xlsx" fmt.Println("url fileName:", url+fileName) title := []interface{}{"姓名", "电话", "提交时间"} cell, _ := excelize.CoordinatesToCellName(1, 1) if err = streamWriter.SetRow(cell, title); err != nil { fmt.Println(err) } var row []interface{} nExcelStartRow := 0 for rowId := 0; rowId < len(req); rowId++ { row = []interface{}{ req[rowId].Name, req[rowId].Tel, req[rowId].CreatedAt, } cell, _ = excelize.CoordinatesToCellName(1, nExcelStartRow+2) if err = streamWriter.SetRow(cell, row); err != nil { fmt.Println(err) } nExcelStartRow++ } if err := streamWriter.Flush(); err != nil { fmt.Println(err) } fmt.Println("save fileName:", url+fileName) if err := file.SaveAs(ExportPath + fileName); err != nil { fmt.Println(err) } return url + fileName, nil } // ConvertCertListToString 转换证书列表数据 func ConvertCertListToString(certList []int) string { var result []string for _, cert := range certList { if certName, ok := certMap[cert]; ok { result = append(result, certName) } } return strings.Join(result, ",") } func GetSMSCode(req *GetCodeReq, db *gorm.DB, nType int) (*GetCodeResp, error) { // Generate random 6-digit OTP rand.Seed(time.Now().UnixNano()) otp := rand.Intn(900000) + 100000 expiry := time.Now().Add(5 * time.Minute) // 发送短信 var err error var message string if nType == 2 { // 重庆旅游 message = fmt.Sprintf("【边城旅行】短信验证码:%d,有效期5分钟,您正在领取优惠名额。如非本人操作,请忽略本短信。", otp) } else { // 八大员操作证 message = fmt.Sprintf("【捷速教育】短信验证码:%d,有效期5分钟,您正在领取免费报考福利。如非本人操作,请忽略本短信。", otp) } fmt.Println(message) var phoneList []string phoneList = append(phoneList, req.Tel) err = GtSendMessage(phoneList, message) if err != nil { return nil, err } // 成功后记录数据 codeData := &ClueCode{} codeData.Phone = req.Tel codeData.Code = otp codeData.Expiry = expiry err = db.Create(codeData).Error if err != nil { return nil, err } return &GetCodeResp{ Code: otp, }, nil } func VerifySMSCode(req *VerifyCodeReq, db *gorm.DB) error { var codeDataList []ClueCode err := db.Model(&ClueCode{}).Where("phone = ?", req.Tel).Find(&codeDataList).Error if err != nil { return err } if len(codeDataList) == 0 { return errors.New("未查询到验证码,请重新获取") } // 校验当前验证码 flag := false for _, v := range codeDataList { if req.Code != v.Code { continue } else { if time.Now().After(v.Expiry) { return errors.New("验证码已过期,请重新获取") } else { flag = true } } } if !flag { return errors.New("校验失败,请重新获取") } return nil } // CheckPhone 检查手机号是否存在 func CheckPhone(nType int, tel string, db *gorm.DB) (bool, error) { var exist bool var whiteExist bool var err error if nType == 1 { exist, err = QueryRecordExist(fmt.Sprintf("SELECT * FROM clue_user WHERE tel='%s'", tel), db) if err != nil { logger.Errorf("CheckPhone err:", err) return false, err } } else if nType == 2 { exist, err = QueryRecordExist(fmt.Sprintf("SELECT * FROM clue_user_travel WHERE tel='%s'", tel), db) if err != nil { logger.Errorf("CheckPhone err:", err) return false, err } } else { return false, errors.New("参数type类型有误") } whiteExist, err = QueryRecordExist(fmt.Sprintf("SELECT * FROM white_list WHERE phone='%s'", tel), db) if err != nil { logger.Errorf("CheckPhone err:", err) return false, err } if exist && !whiteExist { return true, nil } return false, nil } // RecordUserData 回传成功后记录到数据库 func RecordUserData(req *NewSendDataReq, db *gorm.DB) error { if req.Type == 1 { h5Data := &ClueUser{} h5Data.Name = req.Name h5Data.Tel = req.Tel if len(req.CertList) != 0 { h5Data.Cert = ConvertCertListToString(req.CertList) } err := db.Create(h5Data).Error if err != nil { logger.Info("Create ClueUser err:", err) return err } } else if req.Type == 2 { h5Data := &ClueUserTravel{} h5Data.Name = req.Name h5Data.Tel = req.Tel err := db.Create(h5Data).Error if err != nil { logger.Info("Create ClueUser err:", err) return err } } return nil }