实现项目列表、概述功能

pull/25/merge
Minho 2017-04-22 17:24:17 +08:00
parent 0647707e44
commit ca0d5094c1
17 changed files with 1219 additions and 105 deletions

View File

@ -18,4 +18,5 @@ db_database=mindoc_db
db_username=root db_username=root
db_password=123456 db_password=123456
queue_size=50 #项目默认封面
cover=/static/images/book.jpg

View File

@ -1,38 +1,228 @@
package controllers 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 { type BookController struct {
BaseController BaseController
} }
func (p *BookController) Index() { func (c *BookController) Index() {
p.TplName = "book/index.tpl" 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 项目概要 . // Dashboard 项目概要 .
func (p *BookController) Dashboard() { func (c *BookController) Dashboard() {
p.TplName = "book/dashboard.tpl" 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 项目设置 . // Setting 项目设置 .
func (p *BookController) Setting() { func (c *BookController) Setting() {
p.TplName = "book/setting.tpl" 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() { func (c *BookController) AddMember() {
p.TplName = "book/users.tpl" 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() { func (c *BookController) Create() {
if c.Ctx.Input.IsPost() { if c.Ctx.Input.IsPost() {
book_name := strings.TrimSpace(c.GetString("book_name","")) book_name := strings.TrimSpace(c.GetString("book_name",""))
identify := strings.TrimSpace(c.GetString("identify","")) identify := strings.TrimSpace(c.GetString("identify",""))
description := strings.TrimSpace(c.GetString("description","")) 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") 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") c.JsonResult(6001,"error")
} }

20
models/base.go 100644
View File

@ -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
}

View File

@ -1,6 +1,11 @@
package models package models
import "time" import (
"time"
"github.com/astaxie/beego/orm"
"github.com/lifei6671/godoc/conf"
)
// Book struct . // Book struct .
type Book struct { type Book struct {
@ -9,17 +14,20 @@ type Book struct {
BookName string `orm:"column(book_name);size(500)" json:"book_name"` BookName string `orm:"column(book_name);size(500)" json:"book_name"`
// Identify 项目唯一标识. // Identify 项目唯一标识.
Identify string `orm:"column(identify);size(100);unique" json:"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 项目描述.
Description string `orm:"column(description);size(2000)" json:"description"` Description string `orm:"column(description);size(2000)" json:"description"`
Label string `orm:"column(label);size(500)" json:"label"`
// PrivatelyOwned 项目私有: 0 公开/ 1 私有 // PrivatelyOwned 项目私有: 0 公开/ 1 私有
PrivatelyOwned int `orm:"column(privately_owned);type(int);default(0)" json:"privately_owned"` PrivatelyOwned int `orm:"column(privately_owned);type(int);default(0)" json:"privately_owned"`
// 当项目是私有时的访问Token. // 当项目是私有时的访问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 包含文档数量.
DocCount int `orm:"column(doc_count);type(int)" json:"doc_count"` 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"` CommentStatus string `orm:"column(comment_status);size(20);default(open)" json:"comment_status"`
CommentCount int `orm:"column(comment_count);type(int)" json:"comment_count"` CommentCount int `orm:"column(comment_count);type(int)" json:"comment_count"`
Cover string `orm:"column();size(1000)" json:"cover"`
// CreateTime 创建时间 . // CreateTime 创建时间 .
CreateTime time.Time `orm:"type(datetime);column(create_time);auto_now_add"` 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"` Version int64 `orm:"type(bigint);column(version)" json:"version"`
} }
// TableName 获取对应数据库表名. // TableName 获取对应数据库表名.
func (m *Book) TableName() string { func (m *Book) TableName() string {
return "books" return "books"
@ -36,4 +45,96 @@ func (m *Book) TableName() string {
func (m *Book) TableEngine() string { func (m *Book) TableEngine() string {
return "INNODB" 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
}

View File

@ -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","<br/>",-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
}

View File

@ -1,6 +1,9 @@
package models package models
import "time" import (
"time"
"github.com/lifei6671/godoc/conf"
)
// Document struct. // Document struct.
type Document struct { type Document struct {
@ -32,3 +35,30 @@ func (m *Document) TableName() string {
func (m *Document) TableEngine() string { func (m *Document) TableEngine() string {
return "INNODB" return "INNODB"
} }
func (m *Document) TableNameWithPrefix() string {
return conf.GetDatabasePrefix() + m.TableName()
}
func NewDocument() *Document {
return &Document{}
}

View File

@ -13,4 +13,6 @@ var(
// ErrInvalidParameter 参数错误. // ErrInvalidParameter 参数错误.
ErrInvalidParameter = errors.New("Invalid parameter") ErrInvalidParameter = errors.New("Invalid parameter")
ErrPermissionDenied = errors.New("Permission denied")
) )

View File

@ -5,6 +5,7 @@ import (
"time" "time"
"github.com/astaxie/beego/orm" "github.com/astaxie/beego/orm"
"github.com/lifei6671/godoc/utils" "github.com/lifei6671/godoc/utils"
"github.com/lifei6671/godoc/conf"
) )
type Member struct { type Member struct {
@ -31,6 +32,10 @@ func (m *Member) TableEngine() string {
return "INNODB" return "INNODB"
} }
func (m *Member)TableNameWithPrefix() string {
return conf.GetDatabasePrefix() + m.TableName()
}
func NewMember() *Member { func NewMember() *Member {
return &Member{} return &Member{}
} }
@ -95,3 +100,32 @@ func (m *Member) Find(id int) error{
} }
return nil return nil
} }
func (m *Member) FindByAccount (account string) error {
o := orm.NewOrm()
err := o.QueryTable(m.TableNameWithPrefix()).Filter("account",account).One(m)
return err
}

View File

@ -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
}

View File

@ -1,5 +1,10 @@
package models package models
import (
"github.com/lifei6671/godoc/conf"
"github.com/astaxie/beego/orm"
)
type Relationship struct { type Relationship struct {
RelationshipId int `orm:"pk;auto;unique;column(relationship_id)" json:"relationship_id"` RelationshipId int `orm:"pk;auto;unique;column(relationship_id)" json:"relationship_id"`
MemberId int `orm:"column(member_id);type(int)" json:"member_id"` MemberId int `orm:"column(member_id);type(int)" json:"member_id"`
@ -13,6 +18,10 @@ type Relationship struct {
func (m *Relationship) TableName() string { func (m *Relationship) TableName() string {
return "relationship" return "relationship"
} }
func (m *Relationship) TableNameWithPrefix() string {
return conf.GetDatabasePrefix() + m.TableName()
}
// TableEngine 获取数据使用的引擎. // TableEngine 获取数据使用的引擎.
func (m *Relationship) TableEngine() string { func (m *Relationship) TableEngine() string {
return "INNODB" return "INNODB"
@ -24,3 +33,39 @@ func (u *Relationship) TableUnique() [][]string {
[]string{"MemberId", "BookId"}, []string{"MemberId", "BookId"},
} }
} }
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
}

View File

@ -24,8 +24,9 @@ func init() {
beego.Router("/book/:key/dashboard", &controllers.BookController{},"*:Dashboard") beego.Router("/book/:key/dashboard", &controllers.BookController{},"*:Dashboard")
beego.Router("/book/:key/setting", &controllers.BookController{},"*:Setting") beego.Router("/book/:key/setting", &controllers.BookController{},"*:Setting")
beego.Router("/book/:key/users", &controllers.BookController{},"*:Users") 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/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/create", &controllers.BookMemberController{},"*:Create")
beego.Router("/book/:key/users/change", &controllers.BookMemberController{},"*:Change") beego.Router("/book/:key/users/change", &controllers.BookMemberController{},"*:Change")

View File

@ -11,3 +11,24 @@ function showSuccess($msg) {
$("#form-error-message").addClass("success-message").removeClass("error-message").text($msg); $("#form-error-message").addClass("success-message").removeClass("error-message").text($msg);
return true; return true;
} }
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;
};

332
utils/pager.go 100644
View File

@ -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)" --tblogTb_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 += "<li><a href='" + po.Href + "&" + po.ParamName + "=" + con.Itoa(1) + "'>" + con.Itoa(1) + "</a><li>"
rs += "<li><a href=''>...</a></li>"
for i := totalPages - po.LinkItemCount; i <= totalPages; i++ {
if po.CurrentPage != i {
rs += "<li><a href='" + po.Href + "&" + po.ParamName + "=" + con.Itoa(i) + "'>" + con.Itoa(i) + "</a></li>"
} else {
rs += "<li class=\"active\"><a href=\"###\">" + con.Itoa(i) + " <span class=\"sr-only\">(current)</span></a></li>"
}
}
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 += "<li><a href='" + po.Href + "&" + po.ParamName + "=" + con.Itoa(1) + "'>" + con.Itoa(1) + "</a></li>"
rs += "<a href=''>...</a>"
for i := po.CurrentPage - po.LinkItemCount/2 + 1; i <= po.CurrentPage+po.LinkItemCount/2-1; i++ {
if po.CurrentPage != i {
rs += "<a href='" + po.Href + "&" + po.ParamName + "=" + con.Itoa(i) + "'>" + con.Itoa(i) + "</a>"
} else {
rs += "<li class=\"active\"><a href=\"###\">" + con.Itoa(i) + " <span class=\"sr-only\">(current)</span></a></li>"
}
}
rs += "<a href=''>...</a>"
rs += "<li><a href='" + po.Href + "&" + po.ParamName + "=" + con.Itoa(totalpages) + "'>" + con.Itoa(totalpages) + "</a></li>"
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 += "<li><a href=\"" + po.Href + "&" + po.ParamName + "=" + con.Itoa(i) + "\">...</a></li>"
} else if i == po.LinkItemCount+1 {
rs += "<li><a href=\"" + po.Href + "&" + po.ParamName + "=" + con.Itoa(totalpages) + "\">" + con.Itoa(totalpages) + "</a></li>"
} else {
if po.CurrentPage != i {
rs += "<li><a href='" + po.Href + "&" + po.ParamName + "=" + con.Itoa(i) + "'>" + con.Itoa(i) + "</a></li>"
} else {
rs += "<li class=\"active\"><a href=\"###\">" + con.Itoa(i) + " <span class=\"sr-only\">(current)</span></a></li>"
}
}
}
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 += "<li><a href='" + po.Href + "&" + po.ParamName + "=" + con.Itoa(i) + "'>" + con.Itoa(i) + "</a></li>"
} else {
rs += "<li class=\"active\"><a href=\"###\">" + con.Itoa(i) + " <span class=\"sr-only\">(current)</span></a></li>"
}
}
rs += getFooter(po, totalpages)
return rs
}
/**
*
*/
func getHeader(po *PageOptions, totalpages int) string {
var rs string = "<ul class=\"pagination\">"
if po.EnableFirstLastLink { //当首页,尾页都设定的时候,就显示
rs += "<li" + judgeDisable(po, totalpages, 0) + " ><a href='" + po.Href + "&" + po.ParamName + "=" + con.Itoa(1) + "'>" + po.FirstPageText + "</a></li>"
}
if po.EnablePreNexLink { // disabled=\"disabled\"
var a int = po.CurrentPage - 1
if po.CurrentPage == 1 {
a = 1
}
rs += "<li" + judgeDisable(po, totalpages, 0) + " ><a href='" + po.Href + "&" + po.ParamName + "=" + con.Itoa(a) + "'>" + po.PrePageText + "</a></li>"
}
return rs
}
/**
*
*/
func getFooter(po *PageOptions, totalpages int) string {
var rs string = ""
if po.EnablePreNexLink {
var a int = po.CurrentPage + 1
if po.CurrentPage == totalpages {
a = totalpages
}
rs += "<li " + judgeDisable(po, totalpages, 1) + " ><a href='" + po.Href + "&" + po.ParamName + "=" + con.Itoa(a) + "'>" + po.NextPageText + "</a></li>"
}
if po.EnableFirstLastLink { //当首页,尾页都设定的时候,就显示
rs += "<li " + judgeDisable(po, totalpages, 1) + " ><a href='" + po.Href + "&" + po.ParamName + "=" + con.Itoa(totalpages) + "'>" + po.LastPageText + "</a></li>"
}
rs += "</ul>"
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
}

View File

@ -26,53 +26,63 @@
<div class="row"> <div class="row">
<div class="page-left"> <div class="page-left">
<ul class="menu"> <ul class="menu">
<li class="active"><a href="{{urlfor "BookController.Dashboard" ":key" "test"}}" class="item"><i class="fa fa-dashboard" aria-hidden="true"></i> 概要</a> </li> <li class="active"><a href="{{urlfor "BookController.Dashboard" ":key" .Model.Identify}}" class="item"><i class="fa fa-dashboard" aria-hidden="true"></i> 概要</a> </li>
<li><a href="{{urlfor "BookController.Users" ":key" "test"}}" class="item"><i class="fa fa-users" aria-hidden="true"></i> 成员</a> </li> <li><a href="{{urlfor "BookController.Users" ":key" .Model.Identify}}" class="item"><i class="fa fa-users" aria-hidden="true"></i> 成员</a> </li>
<li><a href="{{urlfor "BookController.Setting" ":key" "test"}}" class="item"><i class="fa fa-gear" aria-hidden="true"></i> 设置</a> </li> <li><a href="{{urlfor "BookController.Setting" ":key" .Model.Identify}}" class="item"><i class="fa fa-gear" aria-hidden="true"></i> 设置</a> </li>
</ul> </ul>
</div> </div>
<div class="page-right"> <div class="page-right">
<div class="m-box"> <div class="m-box">
<div class="box-head"> <div class="box-head">
<strong class="box-title"><i class="fa fa-unlock" aria-hidden="true" title="公开项目" data-toggle="tooltip"></i> 这是一个测试项目</strong> <strong class="box-title">
<a href="{{urlfor "BookController.Edit" ":key" "test" ":id" "1"}}" class="btn btn-default btn-sm pull-right" target="_blank"><i class="fa fa-edit" aria-hidden="true"></i> 编辑</a> {{if eq .Model.PrivatelyOwned 0}}
<a href="{{urlfor "DocumentController.Index" ":key" "test"}}" class="btn btn-default btn-sm pull-right" style="margin-right: 5px;" target="_blank"><i class="fa fa-eye"></i> 阅读</a> <i class="fa fa-unlock" aria-hidden="true" title="公开项目" data-toggle="tooltip"></i>
<a href="{{urlfor "DocumentController.Index" ":key" "test"}}" class="btn btn-default btn-sm pull-right" style="margin-right: 5px;" target="_blank"><i class="fa fa-upload" aria-hidden="true"></i> 发布</a> {{else}}
<i class="fa fa-lock" aria-hidden="true" title="私有项目" data-toggle="tooltip"></i>
{{end}}
{{.Model.BookName}}
</strong>
{{if ne .Model.RoleId 3}}
<a href="{{urlfor "BookController.Edit" ":key" .Model.Identify ":id" .Model.BookId}}" class="btn btn-default btn-sm pull-right" target="_blank"><i class="fa fa-edit" aria-hidden="true"></i> 编辑</a>
<a href="{{urlfor "DocumentController.Index" ":key" .Model.Identify}}" class="btn btn-default btn-sm pull-right" style="margin-right: 5px;" target="_blank"><i class="fa fa-eye"></i> 阅读</a>
<a href="{{urlfor "DocumentController.Index" ":key" .Model.Identify}}" class="btn btn-default btn-sm pull-right" style="margin-right: 5px;" target="_blank"><i class="fa fa-upload" aria-hidden="true"></i> 发布</a>
{{end}}
</div> </div>
</div> </div>
<div class="box-body"> <div class="box-body">
<div class="dashboard"> <div class="dashboard">
<div class="pull-left" style="width: 200px;margin-bottom: 15px;"> <div class="pull-left" style="width: 200px;margin-bottom: 15px;">
<div class="book-image"> <div class="book-image">
<img src="/static/images/5fcb811e04c23cdb2088f26923fcc287_100.jpg"> <img src="{{.Model.Cover}}" onerror="this.src='/static/images/book.jpg'" width="174" height="229" style="border: 1px solid #666">
</div> </div>
</div> </div>
<div class="list"> <div class="list">
<span class="title">创建者:</span> <span class="title">创建者:</span>
<span class="body"> <span class="body">{{.Model.CreateName}}</span>
Minho
</span>
</div> </div>
<div class="list"> <div class="list">
<span class="title">文档数量:</span> <span class="title">文档数量:</span>
<span class="body">20</span> <span class="body">{{.Model.DocCount}}</span>
</div> </div>
<div class="list"> <div class="list">
<span class="title">创建时间:</span> <span class="title">创建时间:</span>
<span class="body"> 2017-05-25 12:25:45 </span> <span class="body"> {{date .Model.CreateTime "Y-m-d H:i:s"}} </span>
</div> </div>
<div class="list"> <div class="list">
<span class="title">修改时间:</span> <span class="title">修改时间:</span>
<span class="body"> 2017-05-25 12:25:45 </span> <span class="body"> {{date .Model.ModifyTime "Y-m-d H:i:s"}} </span>
</div> </div>
<div class="summary">《TCP/IP详解卷1协议》是一本完整而详细的TCP/IP协议指南。描述了属于每一层的各个协议以及它们如何在不同操作系统中运行。<br> <div class="list">
<br> <span class="title">担任角色:</span>
作者用Lawrence Berkeley实验室的tcpdump程序来捕获不同操作系统和TCP/IP实现之间传输的不同分组。对tcpdump输出的研究可以帮助理解不同协议如何工作。 <br> <span class="body">{{.Model.RoleName}}</span>
<br>
本书适合作为计算机专业学生学习网络的教材和教师参考书。也适用于研究网络的技术人员。
</div> </div>
<div class="list">
<span class="title">评论数量:</span>
<span class="body">{{.Model.CommentCount}} 条</span>
</div>
<div class="summary">{{.Model.Description}} </div>
</div> </div>
</div> </div>

View File

@ -37,35 +37,54 @@
</div> </div>
</div> </div>
<div class="box-body"> <div class="box-body">
<div class="book-list"> <div class="book-list" id="bookList">
<div class="list-item"> <template v-if="lists.length <= 0">
</template>
<template v-else>
<div class="list-item" v-for="item in lists">
<div class="book-title"> <div class="book-title">
<div class="pull-left"> <div class="pull-left">
<a href="{{urlfor "BookController.Dashboard" ":key" "test"}}" title="项目概要" data-toggle="tooltip"> <a :href="'/book/' + item.identify + '/dashboard'" title="项目概要" data-toggle="tooltip">
<i class="fa fa-unlock" aria-hidden="true"></i> 测试项目 <i class="fa fa-unlock" aria-hidden="true"></i> ${item.book_name}
</a> </a>
</div> </div>
<div class="pull-right"> <div class="pull-right">
<a href="{{urlfor "DocumentController.Index" ":key" "test"}}" title="查看文档" data-toggle="tooltip"><i class="fa fa-eye"></i> 查看文档</a> <a :href="'{{urlfor "DocumentController.Index" ":key" ""}}' + item.identify" title="查看文档" data-toggle="tooltip"><i class="fa fa-eye"></i> 查看文档</a>
<a href="{{urlfor "BookController.Edit" ":key" "test" ":id" "1"}}" title="编辑文档" data-toggle="tooltip"><i class="fa fa-edit" aria-hidden="true"></i> 编辑文档</a> <a :href="'/book/' + item.identify + '/edit'" title="编辑文档" data-toggle="tooltip"><i class="fa fa-edit" aria-hidden="true"></i> 编辑文档</a>
</div> </div>
<div class="clearfix"></div> <div class="clearfix"></div>
</div> </div>
<div class="desc-text"> <div class="desc-text">
<a href="{{urlfor "BookController.Dashboard" ":key" "test"}}" title="项目概要" style="font-size: 12px;" target="_blank"> <template v-if="item.description === ''">
这是一个测试用户测试项目 &nbsp;
</template>
<template v-else="">
<a :href="'/book/' + item.identify + '/dashboard'" title="项目概要" style="font-size: 12px;" target="_blank">
${item.description}
</a> </a>
</template>
</div> </div>
<div class="info"> <div class="info">
<span title="创建时间" data-toggle="tooltip" data-placement="bottom"><i class="fa fa-clock-o"></i> 2016/11/27 06:09</span> <span title="创建时间" data-toggle="tooltip" data-placement="bottom"><i class="fa fa-clock-o"></i>
<span title="创建者" data-toggle="tooltip" data-placement="bottom"><i class="fa fa-user"></i> admin</span> ${(new Date(item.create_time)).format("yyyy-MM-dd hh:mm:ss")}
<span title="文档数量" data-toggle="tooltip" data-placement="bottom"><i class="fa fa-pie-chart"></i> 4</span>
<span title="项目角色" data-toggle="tooltip" data-placement="bottom"><i class="fa fa-user-secret"></i> 拥有者</span> </span>
<span title="最后编辑" data-toggle="tooltip" data-placement="bottom"><i class="fa fa-pencil"></i> 最后编辑: admin 于 2017-04-20 12:19</span> <span title="创建者" data-toggle="tooltip" data-placement="bottom"><i class="fa fa-user"></i> ${item.create_name}</span>
<span title="文档数量" data-toggle="tooltip" data-placement="bottom"><i class="fa fa-pie-chart"></i> ${item.doc_count}</span>
<span title="项目角色" data-toggle="tooltip" data-placement="bottom"><i class="fa fa-user-secret"></i>${item.role_name}</span>
<template v-if="item.last_modify_text !== ''">
<span title="最后编辑" data-toggle="tooltip" data-placement="bottom"><i class="fa fa-pencil"></i> 最后编辑: ${item.last_modify_text}</span>
</template>
</div> </div>
</div> </div>
</template>
</div> </div>
<nav>
{{.PageHtml}}
</nav>
</div> </div>
</div> </div>
</div> </div>
@ -91,7 +110,7 @@
</div> </div>
<input type="text" class="form-control pull-left" style="width: 220px;vertical-align: middle" placeholder="项目唯一标识(不能超过50字)" name="identify" id="identify"> <input type="text" class="form-control pull-left" style="width: 220px;vertical-align: middle" placeholder="项目唯一标识(不能超过50字)" name="identify" id="identify">
<div class="clearfix"></div> <div class="clearfix"></div>
<p class="text" style="font-size: 12px;color: #999;margin-top: 6px;">文档标识只能包含小写字母、数字,以及“-”和“_”符号,并且只能小写字母头</p> <p class="text" style="font-size: 12px;color: #999;margin-top: 6px;">文档标识只能包含小写字母、数字,以及“-”和“_”符号,并且只能小写字母头</p>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -118,12 +137,12 @@
</div> </div>
<div class="col-lg-3"> <div class="col-lg-3">
<label> <label>
<input type="radio" name="comment_status" value="">关闭评论<span class="text"></span> <input type="radio" name="comment_status" value="closed">关闭评论<span class="text"></span>
</label> </label>
</div> </div>
<div class="col-lg-3"> <div class="col-lg-3">
<label> <label>
<input type="radio" name="comment_status" value="">仅允许参与者评论<span class="text"></span> <input type="radio" name="comment_status" value="group_only">仅允许参与者评论<span class="text"></span>
</label> </label>
</div> </div>
<div class="col-lg-3"> <div class="col-lg-3">
@ -147,6 +166,7 @@
<script src="/static/jquery/1.12.4/jquery.min.js"></script> <script src="/static/jquery/1.12.4/jquery.min.js"></script>
<script src="/static/bootstrap/js/bootstrap.min.js"></script> <script src="/static/bootstrap/js/bootstrap.min.js"></script>
<script src="/static/vuejs/vue.min.js" type="text/javascript"></script>
<script src="/static/js/jquery.form.js" type="text/javascript"></script> <script src="/static/js/jquery.form.js" type="text/javascript"></script>
<script src="/static/js/main.js" type="text/javascript"></script> <script src="/static/js/main.js" type="text/javascript"></script>
<script type="text/javascript"> <script type="text/javascript">
@ -176,8 +196,26 @@
return showSuccess(""); return showSuccess("");
}, },
success : function (res) { success : function (res) {
console.log(res)
if(res.errcode === 0){
}else{
showError(res.message);
} }
}
});
new Vue({
el : "#bookList",
data : {
lists : {{.Result}}
},
delimiters : ['${','}'],
methods : {
}
});
Vue.nextTick(function () {
$("[data-toggle='tooltip']").tooltip();
}); });
}); });
</script> </script>

View File

@ -5,7 +5,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>概要 - Powered by MinDoc</title> <title>设置 - Powered by MinDoc</title>
<!-- Bootstrap --> <!-- Bootstrap -->
<link href="/static/bootstrap/css/bootstrap.min.css" rel="stylesheet"> <link href="/static/bootstrap/css/bootstrap.min.css" rel="stylesheet">
@ -26,9 +26,9 @@
<div class="row"> <div class="row">
<div class="page-left"> <div class="page-left">
<ul class="menu"> <ul class="menu">
<li><a href="{{urlfor "BookController.Dashboard" ":key" "test"}}" class="item"><i class="fa fa-dashboard" aria-hidden="true"></i> 概要</a> </li> <li><a href="{{urlfor "BookController.Dashboard" ":key" .Model.Identify}}" class="item"><i class="fa fa-dashboard" aria-hidden="true"></i> 概要</a> </li>
<li><a href="{{urlfor "BookController.Users" ":key" "test"}}" class="item"><i class="fa fa-users" aria-hidden="true"></i> 成员</a> </li> <li><a href="{{urlfor "BookController.Users" ":key" .Model.Identify}}" class="item"><i class="fa fa-users" aria-hidden="true"></i> 成员</a> </li>
<li class="active"><a href="{{urlfor "BookController.Setting" ":key" "test"}}" class="item"><i class="fa fa-gear" aria-hidden="true"></i> 设置</a> </li> <li class="active"><a href="{{urlfor "BookController.Setting" ":key" .Model.Identify}}" class="item"><i class="fa fa-gear" aria-hidden="true"></i> 设置</a> </li>
</ul> </ul>
</div> </div>
@ -36,8 +36,17 @@
<div class="m-box"> <div class="m-box">
<div class="box-head"> <div class="box-head">
<strong class="box-title"> 项目设置</strong> <strong class="box-title"> 项目设置</strong>
{{if eq .Model.RoleId 0 1}}
{{if eq .Model.RoleId 0}}
<button type="button" class="btn btn-success btn-sm pull-right">转让项目</button> <button type="button" class="btn btn-success btn-sm pull-right">转让项目</button>
{{end}}
<button type="button" class="btn btn-danger btn-sm pull-right" style="margin-right: 5px;">删除项目</button> <button type="button" class="btn btn-danger btn-sm pull-right" style="margin-right: 5px;">删除项目</button>
{{end}}
{{if eq .Model.PrivatelyOwned 1}}
<button type="button" class="btn btn-success btn-sm pull-right" style="margin-right: 5px;">转为公有</button>
{{else}}
<button type="button" class="btn btn-danger btn-sm pull-right" style="margin-right: 5px;">转为私有</button>
{{end}}
</div> </div>
</div> </div>
<div class="box-body" style="padding-right: 200px;"> <div class="box-body" style="padding-right: 200px;">
@ -45,18 +54,68 @@
<form method="post" id="bookEditForm"> <form method="post" id="bookEditForm">
<div class="form-group"> <div class="form-group">
<label>标题</label> <label>标题</label>
<input type="text" class="form-control" placeholder="项目名称"> <input type="text" class="form-control" placeholder="项目名称" value="{{.Model.BookName}}">
</div>
<div class="form-group">
<label>标识</label>
<input type="text" class="form-control" value=" {{.BaseUrl}}{{urlfor "DocumentController.Index" ":key" .Model.Identify}}" disabled>
</div>
<div class="form-group">
<label>描述</label>
<textarea rows="3" class="form-control" name="description" style="height: 90px">{{.Model.Description}}</textarea>
<p class="text">描述信息不超过300个字符</p>
</div>
<div class="form-group">
<label>标签</label>
<input type="text" class="form-control" placeholder="项目标签" value="{{.Model.Label}}">
<p class="text">最多允许添加10个标签多个标签请用“;”分割</p>
</div>
<div class="form-group">
<label>开启评论</label>
<div class="radio">
<label class="radio-inline">
<input type="radio" {{if eq .Model.CommentStatus "open"}}checked{{end}} name="comment_status" value="open">允许所有人评论<span class="text"></span>
</label>
<label class="radio-inline">
<input type="radio" {{if eq .Model.CommentStatus "closed"}}checked{{end}} name="comment_status" value="closed">关闭评论<span class="text"></span>
</label>
<label class="radio-inline">
<input type="radio" {{if eq .Model.CommentStatus "group_only"}}checked{{end}} name="comment_status" value="group_only">仅允许参与者评论<span class="text"></span>
</label>
<label class="radio-inline">
<input type="radio" {{if eq .Model.CommentStatus "registered_only"}}checked{{end}} name="comment_status" value="registered_only">仅允许注册者评论<span class="text"></span>
</label>
</div>
</div>
{{if eq .Model.PrivatelyOwned 1}}
<div class="form-group">
<label>访问令牌</label>
<div class="row">
<div class="col-sm-8">
<input type="text" class="form-control" placeholder="访问令牌" readonly>
</div>
<div class="col-sm-4">
<button class="btn btn-success btn-sm">重写生成</button>
<button class="btn btn-danger btn-sm">删除令牌</button>
</div>
</div>
</div>
{{end}}
<div class="form-group">
<button type="submit" class="btn btn-success" data-loading-text="保存中...">保存修改</button>
<span id="form-error-message" class="error-message"></span>
</div> </div>
</form> </form>
</div> </div>
<div class="form-right"> <div class="form-right">
<label> <label>
<a href="javascript:;" data-toggle="modal" data-target="#upload-logo-panel"> <a href="javascript:;" data-toggle="modal" data-target="#upload-logo-panel">
<img src="/static/images/5fcb811e04c23cdb2088f26923fcc287_100.jpg" onerror="this.src='https://wiki.iminho.me/static/images/middle.gif'" alt="头像" style="max-width: 120px;" id="headimgurl"> <img src="{{.Model.Cover}}" onerror="this.src='/static/images/book.png'" alt="封面" style="max-width: 120px;border: 1px solid #999" id="headimgurl">
</a> </a>
</label> </label>
</div> </div>
<div class="clearfix"></div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -5,7 +5,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>概要 - Powered by MinDoc</title> <title>成员 - Powered by MinDoc</title>
<!-- Bootstrap --> <!-- Bootstrap -->
<link href="/static/bootstrap/css/bootstrap.min.css" rel="stylesheet"> <link href="/static/bootstrap/css/bootstrap.min.css" rel="stylesheet">
@ -26,9 +26,9 @@
<div class="row"> <div class="row">
<div class="page-left"> <div class="page-left">
<ul class="menu"> <ul class="menu">
<li><a href="{{urlfor "BookController.Dashboard" ":key" "test"}}" class="item"><i class="fa fa-dashboard" aria-hidden="true"></i> 概要</a> </li> <li><a href="{{urlfor "BookController.Dashboard" ":key" .Model.Identify}}" class="item"><i class="fa fa-dashboard" aria-hidden="true"></i> 概要</a> </li>
<li class="active"><a href="{{urlfor "BookController.Users" ":key" "test"}}" class="item"><i class="fa fa-users" aria-hidden="true"></i> 成员</a> </li> <li class="active"><a href="{{urlfor "BookController.Users" ":key" .Model.Identify}}" class="item"><i class="fa fa-users" aria-hidden="true"></i> 成员</a> </li>
<li><a href="{{urlfor "BookController.Setting" ":key" "test"}}" class="item"><i class="fa fa-gear" aria-hidden="true"></i> 设置</a> </li> <li><a href="{{urlfor "BookController.Setting" ":key" .Model.Identify}}" class="item"><i class="fa fa-gear" aria-hidden="true"></i> 设置</a> </li>
</ul> </ul>
</div> </div>
@ -36,37 +36,24 @@
<div class="m-box"> <div class="m-box">
<div class="box-head"> <div class="box-head">
<strong class="box-title"> 成员管理</strong> <strong class="box-title"> 成员管理</strong>
<a href="{{urlfor "BookController.Edit" ":key" "test" ":id" "1"}}" class="btn btn-success btn-sm pull-right" target="_blank"><i class="fa fa-edit" aria-hidden="true"></i> 添加成员</a> <button type="button" class="btn btn-success btn-sm pull-right" data-toggle="modal" data-target="#addBookMemberDialogModal"><i class="fa fa-user-plus" aria-hidden="true"></i> 添加成员</button>
</div> </div>
</div> </div>
<div class="box-body"> <div class="box-body">
<div class="users-list"> <div class="users-list" id="userList">
<div class="list-item"> <template v-if="lists.length <= 0">
<img src="/static/images/middle.gif" class="img-circle" width="34" height="34"> <div class="text-center">暂无数据</div>
<span>lifei6671</span> </template>
<template v-else>
<div class="list-item" v-for="item in lists">
<img :src="item.avatar" onerror="this.src='/static/images/middle.gif'" class="img-circle" width="34" height="34">
<span>${item.account}</span>
<div class="operate"> <div class="operate">
<template v-if="item.role_id == 0">
创始人 创始人
</div> </template>
</div> <template v-else-if="item.role_id == 1">
<div class="list-item"> {{if eq .Member.Role 0}}
<img src="/static/images/middle.gif" class="img-circle" width="34" height="34">
<span>lifei6671</span>
<div class="operate">
<div class="btn-group">
<button type="button" class="btn btn-default btn-sm" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">编辑者 <span class="caret"></span></button>
<ul class="dropdown-menu">
<li><a href="#">管理员</a> </li>
<li><a href="#">编辑者</a> </li>
<li><a href="#">观察者</a> </li>
</ul>
</div>
<a href="#" class="btn btn-danger btn-sm">移除</a>
</div>
</div>
<div class="list-item">
<img src="/static/images/middle.gif" class="img-circle" width="34" height="34">
<span>lifei6671</span>
<div class="operate">
<div class="btn-group"> <div class="btn-group">
<button type="button" class="btn btn-default btn-sm" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">编辑者 <span class="caret"></span></button> <button type="button" class="btn btn-default btn-sm" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">编辑者 <span class="caret"></span></button>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
@ -76,8 +63,11 @@
</ul> </ul>
</div> </div>
<a href="#" class="btn btn-danger btn-sm">移除</a> <a href="#" class="btn btn-danger btn-sm">移除</a>
{{end}}
</template>
</div> </div>
</div> </div>
</template>
</div> </div>
</div> </div>
</div> </div>
@ -85,9 +75,77 @@
</div> </div>
{{template "widgets/footer.tpl" .}} {{template "widgets/footer.tpl" .}}
</div> </div>
<!-- Modal -->
<div class="modal fade" id="addBookMemberDialogModal" tabindex="-1" role="dialog" aria-labelledby="addBookMemberDialogModalLabel">
<div class="modal-dialog modal-sm" role="document" style="width: 400px;">
<form method="post" autocomplete="off" class="form-horizontal" action="{{urlfor "BookController.AddMember"}}" id="addBookMemberDialogForm">
<input type="hidden" name="identify" value="{{.Model.Identify}}">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="myModalLabel">添加成员</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label class="col-sm-2 control-label">账号</label>
<div class="col-sm-10">
<input type="text" name="account" class="form-control" placeholder="用户账号" id="account" maxlength="50">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">角色</label>
<div class="col-sm-10">
<select name="role_id" class="form-control">
<option value="1">管理员</option>
<option value="2">编辑者</option>
<option value="3">观察者</option>
</select>
</div>
</div>
<div class="clearfix"></div>
</div>
<div class="modal-footer">
<span id="form-error-message"></span>
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
<button type="submit" class="btn btn-success">保存</button>
</div>
</div>
</form>
</div>
</div><!--END Modal-->
<script src="/static/jquery/1.12.4/jquery.min.js"></script> <script src="/static/jquery/1.12.4/jquery.min.js"></script>
<script src="/static/bootstrap/js/bootstrap.min.js"></script> <script src="/static/bootstrap/js/bootstrap.min.js"></script>
<script src="/static/vuejs/vue.min.js"></script>
<script src="/static/js/jquery.form.js" type="text/javascript"></script>
<script src="/static/js/main.js" type="text/javascript"></script> <script src="/static/js/main.js" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
$("#addBookMemberDialogForm").ajaxForm({
beforeSubmit : function () {
var account = $.trim($("#account").val());
if(account === ""){
return showError("账号不能为空");
}
},
success : function (res) {
}
});
new Vue({
el : "#userList",
data : {
lists : {{.Result}}
},
delimiters : ['${','}'],
methods : {
}
});
Vue.nextTick(function () {
$("[data-toggle='tooltip']").tooltip();
});
});
</script>
</body> </body>
</html> </html>