package merchant import ( "errors" stringUtils "eta/eta_mini_ht_api/common/utils/string" "eta/eta_mini_ht_api/models" "fmt" "sort" "strings" "sync/atomic" "time" ) type SaleStatus string type MerchantProductType string const ( detailColumns = "id,source_id,title,cover_src,cover_url,description,price,type,is_permanent,valid_days,sale_status,created_time,updated_time,deleted" detailColumnsWithRisk = "merchant_products.id,source_id,title,cover_src,cover_url,description,price,type,is_permanent,valid_days,sale_status,created_time,updated_time,deleted,permissions.risk_level as risk_level" sourceIdColumn = "id,source_id" ) const ( OnSale SaleStatus = "on_sale" //上架 OffSale SaleStatus = "off_sale" //下架 Package MerchantProductType = "package" Report MerchantProductType = "report" Video MerchantProductType = "video" Audio MerchantProductType = "audio" ) // MerchantProduct 商户产品信息结构体 type MerchantProduct struct { Id int `gorm:"column:id;primary_key;autoIncrement;comment:主键"` SourceId int `gorm:"column:source_id;type:int(11);comment:单品或者套餐对应的主键"` Title string `gorm:"column:title;type:varchar(255);comment:标题"` CoverSrc int `gorm:"column:cover_src;type:int(11);comment:封面图片资源库id"` CoverUrl string `gorm:"column:cover_url;type:varchar(255);comment:封面图片url"` Description string `gorm:"column:description;type:varchar(255);comment:描述"` Price string `gorm:"column:price;type:decimal(10,2);comment:价格"` RiskLevel string `gorm:"column:risk_level;type:varchar(100);comment:风险等级"` Type MerchantProductType `gorm:"column:type;type:enum('report','video','audio','package');not null;comment:类型"` IsPermanent bool `gorm:"column:is_permanent;type:int(1);not null;default:0;comment:是否永久"` ValidDays int `gorm:"column:valid_days;type:int(11);comment:有效期天数"` SaleStatus SaleStatus `gorm:"column:sale_status;type:enum('on_sale','off_sale');not null;default:'on_sale';comment:上架/下架状态"` Deleted int `gorm:"column:deleted;type:tinyint(1);not null;default:0;comment:是否删除"` CreatedTime time.Time `gorm:"column:created_time;type:datetime;comment:创建时间"` UpdatedTime time.Time `gorm:"column:updated_time;type:datetime;comment:更新时间;default:CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP"` } // TableName 指定表名 func (MerchantProduct) TableName() string { return "merchant_products" } func GetMerchantProductById(id int) (product MerchantProduct, err error) { db := models.Main() err = db.Select(detailColumns).Where("id = ? ", id).First(&product).Error return } func GetMerchantProductBySourceId(sourceId int, productType ...MerchantProductType) (product MerchantProduct, err error) { db := models.Main() if len(productType) > 0 { if len(productType) == 1 { if productType[0] == Package { err = db.Select(detailColumnsWithRisk).Joins("left join permissions on permissions.permission_id=source_id").Where("source_id =? and type = ? and deleted =?", sourceId, productType[0], 0).First(&product).Error } else { err = db.Select(detailColumns).Where("source_id =? and type = ? and deleted =?", sourceId, productType[0], 0).First(&product).Error } } else { err = db.Select(detailColumns).Where("source_id =? and type in (?) and deleted =?", sourceId, productType, 0).First(&product).Error } } else { err = db.Select(detailColumns).Where("source_id =? and deleted =?", sourceId, 0).First(&product).Error } return } func GetProductListBySourceIds(ids []int, detail bool, productType ...MerchantProductType) (productList []MerchantProduct, err error) { db := models.Main() var columns string if productType == nil { err = errors.New("productType参数不能为空") return } if detail { columns = detailColumns } else { columns = sourceIdColumn } if len(productType) > 0 { if len(productType) == 1 { if productType[0] == Package { err = db.Select(detailColumnsWithRisk).Joins("left join permissions on permissions.permission_id=source_id").Where("source_id in ? and type = ? and deleted =? order by created_time desc", ids, productType[0], false).Find(&productList).Error } else { err = db.Select(columns).Where("source_id in ? and type = ? and deleted =? order by created_time desc", ids, productType[0], false).Find(&productList).Error } } else { err = db.Select(columns).Where("source_id in ? and type in (?) and deleted =? by created_time desc", ids, productType, false).Find(&productList).Error } } else { err = db.Select(columns).Where("source_id in ? and deleted =? by created_time desc", ids, productType, false).Find(&productList).Error } return } func GetTotalPageCountByProductType(productType MerchantProductType) (total int64, latestId int64) { db := models.Main() _ = db.Model(&MerchantProduct{}).Select("count(*)").Where("type=? and deleted =?", productType, false).Scan(&total).Error _ = db.Model(&MerchantProduct{}).Select("max(id)").Where("type=? and deleted =?", productType, false).Scan(&latestId).Error return } func GetProductPageByProductType(productIds []int, id int64, offset int, limit int) (list []MerchantProduct, err error) { db := models.Main() err = db.Select(detailColumns).Where("id <= ? and deleted =? and id in ? order by created_time desc limit ?,? ", id, false, productIds, offset, limit).Find(&list).Error return } func GetProductListByProductType(productType MerchantProductType, detail bool) (list []MerchantProduct, err error) { db := models.Main() var columns string if detail { columns = detailColumns } else { columns = sourceIdColumn } if productType == "" { err = errors.New("productType参数不能为空") return } err = db.Select(columns).Where(" type = ? and deleted =? order by created_time desc", productType, false).Find(&list).Error return } type MerchantProductIdMap struct { Type string SourceId string } func GetProductByProductType() (productIds map[string]string, err error) { db := models.Main() var productIdMap []MerchantProductIdMap sql := `SELECT type,GROUP_CONCAT(source_id ORDER BY source_id SEPARATOR ',') as source_id FROM merchant_products GROUP BY type` err = db.Raw(sql).Find(&productIdMap).Error productIds = make(map[string]string, len(productIdMap)) for _, v := range productIdMap { productIds[v.Type] = v.SourceId } return } func generateSignalPdSql(idMap map[string][]int) (condition string) { for k, v := range idMap { if condition == "" { condition = "(" + fmt.Sprintf("(type ='%s' and source_id in (%s))", k, strings.Join(stringUtils.IntToStringSlice(v), ",")) } else { condition = condition + fmt.Sprintf(" or (type ='%s' and source_id in (%s))", k, strings.Join(stringUtils.IntToStringSlice(v), ",")) } } condition = condition + ")" if len(idMap) == 1 { condition = condition[1 : len(condition)-1] } return } func LatestId() (latestId int64) { db := models.Main() _ = db.Model(&MerchantProduct{}).Select("max(id)").Where("deleted=?", false).Scan(&latestId).Error return } type ProductDTO struct { SourceId int SourceType string Score float64 } func ProductListBySort(list []ProductDTO, id int64, offset int, size int) (productList []MerchantProduct, err error) { var productMap = make(map[string][]int, len(list)) sort.Slice(list, func(i, j int) bool { return list[i].Score > list[j].Score }) var idSort []int for _, v := range list { idSort = append(idSort, v.SourceId) } for _, v := range list { ids := productMap[v.SourceType] ids = append(ids, v.SourceId) productMap[v.SourceType] = ids } sql := generateSignalPdSql(productMap) db := models.Main() query := fmt.Sprintf("id <= ? and deleted =? and %s order by Field(id,?) desc limit ?,?", sql) err = db.Select(detailColumns).Where(query, id, false, strings.Join(stringUtils.IntToStringSlice(idSort), ","), offset, size).Find(&productList).Error return } type packageStruct struct { SourceId int Weight int32 } func PackageListBySort(weightMap map[int]*atomic.Int32, id int64, offset int, size int) (productList []MerchantProduct, err error) { var packageList []packageStruct for k, v := range weightMap { packageList = append(packageList, packageStruct{ SourceId: k, Weight: v.Load(), }) } sort.Slice(packageList, func(i, j int) bool { return packageList[i].Weight > packageList[j].Weight }) var idSort []int for _, v := range packageList { idSort = append(idSort, v.SourceId) } db := models.Main() err = db.Select(detailColumns).Where("id <= ? and type =? and deleted =? and source_id in ? order by Field(id,?) desc limit ?,? ", id, Package, false, idSort, strings.Join(stringUtils.IntToStringSlice(idSort), ","), offset, size).Find(&productList).Error return } func GetOffSaleProducts(query []MerchantProductType) (list []MerchantProduct, err error) { db := models.Main() err = db.Select(detailColumns).Where(" deleted =? and type in ? and sale_status = ? ", false, query, OffSale).Find(&list).Error return } func GetReportOnSalePackageIds(ids []int) (sourceIds []int, err error) { sql := ` SELECT r.id FROM reports r LEFT JOIN permission_classify_mapping pcm ON r.classify_id = pcm.classify_id LEFT JOIN merchant_products mp ON mp.source_id = pcm.permission_id AND mp.type = 'package' AND mp.sale_status = 'on_sale' AND mp.deleted = 0 WHERE mp.id IS NOT NULL and r.id in ? UNION ALL SELECT r.id FROM reports r LEFT JOIN permissions p ON r.plate_name = p.NAME LEFT JOIN merchant_products mp ON mp.source_id = p.permission_id AND mp.type = 'package' AND mp.sale_status = 'on_sale' AND mp.deleted = 0 WHERE mp.id IS NOT NULL and r.id in ?` db := models.Main() err = db.Raw(sql, ids, ids).Scan(&sourceIds).Error return } func GetMediaOnSalePackageIds(ids []int) (sourceIds []int, err error) { sql := ` SELECT distinct mpm.media_id FROM media_permission_mappings mpm LEFT JOIN merchant_products mp ON mp.source_id = mpm.permission_id AND mp.type = 'package' AND mp.sale_status = 'on_sale' and mp.deleted=0 WHERE mpm.deleted=0 and mp.id is not null and mpm.media_id in ?` db := models.Main() err = db.Raw(sql, ids).Scan(&sourceIds).Error return } func GetOnSaleReportIds(ids []int) (sourceIds []int, err error) { sql := `SELECT r.id FROM reports r LEFT JOIN merchant_products mp ON mp.source_id = r.id AND mp.type = 'report' AND mp.sale_status = 'on_sale' AND mp.deleted = 0 WHERE mp.id IS NOT NULL and r.id in ?` db := models.Main() err = db.Raw(sql, ids).Scan(&sourceIds).Error return } func GetOnSaleMediaIds(ids []int, productType MerchantProductType) (sourceIds []int, err error) { sql := `SELECT distinct mpm.media_id FROM media_permission_mappings mpm LEFT JOIN merchant_products mp ON mp.source_id = mpm.media_id AND mp.type = ? AND mp.sale_status = 'on_sale' AND mp.deleted = 0 WHERE mpm.deleted=0 and mp.id is not null and mpm.media_id in ?` db := models.Main() err = db.Raw(sql, productType, ids).Scan(&sourceIds).Error return }