├── .gitignore ├── README.md ├── conf ├── app.conf └── pages.xml ├── controllers ├── StatPageController.go └── default.go ├── main.go ├── models └── XmlConfig.go ├── routers └── router.go ├── static ├── css │ ├── Material+Icons.css │ ├── dashboard.css │ ├── dataTables.material.min.css │ ├── material.blue-indigo.min.css │ └── material.min.css ├── fonts │ └── flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2 ├── html │ ├── test01.html │ ├── test02.html │ ├── test03.html │ └── test04.html ├── img │ └── user.jpg └── js │ ├── dataTables.buttons.min.js │ ├── dataTables.material.min.js │ ├── datatables.Chinese.json │ ├── jquery-3.3.1.min.js │ ├── jquery.dataTables.min.js │ └── material.min.js ├── tests └── default_test.go └── views ├── footer.html ├── header.html ├── index.html ├── meta.html ├── reporter └── page.html └── right.html /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml 3 | .DS_Store 4 | *.zip 5 | *.log 6 | doc 7 | bin 8 | pkg 9 | main 10 | version 11 | tmp 12 | *.exe 13 | *.exe~ 14 | *.db 15 | go-stat-reporter -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### 1,系统技术组成 2 | 3 | > 1,使用golang beego jquery 开发web的数据报表系统。 4 | 5 | > 2,使用datatables 做数据展示。通过xml进行配置 6 | 7 | > 3,使用Material Design做样式展示。 8 | 9 | https://datatables.net/examples/styling/material.html 10 | > 还是preview 版本的呢。但是不影响使用,之前使用python调试过接口。只是样式换了下。问题不大。 11 | 12 | 报表使用 http://echarts.baidu.com/ -------------------------------------------------------------------------------- /conf/app.conf: -------------------------------------------------------------------------------- 1 | appname = go-stat-reporter 2 | httpport = 8080 3 | runmode = dev 4 | 5 | dbhost = ${MYSQL_HOST||mariadb} 6 | dbport = ${MYSQL_PORT||3306} 7 | dbuser = ${MYSQL_USER||root} 8 | dbpassword = ${MYSQL_PASSWD||mariadb} 9 | db = ${MYSQL_DB||stock_data} -------------------------------------------------------------------------------- /conf/pages.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | date,type,rate 7 | 8 |
9 | 10 |
11 | date,loan_type,rate 12 | 13 |
14 | 15 |
16 | date,before,now,changed 17 | 18 |
19 |
20 | 21 | 22 |
23 | month,m2,m2_yoy,m1,m1_yoy,m0,m0_yoy,cd,cd_yoy,qm,qm_yoy,ftd,ftd_yoy,sd,sd_yoy,rests,rests_yoy 24 | 25 | 34 |
35 |
36 |
-------------------------------------------------------------------------------- /controllers/StatPageController.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "github.com/astaxie/beego" 5 | "github.com/astaxie/beego/orm" 6 | "fmt" 7 | "strconv" 8 | "github.com/astaxie/beego/logs" 9 | "strings" 10 | "github.com/golangpkg/go-stat-reporter/models" 11 | ) 12 | 13 | type StatPageController struct { 14 | beego.Controller 15 | } 16 | 17 | type StatTableApiJson struct { 18 | Draw int `json:"draw"` 19 | RecordsTotal int `json:"recordsTotal"` 20 | RecordsFiltered int `json:"recordsFiltered"` 21 | Data []interface{} `json:"data"` 22 | } 23 | 24 | //html页面 25 | func (c *StatPageController) PageHtml() { 26 | //获得pageId 27 | tableId := c.Ctx.Input.Param(":pageId") //c.GetString("pageId", "") 28 | tableId = strings.Replace(tableId, ".html", "", -1) 29 | page, idx, err := models.GetPage(tableId) 30 | logs.Info("page: ", tableId, page) 31 | c.Data["XmlPageList"] = models.ConstantXmlPages.Pages 32 | c.Data["RightNavIdx"] = idx //返回第几个菜单索引,用来高亮显示菜单。 33 | if err == nil { 34 | c.Data["Page"] = page 35 | } else { 36 | c.Data["Page"] = &models.XMLPage{} 37 | } 38 | c.TplName = "reporter/page.html" 39 | } 40 | 41 | //Ajax分页 42 | func (c *StatPageController) TableApi() { 43 | defer c.ServeJSON() 44 | 45 | //获得id 46 | tableId := c.GetString("tableId", "") 47 | startParam := c.GetString("start", "") 48 | lengthParam := c.GetString("length", "") 49 | table, err := models.GetTable(tableId) 50 | logs.Info("table: ", table) 51 | if err == nil { 52 | c.Data["Table"] = table 53 | } else { 54 | c.Data["Table"] = &models.XMLDataTable{} 55 | } 56 | //获得全部 request参数。 57 | paramsTmp := c.Ctx.Request.Form 58 | logs.Info("startParam :", startParam, ", lengthParam:", lengthParam) 59 | orderByColumn := []string{} 60 | orderByDir := []string{} 61 | 62 | for key, val := range paramsTmp { 63 | //循环找到排序字段,然后放到数组里面。 64 | if strings.Index(key, "order[") == 0 && strings.Index(key, "[column]") > 0 { 65 | logs.Info("get order column :", key, val) 66 | orderByColumn = append(orderByColumn, val[0]) 67 | } 68 | //排序dir。 69 | if strings.Index(key, "order[") == 0 && strings.Index(key, "[dir]") > 0 { 70 | logs.Info("get order dir :", key, val) 71 | orderByDir = append(orderByDir, val[0]) 72 | } 73 | } 74 | logs.Info("orderByColumn : ", orderByColumn) 75 | logs.Info("orderByDir : ", orderByDir) 76 | logs.Info("table : %v ", table) 77 | 78 | //#######################组装order by sql。####################### 79 | orderBySql := "" 80 | if len(orderByColumn) != 0 && len(orderByDir) != 0 { 81 | orderBySql = " ORDER BY " 82 | idx := 0 83 | for _, val := range orderByColumn { 84 | //找到排序字段和dir。 85 | tmpIndex, _ := strconv.Atoi(val) 86 | logs.Info("get val :", tmpIndex) 87 | colTmp := table.ColumnArray[tmpIndex] 88 | dirTmp := orderByDir[idx] 89 | 90 | logs.Info("key:", tmpIndex, "colTmp :", colTmp, ", dirTmp :", dirTmp) 91 | //排序sql。 92 | tmpOrderSql := fmt.Sprintf(" convert(`%s`, decimal) %s", colTmp, dirTmp) 93 | 94 | //增加order sql 排序。 95 | if idx != 0 { 96 | orderBySql += " , " + tmpOrderSql 97 | } else { 98 | orderBySql += tmpOrderSql 99 | } 100 | idx += 1 101 | } 102 | } 103 | 104 | sql := fmt.Sprintf(" SELECT * FROM %s %s LIMIT %s,%s ", table.Table, orderBySql, startParam, lengthParam) 105 | sqlCount := fmt.Sprintf(" SELECT COUNT(1) as num FROM %s ", table.Table) 106 | logs.Info("select sql :", sql) 107 | logs.Info("count sql :", sqlCount) 108 | //stock_web_list = self.db.query(sql) 109 | 110 | var maps []orm.Params 111 | var list []interface{} 112 | o := orm.NewOrm() 113 | dataListTmp, err1 := o.Raw(sql).Values(&maps) 114 | if err1 == nil && dataListTmp > 0 { 115 | fmt.Println(maps[0]) // slene 116 | for _, val := range maps { 117 | //logs.Info("key:", key, ", val:", val) 118 | list = append(list, val) 119 | } 120 | } 121 | 122 | //记录count数量。 123 | numTmp := 0 124 | dataListTmp2, err2 := o.Raw(sqlCount).Values(&maps) 125 | if err2 == nil && dataListTmp2 > 0 { 126 | //fmt.Println(maps[0]["num"]) // slene 127 | //转换字符串。 128 | if s, err := strconv.Atoi(maps[0]["num"].(string)); err == nil { 129 | fmt.Printf("%T, %v", s, s) 130 | numTmp = s 131 | } 132 | } 133 | 134 | //放入data数据: 135 | tmpJson := &StatTableApiJson{} 136 | tmpJson.RecordsTotal = numTmp 137 | tmpJson.RecordsFiltered = numTmp 138 | tmpJson.Data = list 139 | c.Data["json"] = tmpJson 140 | } 141 | -------------------------------------------------------------------------------- /controllers/default.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "github.com/astaxie/beego" 5 | ) 6 | 7 | type MainController struct { 8 | beego.Controller 9 | } 10 | 11 | func (c *MainController) Index() { 12 | c.Redirect("/admin/index", 302) 13 | } 14 | 15 | func (c *MainController) AdminIndex() { 16 | c.TplName = "index.html" 17 | } 18 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "github.com/golangpkg/go-stat-reporter/routers" 5 | _ "github.com/go-sql-driver/mysql" 6 | "github.com/astaxie/beego" 7 | "github.com/golangpkg/go-stat-reporter/models" 8 | "os" 9 | "github.com/astaxie/beego/orm" 10 | "github.com/astaxie/beego/logs" 11 | "github.com/astaxie/beego/context" 12 | "html/template" 13 | ) 14 | 15 | func initDb() { 16 | //数据库注册。 17 | dbhost := beego.AppConfig.String("dbhost") 18 | dbport := beego.AppConfig.String("dbport") 19 | dbuser := beego.AppConfig.String("dbuser") 20 | dbpassword := beego.AppConfig.String("dbpassword") 21 | db := beego.AppConfig.String("db") 22 | // 参数4(可选) 设置最大空闲连接 23 | maxIdle := 30 24 | // 参数5(可选) 设置最大数据库连接 25 | maxConn := 30 26 | conn := dbuser + ":" + dbpassword + "@tcp(" + dbhost + ":" + dbport + ")/" + db + "?charset=utf8" 27 | orm.RegisterDataBase("default", "mysql", conn, maxIdle, maxConn) 28 | orm.Debug = true 29 | //同步 ORM 对象和数据库 30 | //这时, 在你重启应用的时候, beego 便会自动帮你创建数据库表。 31 | //orm.RunSyncdb("default", false, true) 32 | } 33 | 34 | func intiFilter() { 35 | //增加拦截器。 36 | var FilterUserByAdmin = func(ctx *context.Context) { 37 | url := ctx.Input.URL() 38 | pageName := ctx.Input.Query("pageId") 39 | //登录页面不过滤。 40 | if url == "/admin/userInfo/login" || url == "/admin/userInfo/logout" { 41 | return 42 | } 43 | logs.Info("########### url: ", url, ", pageName:", pageName, ",ParamsLen", ctx.Input.ParamsLen()) 44 | //ctx.Input.SetData(urlTag, true) 45 | ctx.Input.SetData("PageList", &models.ConstantXmlPages.Pages) 46 | } 47 | beego.InsertFilter("/admin/*", beego.BeforeExec, FilterUserByAdmin) 48 | 49 | } 50 | 51 | //总体初始化。 52 | func init() { 53 | //初始化数据库。 54 | initDb() 55 | //初始化filter 56 | intiFilter() 57 | //开启session。配置文件 配置下sessionon = true即可。 58 | beego.BConfig.WebConfig.Session.SessionOn = true 59 | //初始化xml数据模板。 60 | pwd, _ := os.Getwd() 61 | println("get pwd:", pwd) 62 | models.ReadXMLConfig(pwd + "/conf/pages.xml") 63 | println("######################") 64 | } 65 | 66 | //http://blog.xiayf.cn/2013/11/01/unescape-html-in-golang-html_template/ 67 | // 定义函数unescaped 68 | func rawJs(x string) interface{} { return template.JS(x) } 69 | func rawHtml(x string) interface{} { return template.HTML(x) } 70 | 71 | func main() { 72 | //增加自定义函数。 73 | beego.AddFuncMap("rawJs", rawJs) 74 | beego.AddFuncMap("rawHtml", rawHtml) 75 | //放到最后。 76 | beego.Run() 77 | } 78 | -------------------------------------------------------------------------------- /models/XmlConfig.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "encoding/xml" 5 | "io/ioutil" 6 | "os" 7 | "fmt" 8 | "errors" 9 | "strings" 10 | ) 11 | 12 | //Table标签 13 | type XMLDataTable struct { 14 | XMLName xml.Name `xml:"dataTable"̀` 15 | Id string `xml:"id,attr"̀` 16 | Name string `xml:"name,attr"̀` 17 | Table string `xml:"table"̀` 18 | Column string `xml:"column"̀` 19 | Label string ` xml:"label"̀` 20 | ColumnArray []string //字段项 21 | LabelArray []string //字段名字 22 | } 23 | 24 | //Table标签 25 | type XMLDataChart struct { 26 | XMLName xml.Name `xml:"dataChart"̀` 27 | Id string `xml:"id,attr"̀` 28 | Name string `xml:"name,attr"̀` 29 | Type string `xml:"type,attr"̀` 30 | Table string `xml:"table"̀` 31 | Column string `xml:"column"̀` 32 | Label string ` xml:"label"̀` 33 | } 34 | 35 | //Page标签 36 | type XMLPage struct { 37 | XMLName xml.Name `xml:"page"̀` 38 | Id string `xml:"id,attr"̀` 39 | Name string `xml:"name,attr"̀` 40 | DataTables []XMLDataTable `xml:"dataTable"̀` 41 | DataCharts []XMLDataChart `xml:"dataChart"̀` 42 | } 43 | 44 | //Pages标签 45 | type XMLPages struct { 46 | XMLName xml.Name `xml:"pages"̀` 47 | Pages []XMLPage `xml:"page"̀` 48 | } 49 | 50 | var ConstantXmlPages XMLPages 51 | 52 | //参考代码: 53 | // https://tutorialedge.net/golang/parsing-xml-with-golang/ 54 | func ReadXMLConfig(file string) { 55 | xmlFile, err := os.Open(file) 56 | if err != nil { 57 | fmt.Println(err) 58 | return 59 | } 60 | fmt.Println("Successfully Open XML : " + file) 61 | defer xmlFile.Close() 62 | byteValue, _ := ioutil.ReadAll(xmlFile) 63 | xml.Unmarshal(byteValue, &ConstantXmlPages) 64 | println(ConstantXmlPages.Pages) 65 | 66 | for _, page := range ConstantXmlPages.Pages { 67 | println("page:", page.Name) 68 | for i, table := range page.DataTables { 69 | println("table:", table.Name) 70 | //转换 column为数组字段。 71 | if table.Column != "" { 72 | tmpStr := strings.Replace(table.Column, "\"", "", -1) 73 | tmpStr = strings.Replace(tmpStr, " ", "", -1) 74 | tmpStr = strings.Replace(tmpStr, "\r", "", -1) 75 | tmpStr = strings.Replace(tmpStr, "\n", "", -1) 76 | table.ColumnArray = strings.Split(tmpStr, ",") 77 | } 78 | //转换 label 为数组字段。 79 | if table.Label != "" { 80 | tmpStr := strings.Replace(table.Label, "\"", "", -1) 81 | tmpStr = strings.Replace(tmpStr, " ", "", -1) 82 | tmpStr = strings.Replace(tmpStr, "\r", "", -1) 83 | tmpStr = strings.Replace(tmpStr, "\n", "", -1) 84 | table.LabelArray = strings.Split(tmpStr, ",") 85 | } 86 | //fmt.Printf("table %v", table) 87 | //在将数据放到数组里面。 88 | page.DataTables[i] = table 89 | } 90 | } 91 | 92 | return 93 | } 94 | 95 | //循环pages的全部数据,找到id,返回page,和当前index。 96 | func GetPage(id string) (page XMLPage, idx int, err error) { 97 | for idx, page := range ConstantXmlPages.Pages { 98 | if page.Id == id { 99 | return page, idx, nil 100 | } 101 | } 102 | return page, 0, errors.New("no page .") 103 | } 104 | 105 | //循环Tables的全部数据,找到id,返回Table。 106 | func GetTable(id string) (table XMLDataTable, err error) { 107 | for _, page := range ConstantXmlPages.Pages { 108 | for _, table2 := range page.DataTables { 109 | if table2.Id == id { 110 | return table2, nil 111 | } 112 | } 113 | } 114 | return table, errors.New("no page .") 115 | } 116 | -------------------------------------------------------------------------------- /routers/router.go: -------------------------------------------------------------------------------- 1 | package routers 2 | 3 | import ( 4 | "github.com/golangpkg/go-stat-reporter/controllers" 5 | "github.com/astaxie/beego" 6 | ) 7 | 8 | func init() { 9 | 10 | beego.Router("/", &controllers.MainController{}, "get:Index") 11 | beego.Router("/reporter/index", &controllers.MainController{}, "get:AdminIndex") 12 | //主要报表数据接口。 13 | beego.Router("/reporter/:pageId", &controllers.StatPageController{}, "get:PageHtml") 14 | beego.Router("/reporter/api", &controllers.StatPageController{}, "get:TableApi") 15 | } 16 | -------------------------------------------------------------------------------- /static/css/Material+Icons.css: -------------------------------------------------------------------------------- 1 | /* fallback */ 2 | @font-face { 3 | font-family: 'Material Icons'; 4 | font-style: normal; 5 | font-weight: 400; 6 | src: url(/static/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format('woff2'); 7 | } 8 | 9 | .material-icons { 10 | font-family: 'Material Icons'; 11 | font-weight: normal; 12 | font-style: normal; 13 | font-size: 24px; 14 | line-height: 1; 15 | letter-spacing: normal; 16 | text-transform: none; 17 | display: inline-block; 18 | white-space: nowrap; 19 | word-wrap: normal; 20 | direction: ltr; 21 | -webkit-font-feature-settings: 'liga'; 22 | -webkit-font-smoothing: antialiased; 23 | } -------------------------------------------------------------------------------- /static/css/dashboard.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | font-family: 'Roboto', 'Helvetica', sans-serif; 3 | } 4 | .demo-avatar { 5 | width: 48px; 6 | height: 48px; 7 | border-radius: 24px; 8 | } 9 | .demo-layout .mdl-layout__header .mdl-layout__drawer-button { 10 | color: rgba(0, 0, 0, 0.54); 11 | } 12 | .mdl-layout__drawer .avatar { 13 | margin-bottom: 16px; 14 | } 15 | .demo-drawer { 16 | border: none; 17 | } 18 | /* iOS Safari specific workaround */ 19 | .demo-drawer .mdl-menu__container { 20 | z-index: -1; 21 | } 22 | .demo-drawer .demo-navigation { 23 | z-index: -2; 24 | } 25 | /* END iOS Safari specific workaround */ 26 | .demo-drawer .mdl-menu .mdl-menu__item { 27 | display: -webkit-flex; 28 | display: -ms-flexbox; 29 | display: flex; 30 | -webkit-align-items: center; 31 | -ms-flex-align: center; 32 | align-items: center; 33 | } 34 | .demo-drawer-header { 35 | box-sizing: border-box; 36 | display: -webkit-flex; 37 | display: -ms-flexbox; 38 | display: flex; 39 | -webkit-flex-direction: column; 40 | -ms-flex-direction: column; 41 | flex-direction: column; 42 | -webkit-justify-content: flex-end; 43 | -ms-flex-pack: end; 44 | justify-content: flex-end; 45 | padding: 16px; 46 | height: 151px; 47 | } 48 | .demo-avatar-dropdown { 49 | display: -webkit-flex; 50 | display: -ms-flexbox; 51 | display: flex; 52 | position: relative; 53 | -webkit-flex-direction: row; 54 | -ms-flex-direction: row; 55 | flex-direction: row; 56 | -webkit-align-items: center; 57 | -ms-flex-align: center; 58 | align-items: center; 59 | width: 100%; 60 | } 61 | 62 | .demo-navigation { 63 | -webkit-flex-grow: 1; 64 | -ms-flex-positive: 1; 65 | flex-grow: 1; 66 | } 67 | .demo-layout .demo-navigation .mdl-navigation__link { 68 | display: -webkit-flex !important; 69 | display: -ms-flexbox !important; 70 | display: flex !important; 71 | -webkit-flex-direction: row; 72 | -ms-flex-direction: row; 73 | flex-direction: row; 74 | -webkit-align-items: center; 75 | -ms-flex-align: center; 76 | align-items: center; 77 | color: rgba(255, 255, 255, 0.56); 78 | font-weight: 500; 79 | } 80 | .demo-layout .demo-navigation .mdl-navigation__link:hover { 81 | background-color: #00BCD4; 82 | color: #37474F; 83 | } 84 | .demo-navigation .mdl-navigation__link .material-icons { 85 | font-size: 24px; 86 | color: rgba(255, 255, 255, 0.56); 87 | margin-right: 32px; 88 | } 89 | 90 | .demo-content { 91 | max-width: 1080px; 92 | } 93 | 94 | .demo-charts { 95 | -webkit-align-items: center; 96 | -ms-flex-align: center; 97 | align-items: center; 98 | } 99 | .demo-chart:nth-child(1) { 100 | color: #ACEC00; 101 | } 102 | .demo-chart:nth-child(2) { 103 | color: #00BBD6; 104 | } 105 | .demo-chart:nth-child(3) { 106 | color: #BA65C9; 107 | } 108 | .demo-chart:nth-child(4) { 109 | color: #EF3C79; 110 | } 111 | .demo-graphs { 112 | padding: 16px 32px; 113 | display: -webkit-flex; 114 | display: -ms-flexbox; 115 | display: flex; 116 | -webkit-flex-direction: column; 117 | -ms-flex-direction: column; 118 | flex-direction: column; 119 | -webkit-align-items: stretch; 120 | -ms-flex-align: stretch; 121 | align-items: stretch; 122 | } 123 | /* TODO: Find a proper solution to have the graphs 124 | * not float around outside their container in IE10/11. 125 | * Using a browserhacks.com solution for now. 126 | */ 127 | _:-ms-input-placeholder, :root .demo-graphs { 128 | min-height: 664px; 129 | } 130 | _:-ms-input-placeholder, :root .demo-graph { 131 | max-height: 300px; 132 | } 133 | /* TODO end */ 134 | .demo-graph:nth-child(1) { 135 | color: #00b9d8; 136 | } 137 | .demo-graph:nth-child(2) { 138 | color: #d9006e; 139 | } 140 | 141 | .demo-cards { 142 | -webkit-align-items: flex-start; 143 | -ms-flex-align: start; 144 | align-items: flex-start; 145 | -webkit-align-content: flex-start; 146 | -ms-flex-line-pack: start; 147 | align-content: flex-start; 148 | } 149 | .demo-cards .demo-separator { 150 | height: 32px; 151 | } 152 | .demo-cards .mdl-card__title.mdl-card__title { 153 | color: white; 154 | font-size: 24px; 155 | font-weight: 400; 156 | } 157 | .demo-cards ul { 158 | padding: 0; 159 | } 160 | .demo-cards h3 { 161 | font-size: 1em; 162 | } 163 | .demo-updates .mdl-card__title { 164 | min-height: 200px; 165 | background-image: url('images/dog.png'); 166 | background-position: 90% 100%; 167 | background-repeat: no-repeat; 168 | } 169 | .demo-cards .mdl-card__actions a { 170 | color: #00BCD4; 171 | text-decoration: none; 172 | } 173 | 174 | .demo-options h3 { 175 | margin: 0; 176 | } 177 | .demo-options .mdl-checkbox__box-outline { 178 | border-color: rgba(255, 255, 255, 0.89); 179 | } 180 | .demo-options ul { 181 | margin: 0; 182 | list-style-type: none; 183 | } 184 | .demo-options li { 185 | margin: 4px 0; 186 | } 187 | .demo-options .material-icons { 188 | color: rgba(255, 255, 255, 0.89); 189 | } 190 | .demo-options .mdl-card__actions { 191 | height: 64px; 192 | display: -webkit-flex; 193 | display: -ms-flexbox; 194 | display: flex; 195 | box-sizing: border-box; 196 | -webkit-align-items: center; 197 | -ms-flex-align: center; 198 | align-items: center; 199 | } 200 | -------------------------------------------------------------------------------- /static/css/dataTables.material.min.css: -------------------------------------------------------------------------------- 1 | div.dataTables_wrapper div.dataTables_filter{text-align:right}div.dataTables_wrapper div.dataTables_filter input{margin-left:0.5em}div.dataTables_wrapper div.dataTables_info{padding-top:10px;white-space:nowrap}div.dataTables_wrapper div.dataTables_processing{position:absolute;top:50%;left:50%;width:200px;margin-left:-100px;text-align:center}div.dataTables_wrapper div.dataTables_paginate{text-align:right}div.dataTables_wrapper div.mdl-grid.dt-table{padding-top:0;padding-bottom:0}div.dataTables_wrapper div.mdl-grid.dt-table>div.mdl-cell{margin-top:0;margin-bottom:0}table.dataTable thead>tr>th.sorting_asc,table.dataTable thead>tr>th.sorting_desc,table.dataTable thead>tr>th.sorting,table.dataTable thead>tr>td.sorting_asc,table.dataTable thead>tr>td.sorting_desc,table.dataTable thead>tr>td.sorting{padding-right:30px}table.dataTable thead>tr>th:active,table.dataTable thead>tr>td:active{outline:none}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{cursor:pointer;position:relative}table.dataTable thead .sorting:before,table.dataTable thead .sorting:after,table.dataTable thead .sorting_asc:before,table.dataTable thead .sorting_asc:after,table.dataTable thead .sorting_desc:before,table.dataTable thead .sorting_desc:after,table.dataTable thead .sorting_asc_disabled:before,table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc_disabled:before,table.dataTable thead .sorting_desc_disabled:after{position:absolute;bottom:11px;display:block;opacity:0.3;font-size:1.3em}table.dataTable thead .sorting:before,table.dataTable thead .sorting_asc:before,table.dataTable thead .sorting_desc:before,table.dataTable thead .sorting_asc_disabled:before,table.dataTable thead .sorting_desc_disabled:before{right:1em;content:"\2191"}table.dataTable thead .sorting:after,table.dataTable thead .sorting_asc:after,table.dataTable thead .sorting_desc:after,table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc_disabled:after{right:0.5em;content:"\2193"}table.dataTable thead .sorting_asc:before,table.dataTable thead .sorting_desc:after{opacity:1}table.dataTable thead .sorting_asc_disabled:before,table.dataTable thead .sorting_desc_disabled:after{opacity:0} 2 | -------------------------------------------------------------------------------- /static/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golangpkg/go-stat-reporter/b08d197a79515b90e46d640be2b42ec2fedbeb34/static/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2 -------------------------------------------------------------------------------- /static/html/test01.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Material Design Lite 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
32 |
33 | Home 34 |
35 |
36 | 39 |
40 | 41 | 42 |
43 |
44 | 47 |
    48 |
  • About
  • 49 |
  • Contact
  • 50 |
  • Legal information
  • 51 |
52 |
53 |
54 |
55 |
56 | 57 |
58 | 欢迎使用统计报表系统 59 |
60 |
61 |
62 | 74 |
75 |
76 |
77 |
78 | 79 | 80 | 82% 81 | 82 | 83 | 84 | 82% 85 | 86 | 87 | 88 | 82% 89 | 90 | 91 | 92 | 82% 93 | 94 | 95 | 96 | 82% 97 | 98 | 99 | 100 | 82% 101 | 102 | 103 | 104 | 82% 105 | 106 |
107 |
108 | 109 | 110 | 111 | 112 | 113 | 114 |
115 | 116 |
117 |
118 |
119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 500 143 | 400 144 | 300 145 | 200 146 | 100 147 | 1 148 | 2 149 | 3 150 | 4 151 | 5 152 | 6 153 | 7 154 | 155 | 156 | 158 | 159 | 160 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | -------------------------------------------------------------------------------- /static/html/test02.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Material Design Lite 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 |
21 | Home 22 |
23 |
24 |
25 |
26 |
27 | 28 |
29 | 欢迎使用统计报表系统 30 |
31 |
32 |
33 | 45 |
46 |
47 |
48 |
49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 |
NamePositionOfficeAgeStart dateSalary
Tiger NixonSystem ArchitectEdinburgh612011/04/25$320,800
Garrett WintersAccountantTokyo632011/07/25$170,750
Ashton CoxJunior Technical AuthorSan Francisco662009/01/12$86,000
Cedric KellySenior Javascript DeveloperEdinburgh222012/03/29$433,060
Airi SatouAccountantTokyo332008/11/28$162,700
Brielle WilliamsonIntegration SpecialistNew York612012/12/02$372,000
Herrod ChandlerSales AssistantSan Francisco592012/08/06$137,500
Rhona DavidsonIntegration SpecialistTokyo552010/10/14$327,900
Colleen HurstJavascript DeveloperSan Francisco392009/09/15$205,500
Sonya FrostSoftware EngineerEdinburgh232008/12/13$103,600
Jena GainesOffice ManagerLondon302008/12/19$90,560
Doris WilderSales AssistantSidney232010/09/20$85,600
Angelica RamosChief Executive Officer (CEO)London472009/10/09$1,200,000
Gavin JoyceDeveloperEdinburgh422010/12/22$92,575
Jennifer ChangRegional DirectorSingapore282010/11/14$357,650
Brenden WagnerSoftware EngineerSan Francisco282011/06/07$206,850
Martena MccrayPost-Sales supportEdinburgh462011/03/09$324,050
Unity ButlerMarketing DesignerSan Francisco472009/12/09$85,675
Howard HatfieldOffice ManagerSan Francisco512008/12/16$164,500
Hope FuentesSecretarySan Francisco412010/02/12$109,850
Vivian HarrellFinancial ControllerSan Francisco622009/02/14$452,500
Timothy MooneyOffice ManagerLondon372008/12/11$136,200
Jackson BradshawDirectorNew York652008/09/26$645,750
Olivia LiangSupport EngineerSingapore642011/02/03$234,500
Bruno NashSoftware EngineerLondon382011/05/03$163,500
Sakura YamamotoSupport EngineerTokyo372009/08/19$139,575
Thor WaltonDeveloperNew York612013/08/11$98,540
Finn CamachoSupport EngineerSan Francisco472009/07/07$87,500
Serge BaldwinData CoordinatorSingapore642012/04/09$138,575
NamePositionOfficeAgeStart dateSalary
305 |
306 |
307 |
308 |
309 | 310 | 311 | 312 | 324 | 325 | 326 | -------------------------------------------------------------------------------- /static/html/test03.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Material Design Lite 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 25 | 26 |
27 |
28 | 29 |
30 | 31 | Title 32 |
33 |
35 | 39 |
40 | 42 |
43 |
44 |
45 | 46 |
47 |
48 | 49 | 55 |
56 |
57 |
58 | Title 59 | 65 |
66 |
67 |
68 |
69 |
70 |
71 | 72 | 73 | 74 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /static/html/test04.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Material Design Lite 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |
22 |
23 | 24 | Title 25 | 26 |
27 | 28 | 34 |
35 |
36 |
37 | Title 38 | 44 |
45 |
46 |
47 |
48 |
49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /static/img/user.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golangpkg/go-stat-reporter/b08d197a79515b90e46d640be2b42ec2fedbeb34/static/img/user.jpg -------------------------------------------------------------------------------- /static/js/dataTables.buttons.min.js: -------------------------------------------------------------------------------- 1 | /*! Buttons for DataTables 1.1.2 2 | * ©2015 SpryMedia Ltd - datatables.net/license 3 | */ 4 | !function(a){"function"==typeof define&&define.amd?define(["jquery","datatables.net"],function(b){return a(b,window,document)}):"object"==typeof exports?module.exports=function(b,c){return b||(b=window),c&&c.fn.dataTable||(c=require("datatables.net")(b,c).$),a(c,b,b.document)}:a(jQuery,window,document)}(function(a,b,c,d){"use strict";var e=a.fn.dataTable,f=0,g=0,h=e.ext.buttons,i=function(b,c){c===!0&&(c={}),a.isArray(c)&&(c={buttons:c}),this.c=a.extend(!0,{},i.defaults,c),c.buttons&&(this.c.buttons=c.buttons),this.s={dt:new e.Api(b),buttons:[],subButtons:[],listenKeys:"",namespace:"dtb"+f++},this.dom={container:a("<"+this.c.dom.container.tag+"/>").addClass(this.c.dom.container.className)},this._constructor()};a.extend(i.prototype,{action:function(a,b){var c=this._indexToButton(a).conf;this.s.dt;return b===d?c.action:(c.action=b,this)},active:function(a,b){var c=this._indexToButton(a),e=this.c.dom.button.active;return b===d?c.node.hasClass(e):(c.node.toggleClass(e,b===d?!0:b),this)},add:function(a,b){if("string"==typeof a&&-1!==a.indexOf("-")){var c=a.split("-");this.c.buttons[1*c[0]].buttons.splice(1*c[1],0,b)}else this.c.buttons.splice(1*a,0,b);return this.dom.container.empty(),this._buildButtons(this.c.buttons),this},container:function(){return this.dom.container},disable:function(a){var b=this._indexToButton(a);return b.node.addClass(this.c.dom.button.disabled),this},destroy:function(){a("body").off("keyup."+this.s.namespace);var b,c,d,e,f=this.s.buttons,g=this.s.subButtons;for(b=0,c=f.length;c>b;b++)for(this.removePrep(b),d=0,e=g[b].length;e>d;d++)this.removePrep(b+"-"+d);this.removeCommit(),this.dom.container.remove();var h=this.s.dt.settings()[0];for(b=0,c=h.length;c>b;b++)if(h.inst===this){h.splice(b,1);break}return this},enable:function(a,b){if(b===!1)return this.disable(a);var c=this._indexToButton(a);return c.node.removeClass(this.c.dom.button.disabled),this},name:function(){return this.c.name},node:function(a){var b=this._indexToButton(a);return b.node},removeCommit:function(){var a,b,c,d=this.s.buttons,e=this.s.subButtons;for(a=d.length-1;a>=0;a--)null===d[a]&&(d.splice(a,1),e.splice(a,1),this.c.buttons.splice(a,1));for(a=0,b=e.length;b>a;a++)for(c=e[a].length-1;c>=0;c--)null===e[a][c]&&(e[a].splice(c,1),this.c.buttons[a].buttons.splice(c,1));return this},removePrep:function(a){var b,c=this.s.dt;if("number"==typeof a||-1===a.indexOf("-"))b=this.s.buttons[1*a],b.conf.destroy&&b.conf.destroy.call(c.button(a),c,b,b.conf),b.node.remove(),this._removeKey(b.conf),this.s.buttons[1*a]=null;else{var d=a.split("-");b=this.s.subButtons[1*d[0]][1*d[1]],b.conf.destroy&&b.conf.destroy.call(c.button(a),c,b,b.conf),b.node.remove(),this._removeKey(b.conf),this.s.subButtons[1*d[0]][1*d[1]]=null}return this},text:function(a,b){var c=this._indexToButton(a),e=this.c.dom.collection.buttonLiner,f="string"==typeof a&&-1!==a.indexOf("-")&&e&&e.tag?e.tag:this.c.dom.buttonLiner.tag,g=this.s.dt,h=function(a){return"function"==typeof a?a(g,c.node,c.conf):a};return b===d?h(c.conf.text):(c.conf.text=b,f?c.node.children(f).html(h(b)):c.node.html(h(b)),this)},toIndex:function(a){var b,c,d,e,f=this.s.buttons,g=this.s.subButtons;for(b=0,c=f.length;c>b;b++)if(f[b].node[0]===a)return b+"";for(b=0,c=g.length;c>b;b++)for(d=0,e=g[b].length;e>d;d++)if(g[b][d].node[0]===a)return b+"-"+d},_constructor:function(){var b=this,d=this.s.dt,e=d.settings()[0];e._buttons||(e._buttons=[]),e._buttons.push({inst:this,name:this.c.name}),this._buildButtons(this.c.buttons),d.on("destroy",function(){b.destroy()}),a("body").on("keyup."+this.s.namespace,function(a){if(!c.activeElement||c.activeElement===c.body){var d=String.fromCharCode(a.keyCode).toLowerCase();-1!==b.s.listenKeys.toLowerCase().indexOf(d)&&b._keypress(d,a)}})},_addKey:function(b){b.key&&(this.s.listenKeys+=a.isPlainObject(b.key)?b.key.key:b.key)},_buildButtons:function(b,c,e){var f=this.s.dt,g=0;c||(c=this.dom.container,this.s.buttons=[],this.s.subButtons=[]);for(var h=0,i=b.length;i>h;h++){var j=this._resolveExtends(b[h]);if(j)if(a.isArray(j))this._buildButtons(j,c,e);else{var k=this._buildButton(j,e!==d);if(k){var l=k.node;if(c.append(k.inserter),e===d?(this.s.buttons.push({node:l,conf:j,inserter:k.inserter}),this.s.subButtons.push([])):this.s.subButtons[e].push({node:l,conf:j,inserter:k.inserter}),j.buttons){var m=this.c.dom.collection;j._collection=a("<"+m.tag+"/>").addClass(m.className),this._buildButtons(j.buttons,j._collection,g)}j.init&&j.init.call(f.button(l),f,l,j),g++}}}},_buildButton:function(b,c){var d=this.c.dom.button,e=this.c.dom.buttonLiner,f=this.c.dom.collection,h=this.s.dt,i=function(a){return"function"==typeof a?a(h,k,b):a};if(c&&f.button&&(d=f.button),c&&f.buttonLiner&&(e=f.buttonLiner),b.available&&!b.available(h,b))return!1;var j=function(b,c,d,e){e.action.call(c.button(d),b,c,d,e),a(c.table().node()).triggerHandler("buttons-action.dt",[c.button(d),c,d,e])},k=a("<"+d.tag+"/>").addClass(d.className).attr("tabindex",this.s.dt.settings()[0].iTabIndex).attr("aria-controls",this.s.dt.table().node().id).on("click.dtb",function(a){a.preventDefault(),!k.hasClass(d.disabled)&&b.action&&j(a,h,k,b),k.blur()}).on("keyup.dtb",function(a){13===a.keyCode&&!k.hasClass(d.disabled)&&b.action&&j(a,h,k,b)});e.tag?k.append(a("<"+e.tag+"/>").html(i(b.text)).addClass(e.className)):k.html(i(b.text)),b.enabled===!1&&k.addClass(d.disabled),b.className&&k.addClass(b.className),b.titleAttr&&k.attr("title",b.titleAttr),b.namespace||(b.namespace=".dt-button-"+g++);var l,m=this.c.dom.buttonContainer;return l=m&&m.tag?a("<"+m.tag+"/>").addClass(m.className).append(k):k,this._addKey(b),{node:k,inserter:l}},_indexToButton:function(a){if("number"==typeof a||-1===a.indexOf("-"))return this.s.buttons[1*a];var b=a.split("-");return this.s.subButtons[1*b[0]][1*b[1]]},_keypress:function(b,c){var d,e,f,g,h=this.s.buttons,i=this.s.subButtons,j=function(d,e){if(d.key)if(d.key===b)e.click();else if(a.isPlainObject(d.key)){if(d.key.key!==b)return;if(d.key.shiftKey&&!c.shiftKey)return;if(d.key.altKey&&!c.altKey)return;if(d.key.ctrlKey&&!c.ctrlKey)return;if(d.key.metaKey&&!c.metaKey)return;e.click()}};for(d=0,e=h.length;e>d;d++)j(h[d].conf,h[d].node);for(d=0,e=i.length;e>d;d++)for(f=0,g=i[d].length;g>f;f++)j(i[d][f].conf,i[d][f].node)},_removeKey:function(b){if(b.key){var c=a.isPlainObject(b.key)?b.key.key:b.key,d=this.s.listenKeys.split(""),e=a.inArray(c,d);d.splice(e,1),this.s.listenKeys=d.join("")}},_resolveExtends:function(b){var c,e,f=this.s.dt,g=function(c){for(var e=0;!a.isPlainObject(c)&&!a.isArray(c);){if(c===d)return;if("function"==typeof c){if(c=c(f,b),!c)return!1}else if("string"==typeof c){if(!h[c])throw"Unknown button type: "+c;c=h[c]}if(e++,e>30)throw"Buttons: Too many iterations"}return a.isArray(c)?c:a.extend({},c)};for(b=g(b);b&&b.extend;){if(!h[b.extend])throw"Cannot extend unknown button type: "+b.extend;var i=g(h[b.extend]);if(a.isArray(i))return i;if(!i)return!1;var j=i.className;b=a.extend({},i,b),j&&b.className!==j&&(b.className=j+" "+b.className);var k=b.postfixButtons;if(k){for(b.buttons||(b.buttons=[]),c=0,e=k.length;e>c;c++)b.buttons.push(k[c]);b.postfixButtons=null}var l=b.prefixButtons;if(l){for(b.buttons||(b.buttons=[]),c=0,e=l.length;e>c;c++)b.buttons.splice(c,0,l[c]);b.prefixButtons=null}b.extend=i.extend}return b}}),i.background=function(b,c,e){e===d&&(e=400),b?a("
").addClass(c).css("display","none").appendTo("body").fadeIn(e):a("body > div."+c).fadeOut(e,function(){a(this).remove()})},i.instanceSelector=function(b,c){if(!b)return a.map(c,function(a){return a.inst});var d=[],e=a.map(c,function(a){return a.name}),f=function(b){if(a.isArray(b))for(var g=0,h=b.length;h>g;g++)f(b[g]);else if("string"==typeof b)if(-1!==b.indexOf(","))f(b.split(","));else{var i=a.inArray(a.trim(b),e);-1!==i&&d.push(c[i].inst)}else"number"==typeof b&&d.push(c[b].inst)};return f(b),d},i.buttonSelector=function(b,c){for(var e=[],f=function(b,c){var g,h,i=[];a.each(c.s.buttons,function(a,b){null!==b&&i.push({node:b.node[0],name:b.conf.name})}),a.each(c.s.subButtons,function(b,c){a.each(c,function(a,b){null!==b&&i.push({node:b.node[0],name:b.conf.name})})});var j=a.map(i,function(a){return a.node});if(a.isArray(b)||b instanceof a)for(g=0,h=b.length;h>g;g++)f(b[g],c);else if(null===b||b===d||"*"===b)for(g=0,h=i.length;h>g;g++)e.push({inst:c,idx:c.toIndex(i[g].node)});else if("number"==typeof b)e.push({inst:c,idx:b});else if("string"==typeof b)if(-1!==b.indexOf(",")){var k=b.split(",");for(g=0,h=k.length;h>g;g++)f(a.trim(k[g]),c)}else if(b.match(/^\d+(\-\d+)?$/))e.push({inst:c,idx:b});else if(-1!==b.indexOf(":name")){var l=b.replace(":name","");for(g=0,h=i.length;h>g;g++)i[g].name===l&&e.push({inst:c,idx:c.toIndex(i[g].node)})}else a(j).filter(b).each(function(){e.push({inst:c,idx:c.toIndex(this)})});else if("object"==typeof b&&b.nodeName){var m=a.inArray(b,j);-1!==m&&e.push({inst:c,idx:c.toIndex(j[m])})}},g=0,h=b.length;h>g;g++){var i=b[g];f(c,i)}return e},i.defaults={buttons:["copy","excel","csv","pdf","print"],name:"main",tabIndex:0,dom:{container:{tag:"div",className:"dt-buttons"},collection:{tag:"div",className:"dt-button-collection"},button:{tag:"a",className:"dt-button",active:"active",disabled:"disabled"},buttonLiner:{tag:"span",className:""}}},i.version="1.1.2",a.extend(h,{collection:{text:function(a,b,c){return a.i18n("buttons.collection","Collection")},className:"buttons-collection",action:function(d,e,f,g){var h=f,j=h.offset(),k=a(e.table().container()),l=!1;a("div.dt-button-background").length&&(l=a("div.dt-button-collection").offset(),a(c).trigger("click.dtb-collection")),g._collection.addClass(g.collectionLayout).css("display","none").appendTo("body").fadeIn(g.fade);var m=g._collection.css("position");if(l&&"absolute"===m)g._collection.css({top:l.top+5,left:l.left+5});else if("absolute"===m){g._collection.css({top:j.top+h.outerHeight(),left:j.left});var n=j.left+g._collection.outerWidth(),o=k.offset().left+k.width();n>o&&g._collection.css("left",j.left-(n-o))}else{var p=g._collection.height()/2;p>a(b).height()/2&&(p=a(b).height()/2),g._collection.css("marginTop",-1*p)}g.background&&i.background(!0,g.backgroundClassName,g.fade),setTimeout(function(){a("div.dt-button-background").on("click.dtb-collection",function(){}),a("body").on("click.dtb-collection",function(b){a(b.target).parents().andSelf().filter(g._collection).length||(g._collection.fadeOut(g.fade,function(){g._collection.detach()}),a("div.dt-button-background").off("click.dtb-collection"),i.background(!1,g.backgroundClassName,g.fade),a("body").off("click.dtb-collection"),e.off("buttons-action.b-internal"))})},10),g.autoClose&&e.on("buttons-action.b-internal",function(){a("div.dt-button-background").click()})},background:!0,collectionLayout:"",backgroundClassName:"dt-button-background",autoClose:!1,fade:400},copy:function(a,b){return h.copyHtml5?"copyHtml5":h.copyFlash&&h.copyFlash.available(a,b)?"copyFlash":void 0},csv:function(a,b){return h.csvHtml5&&h.csvHtml5.available(a,b)?"csvHtml5":h.csvFlash&&h.csvFlash.available(a,b)?"csvFlash":void 0},excel:function(a,b){return h.excelHtml5&&h.excelHtml5.available(a,b)?"excelHtml5":h.excelFlash&&h.excelFlash.available(a,b)?"excelFlash":void 0},pdf:function(a,b){return h.pdfHtml5&&h.pdfHtml5.available(a,b)?"pdfHtml5":h.pdfFlash&&h.pdfFlash.available(a,b)?"pdfFlash":void 0},pageLength:function(b,c){var d=b.settings()[0].aLengthMenu,e=a.isArray(d[0])?d[0]:d,f=a.isArray(d[0])?d[1]:d,g=function(a){return a.i18n("buttons.pageLength",{"-1":"Show all rows",_:"Show %d rows"},a.page.len())};return{extend:"collection",text:g,className:"buttons-page-length",autoClose:!0,buttons:a.map(e,function(a,b){return{text:f[b],action:function(b,c,d,e){c.page.len(a).draw()},init:function(b,c,d){var e=this,f=function(){e.active(b.page.len()===a)};b.on("length.dt"+d.namespace,f),f()},destroy:function(a,b,c){a.off("length.dt"+c.namespace)}}}),init:function(a,b,c){var d=this;a.on("length.dt"+c.namespace,function(){d.text(g(a))})},destroy:function(a,b,c){a.off("length.dt"+c.namespace)}}}}),e.Api.register("buttons()",function(a,b){return b===d&&(b=a,a=d),this.iterator(!0,"table",function(c){return c._buttons?i.buttonSelector(i.instanceSelector(a,c._buttons),b):void 0},!0)}),e.Api.register("button()",function(a,b){var c=this.buttons(a,b);return c.length>1&&c.splice(1,c.length),c}),e.Api.registerPlural("buttons().active()","button().active()",function(a){return a===d?this.map(function(a){return a.inst.active(a.idx)}):this.each(function(b){b.inst.active(b.idx,a)})}),e.Api.registerPlural("buttons().action()","button().action()",function(a){return a===d?this.map(function(a){return a.inst.action(a.idx)}):this.each(function(b){b.inst.action(b.idx,a)})}),e.Api.register(["buttons().enable()","button().enable()"],function(a){return this.each(function(b){b.inst.enable(b.idx,a)})}),e.Api.register(["buttons().disable()","button().disable()"],function(){return this.each(function(a){a.inst.disable(a.idx)})}),e.Api.registerPlural("buttons().nodes()","button().node()",function(){var b=a();return a(this.each(function(a){b=b.add(a.inst.node(a.idx))})),b}),e.Api.registerPlural("buttons().text()","button().text()",function(a){return a===d?this.map(function(a){return a.inst.text(a.idx)}):this.each(function(b){b.inst.text(b.idx,a)})}),e.Api.registerPlural("buttons().trigger()","button().trigger()",function(){return this.each(function(a){a.inst.node(a.idx).trigger("click")})}),e.Api.registerPlural("buttons().containers()","buttons().container()",function(){var b=a();return a(this.each(function(a){b=b.add(a.inst.container())})),b}),e.Api.register("button().add()",function(a,b){return 1===this.length&&this[0].inst.add(a,b),this.button(a)}),e.Api.register("buttons().destroy()",function(a){return this.pluck("inst").unique().each(function(a){a.destroy()}),this}),e.Api.registerPlural("buttons().remove()","buttons().remove()",function(){return this.each(function(a){a.inst.removePrep(a.idx)}),this.pluck("inst").unique().each(function(a){a.removeCommit()}),this});var j;e.Api.register("buttons.info()",function(b,c,e){var f=this;return b===!1?(a("#datatables_buttons_info").fadeOut(function(){a(this).remove()}),clearTimeout(j),j=null,this):(j&&clearTimeout(j),a("#datatables_buttons_info").length&&a("#datatables_buttons_info").remove(),b=b?"

"+b+"

":"",a('
').html(b).append(a("
")["string"==typeof c?"html":"append"](c)).css("display","none").appendTo("body").fadeIn(),e!==d&&0!==e&&(j=setTimeout(function(){f.buttons.info(!1)},e)),this)}),e.Api.register("buttons.exportData()",function(a){return this.context.length?l(new e.Api(this.context[0]),a):void 0});var k=a("