471 lines
12 KiB
Go
471 lines
12 KiB
Go
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
|
||
}
|