ec_dashboard_config.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. package admin
  2. import (
  3. "bytes"
  4. "strconv"
  5. "strings"
  6. "github.com/ahmetb/go-linq/v3"
  7. "github.com/qor5/admin/example/models"
  8. "github.com/qor5/admin/presets"
  9. "github.com/qor5/ui/vuetify"
  10. "github.com/qor5/web"
  11. h "github.com/theplant/htmlgo"
  12. "github.com/wcharczuk/go-chart/v2"
  13. "github.com/wcharczuk/go-chart/v2/drawing"
  14. "gorm.io/gorm"
  15. )
  16. type ECDashboard struct{}
  17. func configECDashboard(pb *presets.Builder, db *gorm.DB) {
  18. b := pb.Model(&ECDashboard{}).Label("EC Dashboard").URIName("ec-dashboard")
  19. lb := b.Listing()
  20. lb.PageFunc(func(ctx *web.EventContext) (r web.PageResponse, err error) {
  21. // DB query
  22. var productCount int64
  23. var orderCount int64
  24. var orders []*models.Order
  25. if err = db.Model(&models.Product{}).Count(&productCount).Error; err != nil {
  26. r.Body = errorBody(err.Error())
  27. return
  28. }
  29. if err = db.Model(&models.Order{}).Find(&orders).Count(&orderCount).Error; err != nil {
  30. r.Body = errorBody(err.Error())
  31. return
  32. }
  33. // Chart generate
  34. var pie chart.PieChart
  35. pieBuffer := bytes.NewBuffer([]byte{})
  36. if orderCount > 0 {
  37. iter := linq.From(orders)
  38. pie = chart.PieChart{
  39. Width: 1024,
  40. Height: 1024,
  41. Values: []chart.Value{
  42. {
  43. Value: float64(iter.Where(func(i interface{}) bool {
  44. return i.(*models.Order).Status == models.OrderStatus_Pending
  45. }).Count()),
  46. Label: string(models.OrderStatus_Pending),
  47. Style: chart.Style{FillColor: drawing.ColorFromHex(models.OrderStatusColor_Grey[1:])},
  48. },
  49. {
  50. Value: float64(iter.Where(func(i interface{}) bool {
  51. return i.(*models.Order).Status == models.OrderStatus_Authorised
  52. }).Count()),
  53. Label: string(models.OrderStatus_Authorised),
  54. Style: chart.Style{FillColor: drawing.ColorFromHex(models.OrderStatusColor_Blue[1:])},
  55. },
  56. {
  57. Value: float64(iter.Where(func(i interface{}) bool {
  58. return i.(*models.Order).Status == models.OrderStatus_Cancelled
  59. }).Count()),
  60. Label: string(models.OrderStatus_Cancelled),
  61. Style: chart.Style{FillColor: drawing.ColorFromHex(models.OrderStatusColor_Red[1:])},
  62. },
  63. {
  64. Value: float64(iter.Where(func(i interface{}) bool {
  65. return i.(*models.Order).Status == models.OrderStatus_AuthUnknown
  66. }).Count()),
  67. Label: string(models.OrderStatus_AuthUnknown),
  68. Style: chart.Style{FillColor: drawing.ColorFromHex(models.OrderStatusColor_Red[1:])},
  69. },
  70. {
  71. Value: float64(iter.Where(func(i interface{}) bool {
  72. return i.(*models.Order).Status == models.OrderStatus_Sending
  73. }).Count()),
  74. Label: string(models.OrderStatus_Sending),
  75. Style: chart.Style{FillColor: drawing.ColorFromHex(models.OrderStatusColor_Orange[1:])},
  76. },
  77. {
  78. Value: float64(iter.Where(func(i interface{}) bool {
  79. return i.(*models.Order).Status == models.OrderStatus_CheckedIn
  80. }).Count()),
  81. Label: string(models.OrderStatus_CheckedIn),
  82. Style: chart.Style{FillColor: drawing.ColorFromHex(models.OrderStatusColor_Green[1:])},
  83. },
  84. // TODO: add more status
  85. },
  86. }
  87. err = pie.Render(chart.SVG, pieBuffer)
  88. }
  89. body := vuetify.VContainer(
  90. vuetify.VRow(
  91. h.Div(
  92. h.Div(h.Strong("Statistics")).Class("mt-2 col col-12"),
  93. h.Div(
  94. h.Div(
  95. vuetify.VCard(
  96. vuetify.VCardTitle(h.Text(strconv.Itoa(int(productCount)))),
  97. vuetify.VCardSubtitle(h.Text("Products")),
  98. ).Outlined(true),
  99. ).Class("pa-4 pt-12"),
  100. h.Div(
  101. vuetify.VCard(
  102. vuetify.VCardTitle(h.Text(strconv.Itoa(int(orderCount)))),
  103. vuetify.VCardSubtitle(h.Text("Orders")),
  104. ).Outlined(true),
  105. ).Class("pa-4"),
  106. ).Class("v-card v-sheet theme--light").Style("height: 300px;"),
  107. ).Class("col col-6"),
  108. h.Div(
  109. h.Div(h.Strong("Order Status")).Class("mt-2 col col-12"),
  110. h.Div(
  111. h.RawHTML(
  112. strings.Replace(pieBuffer.String(), `width="1024" height="1024"`, `width="100%" height="100%" viewBox="-85 -80 1200 1200"`, -1)),
  113. ).Class("v-card v-sheet theme--light").Style("height: 300px;"),
  114. ).Class("col col-6"),
  115. ),
  116. )
  117. r.Body = body
  118. r.PageTitle = "EC Dashboard"
  119. return
  120. })
  121. }
  122. func errorBody(msg string) h.HTMLComponent {
  123. return vuetify.VContainer(
  124. h.P().Text(msg),
  125. )
  126. }