feat: add comment
This commit is contained in:
parent
10c91410cf
commit
357b865246
|
@ -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()
|
||||
}
|
|
@ -561,4 +561,4 @@ func (p *ProjectController) ViewProject() {
|
|||
}
|
||||
}
|
||||
p.ServeJSON()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,6 +103,7 @@ func (a *Adapter) createTable() {
|
|||
new(ProjectSubject),
|
||||
|
||||
new(Message),
|
||||
new(Comment),
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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>
|
||||
}
|
||||
/>
|
||||
|
|
|
@ -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}
|
||||
|
|
Loading…
Reference in New Issue