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  }