Merge pull request #779 from hz-bin/master

增加评论功能
pull/794/head
玖亖伍 2022-05-09 18:11:46 +08:00 committed by GitHub
commit dbc9fd9c91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 332 additions and 54 deletions

View File

@ -110,6 +110,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

@ -518,7 +518,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
@ -636,7 +635,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,97 @@
package controllers
import (
"strings"
"time"
"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)
// 获取评论、分页
comments, count, pageIndex := models.NewComment().QueryCommentByDocumentId(docid, pageIndex, conf.PageSize, c.Member)
page := pagination.PageUtil(int(count), pageIndex, conf.PageSize, comments)
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")
_, err := models.NewDocument().Find(id)
if err != nil {
c.JsonResult(1, "文章不存在")
}
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
m.Insert()
var data struct {
DocId int `json:"doc_id"`
}
data.DocId = id
c.JsonResult(0, "ok", data)
}
func (c *CommentController) Index() {
c.Prepare()
c.TplName = "comment/index.tpl"
}
func (c *CommentController) Delete() {
if c.Ctx.Input.IsPost() {
id, _ := c.GetInt("id", 0)
m, err := models.NewComment().Find(id)
if err != nil {
c.JsonResult(1, "评论不存在")
}
doc, err := models.NewDocument().Find(m.DocumentId)
if err != nil {
c.JsonResult(1, "文章不存在")
}
// 判断是否有权限删除
bookRole, _ := models.NewRelationship().FindForRoleId(doc.BookId, c.Member.MemberId)
if m.CanDelete(c.Member.MemberId, bookRole) {
err := m.Delete()
if err != nil {
c.JsonResult(1, "删除错误")
} else {
c.JsonResult(0, "ok")
}
} else {
c.JsonResult(1, "没有权限删除")
}
}
}

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

@ -240,6 +240,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

@ -33,6 +33,8 @@ type Comment struct {
ParentId int `orm:"column(parent_id);type(int);default(0)" json:"parent_id"`
AgreeCount int `orm:"column(agree_count);type(int);default(0)" json:"agree_count"`
AgainstCount int `orm:"column(against_count);type(int);default(0)" json:"against_count"`
Index int `orm:"-" json:"index"`
ShowDel int `orm:"-" json:"show_del"`
}
// TableName 获取对应数据库表名.
@ -52,14 +54,41 @@ func (m *Comment) TableNameWithPrefix() string {
func NewComment() *Comment {
return &Comment{}
}
func (m *Comment) Find(id int) (*Comment, error) {
if id <= 0 {
return m, ErrInvalidParameter
}
o := orm.NewOrm()
err := o.Read(m)
return m, err
// 是否有权限删除
func (m *Comment) CanDelete(user_memberid int, user_bookrole conf.BookRole) bool {
return user_memberid == m.MemberId || user_bookrole == conf.BookFounder || user_bookrole == conf.BookAdmin
}
// 根据文档id查询文档评论
func (m *Comment) QueryCommentByDocumentId(doc_id, page, pagesize int, member *Member) (comments []Comment, count int64, ret_page int) {
doc, err := NewDocument().Find(doc_id)
if err != nil {
return
}
o := orm.NewOrm()
count, _ = o.QueryTable(m.TableNameWithPrefix()).Filter("document_id", doc_id).Count()
if -1 == page { // 请求最后一页
var total int = int(count)
if total % pagesize == 0 {
page = total / pagesize
} else {
page = total / pagesize + 1
}
}
offset := (page - 1) * pagesize
ret_page = page
o.QueryTable(m.TableNameWithPrefix()).Filter("document_id", doc_id).OrderBy("comment_date").Offset(offset).Limit(pagesize).All(&comments)
bookRole, _ := NewRelationship().FindForRoleId(doc.BookId, member.MemberId)
for i := 0; i < len(comments); i++ {
comments[i].Index = (i + 1) + (page - 1) * pagesize
if comments[i].CanDelete(member.MemberId, bookRole) {
comments[i].ShowDel = 1
}
}
return
}
func (m *Comment) Update(cols ...string) error {
@ -135,3 +164,18 @@ func (m *Comment) Insert() error {
return err
}
// 删除一条评论
func (m *Comment) Delete() error {
o := orm.NewOrm()
_, err := o.Delete(m)
return err
}
func (m *Comment) Find(id int, cols ...string) (*Comment, error) {
o := orm.NewOrm()
if err := o.QueryTable(m.TableNameWithPrefix()).Filter("comment_id", id).One(m, cols...); err != nil {
return m, err
}
return m, nil
}

View File

@ -205,6 +205,7 @@ func init() {
web.Router("/attach_files/:key/:attach_id", &controllers.DocumentController{}, "get:DownloadAttachment")
web.Router("/comment/create", &controllers.CommentController{}, "post:Create")
web.Router("/comment/delete", &controllers.CommentController{}, "post:Delete")
web.Router("/comment/lists", &controllers.CommentController{}, "get:Lists")
web.Router("/comment/index", &controllers.CommentController{}, "*:Index")

File diff suppressed because one or more lines are too long

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,104 @@ 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 pageClicked($page, $docid) {
$.ajax({
url : "/comment/lists?page=" + $page + "&docid=" + $docid,
type : "GET",
success : function ($res) {
console.log($res.data);
loadComment($res.data.page, $res.data.doc_id);
},
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\">";
if (c[i].show_del == 1) html += "<span class=\"operate toggle\">";
else html += "<span class=\"operate\">";
html += "<span class=\"number\">" + c[i].index + "#</span>";
if (c[i].show_del == 1) html += "<i class=\"delete e-delete glyphicon glyphicon-remove\" style=\"color:red\" onclick=\"onDelComment(" + c[i].comment_id + ")\"></i>";
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){
pageClicked(page, $docid);
}
});
} else {
$("#page").find("li").remove();
}
}
// 删除评论
function onDelComment($id) {
console.log($id);
$.ajax({
url : "/comment/delete",
data : {"id": $id},
type : "POST",
success : function ($res) {
if ($res.errcode == 0) {
layer.msg("删除成功");
$("div[data-id=" + $id + "]").remove();
} else {
layer.msg($res.message);
}
},
error : function () {
layer.msg("删除失败");
}
});
}
// 重新渲染页面
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
@ -53,7 +150,7 @@ function loadDocument($url, $id, $callback) {
$.ajax({
url : $url,
type : "GET",
beforeSend : function (xhr) {
beforeSend : function () {
var data = events.data($id);
if(data) {
if (typeof $callback === "function") {
@ -61,11 +158,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});
@ -75,29 +168,19 @@ function loadDocument($url, $id, $callback) {
NProgress.start();
},
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;
success : function ($res) {
if ($res.errcode === 0) {
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.data($id, $res.data);
events.trigger('article.open', { $url : $url, $id : $id });
} else if (res.errcode === 6000) {
} else if ($res.errcode === 6000) {
window.location.href = "/";
} else {
layer.msg("加载失败");
@ -129,9 +212,6 @@ function initHighlighting() {
}
}
$(function () {
$(".view-backtop").on("click", function () {
$('.manual-right').animate({ scrollTop: '0px' }, 200);
@ -287,4 +367,25 @@ $(function () {
console.log($param);
}
};
// 提交评论
$("#commentForm").ajaxForm({
beforeSubmit : function () {
$("#btnSubmitComment").button("loading");
},
success : function (res) {
if(res.errcode === 0){
layer.msg("保存成功");
}else{
layer.msg("保存失败");
}
$("#btnSubmitComment").button("reset");
$("#commentContent").val("");
pageClicked(-1, res.data.doc_id); // -1 表示请求最后一页
},
error : function () {
layer.msg("服务错误");
$("#btnSubmitComment").button("reset");
}
});
});

View File

@ -132,3 +132,29 @@ func (p *Pagination) getLang() string {
}
return ulang
}
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

@ -96,6 +96,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>{{i18n $.Lang "blog.access_pass"}}</label>