feat: show message list

This commit is contained in:
lbaf23 2021-08-14 13:11:29 +08:00
parent 36506b8e94
commit 9b1daab60b
10 changed files with 217 additions and 74 deletions

View File

@ -3,7 +3,6 @@ package controllers
import (
"OpenPBL/models"
"OpenPBL/util"
"fmt"
"github.com/astaxie/beego"
"github.com/casdoor/casdoor-go-sdk/auth"
)
@ -64,8 +63,6 @@ func (m *MessageController) GetUserMessages() {
var rows int64
messages, rows, err = models.GetMessages(uid, orderType, t, r, from, size)
fmt.Println(err)
if err != nil {
m.Data["json"] = MessagesResponse{
Code: 400,

View File

@ -4,8 +4,10 @@ import (
"OpenPBL/models"
"OpenPBL/util"
"encoding/json"
"fmt"
"github.com/astaxie/beego"
"github.com/casdoor/casdoor-go-sdk/auth"
"time"
)
// StudentController
@ -69,6 +71,19 @@ func (u *StudentController) LearnProject() {
Code: 200,
Msg: "加入成功",
}
project, err := models.GetProjectById(pid)
if err == nil {
content := fmt.Sprintf("成功加入课程 \"%v\" ", project.ProjectTitle)
CreateMessage(&models.Message{
ReceiverId: uid,
MessageType: "info",
MessageTitle: "加入课程",
Content: content,
ReadMessage: false,
CreateAt: time.Time{},
})
}
u.Data["json"] = resp
u.ServeJSON()
}
@ -112,6 +127,20 @@ func (u *StudentController) ExitProject() {
Code: 200,
Msg: "退出成功",
}
project, err := models.GetProjectById(pid)
if err == nil {
content := fmt.Sprintf("成功退出课程 \"%v\" ", project.ProjectTitle)
CreateMessage(&models.Message{
ReceiverId: uid,
MessageType: "info",
MessageTitle: "退出课程",
Content: content,
ReadMessage: false,
CreateAt: time.Time{},
})
}
u.Data["json"] = resp
u.ServeJSON()
}

View File

@ -14,7 +14,7 @@ type Message struct {
MessageTitle string `json:"messageTitle" xorm:"text"`
Content string `json:"content" xorm:"longtext"`
Read bool `json:"read" xorm:"default false index"`
ReadMessage bool `json:"readMessage" xorm:"default false index"`
CreateAt time.Time `json:"createAt" xorm:"created"`
}
@ -36,47 +36,43 @@ func (m *Message) Delete() (err error) {
func ReadMessage(messageId int64, uid string) (err error) {
_, err = (&Message{}).GetEngine().
ID(messageId).
MustCols("read_message").
Update(&Message{
Id: messageId,
ReceiverId: uid,
Read: true,
ReadMessage: true,
})
return
}
func ReadAllMessage(uid string) (err error) {
_, err = (&Message{}).GetEngine().
Where("receiver_id = ?", uid).
MustCols("read_message").
Update(&Message{
ReceiverId: uid,
Read: true,
ReadMessage: true,
})
return
}
func GetMessages(uid string, orderType string, messageType string, read string, from int, size int) (m []Message, rows int64, err error) {
func GetMessages(uid string, orderType string, messageType string, readType string, from int, size int) (m []Message, rows int64, err error) {
s := (&Message{}).GetEngine().
Where("receiver_id = ?", uid)
s2 := (&Message{}).GetEngine().
Where("receiver_id = ?", uid)
if read == "read" {
s = s.Where("read = true")
s2 = s2.Where("read = true")
} else if read == "unread" {
s = s.Where("read = false")
s2 = s2.Where("read = false")
if readType == "read" {
s = s.Where("read_message = true")
s2 = s2.Where("read_message = true")
} else if readType == "unread" {
s = s.Where("read_message = false")
s2 = s2.Where("read_message = false")
}
if messageType == "error" || messageType == "info" || messageType == "warn" {
s = s.Where("message_type = ?", messageType)
s2 = s2.Where("message_type = ?", messageType)
}
rows, err = s2.Count()
rows, err = s2.Count(&Message{})
if orderType == "asc" {
s = s.Asc("create_at")
} else {
s = s.Desc("create_at")
}
err = s.Limit(size, from).Find(&m)
err = s.Desc("create_at").Limit(size, from).Find(&m)
return
}

View File

@ -67,6 +67,17 @@ func (f *Favourite) GetEngine() *xorm.Session {
return adapter.Engine.Table(f)
}
func GetProjectById(pid int64) (project Project, err error) {
var b bool
b, err = (&Project{}).GetEngine().
ID(pid).
Get(&project)
if !b {
err = errors.New("404")
}
return
}
func GetProjectByPidForTeacher(pid int64, uid string) (pd ProjectDetail, err error) {
var p Project
c, err := (&Project{}).GetEngine().

View File

@ -1,41 +1,10 @@
import React, {useState} from "react";
import React from "react";
import MessageList from "../component/MessageList";
import MessageApi from "../../../api/MessageApi"
function AllMessage() {
const [messages, setMessages] = useState([])
const [loading, setLoading] = useState(false)
const [total, setTotal] = useState(0)
const updateMessageList = (from, size) => {
setLoading(true)
const query = {
readType: 'all',
messageType: 'all',
from: from,
size: size,
orderType: 'desc'
}
MessageApi.getUserMessages(query)
.then(res=>{
setLoading(false)
if (res.data.code === 200) {
setMessages(res.data.messages)
setTotal(res.data.count)
}
})
.catch(e=>{console.log(e)})
}
return (
<div>
<MessageList
loading={loading}
total={total}
updateMessageList={updateMessageList}
messages={messages}
/>
<MessageList readType="all"/>
</div>
)
}

View File

@ -1,9 +1,10 @@
import React from "react";
import MessageList from "../component/MessageList";
function ReadMessage() {
return (
<div>
read
<MessageList readType="read"/>
</div>
)
}

View File

@ -1,9 +1,10 @@
import React from "react";
import MessageList from "../component/MessageList";
function UnreadMessage() {
return (
<div>
unread
<MessageList readType="unread"/>
</div>
)
}

View File

@ -1,27 +1,111 @@
import React, {useEffect, useState} from "react";
import {Button, Pagination, Table} from "antd";
import {Button, Pagination, Popconfirm, Table} from "antd";
import {DeleteOutlined} from "@ant-design/icons"
import util from "../../component/Util"
import MessageApi from "../../../api/MessageApi";
function MessageList(obj) {
const [page, setPage] = useState(1)
const [pageSize, setPageSize] = useState(10)
const [messages, setMessages] = useState([])
const [loading, setLoading] = useState(false)
const [btLoading, setBtLoading] = useState(false)
const [total, setTotal] = useState(0)
useEffect(()=>{
obj.updateMessageList(page - 1, pageSize);
updateMessageList((page-1)*pageSize, pageSize);
}, [])
const updateMessageList = (from, size) => {
setLoading(true)
const query = {
readType: obj.readType,
messageType: 'all',
from: from,
size: size,
orderType: 'desc'
}
MessageApi.getUserMessages(query)
.then(res=>{
setLoading(false)
if (res.data.code === 200) {
setMessages(res.data.messages)
setTotal(res.data.count)
}
})
.catch(e=>{console.log(e)})
}
const changePage = p => {
setPage(p)
obj.updateMessageList((p-1)*pageSize, pageSize)
updateMessageList((p-1)*pageSize, pageSize)
}
const deleteMessage = item => {
setLoading(true)
MessageApi.deleteMessage(item)
.then(res=>{
setLoading(false)
if (res.data.code === 200) {
updateMessageList((page-1)*pageSize, pageSize)
}
})
.catch(e=>{console.log(e)})
}
const setReadMessage = (expanded, record) => {
if (expanded && !record.readMessage) {
MessageApi.readMessage(record)
.then(res => {
if (res.data.code === 200) {
updateMessageList((page - 1) * pageSize, pageSize)
}
})
.catch(e => {
console.log(e)
})
}
}
const setReadAll = () => {
setBtLoading(true)
MessageApi.readAllMessage()
.then(res=>{
setBtLoading(false)
if (res.data.code === 200) {
updateMessageList((page - 1) * pageSize, pageSize)
}
})
.catch(e=>{console.log(e)})
}
return (
<div>
{obj.readType === "all" || obj.readType === "unread" ?
<div style={{float: 'right', padding: '20px'}}>
<Button onClick={setReadAll} loading={btLoading}>全部设为已读</Button>
</div>
: null
}
<Table
loading={obj.loading}
dataSource={obj.messages}
loading={loading}
rowKey="id"
dataSource={messages}
columns={[
{
title: '状态',
dataIndex: 'readMessage',
key: 'readMessage',
render: (text, item, index) =>(
<>
{!text ?
<span style={{color: 'green'}}>未读</span>
:
<span style={{color: 'gray'}}>已读</span>
}
</>
)
},
{
title: '标题',
dataIndex: 'messageTitle',
@ -49,25 +133,38 @@ function MessageList(obj) {
</>
)
},
{
title: '内容',
dataIndex: 'content',
key: 'content'
},
{
title: '操作',
dataIndex: 'active',
key: 'active',
dataIndex: 'action',
key: 'action',
render: (text, item, index) => (
<>
<Button>未读</Button>
<Popconfirm title="确定删除消息?" onConfirm={e=>deleteMessage(item)}>
<Button shape="circle" type="text" icon={<DeleteOutlined />}/>
</Popconfirm>
</>
)
}
]}
expandable={{
expandedRowRender: record => <p style={{ margin: 10 }}>{record.content}</p>,
rowExpandable: record => true,
onExpand: setReadMessage
}}
pagination={false}
/>
<Pagination
total={obj.total}
showTotal={t => `${obj.total}条消息`}
total={total}
showTotal={t => `${total}条消息`}
current={page}
onChange={changePage}
onShowSizeChange={()=>obj.updateMessageList(page-1, pageSize)}
onShowSizeChange={()=>updateMessageList(page-1, pageSize)}
style={{margin: '20px', textAlign: 'right'}}
/>
</div>

View File

@ -46,7 +46,10 @@ class ProjectInfo extends React.PureComponent {
teacher: {},
menu: menu,
lastLearn: {},
favBtLoading: false
favBtLoading: false,
learnBtLoading: false,
exitBtLoading: false,
closeBtLoading: false
};
}
@ -111,8 +114,14 @@ class ProjectInfo extends React.PureComponent {
}
}
learnProject = e => {
this.setState({
learnBtLoading: true
})
StudentApi.learnProject(this.state.pid)
.then((res) => {
this.setState({
learnBtLoading: true
})
if (res.data.code === 200) {
let p = Object.assign({}, this.state.project)
p.learning = true
@ -141,8 +150,14 @@ class ProjectInfo extends React.PureComponent {
})
}
closeProject = e => {
this.setState({
closeBtLoading: true
})
ProjectApi.closeProject(this.state.pid)
.then(res => {
this.setState({
closeBtLoading: false
})
if (res.data.code === 200) {
let p = Object.assign({}, this.state.project)
p.closed = true
@ -158,8 +173,14 @@ class ProjectInfo extends React.PureComponent {
})
}
exitProject = e => {
this.setState({
exitBtLoading: true
})
StudentApi.exitProject(this.state.pid)
.then(res => {
this.setState({
exitBtLoading: false
})
if (res.data.code === 200) {
if (this.props.account.tag === '老师') {
window.location.href = '/my-project/published'
@ -178,7 +199,7 @@ class ProjectInfo extends React.PureComponent {
ProjectApi.deleteProject(this.state.pid)
.then(res => {
if (res.data.code === 200) {
if (this.props.account === '老师') {
if (this.props.account.tag === '老师') {
window.location.href = '/my-project/published'
} else {
window.location.href = '/my-project/learning'
@ -233,9 +254,20 @@ class ProjectInfo extends React.PureComponent {
project: project
})
}
projectState = () => {
if (this.state.project.published) {
if (this.state.project.closed) {
return "( 已结束 )"
} else {
return "( 进行中 )"
}
} else {
return "( 编辑中 )"
}
}
render() {
const {project, teacher, menu, pid, lastLearn, favBtLoading} = this.state;
const {project, teacher, menu, pid, lastLearn, favBtLoading, learnBtLoading, exitBtLoading, closeBtLoading} = this.state;
const teacherBt = (
<div style={{float: 'right'}}>
@ -244,7 +276,6 @@ class ProjectInfo extends React.PureComponent {
title="确定结束项目?"
placement="topRight"
onConfirm={this.closeProject}
onCancel={this.cancelCloseProject}
okText="确定"
cancelText="取消"
>
@ -253,6 +284,7 @@ class ProjectInfo extends React.PureComponent {
size="middle"
danger
style={{margin: '5px'}}
loading={closeBtLoading}
>
结束项目
</Button>
@ -345,6 +377,7 @@ class ProjectInfo extends React.PureComponent {
shape="round"
size="middle"
style={{margin: '5px'}}
loading={exitBtLoading}
>退出项目
</Button>
</Popconfirm>
@ -356,6 +389,7 @@ class ProjectInfo extends React.PureComponent {
size="middle"
style={{margin: '5px'}}
onClick={this.learnProject}
loading={learnBtLoading}
>加入学习
</Button>
}
@ -400,7 +434,15 @@ class ProjectInfo extends React.PureComponent {
<Col flex="auto">
<p style={{fontSize: '20px'}}>
{project.projectTitle}&nbsp;&nbsp;
{project.created ? <Tag color="geekblue">我创建的项目</Tag> : null}
{project.created ?
<>
<Tag color="geekblue">我创建的项目</Tag>
<span style={{color: 'gray', fontSize: '15px'}}>
{this.projectState()}
</span>
</>
: null
}
{project.learning ? <Tag color="geekblue">正在学习</Tag> : null}
<span style={{float: 'right'}}>
{project.favourite ?

View File

@ -23,7 +23,7 @@ const logo = "https://cdn.open-ct.com/logo/openct_logo_1082x328.png"
class HeaderLayout extends React.Component {
state = {
current: 'home',
account: null,
account: undefined,
messageCount: 0,
menu: 'home'
}