venue.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. /*
  2. Package dao venue
  3. 场馆(venue)=>场地(place)=>区域(area)的三级层次,均为一对多
  4. venue表冗余place_num表示场地数,
  5. place表通过ID对应place_polygon,存有area的地理位置信息
  6. */
  7. package dao
  8. import (
  9. "context"
  10. "encoding/json"
  11. "fmt"
  12. "go-common/app/service/openplatform/ticket-item/model"
  13. "go-common/library/cache/redis"
  14. "go-common/library/database/elastic"
  15. "go-common/library/ecode"
  16. "go-common/library/log"
  17. "github.com/jinzhu/gorm"
  18. )
  19. // RawVenues 批量获取场馆
  20. func (d *Dao) RawVenues(c context.Context, ids []int64) (vl map[int64]*model.Venue, err error) {
  21. vrows, err := d.db.Model(&model.Venue{}).Where("id in (?)", ids).Rows()
  22. vl = make(map[int64]*model.Venue)
  23. if err != nil {
  24. log.Error("RawVenues(%v) error(%v)", ids, err)
  25. return
  26. }
  27. defer vrows.Close()
  28. for vrows.Next() {
  29. var v model.Venue
  30. err = d.db.ScanRows(vrows, &v)
  31. vl[v.ID] = &v
  32. }
  33. return
  34. }
  35. // CacheVenues 缓存批量获取场馆
  36. func (d *Dao) CacheVenues(c context.Context, ids []int64) (vl map[int64]*model.Venue, err error) {
  37. var keys []interface{}
  38. keyVidMap := make(map[string]int64, len(ids))
  39. for _, id := range ids {
  40. key := keyVenue(id)
  41. if _, ok := keyVidMap[key]; !ok {
  42. // duplicate pid
  43. keyVidMap[key] = id
  44. keys = append(keys, key)
  45. }
  46. }
  47. conn := d.redis.Get(c)
  48. defer conn.Close()
  49. var data [][]byte
  50. log.Info("MGET %v", model.JSONEncode(keys))
  51. if data, err = redis.ByteSlices((conn.Do("MGET", keys))); err != nil {
  52. log.Error("VenueList MGET %v ERR: %v", model.JSONEncode(keys), err)
  53. return
  54. }
  55. vl = make(map[int64]*model.Venue)
  56. for _, d := range data {
  57. if d != nil {
  58. var v *model.Venue
  59. vl[v.ID] = v
  60. json.Unmarshal(d, &v)
  61. }
  62. }
  63. return
  64. }
  65. // AddCacheVenues 缓存场馆信息
  66. func (d *Dao) AddCacheVenues(c context.Context, vl map[int64]*model.Venue) (err error) {
  67. conn := d.redis.Get(c)
  68. defer func() {
  69. conn.Flush()
  70. conn.Close()
  71. }()
  72. var data []interface{}
  73. var keys []string
  74. for k, v := range vl {
  75. b, _ := json.Marshal(v)
  76. key := keyVenue(k)
  77. keys = append(keys, key)
  78. data = append(data, key, b)
  79. }
  80. log.Info("MSET %v", keys)
  81. if err = conn.Send("MSET", data...); err != nil {
  82. return
  83. }
  84. for i := 0; i < len(data); i += 2 {
  85. conn.Send("EXPIRE", data[i], CacheTimeout)
  86. }
  87. return
  88. }
  89. // VenueSearch 场馆搜索
  90. func (d *Dao) VenueSearch(c context.Context, req *model.VenueSearchParam) (venues *model.VenueSearchList, err error) {
  91. r := d.es.NewRequest("ticket_venue").Index("ticket_venue")
  92. if req.ID > 0 {
  93. r.WhereEq("id", req.ID)
  94. } else if req.Name != "" {
  95. r.WhereLike([]string{"name"}, []string{req.Name}, false, elastic.LikeLevelLow)
  96. }
  97. if req.ProvinceID > 0 {
  98. r.WhereEq("province", req.ProvinceID)
  99. }
  100. if req.CityID > 0 {
  101. r.WhereEq("city", req.CityID)
  102. }
  103. r.Order("ctime", elastic.OrderDesc).Ps(req.Ps).Pn(req.Pn)
  104. log.Info(fmt.Sprintf("%s/x/admin/search/query?%s", d.c.URL.ElasticHost, r.Params()))
  105. venues = new(model.VenueSearchList)
  106. if err = r.Scan(c, venues); err != nil {
  107. log.Error("VenueSearch(%v) r.Query(%s) error(%s)", req, r.Params(), err)
  108. }
  109. return
  110. }
  111. // AddVenue 添加场馆信息
  112. func (d *Dao) AddVenue(c context.Context, venue *model.Venue) (err error) {
  113. if err = d.db.Create(venue).Error; err != nil {
  114. log.Error("添加场馆信息失败:%s", err)
  115. err = ecode.NotModified
  116. return
  117. }
  118. return
  119. }
  120. // UpdateVenue 编辑场馆信息
  121. func (d *Dao) UpdateVenue(c context.Context, venue *model.Venue) (err error) {
  122. // update venue with new info (using map can update the column with empty string)
  123. if err = d.db.Table("venue").Where("id = ?", venue.ID).Updates(
  124. map[string]interface{}{
  125. "name": venue.Name,
  126. "city": venue.City,
  127. "province": venue.Province,
  128. "district": venue.District,
  129. "address_detail": venue.AddressDetail,
  130. "status": venue.Status,
  131. "traffic": venue.Traffic,
  132. }).Error; err != nil {
  133. log.Error("更新场馆信息失败:%s", err)
  134. err = ecode.NotModified
  135. return
  136. }
  137. return
  138. }
  139. // TxIncPlaceNum 增加场馆的场地数(事务)
  140. func (d *Dao) TxIncPlaceNum(c context.Context, tx *gorm.DB, venueID int64) (err error) {
  141. var oriVenue model.Venue
  142. if err = tx.First(&oriVenue, venueID).Error; err != nil {
  143. log.Error("查找对应的场馆信息(ID:%d)失败:%s", venueID, err)
  144. err = ecode.NotModified
  145. return
  146. }
  147. if err = tx.Model(&oriVenue).Updates(
  148. map[string]interface{}{
  149. "place_num": oriVenue.PlaceNum + 1,
  150. }).Error; err != nil {
  151. log.Error("更新场馆信息(ID:%d)失败:%s", venueID, err)
  152. err = ecode.NotModified
  153. return
  154. }
  155. return
  156. }
  157. // TxDecPlaceNum 减少场馆的场地数(事务)
  158. func (d *Dao) TxDecPlaceNum(c context.Context, tx *gorm.DB, venueID int64) (err error) {
  159. var oriVenue model.Venue
  160. if err = tx.First(&oriVenue, venueID).Error; err != nil {
  161. log.Error("查找对应的场馆信息(ID:%d)失败:%s", venueID, err)
  162. err = ecode.NotModified
  163. return
  164. }
  165. if oriVenue.PlaceNum < 1 {
  166. log.Error("更新场馆信息(ID:%d)失败:场地数小于1", venueID)
  167. err = ecode.NotModified
  168. return
  169. }
  170. if err = tx.Model(&oriVenue).Updates(
  171. map[string]interface{}{
  172. "place_num": oriVenue.PlaceNum - 1,
  173. }).Error; err != nil {
  174. log.Error("更新场馆信息(ID:%d)失败:%s", venueID, err)
  175. err = ecode.NotModified
  176. return
  177. }
  178. return
  179. }
  180. // RawPlace 获取场地
  181. func (d *Dao) RawPlace(c context.Context, id int64) (place *model.Place, err error) {
  182. place = new(model.Place)
  183. err = d.db.Model(&model.Place{}).First(&place, id).Scan(&place).Error
  184. if err != nil {
  185. log.Error("RawPlace(%v) error(%v)", id, err)
  186. }
  187. return
  188. }
  189. // RawPlacePolygon 获取场地坐标
  190. func (d *Dao) RawPlacePolygon(c context.Context, id int64) (placePolygon *model.PlacePolygon, err error) {
  191. placePolygon = new(model.PlacePolygon)
  192. err = d.db.Model(&model.PlacePolygon{}).First(&placePolygon, id).Scan(&placePolygon).Error
  193. if err != nil {
  194. log.Error("RawPlacePolygon(%v) error(%v)", id, err)
  195. }
  196. return
  197. }
  198. // TxRawPlace 获取场地(事务)
  199. func (d *Dao) TxRawPlace(c context.Context, tx *gorm.DB, id int64) (place *model.Place, err error) {
  200. place = new(model.Place)
  201. err = tx.Model(&model.Place{}).First(&place, id).Scan(&place).Error
  202. if err != nil {
  203. log.Error("TxRawPlace(%v) error(%v)", id, err)
  204. }
  205. return
  206. }
  207. // CachePlace 缓存获取场地
  208. func (d *Dao) CachePlace(c context.Context, id int64) (place *model.Place, err error) {
  209. var data []byte
  210. key := keyPlace(id)
  211. conn := d.redis.Get(c)
  212. defer conn.Close()
  213. log.Info("GET %v", key)
  214. if data, err = redis.Bytes((conn.Do("GET", key))); err != nil {
  215. if err == redis.ErrNil {
  216. err = nil
  217. }
  218. return
  219. }
  220. json.Unmarshal(data, &place)
  221. return
  222. }
  223. // AddCachePlace 缓存场地信息
  224. func (d *Dao) AddCachePlace(c context.Context, id int64, place *model.Place) (err error) {
  225. conn := d.redis.Get(c)
  226. defer func() {
  227. conn.Flush()
  228. conn.Close()
  229. }()
  230. var data []interface{}
  231. key := keyPlace(id)
  232. data = append(data, key, place)
  233. log.Info("SET %v", key)
  234. if err = conn.Send("SET", data...); err != nil {
  235. return
  236. }
  237. conn.Send("EXPIRE", data[0], CacheTimeout)
  238. return
  239. }
  240. // TxAddPlace 添加场地信息(事务)
  241. func (d *Dao) TxAddPlace(c context.Context, tx *gorm.DB, place *model.Place) (err error) {
  242. if err = tx.Create(place).Error; err != nil {
  243. log.Error("添加场地信息失败:%s", err)
  244. err = ecode.NotModified
  245. return
  246. }
  247. return
  248. }
  249. // TxUpdatePlace 编辑场地信息(事务)
  250. func (d *Dao) TxUpdatePlace(c context.Context, tx *gorm.DB, place *model.Place) (err error) {
  251. // find original place with id
  252. if err = tx.Table("place").Where("id = ?", place.ID).Update(
  253. map[string]interface{}{
  254. "name": place.Name,
  255. "base_pic": place.BasePic,
  256. "status": place.Status,
  257. "venue": place.Venue,
  258. "d_width": place.DWidth,
  259. "d_height": place.DHeight,
  260. }).Error; err != nil {
  261. log.Error("更新场地信息(ID:%d)失败:%s", place.ID, err)
  262. err = ecode.NotModified
  263. return
  264. }
  265. return
  266. }
  267. // TxAddOrUpdateAreaPolygon 添加或更新区域的场地坐标信息(事务)
  268. func (d *Dao) TxAddOrUpdateAreaPolygon(c context.Context, tx *gorm.DB, place int64, area int64, coordinate *string) (err error) {
  269. var (
  270. oriPlacePolygon model.PlacePolygon
  271. coordinates map[int64]string
  272. found bool
  273. )
  274. if res := tx.First(&oriPlacePolygon, place); res.Error != nil {
  275. if !res.RecordNotFound() {
  276. log.Error("查找对应的场地坐标信息(ID:%d)失败:%s", place, res.Error)
  277. err = ecode.NotModified
  278. return
  279. }
  280. coordinates = make(map[int64]string)
  281. oriPlacePolygon.ID = place
  282. found = false
  283. } else {
  284. // 反序列化出coordinate字段
  285. if err = json.Unmarshal([]byte(oriPlacePolygon.Coordinate), &coordinates); err != nil {
  286. log.Error("数据库中的场地坐标信息(ID:%d)反序列化失败:%s", place, err)
  287. err = ecode.NotModified
  288. return
  289. }
  290. found = true
  291. }
  292. // 添加新的coordinate并序列化
  293. coordinates[area] = *coordinate
  294. b, _ := json.Marshal(coordinates)
  295. oriPlacePolygon.Coordinate = string(b)
  296. if found {
  297. if err = tx.Model(&oriPlacePolygon).Updates(
  298. map[string]interface{}{
  299. "coordinate": oriPlacePolygon.Coordinate,
  300. }).Error; err != nil {
  301. log.Error("更新场地坐标信息(ID:%d)失败:%s", place, err)
  302. err = ecode.NotModified
  303. return
  304. }
  305. } else {
  306. if err = tx.Create(oriPlacePolygon).Error; err != nil {
  307. log.Error("创建场地坐标信息(ID:%d)失败:%s", place, err)
  308. err = ecode.NotModified
  309. return
  310. }
  311. }
  312. *coordinate = oriPlacePolygon.Coordinate
  313. return
  314. }
  315. // TxDelAreaPolygon 删除区域的场地坐标信息(事务)
  316. func (d *Dao) TxDelAreaPolygon(c context.Context, tx *gorm.DB, place int64, area int64) (err error) {
  317. var (
  318. oriPlacePolygon model.PlacePolygon
  319. coordinates map[int64]string
  320. )
  321. if err = tx.First(&oriPlacePolygon, place).Error; err != nil {
  322. log.Error("查找对应的场地坐标信息(ID:%d)失败:%s", place, err)
  323. err = ecode.NotModified
  324. return
  325. }
  326. if oriPlacePolygon.Coordinate != "" {
  327. if err = json.Unmarshal([]byte(oriPlacePolygon.Coordinate), &coordinates); err != nil {
  328. log.Error("数据库中的场地坐标信息(ID:%d)反序列化失败:%s", place, err)
  329. err = ecode.NotModified
  330. return
  331. }
  332. } else {
  333. coordinates = make(map[int64]string)
  334. }
  335. // 添加新的coordinate并序列化
  336. if _, ok := coordinates[area]; !ok {
  337. log.Error("数据库中的场地坐标信息(ID:%d)并未包含该区域(ID:%d),删除失败", place, area)
  338. err = ecode.NotModified
  339. return
  340. }
  341. delete(coordinates, area)
  342. b, _ := json.Marshal(coordinates)
  343. oriPlacePolygon.Coordinate = string(b)
  344. if err = tx.Model(&oriPlacePolygon).Updates(
  345. map[string]interface{}{
  346. "coordinate": oriPlacePolygon.Coordinate,
  347. }).Error; err != nil {
  348. log.Error("创建场地坐标信息(ID:%d)失败:%s", place, err)
  349. err = ecode.NotModified
  350. return
  351. }
  352. return
  353. }
  354. // RawArea 获取区域
  355. func (d *Dao) RawArea(c context.Context, id int64) (area *model.Area, err error) {
  356. area = new(model.Area)
  357. if err = d.db.Where("deleted_status = 0").First(&area, id).Error; err != nil {
  358. log.Error("RawArea(%v) error(%v)", id, err)
  359. }
  360. return
  361. }
  362. // TxRawArea 获取区域
  363. func (d *Dao) TxRawArea(c context.Context, tx *gorm.DB, id int64) (area *model.Area, err error) {
  364. area = new(model.Area)
  365. if err = tx.Where("deleted_status = 0").First(&area, id).Error; err != nil {
  366. log.Error("TxRawArea(%v) error(%v)", id, err)
  367. }
  368. return
  369. }
  370. // TxRawDeletedAreaByAID 通过场地ID和自定义区域编号获取已删除的区域
  371. func (d *Dao) TxRawDeletedAreaByAID(c context.Context, tx *gorm.DB, aid string, place int64) (area *model.Area, err error) {
  372. area = new(model.Area)
  373. if res := tx.Where("deleted_status = 1").Where("a_id = ? AND place = ?", aid, place).First(&area); res.Error != nil {
  374. if res.RecordNotFound() {
  375. return nil, nil
  376. }
  377. err = res.Error
  378. log.Error("TxRawAreaByAID(%v, %v) error(%v)", aid, place, err)
  379. }
  380. return
  381. }
  382. // TxAddArea 添加区域信息(事务)
  383. func (d *Dao) TxAddArea(c context.Context, tx *gorm.DB, area *model.Area) (err error) {
  384. if res := tx.Create(area); res.Error != nil {
  385. log.Error("添加区域信息失败:%s", res.Error)
  386. err = ecode.NotModified
  387. return
  388. }
  389. return
  390. }
  391. // TxUpdateArea 编辑区域信息(事务)
  392. func (d *Dao) TxUpdateArea(c context.Context, tx *gorm.DB, area *model.Area) (err error) {
  393. if err = tx.Table("area").Where("id = ?", area.ID).Updates(
  394. map[string]interface{}{
  395. "a_id": area.AID,
  396. "name": area.Name,
  397. "place": area.Place,
  398. "deleted_status": area.DeletedStatus,
  399. }).Error; err != nil {
  400. log.Error("更新区域信息(ID:%d)失败:%s", area.ID, err)
  401. err = ecode.NotModified
  402. return
  403. }
  404. return
  405. }
  406. // TxDelArea 软删除区域(事务)
  407. func (d *Dao) TxDelArea(c context.Context, tx *gorm.DB, id int64) (err error) {
  408. if err = tx.Table("area").Where("id = ?", id).Updates(
  409. map[string]interface{}{
  410. "deleted_status": 1,
  411. }).Error; err != nil {
  412. log.Error("删除区域信息失败:%s", err)
  413. err = ecode.NotModified
  414. return
  415. }
  416. return
  417. }