package controllers import ( "encoding/json" "errors" "eta/eta_mini_crm_ht/models" "eta/eta_mini_crm_ht/models/request" "eta/eta_mini_crm_ht/models/response" "eta/eta_mini_crm_ht/services" "eta/eta_mini_crm_ht/utils" "fmt" "github.com/go-sql-driver/mysql" "github.com/rdlucklib/rdluck_tools/paging" "github.com/shopspring/decimal" "math/rand" "os" "path" "strconv" "strings" "sync" "time" ) var ( CNProductMap = map[models.MerchantProductType]string{ models.ProductPackage: "套餐", models.ProductVideo: "视频", models.ProductAudio: "音频", models.ProductReport: "报告", } CNSaleStatusMap = map[models.SaleStatus]string{ models.OnSale: "已上架", models.OffSale: "未上架", } ) type ProductController struct { BaseAuthController } // UnSetProductList // @Title 未设置的产品列表 // @Description 未设置的产品列表 // @Param PageSize query int true "每页数据条数" // @Param CurrentIndex query int true "当前页页码,从1开始" // @Param ClassifyIds query string true "二级分类id,可多选用英文,隔开" // @Param KeyWord query string true "报告标题/创建人" // @Param SortType query string true "排序方式" // @Success 200 {object} models.ReportAuthorResp // @router /unSetProductList [get] func (this *ProductController) UnSetProductList() { br := new(models.BaseResponse).Init() defer func() { this.Data["json"] = br this.ServeJSON() }() pageSize, _ := this.GetInt("PageSize") currentIndex, _ := this.GetInt("CurrentIndex") sortType := this.GetString("SortType") ProductType := this.GetString("ProductType") permissionIds := this.GetString("PermissionIds") KeyWord := this.GetString("KeyWord") var condition string var pars []interface{} if pageSize <= 0 { pageSize = utils.PageSize20 } if currentIndex <= 0 { currentIndex = 1 } if ProductType == "" { br.Msg = "产品类型不能为空" br.ErrMsg = "获取未设置产品列表失败,Err:产品类型为空" return } if KeyWord != "" { switch ProductType { case "report": condition += " AND title like '%" + KeyWord + "%' " case "media": condition += " AND media_name like '%" + KeyWord + "%' " } } sortCondition := " ORDER BY published_time " if sortType == "" { sortType = "DESC" } sortCondition = sortCondition + sortType var permissionIdsList []int if permissionIds != "" { permissionStr := strings.Split(permissionIds, ",") for _, permissionItem := range permissionStr { permissionId, _ := strconv.Atoi(permissionItem) permissionIdsList = append(permissionIdsList, permissionId) } } total, ids, err := services.GetUnsetProductCountByCondition(ProductType, permissionIdsList, condition, pars) if err != nil { br.Msg = "获取未设置产品列表失败" br.ErrMsg = "获取未设置产品列表失败,Err:" + err.Error() return } var list []*services.ProductView if len(ids) > 0 { startSize := utils.StartIndex(currentIndex, pageSize) list, err = services.GetUnsetProductByCondition(ProductType, ids, sortCondition, startSize, pageSize) if err != nil { br.Msg = "获取未设置产品列表失败" br.ErrMsg = "获取未设置产品列表失败,Err:" + err.Error() return } } var wg sync.WaitGroup wg.Add(len(list)) for _, product := range list { go func(product *services.ProductView) { defer wg.Done() switch product.ProductType { case "report": product.RiskLevel, _, product.PermissionNames, _ = services.GetRiskLevel("report", product.SourceId) product.ProductType = "报告" case "video": product.RiskLevel, _, product.PermissionNames, _ = services.GetRiskLevel("media", product.SourceId) product.ProductType = "视频" case "audio": product.RiskLevel, _, product.PermissionNames, _ = services.GetRiskLevel("media", product.SourceId) product.ProductType = "音频" } }(product) } wg.Wait() page := paging.GetPaging(currentIndex, pageSize, total) resp := new(response.ProductListResp) resp.List = list resp.Paging = page br.Ret = 200 br.Success = true br.Data = resp br.Msg = "获取成功" } // AddProduct @Title 新增单品 // @Description 新增单品 // @Param File query file true "文件" // @Success 200 {object} models.ReportAuthorResp // @router /addProduct [post] func (this *ProductController) AddProduct() { br := new(models.BaseResponse).Init() defer func() { this.Data["json"] = br this.ServeJSON() }() var req request.ProductReq var permissionName string err := json.Unmarshal(this.Ctx.Input.RequestBody, &req) if err != nil { br.Msg = "参数解析异常!" br.ErrMsg = "参数解析失败,Err:" + err.Error() return } var product models.MerchantProduct if req.Type == "package" { if req.ValidDays <= 0 { br.Msg = "套餐有效期非法" br.ErrMsg = "套餐有效期非法,天数不能是负数" return } if req.ProductName == "" { br.Msg = "套餐名称不能为空" br.ErrMsg = "套餐名称不能为空" return } product.Title = req.ProductName product.ValidDays = req.ValidDays product.Description = req.Description if req.CoverSrc == "" { var imageList []models.ImageSource imageList, err = models.GetImageByPermissionId(req.SourceId) if err != nil { utils.FileLog.Error("套餐封面获取失败", err.Error()) //br.Msg = "默认套餐封面获取失败,请上传封面" //br.ErrMsg = "默认套餐封面获取失败,请上传封面,Err:" + err.Error() //return } else { if len(imageList) > 0 { var rnd = rand.New(rand.NewSource(time.Now().UnixNano())) index := rnd.Intn(len(imageList)) product.CoverSrc = imageList[index].Id } } } else { product.CoverUrl = req.CoverSrc } } switch req.Type { case "report": _, product.Title, _, err = services.GetRiskLevel("report", req.SourceId) product.IsPermanent = true case "audio": _, product.Title, _, err = services.GetRiskLevel("audio", req.SourceId) product.IsPermanent = true case "video": _, product.Title, _, err = services.GetRiskLevel("video", req.SourceId) product.IsPermanent = true case "package": _, permissionName, _, err = services.GetRiskLevel("package", req.SourceId) default: br.Msg = "产品类型错误" br.ErrMsg = "获取产品列表失败,Err:产品类型错误" return } if err != nil { utils.FileLog.Error("新增单品失败", err.Error()) br.Msg = "新增产品错误" if strings.Contains(err.Error(), " no row found") { br.Msg = "新增产品错误,产品信息不存在" } else { br.Msg = "新增产品错误" + err.Error() } return } if product.Title == "" { br.Msg = "产品名称不能为空" br.ErrMsg = "产品名称不能为空" return } var price decimal.Decimal price, err = decimal.NewFromString(req.Price) if err != nil { br.Msg = "产品价格格式不正确" br.ErrMsg = "产品价格格式不正确,err:" + err.Error() + "price:" + product.Price return } if price.Cmp(decimal.New(0, 0)) <= 0 { br.Msg = "产品价格不能小于0" br.ErrMsg = "产品价格不能小于0" return } product.SaleStatus = models.OnSale product.CreatedTime = time.Now() product.Price = req.Price product.SourceId = req.SourceId product.Type = models.MerchantProductType(req.Type) product.Creator = this.SysUser.SysRealName if product.Type == "" { br.Msg = "新增产品错误" br.ErrMsg = "产品类型为空" return } err = product.AddProduct() if err != nil { var mysqlErr *mysql.MySQLError if errors.As(err, &mysqlErr) { if mysqlErr.Number == 1062 { if product.Type == models.ProductPackage { var dbProduct models.MerchantProduct dbProduct, err = models.GetProductByProductType(product.SourceId, models.ProductPackage) if err != nil { utils.FileLog.Error("获取套餐产品信息失败,err:" + err.Error()) br.Msg = "[" + permissionName + "]已设置付费套餐,请重新选择" br.ErrMsg = "[" + permissionName + "]已设置付费套餐,请重新选择" } else { br.Msg = "[" + permissionName + "]已设置付费套餐[" + dbProduct.Title + "],请重新选择" br.ErrMsg = "[" + permissionName + "]已设置付费套餐[" + dbProduct.Title + "],请重新选择" } } else { br.Msg = "该产品已设置付费,请刷新后重试" br.ErrMsg = "该产品已设置付费,请刷新后重试" } } else { utils.FileLog.Error("新增产品失败,err:" + err.Error()) br.Msg = "新增产品失败" br.ErrMsg = "新增产品失败,err:" + err.Error() } } else { utils.FileLog.Error("新增产品失败,err:" + err.Error()) br.Msg = "新增产品失败" br.ErrMsg = "新增产品失败,err:" + err.Error() } return } br.Ret = 200 br.Success = true br.Msg = "新增产品成功" return } // UpdateSaleStatus @Title 上下架产品 // @Description 上下架产品 // @Param File query file true "文件" // @Success 200 {object} models.ReportAuthorResp // @router /updateSaleStatus [post] func (this *ProductController) UpdateSaleStatus() { br := new(models.BaseResponse).Init() defer func() { this.Data["json"] = br this.ServeJSON() }() defer func() { this.Data["json"] = br this.ServeJSON() }() var req request.ProductSaleStatusReq err := json.Unmarshal(this.Ctx.Input.RequestBody, &req) if err != nil { br.Msg = "参数解析异常!" br.ErrMsg = "参数解析失败,Err:" + err.Error() return } if req.ProductId <= 0 { br.Msg = "产品编号非法!" br.ErrMsg = "产品编号非法,不能小于0" return } if req.SaleStatus != "onSale" && req.SaleStatus != "offSale" { br.Msg = "产品销售状态非法!" br.ErrMsg = "产品销售状态非法,未知的上下架类型:" + req.SaleStatus return } var saleStatus models.SaleStatus var messageStatus string switch req.SaleStatus { case "onSale": saleStatus = models.OnSale messageStatus = "上架" case "offSale": saleStatus = models.OffSale messageStatus = "下架" } product := models.MerchantProduct{ Id: req.ProductId, SaleStatus: saleStatus, UpdatedTime: time.Now(), } err = product.UpdateProductSaleStatus() if err != nil { br.Msg = messageStatus + "失败" br.ErrMsg = messageStatus + "失败,err:" + err.Error() return } br.Msg = messageStatus + "成功" br.Ret = 200 br.Success = true } // DeleteProduct @Title 删除产品 // @Description 删除产品 // @Param File query file true "文件" // @Success 200 {object} models.ReportAuthorResp // @router /deleteProduct [post] func (this *ProductController) DeleteProduct() { br := new(models.BaseResponse).Init() defer func() { this.Data["json"] = br this.ServeJSON() }() defer func() { this.Data["json"] = br this.ServeJSON() }() var req request.ProductSaleStatusReq err := json.Unmarshal(this.Ctx.Input.RequestBody, &req) if err != nil { br.Msg = "参数解析异常!" br.ErrMsg = "参数解析失败,Err:" + err.Error() return } if req.ProductId <= 0 { br.Msg = "产品编号非法!" br.ErrMsg = "产品编号非法,不能小于0" return } product := models.MerchantProduct{ Id: req.ProductId, Deleted: req.ProductId, UpdatedTime: time.Now(), } err = product.Delete() if err != nil { br.Msg = "删除产品失败" br.ErrMsg = "删除产品失败,err:" + err.Error() return } br.Msg = "删除产品成功" br.Ret = 200 br.Success = true } // ProductList // @Title 产品列表 // @Description pdf研报列表 // @Param PageSize query int true "每页数据条数" // @Param CurrentIndex query int true "当前页页码,从1开始" // @Param ClassifyIds query string true "二级分类id,可多选用英文,隔开" // @Param KeyWord query string true "报告标题/创建人" // @Param SortType query string true "排序方式" // @Success 200 {object} models.ReportAuthorResp // @router /productList [get] func (this *ProductController) ProductList() { br := new(models.BaseResponse).Init() defer func() { this.Data["json"] = br this.ServeJSON() }() pageSize, _ := this.GetInt("PageSize") currentIndex, _ := this.GetInt("CurrentIndex") sortType := this.GetString("SortType") sortColumn := this.GetString("SortColumn") KeyWord := this.GetString("KeyWord") CreatedTime := this.GetString("CreatedTime") UpdatedTime := this.GetString("UpdatedTime") IsSingle, _ := this.GetBool("IsSingle", true) ProductType := this.GetString("ProductType") SaleStatus := this.GetString("SaleStatus") var condition string if pageSize <= 0 { pageSize = utils.PageSize20 } if currentIndex <= 0 { currentIndex = 1 } if KeyWord != "" { condition += " AND title like '%" + KeyWord + "%'" } var sortCondition string if sortColumn == "" { sortCondition = " ORDER BY created_time " } else { sortCondition = " ORDER BY " + sortColumn + " " } if sortType == "" { sortType = "DESC" } if CreatedTime != "" { condition += " AND Date(created_time) = '" + CreatedTime + "'" } if UpdatedTime != "" { condition += " AND Date(updated_time) = '" + UpdatedTime + "'" } if SaleStatus != "" { switch SaleStatus { case "onSale": condition += " AND sale_status='on_sale'" case "offSale": condition += " AND sale_status='off_sale'" default: br.Msg = "无效的销售状态" br.ErrMsg = "无效的销售状态:" + SaleStatus return } } if IsSingle { if ProductType != "" { switch ProductType { case "report": condition += " AND type='" + string(models.ProductReport) + "'" case "audio": condition += " AND type='" + string(models.ProductAudio) + "'" case "video": condition += " AND type='" + string(models.ProductVideo) + "'" default: br.Msg = "无效的产品类型" br.ErrMsg = "无效的产品类型:" + ProductType return } } else { condition += " AND type != '" + string(models.ProductPackage) + "'" } } else { condition += " AND type = '" + string(models.ProductPackage) + "'" } sortCondition = sortCondition + sortType total, err := models.GetProductCountByCondition(condition) if err != nil { br.Msg = "获取产品列表失败" br.ErrMsg = "获取产品列表失败,Err:" + err.Error() return } startSize := utils.StartIndex(currentIndex, pageSize) List, err := models.GetProductByCondition(condition, sortCondition, startSize, pageSize) if err != nil { br.Msg = "获取产品列表失败" br.ErrMsg = "获取产品列表失败,Err:" + err.Error() return } var ListView []*services.ProductView for _, product := range List { view := &services.ProductView{ Id: product.Id, ProductName: product.Title, ProductType: CNProductMap[product.Type], PublishedTime: product.CreatedTime.Format(time.DateTime), Price: fmt.Sprintf("¥%s", product.Price), SaleStatus: CNSaleStatusMap[product.SaleStatus], CoverSrc: product.CoverUrl, ValidDays: product.ValidDays, Creator: product.Creator, IsPermanent: product.IsPermanent, Description: product.Description, SourceId: product.SourceId, } if product.CoverUrl == "" && product.CoverSrc > 0 { image, imageErr := models.GetImageById(product.CoverSrc) if err != nil { utils.FileLog.Warn("获取图片资源失败,err:%s,imageId:%d", imageErr, product.CoverSrc) } else { view.CoverSrc = image.SrcUrl } } if !product.UpdatedTime.IsZero() { view.UpdatedTime = product.UpdatedTime.Format(time.DateTime) } view.RiskLevel, _, _, _ = services.GetRiskLevel(string(product.Type), product.SourceId) ListView = append(ListView, view) } page := paging.GetPaging(currentIndex, pageSize, total) resp := new(response.ProductListResp) resp.List = ListView resp.Paging = page br.Ret = 200 br.Success = true br.Data = resp br.Msg = "获取成功" } // ProductRisk // @Title 产品列表 // @Description pdf研报列表 // @Param PageSize query int true "每页数据条数" // @Param CurrentIndex query int true "当前页页码,从1开始" // @Param ClassifyIds query string true "二级分类id,可多选用英文,隔开" // @Param KeyWord query string true "报告标题/创建人" // @Param SortType query string true "排序方式" // @Success 200 {object} models.ReportAuthorResp // @router /productRisk [get] func (this *ProductController) ProductRisk() { br := new(models.BaseResponse).Init() defer func() { this.Data["json"] = br this.ServeJSON() }() SourceId, _ := this.GetInt("SourceId", 0) ProductType := this.GetString("ProductType") if SourceId <= 0 { br.Msg = "无效的产品ID" br.ErrMsg = "无效的产品ID:" + strconv.Itoa(SourceId) return } riskLevel, _, _, err := services.GetRiskLevel(ProductType, SourceId) if err != nil { utils.FileLog.Error("查询产品风险等级失败", err.Error) return } resp := new(response.ProductRiskResp) resp.RiskLevel = riskLevel resp.SourceId = SourceId resp.ProductType = ProductType br.Ret = 200 br.Success = true br.Data = resp br.Msg = "获取成功" } // EditProduct @Title 编辑产品 // @Description 编辑产品 // @Param File query file true "文件" // @Success 200 {object} models.ReportAuthorResp // @router /editProduct [post] func (this *ProductController) EditProduct() { br := new(models.BaseResponse).Init() defer func() { this.Data["json"] = br this.ServeJSON() }() var req request.ProductReq err := json.Unmarshal(this.Ctx.Input.RequestBody, &req) if err != nil { br.Msg = "参数解析异常!" br.ErrMsg = "参数解析失败,Err:" + err.Error() return } var product models.MerchantProduct if req.Type == "package" { if req.ValidDays <= 0 { br.Msg = "套餐有效期非法" br.ErrMsg = "套餐有效期非法,天数不能是负数" return } if req.ProductName == "" { br.Msg = "套餐名称不能为空" br.ErrMsg = "套餐名称不能为空" return } product.Title = req.ProductName product.ValidDays = req.ValidDays product.Description = req.Description if req.CoverSrc == "" { var imageList []models.ImageSource imageList, err = models.GetImageByPermissionId(req.SourceId) if err != nil { utils.FileLog.Error("套餐封面获取失败", err.Error()) //br.Msg = "默认套餐封面获取失败,请上传封面" //br.ErrMsg = "默认套餐封面获取失败,请上传封面,Err:" + err.Error() //return } else { if len(imageList) > 0 { var rnd = rand.New(rand.NewSource(time.Now().UnixNano())) index := rnd.Intn(len(imageList)) product.CoverSrc = imageList[index].Id } } } else { product.CoverUrl = req.CoverSrc } } switch req.Type { case "report": _, product.Title, _, err = services.GetRiskLevel("report", req.SourceId) case "audio": _, product.Title, _, err = services.GetRiskLevel("audio", req.SourceId) case "video": _, product.Title, _, err = services.GetRiskLevel("video", req.SourceId) case "package": _, _, _, err = services.GetRiskLevel("package", req.SourceId) default: br.Msg = "产品类型错误" br.ErrMsg = "获取产品列表失败,Err:产品类型错误" return } if err != nil { utils.FileLog.Error("编辑产品失败", err.Error()) br.Msg = "编辑产品失败" if strings.Contains(err.Error(), " no row found") { br.Msg = "编辑产品失败,产品信息不存在" } else { br.Msg = "编辑产品失败" + err.Error() } return } if product.Title == "" { br.Msg = "产品名称不能为空" br.ErrMsg = "产品名称不能为空" return } var price decimal.Decimal price, err = decimal.NewFromString(req.Price) if err != nil { br.Msg = "产品价格格式不正确" br.ErrMsg = "产品价格格式不正确,err:" + err.Error() + "price:" + product.Price return } if price.Cmp(decimal.New(0, 0)) <= 0 { br.Msg = "产品价格不能小于0" br.ErrMsg = "产品价格不能小于0" return } product.Id = req.ProductId product.SaleStatus = models.OnSale product.CreatedTime = time.Now() product.Price = req.Price product.SourceId = req.SourceId product.Type = models.MerchantProductType(req.Type) product.Creator = this.SysUser.SysRealName if product.Type == "" { br.Msg = "编辑产品失败" br.ErrMsg = "产品类型为空" return } err = product.EditProduct() if err != nil { utils.FileLog.Error("编辑产品失败,err:" + err.Error()) br.Msg = "编辑产品失败" br.ErrMsg = "编辑产品失败,err:" + err.Error() return } br.Ret = 200 br.Success = true br.Msg = "编辑产品成功" return } // UploadFile @Title 上传图片 // @Description 上传图片 // @Param File query file true "文件" // @Success 200 {object} models.ReportAuthorResp // @router /uploadFile [post] func (this *ProductController) UploadFile() { br := new(models.BaseResponse).Init() defer func() { this.Data["json"] = br this.ServeJSON() }() f, h, err := this.GetFile("File") if err != nil { br.Msg = "获取资源信息失败" br.ErrMsg = "获取资源信息失败,Err:" + err.Error() return } defer f.Close() size, err := strconv.Atoi(utils.UPLOAD_IMG_SIZE) if err != nil { size = 100 } if h.Size > 1024*1024*int64(size) { br.Msg = fmt.Sprintf("图片大小不能超过%dK", size) br.ErrMsg = "图片上传失败,Err:" + err.Error() return } ext := path.Ext(h.Filename) dateDir := time.Now().Format("20060102") uploadDir := utils.STATIC_DIR + "ht/product" + dateDir err = os.MkdirAll(uploadDir, utils.DIR_MOD) if err != nil { br.Msg = "存储目录创建失败" br.ErrMsg = "存储目录创建失败,Err:" + err.Error() return } randStr := utils.GetRandStringNoSpecialChar(28) fileName := randStr + ext fpath := uploadDir + "/" + fileName err = this.SaveToFile("File", fpath) if err != nil { br.Msg = "图片上传失败" br.ErrMsg = "图片上传失败,Err:" + err.Error() return } audioUploadDir := utils.RESOURCE_DIR + "img/" savePdfToOssPath := audioUploadDir + time.Now().Format("200601/20060102/") audioName := utils.GetRandStringNoSpecialChar(28) savePdfToOssPath += audioName + ext defer func() { err = os.Remove(fpath) fmt.Sprintf("删除文件失败:%v", err) }() ossClient := services.NewOssClient() if ossClient == nil { br.Msg = "图片上传失败" br.ErrMsg = "初始化OSS服务失败" return } mp3Url, err := ossClient.UploadFile("", fpath, savePdfToOssPath) if err != nil { br.Msg = "图片上传失败" br.ErrMsg = "图片上传失败,Err:" + err.Error() return } base := path.Base(h.Filename) resp := new(response.MediaUploadResp) resp.Url = mp3Url resp.FileName = base br.Data = resp br.Msg = "上传成功" br.Ret = 200 br.Success = true }