增加评论功能

pull/678/head
wangbin05 2021-04-03 17:40:08 +08:00
parent dc578c3b34
commit 7fb0e66ddc
11 changed files with 301 additions and 91 deletions

View File

@ -109,6 +109,7 @@ func RegisterModel() {
new(models.TeamMember),
new(models.TeamRelationship),
new(models.Itemsets),
new(models.Comment),
)
gob.Register(models.Blog{})
gob.Register(models.Document{})

View File

@ -516,7 +516,6 @@ func (c *BookController) Create() {
book.Identify = identify
book.DocCount = 0
book.MemberId = c.Member.MemberId
book.CommentCount = 0
book.Version = time.Now().Unix()
book.IsEnableShare = 0
book.IsUseFirstDocument = 1
@ -634,7 +633,6 @@ func (c *BookController) Import() {
book.Identify = identify
book.DocCount = 0
book.MemberId = c.Member.MemberId
book.CommentCount = 0
book.Version = time.Now().Unix()
book.ItemId = itemId

View File

@ -0,0 +1,67 @@
package controllers
import (
"strings"
"time"
"github.com/astaxie/beego"
"github.com/mindoc-org/mindoc/conf"
"github.com/mindoc-org/mindoc/models"
"github.com/mindoc-org/mindoc/utils/pagination"
)
type CommentController struct {
BaseController
}
func (c *CommentController) Lists() {
docid, _ := c.GetInt("docid", 0)
pageIndex, _ := c.GetInt("page", 1)
beego.Info("CommentController.Lists", docid, pageIndex)
// 获取评论、分页
comments, count := models.NewComment().QueryCommentByDocumentId(docid, pageIndex, conf.PageSize)
page := pagination.PageUtil(int(count), pageIndex, conf.PageSize, comments)
beego.Info("docid=", docid, "Page", page)
var data struct {
DocId int `json:"doc_id"`
Page pagination.Page `json:"page"`
}
data.DocId = docid
data.Page = page
c.JsonResult(0, "ok", data)
return
}
func (c *CommentController) Create() {
content := c.GetString("content")
id, _ := c.GetInt("doc_id")
m := models.NewComment()
m.DocumentId = id
if len(c.Member.RealName) != 0 {
m.Author = c.Member.RealName
} else {
m.Author = c.Member.Account
}
m.MemberId = c.Member.MemberId
m.IPAddress = c.Ctx.Request.RemoteAddr
m.IPAddress = strings.Split(m.IPAddress, ":")[0]
m.CommentDate = time.Now()
m.Content = content
beego.Info(m)
m.Insert()
c.JsonResult(0, "ok")
}
func (c *CommentController) Index() {
c.Prepare()
c.TplName = "comment/index.tpl"
}

View File

@ -65,6 +65,15 @@ func (c *DocumentController) Index() {
c.Data["Content"] = template.HTML(doc.Release)
c.Data["Description"] = utils.AutoSummary(doc.Release, 120)
doc.IncrViewCount(doc.DocumentId)
c.Data["ViewCount"] = doc.ViewCount + 1
c.Data["DocumentId"] = doc.DocumentId
// 获取评论、分页
comments, count := models.NewComment().QueryCommentByDocumentId(doc.DocumentId, 1, conf.PageSize)
page := pagination.PageUtil(int(count), 1, conf.PageSize, comments)
c.Data["Page"] = page
beego.Info("docid=", doc.DocumentId, "Page", page)
}
} else {
c.Data["Title"] = "概要"
@ -83,7 +92,6 @@ func (c *DocumentController) Index() {
}
c.Data["Model"] = bookResult
c.Data["Result"] = template.HTML(tree)
}
// 阅读文档
@ -138,6 +146,7 @@ func (c *DocumentController) Read() {
doc.Processor()
c.Data["DocumentId"] = doc.DocumentId
attach, err := models.NewAttachment().FindListByDocumentId(doc.DocumentId)
if err == nil {
doc.AttachList = attach
@ -146,19 +155,29 @@ func (c *DocumentController) Read() {
doc.IncrViewCount(doc.DocumentId)
c.Data["ViewCount"] = doc.ViewCount + 1
// 获取评论、分页
comments, count := models.NewComment().QueryCommentByDocumentId(doc.DocumentId, 1, conf.PageSize)
page := pagination.PageUtil(int(count), 1, conf.PageSize, comments)
c.Data["Page"] = page
beego.Info("docid=", doc.DocumentId, "Page", page)
if c.IsAjax() {
var data struct {
DocTitle string `json:"doc_title"`
Body string `json:"body"`
Title string `json:"title"`
Version int64 `json:"version"`
ViewCount int `json:"view_count"`
DocTitle string `json:"doc_title"`
Body string `json:"body"`
Title string `json:"title"`
Version int64 `json:"version"`
ViewCount int `json:"view_count"`
DocId int `json:"doc_id"`
Page pagination.Page `json:"page"`
}
data.DocTitle = doc.DocumentName
data.Body = doc.Release
data.Title = doc.DocumentName + " - Powered by MinDoc"
data.Version = doc.Version
data.ViewCount = doc.ViewCount + 1
data.DocId = doc.DocumentId
data.Page = page
c.JsonResult(0, "ok", data)
}

View File

@ -1,19 +0,0 @@
package controllers
type CommentController struct {
BaseController
}
func (c *CommentController) Lists() {
}
func (c *CommentController) Create() {
c.JsonResult(0, "ok")
}
func (c *CommentController) Index() {
c.Prepare()
c.TplName = "comment/index.tpl"
}

View File

@ -233,6 +233,17 @@ func (m *BookResult) ToBookResult(book Book) *BookResult {
m.ItemName = item.ItemName
}
}
if m.CommentStatus == "closed" {
m.IsDisplayComment = false
} else if m.CommentStatus == "open" {
m.IsDisplayComment = true
} else if m.CommentStatus == "registered_only" {
// todo
} else if m.CommentStatus == "group_only" {
// todo
} else {
m.IsDisplayComment = false;
}
return m
}

View File

@ -52,6 +52,7 @@ func (m *Comment) TableNameWithPrefix() string {
func NewComment() *Comment {
return &Comment{}
}
func (m *Comment) Find(id int) (*Comment, error) {
if id <= 0 {
return m, ErrInvalidParameter
@ -62,6 +63,15 @@ func (m *Comment) Find(id int) (*Comment, error) {
return m, err
}
// 根据文档id查询文档评论
func (m *Comment) QueryCommentByDocumentId(doc_id, page, pagesize int) (comments []Comment, count int64) {
o := orm.NewOrm()
offset := (page - 1) * pagesize
o.QueryTable(m.TableNameWithPrefix()).Filter("document_id", doc_id).OrderBy("comment_date").Offset(offset).Limit(pagesize).All(&comments)
count, _ = o.QueryTable(m.TableNameWithPrefix()).Filter("document_id", doc_id).Count()
return
}
func (m *Comment) Update(cols ...string) error {
o := orm.NewOrm()

View File

@ -4,7 +4,6 @@ var events = function () {
window.sessionStorage && window.sessionStorage.setItem("MinDoc::LastLoadDocument:" + window.book.identify, $param.$id);
var prevState = window.history.state || {};
if ('pushState' in history) {
if ($param.$id) {
prevState.$id === $param.$id || window.history.pushState($param, $param.$id, $param.$url);
} else {
@ -43,6 +42,86 @@ var events = function () {
}();
function format(d) {
return d < 10 ? "0" + d : "" + d;
}
function timeFormat(time) {
var span = Date.parse(time)
var date = new Date(span)
var year = date.getFullYear();
var month = format(date.getMonth() + 1);
var day = format(date.getDate());
var hour = format(date.getHours());
var min = format(date.getMinutes());
var sec = format(date.getSeconds());
return year + "-" + month + "-" + day + " " + hour + ":" + min + ":" + sec;
}
function onPageClicked(page, docid) {
$.ajax({
url : "/comment/lists?page=" + page + "&docid=" + docid,
type : "GET",
beforeSend : function (xhr) {
NProgress.start();
},
success : function (res) {
console.log(res.data);
loadComment(res.data.page, res.data.doc_id);
},
complete : function () {
NProgress.done();
},
error : function () {
layer.msg("加载失败");
}
});
}
// 加载评论
function loadComment(page, docid) {
$("#commentList").empty();
var html = ""
var c = page.List;
for (var i = 0; c && i < c.length; i++) {
html += "<div class=\"comment-item\" data-id=\"" + c[i].comment_id + "\">";
html += "<p class=\"info\"><a class=\"name\">" + c[i].author + "</a><span class=\"date\">" + timeFormat(c[i].comment_date) + "</span></p>";
html += "<div class=\"content\">" + c[i].content + "</div>";
html += "<p class=\"util\">";
html += "<span class=\"operate\">";
html += "<span class=\"number\">" + i + "#</span>";
html += "</span>";
html += "</p>";
html += "</div>";
}
$("#commentList").append(html);
if (page.TotalPage > 1) {
$("#page").bootstrapPaginator({
currentPage: page.PageNo,
totalPages: page.TotalPage,
bootstrapMajorVersion: 3,
size: "middle",
onPageClicked: function(e,originalEvent,type,page){
onPageClicked(page, docid);
}
});
} else {
$("#page").find("li").remove();
}
}
// 重新渲染页面
function renderPage(data) {
$("#page-content").html(data.body);
$("title").text(data.title);
$("#article-title").text(data.doc_title);
$("#article-info").text(data.doc_info);
$("#view_count").text("阅读次数:" + data.view_count);
$("#doc_id").val(data.doc_id);
loadComment(data.page, data.doc_id);
}
/***
*
* @param $url
@ -61,11 +140,7 @@ function loadDocument($url, $id, $callback) {
}else if(data.version && data.version != $callback){
return true;
}
$("#page-content").html(data.body);
$("title").text(data.title);
$("#article-title").text(data.doc_title);
$("#article-info").text(data.doc_info);
$("#view_count").text("阅读次数:" + data.view_count);
renderPage(data);
events.trigger('article.open', {$url: $url, $id: $id});
@ -77,23 +152,13 @@ function loadDocument($url, $id, $callback) {
},
success : function (res) {
if (res.errcode === 0) {
var body = res.data.body;
var doc_title = res.data.doc_title;
var title = res.data.title;
var doc_info = res.data.doc_info;
var view_count = res.data.view_count;
renderPage(res.data);
$body = body;
$body = res.data.body;
if (typeof $callback === "function" ) {
$body = $callback(body);
}
$("#page-content").html($body);
$("title").text(title);
$("#article-title").text(doc_title);
$("#article-info").text(doc_info);
$("#view_count").text("阅读次数:" + view_count);
events.data($id, res.data);
events.trigger('article.open', { $url : $url, $id : $id });
@ -129,9 +194,6 @@ function initHighlighting() {
}
}
$(function () {
$(".view-backtop").on("click", function () {
$('.manual-right').animate({ scrollTop: '0px' }, 200);

View File

@ -112,3 +112,28 @@ func (p *Pagination) pageURL(page string) string {
return u.String()
}
type Page struct {
PageNo int `json:"PageNo"`
PageSize int `json:"PageSize"`
TotalPage int `json:"TotalPage"`
TotalCount int `json:"TotalCount"`
FirstPage bool `json:"FirstPage"`
LastPage bool `json:"LastPage"`
List interface{} `json:"List"`
}
func PageUtil(count int, pageNo int, pageSize int, list interface{}) Page {
tp := count / pageSize
if count%pageSize > 0 {
tp = count/pageSize + 1
}
return Page {
PageNo: pageNo,
PageSize: pageSize,
TotalPage: tp,
TotalCount: count,
FirstPage: pageNo == 1,
LastPage: pageNo == tp,
List: list,
}
}

View File

@ -93,6 +93,23 @@
</label>
</div>
</div>
<div class="form-group">
<label>评论</label>
<div class="radio">
<label class="radio-inline">
<input type="radio"{{if eq .Model.CommentStatus "closed"}} checked{{end}} name="comment_status" value="closed"> 关闭评论
</label>
<label class="radio-inline">
<input type="radio"{{if eq .Model.CommentStatus "open"}} checked{{end}} name="comment_status" value="open"> 所有人可见
</label>
<label class="radio-inline">
<input type="radio"{{if eq .Model.CommentStatus "registered_only"}} checked{{end}} name="comment_status" value="registered_only"> 注册用户可见
</label>
<label class="radio-inline">
<input type="radio"{{if eq .Model.CommentStatus "group_only"}} checked{{end}} name="comment_status" value="group_only"> 成员可见
</label>
</div>
</div>
{{if eq .Model.PrivatelyOwned 1}}
<div class="form-group">
<label>访问密码</label>

View File

@ -168,61 +168,51 @@
</div>
</div>
<div class="article-content">
<!-- 文章内容 -->
<div class="article-body {{if eq .Model.Editor "markdown"}}markdown-body editormd-preview-container{{else}}editor-content{{end}}" id="page-content">
{{.Content}}
</div>
<!--
{{/*
{{if .Model.IsDisplayComment}}
<div id="articleComment" class="m-comment">
<div class="comment-result">
<strong class="title">相关评论(<b class="comment-total">{{.Model.CommentCount}}</b>)</strong>
<div class="comment-post">
<form class="form" action="/comment/create" method="post">
<label class="enter w-textarea textarea-full">
<textarea class="textarea-input form-control" name="content" placeholder="文明上网,理性发言" style="height: 72px;"></textarea>
<input type="hidden" name="doc_id" value="118003">
</label>
<div class="util cf">
<div class="pull-left"><span style="font-size: 12px;color: #999"> 支持Markdown语法 </span></div>
<div class="pull-right">
<span class="form-tip w-fragment fragment-tip">Ctrl + Enter快速发布</span>
<label class="form-submit w-btn btn-success btn-m">
<button class="btn btn-success btn-sm" type="submit">发布</button>
</label>
</div>
</div>
</form>
<!-- 评论列表 -->
<div class="comment-list" id="commentList">
{{range $i, $c := .Page.List}}
<div class="comment-item" data-id="{{$c.CommentId}}">
<p class="info"><a class="name">{{$c.Author}}</a><span class="date">{{date $c.CommentDate "Y-m-d H:i:s"}}</span></p>
<div class="content">{{$c.Content}}</div>
<p class="util">
<span class="operate">
<span class="number">{{$i}}#</span>
</span>
</p>
</div>
<div class="clearfix"></div>
<div class="comment-list">
<div class="comment-empty"><b class="text">暂无相关评论</b></div>
<div class="comment-item" data-id="5841">
<p class="info"><a href="/@phptest" class="name">静夜思</a><span class="date">9月1日评论</span></p>
<div class="content">一直不明白,控制器分层和模型分层调用起来到底有什么区别</div>
<p class="util">
<span class="vote">
<a class="agree e-agree" href="javascript:;" data-id="5841" title="赞成">
<i class="fa fa-thumbs-o-up"></i></a><b class="count">4</b>
<a class="oppose e-oppose" href="javascript:;" data-id="5841" title="反对"><i class="fa fa-thumbs-o-down"></i></a>
</span>
<a class="reply e-reply" data-account="phptest">回复</a>
<span class="operate toggle">
<a class="delete e-delete" data-id="5841" data-href="/comment/delete"><i class="icon icon-cross"></i></a>
<span class="number">23#</span>
</span>
</p>
{{end}}
</div>
<!-- 翻页 -->
<ul id="page"></ul>
<!-- 发表评论 -->
<div class="comment-post">
<form class="form" id="commentForm" action="{{urlfor "CommentController.Create"}}" method="post">
<label class="enter w-textarea textarea-full">
<textarea class="textarea-input form-control" name="content" placeholder="文明上网,理性发言" style="height: 72px;"></textarea>
<input type="hidden" name="doc_id" id="doc_id" value="{{.DocumentId}}">
</label>
<div class="pull-right">
<button class="btn btn-success btn-sm" type="submit">发布</button>
</div>
</div>
</form>
</div>
</div>
{{end}}
*/}}-->
<!-- 返回顶部 -->
<div class="jump-top">
<a href="javascript:;" class="view-backtop"><i class="fa fa-arrow-up" aria-hidden="true"></i></a>
</div>
</div>
</div>
</div>
<div class="manual-progress"><b class="progress-bar"></b></div>
@ -247,7 +237,7 @@
<div class="form-group">
<label for="password" class="col-sm-2 control-label">项目地址</label>
<div class="col-sm-10">
<input type="text" value="{{urlfor "DocumentController.Index" ":key" .Model.Identify}}" class="form-control" onmouseover="this.select()" id="projectUrl" title="项目地址">
<input type="text" value="{{urlfor "DocumentController.Index" ":key" .Model.Identify}}" class="form-control" onmouseover="this.select()" title="项目地址">
</div>
<div class="clearfix"></div>
</div>
@ -276,7 +266,7 @@
<div class="form-group">
<label for="password" class="col-sm-2 control-label">项目地址</label>
<div class="col-sm-10">
<input type="text" value="{{urlfor "DocumentController.Index" ":key" .Model.Identify}}" class="form-control" onmouseover="this.select()" id="projectUrl" title="项目地址">
<input type="text" value="{{urlfor "DocumentController.Index" ":key" .Model.Identify}}" class="form-control" onmouseover="this.select()" title="项目地址">
</div>
<div class="clearfix"></div>
</div>
@ -290,6 +280,7 @@
<script src="{{cdnjs "/static/jquery/1.12.4/jquery.min.js"}}"></script>
<script src="{{cdnjs "/static/bootstrap/js/bootstrap.min.js"}}"></script>
<script src="{{cdnjs "/static/js/bootstrap-paginator.min.js"}}"></script>
<script src="{{cdnjs "/static/js/jquery.form.js"}}" type="text/javascript"></script>
<script src="{{cdnjs "/static/layer/layer.js"}}" type="text/javascript"></script>
<script src="{{cdnjs "/static/jstree/3.3.4/jstree.min.js"}}" type="text/javascript"></script>
@ -299,6 +290,18 @@
<script src="{{cdnjs "/static/js/kancloud.js" "version"}}" type="text/javascript"></script>
<script src="{{cdnjs "/static/js/splitbar.js" "version"}}" type="text/javascript"></script>
<script type="text/javascript">
if ({{.Page.TotalPage}} > 1) {
$("#page").bootstrapPaginator({
currentPage: '{{.Page.PageNo}}',
totalPages: '{{.Page.TotalPage}}',
bootstrapMajorVersion: 3,
size: "middle",
onPageClicked: function(e, originalEvent, type, page){
onPageClicked(page, {{.DocumentId}});
}
});
}
$(function () {
$("#searchList").on("click","a",function () {
var id = $(this).attr("data-id");
@ -346,6 +349,22 @@ $(function () {
window.jsTree.jstree().open_all()
}
})
// 提交评论
$("#commentForm").ajaxForm({
beforeSubmit : function () {
},
success : function (res) {
if(res.errcode === 0){
console.log("success")
}else{
console.log("error")
}
},
error : function () {
console.log("server error")
}
});
});
</script>
{{.Scripts}}