fix: bug modify (#12)

* fix: get server url

* refactor: fix ui

* feat: message list

* refactor: rename to web

* feat: support redis endpoint

* fix: redis session

* docs: update README

* fix: skip preflight check

* docs: update README
This commit is contained in:
lbaf23 2021-08-08 17:04:55 +08:00 committed by GitHub
parent 8e3c8a7d78
commit fb330b43f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 392 additions and 76 deletions

View File

@ -8,11 +8,11 @@ RUN go env -w CGO_ENABLED=0 GOPROXY=https://goproxy.io,direct GOOS=linux GOARCH=
ENV PATH=$PATH:/openpbl/node-v12.22.0-linux-x64/bin ENV PATH=$PATH:/openpbl/node-v12.22.0-linux-x64/bin
RUN npm install -g yarn RUN npm install -g yarn
COPY openpbl-landing/package.json /openpbl/openpbl-landing/package.json COPY web/package.json /openpbl/web/package.json
RUN cd openpbl-landing && yarn install RUN cd web && yarn install
COPY openpbl-landing /openpbl/openpbl-landing COPY web /openpbl/web
RUN cd openpbl-landing && yarn build && rm -rf node_modules RUN cd web && yarn build && rm -rf node_modules
COPY ./ /openpbl COPY ./ /openpbl
RUN cd /openpbl && go build main.go RUN cd /openpbl && go build main.go

View File

@ -9,8 +9,6 @@ System of PBL.
`web/.env` `web/.env`
```dotenv ```dotenv
REACT_APP_BASE_URL='http://localhost:5000/api'
REACT_APP_OSS_REGION='oss-cn-hangzhou' REACT_APP_OSS_REGION='oss-cn-hangzhou'
REACT_APP_OSS_ACCESSKEYID= REACT_APP_OSS_ACCESSKEYID=
REACT_APP_OSS_ACCESSKEYSECRET= REACT_APP_OSS_ACCESSKEYSECRET=
@ -23,6 +21,7 @@ REACT_APP_APP_NAME=
REACT_APP_CASDOOR_ORGANIZATION='openct' REACT_APP_CASDOOR_ORGANIZATION='openct'
GENERATE_SOURCEMAP=false GENERATE_SOURCEMAP=false
SKIP_PREFLIGHT_CHECK=true
``` ```
```bash ```bash
@ -56,6 +55,7 @@ driverName = mysql
dataSourceName = root:123@tcp(localhost:3306)/ dataSourceName = root:123@tcp(localhost:3306)/
dbName = openpbl_db dbName = openpbl_db
redisEndpoint =
jwtSecret = CasdoorSecret jwtSecret = CasdoorSecret
casdoorEndpoint = casdoorEndpoint =

View File

@ -11,6 +11,7 @@ driverName = mysql
dataSourceName = root:123@tcp(localhost:3306)/ dataSourceName = root:123@tcp(localhost:3306)/
dbName = openpbl_db dbName = openpbl_db
redisEndpoint =
jwtSecret = CasdoorSecret jwtSecret = CasdoorSecret
casdoorEndpoint = casdoorEndpoint =

View File

@ -3,6 +3,7 @@ package controllers
import ( import (
"OpenPBL/models" "OpenPBL/models"
"OpenPBL/util" "OpenPBL/util"
"fmt"
"github.com/astaxie/beego" "github.com/astaxie/beego"
"github.com/casdoor/casdoor-go-sdk/auth" "github.com/casdoor/casdoor-go-sdk/auth"
) )
@ -36,12 +37,14 @@ type MessagesResponse struct {
// GetUserMessages // GetUserMessages
// @Title // @Title
// @Description // @Description
// @Param type path string true "received sent" // @Param readType params string true "read unread all"
// @Param messageType params string true "info warn error all"
// @Param from params int false "" // @Param from params int false ""
// @Param size params int false "" // @Param size params int false ""
// @Param orderType params string false "desc asc"
// @Success 200 {object} MessagesResponse // @Success 200 {object} MessagesResponse
// @Failure 400 // @Failure 400
// @router /:type [get] // @router / [get]
func (m *MessageController) GetUserMessages() { func (m *MessageController) GetUserMessages() {
user := m.GetSessionUser() user := m.GetSessionUser()
var resp ProjectResponse var resp ProjectResponse
@ -62,16 +65,17 @@ func (m *MessageController) GetUserMessages() {
if err != nil { if err != nil {
size = 10 size = 10
} }
t := m.GetString(":type") orderType := m.GetString("orderType")
r := m.GetString("readType")
t := m.GetString("messageType")
uid := util.GetUserId(user) uid := util.GetUserId(user)
var messages []models.Message var messages []models.Message
var rows int64 var rows int64
if t == "received" { messages, rows, err = models.GetMessages(uid, orderType, t, r, from, size)
messages, rows, err = models.GetReceivedMessages(uid, "desc", from, size)
} else if t == "sent" { fmt.Println(err)
messages, rows, err = models.GetSentMessages(uid, "desc", from, size)
}
if err != nil { if err != nil {
m.Data["json"] = MessagesResponse{ m.Data["json"] = MessagesResponse{
Code: 400, Code: 400,
@ -85,3 +89,121 @@ func (m *MessageController) GetUserMessages() {
} }
m.ServeJSON() m.ServeJSON()
} }
// ReadUserMessage
// @Title
// @Description
// @Param messageId path string true ""
// @Success 200 {object} Response
// @Failure 400
// @router /:messageId/read [post]
func (m *MessageController) ReadUserMessage() {
user := m.GetSessionUser()
var resp ProjectResponse
if user == nil {
resp = ProjectResponse{
Code: 401,
Msg: "请先登录",
}
m.Data["json"] = resp
m.ServeJSON()
return
}
uid := util.GetUserId(user)
mid, err := m.GetInt64(":messageId")
err = models.ReadMessage(mid, uid)
if err != nil {
m.Data["json"] = Response{
Code: 400,
Msg: err.Error(),
}
} else {
m.Data["json"] = Response{
Code: 200,
}
}
m.ServeJSON()
}
// DeleteUserMessage
// @Title
// @Description
// @Param messageId path string true ""
// @Success 200 {object} Response
// @Failure 400
// @router /:messageId/delete [post]
func (m *MessageController) DeleteUserMessage() {
user := m.GetSessionUser()
var resp ProjectResponse
if user == nil {
resp = ProjectResponse{
Code: 401,
Msg: "请先登录",
}
m.Data["json"] = resp
m.ServeJSON()
return
}
uid := util.GetUserId(user)
mid, err := m.GetInt64(":messageId")
msg := models.Message{
Id: mid,
ReceiverId: uid,
}
err = msg.Delete()
if err != nil {
m.Data["json"] = Response{
Code: 400,
Msg: err.Error(),
}
} else {
m.Data["json"] = Response{
Code: 200,
}
}
m.ServeJSON()
}
// ReadAllUserMessage
// @Title
// @Description
// @Success 200 {object} Response
// @Failure 400
// @router /read-all [post]
func (m *MessageController) ReadAllUserMessage() {
user := m.GetSessionUser()
var resp ProjectResponse
if user == nil {
resp = ProjectResponse{
Code: 401,
Msg: "请先登录",
}
m.Data["json"] = resp
m.ServeJSON()
return
}
uid := util.GetUserId(user)
err := models.ReadAllMessage(uid)
if err != nil {
m.Data["json"] = Response{
Code: 400,
Msg: err.Error(),
}
} else {
m.Data["json"] = Response{
Code: 200,
}
}
m.ServeJSON()
}
func CreateMessage(msg *models.Message) bool {
err := msg.Create()
if err != nil {
return false
}
return true
}

View File

@ -16,4 +16,4 @@ services:
environment: environment:
MYSQL_ROOT_PASSWORD: root MYSQL_ROOT_PASSWORD: root
volumes: volumes:
- /usr/local/docker/openpbl-mysql:/var/lib/mysql - /usr/local/docker/mysql:/var/lib/mysql

1
go.sum
View File

@ -126,6 +126,7 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=

14
main.go
View File

@ -9,6 +9,7 @@ import (
"flag" "flag"
"github.com/astaxie/beego" "github.com/astaxie/beego"
"github.com/astaxie/beego/plugins/cors" "github.com/astaxie/beego/plugins/cors"
_ "github.com/astaxie/beego/session/redis"
"log" "log"
) )
@ -20,11 +21,11 @@ func main() {
var err error var err error
configPath := util.GetConfigFile(mode) configPath := util.GetConfigFile(mode)
err = beego.LoadAppConfig("ini", configPath) err = beego.LoadAppConfig("ini", configPath)
if err != nil { if err != nil {
panic(err) panic(err)
} }
log.Println("App start with runmode: " + mode) log.Println("App start with runmode: " + mode)
log.Println("Load config file: " + configPath)
models.InitAdapter() models.InitAdapter()
controllers.InitCasdoor() controllers.InitCasdoor()
@ -39,15 +40,20 @@ func main() {
beego.BConfig.WebConfig.DirectoryIndex = true beego.BConfig.WebConfig.DirectoryIndex = true
beego.BConfig.WebConfig.StaticDir["/swagger"] = "swagger" beego.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"
} }
beego.SetStaticPath("/static", "openpbl-landing/build/static") beego.SetStaticPath("/static", "web/build/static")
beego.BConfig.WebConfig.DirectoryIndex = true beego.BConfig.WebConfig.DirectoryIndex = true
beego.InsertFilter("/", beego.BeforeRouter, routers.TransparentStatic) beego.InsertFilter("/", beego.BeforeRouter, routers.TransparentStatic)
beego.InsertFilter("/*", beego.BeforeRouter, routers.TransparentStatic) beego.InsertFilter("/*", beego.BeforeRouter, routers.TransparentStatic)
beego.BConfig.WebConfig.Session.SessionName = "openct_session_id" beego.BConfig.WebConfig.Session.SessionName = "openpbl_session_id"
if beego.AppConfig.String("redisEndpoint") == "" {
beego.BConfig.WebConfig.Session.SessionProvider = "file" beego.BConfig.WebConfig.Session.SessionProvider = "file"
beego.BConfig.WebConfig.Session.SessionProviderConfig = "./tmp" beego.BConfig.WebConfig.Session.SessionProviderConfig = "./tmp"
beego.BConfig.WebConfig.Session.SessionGCMaxLifetime = 3600 * 24 * 365 } else {
beego.BConfig.WebConfig.Session.SessionProvider = "redis"
beego.BConfig.WebConfig.Session.SessionProviderConfig = beego.AppConfig.String("redisEndpoint")
}
beego.BConfig.WebConfig.Session.SessionGCMaxLifetime = 3600 * 24 * 30
beego.Run() beego.Run()
} }

View File

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

View File

@ -6,21 +6,17 @@ import (
) )
type Message struct { type Message struct {
Id int64 `json:"id" xorm:"not null pk"` Id int64 `json:"id" xorm:"not null pk autoincr"`
ReceiverId string `json:"receiverId" xorm:"not null index"` ReceiverId string `json:"receiverId" xorm:"index"`
SenderId string `json:"senderId" xorm:"index"` MessageType string `json:"messageType" xorm:"not null index"` // warn error info
SenderName string `json:"senderName"`
ProjectId int64 `json:"projectId" xorm:"index"` MessageTitle string `json:"messageTitle" xorm:"text"`
ProjectTitle string `json:"projectTitle"` Content string `json:"content" xorm:"longtext"`
MessageType string `json:"messageType" xorm:"not null index"` // remind message
Content string `json:"content" xorm:"text"`
Read bool `json:"read" xorm:"default false index"` Read bool `json:"read" xorm:"default false index"`
CreateAt time.Time `json:"CreateAt" xorm:"created"` CreateAt time.Time `json:"createAt" xorm:"created"`
} }
@ -37,34 +33,50 @@ func (m *Message) Delete() (err error) {
return return
} }
func ReadMessage(messageId int64) (err error) { func ReadMessage(messageId int64, uid string) (err error) {
_, err = (&Message{}).GetEngine(). _, err = (&Message{}).GetEngine().
ID(messageId). ID(messageId).
Update(&Message{ Update(&Message{
Id: messageId, Id: messageId,
ReceiverId: uid,
Read: true,
})
return
}
func ReadAllMessage(uid string) (err error) {
_, err = (&Message{}).GetEngine().
Update(&Message{
ReceiverId: uid,
Read: true, Read: true,
}) })
return return
} }
func GetReceivedMessages(uid string, orderType string, from int, size int) (m []Message, rows int64, err error) { func GetMessages(uid string, orderType string, messageType string, read string, from int, size int) (m []Message, rows int64, err error) {
err = (&Message{}).GetEngine(). s := (&Message{}).GetEngine().
Where("receiver_id = ?", uid). Where("receiver_id = ?", uid)
Desc("create_at"). s2 := (&Message{}).GetEngine().
Limit(size, from). Where("receiver_id = ?", uid)
Find(&m) if read == "read" {
rows, err = (&Message{}).GetEngine(). s = s.Where("read = true")
Count(&Message{ReceiverId: uid}) s2 = s2.Where("read = true")
return } else if read == "unread" {
s = s.Where("read = false")
s2 = s2.Where("read = false")
}
if messageType == "error" || messageType == "info" || messageType == "warn" {
s = s.Where("message_type = ?", messageType)
s2 = s2.Where("message_type = ?", messageType)
} }
func GetSentMessages(uid string, orderType string, from int, size int) (m []Message, rows int64, err error) { rows, err = s2.Count()
err = (&Message{}).GetEngine().
Where("sender_id = ?", uid). if orderType == "asc" {
Desc("create_at"). s = s.Asc("create_at")
Limit(size, from). } else {
Find(&m) s = s.Desc("create_at")
rows, err = (&Message{}).GetEngine(). }
Count(&Message{SenderId: uid})
err = s.Limit(size, from).Find(&m)
return return
} }

View File

@ -37,7 +37,7 @@ func init() {
beego.GlobalControllerRouter["OpenPBL/controllers:MessageController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:MessageController"], beego.GlobalControllerRouter["OpenPBL/controllers:MessageController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:MessageController"],
beego.ControllerComments{ beego.ControllerComments{
Method: "GetUserMessages", Method: "GetUserMessages",
Router: "/:type", Router: "/",
AllowHTTPMethods: []string{"get"}, AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(), MethodParams: param.Make(),
Filters: nil, Filters: nil,

View File

@ -13,7 +13,7 @@ func TransparentStatic(ctx *context.Context) {
return return
} }
path := "openpbl-landing/build" path := "web/build"
if urlPath == "/" { if urlPath == "/" {
path += "/index.html" path += "/index.html"
} else { } else {
@ -21,7 +21,7 @@ func TransparentStatic(ctx *context.Context) {
} }
if _, err := os.Stat(path); os.IsNotExist(err) { if _, err := os.Stat(path); os.IsNotExist(err) {
http.ServeFile(ctx.ResponseWriter, ctx.Request, "openpbl-landing/build/index.html") http.ServeFile(ctx.ResponseWriter, ctx.Request, "web/build/index.html")
} else { } else {
http.ServeFile(ctx.ResponseWriter, ctx.Request, path) http.ServeFile(ctx.ResponseWriter, ctx.Request, path)
} }

View File

@ -35,6 +35,10 @@ func init() {
beego.NSInclude( beego.NSInclude(
&controllers.StudentController{})), &controllers.StudentController{})),
beego.NSNamespace("/message",
beego.NSInclude(
&controllers.MessageController{})),
) )
beego.AddNamespace(ns) beego.AddNamespace(ns)
} }

View File

@ -1,5 +1,3 @@
REACT_APP_BASE_URL='http://localhost:5000/api'
REACT_APP_OSS_REGION='oss-cn-hangzhou' REACT_APP_OSS_REGION='oss-cn-hangzhou'
REACT_APP_OSS_ACCESSKEYID= REACT_APP_OSS_ACCESSKEYID=
REACT_APP_OSS_ACCESSKEYSECRET= REACT_APP_OSS_ACCESSKEYSECRET=
@ -12,3 +10,4 @@ REACT_APP_APP_NAME=
REACT_APP_CASDOOR_ORGANIZATION='openct' REACT_APP_CASDOOR_ORGANIZATION='openct'
GENERATE_SOURCEMAP=false GENERATE_SOURCEMAP=false
SKIP_PREFLIGHT_CHECK=true

View File

@ -1,5 +1,5 @@
{ {
"name": "openpbl-landing", "name": "web",
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {

33
web/src/api/MessageApi.js Normal file
View File

@ -0,0 +1,33 @@
import request from "./request";
import qs from 'qs'
const MessageApi = {
getUserMessages(query) {
return request({
url: `/message`,
method: 'get',
params: query
})
},
readMessage(m) {
return request({
url: `/message/${m.id}/read`,
method: 'post',
data: qs.stringify(m)
})
},
readAllMessage() {
return request({
url: `/message/read-all`,
method: 'post',
})
},
deleteMessage(m) {
return request({
url: `/message/${m.id}/delete`,
method: 'post',
})
}
}
export default MessageApi

View File

@ -1,8 +1,16 @@
import axios from 'axios' import axios from 'axios'
import {message} from 'antd' import {message} from 'antd'
function getServerUrl() {
const hostname = window.location.hostname
if (hostname === 'localhost') {
return `http://${hostname}:5000/api`
}
return '/api'
}
const request = axios.create({ const request = axios.create({
baseURL: process.env.REACT_APP_BASE_URL, baseURL: getServerUrl(),
timeout: 10000, timeout: 10000,
withCredentials: true withCredentials: true
}) })

View File

@ -1,9 +1,41 @@
import React from "react"; import React, {useState} from "react";
import MessageList from "../component/MessageList";
import MessageApi from "../../../api/MessageApi"
function AllMessage() { 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 ( return (
<div> <div>
all message <MessageList
loading={loading}
total={total}
updateMessageList={updateMessageList}
messages={messages}
/>
</div> </div>
) )
} }

View File

@ -0,0 +1,10 @@
import React from "react";
import MessageList from "../component/MessageList";
function Communication() {
return (
<>
</>
)
}
export default Communication

View File

@ -0,0 +1,77 @@
import React, {useEffect, useState} from "react";
import {Button, Pagination, Table} from "antd";
import util from "../../component/Util"
function MessageList(obj) {
const [page, setPage] = useState(1)
const [pageSize, setPageSize] = useState(10)
useEffect(()=>{
obj.updateMessageList(page - 1, pageSize);
}, [])
const changePage = p => {
setPage(p)
obj.updateMessageList((p-1)*pageSize, pageSize)
}
return (
<div>
<Table
loading={obj.loading}
dataSource={obj.messages}
columns={[
{
title: '标题',
dataIndex: 'messageTitle',
key: 'messageTitle'
},
{
title: '时间',
dataIndex: 'createAt',
key: 'createAt',
render: (text, item, index) => (
<>
{util.FilterMoment(text)}
</>
)
},
{
title: '类型',
dataIndex: 'messageType',
key: 'messageType',
render: (text, item, index) => (
<>
{text === 'warning' ? '警告': null}
{text === 'info' ? '信息': null}
{text === 'error' ? '错误': null}
</>
)
},
{
title: '操作',
dataIndex: 'active',
key: 'active',
render: (text, item, index) => (
<>
<Button>未读</Button>
</>
)
}
]}
pagination={false}
/>
<Pagination
total={obj.total}
showTotal={t => `${obj.total}条消息`}
current={page}
onChange={changePage}
onShowSizeChange={()=>obj.updateMessageList(page-1, pageSize)}
style={{margin: '20px', textAlign: 'right'}}
/>
</div>
)
}
export default MessageList

View File

@ -1,12 +1,12 @@
import React from "react"; import React from "react";
import DocumentTitle from "react-document-title"; import DocumentTitle from "react-document-title";
import {Affix, Layout, Menu} from "antd"; import {Affix, Layout, Menu} from "antd";
import {Link, Redirect, Route, Switch} from "react-router-dom"; import {Link, Redirect, Route, Switch} from "react-router-dom";
import AllMessage from "./AllMessage"; import AllMessage from "./AllMessage";
import UnreadMessage from "./UnreadMessage"; import UnreadMessage from "./UnreadMessage";
import ReadMessage from "./ReadMessage"; import ReadMessage from "./ReadMessage";
import Communication from "./Communication";
class Message extends React.Component { class Message extends React.Component {
state = { state = {
@ -32,12 +32,20 @@ class Message extends React.Component {
未读消息 未读消息
</Link> </Link>
</Menu.Item> </Menu.Item>
<Menu.Item key="read-message">已读消息</Menu.Item> <Menu.Item key="read-message">
<Menu.Item key="remind">留言沟通</Menu.Item> <Link to="/message/read">
已读消息
</Link>
</Menu.Item>
<Menu.Item key="remind">
<Link to="/message/communication">
留言沟通
</Link>
</Menu.Item>
</Menu> </Menu>
</Layout.Sider> </Layout.Sider>
</Affix> </Affix>
<Layout.Content style={{backgroundColor: 'white'}}> <Layout.Content style={{backgroundColor: 'white', marginLeft: '10px'}}>
<Switch> <Switch>
<Route exact path="/message" render={() => ( <Route exact path="/message" render={() => (
<Redirect to="/message/all"/> <Redirect to="/message/all"/>
@ -45,6 +53,7 @@ class Message extends React.Component {
<Route exact path="/message/all" component={AllMessage}/> <Route exact path="/message/all" component={AllMessage}/>
<Route exact path="/message/unread" component={UnreadMessage}/> <Route exact path="/message/unread" component={UnreadMessage}/>
<Route exact path="/message/read" component={ReadMessage}/> <Route exact path="/message/read" component={ReadMessage}/>
<Route exact path="/message/communication" component={Communication}/>
</Switch> </Switch>
</Layout.Content> </Layout.Content>
</Layout> </Layout>

View File

@ -6,7 +6,7 @@ import {Link} from 'react-router-dom'
import ChapterApi from "../../../../../api/ChapterApi" import ChapterApi from "../../../../../api/ChapterApi"
import SectionApi from "../../../../../api/SectionApi" import SectionApi from "../../../../../api/SectionApi"
import util from "../../../component/Util" import util from "../../../../component/Util"
const {SubMenu} = Menu; const {SubMenu} = Menu;

View File

@ -4,7 +4,7 @@ import {Button, Collapse, Divider, InputNumber, List, message, Progress, Tooltip
import TaskApi from "../../../../api/TaskApi"; import TaskApi from "../../../../api/TaskApi";
import ChapterApi from "../../../../api/ChapterApi"; import ChapterApi from "../../../../api/ChapterApi";
import TaskCard from "../../PreviewProject/component/TaskCard"; import TaskCard from "../../PreviewProject/component/TaskCard";
import util from "../../component/Util" import util from "../../../component/Util"
import SubmitApi from "../../../../api/SubmitApi"; import SubmitApi from "../../../../api/SubmitApi";
function StudentEvidence(obj) { function StudentEvidence(obj) {

View File

@ -31,7 +31,7 @@ class MyProject extends React.PureComponent {
const {type} = this.state const {type} = this.state
return ( return (
<DocumentTitle title="My Project"> <DocumentTitle title="My Project">
<Layout> <Layout style={{margin: '20px'}}>
<Affix offsetTop={0}> <Affix offsetTop={0}>
<Layout.Sider <Layout.Sider
breakpoint="lg" breakpoint="lg"
@ -95,7 +95,7 @@ class MyProject extends React.PureComponent {
} }
</Layout.Sider> </Layout.Sider>
</Affix> </Affix>
<Layout.Content> <Layout.Content style={{marginLeft: '10px'}}>
{type === 'teacher' ? {type === 'teacher' ?
<Switch> <Switch>
<Route exact path="/my-project" render={() => ( <Route exact path="/my-project" render={() => (

View File

@ -6,7 +6,7 @@ import SectionApi from "../../../api/SectionApi";
import "../CreateProject/Section/component/section-edit.less" import "../CreateProject/Section/component/section-edit.less"
import "./preview.less" import "./preview.less"
import TaskApi from "../../../api/TaskApi"; import TaskApi from "../../../api/TaskApi";
import util from "../component/Util" import util from "../../component/Util"
import StudentApi from "../../../api/StudentApi"; import StudentApi from "../../../api/StudentApi";
import TaskCard from "./component/TaskCard"; import TaskCard from "./component/TaskCard";

View File

@ -11,7 +11,7 @@ import TaskApi from "../../../../api/TaskApi";
import ProjectApi from "../../../../api/ProjectApi"; import ProjectApi from "../../../../api/ProjectApi";
import ChapterApi from "../../../../api/ChapterApi"; import ChapterApi from "../../../../api/ChapterApi";
import SectionApi from "../../../../api/SectionApi"; import SectionApi from "../../../../api/SectionApi";
import util from "../../component/Util" import util from "../../../component/Util"
import "./index.less" import "./index.less"
const {SubMenu} = Menu const {SubMenu} = Menu

View File

@ -3,7 +3,7 @@ import {Menu, message, Progress} from 'antd'
import QueueAnim from 'rc-queue-anim'; import QueueAnim from 'rc-queue-anim';
import ChapterApi from "../../../../api/ChapterApi"; import ChapterApi from "../../../../api/ChapterApi";
import util from "../../component/Util" import util from "../../../component/Util"
const {SubMenu} = Menu; const {SubMenu} = Menu;

View File

@ -4,7 +4,7 @@ import {Avatar, Button, message, Pagination, Popconfirm, Table} from "antd";
import {DeleteOutlined} from "@ant-design/icons" import {DeleteOutlined} from "@ant-design/icons"
import ProjectApi from "../../../../api/ProjectApi"; import ProjectApi from "../../../../api/ProjectApi";
import util from "../../component/Util" import util from "../../../component/Util"
import {Link} from "react-router-dom"; import {Link} from "react-router-dom";
function StudentAdmin(obj) { function StudentAdmin(obj) {

View File

@ -14,7 +14,7 @@ import StudentApi from "../../../api/StudentApi";
import StudentAdmin from "./component/StudentAdmin"; import StudentAdmin from "./component/StudentAdmin";
import {getUser} from "../../User/Auth/Auth"; import {getUser} from "../../User/Auth/Auth";
import {DeleteOutlined} from "@ant-design/icons"; import {DeleteOutlined} from "@ant-design/icons";
import util from "../component/Util" import util from "../../component/Util"
import StudentEvidence from "../Evidence/component/StudentEvidence"; import StudentEvidence from "../Evidence/component/StudentEvidence";
class ProjectInfo extends React.PureComponent { class ProjectInfo extends React.PureComponent {

View File

@ -6,7 +6,7 @@ import {Link} from 'react-router-dom';
import './project-list.less'; import './project-list.less';
import ProjectListApi from '../../../api/ProjectListApi' import ProjectListApi from '../../../api/ProjectListApi'
import util from './Util' import util from '../../component/Util'
const {Meta} = Card; const {Meta} = Card;
const {Search} = Input; const {Search} = Input;