product_config.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. package admin
  2. import (
  3. "context"
  4. "fmt"
  5. "strconv"
  6. "time"
  7. "github.com/qor5/admin/example/models"
  8. "github.com/qor5/admin/media"
  9. "github.com/qor5/admin/media/media_library"
  10. media_view "github.com/qor5/admin/media/views"
  11. "github.com/qor5/admin/presets"
  12. "github.com/qor5/ui/vuetify"
  13. "github.com/qor5/web"
  14. "github.com/qor5/admin/worker"
  15. h "github.com/theplant/htmlgo"
  16. "gorm.io/gorm"
  17. )
  18. func configProduct(b *presets.Builder, db *gorm.DB, wb *worker.Builder) *presets.ModelBuilder {
  19. p := b.Model(&models.Product{})
  20. eb := p.Editing("Status", "Schedule", "Code", "Name", "Price", "Image")
  21. listing := p.Listing("Code", "Name", "Price", "Image").SearchColumns("Code", "Name").SelectableColumns(true)
  22. listing.ActionsAsMenu(true)
  23. noParametersJob := wb.ActionJob(
  24. "No parameters",
  25. p,
  26. func(ctx context.Context, job worker.QorJobInterface) error {
  27. for i := 1; i <= 10; i++ {
  28. select {
  29. case <-ctx.Done():
  30. job.AddLog("job aborted")
  31. return nil
  32. default:
  33. job.SetProgress(uint(i * 10))
  34. time.Sleep(time.Second)
  35. }
  36. }
  37. job.SetProgressText(`<a href="https://qor5-test.s3.ap-northeast-1.amazonaws.com/system/media_libraries/37/file.@qor_preview.png">Please download this file</a>`)
  38. return nil
  39. },
  40. ).Description("This test demo is used to show that an no parameter job can be executed")
  41. parametersBoxJob := wb.ActionJob(
  42. "Parameter input box",
  43. p,
  44. func(ctx context.Context, job worker.QorJobInterface) error {
  45. for i := 1; i <= 10; i++ {
  46. select {
  47. case <-ctx.Done():
  48. job.AddLog("job aborted")
  49. return nil
  50. default:
  51. job.SetProgress(uint(i * 10))
  52. time.Sleep(time.Second)
  53. }
  54. }
  55. job.SetProgressText(`<a href="https://qor5-test.s3.ap-northeast-1.amazonaws.com/system/media_libraries/37/file.@qor_preview.png">Please download this file</a>`)
  56. return nil
  57. },
  58. ).Description("This test demo is used to show that an input box when there are parameters").
  59. Params(&struct{ Name string }{})
  60. displayLogJob := wb.ActionJob(
  61. "Display log",
  62. p,
  63. func(ctx context.Context, job worker.QorJobInterface) error {
  64. for i := 1; i <= 10; i++ {
  65. select {
  66. case <-ctx.Done():
  67. job.AddLog("job aborted")
  68. return nil
  69. default:
  70. job.SetProgress(uint(i * 10))
  71. job.AddLog(fmt.Sprintf("%v", i))
  72. time.Sleep(time.Second)
  73. }
  74. }
  75. job.SetProgressText(`<a href="https://qor5-test.s3.ap-northeast-1.amazonaws.com/system/media_libraries/37/file.@qor_preview.png">Please download this file</a>`)
  76. return nil
  77. },
  78. ).Description("This test demo is used to show the log section of this job").
  79. Params(&struct{ Name string }{}).
  80. DisplayLog(true).
  81. ProgressingInterval(4000)
  82. getArgsJob := wb.ActionJob(
  83. "Get Args",
  84. p,
  85. func(ctx context.Context, job worker.QorJobInterface) error {
  86. jobInfo, err := job.GetJobInfo()
  87. if err != nil {
  88. return err
  89. }
  90. job.AddLog(fmt.Sprintf("Action Params Name is %#+v", jobInfo.Argument.(*struct{ Name string }).Name))
  91. job.AddLog(fmt.Sprintf("Origina Context AuthInfo is %#+v", jobInfo.Context["AuthInfo"]))
  92. job.AddLog(fmt.Sprintf("Origina Context URL is %#+v", jobInfo.Context["URL"]))
  93. for i := 1; i <= 10; i++ {
  94. select {
  95. case <-ctx.Done():
  96. return nil
  97. default:
  98. job.SetProgress(uint(i * 10))
  99. time.Sleep(time.Second)
  100. }
  101. }
  102. job.SetProgressText(`<a href="https://qor5-test.s3.ap-northeast-1.amazonaws.com/system/media_libraries/37/file.@qor_preview.png">Please download this file</a>`)
  103. return nil
  104. },
  105. ).Description("This test demo is used to show how to get the action's arguments and original page context").
  106. Params(&struct{ Name string }{}).
  107. DisplayLog(true).
  108. ContextHandler(func(ctx *web.EventContext) map[string]interface{} {
  109. auth, err := ctx.R.Cookie("auth")
  110. if err == nil {
  111. return map[string]interface{}{"AuthInfo": auth.Value}
  112. }
  113. return nil
  114. })
  115. listing.BulkAction("Action Job - No parameters").
  116. ButtonCompFunc(
  117. func(ctx *web.EventContext) h.HTMLComponent {
  118. return vuetify.VBtn("Action Job - No parameters").Color("secondary").Depressed(true).Class("ml-2").
  119. Attr("@click", noParametersJob.URL())
  120. })
  121. listing.BulkAction("Action Job - Parameter input box").
  122. ButtonCompFunc(
  123. func(ctx *web.EventContext) h.HTMLComponent {
  124. return vuetify.VBtn("Action Job - Parameter input box").Color("secondary").Depressed(true).Class("ml-2").
  125. Attr("@click", parametersBoxJob.URL())
  126. })
  127. listing.BulkAction("Action Job - Display log").
  128. ButtonCompFunc(
  129. func(ctx *web.EventContext) h.HTMLComponent {
  130. return vuetify.VBtn("Action Job - Display log").Color("secondary").Depressed(true).Class("ml-2").
  131. Attr("@click", displayLogJob.URL())
  132. })
  133. listing.BulkAction("Action Job - Get Args").
  134. ButtonCompFunc(
  135. func(ctx *web.EventContext) h.HTMLComponent {
  136. return vuetify.VBtn("Action Job - Get Args").Color("secondary").Depressed(true).Class("ml-2").
  137. Attr("@click", getArgsJob.URL())
  138. })
  139. eb.ValidateFunc(func(obj interface{}, ctx *web.EventContext) (err web.ValidationErrors) {
  140. u := obj.(*models.Product)
  141. if u.Code == "" {
  142. err.FieldError("Name", "Code is required")
  143. }
  144. if u.Name == "" {
  145. err.FieldError("Name", "Name is required")
  146. }
  147. return
  148. })
  149. eb.Field("Image").
  150. WithContextValue(
  151. media_view.MediaBoxConfig,
  152. &media_library.MediaBoxConfig{
  153. AllowType: "image",
  154. Sizes: map[string]*media.Size{
  155. "thumb": {
  156. Width: 100,
  157. Height: 100,
  158. },
  159. },
  160. })
  161. return p
  162. }
  163. type productItem struct {
  164. ID string `json:"id"`
  165. Name string `json:"name"`
  166. Image string `json:"image"`
  167. }
  168. func productsSelector(db *gorm.DB) web.EventFunc {
  169. return func(ctx *web.EventContext) (r web.EventResponse, err error) {
  170. var ps []models.Product
  171. var items []productItem
  172. searchKey := ctx.R.FormValue("keyword")
  173. sql := db.Order("created_at desc").Limit(10)
  174. if searchKey != "" {
  175. key := fmt.Sprintf("%%%s%%", searchKey)
  176. sql = sql.Where("name ILIKE ? or code ILIKE ?", key, key)
  177. }
  178. sql.Find(&ps)
  179. for _, p := range ps {
  180. items = append(items, productItem{
  181. ID: strconv.Itoa(int(p.ID)),
  182. Name: p.Name,
  183. Image: p.Image.URL("thumb"),
  184. })
  185. }
  186. r.Data = items
  187. return
  188. }
  189. }