github.com/kotovmak/go-admin@v1.1.1/plugins/admin/controller/show.go (about) 1 package controller 2 3 import ( 4 "bytes" 5 "crypto/md5" 6 "fmt" 7 template2 "html/template" 8 "mime" 9 "net/http" 10 "path" 11 "strconv" 12 "strings" 13 "time" 14 15 "github.com/360EntSecGroup-Skylar/excelize" 16 "github.com/GoAdminGroup/html" 17 "github.com/kotovmak/go-admin/context" 18 "github.com/kotovmak/go-admin/modules/auth" 19 "github.com/kotovmak/go-admin/modules/errors" 20 "github.com/kotovmak/go-admin/modules/language" 21 "github.com/kotovmak/go-admin/modules/logger" 22 "github.com/kotovmak/go-admin/plugins/admin/modules" 23 "github.com/kotovmak/go-admin/plugins/admin/modules/constant" 24 "github.com/kotovmak/go-admin/plugins/admin/modules/form" 25 "github.com/kotovmak/go-admin/plugins/admin/modules/guard" 26 "github.com/kotovmak/go-admin/plugins/admin/modules/parameter" 27 "github.com/kotovmak/go-admin/plugins/admin/modules/response" 28 "github.com/kotovmak/go-admin/plugins/admin/modules/table" 29 "github.com/kotovmak/go-admin/template" 30 "github.com/kotovmak/go-admin/template/icon" 31 "github.com/kotovmak/go-admin/template/types" 32 "github.com/kotovmak/go-admin/template/types/action" 33 ) 34 35 // ShowInfo show info page. 36 func (h *Handler) ShowInfo(ctx *context.Context) { 37 38 prefix := ctx.Query(constant.PrefixKey) 39 40 panel := h.table(prefix, ctx) 41 42 if panel.GetOnlyUpdateForm() { 43 ctx.Redirect(h.routePathWithPrefix("show_edit", prefix)) 44 return 45 } 46 47 if panel.GetOnlyNewForm() { 48 ctx.Redirect(h.routePathWithPrefix("show_new", prefix)) 49 return 50 } 51 52 if panel.GetOnlyDetail() { 53 ctx.Redirect(h.routePathWithPrefix("detail", prefix)) 54 return 55 } 56 57 params := parameter.GetParam(ctx.Request.URL, panel.GetInfo().DefaultPageSize, panel.GetInfo().SortField, 58 panel.GetInfo().GetSort()) 59 60 buf := h.showTable(ctx, prefix, params, panel) 61 ctx.HTML(http.StatusOK, buf.String()) 62 } 63 64 func (h *Handler) showTableData(ctx *context.Context, prefix string, params parameter.Parameters, 65 panel table.Table, urlNamePrefix string) (table.Table, table.PanelInfo, []string, error) { 66 if panel == nil { 67 panel = h.table(prefix, ctx) 68 } 69 70 panelInfo, err := panel.GetData(params.WithIsAll(false)) 71 72 if err != nil { 73 return panel, panelInfo, nil, err 74 } 75 76 var ( 77 paramStr = params.DeleteIsAll().GetRouteParamStr() 78 79 editUrl = modules.AorEmpty(!panel.GetInfo().IsHideEditButton, h.routePathWithPrefix(urlNamePrefix+"show_edit", prefix)+paramStr) 80 newUrl = modules.AorEmpty(!panel.GetInfo().IsHideNewButton, h.routePathWithPrefix(urlNamePrefix+"show_new", prefix)+paramStr) 81 deleteUrl = modules.AorEmpty(!panel.GetInfo().IsHideDeleteButton, h.routePathWithPrefix(urlNamePrefix+"delete", prefix)+paramStr) 82 exportUrl = modules.AorEmpty(!panel.GetInfo().IsHideExportButton, h.routePathWithPrefix(urlNamePrefix+"export", prefix)+paramStr) 83 detailUrl = modules.AorEmpty(!panel.GetInfo().IsHideDetailButton, h.routePathWithPrefix(urlNamePrefix+"detail", prefix)+paramStr) 84 85 infoUrl = h.routePathWithPrefix(urlNamePrefix+"info", prefix) 86 updateUrl = h.routePathWithPrefix(urlNamePrefix+"update", prefix) + paramStr 87 88 user = auth.Auth(ctx) 89 ) 90 91 editUrl = user.GetCheckPermissionByUrlMethod(editUrl, h.route(urlNamePrefix+"show_edit").Method()) 92 newUrl = user.GetCheckPermissionByUrlMethod(newUrl, h.route(urlNamePrefix+"show_new").Method()) 93 deleteUrl = user.GetCheckPermissionByUrlMethod(deleteUrl, h.route(urlNamePrefix+"delete").Method()) 94 exportUrl = user.GetCheckPermissionByUrlMethod(exportUrl, h.route(urlNamePrefix+"export").Method()) 95 detailUrl = user.GetCheckPermissionByUrlMethod(detailUrl, h.route(urlNamePrefix+"detail").Method()) 96 97 return panel, panelInfo, []string{editUrl, newUrl, deleteUrl, exportUrl, detailUrl, infoUrl, updateUrl}, nil 98 } 99 100 func (h *Handler) showTable(ctx *context.Context, prefix string, params parameter.Parameters, panel table.Table) *bytes.Buffer { 101 102 panel, panelInfo, urls, err := h.showTableData(ctx, prefix, params, panel, "") 103 if err != nil { 104 return h.Execute(ctx, auth.Auth(ctx), 105 template.WarningPanelWithDescAndTitle(err.Error(), errors.Msg, errors.Msg), "", 106 template.ExecuteOptions{Animation: params.Animation}) 107 } 108 109 if panel.GetInfo().HasError() { 110 if panel.GetInfo().PageErrorHTML != template2.HTML("") { 111 return h.Execute(ctx, auth.Auth(ctx), 112 types.Panel{Content: panel.GetInfo().PageErrorHTML}, "", 113 template.ExecuteOptions{Animation: params.Animation}) 114 } 115 return h.Execute(ctx, auth.Auth(ctx), 116 template.WarningPanel(panel.GetInfo().PageError.Error(), 117 template.GetPageTypeFromPageError(panel.GetInfo().PageError)), "", 118 template.ExecuteOptions{Animation: params.Animation}) 119 } 120 121 editUrl, newUrl, deleteUrl, exportUrl, detailUrl, infoUrl, 122 updateUrl := urls[0], urls[1], urls[2], urls[3], urls[4], urls[5], urls[6] 123 124 var ( 125 actionJs template2.JS 126 body template2.HTML 127 dataTable types.DataTableAttribute 128 129 user = auth.Auth(ctx) 130 info = panel.GetInfo() 131 actionBtns = info.Action 132 allActionBtns = info.ActionButtons.CheckPermissionWhenURLAndMethodNotEmpty(user) 133 ) 134 135 if actionBtns == template.HTML("") && len(allActionBtns) > 0 { 136 if info.ActionButtonFold { 137 ext := template2.HTML("") 138 if deleteUrl != "" { 139 ext = html.LiEl().SetClass("divider").Get() 140 allActionBtns = append([]types.Button{types.GetActionButton(language.GetFromHtml("delete"), 141 types.NewDefaultAction(`data-id='{{.Id}}' data-param='{{(index .Value "__goadmin_delete_params").Content}}' style="cursor: pointer;"`, 142 ext, "", ""), "grid-row-delete")}, allActionBtns...) 143 } 144 ext = template2.HTML("") 145 if detailUrl != "" { 146 if editUrl == "" && deleteUrl == "" { 147 ext = html.LiEl().SetClass("divider").Get() 148 } 149 allActionBtns = append([]types.Button{types.GetActionButton(language.GetFromHtml("detail"), 150 action.Jump(detailUrl+"&"+constant.DetailPKKey+`={{.Id}}{{(index .Value "__goadmin_detail_params").Content}}`, ext))}, allActionBtns...) 151 } 152 if editUrl != "" { 153 if detailUrl == "" && deleteUrl == "" { 154 ext = html.LiEl().SetClass("divider").Get() 155 } 156 allActionBtns = append([]types.Button{types.GetActionButton(language.GetFromHtml("edit"), 157 action.Jump(editUrl+"&"+constant.EditPKKey+`={{.Id}}{{(index .Value "__goadmin_edit_params").Content}}`, ext))}, allActionBtns...) 158 } 159 160 var content template2.HTML 161 content, actionJs = allActionBtns.Content() 162 163 actionBtns = html.Div(html.Div( 164 html.A(icon.Icon(icon.EllipsisV), 165 html.M{"color": "#676565"}, 166 html.M{"href": "#"}, 167 ), html.M{"cursor": "pointer", "width": "100%"}, html.M{"class": "dropdown-toggle", "data-toggle": "dropdown"})+ 168 html.Ul(content, 169 html.M{"min-width": "20px !important", "left": "-32px", "overflow": "hidden"}, 170 html.M{"class": "dropdown-menu", "role": "menu", "aria-labelledby": "dLabel"}), 171 172 html.M{"text-align": "center"}, html.M{"class": "dropdown"}) 173 } else { 174 actionBtns, actionJs = allActionBtns.Content() 175 } 176 } else { 177 info.ActionButtonFold = false 178 } 179 180 btns, btnsJs := info.Buttons.CheckPermissionWhenURLAndMethodNotEmpty(user).Content() 181 182 if info.TabGroups.Valid() { 183 184 dataTable = aDataTable(). 185 SetThead(panelInfo.Thead). 186 SetDeleteUrl(deleteUrl). 187 SetNewUrl(newUrl). 188 SetExportUrl(exportUrl) 189 190 var ( 191 tabsHtml = make([]map[string]template2.HTML, len(info.TabHeaders)) 192 infoListArr = panelInfo.InfoList.GroupBy(info.TabGroups) 193 theadArr = panelInfo.Thead.GroupBy(info.TabGroups) 194 ) 195 for key, header := range info.TabHeaders { 196 tabsHtml[key] = map[string]template2.HTML{ 197 "title": template2.HTML(header), 198 "content": aDataTable(). 199 SetInfoList(infoListArr[key]). 200 SetInfoUrl(infoUrl). 201 SetButtons(btns). 202 SetActionJs(btnsJs + actionJs). 203 SetHasFilter(len(panelInfo.FilterFormData) > 0). 204 SetAction(actionBtns). 205 SetActionFold(info.ActionButtonFold). 206 SetIsTab(key != 0). 207 SetPrimaryKey(panel.GetPrimaryKey().Name). 208 SetThead(theadArr[key]). 209 SetHideRowSelector(info.IsHideRowSelector). 210 SetLayout(info.TableLayout). 211 SetExportUrl(exportUrl). 212 SetNewUrl(newUrl). 213 SetSortUrl(params.GetFixedParamStrWithoutSort()). 214 SetEditUrl(editUrl). 215 SetUpdateUrl(updateUrl). 216 SetDetailUrl(detailUrl). 217 SetDeleteUrl(deleteUrl). 218 GetContent(), 219 } 220 } 221 body = aTab().SetData(tabsHtml).GetContent() 222 } else { 223 dataTable = aDataTable(). 224 SetInfoList(panelInfo.InfoList). 225 SetInfoUrl(infoUrl). 226 SetButtons(btns). 227 SetLayout(info.TableLayout). 228 SetActionJs(btnsJs + actionJs). 229 SetAction(actionBtns). 230 SetHasFilter(len(panelInfo.FilterFormData) > 0). 231 SetPrimaryKey(panel.GetPrimaryKey().Name). 232 SetThead(panelInfo.Thead). 233 SetExportUrl(exportUrl). 234 SetActionFold(info.ActionButtonFold). 235 SetHideRowSelector(info.IsHideRowSelector). 236 SetHideFilterArea(info.IsHideFilterArea). 237 SetNewUrl(newUrl). 238 SetEditUrl(editUrl). 239 SetSortUrl(params.GetFixedParamStrWithoutSort()). 240 SetUpdateUrl(updateUrl). 241 SetDetailUrl(detailUrl). 242 SetDeleteUrl(deleteUrl) 243 body = dataTable.GetContent() 244 } 245 246 isNotIframe := ctx.Query(constant.IframeKey) != "true" 247 paginator := panelInfo.Paginator 248 249 if !isNotIframe { 250 paginator = paginator.SetEntriesInfo("") 251 } 252 253 boxModel := aBox(). 254 SetBody(body). 255 SetNoPadding(). 256 SetHeader(dataTable.GetDataTableHeader() + info.HeaderHtml). 257 WithHeadBorder(). 258 SetIframeStyle(!isNotIframe). 259 SetFooter(paginator.GetContent() + info.FooterHtml) 260 261 if len(panelInfo.FilterFormData) > 0 { 262 boxModel = boxModel.SetSecondHeaderClass("filter-area"). 263 SetSecondHeader(aForm(). 264 SetContent(panelInfo.FilterFormData). 265 SetPrefix(h.config.PrefixFixSlash()). 266 SetInputWidth(info.FilterFormInputWidth). 267 SetHeadWidth(info.FilterFormHeadWidth). 268 SetMethod("get"). 269 SetLayout(info.FilterFormLayout). 270 SetUrl(infoUrl). // + params.GetFixedParamStrWithoutColumnsAndPage() 271 SetHiddenFields(map[string]string{ 272 form.NoAnimationKey: "true", 273 }). 274 SetOperationFooter(filterFormFooter(infoUrl)). 275 GetContent()) 276 } 277 278 content := boxModel.GetContent() 279 280 if info.Wrapper != nil { 281 content = info.Wrapper(content) 282 } 283 284 interval := make([]int, 0) 285 autoRefresh := info.AutoRefresh != uint(0) 286 if autoRefresh { 287 interval = append(interval, int(info.AutoRefresh)) 288 } 289 290 return h.Execute(ctx, user, types.Panel{ 291 Content: content, 292 Description: template2.HTML(panelInfo.Description), 293 Title: modules.AorBHTML(isNotIframe, template2.HTML(panelInfo.Title), ""), 294 MiniSidebar: info.HideSideBar, 295 AutoRefresh: autoRefresh, 296 RefreshInterval: interval, 297 }, "", template.ExecuteOptions{Animation: params.Animation, NoCompress: info.NoCompress}) 298 } 299 300 // Assets return front-end assets according the request path. 301 func (h *Handler) Assets(ctx *context.Context) { 302 filepath := h.config.URLRemovePrefix(ctx.Path()) 303 data, err := aTemplate().GetAsset(filepath) 304 305 if err != nil { 306 data, err = template.GetAsset(filepath) 307 if err != nil { 308 logger.Error("asset err", err) 309 ctx.Write(http.StatusNotFound, map[string]string{}, "") 310 return 311 } 312 } 313 314 var contentType = mime.TypeByExtension(path.Ext(filepath)) 315 316 if contentType == "" { 317 contentType = "application/octet-stream" 318 } 319 320 etag := fmt.Sprintf("%x", md5.Sum(data)) 321 322 if match := ctx.Headers("If-None-Match"); match != "" { 323 if strings.Contains(match, etag) { 324 ctx.SetStatusCode(http.StatusNotModified) 325 return 326 } 327 } 328 329 ctx.DataWithHeaders(http.StatusOK, map[string]string{ 330 "Content-Type": contentType, 331 "Cache-Control": "max-age=2592000", 332 "Content-Length": strconv.Itoa(len(data)), 333 "ETag": etag, 334 }, data) 335 } 336 337 // Export export table rows as excel object. 338 func (h *Handler) Export(ctx *context.Context) { 339 param := guard.GetExportParam(ctx) 340 341 tableName := "Sheet1" 342 prefix := ctx.Query(constant.PrefixKey) 343 panel := h.table(prefix, ctx) 344 345 f := excelize.NewFile() 346 index := f.NewSheet(tableName) 347 f.SetActiveSheet(index) 348 349 var ( 350 infoData table.PanelInfo 351 fileName string 352 err error 353 tableInfo = panel.GetInfo() 354 params parameter.Parameters 355 ) 356 357 if fn := panel.GetInfo().ExportProcessFn; fn != nil { 358 params = parameter.GetParam(ctx.Request.URL, tableInfo.DefaultPageSize, tableInfo.SortField, 359 tableInfo.GetSort()) 360 p, err := fn(params.WithIsAll(param.IsAll)) 361 if err != nil { 362 response.Error(ctx, "export error") 363 return 364 } 365 infoData.Thead = p.Thead 366 infoData.InfoList = p.InfoList 367 } else { 368 if len(param.Id) == 0 { 369 params = parameter.GetParam(ctx.Request.URL, tableInfo.DefaultPageSize, tableInfo.SortField, 370 tableInfo.GetSort()) 371 infoData, err = panel.GetData(params.WithIsAll(param.IsAll)) 372 fileName = fmt.Sprintf("%s-%d-page-%s-pageSize-%s.xlsx", tableInfo.Title, time.Now().Unix(), 373 params.Page, params.PageSize) 374 } else { 375 infoData, err = panel.GetDataWithIds(parameter.GetParam(ctx.Request.URL, 376 tableInfo.DefaultPageSize, tableInfo.SortField, tableInfo.GetSort()).WithPKs(param.Id...)) 377 fileName = fmt.Sprintf("%s-%d-id-%s.xlsx", tableInfo.Title, time.Now().Unix(), strings.Join(param.Id, "_")) 378 } 379 if err != nil { 380 response.Error(ctx, "export error") 381 return 382 } 383 } 384 385 // TODO: support any numbers of fields. 386 orders := []string{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", 387 "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"} 388 389 if len(infoData.Thead) > 26 { 390 j := -1 391 for i := 0; i < len(infoData.Thead)-26; i++ { 392 if i%26 == 0 { 393 j++ 394 } 395 letter := orders[j] + orders[i%26] 396 orders = append(orders, letter) 397 } 398 } 399 400 columnIndex := 0 401 for _, head := range infoData.Thead { 402 if !head.Hide { 403 f.SetCellValue(tableName, orders[columnIndex]+"1", head.Head) 404 columnIndex++ 405 } 406 } 407 408 count := 2 409 for _, info := range infoData.InfoList { 410 columnIndex = 0 411 for _, head := range infoData.Thead { 412 if !head.Hide { 413 if tableInfo.IsExportValue() { 414 f.SetCellValue(tableName, orders[columnIndex]+strconv.Itoa(count), info[head.Field].Value) 415 } else { 416 f.SetCellValue(tableName, orders[columnIndex]+strconv.Itoa(count), info[head.Field].Content) 417 } 418 columnIndex++ 419 } 420 } 421 count++ 422 } 423 424 buf, err := f.WriteToBuffer() 425 426 if err != nil || buf == nil { 427 response.Error(ctx, "export error") 428 return 429 } 430 431 ctx.AddHeader("content-disposition", `attachment; filename=`+fileName) 432 ctx.Data(200, "application/vnd.ms-excel", buf.Bytes()) 433 }