academy_archive.go 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977
  1. package http
  2. import (
  3. "context"
  4. "fmt"
  5. "math"
  6. "net/http"
  7. "strings"
  8. "time"
  9. "go-common/app/admin/main/creative/model/academy"
  10. "go-common/app/interface/openplatform/article/model"
  11. "go-common/app/service/main/archive/api"
  12. "go-common/library/ecode"
  13. "go-common/library/log"
  14. bm "go-common/library/net/http/blademaster"
  15. "go-common/library/net/http/blademaster/render"
  16. "go-common/library/sync/errgroup"
  17. "go-common/library/xstr"
  18. "go-common/library/net/metadata"
  19. "github.com/davecgh/go-spew/spew"
  20. "github.com/jinzhu/gorm"
  21. )
  22. func addArc(c *bm.Context) {
  23. var err error
  24. v := new(struct {
  25. OID int64 `form:"oid" validate:"required"`
  26. Business int8 `form:"business"`
  27. Comment string `form:"comment"`
  28. CourseTID int64 `form:"course_tid" validate:"required"`
  29. OperTID int64 `form:"oper_tid" validate:"required"`
  30. ClassTID string `form:"class_tid" validate:"required"`
  31. ArticleTID int64 `form:"article_tid"`
  32. RecommendTID int64 `form:"recommend_tid" validate:"required"`
  33. })
  34. ip := metadata.String(c, metadata.RemoteIP)
  35. if err = c.Bind(v); err != nil {
  36. return
  37. }
  38. if v.OID == 0 {
  39. c.JSON(nil, ecode.RequestErr)
  40. return
  41. }
  42. if arc, err := checkExist(v.OID); err == nil && arc.OID != 0 {
  43. c.JSON(nil, ecode.CreativeAcademyOIDExistErr)
  44. return
  45. }
  46. uid, uname := getUIDName(c)
  47. action := ""
  48. if v.Business == academy.BusinessForArchvie {
  49. action = "添加单个视频稿件"
  50. } else if v.Business == academy.BusinessForArticle {
  51. action = "添加单个专栏稿件"
  52. }
  53. svc.SendAcademyLog(c, &academy.LogParam{UID: uid, UName: uname, Action: action, OIDs: xstr.JoinInts([]int64{v.OID})})
  54. c.JSON(nil, bulkInsertArcs(c, []int64{v.OID}, v.Business, v.CourseTID, v.OperTID, v.ArticleTID, v.RecommendTID, v.ClassTID, v.Comment, ip))
  55. }
  56. func upArcTag(c *bm.Context) {
  57. var err error
  58. v := new(struct {
  59. OID int64 `form:"oid" validate:"required"`
  60. Business int8 `form:"business"`
  61. Comment string `form:"comment"`
  62. CourseTID int64 `form:"course_tid" validate:"required"`
  63. OperTID int64 `form:"oper_tid" validate:"required"`
  64. ClassTID string `form:"class_tid" validate:"required"`
  65. ArticleTID int64 `form:"article_tid"`
  66. RecommendTID int64 `form:"recommend_tid" validate:"required"`
  67. })
  68. if err = c.Bind(v); err != nil {
  69. return
  70. }
  71. if v.OID == 0 {
  72. c.JSON(nil, ecode.RequestErr)
  73. return
  74. }
  75. if _, err = checkExist(v.OID); err != nil {
  76. c.JSON(nil, err)
  77. return
  78. }
  79. uid, uname := getUIDName(c)
  80. action := ""
  81. if v.Business == academy.BusinessForArchvie {
  82. action = "更新单个视频稿件"
  83. } else if v.Business == academy.BusinessForArticle {
  84. action = "更新单个专栏稿件"
  85. }
  86. svc.SendAcademyLog(c, &academy.LogParam{UID: uid, UName: uname, Action: action, OIDs: xstr.JoinInts([]int64{v.OID})})
  87. c.JSON(nil, bulkUpdateArcs([]int64{v.OID}, v.Business, v.CourseTID, v.OperTID, v.ArticleTID, v.RecommendTID, v.ClassTID, v.Comment))
  88. }
  89. func removeArcTag(c *bm.Context) {
  90. var err error
  91. v := new(struct {
  92. OID int64 `form:"oid" validate:"required"`
  93. Business int8 `form:"business"`
  94. })
  95. if err = c.Bind(v); err != nil {
  96. return
  97. }
  98. if v.OID == 0 {
  99. c.JSON(nil, ecode.RequestErr)
  100. return
  101. }
  102. if _, err = checkExist(v.OID); err != nil {
  103. c.JSON(nil, err)
  104. return
  105. }
  106. uid, uname := getUIDName(c)
  107. action := ""
  108. if v.Business == academy.BusinessForArchvie {
  109. action = "移除单个视频稿件"
  110. } else if v.Business == academy.BusinessForArticle {
  111. action = "移除单个专栏稿件"
  112. }
  113. svc.SendAcademyLog(c, &academy.LogParam{UID: uid, UName: uname, Action: action, OIDs: xstr.JoinInts([]int64{v.OID})})
  114. c.JSON(nil, bulkRemoveArcs([]int64{v.OID}, v.Business))
  115. }
  116. func viewArc(c *bm.Context) {
  117. var err error
  118. v := new(struct {
  119. OID int64 `form:"oid"`
  120. Business int8 `form:"business"`
  121. })
  122. if err = c.Bind(v); err != nil {
  123. return
  124. }
  125. if v.OID == 0 {
  126. c.JSON(nil, ecode.RequestErr)
  127. return
  128. }
  129. if _, err = checkExist(v.OID); err != nil {
  130. c.JSON(nil, err)
  131. return
  132. }
  133. ap := &academy.EsParam{
  134. OID: v.OID,
  135. Business: v.Business,
  136. State: academy.DefaultState,
  137. Pn: 1,
  138. Ps: 1,
  139. IP: metadata.String(c, metadata.RemoteIP),
  140. }
  141. res, err := search(c, ap)
  142. if err != nil {
  143. c.JSON(nil, err)
  144. return
  145. }
  146. if res == nil || len(res.Items) == 0 {
  147. c.JSON(nil, ecode.NothingFound)
  148. return
  149. }
  150. c.JSON(res.Items, nil)
  151. }
  152. func listArc(c *bm.Context) {
  153. var (
  154. err error
  155. tids []int64
  156. tidsMap map[int][]int64
  157. )
  158. v := new(struct {
  159. OID int64 `form:"oid"`
  160. Keyword string `form:"keyword"`
  161. Uname string `form:"uname"`
  162. Business int8 `form:"business"`
  163. TID string `form:"tids"`
  164. State int `form:"state" default:"2018"`
  165. Copyright int `form:"copyright"`
  166. Pn int `form:"pn" validate:"required,min=1"`
  167. Ps int `form:"ps" validate:"required,min=1"`
  168. })
  169. if err = c.Bind(v); err != nil {
  170. return
  171. }
  172. if v.Pn == 0 {
  173. v.Pn = 1
  174. }
  175. if v.Ps > 20 {
  176. v.Ps = 20
  177. }
  178. if v.TID != "" {
  179. if tids, err = xstr.SplitInts(v.TID); err != nil {
  180. log.Error("strconv.ParseInt(%s) error(%v)", v.TID, err)
  181. c.JSON(nil, ecode.RequestErr)
  182. return
  183. }
  184. if len(tids) >= 0 {
  185. tags, getMapErr := getTagParentChildMap()
  186. if getMapErr != nil {
  187. c.JSON(nil, getMapErr)
  188. return
  189. }
  190. tidsMap = filterTIDs(tids, tags)
  191. }
  192. }
  193. ap := &academy.EsParam{
  194. OID: v.OID,
  195. Keyword: v.Keyword,
  196. Business: v.Business,
  197. Uname: v.Uname,
  198. TID: tids,
  199. Copyright: v.Copyright,
  200. State: v.State,
  201. Pn: v.Pn,
  202. Ps: v.Ps,
  203. IP: metadata.String(c, metadata.RemoteIP),
  204. TidsMap: tidsMap,
  205. }
  206. res, err := search(c, ap)
  207. if err != nil {
  208. c.JSON(nil, err)
  209. return
  210. }
  211. c.Render(http.StatusOK, render.MapJSON(map[string]interface{}{
  212. "code": 0,
  213. "message": "0",
  214. "data": res,
  215. }))
  216. }
  217. func bindArcInfo(c context.Context, oids []int64, bs int8, ip string) (res map[int64]*academy.ArchiveMeta, err error) {
  218. res = make(map[int64]*academy.ArchiveMeta)
  219. if bs == academy.BusinessForArchvie {
  220. arcs, err := svc.Archives(c, oids)
  221. if err != nil {
  222. return nil, err
  223. }
  224. stat, err := svc.Stats(c, oids, ip)
  225. if err != nil {
  226. log.Error("s.arc.Stats oids(%+v)|business(%d)|error(%v)", oids, bs, err)
  227. return nil, err
  228. }
  229. for _, oid := range oids {
  230. a := &academy.ArchiveMeta{}
  231. if v, ok := arcs[oid]; ok && v != nil {
  232. a.OID = oid
  233. a.Title = v.Title
  234. a.State = v.State
  235. a.Type = v.TypeName
  236. a.Cover = v.Pic
  237. a.UName = v.Author.Name
  238. if t, ok := stat[oid]; ok && t != nil {
  239. a.Hot = countArcHot(t, int64(v.PubDate))
  240. }
  241. res[oid] = a
  242. }
  243. }
  244. } else if bs == academy.BusinessForArticle {
  245. arts, err := svc.Articles(c, oids)
  246. if err != nil {
  247. return nil, err
  248. }
  249. for _, oid := range oids {
  250. if v, ok := arts[oid]; ok && v != nil {
  251. a := &academy.ArchiveMeta{
  252. OID: oid,
  253. Title: v.Title,
  254. State: v.State,
  255. }
  256. if v.Category != nil {
  257. a.Type = v.Category.Name
  258. }
  259. if len(v.ImageURLs) > 0 {
  260. a.Cover = v.ImageURLs[0]
  261. }
  262. if v.Author != nil {
  263. a.UName = v.Author.Name
  264. }
  265. a.Hot = countArtHot(v)
  266. res[oid] = a
  267. }
  268. }
  269. }
  270. return
  271. }
  272. func bindTags(oidTIDsMap map[int64][]int64) (res map[int64]map[int][]*academy.TagMeta, err error) {
  273. res = make(map[int64]map[int][]*academy.TagMeta)
  274. for oid, tids := range oidTIDsMap {
  275. var tags []*academy.Tag
  276. if err = svc.DB.Model(&academy.Tag{}).Where("id in (?)", tids).Find(&tags).Error; err != nil {
  277. log.Error("creative-admin bindTags error(%v)", err)
  278. return
  279. }
  280. oidTIDs := make(map[int][]*academy.TagMeta)
  281. ctgs := make(map[int64][]*academy.TagMeta)
  282. for _, v := range tags {
  283. tg := renderTag(v)
  284. switch tg.Type {
  285. case academy.Course:
  286. oidTIDs[academy.Course] = append(oidTIDs[academy.Course], tg)
  287. case academy.Operation:
  288. oidTIDs[academy.Operation] = append(oidTIDs[academy.Operation], tg)
  289. case academy.Classify:
  290. ctgs[tg.ParentID] = append(ctgs[tg.ParentID], tg)
  291. case academy.ArticleClass:
  292. oidTIDs[academy.ArticleClass] = append(oidTIDs[academy.ArticleClass], tg)
  293. case academy.Recommend:
  294. oidTIDs[academy.Recommend] = append(oidTIDs[academy.Recommend], tg)
  295. }
  296. }
  297. for pid, tgs := range ctgs {
  298. parent := &academy.Tag{}
  299. if err = svc.DB.Model(&academy.Tag{}).Where("id = ?", pid).Find(parent).Error; err != nil {
  300. log.Error("creative-admin bindTags get parent tag error(%v)", err)
  301. continue
  302. }
  303. p := renderTag(parent)
  304. p.Children = tgs
  305. oidTIDs[academy.Classify] = append(oidTIDs[academy.Classify], p)
  306. }
  307. res[oid] = oidTIDs
  308. }
  309. return
  310. }
  311. func batchAddArc(c *bm.Context) {
  312. var (
  313. err error
  314. oids, newOIDs, oldOIDs []int64
  315. )
  316. v := new(struct {
  317. OIDs string `form:"oids" validate:"required"`
  318. Business int8 `form:"business"`
  319. Comment string `form:"comment"`
  320. CourseTID int64 `form:"course_tid" validate:"required"`
  321. OperTID int64 `form:"oper_tid" validate:"required"`
  322. ClassTID string `form:"class_tid" validate:"required"`
  323. ArticleTID int64 `form:"article_tid"`
  324. RecommendTID int64 `form:"recommend_tid" validate:"required"`
  325. })
  326. ip := metadata.String(c, metadata.RemoteIP)
  327. if err = c.Bind(v); err != nil {
  328. return
  329. }
  330. if v.OIDs != "" {
  331. if oids, err = xstr.SplitInts(v.OIDs); err != nil {
  332. log.Error("batchAddArc xstr.SplitInts OIDs(%+v)|error(%v)", v.OIDs, err)
  333. c.JSON(nil, ecode.RequestErr)
  334. return
  335. }
  336. }
  337. for _, oid := range oids {
  338. if arc, err := checkExist(oid); err == nil && arc.OID != 0 { //表里已存在该稿件
  339. oldOIDs = append(oldOIDs, oid)
  340. } else {
  341. newOIDs = append(newOIDs, oid)
  342. }
  343. }
  344. if len(newOIDs) == 0 {
  345. log.Error("batchAddArc oldOIDs(%+v)", oldOIDs)
  346. c.JSON(nil, ecode.CreativeAcademyOIDExistErr)
  347. return
  348. }
  349. uid, uname := getUIDName(c)
  350. action := ""
  351. if v.Business == academy.BusinessForArchvie {
  352. action = "批量添加视频稿件"
  353. } else if v.Business == academy.BusinessForArticle {
  354. action = "批量添加专栏稿件"
  355. }
  356. svc.SendAcademyLog(c, &academy.LogParam{UID: uid, UName: uname, Action: action, OIDs: xstr.JoinInts(newOIDs)})
  357. c.JSON(nil, bulkInsertArcs(c, newOIDs, v.Business, v.CourseTID, v.OperTID, v.ArticleTID, v.RecommendTID, v.ClassTID, v.Comment, ip))
  358. }
  359. //批量插入稿件表
  360. func bulkInsertArcs(c *bm.Context, oids []int64, bs int8, courseTID, operTID, articleTID, recommendTID int64, classTID, comment, ip string) (err error) {
  361. arcInfo, err := bindArcInfo(c, oids, bs, ip)
  362. if err != nil {
  363. return err
  364. }
  365. arcs := make([]*academy.Archive, 0, len(oids))
  366. for _, oid := range oids {
  367. a, ok := arcInfo[oid]
  368. if !ok || a == nil { //校验oid是否有效
  369. if bs == academy.BusinessForArchvie {
  370. err = ecode.CreativeArcServiceErr
  371. } else if bs == academy.BusinessForArticle {
  372. err = ecode.CreativeArticleRPCErr
  373. }
  374. log.Error("bulkInsertArcs add archive with invalid oid(%d)|business(%d)", oid, bs)
  375. return
  376. }
  377. arcs = append(arcs, setArcParam(oid, a.Hot, bs, comment))
  378. }
  379. valArcs := make([]string, 0, len(arcs))
  380. valArcArgs := make([]interface{}, 0)
  381. for _, v := range arcs {
  382. valArcs = append(valArcs, "(?, ?, ?, ?, ?, ?, ?)")
  383. valArcArgs = append(valArcArgs, v.OID, v.Hot, v.Business, v.State, v.Comment, v.CTime, v.MTime)
  384. }
  385. //批量插入稿件标签关联表
  386. ctids, err := xstr.SplitInts(classTID)
  387. if err != nil {
  388. return
  389. }
  390. tags := make([]*academy.ArchiveTag, 0)
  391. for _, oid := range oids {
  392. tags = append(tags, setTagParam(oid, courseTID, bs), setTagParam(oid, operTID, bs), setTagParam(oid, recommendTID, bs))
  393. for _, cid := range ctids { //分类标签支持绑定多个二级标签
  394. tags = append(tags, setTagParam(oid, cid, bs))
  395. }
  396. if bs == academy.BusinessForArticle && articleTID > 0 { //专栏特殊分类
  397. tags = append(tags, setTagParam(oid, articleTID, bs))
  398. }
  399. }
  400. valTags := make([]string, 0)
  401. valTagArgs := make([]interface{}, 0)
  402. for _, v := range tags {
  403. valTags = append(valTags, "(?, ?, ?, ?, ?, ?)")
  404. valTagArgs = append(valTagArgs, v.OID, v.TID, v.State, v.CTime, v.MTime, v.Business)
  405. }
  406. sqlArcStr := fmt.Sprintf("INSERT INTO academy_archive (oid, hot, business, state, comment, ctime, mtime) VALUES %s ON DUPLICATE KEY UPDATE state=0, comment=VALUES(comment), mtime=VALUES(mtime)", strings.Join(valArcs, ","))
  407. sqlTagStr := fmt.Sprintf("INSERT INTO academy_archive_tag (oid, tid, state, ctime, mtime, business) VALUES %s ON DUPLICATE KEY UPDATE state=0, mtime=VALUES(mtime)", strings.Join(valTags, ","))
  408. tx := svc.DB.Begin()
  409. if err = tx.Exec(sqlArcStr, valArcArgs...).Error; err != nil {
  410. log.Error("creative-admin bulkInsertArcs error(%v)", err)
  411. tx.Rollback()
  412. return
  413. }
  414. if err = tx.Exec(sqlTagStr, valTagArgs...).Error; err != nil {
  415. log.Error("creative-admin bulkInsertArcs error(%v)", err)
  416. tx.Rollback()
  417. return
  418. }
  419. tx.Commit()
  420. return nil
  421. }
  422. func setArcParam(oid, hot int64, bs int8, comment string) (arc *academy.Archive) {
  423. now := time.Now().Format("2006-01-02 15:04:05")
  424. arc = &academy.Archive{
  425. OID: oid,
  426. Business: bs,
  427. CTime: now,
  428. MTime: now,
  429. Comment: comment,
  430. Hot: hot,
  431. State: academy.StateNormal,
  432. }
  433. return
  434. }
  435. func setTagParam(oid, tid int64, bs int8) (res *academy.ArchiveTag) {
  436. now := time.Now().Format("2006-01-02 15:04:05")
  437. res = &academy.ArchiveTag{
  438. OID: oid,
  439. TID: tid,
  440. CTime: now,
  441. MTime: now,
  442. Business: bs,
  443. State: academy.StateNormal,
  444. }
  445. return
  446. }
  447. func batchUpArc(c *bm.Context) {
  448. var (
  449. err error
  450. oids []int64
  451. )
  452. v := new(struct {
  453. OIDs string `form:"oids" validate:"required"`
  454. Business int8 `form:"business"`
  455. Comment string `form:"comment"`
  456. CourseTID int64 `form:"course_tid" validate:"required"`
  457. OperTID int64 `form:"oper_tid" validate:"required"`
  458. ClassTID string `form:"class_tid" validate:"required"`
  459. ArticleTID int64 `form:"article_tid"`
  460. RecommendTID int64 `form:"recommend_tid" validate:"required"`
  461. })
  462. if err = c.Bind(v); err != nil {
  463. return
  464. }
  465. if v.OIDs != "" {
  466. if oids, err = xstr.SplitInts(v.OIDs); err != nil {
  467. c.JSON(nil, ecode.RequestErr)
  468. return
  469. }
  470. }
  471. for _, oid := range oids {
  472. if _, err = checkExist(oid); err != nil {
  473. c.JSON(nil, err)
  474. return
  475. }
  476. }
  477. uid, uname := getUIDName(c)
  478. action := ""
  479. if v.Business == academy.BusinessForArchvie {
  480. action = "批量更新视频稿件"
  481. } else if v.Business == academy.BusinessForArticle {
  482. action = "批量更新专栏稿件"
  483. }
  484. svc.SendAcademyLog(c, &academy.LogParam{UID: uid, UName: uname, Action: action, OIDs: xstr.JoinInts(oids)})
  485. c.JSON(nil, bulkUpdateArcs(oids, v.Business, v.CourseTID, v.OperTID, v.ArticleTID, v.RecommendTID, v.ClassTID, v.Comment))
  486. }
  487. func bulkUpdateArcs(oids []int64, bs int8, courseTID, operTID, articleTID, recommendTID int64, classTID, comment string) (err error) {
  488. var (
  489. tids []int64
  490. arcTags []*academy.ArchiveTags
  491. arcMapTids map[int64][]int64
  492. delOIDTidsMap, newOIDTidsMap map[int64][]int64
  493. )
  494. //更新其他类别标签
  495. var (
  496. ats []*academy.ArchiveTags
  497. ids []int64
  498. )
  499. if err = svc.DB.Raw("SELECT b.*, c.type FROM (SELECT t.id,t.tid,a.oid FROM academy_archive AS a LEFT JOIN academy_archive_tag AS t ON t.oid = a.oid WHERE a.oid IN (?) AND a.business=? AND a.state=0 AND t.state=0) b LEFT JOIN academy_tag AS c ON c.id=b.tid WHERE c.type!=?", oids, bs, academy.Classify).Find(&ats).Error; err != nil {
  500. log.Error("creative-admin bulkUpdateArcs get all archive tags error(%v)", err)
  501. return
  502. }
  503. if len(ats) == 0 {
  504. return
  505. }
  506. ids = make([]int64, 0, len(ats))
  507. for _, a := range ats {
  508. if a == nil {
  509. log.Error("creative-admin bulkUpdateArcs update other tags get nil a(%+v)", a)
  510. return
  511. }
  512. ids = append(ids, a.ID)
  513. }
  514. tx := svc.DB.Begin()
  515. // 对于提交上来的其他标签先统一删除再统一插入
  516. if err = tx.Model(&academy.ArchiveTag{}).Where("id IN (?)", ids).
  517. Updates(map[string]interface{}{
  518. "state": academy.StateRemove,
  519. }).Error; err != nil {
  520. log.Error("bulkUpdateArcs first delete other tags by ids(%v)|error(%v)", ids, err)
  521. tx.Rollback()
  522. return
  523. }
  524. tags := make([]*academy.ArchiveTag, 0)
  525. for _, oid := range oids {
  526. tags = append(tags, setTagParam(oid, courseTID, bs), setTagParam(oid, operTID, bs), setTagParam(oid, recommendTID, bs))
  527. if bs == academy.BusinessForArticle && articleTID > 0 { //专栏特殊分类
  528. tags = append(tags, setTagParam(oid, articleTID, bs))
  529. }
  530. }
  531. valTags := make([]string, 0)
  532. valTagArgs := make([]interface{}, 0)
  533. for _, v := range tags {
  534. valTags = append(valTags, "(?, ?, ?, ?, ?, ?)")
  535. valTagArgs = append(valTagArgs, v.OID, v.TID, v.State, v.CTime, v.MTime, v.Business)
  536. }
  537. sqlTagStr := fmt.Sprintf("INSERT INTO academy_archive_tag (oid, tid, state, ctime, mtime, business) VALUES %s ON DUPLICATE KEY UPDATE state=0,oid=VALUES(oid),tid=VALUES(tid),business=VALUES(business)", strings.Join(valTags, ","))
  538. if err = tx.Exec(sqlTagStr, valTagArgs...).Error; err != nil {
  539. log.Error("bulkUpdateArcs update other tags valTagArgs(%+v)", valTagArgs...)
  540. tx.Rollback()
  541. return
  542. }
  543. //处理分类标签
  544. tids, err = xstr.SplitInts(classTID)
  545. if err != nil {
  546. return err
  547. }
  548. if err = svc.DB.Raw("SELECT b.*, c.type FROM (SELECT t.id,t.tid,a.oid FROM academy_archive AS a LEFT JOIN academy_archive_tag AS t ON t.oid = a.oid WHERE a.oid IN (?) AND a.business=? AND a.state=0 AND t.state=0) b LEFT JOIN academy_tag AS c ON c.id=b.tid WHERE c.type=?", oids, bs, academy.Classify).Find(&arcTags).Error; err != nil {
  549. log.Error("creative-admin bulkUpdateArcs archive class tags error(%v)", err)
  550. return
  551. }
  552. arcMapTids = make(map[int64][]int64)
  553. for _, v := range arcTags {
  554. arcMapTids[v.OID] = append(arcMapTids[v.OID], v.TID)
  555. }
  556. newOIDTidsMap = make(map[int64][]int64)
  557. delOIDTidsMap = make(map[int64][]int64)
  558. for oid, ids := range arcMapTids {
  559. isInDB := make(map[int64]int64)
  560. for _, id := range ids {
  561. isInDB[id] = id
  562. }
  563. log.Info("creative-admin bulkUpdateArcs oid(%d)|isInDB(%+v)", oid, isInDB)
  564. isInSub := make(map[int64]int64)
  565. for _, tid := range tids {
  566. isInSub[tid] = tid
  567. if _, ok := isInDB[tid]; !ok {
  568. newOIDTidsMap[oid] = append(newOIDTidsMap[oid], tid)
  569. }
  570. }
  571. log.Info("creative-admin bulkUpdateArcs oid(%d)|isInSubmit(%+v)", oid, isInSub)
  572. for _, id := range ids {
  573. if _, ok := isInSub[id]; !ok {
  574. delOIDTidsMap[oid] = append(delOIDTidsMap[oid], id)
  575. }
  576. }
  577. }
  578. if len(newOIDTidsMap) > 0 { //insert on update
  579. tags := make([]*academy.ArchiveTag, 0)
  580. for oid, tgs := range newOIDTidsMap { //分类标签支持绑定多个二级标签
  581. for _, cid := range tgs {
  582. tags = append(tags, setTagParam(oid, cid, bs))
  583. }
  584. }
  585. valTags := make([]string, 0)
  586. valTagArgs := make([]interface{}, 0)
  587. for _, v := range tags {
  588. valTags = append(valTags, "(?, ?, ?, ?, ?, ?)")
  589. valTagArgs = append(valTagArgs, v.OID, v.TID, v.State, v.CTime, v.MTime, v.Business)
  590. }
  591. sqlTagStr := fmt.Sprintf("INSERT INTO academy_archive_tag (oid, tid, state, ctime, mtime, business) VALUES %s ON DUPLICATE KEY UPDATE state=0, oid=VALUES(oid), tid=VALUES(tid), business=VALUES(business), mtime=VALUES(mtime)", strings.Join(valTags, ","))
  592. if err = tx.Exec(sqlTagStr, valTagArgs...).Error; err != nil {
  593. log.Error("creative-admin bulkUpdateArcs insert new class tags error(%v)", err)
  594. tx.Rollback()
  595. return
  596. }
  597. }
  598. if len(delOIDTidsMap) > 0 { //delete
  599. delMapID := make(map[int64]int64)
  600. for _, tgs := range delOIDTidsMap {
  601. for _, tid := range tgs {
  602. delMapID[tid] = tid
  603. }
  604. }
  605. delIDs := make([]int64, 0)
  606. for _, a := range arcTags {
  607. if _, ok := delMapID[a.TID]; ok {
  608. delIDs = append(delIDs, a.ID)
  609. }
  610. }
  611. if err = tx.Model(&academy.ArchiveTag{}).Where("id IN (?)", delIDs).
  612. Updates(map[string]interface{}{
  613. "state": academy.StateRemove,
  614. "mtime": time.Now().Format("2006-01-02 15:04:05"),
  615. }).Error; err != nil {
  616. log.Error("creative-admin bulkUpdateArcs delete class tags by ids(%v)|error(%v)", delIDs, err)
  617. tx.Rollback()
  618. return
  619. }
  620. }
  621. // 统一更新comment
  622. if err = tx.Model(&academy.Archive{}).Where("business = ?", bs).Where("oid IN (?)", oids).
  623. Updates(map[string]interface{}{
  624. "comment": comment,
  625. "mtime": time.Now().Format("2006-01-02 15:04:05"),
  626. }).Error; err != nil {
  627. log.Error("creative-admin bulkUpdateArcs update all comment error(%v)", err)
  628. tx.Rollback()
  629. return
  630. }
  631. tx.Commit()
  632. return
  633. }
  634. func batchRemoveArc(c *bm.Context) {
  635. var (
  636. err error
  637. oids []int64
  638. )
  639. v := new(struct {
  640. OIDs string `form:"oids" validate:"required"`
  641. Business int8 `form:"business"`
  642. })
  643. if err = c.Bind(v); err != nil {
  644. return
  645. }
  646. if v.OIDs != "" {
  647. if oids, err = xstr.SplitInts(v.OIDs); err != nil {
  648. c.JSON(nil, ecode.RequestErr)
  649. return
  650. }
  651. }
  652. for _, oid := range oids {
  653. if _, err = checkExist(oid); err != nil {
  654. c.JSON(nil, err)
  655. return
  656. }
  657. }
  658. uid, uname := getUIDName(c)
  659. action := ""
  660. if v.Business == academy.BusinessForArchvie {
  661. action = "批量移除视频稿件"
  662. } else if v.Business == academy.BusinessForArticle {
  663. action = "批量移除专栏稿件"
  664. }
  665. svc.SendAcademyLog(c, &academy.LogParam{UID: uid, UName: uname, Action: action, OIDs: xstr.JoinInts(oids)})
  666. c.JSON(nil, bulkRemoveArcs(oids, v.Business))
  667. }
  668. func bulkRemoveArcs(oids []int64, bs int8) (err error) {
  669. var (
  670. db *gorm.DB
  671. now = time.Now().Format("2006-01-02 15:04:05")
  672. ats []*academy.ArchiveTags
  673. IDs []int64
  674. )
  675. db = svc.DB.Raw("SELECT t.id,t.tid,a.oid,a.business FROM academy_archive AS a LEFT JOIN academy_archive_tag AS t ON t.oid = a.oid WHERE a.oid IN (?) AND a.business=?", oids, bs)
  676. if err = db.Find(&ats).Error; err != nil {
  677. log.Error("creative-admin bulkRemoveArcs error(%v)", err)
  678. return
  679. }
  680. if len(ats) == 0 {
  681. return
  682. }
  683. for _, a := range ats {
  684. IDs = append(IDs, a.ID)
  685. }
  686. tx := svc.DB.Begin()
  687. if err = tx.Model(&academy.Archive{}).Where("oid IN (?) AND business=?", oids, bs).Updates(map[string]interface{}{
  688. "mtime": now,
  689. "state": academy.StateRemove,
  690. }).Error; err != nil {
  691. log.Error("creative-admin bulkRemoveArcs error(%v)", err)
  692. tx.Rollback()
  693. return
  694. }
  695. if err = tx.Model(&academy.ArchiveTag{}).Where("id IN (?)", IDs).Updates(map[string]interface{}{
  696. "mtime": now,
  697. "state": academy.StateRemove,
  698. }).Error; err != nil {
  699. tx.Rollback()
  700. log.Error("creative-admin bulkRemoveArcs error(%v)", err)
  701. return
  702. }
  703. tx.Commit()
  704. return
  705. }
  706. func arcCountByTids(tids []int64) (res map[int64]int, err error) {
  707. var (
  708. countSQL = "SELECT tid, count(DISTINCT oid) AS count FROM academy_archive_tag WHERE state=0 AND tid IN (?) GROUP BY tid"
  709. ats []*academy.ArchiveCount
  710. )
  711. if err = svc.DB.Raw(countSQL, tids).Find(&ats).Error; err != nil {
  712. log.Error("creative-admin get arcCountByTids error(%v)", err)
  713. return
  714. }
  715. if len(ats) == 0 {
  716. return
  717. }
  718. res = make(map[int64]int)
  719. for _, a := range ats {
  720. res[a.TID] = a.Count
  721. }
  722. return
  723. }
  724. func checkExist(oid int64) (arc *academy.Archive, err error) {
  725. arc = &academy.Archive{}
  726. err = svc.DB.Model(&academy.Archive{}).Where("state=?", academy.StateNormal).Where("oid=?", oid).Find(arc).Error
  727. if err != nil {
  728. if err != gorm.ErrRecordNotFound {
  729. log.Error("creative-admin checkExist oid(%d)|error(%v)", oid, err)
  730. }
  731. }
  732. return
  733. }
  734. func fixArchive(c *bm.Context) {
  735. var err error
  736. v := new(struct {
  737. ID int64 `form:"id"`
  738. OID int64 `form:"oid"`
  739. Business int8 `form:"business"`
  740. State int8 `form:"state"`
  741. })
  742. if err = c.Bind(v); err != nil {
  743. return
  744. }
  745. if err = svc.DB.Model(&academy.Archive{}).Where("id=?", v.ID).Updates(map[string]interface{}{
  746. "oid": v.OID,
  747. "business": v.Business,
  748. "state": v.State,
  749. "mtime": time.Now().Format("2006-01-02 15:04:05"),
  750. }).Error; err != nil {
  751. log.Error("creative-admin fixArchive error(%v)", err)
  752. }
  753. c.JSON(nil, err)
  754. }
  755. func search(c *bm.Context, ap *academy.EsParam) (res *academy.Archives, err error) {
  756. var (
  757. oids []int64
  758. tempMapTIDs map[int64][]int64
  759. arcs []*academy.ArchiveOrigin
  760. items []*academy.ArchiveMeta
  761. com = make(map[int64]string)
  762. )
  763. res = &academy.Archives{
  764. Items: []*academy.ArchiveMeta{},
  765. Pager: &academy.Pager{},
  766. }
  767. sear, err := svc.ArchivesWithES(c, ap)
  768. if err != nil {
  769. log.Error("search svc.ArchivesWithES error(%v)", err)
  770. return
  771. }
  772. arcs = make([]*academy.ArchiveOrigin, 0)
  773. if sear == nil || len(sear.Result) == 0 {
  774. return
  775. }
  776. tempMapTIDs = make(map[int64][]int64)
  777. for _, v := range sear.Result {
  778. oids = append(oids, v.OID)
  779. tempMapTIDs[v.OID] = v.TID
  780. }
  781. res.Pager.Total = sear.Page.Total
  782. res.Pager.Num = sear.Page.Num
  783. res.Pager.Size = sear.Page.Size
  784. g, _ := errgroup.WithContext(c)
  785. var (
  786. arcInfo map[int64]*academy.ArchiveMeta
  787. tagInfo map[int64]map[int][]*academy.TagMeta
  788. bindMapTIDs map[int64][]int64
  789. )
  790. bindMapTIDs = make(map[int64][]int64)
  791. for _, oid := range oids {
  792. if v, ok := tempMapTIDs[oid]; ok {
  793. bindMapTIDs[oid] = v
  794. }
  795. }
  796. g.Go(func() error {
  797. arcInfo, err = bindArcInfo(c, oids, ap.Business, metadata.String(c, metadata.RemoteIP))
  798. return err
  799. })
  800. g.Go(func() error {
  801. com, err = bindArcComment(oids, ap.Business)
  802. return err
  803. })
  804. g.Go(func() error {
  805. tagInfo, err = bindTags(bindMapTIDs)
  806. return err
  807. })
  808. if err = g.Wait(); err != nil {
  809. return
  810. }
  811. log.Info("search arcInfo(%s)", spew.Sdump(arcInfo))
  812. items = make([]*academy.ArchiveMeta, 0, len(arcs))
  813. for _, oid := range oids {
  814. a, ok := arcInfo[oid]
  815. if !ok || a == nil {
  816. log.Error("search get archive info error by oid(%d)", oid)
  817. return
  818. }
  819. if v, ok := tagInfo[oid]; ok {
  820. a.Tags = v
  821. }
  822. if co, ok := com[oid]; ok {
  823. a.Comment = co
  824. }
  825. items = append(items, a)
  826. }
  827. res.Items = items
  828. return
  829. }
  830. func bindArcComment(oids []int64, bs int8) (res map[int64]string, err error) {
  831. var arcs []*academy.Archive
  832. if err = svc.DB.Model(&academy.Archive{}).Where("oid in(?)", oids).Where("business=?", bs).Group("oid").Find(&arcs).Error; err != nil {
  833. log.Error("bindArcComment d.DB.Model oids(%+v)|business(%d)|error(%v)", oids, bs, err)
  834. return
  835. }
  836. res = make(map[int64]string)
  837. for _, v := range arcs {
  838. res[v.OID] = v.Comment
  839. }
  840. return
  841. }
  842. //countArcHot 视频=硬币*0.4+收藏*0.3+弹幕*0.4+评论*0.4+播放*0.25+点赞*0.4+分享*0.6 最新视频(一天内发布)提权[总值*1.5]
  843. func countArcHot(t *api.Stat, ptime int64) int64 {
  844. if t == nil {
  845. return 0
  846. }
  847. hot := float64(t.Coin)*0.4 +
  848. float64(t.Fav)*0.3 +
  849. float64(t.Danmaku)*0.4 +
  850. float64(t.Reply)*0.4 +
  851. float64(t.View)*0.25 +
  852. float64(t.Like)*0.4 +
  853. float64(t.Share)*0.6
  854. if ptime >= time.Now().AddDate(0, 0, -1).Unix() && ptime <= time.Now().Unix() {
  855. hot *= 1.5
  856. }
  857. return int64(math.Floor(hot))
  858. }
  859. // countArtHot 专栏=硬币*0.4+收藏*0.3+评论*0.4+阅读*0.25+点赞*0.4+分享*0.6 最新专栏(一天内发布)提权[总值*1.5]
  860. func countArtHot(t *model.Meta) int64 {
  861. if t.Stats == nil {
  862. return 0
  863. }
  864. hot := float64(t.Stats.Coin)*0.4 +
  865. float64(t.Stats.Favorite)*0.3 +
  866. float64(t.Stats.Reply)*0.4 +
  867. float64(t.Stats.View)*0.25 +
  868. float64(t.Stats.Like)*0.4 +
  869. float64(t.Stats.Share)*0.6
  870. if int64(t.PublishTime) >= time.Now().AddDate(0, 0, -1).Unix() && int64(t.PublishTime) <= time.Now().Unix() {
  871. hot *= 1.5
  872. }
  873. return int64(math.Floor(hot))
  874. }
  875. // getParentChildMap
  876. func getTagParentChildMap() (res map[int64]*academy.Tag, err error) {
  877. var (
  878. db *gorm.DB
  879. tags []*academy.Tag
  880. )
  881. db = svc.DB.Order("rank ASC").Find(&tags)
  882. if err = db.Error; err != nil {
  883. log.Error("creative-admin getTagParentChildMap error(%v)", err)
  884. return
  885. }
  886. res = make(map[int64]*academy.Tag)
  887. for _, t := range tags {
  888. res[t.ID] = t
  889. }
  890. for _, v := range res {
  891. if v == nil {
  892. continue
  893. }
  894. if v.ParentID == 0 {
  895. for _, t := range tags {
  896. if t == nil {
  897. continue
  898. }
  899. if t.ParentID == v.ID {
  900. v.Children = append(v.Children, t)
  901. }
  902. }
  903. }
  904. }
  905. return
  906. }
  907. // filterTIDs
  908. func filterTIDs(tids []int64, parentChildMap map[int64]*academy.Tag) (res map[int][]int64) {
  909. if len(tids) == 0 {
  910. return
  911. }
  912. log.Info("s.filterTIDs origin tids(%+v)", tids)
  913. res = make(map[int][]int64)
  914. ochs := make([]int64, 0) //原始提交的二级标签
  915. ops := make([]int64, 0) //原始提交的一级标签
  916. qchs := make([]int64, 0) //通过一级标签查询出来的二级标签
  917. for _, id := range tids {
  918. t, ok := parentChildMap[id]
  919. if !ok || t == nil {
  920. continue
  921. }
  922. if t.Type == academy.Classify {
  923. if t.ParentID != 0 { //原始提交的二级标签
  924. ochs = append(ochs, id)
  925. } else if t.ParentID == 0 && len(t.Children) > 0 { //通过一级标签查询出来的二级标签
  926. for _, v := range t.Children {
  927. qchs = append(qchs, v.ID)
  928. }
  929. } else if t.ParentID == 0 && len(t.Children) == 0 {
  930. ops = append(ops, id)
  931. }
  932. } else {
  933. res[int(t.Type)] = append(res[int(t.Type)], id)
  934. }
  935. }
  936. if len(ochs) > 0 { //如果分类标签中提交了原始的二级标签则认为按该二级标签进行筛选,如果可以查询到二级标签认为筛选全部二级,否则一级参与查询.
  937. res[academy.Classify] = ochs
  938. } else if len(qchs) > 0 {
  939. res[academy.Classify] = qchs
  940. } else if len(ops) > 0 {
  941. res[academy.Classify] = ops
  942. }
  943. log.Info("s.filterTIDs res(%s)", spew.Sdump(res))
  944. return
  945. }