491 lines
13 KiB
Go
491 lines
13 KiB
Go
|
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)
|
|||
|
}
|