merchant_product.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. package merchant
  2. import (
  3. "errors"
  4. stringUtils "eta/eta_mini_ht_api/common/utils/string"
  5. "eta/eta_mini_ht_api/models"
  6. "fmt"
  7. "sort"
  8. "strings"
  9. "sync/atomic"
  10. "time"
  11. )
  12. type SaleStatus string
  13. type MerchantProductType string
  14. const (
  15. detailColumns = "id,source_id,title,cover_src,cover_url,description,price,type,is_permanent,valid_days,sale_status,created_time,updated_time,deleted"
  16. 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"
  17. sourceIdColumn = "id,source_id"
  18. )
  19. const (
  20. OnSale SaleStatus = "on_sale" //上架
  21. OffSale SaleStatus = "off_sale" //下架
  22. Package MerchantProductType = "package"
  23. Report MerchantProductType = "report"
  24. Video MerchantProductType = "video"
  25. Audio MerchantProductType = "audio"
  26. )
  27. // MerchantProduct 商户产品信息结构体
  28. type MerchantProduct struct {
  29. Id int `gorm:"column:id;primary_key;autoIncrement;comment:主键"`
  30. SourceId int `gorm:"column:source_id;type:int(11);comment:单品或者套餐对应的主键"`
  31. Title string `gorm:"column:title;type:varchar(255);comment:标题"`
  32. CoverSrc int `gorm:"column:cover_src;type:int(11);comment:封面图片资源库id"`
  33. CoverUrl string `gorm:"column:cover_url;type:varchar(255);comment:封面图片url"`
  34. Description string `gorm:"column:description;type:varchar(255);comment:描述"`
  35. Price string `gorm:"column:price;type:decimal(10,2);comment:价格"`
  36. RiskLevel string `gorm:"column:risk_level;type:varchar(100);comment:风险等级"`
  37. Type MerchantProductType `gorm:"column:type;type:enum('report','video','audio','package');not null;comment:类型"`
  38. IsPermanent bool `gorm:"column:is_permanent;type:int(1);not null;default:0;comment:是否永久"`
  39. ValidDays int `gorm:"column:valid_days;type:int(11);comment:有效期天数"`
  40. SaleStatus SaleStatus `gorm:"column:sale_status;type:enum('on_sale','off_sale');not null;default:'on_sale';comment:上架/下架状态"`
  41. Deleted int `gorm:"column:deleted;type:tinyint(1);not null;default:0;comment:是否删除"`
  42. CreatedTime time.Time `gorm:"column:created_time;type:datetime;comment:创建时间"`
  43. UpdatedTime time.Time `gorm:"column:updated_time;type:datetime;comment:更新时间;default:CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP"`
  44. }
  45. // TableName 指定表名
  46. func (MerchantProduct) TableName() string {
  47. return "merchant_products"
  48. }
  49. func GetMerchantProductById(id int) (product MerchantProduct, err error) {
  50. db := models.Main()
  51. err = db.Select(detailColumns).Where("id = ? ", id).First(&product).Error
  52. return
  53. }
  54. func GetMerchantProductBySourceId(sourceId int, productType ...MerchantProductType) (product MerchantProduct, err error) {
  55. db := models.Main()
  56. if len(productType) > 0 {
  57. if len(productType) == 1 {
  58. if productType[0] == Package {
  59. 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
  60. } else {
  61. err = db.Select(detailColumns).Where("source_id =? and type = ? and deleted =?", sourceId, productType[0], 0).First(&product).Error
  62. }
  63. } else {
  64. err = db.Select(detailColumns).Where("source_id =? and type in (?) and deleted =?", sourceId, productType, 0).First(&product).Error
  65. }
  66. } else {
  67. err = db.Select(detailColumns).Where("source_id =? and deleted =?", sourceId, 0).First(&product).Error
  68. }
  69. return
  70. }
  71. func GetProductListBySourceIds(ids []int, detail bool, productType ...MerchantProductType) (productList []MerchantProduct, err error) {
  72. db := models.Main()
  73. var columns string
  74. if productType == nil {
  75. err = errors.New("productType参数不能为空")
  76. return
  77. }
  78. if detail {
  79. columns = detailColumns
  80. } else {
  81. columns = sourceIdColumn
  82. }
  83. if len(productType) > 0 {
  84. if len(productType) == 1 {
  85. if productType[0] == Package {
  86. 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
  87. } else {
  88. err = db.Select(columns).Where("source_id in ? and type = ? and deleted =? order by created_time desc", ids, productType[0], false).Find(&productList).Error
  89. }
  90. } else {
  91. err = db.Select(columns).Where("source_id in ? and type in (?) and deleted =? by created_time desc", ids, productType, false).Find(&productList).Error
  92. }
  93. } else {
  94. err = db.Select(columns).Where("source_id in ? and deleted =? by created_time desc", ids, productType, false).Find(&productList).Error
  95. }
  96. return
  97. }
  98. func GetTotalPageCountByProductType(productType MerchantProductType) (total int64, latestId int64) {
  99. db := models.Main()
  100. _ = db.Model(&MerchantProduct{}).Select("count(*)").Where("type=? and deleted =?", productType, false).Scan(&total).Error
  101. _ = db.Model(&MerchantProduct{}).Select("max(id)").Where("type=? and deleted =?", productType, false).Scan(&latestId).Error
  102. return
  103. }
  104. func GetProductPageByProductType(productIds []int, id int64, offset int, limit int) (list []MerchantProduct, err error) {
  105. db := models.Main()
  106. 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
  107. return
  108. }
  109. func GetProductListByProductType(productType MerchantProductType, detail bool) (list []MerchantProduct, err error) {
  110. db := models.Main()
  111. var columns string
  112. if detail {
  113. columns = detailColumns
  114. } else {
  115. columns = sourceIdColumn
  116. }
  117. if productType == "" {
  118. err = errors.New("productType参数不能为空")
  119. return
  120. }
  121. err = db.Select(columns).Where(" type = ? and deleted =? order by created_time desc", productType, false).Find(&list).Error
  122. return
  123. }
  124. type MerchantProductIdMap struct {
  125. Type string
  126. SourceId string
  127. }
  128. func GetProductByProductType() (productIds map[string]string, err error) {
  129. db := models.Main()
  130. var productIdMap []MerchantProductIdMap
  131. sql := `SELECT type,GROUP_CONCAT(source_id ORDER BY source_id SEPARATOR ',') as source_id FROM merchant_products GROUP BY type`
  132. err = db.Raw(sql).Find(&productIdMap).Error
  133. productIds = make(map[string]string, len(productIdMap))
  134. for _, v := range productIdMap {
  135. productIds[v.Type] = v.SourceId
  136. }
  137. return
  138. }
  139. func generateSignalPdSql(idMap map[string][]int) (condition string) {
  140. for k, v := range idMap {
  141. if condition == "" {
  142. condition = "(" + fmt.Sprintf("(type ='%s' and source_id in (%s))", k, strings.Join(stringUtils.IntToStringSlice(v), ","))
  143. } else {
  144. condition = condition + fmt.Sprintf(" or (type ='%s' and source_id in (%s))", k, strings.Join(stringUtils.IntToStringSlice(v), ","))
  145. }
  146. }
  147. condition = condition + ")"
  148. if len(idMap) == 1 {
  149. condition = condition[1 : len(condition)-1]
  150. }
  151. return
  152. }
  153. func LatestId() (latestId int64) {
  154. db := models.Main()
  155. _ = db.Model(&MerchantProduct{}).Select("max(id)").Where("deleted=?", false).Scan(&latestId).Error
  156. return
  157. }
  158. type ProductDTO struct {
  159. SourceId int
  160. SourceType string
  161. Score float64
  162. }
  163. func ProductListBySort(list []ProductDTO, id int64, offset int, size int) (productList []MerchantProduct, err error) {
  164. var productMap = make(map[string][]int, len(list))
  165. sort.Slice(list, func(i, j int) bool {
  166. return list[i].Score > list[j].Score
  167. })
  168. var idSort []int
  169. for _, v := range list {
  170. idSort = append(idSort, v.SourceId)
  171. }
  172. for _, v := range list {
  173. ids := productMap[v.SourceType]
  174. ids = append(ids, v.SourceId)
  175. productMap[v.SourceType] = ids
  176. }
  177. sql := generateSignalPdSql(productMap)
  178. db := models.Main()
  179. query := fmt.Sprintf("id <= ? and deleted =? and %s order by Field(id,?) desc limit ?,?", sql)
  180. err = db.Select(detailColumns).Where(query, id, false, strings.Join(stringUtils.IntToStringSlice(idSort), ","), offset, size).Find(&productList).Error
  181. return
  182. }
  183. type packageStruct struct {
  184. SourceId int
  185. Weight int32
  186. }
  187. func PackageListBySort(weightMap map[int]*atomic.Int32, id int64, offset int, size int) (productList []MerchantProduct, err error) {
  188. var packageList []packageStruct
  189. for k, v := range weightMap {
  190. packageList = append(packageList, packageStruct{
  191. SourceId: k,
  192. Weight: v.Load(),
  193. })
  194. }
  195. sort.Slice(packageList, func(i, j int) bool {
  196. return packageList[i].Weight > packageList[j].Weight
  197. })
  198. var idSort []int
  199. for _, v := range packageList {
  200. idSort = append(idSort, v.SourceId)
  201. }
  202. db := models.Main()
  203. 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
  204. return
  205. }
  206. func GetOffSaleProducts(query []MerchantProductType) (list []MerchantProduct, err error) {
  207. db := models.Main()
  208. err = db.Select(detailColumns).Where(" deleted =? and type in ? and sale_status = ? ", false, query, OffSale).Find(&list).Error
  209. return
  210. }
  211. func GetReportOnSalePackageIds(ids []int) (sourceIds []int, err error) {
  212. sql := `
  213. SELECT
  214. r.id
  215. FROM
  216. reports r
  217. LEFT JOIN permission_classify_mapping pcm ON r.classify_id = pcm.classify_id
  218. LEFT JOIN merchant_products mp ON mp.source_id = pcm.permission_id
  219. AND mp.type = 'package'
  220. AND mp.sale_status = 'on_sale'
  221. AND mp.deleted = 0
  222. WHERE
  223. mp.id IS NOT NULL and r.id in ?
  224. UNION ALL
  225. SELECT
  226. r.id
  227. FROM
  228. reports r
  229. LEFT JOIN permissions p ON r.plate_name = p.NAME
  230. LEFT JOIN merchant_products mp ON mp.source_id = p.permission_id
  231. AND mp.type = 'package'
  232. AND mp.sale_status = 'on_sale'
  233. AND mp.deleted = 0
  234. WHERE
  235. mp.id IS NOT NULL and r.id in ?`
  236. db := models.Main()
  237. err = db.Raw(sql, ids, ids).Scan(&sourceIds).Error
  238. return
  239. }
  240. func GetMediaOnSalePackageIds(ids []int) (sourceIds []int, err error) {
  241. sql := ` SELECT
  242. distinct mpm.media_id
  243. FROM
  244. media_permission_mappings mpm
  245. LEFT JOIN merchant_products mp ON mp.source_id = mpm.permission_id
  246. AND mp.type = 'package'
  247. AND mp.sale_status = 'on_sale'
  248. and mp.deleted=0
  249. WHERE
  250. mpm.deleted=0 and mp.id is not null and mpm.media_id in ?`
  251. db := models.Main()
  252. err = db.Raw(sql, ids).Scan(&sourceIds).Error
  253. return
  254. }
  255. func GetOnSaleReportIds(ids []int) (sourceIds []int, err error) {
  256. sql := `SELECT
  257. r.id
  258. FROM
  259. reports r
  260. LEFT JOIN merchant_products mp ON mp.source_id = r.id
  261. AND mp.type = 'report'
  262. AND mp.sale_status = 'on_sale'
  263. AND mp.deleted = 0
  264. WHERE
  265. mp.id IS NOT NULL and r.id in ?`
  266. db := models.Main()
  267. err = db.Raw(sql, ids).Scan(&sourceIds).Error
  268. return
  269. }
  270. func GetOnSaleMediaIds(ids []int, productType MerchantProductType) (sourceIds []int, err error) {
  271. sql := `SELECT
  272. distinct mpm.media_id
  273. FROM
  274. media_permission_mappings mpm
  275. LEFT JOIN merchant_products mp ON mp.source_id = mpm.media_id
  276. AND mp.type = ?
  277. AND mp.sale_status = 'on_sale'
  278. AND mp.deleted = 0
  279. WHERE
  280. mpm.deleted=0 and mp.id is not null and mpm.media_id in ?`
  281. db := models.Main()
  282. err = db.Raw(sql, productType, ids).Scan(&sourceIds).Error
  283. return
  284. }