feat: show message list
This commit is contained in:
parent
36506b8e94
commit
9b1daab60b
|
@ -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,
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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().
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import React from "react";
|
||||
import MessageList from "../component/MessageList";
|
||||
|
||||
function ReadMessage() {
|
||||
return (
|
||||
<div>
|
||||
read
|
||||
<MessageList readType="read"/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import React from "react";
|
||||
import MessageList from "../component/MessageList";
|
||||
|
||||
function UnreadMessage() {
|
||||
return (
|
||||
<div>
|
||||
unread
|
||||
<MessageList readType="unread"/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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}
|
||||
{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 ?
|
||||
|
|
|
@ -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'
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue