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) }