repo.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. package repository
  2. import (
  3. "gorm.io/gorm"
  4. "wails-app/internal/dao"
  5. "wails-app/internal/global"
  6. )
  7. type TicketRepository struct{}
  8. func (r *TicketRepository) Create(ticket *dao.DigitalTicket) error {
  9. return r.CreateTx(global.GVA_DB, ticket)
  10. }
  11. func (r *TicketRepository) CreateTx(db *gorm.DB, ticket *dao.DigitalTicket) error {
  12. return db.Create(ticket).Error
  13. }
  14. func (r *TicketRepository) GetByTicketNo(ticketNo string) (*dao.DigitalTicket, error) {
  15. var t dao.DigitalTicket
  16. err := global.GVA_DB.Where("ticket_no = ?", ticketNo).First(&t).Error
  17. if err != nil {
  18. return nil, err
  19. }
  20. return &t, nil
  21. }
  22. func (r *TicketRepository) GetByID(id uint) (*dao.DigitalTicket, error) {
  23. return r.GetByIDTx(global.GVA_DB, id)
  24. }
  25. func (r *TicketRepository) GetByIDTx(db *gorm.DB, id uint) (*dao.DigitalTicket, error) {
  26. var t dao.DigitalTicket
  27. err := db.First(&t, id).Error
  28. if err != nil {
  29. return nil, err
  30. }
  31. return &t, nil
  32. }
  33. func (r *TicketRepository) UpdateState(id uint, state string, updates map[string]interface{}) error {
  34. return r.UpdateStateTx(global.GVA_DB, id, state, updates)
  35. }
  36. func (r *TicketRepository) GetByVehicleRecordID(recordID uint) (*dao.DigitalTicket, error) {
  37. return r.GetByVehicleRecordIDTx(global.GVA_DB, recordID)
  38. }
  39. func (r *TicketRepository) GetByVehicleRecordIDTx(db *gorm.DB, recordID uint) (*dao.DigitalTicket, error) {
  40. var t dao.DigitalTicket
  41. err := db.Where("vehicle_record_id = ?", recordID).Order("id DESC").First(&t).Error
  42. if err != nil {
  43. return nil, err
  44. }
  45. return &t, nil
  46. }
  47. func (r *TicketRepository) UpdateStateTx(db *gorm.DB, id uint, state string, updates map[string]interface{}) error {
  48. updates["state"] = state
  49. return db.Model(&dao.DigitalTicket{}).Where("id = ?", id).Updates(updates).Error
  50. }
  51. type TicketListQuery struct {
  52. PlateNumber string `form:"plate_number"`
  53. State string `form:"state"`
  54. Page int `form:"page"`
  55. PageSize int `form:"page_size"`
  56. }
  57. type TicketSummary struct {
  58. Total int64 `json:"total"`
  59. Pending int64 `json:"pending"`
  60. Paid int64 `json:"paid"`
  61. Exited int64 `json:"exited"`
  62. Expired int64 `json:"expired"`
  63. }
  64. func (r *TicketRepository) List(q TicketListQuery) ([]dao.DigitalTicket, int64, error) {
  65. db := ticketQuery(q, true)
  66. var total int64
  67. db.Count(&total)
  68. if q.Page <= 0 {
  69. q.Page = 1
  70. }
  71. if q.PageSize <= 0 {
  72. q.PageSize = 10
  73. }
  74. var list []dao.DigitalTicket
  75. err := db.Order("digital_ticket.id DESC").Offset((q.Page - 1) * q.PageSize).Limit(q.PageSize).Find(&list).Error
  76. return list, total, err
  77. }
  78. // Summary returns counts for the complete filtered result set. Pagination and
  79. // the selected state tab are intentionally ignored so the dashboard totals do
  80. // not change when the user moves between pages.
  81. func (r *TicketRepository) Summary(q TicketListQuery) (TicketSummary, error) {
  82. db := ticketQuery(q, false)
  83. var rows []struct {
  84. State string
  85. Count int64
  86. }
  87. if err := db.Select("digital_ticket.state, COUNT(*) AS count").Group("digital_ticket.state").Scan(&rows).Error; err != nil {
  88. return TicketSummary{}, err
  89. }
  90. var summary TicketSummary
  91. for _, row := range rows {
  92. summary.Total += row.Count
  93. switch row.State {
  94. case "created", "pending_payment":
  95. summary.Pending += row.Count
  96. case "paid":
  97. summary.Paid += row.Count
  98. case "exited":
  99. summary.Exited += row.Count
  100. case "expired":
  101. summary.Expired += row.Count
  102. }
  103. }
  104. return summary, nil
  105. }
  106. // ticketQuery applies filters shared by the paged list and the unpaged
  107. // summary. A left join keeps old tickets searchable even when their copied
  108. // plate_number column is empty and the vehicle record still has the plate.
  109. func ticketQuery(q TicketListQuery, includeState bool) *gorm.DB {
  110. db := global.GVA_DB.Model(&dao.DigitalTicket{})
  111. if q.PlateNumber != "" {
  112. like := "%" + q.PlateNumber + "%"
  113. db = db.Joins("LEFT JOIN vehicle_record ON vehicle_record.id = digital_ticket.vehicle_record_id").
  114. Where("(digital_ticket.plate_number LIKE ? OR vehicle_record.plate_number LIKE ?)", like, like)
  115. }
  116. if includeState && q.State != "" {
  117. if q.State == "pending_payment" {
  118. db = db.Where("digital_ticket.state IN ?", []string{"created", "pending_payment"})
  119. } else {
  120. db = db.Where("digital_ticket.state = ?", q.State)
  121. }
  122. }
  123. return db
  124. }