diff --git a/conf/app.conf b/conf/app.conf index dc79ee37..7c1ff29e 100644 --- a/conf/app.conf +++ b/conf/app.conf @@ -18,4 +18,5 @@ db_database=mindoc_db db_username=root db_password=123456 -queue_size=50 \ No newline at end of file +#项目默认封面 +cover=/static/images/book.jpg \ No newline at end of file diff --git a/controllers/book.go b/controllers/book.go index d56657f6..56fadb46 100644 --- a/controllers/book.go +++ b/controllers/book.go @@ -1,38 +1,228 @@ package controllers -import "strings" +import ( + "strings" + "regexp" + "strconv" + "time" + "encoding/json" + "html/template" + + "github.com/lifei6671/godoc/models" + "github.com/lifei6671/godoc/utils" + "github.com/astaxie/beego" + "github.com/astaxie/beego/orm" +) type BookController struct { BaseController } -func (p *BookController) Index() { - p.TplName = "book/index.tpl" +func (c *BookController) Index() { + c.Prepare() + c.TplName = "book/index.tpl" + + pageIndex, _ := c.GetInt("page", 1) + + books,totalCount,err := models.NewBook().FindToPager(pageIndex,10,c.Member.MemberId) + + if err != nil { + c.Abort("500") + } + + html := utils.GetPagerHtml(c.Ctx.Request.RequestURI,pageIndex,10,totalCount) + + c.Data["PageHtml"] = html + + b,err := json.Marshal(books) + + if err != nil { + c.Data["Result"] = template.JS("[]") + }else{ + c.Data["Result"] = template.JS(string(b)) + } } // Dashboard 项目概要 . -func (p *BookController) Dashboard() { - p.TplName = "book/dashboard.tpl" +func (c *BookController) Dashboard() { + c.Prepare() + c.TplName = "book/dashboard.tpl" + + key := c.Ctx.Input.Param(":key") + + if key == ""{ + c.Abort("404") + } + + book,err := models.NewBookResult().FindByIdentify(key,c.Member.MemberId) + if err != nil { + if err == models.ErrPermissionDenied { + c.Abort("403") + } + c.Abort("500") + } + + c.Data["Model"] = *book } // Setting 项目设置 . -func (p *BookController) Setting() { - p.TplName = "book/setting.tpl" +func (c *BookController) Setting() { + c.Prepare() + c.TplName = "book/setting.tpl" + + key := c.Ctx.Input.Param(":key") + + if key == ""{ + c.Abort("404") + } + + book,err := models.NewBookResult().FindByIdentify(key,c.Member.MemberId) + if err != nil { + if err == models.ErrPermissionDenied { + c.Abort("403") + } + c.Abort("500") + } + + c.Data["Model"] = *book + +} +//用户列表. +func (c *BookController) Users() { + c.Prepare() + c.TplName = "book/users.tpl" + + key := c.Ctx.Input.Param(":key") + pageIndex,_ := c.GetInt("page",1) + + if key == ""{ + c.Abort("404") + } + + book,err := models.NewBookResult().FindByIdentify(key,c.Member.MemberId) + if err != nil { + if err == models.ErrPermissionDenied { + c.Abort("403") + } + c.Abort("500") + } + + c.Data["Model"] = *book + + members,totalCount,err := models.NewMemberRelationshipResult().FindForUsersByBookId(book.BookId,pageIndex,15) + + html := utils.GetPagerHtml(c.Ctx.Request.RequestURI,pageIndex,10,totalCount) + + c.Data["PageHtml"] = html + b,err := json.Marshal(members) + + if err != nil { + c.Data["Result"] = template.JS("[]") + }else{ + c.Data["Result"] = template.JS(string(b)) + } } -func (p *BookController) Users() { - p.TplName = "book/users.tpl" +func (c *BookController) AddMember() { + identify := c.GetString("identify") + account := c.GetString("account") + role_id,_ := c.GetInt("role_id",3) + + if identify == "" || account == ""{ + c.JsonResult(6001,"参数错误") + } + book ,err := models.NewBookResult().FindByIdentify("identify",c.Member.MemberId) + + if err != nil { + if err == models.ErrPermissionDenied { + c.JsonResult(403,"权限不足") + } + if err == orm.ErrNoRows { + c.JsonResult(404,"项目不能存在") + } + c.JsonResult(6002,err.Error()) + } + if book.RoleId != 0 && book.RoleId != 1 { + c.JsonResult(403,"权限不足") + } + + member := models.NewMember() + + if err := member.FindByAccount(account) ; err != nil { + c.JsonResult(404,"用户不存在") + } + + if _,err := models.NewRelationship().FindForRoleId(book.BookId,member.MemberId);err == orm.ErrNoRows { + c.JsonResult(6003,"用户已存在该项目中") + } + + relationship := models.NewRelationship() + relationship.BookId = book.BookId + relationship.MemberId = member.MemberId + relationship.RoleId = role_id + + if err := relationship.Insert(); err == nil { + c.JsonResult(0,"ok",member) + } + c.JsonResult(500,err.Error()) } + func (c *BookController) Create() { if c.Ctx.Input.IsPost() { book_name := strings.TrimSpace(c.GetString("book_name","")) identify := strings.TrimSpace(c.GetString("identify","")) description := strings.TrimSpace(c.GetString("description","")) - privately_owned := c.GetString("privately_owned") + privately_owned,_ := strconv.Atoi(c.GetString("privately_owned")) comment_status := c.GetString("comment_status") + if book_name == "" { + c.JsonResult(6001,"项目名称不能为空") + } + if identify == "" { + c.JsonResult(6002,"项目标识不能为空") + } + if ok,err := regexp.MatchString(`^[a-z]+[a-zA-Z0-9_\-]*$`,identify); !ok || err != nil { + c.JsonResult(6003,"文档标识只能包含小写字母、数字,以及“-”和“_”符号,并且只能小写字母开头") + } + if strings.Count(identify,"") > 50 { + c.JsonResult(6004,"文档标识不能超过50字") + } + if strings.Count(description,"") > 500 { + c.JsonResult(6004,"项目描述不能大于500字") + } + if privately_owned !=0 && privately_owned != 1 { + privately_owned = 1 + } + if comment_status != "open" && comment_status != "closed" && comment_status != "group_only" && comment_status != "registered_only" { + comment_status = "closed" + } + + book := models.NewBook() + + if books,err := book.FindByField("identify",identify); err == nil || len(books) > 0 { + c.JsonResult(6006,"项目标识已存在") + } + + book.BookName = book_name + book.Description = description + book.CommentCount = 0 + book.PrivatelyOwned = privately_owned + book.CommentStatus = comment_status + book.Identify = identify + book.DocCount = 0 + book.MemberId = c.Member.MemberId + book.CommentCount = 0 + book.Version = time.Now().Unix() + book.Cover = beego.AppConfig.String("cover") + + err := book.Insert() + + if err != nil { + c.JsonResult(6005,err.Error()) + } + c.JsonResult(0,"ok",book) } c.JsonResult(6001,"error") } diff --git a/models/base.go b/models/base.go new file mode 100644 index 00000000..081606ff --- /dev/null +++ b/models/base.go @@ -0,0 +1,20 @@ +package models + +import "github.com/astaxie/beego/orm" + +type Model struct { + +} + +func (m *Model) Find(id int) error { + o := orm.NewOrm() + + return o.Read(m) +} + +func (m *Model) Insert() error { + o := orm.NewOrm() + _,err := o.Insert(m) + + return err +} \ No newline at end of file diff --git a/models/book.go b/models/book.go index d2af9926..36638e88 100644 --- a/models/book.go +++ b/models/book.go @@ -1,6 +1,11 @@ package models -import "time" +import ( + "time" + + "github.com/astaxie/beego/orm" + "github.com/lifei6671/godoc/conf" +) // Book struct . type Book struct { @@ -9,17 +14,20 @@ type Book struct { BookName string `orm:"column(book_name);size(500)" json:"book_name"` // Identify 项目唯一标识. Identify string `orm:"column(identify);size(100);unique" json:"identify"` + OrderIndex int `orm:"column(order_index);type(int);default(0)" json:"order_index"` // Description 项目描述. Description string `orm:"column(description);size(2000)" json:"description"` + Label string `orm:"column(label);size(500)" json:"label"` // PrivatelyOwned 项目私有: 0 公开/ 1 私有 PrivatelyOwned int `orm:"column(privately_owned);type(int);default(0)" json:"privately_owned"` // 当项目是私有时的访问Token. - PrivateToken string `orm:"column(private_token);size(500)" json:"private_token"` + PrivateToken string `orm:"column(private_token);size(500);null" json:"private_token"` // DocCount 包含文档数量. DocCount int `orm:"column(doc_count);type(int)" json:"doc_count"` - // CommentStatus 评论设置的状态:open为允许所有人评论,closed为不允许评论, group_only 仅允许参与者评论 ,registered_only 仅允许注册者评论. + // CommentStatus 评论设置的状态:open 为允许所有人评论,closed 为不允许评论, group_only 仅允许参与者评论 ,registered_only 仅允许注册者评论. CommentStatus string `orm:"column(comment_status);size(20);default(open)" json:"comment_status"` CommentCount int `orm:"column(comment_count);type(int)" json:"comment_count"` + Cover string `orm:"column();size(1000)" json:"cover"` // CreateTime 创建时间 . CreateTime time.Time `orm:"type(datetime);column(create_time);auto_now_add"` @@ -28,6 +36,7 @@ type Book struct { Version int64 `orm:"type(bigint);column(version)" json:"version"` } + // TableName 获取对应数据库表名. func (m *Book) TableName() string { return "books" @@ -36,4 +45,96 @@ func (m *Book) TableName() string { func (m *Book) TableEngine() string { return "INNODB" } +func (m *Book) TableNameWithPrefix() string { + return conf.GetDatabasePrefix() + m.TableName() +} +func NewBook() *Book { + return &Book{} +} + +func (m *Book) Insert() error { + o := orm.NewOrm() + _,err := o.Insert(m) + + return err +} + +func (m *Book) Update(cols... string) error { + o := orm.NewOrm() + + _,err := o.Update(m,cols...) + return err +} + +func (m *Book) FindByField(field string,value interface{}) ([]Book,error) { + o := orm.NewOrm() + + var books []Book + _,err := o.QueryTable(conf.GetDatabasePrefix() + m.TableName()).Filter(field,value).All(&books) + + return books,err +} + +func (m *Book) FindToPager(pageIndex, pageSize ,memberId int) (books []BookResult,totalCount int,err error){ + + relationship := NewRelationship() + + o := orm.NewOrm() + + qb, _ := orm.NewQueryBuilder("mysql") + + qb.Select("COUNT(book.book_id) AS total_count"). + From(m.TableNameWithPrefix() + " AS book"). + LeftJoin(relationship.TableNameWithPrefix() + " AS rel"). + On("book.book_id=rel.book_id"). + Where("rel.member_id=?") + + err = o.Raw(qb.String(),memberId).QueryRow(&totalCount) + + if err != nil { + return + } + + offset := (pageIndex - 1) * pageSize + qb2,_ := orm.NewQueryBuilder("mysql") + + qb2.Select("book.*,rel.member_id","rel.role_id","m.account as create_name"). + From(m.TableNameWithPrefix() + " AS book"). + LeftJoin(relationship.TableNameWithPrefix() + " AS rel"). + On("book.book_id=rel.book_id"). + LeftJoin(NewMember().TableNameWithPrefix() + " AS m").On("rel.member_id=m.member_id AND rel.role_id=0"). + Where("rel.member_id=?"). + OrderBy("book.order_index").Desc(). + Limit(pageSize). + Offset(offset) + + _,err = o.Raw(qb2.String(),memberId).QueryRows(&books) + + sql := "SELECT m.account,doc.modify_time FROM md_documents AS doc LEFT JOIN md_members AS m ON doc.modify_at=m.member_id WHERE book_id = ? LIMIT 1 ORDER BY doc.modify_time DESC" + + if err == nil && len(books) > 0{ + for index,book := range books { + var text struct{ + Account string + ModifyTime time.Time + } + + + err1 := o.Raw(sql,book.BookId).QueryRow(&text) + if err1 == nil { + books[index].LastModifyText = text.Account + " 于 " + text.ModifyTime.Format("2006-01-02 15:04:05") + } + if book.RoleId == 0{ + book.RoleName = "创始人" + }else if book.RoleId == 1 { + book.RoleName = "管理员" + }else if book.RoleId == 2 { + book.RoleName = "编辑者" + }else if book.RoleId == 2 { + book.RoleName = "观察者" + } + } + } + return +} \ No newline at end of file diff --git a/models/book_result.go b/models/book_result.go new file mode 100644 index 00000000..e7a9f82d --- /dev/null +++ b/models/book_result.go @@ -0,0 +1,112 @@ +package models + +import ( + "time" + "github.com/astaxie/beego/orm" + "strings" +) + +type BookResult struct { + BookId int `json:"book_id"` + BookName string `json:"book_name"` + Identify string `json:"identify"` + OrderIndex int `json:"order_index"` + Description string `json:"description"` + PrivatelyOwned int `json:"privately_owned"` + PrivateToken string `json:"private_token"` + DocCount int `json:"doc_count"` + CommentStatus string `json:"comment_status"` + CommentCount int `json:"comment_count"` + CreateTime time.Time `json:"create_time"` + CreateName string `json:"create_name"` + ModifyTime time.Time `json:"modify_time"` + Cover string `json:"cover"` + Label string `json:"label"` + MemberId int `json:"member_id"` + RoleId int `json:"role_id"` + RoleName string `json:"role_name"` + + LastModifyText string `json:"last_modify_text"` +} + +func NewBookResult() *BookResult { + return &BookResult{} +} + +func (m *BookResult) FindByIdentify(identify string,member_id int) (*BookResult,error) { + o := orm.NewOrm() + + book := NewBook() + + err := o.QueryTable(book.TableNameWithPrefix()).Filter("identify", identify).One(book) + + if err != nil { + return m, err + } + + relationship := NewRelationship() + + err = o.QueryTable(relationship.TableNameWithPrefix()).Filter("book_id",book.BookId).Filter("member_id",member_id).One(relationship) + + if err != nil { + return m,err + } + var relationship2 Relationship + + err = o.QueryTable(relationship.TableNameWithPrefix()).Filter("book_id",book.BookId).Filter("role_id",0).One(&relationship2) + + if err != nil { + return m,ErrPermissionDenied + } + + member := NewMember() + + err = member.Find(relationship2.MemberId) + if err != nil { + return m,err + } + + m.BookId = book.BookId + m.BookName = book.BookName + m.Identify = book.Identify + m.OrderIndex = book.OrderIndex + m.Description = strings.Replace(book.Description,"\r\n","
",-1) + m.PrivatelyOwned = book.PrivatelyOwned + m.PrivateToken = book.PrivateToken + m.DocCount = book.DocCount + m.CommentStatus = book.CommentStatus + m.CommentCount = book.CommentCount + m.CreateTime = book.CreateTime + m.CreateName = member.Account + m.ModifyTime = book.ModifyTime + m.Cover = book.Cover + m.Label = book.Label + + m.MemberId = relationship.MemberId + m.RoleId = relationship.RoleId + + if m.RoleId == 0{ + m.RoleName = "创始人" + }else if m.RoleId == 1 { + m.RoleName = "管理员" + }else if m.RoleId == 2 { + m.RoleName = "编辑者" + }else if m.RoleId == 2 { + m.RoleName = "观察者" + } + + + doc := NewDocument() + + err = o.QueryTable(doc.TableNameWithPrefix()).Filter("book_id",book.BookId).OrderBy("modify_time").One(doc) + + if err == nil { + member2 := NewMember() + member2.Find(doc.ModifyAt) + + m.LastModifyText = member2.Account + " 于 " + doc.ModifyTime.Format("2006-01-02 15:04:05") + } + + return m,nil + +} diff --git a/models/document.go b/models/document.go index 5cafaaba..f358be4b 100644 --- a/models/document.go +++ b/models/document.go @@ -1,6 +1,9 @@ package models -import "time" +import ( + "time" + "github.com/lifei6671/godoc/conf" +) // Document struct. type Document struct { @@ -32,3 +35,30 @@ func (m *Document) TableName() string { func (m *Document) TableEngine() string { return "INNODB" } + +func (m *Document) TableNameWithPrefix() string { + return conf.GetDatabasePrefix() + m.TableName() +} + +func NewDocument() *Document { + return &Document{} +} + + + + + + + + + + + + + + + + + + + diff --git a/models/errors.go b/models/errors.go index 41038acf..8cbcf3d9 100644 --- a/models/errors.go +++ b/models/errors.go @@ -13,4 +13,6 @@ var( // ErrInvalidParameter 参数错误. ErrInvalidParameter = errors.New("Invalid parameter") + + ErrPermissionDenied = errors.New("Permission denied") ) diff --git a/models/member.go b/models/member.go index a03960e7..7b0ca226 100644 --- a/models/member.go +++ b/models/member.go @@ -5,6 +5,7 @@ import ( "time" "github.com/astaxie/beego/orm" "github.com/lifei6671/godoc/utils" + "github.com/lifei6671/godoc/conf" ) type Member struct { @@ -31,6 +32,10 @@ func (m *Member) TableEngine() string { return "INNODB" } +func (m *Member)TableNameWithPrefix() string { + return conf.GetDatabasePrefix() + m.TableName() +} + func NewMember() *Member { return &Member{} } @@ -94,4 +99,33 @@ func (m *Member) Find(id int) error{ return err } return nil -} \ No newline at end of file +} + +func (m *Member) FindByAccount (account string) error { + o := orm.NewOrm() + + err := o.QueryTable(m.TableNameWithPrefix()).Filter("account",account).One(m) + + return err +} + + + + + + + + + + + + + + + + + + + + + diff --git a/models/member_result.go b/models/member_result.go new file mode 100644 index 00000000..6291a875 --- /dev/null +++ b/models/member_result.go @@ -0,0 +1,60 @@ +package models + +import ( + "time" + "github.com/astaxie/beego/orm" +) + +type MemberRelationshipResult struct { + MemberId int `json:"member_id"` + Account string `json:"account"` + Description string `json:"description"` + Email string `json:"email"` + Phone string `json:"phone"` + Avatar string `json:"avatar"` + Role int `json:"role"` //用户角色:0 管理员/ 1 普通用户 + Status int `json:"status"` //用户状态:0 正常/1 禁用 + CreateTime time.Time `json:"create_time"` + CreateAt int `json:"create_at"` + RelationshipId int `json:"relationship_id"` + BookId int `json:"book_id"` + // RoleId 角色:0 创始人(创始人不能被移除) / 1 管理员/2 编辑者/3 观察者 + RoleId int `json:"role_id"` +} + +func NewMemberRelationshipResult() *MemberRelationshipResult { + return &MemberRelationshipResult{} +} + +func (m *MemberRelationshipResult) FindForUsersByBookId(book_id ,pageIndex, pageSize int) ([]MemberRelationshipResult,int,error) { + o := orm.NewOrm() + + var members []MemberRelationshipResult + + sql1 := "SELECT * FROM md_relationship AS rel LEFT JOIN md_members as member ON rel.member_id = member.member_id WHERE rel.book_id = ? ORDER BY rel.relationship_id DESC LIMIT ?,?" + + sql2 := "SELECT count(*) AS total_count FROM md_relationship AS rel LEFT JOIN md_members as member ON rel.member_id = member.member_id WHERE rel.book_id = ?" + + var total_count int + + err := o.Raw(sql2,book_id).QueryRow(&total_count) + + if err != nil { + return members,0,err + } + + offset := (pageIndex-1) * pageSize + + _,err = o.Raw(sql1,book_id,offset,pageSize).QueryRows(&members) + + if err != nil { + return members,0,err + } + + return members,total_count,nil +} + + + + + diff --git a/models/relationship.go b/models/relationship.go index 394fddc8..c483e037 100644 --- a/models/relationship.go +++ b/models/relationship.go @@ -1,5 +1,10 @@ package models +import ( + "github.com/lifei6671/godoc/conf" + "github.com/astaxie/beego/orm" +) + type Relationship struct { RelationshipId int `orm:"pk;auto;unique;column(relationship_id)" json:"relationship_id"` MemberId int `orm:"column(member_id);type(int)" json:"member_id"` @@ -13,6 +18,10 @@ type Relationship struct { func (m *Relationship) TableName() string { return "relationship" } +func (m *Relationship) TableNameWithPrefix() string { + return conf.GetDatabasePrefix() + m.TableName() +} + // TableEngine 获取数据使用的引擎. func (m *Relationship) TableEngine() string { return "INNODB" @@ -23,4 +32,40 @@ func (u *Relationship) TableUnique() [][]string { return [][]string{ []string{"MemberId", "BookId"}, } -} \ No newline at end of file +} + +func NewRelationship() *Relationship { + return &Relationship{} +} + +func (m *Relationship) FindForRoleId(book_id ,member_id int) (int,error) { + o := orm.NewOrm() + + relationship := NewRelationship() + + err := o.QueryTable(m.TableNameWithPrefix()).Filter("book_id",book_id).Filter("member_id",member_id).One(relationship) + + if err != nil { + return 0,err + } + return relationship.RoleId,nil +} + +func (m *Relationship) Insert() error { + o := orm.NewOrm() + + _,err := o.Insert(m) + + return err +} + +func (m *Relationship) Update() error { + o := orm.NewOrm() + + _,err := o.Update(m) + + return err +} + + + diff --git a/routers/router.go b/routers/router.go index d6a2640d..c5d73646 100644 --- a/routers/router.go +++ b/routers/router.go @@ -24,8 +24,9 @@ func init() { beego.Router("/book/:key/dashboard", &controllers.BookController{},"*:Dashboard") beego.Router("/book/:key/setting", &controllers.BookController{},"*:Setting") beego.Router("/book/:key/users", &controllers.BookController{},"*:Users") - beego.Router("/book/:key/edit/:id", &controllers.BookController{},"*:Edit") + beego.Router("/book/:key/edit", &controllers.BookController{},"*:Edit") beego.Router("/book/create", &controllers.BookController{},"*:Create") + beego.Router("/book/member/create", &controllers.BookController{},"POST:AddMember") beego.Router("/book/:key/users/create", &controllers.BookMemberController{},"*:Create") beego.Router("/book/:key/users/change", &controllers.BookMemberController{},"*:Change") diff --git a/static/js/main.js b/static/js/main.js index f1aa93f4..a98557cf 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -10,4 +10,25 @@ function showError($msg) { function showSuccess($msg) { $("#form-error-message").addClass("success-message").removeClass("error-message").text($msg); return true; -} \ No newline at end of file +} + +Date.prototype.format = function(fmt) { + var o = { + "M+" : this.getMonth()+1, //月份 + "d+" : this.getDate(), //日 + "h+" : this.getHours(), //小时 + "m+" : this.getMinutes(), //分 + "s+" : this.getSeconds(), //秒 + "q+" : Math.floor((this.getMonth()+3)/3), //季度 + "S" : this.getMilliseconds() //毫秒 + }; + if(/(y+)/.test(fmt)) { + fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length)); + } + for(var k in o) { + if(new RegExp("("+ k +")").test(fmt)){ + fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length))); + } + } + return fmt; +}; \ No newline at end of file diff --git a/utils/pager.go b/utils/pager.go new file mode 100644 index 00000000..74c3b30e --- /dev/null +++ b/utils/pager.go @@ -0,0 +1,332 @@ +package utils + +import ( + // "fmt" + html "html/template" + con "strconv" + "strings" + + "github.com/astaxie/beego/orm" + "fmt" +) + +type PageOptions struct { + TableName string //表名 -----------------[必填] + Conditions string //条件 + CurrentPage int //当前页 ,默认1 每次分页,必须在前台设置新的页数,不设置始终默认1.在控制器中使用方式:cp, _ := this.GetInt("pno") po.CurrentPage = int(cp) + PageSize int //页面大小,默认20 + LinkItemCount int //生成A标签的个数 默认10个 + Href string //A标签的链接地址 ---------[不需要设置] + ParamName string //参数名称 默认是pno + FirstPageText string //首页文字 默认"首页" + LastPageText string //尾页文字 默认"尾页" + PrePageText string //上一页文字 默认"上一页" + NextPageText string //下一页文字 默认"下一页" + EnableFirstLastLink bool //是否启用首尾连接 默认false 建议开启 + EnablePreNexLink bool //是否启用上一页,下一页连接 默认false 建议开启 +} + +/** + * 分页函数,适用任何表 + * 返回 总记录条数,总页数,以及当前请求的数据RawSeter,调用中需要"rs.QueryRows(&tblog)"就行了 --tblog是一个Tb_log对象 + * 参数:表名,当前页数,页面大小,条件(查询条件,格式为 " and name='zhifeiya' and age=12 ") + */ +func GetPagesInfo(tableName string, currentpage int, pagesize int, conditions string) (int, int, orm.RawSeter) { + if currentpage <= 1 { + currentpage = 1 + } + if pagesize == 0 { + pagesize = 20 + } + var rs orm.RawSeter + o := orm.NewOrm() + var totalItem, totalpages int = 0, 0 //总条数,总页数 + o.Raw("SELECT count(*) FROM " + tableName + " where 1 > 0 " + conditions).QueryRow(&totalItem) //获取总条数 + if totalItem <= pagesize { + totalpages = 1 + } else if totalItem > pagesize { + temp := totalItem / pagesize + if (totalItem % pagesize) != 0 { + temp = temp + 1 + } + totalpages = temp + } + rs = o.Raw("select * from " + tableName + " where 1 > 0 " + conditions + " LIMIT " + con.Itoa((currentpage-1)*pagesize) + "," + con.Itoa(pagesize)) + return totalItem, totalpages, rs +} + +/** + * 返回总记录条数,总页数,当前页面数据,分页html + * 根据分页选项,生成分页连接 下面是一个实例: + func (this *MainController) Test() { + var po util.PageOptions + po.EnablePreNexLink = true + po.EnableFirstLastLink = true + po.LinkItemCount = 7 + po.TableName = "help_topic" + cp, _ := this.GetInt("pno") + po.CurrentPage = int(cp) + _,_,_ pager := util.GetPagerLinks(&po, this.Ctx) + this.Data["Email"] = html.HTML(pager) + this.TplName = "test.html" + } +*/ +func GetPagerLinks(po *PageOptions,requestURI string) (int, int, orm.RawSeter, html.HTML) { + str := "" + totalItem, totalpages, rs := GetPagesInfo(po.TableName, po.CurrentPage, po.PageSize, po.Conditions) + po = setDefault(po, totalpages) + DealUri(po, requestURI) + if totalpages <= po.LinkItemCount { + str = fun1(po, totalpages) //显示完全 12345678910 + } else if totalpages > po.LinkItemCount { + if po.CurrentPage < po.LinkItemCount { + str = fun2(po, totalpages) //123456789...200 + } else { + if po.CurrentPage + po.LinkItemCount < totalpages { + str = fun3(po, totalpages) + } else { + str = fun4(po, totalpages) + } + } + } + return totalItem, totalpages, rs, html.HTML(str) +} + +func GetPagerHtml(requestURI string,pageIndex, pageSize,totalCount int) (html.HTML){ + po := &PageOptions{ + CurrentPage: pageIndex, + PageSize: pageSize, + EnableFirstLastLink : true, + ParamName : "page", + } + setDefault(po,totalCount) + DealUri(po,requestURI) + str := "" + if totalCount <= po.LinkItemCount { + str = fun1(po, totalCount) //显示完全 12345678910 + } else if totalCount > po.LinkItemCount { + if po.CurrentPage < po.LinkItemCount { + str = fun2(po, totalCount) //123456789...200 + } else { + if po.CurrentPage + po.LinkItemCount < totalCount { + str = fun3(po, totalCount) + } else { + str = fun4(po, totalCount) + } + } + } + str = strings.Replace(str,"?&","?",-1) + //str = strings.Replace(str,"&&","&",-1) + return html.HTML(str) +} + +/** + * 处理url,目的是保存参数 + */ +func DealUri(po *PageOptions, requestURI string) { + var rs string + if strings.Contains(requestURI, "?") { + arr := strings.Split(requestURI, "?") + rs = "" + arr2 := strings.Split(arr[1], "&") + for _, v := range arr2 { + if !strings.Contains(v, po.ParamName) { + if strings.HasSuffix(rs,"&") { + rs += v + }else{ + rs += v + "&" + } + //rs += "&" + v + } + } + if strings.HasPrefix(rs,"&") { + rs = string(rs[1:]) + } + if strings.HasSuffix(rs,"&"){ + rs = string(rs[0:strings.Count(rs,"")-1]) + } + rs = arr[0] + "?" + rs + fmt.Println(rs) + } else { + //rs = requestURI + "?" //+ po.ParamName + "time=" + con.Itoa(time.Now().Second()) + rs = requestURI + "?" + } + + po.Href = rs +} + +/** + * 1...197 198 199 200 + */ +func fun4(po *PageOptions, totalPages int) string { + rs := "" + rs += getHeader(po, totalPages) + rs += "
  • " + con.Itoa(1) + "
  • " + rs += "
  • ...
  • " + for i := totalPages - po.LinkItemCount; i <= totalPages; i++ { + if po.CurrentPage != i { + rs += "
  • " + con.Itoa(i) + "
  • " + } else { + rs += "
  • " + con.Itoa(i) + " (current)
  • " + } + } + rs += getFooter(po, totalPages) + return rs + +} + +/** + * 1...6 7 8 9 10 11 12 13 14 15... 200 + */ +func fun3(po *PageOptions, totalpages int) string { + var rs string = "" + rs += getHeader(po, totalpages) + rs += "
  • " + con.Itoa(1) + "
  • " + rs += "..." + for i := po.CurrentPage - po.LinkItemCount/2 + 1; i <= po.CurrentPage+po.LinkItemCount/2-1; i++ { + if po.CurrentPage != i { + rs += "" + con.Itoa(i) + "" + } else { + rs += "
  • " + con.Itoa(i) + " (current)
  • " + } + } + rs += "..." + rs += "
  • " + con.Itoa(totalpages) + "
  • " + rs += getFooter(po, totalpages) + return rs + +} + +/** + * totalpages > po.LinkItemCount po.CurrentPage < po.LinkItemCount + * 123456789...200 + */ +func fun2(po *PageOptions, totalpages int) string { + var rs string = "" + rs += getHeader(po, totalpages) + for i := 1; i <= po.LinkItemCount+1; i++ { + if i == po.LinkItemCount { + rs += "
  • ...
  • " + } else if i == po.LinkItemCount+1 { + rs += "
  • " + con.Itoa(totalpages) + "
  • " + } else { + if po.CurrentPage != i { + rs += "
  • " + con.Itoa(i) + "
  • " + } else { + rs += "
  • " + con.Itoa(i) + " (current)
  • " + } + } + } + rs += getFooter(po, totalpages) + return rs +} + +/** + * totalpages <= po.LinkItemCount + * 显示完全 12345678910 + */ +func fun1(po *PageOptions, totalpages int) string { + + var rs string = "" + rs += getHeader(po, totalpages) + for i := 1; i <= totalpages; i++ { + if po.CurrentPage != i { + + rs += "
  • " + con.Itoa(i) + "
  • " + } else { + rs += "
  • " + con.Itoa(i) + " (current)
  • " + } + } + rs += getFooter(po, totalpages) + return rs +} + +/** + * 头部 + */ +func getHeader(po *PageOptions, totalpages int) string { + var rs string = "" + return rs +} + +/** + * 设置默认值 + */ +func setDefault(po *PageOptions, totalpages int) *PageOptions { + if len(po.FirstPageText) <= 0 { + po.FirstPageText = "首页" + } + if len(po.LastPageText) <= 0 { + po.LastPageText = "尾页" + } + if len(po.PrePageText) <= 0 { + po.PrePageText = "上一页" + } + if len(po.NextPageText) <= 0 { + po.NextPageText = "下一页" + } + if po.CurrentPage >= totalpages { + po.CurrentPage = totalpages + } + if po.CurrentPage <= 1 { + po.CurrentPage = 1 + } + if po.LinkItemCount == 0 { + po.LinkItemCount = 10 + } + if po.PageSize == 0 { + po.PageSize = 20 + } + if len(po.ParamName) <= 0 { + po.ParamName = "pno" + } + return po +} + +/** + *判断首页尾页 上一页下一页是否能用 + */ +func judgeDisable(po *PageOptions, totalpages int, h_f int) string { + var rs string = "" + //判断头部 + if h_f == 0 { + if po.CurrentPage == 1 { + rs = " " + } + } else { + if po.CurrentPage == totalpages { + rs = " " + } + } + return rs +} \ No newline at end of file diff --git a/views/book/dashboard.tpl b/views/book/dashboard.tpl index 7744de0d..d2f30550 100644 --- a/views/book/dashboard.tpl +++ b/views/book/dashboard.tpl @@ -26,53 +26,63 @@
    - 这是一个测试项目 - 编辑 - 阅读 - 发布 + + {{if eq .Model.PrivatelyOwned 0}} + + {{else}} + + {{end}} + {{.Model.BookName}} + + {{if ne .Model.RoleId 3}} + 编辑 + 阅读 + 发布 + {{end}}
    - +
    创建者: - - Minho - + {{.Model.CreateName}}
    文档数量: - 20 + {{.Model.DocCount}} 篇
    创建时间: - 2017-05-25 12:25:45 + {{date .Model.CreateTime "Y-m-d H:i:s"}}
    修改时间: - 2017-05-25 12:25:45 -
    -
    《TCP/IP详解,卷1:协议》是一本完整而详细的TCP/IP协议指南。描述了属于每一层的各个协议以及它们如何在不同操作系统中运行。
    -
    - 作者用Lawrence Berkeley实验室的tcpdump程序来捕获不同操作系统和TCP/IP实现之间传输的不同分组。对tcpdump输出的研究可以帮助理解不同协议如何工作。
    -
    - 本书适合作为计算机专业学生学习网络的教材和教师参考书。也适用于研究网络的技术人员。 + {{date .Model.ModifyTime "Y-m-d H:i:s"}}
    +
    + 担任角色: + {{.Model.RoleName}} +
    +
    + 评论数量: + {{.Model.CommentCount}} 条 +
    +
    {{.Model.Description}}
    diff --git a/views/book/index.tpl b/views/book/index.tpl index 105d99f4..402f33e5 100644 --- a/views/book/index.tpl +++ b/views/book/index.tpl @@ -37,35 +37,54 @@
    -
    -
    +
    + +
    +
    @@ -91,7 +110,7 @@
    -

    文档标识只能包含小写字母、数字,以及“-”和“_”符号,并且只能小写字母打头

    +

    文档标识只能包含小写字母、数字,以及“-”和“_”符号,并且只能小写字母开头

    @@ -118,12 +137,12 @@
    @@ -147,6 +166,7 @@ + diff --git a/views/book/setting.tpl b/views/book/setting.tpl index 1b6cb10b..d09b93d0 100644 --- a/views/book/setting.tpl +++ b/views/book/setting.tpl @@ -5,7 +5,7 @@ - 概要 - Powered by MinDoc + 设置 - Powered by MinDoc @@ -26,9 +26,9 @@
    @@ -36,8 +36,17 @@
    项目设置 + {{if eq .Model.RoleId 0 1}} + {{if eq .Model.RoleId 0}} + {{end}} + {{end}} + {{if eq .Model.PrivatelyOwned 1}} + + {{else}} + + {{end}}
    @@ -45,18 +54,68 @@
    - + +
    +
    + + +
    +
    + + +

    描述信息不超过300个字符

    +
    +
    + + +

    最多允许添加10个标签,多个标签请用“;”分割

    +
    +
    + +
    + + + + +
    +
    + {{if eq .Model.PrivatelyOwned 1}} +
    + +
    +
    + +
    +
    + + +
    +
    +
    + {{end}} +
    + +
    -
    +
    +
    diff --git a/views/book/users.tpl b/views/book/users.tpl index 1fa7dbf0..70c82076 100644 --- a/views/book/users.tpl +++ b/views/book/users.tpl @@ -5,7 +5,7 @@ - 概要 - Powered by MinDoc + 成员 - Powered by MinDoc @@ -26,9 +26,9 @@
    @@ -36,48 +36,38 @@
    成员管理 - 添加成员 +
    -
    -
    - - lifei6671 -
    - 创始人 -
    -
    -
    - - lifei6671 -
    -
    - - +
    + +
    @@ -85,9 +75,77 @@
    {{template "widgets/footer.tpl" .}}
    + + + + + \ No newline at end of file