listing.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. // @snippet_begin(PresetHelloWorldSample)
  2. package e21_presents
  3. import (
  4. "fmt"
  5. "net/url"
  6. "time"
  7. "github.com/qor5/admin/presets"
  8. "github.com/qor5/admin/presets/actions"
  9. "github.com/qor5/admin/presets/gorm2op"
  10. v "github.com/qor5/ui/vuetify"
  11. "github.com/qor5/ui/vuetifyx"
  12. "github.com/qor5/web"
  13. "github.com/qor5/x/i18n"
  14. h "github.com/theplant/htmlgo"
  15. "golang.org/x/text/language"
  16. "gorm.io/driver/sqlite"
  17. "gorm.io/gorm"
  18. "gorm.io/gorm/logger"
  19. )
  20. type Customer struct {
  21. ID int
  22. Name string
  23. Email string
  24. Description string
  25. CompanyID int
  26. CreatedAt time.Time
  27. UpdatedAt time.Time
  28. ApprovedAt *time.Time
  29. TermAgreedAt *time.Time
  30. ApprovalComment string
  31. }
  32. type Address struct {
  33. ID int
  34. Province string
  35. City string
  36. District string
  37. }
  38. var DB *gorm.DB
  39. func init() {
  40. DB = setupDB()
  41. }
  42. func setupDB() (db *gorm.DB) {
  43. var err error
  44. db, err = gorm.Open(sqlite.Open("/tmp/my.db"), &gorm.Config{})
  45. if err != nil {
  46. panic(err)
  47. }
  48. db.Logger.LogMode(logger.Info)
  49. err = db.AutoMigrate(
  50. &Customer{},
  51. &Company{},
  52. &Address{},
  53. )
  54. if err != nil {
  55. panic(err)
  56. }
  57. return
  58. }
  59. func PresetsHelloWorld(b *presets.Builder) (m *presets.ModelBuilder, db *gorm.DB) {
  60. db = DB
  61. b.I18n().
  62. SupportLanguages(language.English, language.SimplifiedChinese).
  63. RegisterForModule(language.SimplifiedChinese, presets.ModelsI18nModuleKey, Messages_zh_CN)
  64. b.URIPrefix(PresetsHelloWorldPath).
  65. DataOperator(gorm2op.DataOperator(db))
  66. m = b.Model(&Customer{})
  67. return
  68. }
  69. const PresetsHelloWorldPath = "/samples/presets-hello-world"
  70. // @snippet_end
  71. // @snippet_begin(PresetsListingCustomizationFieldsSample)
  72. type Company struct {
  73. ID int
  74. Name string
  75. }
  76. func PresetsListingCustomizationFields(b *presets.Builder) (
  77. cust *presets.ModelBuilder,
  78. cl *presets.ListingBuilder,
  79. ce *presets.EditingBuilder,
  80. db *gorm.DB,
  81. ) {
  82. cust, db = PresetsHelloWorld(b)
  83. b.URIPrefix(PresetsListingCustomizationFieldsPath)
  84. cl = cust.Listing("ID", "Name", "Company", "Email").
  85. SearchColumns("name", "email").SelectableColumns(true)
  86. cl.Field("Company").ComponentFunc(func(obj interface{}, field *presets.FieldContext, ctx *web.EventContext) h.HTMLComponent {
  87. c := obj.(*Customer)
  88. var comp Company
  89. if c.CompanyID == 0 {
  90. return h.Td()
  91. }
  92. db.First(&comp, "id = ?", c.CompanyID)
  93. return h.Td(
  94. h.A().Text(comp.Name).
  95. Attr("@click",
  96. web.POST().EventFunc(actions.Edit).
  97. Query(presets.ParamID, fmt.Sprint(comp.ID)).
  98. URL(PresetsListingCustomizationFieldsPath+"/companies").
  99. Go()),
  100. h.Text("-"),
  101. h.A().Text("(Open in Dialog)").
  102. Attr("@click",
  103. web.POST().EventFunc(actions.Edit).
  104. Query(presets.ParamID, fmt.Sprint(comp.ID)).
  105. Query(presets.ParamOverlay, actions.Dialog).
  106. URL(PresetsListingCustomizationFieldsPath+"/companies").
  107. Go(),
  108. ),
  109. )
  110. })
  111. ce = cust.Editing("Name", "CompanyID")
  112. cust.RegisterEventFunc("updateCompanyList", func(ctx *web.EventContext) (r web.EventResponse, err error) {
  113. companyID := ctx.QueryAsInt(presets.ParamOverlayUpdateID)
  114. r.UpdatePortals = append(r.UpdatePortals, &web.PortalUpdate{
  115. Name: "companyListPortal",
  116. Body: companyList(ctx, db, companyID),
  117. })
  118. return
  119. })
  120. ce.Field("CompanyID").ComponentFunc(func(obj interface{}, field *presets.FieldContext, ctx *web.EventContext) h.HTMLComponent {
  121. c := obj.(*Customer)
  122. return web.Portal(companyList(ctx, db, c.CompanyID)).Name("companyListPortal")
  123. })
  124. comp := b.Model(&Company{})
  125. comp.Editing().ValidateFunc(func(obj interface{}, ctx *web.EventContext) (err web.ValidationErrors) {
  126. c := obj.(*Company)
  127. if len(c.Name) < 5 {
  128. err.GlobalError("name must longer than 5")
  129. }
  130. return
  131. })
  132. return
  133. }
  134. func companyList(ctx *web.EventContext, db *gorm.DB, companyID int) h.HTMLComponent {
  135. msgr := i18n.MustGetModuleMessages(ctx.R, presets.ModelsI18nModuleKey, Messages_en_US).(*Messages)
  136. var comps []Company
  137. db.Find(&comps)
  138. return h.Div(
  139. v.VSelect().
  140. Label(msgr.CustomersCompanyID).
  141. Items(comps).
  142. ItemText("Name").
  143. ItemValue("ID").
  144. Value(companyID).
  145. FieldName("CompanyID"),
  146. h.A().Text("Add Company").Attr("@click",
  147. web.POST().
  148. URL(PresetsListingCustomizationFieldsPath+"/companies").
  149. EventFunc(actions.New).
  150. Query(presets.ParamOverlay, actions.Dialog).
  151. Query(presets.ParamOverlayAfterUpdateScript,
  152. web.POST().EventFunc("updateCompanyList").Go()).
  153. Go(),
  154. ),
  155. )
  156. }
  157. const PresetsListingCustomizationFieldsPath = "/samples/presets-listing-customization-fields"
  158. // @snippet_end
  159. // @snippet_begin(PresetsListingCustomizationFiltersSample)
  160. func PresetsListingCustomizationFilters(b *presets.Builder) (
  161. cust *presets.ModelBuilder,
  162. cl *presets.ListingBuilder,
  163. ce *presets.EditingBuilder,
  164. db *gorm.DB,
  165. ) {
  166. cust, cl, ce, db = PresetsListingCustomizationFields(b)
  167. b.URIPrefix(PresetsListingCustomizationFiltersPath)
  168. cl.FilterDataFunc(func(ctx *web.EventContext) vuetifyx.FilterData {
  169. msgr := i18n.MustGetModuleMessages(ctx.R, presets.ModelsI18nModuleKey, Messages_en_US).(*Messages)
  170. var companyOptions []*vuetifyx.SelectItem
  171. err := db.Model(&Company{}).Select("name as text, id as value").Scan(&companyOptions).Error
  172. if err != nil {
  173. panic(err)
  174. }
  175. return []*vuetifyx.FilterItem{
  176. {
  177. Key: "created",
  178. Label: msgr.CustomersFilterCreated,
  179. ItemType: vuetifyx.ItemTypeDatetimeRange,
  180. SQLCondition: `cast(strftime('%%s', created_at) as INTEGER) %s ?`,
  181. },
  182. {
  183. Key: "approved",
  184. Label: msgr.CustomersFilterApproved,
  185. ItemType: vuetifyx.ItemTypeDatetimeRange,
  186. SQLCondition: `cast(strftime('%%s', approved_at) as INTEGER) %s ?`,
  187. },
  188. {
  189. Key: "name",
  190. Label: msgr.CustomersFilterName,
  191. ItemType: vuetifyx.ItemTypeString,
  192. SQLCondition: `name %s ?`,
  193. },
  194. {
  195. Key: "company",
  196. Label: msgr.CustomersFilterCompany,
  197. ItemType: vuetifyx.ItemTypeSelect,
  198. SQLCondition: `company_id %s ?`,
  199. Options: companyOptions,
  200. },
  201. }
  202. })
  203. return
  204. }
  205. const PresetsListingCustomizationFiltersPath = "/samples/presets-listing-customization-filters"
  206. // @snippet_end
  207. // @snippet_begin(PresetsListingCustomizationTabsSample)
  208. func PresetsListingCustomizationTabs(b *presets.Builder) (
  209. cust *presets.ModelBuilder,
  210. cl *presets.ListingBuilder,
  211. ce *presets.EditingBuilder,
  212. db *gorm.DB,
  213. ) {
  214. cust, cl, ce, db = PresetsListingCustomizationFilters(b)
  215. b.URIPrefix(PresetsListingCustomizationTabsPath)
  216. cl.FilterTabsFunc(func(ctx *web.EventContext) []*presets.FilterTab {
  217. var c Company
  218. db.First(&c)
  219. return []*presets.FilterTab{
  220. {
  221. Label: "Felix",
  222. Query: url.Values{"name.ilike": []string{"felix"}},
  223. },
  224. {
  225. Label: "The Plant",
  226. Query: url.Values{"company": []string{fmt.Sprint(c.ID)}},
  227. },
  228. {
  229. Label: "Approved",
  230. Query: url.Values{"approved.gt": []string{fmt.Sprint(1)}},
  231. },
  232. {
  233. Label: "All",
  234. Query: url.Values{"all": []string{"1"}},
  235. },
  236. }
  237. })
  238. return
  239. }
  240. const PresetsListingCustomizationTabsPath = "/samples/presets-listing-customization-tabs"
  241. // @snippet_end
  242. // @snippet_begin(PresetsListingCustomizationBulkActionsSample)
  243. func PresetsListingCustomizationBulkActions(b *presets.Builder) (
  244. cust *presets.ModelBuilder,
  245. cl *presets.ListingBuilder,
  246. ce *presets.EditingBuilder,
  247. db *gorm.DB,
  248. ) {
  249. cust, cl, ce, db = PresetsListingCustomizationTabs(b)
  250. b.URIPrefix(PresetsListingCustomizationBulkActionsPath)
  251. cl.BulkAction("Approve").Label("Approve").
  252. UpdateFunc(func(selectedIds []string, ctx *web.EventContext) (err error) {
  253. comment := ctx.R.FormValue("ApprovalComment")
  254. if len(comment) < 10 {
  255. ctx.Flash = "comment should larger than 10"
  256. return
  257. }
  258. err = db.Model(&Customer{}).
  259. Where("id IN (?)", selectedIds).
  260. Updates(map[string]interface{}{"approved_at": time.Now(), "approval_comment": comment}).Error
  261. if err != nil {
  262. ctx.Flash = err.Error()
  263. }
  264. return
  265. }).
  266. ComponentFunc(func(selectedIds []string, ctx *web.EventContext) h.HTMLComponent {
  267. comment := ctx.R.FormValue("ApprovalComment")
  268. errorMessage := ""
  269. if ctx.Flash != nil {
  270. errorMessage = ctx.Flash.(string)
  271. }
  272. return v.VTextField().
  273. FieldName("ApprovalComment").
  274. Value(comment).
  275. Label("Comment").
  276. ErrorMessages(errorMessage)
  277. })
  278. cl.BulkAction("Delete").Label("Delete").
  279. UpdateFunc(func(selectedIds []string, ctx *web.EventContext) (err error) {
  280. err = db.Where("id IN (?)", selectedIds).Delete(&Customer{}).Error
  281. return
  282. }).
  283. ComponentFunc(func(selectedIds []string, ctx *web.EventContext) h.HTMLComponent {
  284. return h.Div().Text(fmt.Sprintf("Are you sure you want to delete %s ?", selectedIds)).Class("title deep-orange--text")
  285. })
  286. return
  287. }
  288. const PresetsListingCustomizationBulkActionsPath = "/samples/presets-listing-customization-bulk-actions"
  289. // @snippet_end