feat: add comment

This commit is contained in:
lbaf23 2021-08-14 16:48:41 +08:00
parent 10c91410cf
commit 357b865246
7 changed files with 270 additions and 102 deletions

111
controllers/comment.go Normal file
View File

@ -0,0 +1,111 @@
package controllers
import (
"OpenPBL/models"
"OpenPBL/util"
"time"
)
type CommentResponse struct {
Code int `json:"code"`
Comments []models.Comment `json:"comments"`
Count int64 `json:"count"`
}
// GetProjectComments
// @Title
// @Description
// @Success 200 {object} Response
// @Failure 401
// @Failure 400
// @router /:id/comments [get]
func (p *ProjectController) GetProjectComments() {
pid := p.GetString(":id")
from, err := p.GetInt("from")
if err != nil {
from = 0
}
size, err := p.GetInt("size")
if err != nil {
size = 10
}
isTeacher, err := p.GetBool("isTeacher")
if err != nil {
isTeacher = false
}
text := p.GetString("text")
comments, rows, err := models.GetProjectComments(pid, from, size, text, isTeacher)
if err != nil {
p.Data["json"] = CommentResponse{
Code: 400,
}
} else {
p.Data["json"] = CommentResponse{
Code: 200,
Comments: comments,
Count: rows,
}
}
p.ServeJSON()
}
// CreateProjectComment
// @Title
// @Description
// @Success 200 {object} Response
// @Failure 401
// @Failure 400
// @Failure 403
// @router /:id/comment [post]
func (p *ProjectController) CreateProjectComment() {
pid, err := p.GetInt64(":id")
user := p.GetSessionUser()
uid := util.GetUserId(user)
comment := &models.Comment{
ProjectId: pid,
UserId: uid,
UserAvatar: user.Avatar,
UserName: user.DisplayName,
IsTeacher: util.IsTeacher(user),
Content: p.GetString("content"),
CreateAt: time.Time{},
}
err = comment.Create()
if err != nil {
p.Data["json"] = Response{
Code: 400,
Msg: err.Error(),
}
} else {
p.Data["json"] = Response{
Code: 200,
Msg: "发布成功",
}
}
p.ServeJSON()
}
// DeleteProjectComment
// @Title
// @Description
// @Success 200 {object} Response
// @Failure 401
// @Failure 400
// @router /:id/comment/:commentId/delete [post]
func (p *ProjectController) DeleteProjectComment() {
cid, err := p.GetInt64(":commentId")
err = (&models.Comment{Id: cid}).Delete()
if err != nil {
p.Data["json"] = Response{
Code: 400,
Msg: err.Error(),
}
} else {
p.Data["json"] = Response{
Code: 200,
Msg: "删除成功",
}
}
p.ServeJSON()
}

View File

@ -561,4 +561,4 @@ func (p *ProjectController) ViewProject() {
}
}
p.ServeJSON()
}
}

View File

@ -103,6 +103,7 @@ func (a *Adapter) createTable() {
new(ProjectSubject),
new(Message),
new(Comment),
)
if err != nil {
fmt.Println(err)

View File

@ -1,25 +1,16 @@
package models
import "time"
import (
"time"
"xorm.io/xorm"
)
type Comment struct {
Id int64 `json:"id" xorm:"not null pk autoincr"`
ProjectId int64 `json:"projectId" xorm:"not null index"`
UserId int64 `json:"userId" xorm:"not null index"`
IsTeacher bool `json:"isTeacher" xorm:"not null index default false"`
Content string `json:"content" xorm:"text"`
CreateAt time.Time `json:"createAt" xorm:"created"`
}
type CommentReply struct {
Id int64 `json:"id" xorm:"not null pk autoincr"`
CommentId int64 `json:"commentId" xorm:"not null index"`
UserId int64 `json:"userId" xorm:"not null index"`
UserId string `json:"userId" xorm:"not null index"`
UserAvatar string `json:"userAvatar" xorm:"not null"`
UserName string `json:"userName" xorm:"not null"`
IsTeacher bool `json:"isTeacher" xorm:"not null index default false"`
Content string `json:"content" xorm:"text"`
@ -27,3 +18,33 @@ type CommentReply struct {
CreateAt time.Time `json:"createAt" xorm:"created"`
}
func (c *Comment) GetEngine() *xorm.Session {
return adapter.Engine.Table(c)
}
func (c *Comment) Create() (err error) {
_, err = c.GetEngine().Insert(c)
return
}
func (c *Comment) Delete() (err error) {
_, err = c.GetEngine().Delete(c)
return
}
func GetProjectComments(pid string, from int, size int, text string, teacher bool) (comments []Comment, rows int64, err error) {
s := (&Comment{}).GetEngine().Where("project_id = ?", pid)
s2 := (&Comment{}).GetEngine().Where("project_id = ?", pid)
if teacher {
s = s.Where("is_teacher = true")
s2 = s2.Where("is_teacher = true")
}
if text != "" {
s = s.Where("content like %?%", text)
s2 = s2.Where("content like %?%", text)
}
s = s.Desc("create_at").Limit(size, from)
rows, err = s2.Count(&Comment{})
err = s.Find(&comments)
return
}

27
web/src/api/CommentApi.js Normal file
View File

@ -0,0 +1,27 @@
import request from "./request";
import qs from 'qs'
const CommentApi = {
getProjectComments(pid, q) {
return request({
url: `/project/${pid}/comments`,
method: 'get',
params: q
})
},
createComment(pid, data) {
return request({
url: `/project/${pid}/comment`,
method: 'post',
data: qs.stringify(data)
})
},
deleteComment(pid, cid) {
return request({
url: `/project/${pid}/comment/${cid}/delete`,
method: 'post',
})
}
}
export default CommentApi

View File

@ -1,94 +1,91 @@
import React, {createElement, useEffect, useState} from 'react';
import {DislikeOutlined, LikeOutlined} from '@ant-design/icons';
import {Avatar, Button, Comment, Form, Input, Pagination, Tooltip} from 'antd';
import React, {useEffect, useState} from 'react';
import {Avatar, Button, Comment, Form, Input, Pagination, message, Tooltip, Popconfirm, Switch} from 'antd';
import {DeleteOutlined} from "@ant-design/icons"
import QueueAnim from 'rc-queue-anim';
const commentData = [
{
avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',
author: 'aaaa',
content: '评论内容',
date: '2021-6-6',
likes: 1,
dislikes: 0
},
{
avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',
author: 'aaaa',
content: '评论内容',
date: '2021-6-6',
likes: 0,
dislikes: 1
},
{
avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',
author: 'aaaa',
content: '评论内容',
date: '2021-6-6',
likes: 1,
dislikes: 0
},
{
avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',
author: 'aaaa',
content: '评论内容',
date: '2021-6-6',
likes: 0,
dislikes: 0
},
{
avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',
author: 'aaaa',
content: '评论内容',
date: '2021-6-6',
likes: 0,
dislikes: 0
},
];
import CommentApi from "../../../../api/CommentApi"
import util from "../../../component/Util"
const {TextArea} = Input;
function like(item) {
console.log(item);
}
function dislike(item) {
console.log(item);
}
function ProjectComment(obj) {
const [project, setProject] = useState({});
const [commentList, setCommentList] = useState([]);
const [actions, setActions] = useState([]);
const [text, setText] = useState([])
const [isTeacher, setIsTeacher] = useState(false)
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(10)
const [total, setTotal] = useState(0);
const [value, setValue] = useState('');
const [submitting, setSubmitting] = useState(false);
const updateCommentList = (p, size) => {
// TODO axios.get comment list
console.log(p, size);
setCommentList(commentData);
setTotal(100);
const updateCommentList = (p, size, isTeacher) => {
let query = {
from: (p-1)*size,
size: size,
text: '',
isTeacher: isTeacher,
}
CommentApi.getProjectComments(obj.project.id, query)
.then(res=>{
if (res.data.code === 200) {
if (res.data.comments !== null) {
setCommentList(res.data.comments)
setTotal(res.data.count)
}
}
})
.catch(e=>{console.log(e)})
setPage(p);
};
useEffect(() => {
setProject(obj.project);
updateCommentList(1, 10);
updateCommentList(1, pageSize, isTeacher);
}, []);
const onSubmit = () => {
console.log(value);
if (value === "") {
message.warn("请输入留言内容")
return
}
setSubmitting(true);
setTimeout(() => {
setSubmitting(false);
setValue('');
}, 500);
let c = {
content: value,
projectId: obj.project.id,
}
CommentApi.createComment(obj.project.id, c)
.then(res=>{
setSubmitting(false);
if (res.data.code === 200) {
message.success(res.data.msg)
updateCommentList(page, pageSize, isTeacher)
setValue('');
} else {
message.error(res.data.msg)
}
})
.catch(e=>{console.log(e)})
};
const deleteComment = (item) => {
CommentApi.deleteComment(obj.project.id, item.id)
.then(res=>{
if (res.data.code === 200) {
message.success(res.data.msg)
updateCommentList(page, pageSize, isTeacher)
} else {
message.error(res.data.msg)
}
})
.catch(e=>{console.log(e)})
}
const onChange = (v) => {
setValue(v.target.value);
};
const onChangeSwitch = e => {
setIsTeacher(e)
updateCommentList(page, pageSize, e)
}
return (
<QueueAnim>
@ -101,37 +98,47 @@ function ProjectComment(obj) {
提交
</Button>
</Form.Item>
<Switch
checkedChildren="只看老师"
unCheckedChildren="所有"
defaultChecked={false}
onChange={onChangeSwitch}
value={isTeacher}
/>
{commentList.map((item, index) => (
<Comment
key={index.toString()}
actions={
[
<Tooltip key="comment-basic-like" title="Like">
<span onClick={e => like(item)}>
{createElement(LikeOutlined)}
<span className="comment-action">{item.likes}</span>
</span>
</Tooltip>,
<Tooltip key="comment-basic-dislike" title="Dislike">
<span onClick={e => dislike(item)}>
{React.createElement(DislikeOutlined)}
<span className="comment-action">{item.dislikes}</span>
</span>
</Tooltip>,
<span key="comment-list-reply-to-0">Reply to</span>,
<>
{item.isTeacher ?
<span key="0" style={{color: 'green'}}>老师</span>
:
<span key="0">学生</span>
}
</>,
<>
{obj.account.name === item.userId ?
<Popconfirm title="确定删除留言?" onConfirm={e=>deleteComment(item)}>
<Button type="text" shape="circle" icon={<DeleteOutlined />} />
</Popconfirm>
: null
}
</>
]
}
author={item.author}
author={item.userName}
avatar={
<Avatar
src={item.avatar}
alt={item.author}
src={item.userAvatar}
alt={item.userName}
/>
}
content={item.content}
datetime={
<Tooltip title={item.date}>
<span>{item.date}</span>
<Tooltip title={util.FilterTime(item.createAt)}>
<span>{util.FilterMoment(item.createAt)}</span>
</Tooltip>
}
/>

View File

@ -494,6 +494,7 @@ class ProjectInfo extends React.PureComponent {
>
<Menu.Item key="project-introduce">项目信息</Menu.Item>
<Menu.Item key="project-outline">项目大纲</Menu.Item>
<Menu.Item key="project-comment">留言沟通</Menu.Item>
<Menu.Item key="project-evaluation">评价方案</Menu.Item>
{project.created ? <Menu.Item key="student-admin">学生管理</Menu.Item>
@ -508,7 +509,7 @@ class ProjectInfo extends React.PureComponent {
>
{menu === 'project-introduce' ? <ProjectIntroduce project={project}/> : null}
{menu === 'project-outline' ? <ProjectOutline project={project}/> : null}
{menu === 'project-comment' ? <ProjectComment project={project}/> : null}
{menu === 'project-comment' ? <ProjectComment project={project} account={this.props.account}/> : null}
{menu === 'project-evaluation' ?
<ProjectEvaluation
project={project}