fonchain-fiee/pkg/service/train/train.go

491 lines
13 KiB
Go
Raw Normal View History

2025-02-19 06:24:15 +00:00
package train
import (
"context"
"dubbo.apache.org/dubbo-go/v3/common/logger"
"encoding/json"
"errors"
"fmt"
"github.com/fonchain_enterprise/fonchain-main/api/appointment"
"github.com/fonchain_enterprise/fonchain-main/pkg/cache"
"github.com/fonchain_enterprise/fonchain-main/pkg/config"
"github.com/fonchain_enterprise/fonchain-main/pkg/e"
"github.com/fonchain_enterprise/fonchain-main/pkg/model/vo"
"github.com/fonchain_enterprise/fonchain-main/pkg/serializer"
"github.com/fonchain_enterprise/fonchain-main/pkg/service"
"github.com/fonchain_enterprise/fonchain-main/pkg/utils"
"github.com/fonchain_enterprise/utils/objstorage"
"github.com/gin-gonic/gin"
uuid "github.com/satori/go.uuid"
"github.com/tealeg/xlsx"
"io"
"io/ioutil"
"net/http"
"net/url"
"regexp"
"strings"
)
type User struct {
Com string `json:"com"`
CostCenter string `json:"costCenter"`
Dep string `json:"dep"`
Name string `json:"name"`
Num string `json:"num"`
TelNum string `json:"telNum"`
}
func CreateTrainInfo(c *gin.Context) {
var createTrainInfoRequest appointment.CreateTrainInfoRequest
if err := c.ShouldBind(&createTrainInfoRequest); err != nil {
logger.Errorf("createTrainInfoRequest ShouldBind err", err)
service.ResponseMsg(c, e.SUCCESS, serializer.Response{
Data: nil,
Msg: err.Error(),
Status: e.Failed,
})
return
}
fmt.Println("createTrainInfoRequest", &createTrainInfoRequest)
//获取创建人姓名
//authorization := c.GetHeader(e.Authorization)
//if authorization == "" {
// service.NotLoginRes(c, e.ErrNotLogin)
// return
//}
//
//jwt, err := secret.GetJwtFromStr(authorization)
//
//if err != nil {
// service.NotLoginRes(c, err.Error())
// return
//}
//
////0 解密
//req := api.DecryptJwtRequest{
// Token: jwt,
//}
//
//var provider *account.AccountClientImpl
//info, err := provider.DecryptJwt(c, &req)
//
//if err != nil {
// service.NotLoginRes(c, err.Error())
// return
//}
//createTrainInfoRequest.NameOfCreate = info.NickName
createTrainInfoRequest.NameOfCreate = "功能未加"
// 1预览 2创建
if createTrainInfoRequest.PreviewOrCreat == 2 {
//根据uuid获取二维码链接
//获取培训表uid
var uid uuid.UUID
uid, _ = uuid.NewV4()
qrContent := config.AppointUrl + "/#/pages/start/start?trainUid=" + uid.String()
fmt.Println("AppointUrl", config.AppointUrl)
fmt.Println("qrcontent", qrContent)
qrBytes, err := utils.CreateQr(qrContent, "") // Assuming CreateQr returns []byte
// fmt.Println("qrBytes 是:", qrBytes)
if err != nil {
fmt.Println("创建二维码失败:", err)
service.ResponseQuickMsg(c, e.Failed, "创建二维码失败", nil)
return
}
qrbytess := []byte(qrBytes)
objectName := fmt.Sprintf("%s/%s/%s.jpg", config.ConfigData.Oss.BaseDir, config.Env, uid.String())
BOSClient, _ := objstorage.NewOSS(config.ConfigData.Oss.AccessKeyId, config.ConfigData.Oss.AccessKeySecret, config.ConfigData.Oss.Endpoint)
_, err = BOSClient.PutObjectFromBytes(config.ConfigData.Oss.BucketName, objectName, qrbytess)
if err != nil {
logger.Errorf("quickBos err", err)
return
}
url := fmt.Sprintf("%s/%s", config.ConfigData.Oss.CdnHost, objectName)
fmt.Println("url", url)
createTrainInfoRequest.QrCodeUrl = url
createTrainInfoRequest.Uid = uid.String()
}
rep, err := service.AppointmentProvider.CreateTrainInfo(context.Background(), &createTrainInfoRequest)
if err != nil {
service.ResponseMsg(c, e.SUCCESS, serializer.Response{
Msg: err.Error(),
Status: e.Failed,
})
return
}
c.JSON(http.StatusOK, serializer.Response{
Status: e.Ok,
Code: e.SUCCESS,
Data: rep,
})
}
func UpdateTrainInfo(c *gin.Context) {
var updateTrainInfoRequest appointment.UpdateTrainInfoRequest
if err := c.ShouldBind(&updateTrainInfoRequest); err != nil {
logger.Errorf("updateTrainInfoRequest ShouldBind err", err)
service.ResponseMsg(c, e.SUCCESS, serializer.Response{
Data: nil,
Msg: err.Error(),
Status: e.Failed,
})
return
}
rep, err := service.AppointmentProvider.UpdateTrainInfo(context.Background(), &updateTrainInfoRequest)
if err != nil {
service.ResponseMsg(c, e.SUCCESS, serializer.Response{
Msg: err.Error(),
Status: e.Failed,
})
return
}
c.JSON(http.StatusOK, serializer.Response{
Status: e.Ok,
Code: e.SUCCESS,
Data: rep,
})
}
func DeleteTrainInfo(c *gin.Context) {
var DeleteTrainInfoRequest appointment.DeleteTrainInfoRequest
if err := c.ShouldBind(&DeleteTrainInfoRequest); err != nil {
logger.Errorf("updateTrainInfoRequest ShouldBind err", err)
service.ResponseMsg(c, e.SUCCESS, serializer.Response{
Data: nil,
Msg: err.Error(),
Status: e.Failed,
})
return
}
rep, err := service.AppointmentProvider.DeleteTrainInfo(context.Background(), &DeleteTrainInfoRequest)
if err != nil {
service.ResponseMsg(c, e.SUCCESS, serializer.Response{
Msg: err.Error(),
Status: e.Failed,
})
return
}
c.JSON(http.StatusOK, serializer.Response{
Status: e.Ok,
Code: e.SUCCESS,
Data: rep,
})
}
func TrainInfoList(c *gin.Context) {
var TrainInfoListRequest appointment.TrainInfoListRequest
if err := c.ShouldBind(&TrainInfoListRequest); err != nil {
logger.Errorf("updateTrainInfoRequest ShouldBind err", err)
service.ResponseMsg(c, e.SUCCESS, serializer.Response{
Data: nil,
Msg: err.Error(),
Status: e.Failed,
})
return
}
rep, err := service.AppointmentProvider.TrainInfoList(context.Background(), &TrainInfoListRequest)
if err != nil {
service.ResponseMsg(c, e.SUCCESS, serializer.Response{
Msg: err.Error(),
Status: e.Failed,
})
return
}
c.JSON(http.StatusOK, serializer.Response{
Status: e.Ok,
Code: e.SUCCESS,
Data: rep,
})
}
func SpecificTrainInfoListJson(c *gin.Context) {
var trainUsers []User
res := make(map[string]interface{})
var signNum = 0
var signList []User
var notSignList []User
trainInfoUid := c.Query("trainInfoUid") // 获取名为"name"的GET参数
specificTrainInfoListRequest := appointment.SpecificTrainInfoListRequest{
TrainInfoUid: trainInfoUid,
}
rep, err := service.AppointmentProvider.SpecificTrainInfoList(context.Background(), &specificTrainInfoListRequest)
if err != nil {
service.ResponseMsg(c, e.SUCCESS, serializer.Response{
Msg: err.Error(),
Status: e.Failed,
})
return
}
b, err := cache.RedisClient.Get("temp:train:user").Bytes()
if err == nil {
err = json.Unmarshal(b, &trainUsers)
}
trainUsersMap := make(map[string]User, len(trainUsers))
tempSignTrainUsersMap := make(map[string]struct{}, len(rep.SignInInfo))
for k, v := range trainUsers {
trainUsersMap[strings.TrimSpace(v.Name)] = trainUsers[k]
}
for _, v := range rep.SignInInfo {
tempSignName := strings.TrimSpace(v.SignInName)
if _, ok := tempSignTrainUsersMap[tempSignName]; ok { //有存在的
continue
}
if _, ok := trainUsersMap[tempSignName]; ok { //train中存在
signNum += 1
signList = append(signList, trainUsersMap[tempSignName])
}
tempSignTrainUsersMap[tempSignName] = struct{}{}
}
for k, v := range trainUsers {
singName := strings.TrimSpace(v.Name)
if _, ok := tempSignTrainUsersMap[singName]; !ok {
notSignList = append(notSignList, trainUsers[k])
}
}
res["totalNum"] = len(trainUsers)
res["signNum"] = signNum
res["notSignNum"] = len(trainUsers) - signNum
res["signList"] = signList
res["notSignList"] = notSignList
fmt.Println(res)
c.JSON(http.StatusOK, serializer.Response{
Status: e.Ok,
Code: e.SUCCESS,
Data: res,
})
return
}
func SpecificTrainInfoList(c *gin.Context) {
var specificTrainInfoListRequest appointment.SpecificTrainInfoListRequest
if err := c.ShouldBind(&specificTrainInfoListRequest); err != nil {
logger.Errorf("updateTrainInfoRequest ShouldBind err", err)
service.ResponseMsg(c, e.SUCCESS, serializer.Response{
Data: nil,
Msg: err.Error(),
Status: e.Failed,
})
return
}
rep, err := service.AppointmentProvider.SpecificTrainInfoList(context.Background(), &specificTrainInfoListRequest)
if err != nil {
service.ResponseMsg(c, e.SUCCESS, serializer.Response{
Msg: err.Error(),
Status: e.Failed,
})
return
}
c.JSON(http.StatusOK, serializer.Response{
Status: e.Ok,
Code: e.SUCCESS,
Data: rep,
})
}
func GetPicStream(c *gin.Context) {
var getPicStreamRequest vo.GetPicStreamRequest
if err := c.ShouldBind(&getPicStreamRequest); err != nil {
logger.Errorf("getPicStreamRequest ShouldBind err", err)
service.ResponseMsg(c, e.SUCCESS, serializer.Response{
Data: nil,
Msg: err.Error(),
Status: e.Failed,
})
return
}
// 对文件名进行URL编码
encodedFileName := url.QueryEscape(fmt.Sprintf("%s.%s", getPicStreamRequest.TrainTheme, "jpg"))
// 设置响应头指定文件名并设置字符编码为UTF-8
c.Writer.Header().Add("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"; filename*=UTF-8''%s", encodedFileName, encodedFileName))
c.Writer.Header().Add("Content-Type", "application/octet-stream")
// 发送HTTP GET请求获取图片
response, err := http.Get(getPicStreamRequest.QrUrl)
if err != nil {
fmt.Println(err)
service.ResponseMsg(c, e.SUCCESS, serializer.Response{
Msg: err.Error(),
Status: e.Failed,
})
return
}
defer response.Body.Close()
// 检查HTTP响应状态码
if response.StatusCode != http.StatusOK {
fmt.Println("HTTP请求失败状态码:", response.StatusCode)
return
}
_, err = io.Copy(c.Writer, response.Body)
if err != nil {
fmt.Println("HTTP请求失败状态码:", response.StatusCode)
return
}
// 读取响应体的二进制数据
imageBytes, err := ioutil.ReadAll(response.Body)
if err != nil {
service.ResponseMsg(c, e.SUCCESS, serializer.Response{
Msg: "无法读取响应体",
Status: e.Failed,
})
return
}
//
//// 设置响应头,告诉浏览器下载文件
////c.Header("Content-Disposition", "attachment; filename="+getPicStreamRequest.TrainTheme+".jpg")
////c.Header("Content-Disposition", "attachment; filename="+getPicStreamRequest.TrainTheme+".jpg")
//c.Writer.Header().Add("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, getPicStreamRequest.TrainTheme)+".jpg")
//c.Data(http.StatusOK, "image/jpeg", imageBytes)
rep := &appointment.GetPicStreamResponse{
PicStream: imageBytes,
}
c.JSON(http.StatusOK, serializer.Response{
Status: e.Ok,
Code: e.SUCCESS,
Data: rep,
})
}
func UploadPersonnel(c *gin.Context) {
type Result struct {
SuccessCount int `json:"successCount"`
ErrorCount int `json:"errorCount"`
Uid string `json:"uid"`
}
type UploadReq struct {
URL string `form:"url" binding:"required"`
}
var result Result
var req UploadReq
if err := c.ShouldBind(&req); err != nil {
handleUploadError(c, "参数错误:"+err.Error())
return
}
fileContent, err := downloadFile(req.URL)
if err != nil {
handleUploadError(c, "下载文件失败")
return
}
xlFile, err := xlsx.OpenBinary(fileContent)
if err != nil {
handleUploadError(c, "解析文件失败")
return
}
phoneNumberRegex := regexp.MustCompile(`^\d{11}$`)
uid, err := uuid.NewV4()
if err != nil {
handleUploadError(c, "生成唯一标识失败")
return
}
signReq := appointment.SignPersonnelReq{}
seenPhones := make(map[string]int)
for _, sheet := range xlFile.Sheets {
for rowIndex, row := range sheet.Rows {
if rowIndex == 0 {
continue // 跳过标题行
}
if len(row.Cells) < 2 {
continue // 没有足够的数据列,跳过
}
phone := row.Cells[1].String() // 假设第二列为手机号
if isValidPhoneNumber(phone, phoneNumberRegex) {
seenPhones[phone]++
}
}
}
// 第二次遍历,处理符合条件的数据
for _, sheet := range xlFile.Sheets {
for rowIndex, row := range sheet.Rows {
if rowIndex == 0 || len(row.Cells) < 1 {
continue
}
//TODO
var name, phone string
name = row.Cells[0].String()
if len(row.Cells) > 1 {
phone = row.Cells[1].String()
}
//name, phone := row.Cells[0].String(), row.Cells[1].String()
if name == "" || phone == "" || !isValidPhoneNumber(phone, phoneNumberRegex) || seenPhones[phone] > 1 {
// 如果名称为空,手机号为空,手机号不合法,或者手机号出现多次,增加错误计数并跳过
result.ErrorCount++
continue
}
// 现在已知当前手机号只出现了一次,可以处理数据
signReq.SignPersonnel = append(signReq.SignPersonnel, &appointment.SignPersonnel{
Name: name,
TelNum: phone,
Uid: uid.String(),
})
result.SuccessCount++
}
}
if len(signReq.SignPersonnel) == 0 {
handleUploadError(c, "无正确数据")
return
}
if _, err := service.AppointmentProvider.CreatePersonnel(context.Background(), &signReq); err != nil {
handleUploadError(c, "上传失败")
return
}
result.Uid = uid.String()
service.Success(c, result)
}
func isValidPhoneNumber(phone string, regex *regexp.Regexp) bool {
return len(phone) == 11 && regex.MatchString(phone)
}
func handleUploadError(c *gin.Context, message string) {
service.Error(c, e.InvalidParams, errors.New(message))
}
func downloadFile(url string) ([]byte, error) {
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
contentType := resp.Header.Get("Content-Type")
if contentType != "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" {
return nil, fmt.Errorf("文件格式不正确")
}
return ioutil.ReadAll(resp.Body)
}