refactor: remove redux (#20)

* feat: add store

* feat: add connect

* feat: add loading

* fix: remember menu item

* fix: page size

* refactor: delete api login check

* refactor: set msg err.Error()

* refactor: use function to judge user type

* feat: add global filter

* fix: check project teacher

* refactor: get images from cdn

* refactor: get icon from cdn

* refactor: modify header bar

* refactor: get images from cdn

* fix: fix redux connect

* fix: fix logo size

* feat: add favourite

* fix: favourite menu item

* feat: add loading

* fix: use tag to distinguish user types

* refactor: remove redux

* refactor: ignore commentsRouter*.go
This commit is contained in:
lbaf23 2021-08-13 10:56:22 +08:00 committed by GitHub
parent ae3ac9139f
commit 36506b8e94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 499 additions and 975 deletions

20
.gitignore vendored
View File

@ -1,13 +1,10 @@
# Dependency directories (remove the comment below to include it)
# vendor/
### Go template
# Binaries for programs and plugins # Binaries for programs and plugins
*.exe *.exe
*.exe~ *.exe~
*.dll *.dll
*.so *.so
*.dylib *.dylib
*.swp
# Test binary, built with `go test -c` # Test binary, built with `go test -c`
*.test *.test
@ -18,13 +15,16 @@
# Dependency directories (remove the comment below to include it) # Dependency directories (remove the comment below to include it)
# vendor/ # vendor/
*.zip .idea/
*.iml
tmp/
tmpFiles/
*.tmp *.tmp
logs/
.idea files/
.vscode lastupdate.tmp
routers/commentsRouter*.go
tmp
### Config file ### Config file

View File

@ -2,6 +2,7 @@ package controllers
import ( import (
"OpenPBL/models" "OpenPBL/models"
"OpenPBL/util"
"strconv" "strconv"
) )
@ -21,21 +22,13 @@ type ChaptersResponse struct {
// @router /:id/chapters [get] // @router /:id/chapters [get]
func (p *ProjectController) GetProjectChapters() { func (p *ProjectController) GetProjectChapters() {
user := p.GetSessionUser() user := p.GetSessionUser()
if user == nil {
p.Data["json"] = ChaptersResponse{
Code: 401,
Msg: "请先登录",
}
p.ServeJSON()
return
}
uid := "" uid := ""
show := false show := false
if user.Tag == "student" { if util.IsStudent(user) {
uid = user.Name uid = user.Name
show = true show = true
} }
if user.Tag == "teacher" { if util.IsTeacher(user) {
uid = p.GetString("studentId") uid = p.GetString("studentId")
if uid != "" { if uid != "" {
show = true show = true

View File

@ -47,16 +47,6 @@ type MessagesResponse struct {
// @router / [get] // @router / [get]
func (m *MessageController) GetUserMessages() { func (m *MessageController) GetUserMessages() {
user := m.GetSessionUser() user := m.GetSessionUser()
var resp ProjectResponse
if user == nil {
resp = ProjectResponse{
Code: 401,
Msg: "请先登录",
}
m.Data["json"] = resp
m.ServeJSON()
return
}
from, err := m.GetInt("from") from, err := m.GetInt("from")
if err != nil { if err != nil {
from = 0 from = 0
@ -99,16 +89,6 @@ func (m *MessageController) GetUserMessages() {
// @router /:messageId/read [post] // @router /:messageId/read [post]
func (m *MessageController) ReadUserMessage() { func (m *MessageController) ReadUserMessage() {
user := m.GetSessionUser() 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) uid := util.GetUserId(user)
mid, err := m.GetInt64(":messageId") mid, err := m.GetInt64(":messageId")
err = models.ReadMessage(mid, uid) err = models.ReadMessage(mid, uid)
@ -134,16 +114,6 @@ func (m *MessageController) ReadUserMessage() {
// @router /:messageId/delete [post] // @router /:messageId/delete [post]
func (m *MessageController) DeleteUserMessage() { func (m *MessageController) DeleteUserMessage() {
user := m.GetSessionUser() 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) uid := util.GetUserId(user)
mid, err := m.GetInt64(":messageId") mid, err := m.GetInt64(":messageId")
msg := models.Message{ msg := models.Message{
@ -172,16 +142,6 @@ func (m *MessageController) DeleteUserMessage() {
// @router /read-all [post] // @router /read-all [post]
func (m *MessageController) ReadAllUserMessage() { func (m *MessageController) ReadAllUserMessage() {
user := m.GetSessionUser() 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) uid := util.GetUserId(user)
err := models.ReadAllMessage(uid) err := models.ReadAllMessage(uid)
if err != nil { if err != nil {

View File

@ -44,38 +44,26 @@ type ProjectResponse struct {
// @Failure 400 // @Failure 400
// @router /:id [get] // @router /:id [get]
func (p *ProjectController) GetProjectDetail() { func (p *ProjectController) GetProjectDetail() {
pid := p.GetString(":id") pid, err := p.GetInt64(":id")
user := p.GetSessionUser() user := p.GetSessionUser()
var resp ProjectResponse
if user == nil {
resp = ProjectResponse{
Code: 401,
Msg: "请先登录",
}
p.Data["json"] = resp
p.ServeJSON()
return
}
uid := util.GetUserId(user) uid := util.GetUserId(user)
var err error
var project models.ProjectDetail var project models.ProjectDetail
if user.Tag == "student" { if util.IsStudent(user) {
project, err = models.GetProjectByPidForStudent(pid, uid) project, err = models.GetProjectByPidForStudent(pid, uid)
} else if user.Tag == "teacher" { } else if util.IsTeacher(user) {
project, err = models.GetProjectByPidForTeacher(pid) project, err = models.GetProjectByPidForTeacher(pid, uid)
} }
if err != nil { if err != nil {
resp = ProjectResponse{ p.Data["json"] = ProjectResponse{
Code: 400, Code: 400,
Msg: err.Error(), Msg: err.Error(),
} }
} else { } else {
resp = ProjectResponse{ p.Data["json"] = ProjectResponse{
Code: 200, Code: 200,
Project: project, Project: project,
} }
} }
p.Data["json"] = resp
p.ServeJSON() p.ServeJSON()
} }
@ -90,16 +78,7 @@ func (p *ProjectController) GetProjectDetail() {
func (p *ProjectController) CreateProject() { func (p *ProjectController) CreateProject() {
user := p.GetSessionUser() user := p.GetSessionUser()
var resp Response var resp Response
if user == nil { if !util.IsTeacher(user) {
resp = Response{
Code: 401,
Msg: "请先登录",
}
p.Data["json"] = resp
p.ServeJSON()
return
}
if user.Tag != "teacher" {
resp = Response{ resp = Response{
Code: 403, Code: 403,
Msg: "非法用户", Msg: "非法用户",
@ -140,16 +119,7 @@ func (p *ProjectController) CreateProject() {
func (p *ProjectController) UpdateProject() { func (p *ProjectController) UpdateProject() {
user := p.GetSessionUser() user := p.GetSessionUser()
var resp Response var resp Response
if user == nil { if !util.IsTeacher(user) {
resp = Response{
Code: 401,
Msg: "请先登录",
}
p.Data["json"] = resp
p.ServeJSON()
return
}
if user.Tag != "teacher" {
resp = Response{ resp = Response{
Code: 403, Code: 403,
Msg: "非法用户", Msg: "非法用户",
@ -207,16 +177,7 @@ func (p *ProjectController) UpdateProject() {
func (p *ProjectController) UpdateProjectWeight() { func (p *ProjectController) UpdateProjectWeight() {
user := p.GetSessionUser() user := p.GetSessionUser()
var resp Response var resp Response
if user == nil { if !util.IsTeacher(user) {
resp = Response{
Code: 401,
Msg: "请先登录",
}
p.Data["json"] = resp
p.ServeJSON()
return
}
if user.Tag != "teacher" {
resp = Response{ resp = Response{
Code: 403, Code: 403,
Msg: "非法用户", Msg: "非法用户",
@ -274,16 +235,7 @@ func (u *ProjectController) PublishProject() {
pid, err := u.GetInt64(":id") pid, err := u.GetInt64(":id")
var resp Response var resp Response
user := u.GetSessionUser() user := u.GetSessionUser()
if user == nil { if !util.IsTeacher(user) {
resp = Response{
Code: 401,
Msg: "请先登录",
}
u.Data["json"] = resp
u.ServeJSON()
return
}
if user.Tag != "teacher" {
resp = Response{ resp = Response{
Code: 403, Code: 403,
Msg: "非法的用户", Msg: "非法的用户",
@ -327,16 +279,7 @@ func (u *ProjectController) CloseProject() {
pid, err := u.GetInt64(":id") pid, err := u.GetInt64(":id")
var resp Response var resp Response
user := u.GetSessionUser() user := u.GetSessionUser()
if user == nil { if !util.IsTeacher(user) {
resp = Response{
Code: 401,
Msg: "请先登录",
}
u.Data["json"] = resp
u.ServeJSON()
return
}
if user.Tag != "teacher" {
resp = Response{ resp = Response{
Code: 403, Code: 403,
Msg: "非法的用户", Msg: "非法的用户",
@ -380,16 +323,7 @@ func (u *ProjectController) DeleteProject() {
pid, err := u.GetInt64(":id") pid, err := u.GetInt64(":id")
var resp Response var resp Response
user := u.GetSessionUser() user := u.GetSessionUser()
if user == nil { if !util.IsTeacher(user) {
resp = Response{
Code: 401,
Msg: "请先登录",
}
u.Data["json"] = resp
u.ServeJSON()
return
}
if user.Tag != "teacher" {
resp = Response{ resp = Response{
Code: 403, Code: 403,
Msg: "非法的用户", Msg: "非法的用户",
@ -429,16 +363,6 @@ func (u *ProjectController) RemoveStudent() {
pid, err := u.GetInt64(":projectId") pid, err := u.GetInt64(":projectId")
sid := u.GetString(":studentId") sid := u.GetString(":studentId")
var resp Response var resp Response
user := u.GetSessionUser()
if user == nil {
resp = Response{
Code: 401,
Msg: "请先登录",
}
u.Data["json"] = resp
u.ServeJSON()
return
}
l := &models.LearnProject{ l := &models.LearnProject{
StudentId: sid, StudentId: sid,
ProjectId: pid, ProjectId: pid,
@ -536,3 +460,52 @@ func (p *ProjectController) GetProjectStudents() {
} }
p.ServeJSON() p.ServeJSON()
} }
// AddFavouriteProject
// @Title
// @Description
// @Param projectId path string true ""
// @Success 200 {object} Response
// @Failure 401
// @router /:projectId/favourite/add [post]
func (p *ProjectController) AddFavouriteProject() {
pid, err := p.GetInt64(":projectId")
uid := util.GetUserId(p.GetSessionUser())
err = models.AddFavourite(uid, pid)
if err != nil {
p.Data["json"] = Response{
Code: 400,
Msg: err.Error(),
}
} else {
p.Data["json"] = Response{
Code: 200,
Msg: "收藏成功",
}
}
p.ServeJSON()
}
// RemoveFavouriteProject
// @Title
// @Description
// @Param projectId path string true ""
// @Success 200 {object} Response
// @Failure 401
// @router /:projectId/favourite/remove [post]
func (p *ProjectController) RemoveFavouriteProject() {
pid, err := p.GetInt64(":projectId")
uid := util.GetUserId(p.GetSessionUser())
err = models.RemoveFavourite(uid, pid)
if err != nil {
p.Data["json"] = Response{
Code: 400,
Msg: err.Error(),
}
} else {
p.Data["json"] = Response{
Code: 200,
Msg: "移除成功",
}
}
p.ServeJSON()
}

View File

@ -71,31 +71,23 @@ func (pl *ProjectListController) GetUserProjectList() {
text := pl.GetString("text") text := pl.GetString("text")
user := pl.GetSessionUser() user := pl.GetSessionUser()
var data ProjectList
if user == nil {
data = ProjectList{
Code: 401,
Msg: "请先登录",
}
pl.Data["json"] = data
pl.ServeJSON()
return
}
uid := util.GetUserId(user) uid := util.GetUserId(user)
var data ProjectList
var projects []models.ProjectDetail var projects []models.ProjectDetail
var count int64 var count int64
if user.Tag == "student" { if util.IsStudent(user) {
if t == "learning" { if t == "learning" {
projects, count, err = models.GetMyProjectListBySid(uid, from, size, subject, skill, text, orderBy, orderType, true) projects, count, err = models.GetMyProjectListBySid(uid, from, size, subject, skill, text, orderBy, orderType, true)
} else if t == "finished" { } else if t == "finished" {
projects, count, err = models.GetMyProjectListBySid(uid, from, size, subject, skill, text, orderBy, orderType, false) projects, count, err = models.GetMyProjectListBySid(uid, from, size, subject, skill, text, orderBy, orderType, false)
} else if t == "public" { } else if t == "public" {
projects, count, err = models.GetPublicProjectListForStudent(uid, from, size, subject, skill, text, orderBy, orderType) projects, count, err = models.GetPublicProjectListForStudent(uid, from, size, subject, skill, text, orderBy, orderType, false)
} else if t == "favourite" {
projects, count, err = models.GetPublicProjectListForStudent(uid, from, size, subject, skill, text, orderBy, orderType, true)
} }
} else if user.Tag == "teacher" { } else if util.IsTeacher(user) {
if t == "editing" { if t == "editing" {
projects, count, err = models.GetMyProjectListByTid(uid, from, size, subject, skill, text, orderBy, orderType, false, false) projects, count, err = models.GetMyProjectListByTid(uid, from, size, subject, skill, text, orderBy, orderType, false, false)
} else if t == "published" { } else if t == "published" {
@ -103,7 +95,9 @@ func (pl *ProjectListController) GetUserProjectList() {
} else if t == "finished" { } else if t == "finished" {
projects, count, err = models.GetMyProjectListByTid(uid, from, size, subject, skill, text, orderBy, orderType, true, true) projects, count, err = models.GetMyProjectListByTid(uid, from, size, subject, skill, text, orderBy, orderType, true, true)
} else if t == "public" { } else if t == "public" {
projects, count, err = models.GetPublicProjectListForTeacher(uid, from, size, subject, skill, text, orderBy, orderType) projects, count, err = models.GetPublicProjectListForTeacher(uid, from, size, subject, skill, text, orderBy, orderType, false)
} else if t == "favourite" {
projects, count, err = models.GetPublicProjectListForTeacher(uid, from, size, subject, skill, text, orderBy, orderType, true)
} }
} }
data = ProjectList{ data = ProjectList{

View File

@ -123,7 +123,7 @@ func (p *ProjectController) UpdateChapterSection() {
if err != nil { if err != nil {
p.Data["json"] = Response{ p.Data["json"] = Response{
Code: 400, Code: 400,
Msg: "更新失败", Msg: err.Error(),
} }
} else { } else {
p.Data["json"] = Response{ p.Data["json"] = Response{
@ -158,7 +158,7 @@ func (p *ProjectController) DeleteChapterSection() {
if err != nil { if err != nil {
p.Data["json"] = Response{ p.Data["json"] = Response{
Code: 400, Code: 400,
Msg: "删除失败", Msg: err.Error(),
} }
} else { } else {
p.Data["json"] = Response{ p.Data["json"] = Response{

View File

@ -39,16 +39,7 @@ func (u *StudentController) LearnProject() {
pid, err := u.GetInt64(":projectId") pid, err := u.GetInt64(":projectId")
var resp Response var resp Response
user := u.GetSessionUser() user := u.GetSessionUser()
if user == nil { if !util.IsStudent(user) {
resp = Response{
Code: 401,
Msg: "请先登录",
}
u.Data["json"] = resp
u.ServeJSON()
return
}
if user.Tag != "student" {
resp = Response{ resp = Response{
Code: 403, Code: 403,
Msg: "非法的用户", Msg: "非法的用户",
@ -94,16 +85,7 @@ func (u *StudentController) ExitProject() {
pid, err := u.GetInt64(":projectId") pid, err := u.GetInt64(":projectId")
var resp Response var resp Response
user := u.GetSessionUser() user := u.GetSessionUser()
if user == nil { if !util.IsStudent(user) {
resp = Response{
Code: 401,
Msg: "请先登录",
}
u.Data["json"] = resp
u.ServeJSON()
return
}
if user.Tag != "student" {
resp = Response{ resp = Response{
Code: 403, Code: 403,
Msg: "非法的用户", Msg: "非法的用户",
@ -167,16 +149,7 @@ func (u *StudentController) FinishedProject() {
func (u *StudentController) GetLearnSection() { func (u *StudentController) GetLearnSection() {
var resp Response var resp Response
user := u.GetSessionUser() user := u.GetSessionUser()
if user == nil { if !util.IsStudent(user) {
resp = Response{
Code: 401,
Msg: "请先登录",
}
u.Data["json"] = resp
u.ServeJSON()
return
}
if user.Tag != "student" {
resp = Response{ resp = Response{
Code: 403, Code: 403,
Msg: "非法的用户", Msg: "非法的用户",
@ -213,16 +186,7 @@ func (u *StudentController) GetLearnSection() {
func (u *StudentController) UpdateLearnSection() { func (u *StudentController) UpdateLearnSection() {
var resp Response var resp Response
user := u.GetSessionUser() user := u.GetSessionUser()
if user == nil { if !util.IsStudent(user) {
resp = Response{
Code: 401,
Msg: "请先登录",
}
u.Data["json"] = resp
u.ServeJSON()
return
}
if user.Tag != "student" {
resp = Response{ resp = Response{
Code: 403, Code: 403,
Msg: "非法的用户", Msg: "非法的用户",
@ -265,16 +229,7 @@ func (u *StudentController) UpdateLearnSection() {
func (u *StudentController) GetLastLearnSection() { func (u *StudentController) GetLastLearnSection() {
var resp Response var resp Response
user := u.GetSessionUser() user := u.GetSessionUser()
if user == nil { if !util.IsStudent(user) {
resp = Response{
Code: 401,
Msg: "请先登录",
}
u.Data["json"] = resp
u.ServeJSON()
return
}
if user.Tag != "student" {
resp = Response{ resp = Response{
Code: 200, Code: 200,
Msg: "", Msg: "",

View File

@ -18,16 +18,7 @@ import (
func (p *ProjectController) CreateSubmit() { func (p *ProjectController) CreateSubmit() {
var resp Response var resp Response
user := p.GetSessionUser() user := p.GetSessionUser()
if user == nil { if !util.IsStudent(user) {
resp = Response{
Code: 401,
Msg: "请先登录",
}
p.Data["json"] = resp
p.ServeJSON()
return
}
if user.Tag != "student" {
resp = Response{ resp = Response{
Code: 403, Code: 403,
Msg: "非法用户", Msg: "非法用户",
@ -85,19 +76,9 @@ func (p *ProjectController) CreateSubmit() {
// @Failure 403 body is empty // @Failure 403 body is empty
// @router /:projectId/task/:taskId/submit/:submitId [post] // @router /:projectId/task/:taskId/submit/:submitId [post]
func (p *ProjectController) UpdateSubmit() { func (p *ProjectController) UpdateSubmit() {
var resp Response
user := p.GetSessionUser() user := p.GetSessionUser()
if user == nil {
resp = Response{
Code: 401,
Msg: "请先登录",
}
p.Data["json"] = resp
p.ServeJSON()
return
}
var uid string var uid string
if user.Tag == "student" { if util.IsStudent(user) {
uid = util.GetUserId(user) uid = util.GetUserId(user)
} }
tid, err := p.GetInt64(":taskId") tid, err := p.GetInt64(":taskId")
@ -120,7 +101,7 @@ func (p *ProjectController) UpdateSubmit() {
Scored: scored, Scored: scored,
} }
var c = make([]models.Choice, 0) var c = make([]models.Choice, 0)
if user.Tag == "student" && f.SubmitType == "survey" { if util.IsStudent(user) && f.SubmitType == "survey" {
err = json.Unmarshal([]byte(p.GetString("choices")), &c) err = json.Unmarshal([]byte(p.GetString("choices")), &c)
} }
err = f.Update(c) err = f.Update(c)

View File

@ -44,7 +44,7 @@ func (p *ProjectController) CreateSurvey() {
if err != nil { if err != nil {
p.Data["json"] = Response{ p.Data["json"] = Response{
Code: 400, Code: 400,
Msg: "创建失败", Msg: err.Error(),
} }
} else { } else {
p.Data["json"] = Response{ p.Data["json"] = Response{
@ -79,7 +79,7 @@ func (p *ProjectController) UpdateSurvey() {
if err != nil { if err != nil {
p.Data["json"] = Response{ p.Data["json"] = Response{
Code: 400, Code: 400,
Msg: "更新失败", Msg: err.Error(),
} }
} else { } else {
p.Data["json"] = Response{ p.Data["json"] = Response{
@ -114,7 +114,7 @@ func (p *ProjectController) CreateQuestion() {
if err != nil { if err != nil {
p.Data["json"] = Response{ p.Data["json"] = Response{
Code: 400, Code: 400,
Msg: "创建失败", Msg: err.Error(),
} }
} else { } else {
p.Data["json"] = Response{ p.Data["json"] = Response{
@ -151,7 +151,7 @@ func (p *ProjectController) UpdateQuestion() {
if err != nil { if err != nil {
p.Data["json"] = Response{ p.Data["json"] = Response{
Code: 400, Code: 400,
Msg: "更新失败", Msg: err.Error(),
} }
} else { } else {
p.Data["json"] = Response{ p.Data["json"] = Response{
@ -177,6 +177,7 @@ func (p *ProjectController) ExchangeQuestion() {
if err != nil { if err != nil {
p.Data["json"] = Response{ p.Data["json"] = Response{
Code: 400, Code: 400,
Msg: err.Error(),
} }
} else { } else {
p.Data["json"] = Response{ p.Data["json"] = Response{
@ -203,7 +204,7 @@ func (p *ProjectController) DeleteQuestion() {
if err != nil { if err != nil {
p.Data["json"] = Response{ p.Data["json"] = Response{
Code: 400, Code: 400,
Msg: "参数非法", Msg: err.Error(),
} }
p.ServeJSON() p.ServeJSON()
return return
@ -212,7 +213,7 @@ func (p *ProjectController) DeleteQuestion() {
if err != nil { if err != nil {
p.Data["json"] = Response{ p.Data["json"] = Response{
Code: 400, Code: 400,
Msg: "删除失败", Msg: err.Error(),
} }
} else { } else {
p.Data["json"] = Response{ p.Data["json"] = Response{

View File

@ -23,26 +23,14 @@ type TaskResponse struct {
// @Failure 400 // @Failure 400
// @router /:projectId/section/:sectionId/tasks [get] // @router /:projectId/section/:sectionId/tasks [get]
func (p *ProjectController) GetSectionTasksDetail() { func (p *ProjectController) GetSectionTasksDetail() {
var resp TaskResponse
sid := p.GetString(":sectionId") sid := p.GetString(":sectionId")
var learning bool var learning bool
user := p.GetSessionUser() user := p.GetSessionUser()
if user == nil {
resp = TaskResponse{
Response: Response{
Code: 401,
Msg: "请先登录",
},
}
p.Data["json"] = resp
p.ServeJSON()
return
}
showCount := false showCount := false
if user.Tag != "student" { if !util.IsStudent(user) {
learning = false learning = false
} }
if user.Tag == "teacher" { if util.IsTeacher(user) {
showCount = true showCount = true
} }
uid := util.GetUserId(user) uid := util.GetUserId(user)
@ -80,16 +68,6 @@ func (p *ProjectController) GetSectionTasksDetail() {
// @Failure 400 // @Failure 400
// @router /:projectId/tasks [get] // @router /:projectId/tasks [get]
func (p *ProjectController) GetProjectTasks() { func (p *ProjectController) GetProjectTasks() {
user := p.GetSessionUser()
if user == nil {
p.Data["json"] = Response{
Code: 401,
Msg: "请先登录",
}
p.ServeJSON()
return
}
pid := p.GetString(":projectId") pid := p.GetString(":projectId")
tasks, err := models.GetProjectTasks(pid) tasks, err := models.GetProjectTasks(pid)
if err != nil { if err != nil {
@ -114,37 +92,22 @@ func (p *ProjectController) GetProjectTasks() {
// @Failure 400 // @Failure 400
// @router /:projectId/tasks-detail [get] // @router /:projectId/tasks-detail [get]
func (p *ProjectController) GetProjectTasksDetail() { func (p *ProjectController) GetProjectTasksDetail() {
var resp TaskResponse
var learning bool var learning bool
user := p.GetSessionUser() user := p.GetSessionUser()
if user == nil {
resp = TaskResponse{
Response: Response{
Code: 401,
Msg: "请先登录",
},
}
p.Data["json"] = resp
p.ServeJSON()
return
}
showSubmit := false showSubmit := false
teacherScore := false teacherScore := false
uid := util.GetUserId(user) uid := util.GetUserId(user)
editable := true editable := true
showCount := false showCount := false
pid := p.GetString(":projectId") pid := p.GetString(":projectId")
if util.IsTeacher(user) {
if user.Tag == "teacher" {
uid = p.GetString("studentId") uid = p.GetString("studentId")
showSubmit = true showSubmit = true
editable = false editable = false
teacherScore = true teacherScore = true
showCount = true showCount = true
} }
if user.Tag != "student" { if !util.IsStudent(user) {
learning = false learning = false
} else { } else {
learning = models.IsLearningProject(pid, uid) learning = models.IsLearningProject(pid, uid)
@ -209,7 +172,7 @@ func (p *ProjectController) CreateTask() {
if err != nil { if err != nil {
p.Data["json"] = Response{ p.Data["json"] = Response{
Code: 400, Code: 400,
Msg: "创建失败", Msg: err.Error(),
} }
} else { } else {
p.Data["json"] = Response{ p.Data["json"] = Response{
@ -251,7 +214,7 @@ func (p *ProjectController) UpdateTask() {
if err != nil { if err != nil {
p.Data["json"] = Response{ p.Data["json"] = Response{
Code: 400, Code: 400,
Msg: "更新失败", Msg: err.Error(),
} }
} else { } else {
p.Data["json"] = Response{ p.Data["json"] = Response{
@ -279,7 +242,7 @@ func (p *ProjectController) DeleteTask() {
if err != nil { if err != nil {
p.Data["json"] = Response{ p.Data["json"] = Response{
Code: 400, Code: 400,
Msg: "删除失败", Msg: err.Error(),
} }
} else { } else {
p.Data["json"] = Response{ p.Data["json"] = Response{
@ -305,6 +268,7 @@ func (p *ProjectController) ExchangeTask() {
if err != nil { if err != nil {
p.Data["json"] = Response{ p.Data["json"] = Response{
Code: 400, Code: 400,
Msg: err.Error(),
} }
} else { } else {
p.Data["json"] = Response{ p.Data["json"] = Response{

View File

@ -82,6 +82,7 @@ func (a *Adapter) close() {
func (a *Adapter) createTable() { func (a *Adapter) createTable() {
err := a.Engine.Sync2( err := a.Engine.Sync2(
new(Project), new(Project),
new(Favourite),
new(LearnProject), new(LearnProject),
new(LearnSection), new(LearnSection),

View File

@ -31,9 +31,17 @@ type Project struct {
LearnMinuteWeight int `json:"learnMinuteWeight" xorm:"default 100"` LearnMinuteWeight int `json:"learnMinuteWeight" xorm:"default 100"`
} }
type Favourite struct {
ProjectId int64 `json:"projectId" xorm:"not null pk"`
UserId string `json:"userId" xorm:"not null pk"`
CreateAt time.Time `json:"createAt" xorm:"created"`
}
type ProjectDetail struct { type ProjectDetail struct {
Project `xorm:"extends"` Project `xorm:"extends"`
Learning bool `json:"learning"` Learning bool `json:"learning"`
Created bool `json:"created"`
Favourite bool `json:"favourite"`
} }
type ProjectSkill struct { type ProjectSkill struct {
@ -55,15 +63,27 @@ func (p *ProjectSkill) GetEngine() *xorm.Session {
func (p *ProjectSubject) GetEngine() *xorm.Session { func (p *ProjectSubject) GetEngine() *xorm.Session {
return adapter.Engine.Table(p) return adapter.Engine.Table(p)
} }
func (f *Favourite) GetEngine() *xorm.Session {
return adapter.Engine.Table(f)
}
func GetProjectByPidForTeacher(pid string) (pd ProjectDetail, err error) { func GetProjectByPidForTeacher(pid int64, uid string) (pd ProjectDetail, err error) {
var p Project var p Project
c, err := (&Project{}).GetEngine(). c, err := (&Project{}).GetEngine().
ID(pid). ID(pid).
Get(&p) Get(&p)
favourite, _ := (&Favourite{}).GetEngine().
Exist(&Favourite{
ProjectId: pid,
UserId: uid,
})
created := uid == p.TeacherId
pd = ProjectDetail{ pd = ProjectDetail{
Project: p, Project: p,
Learning: false, Learning: false,
Created: created,
Favourite: favourite,
} }
if !c { if !c {
err = errors.New("404") err = errors.New("404")
@ -71,11 +91,17 @@ func GetProjectByPidForTeacher(pid string) (pd ProjectDetail, err error) {
return return
} }
func GetProjectByPidForStudent(pid string, uid string) (pd ProjectDetail, err error) { func GetProjectByPidForStudent(pid int64, uid string) (pd ProjectDetail, err error) {
c, err := (&Project{}).GetEngine(). c, err := (&Project{}).GetEngine().
Where("project.id = ?", pid). Where("project.id = ?", pid).
Join("LEFT OUTER", LearnProject{}, "project.id = learn_project.project_id and student_id = ?", uid). Join("LEFT OUTER", LearnProject{}, "project.id = learn_project.project_id and student_id = ?", uid).
Get(&pd) Get(&pd)
favourite, _ := (&Favourite{}).GetEngine().
Exist(&Favourite{
ProjectId: pid,
UserId: uid,
})
pd.Favourite = favourite
if !c { if !c {
err = errors.New("404") err = errors.New("404")
} }
@ -155,4 +181,21 @@ func UpdateClosed(p Project) (err error) {
Cols("closed", "closed_at"). Cols("closed", "closed_at").
Update(p) Update(p)
return return
}
func AddFavourite(uid string, pid int64) (err error) {
_, err = (&Favourite{}).GetEngine().Insert(Favourite{
ProjectId: pid,
UserId: uid,
CreateAt: time.Time{},
})
return
}
func RemoveFavourite(uid string, pid int64) (err error) {
_, err = (&Favourite{}).GetEngine().Delete(Favourite{
ProjectId: pid,
UserId: uid,
})
return
} }

View File

@ -38,23 +38,33 @@ func GetMyProjectListBySid(sid string, from int, size int,
} }
func GetPublicProjectListForStudent(sid string, from int, size int, func GetPublicProjectListForStudent(sid string, from int, size int,
subject string, skill string, text string, orderBy string, orderType string) (p []ProjectDetail, rows int64, err error) { subject string, skill string, text string, orderBy string, orderType string, favourite bool) (p []ProjectDetail, rows int64, err error) {
const baseSql = ` const baseSql = `
select %s from ( select %s from (
select * from project where project.published = true and project.closed = false select * from project where project.published = true and project.closed = false
%s %s %s %s %s %s %s
) as p1 left join learn_project on ( ) as p1 left join learn_project on (
p1.id = learn_project.project_id and learn_project.student_id = '%s' p1.id = learn_project.project_id and learn_project.student_id = '%s'
) )
` `
const pageSql = " order by p1.%s %s limit %d, %d " const pageSql = " order by p1.%s %s limit %d, %d "
e0 := ""
if favourite {
e0 = `
and exists (
select favourite.project_id from favourite where favourite.project_id = project.id and favourite.user_id = '%s'
)
`
e0 = fmt.Sprintf(e0, sid)
}
e1 := getSubjectExistSql(subject) e1 := getSubjectExistSql(subject)
e2 := getSkillExistSql(skill) e2 := getSkillExistSql(skill)
e3 := getTextSql(text) e3 := getTextSql(text)
sql1 := fmt.Sprintf(baseSql, "*", e1, e2, e3, sid) + sql1 := fmt.Sprintf(baseSql, "*", e0, e1, e2, e3, sid) +
fmt.Sprintf(pageSql, orderBy, orderType, from, size) fmt.Sprintf(pageSql, orderBy, orderType, from, size)
sql2 := fmt.Sprintf(baseSql, "count(*)", e1, e2, e3, sid) sql2 := fmt.Sprintf(baseSql, "count(*)", e0, e1, e2, e3, sid)
err = adapter.Engine. err = adapter.Engine.
SQL(sql1). SQL(sql1).
@ -95,16 +105,27 @@ func GetMyProjectListByTid(tid string, from int, size int,
} }
func GetPublicProjectListForTeacher(sid string, from int, size int, func GetPublicProjectListForTeacher(sid string, from int, size int,
subject string, skill string, text string, orderBy string, orderType string) (p []ProjectDetail, rows int64, err error) { subject string, skill string, text string, orderBy string, orderType string, favourite bool) (p []ProjectDetail, rows int64, err error) {
baseSql := "select %s from project where published = true and closed = false %s %s %s " baseSql := "select %s from project where published = true and closed = false %s %s %s %s "
pageSql := " order by %s %s limit %d, %d " pageSql := " order by %s %s limit %d, %d "
e0 := ""
if favourite {
e0 = `
and exists (
select favourite.project_id from favourite where favourite.project_id = project.id and favourite.user_id = '%s'
)
`
e0 = fmt.Sprintf(e0, sid)
}
e1 := getSubjectExistSql(subject) e1 := getSubjectExistSql(subject)
e2 := getSkillExistSql(skill) e2 := getSkillExistSql(skill)
e3 := getTextSql(text) e3 := getTextSql(text)
sql1 := fmt.Sprintf(baseSql, "*", e1, e2, e3) + sql1 := fmt.Sprintf(baseSql, "*", e0, e1, e2, e3) +
fmt.Sprintf(pageSql, orderBy, orderType, from, size) fmt.Sprintf(pageSql, orderBy, orderType, from, size)
sql2 := fmt.Sprintf(baseSql, "count(*)", e1, e2, e3) sql2 := fmt.Sprintf(baseSql, "count(*)", e0, e1, e2, e3)
err = adapter.Engine. err = adapter.Engine.
SQL(sql1). SQL(sql1).

View File

@ -1,514 +0,0 @@
package routers
import (
"github.com/astaxie/beego"
"github.com/astaxie/beego/context/param"
)
func init() {
beego.GlobalControllerRouter["OpenPBL/controllers:AuthController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:AuthController"],
beego.ControllerComments{
Method: "GetAccount",
Router: "/account",
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:AuthController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:AuthController"],
beego.ControllerComments{
Method: "Login",
Router: "/login",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:AuthController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:AuthController"],
beego.ControllerComments{
Method: "Logout",
Router: "/logout",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:HomeController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:HomeController"],
beego.ControllerComments{
Method: "GetLatestProjects",
Router: "/projects/latest",
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:MessageController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:MessageController"],
beego.ControllerComments{
Method: "GetUserMessages",
Router: "/",
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:MessageController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:MessageController"],
beego.ControllerComments{
Method: "DeleteUserMessage",
Router: "/:messageId/delete",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:MessageController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:MessageController"],
beego.ControllerComments{
Method: "ReadUserMessage",
Router: "/:messageId/read",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:MessageController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:MessageController"],
beego.ControllerComments{
Method: "ReadAllUserMessage",
Router: "/read-all",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "CreateProject",
Router: "/",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "GetProjectDetail",
Router: "/:id",
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "UpdateProject",
Router: "/:id",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "CreateProjectChapter",
Router: "/:id/chapter",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "GetProjectChapters",
Router: "/:id/chapters",
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "CloseProject",
Router: "/:id/close",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "DeleteProject",
Router: "/:id/delete",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "PublishProject",
Router: "/:id/publish",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "UpdateProjectWeight",
Router: "/:id/weight",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "UpdateProjectChapter",
Router: "/:projectId/chapter/:chapterId",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "DeleteProjectChapter",
Router: "/:projectId/chapter/:chapterId/delete",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "CreateChapterSection",
Router: "/:projectId/chapter/:chapterId/section",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "UpdateChapterSection",
Router: "/:projectId/chapter/:chapterId/section/:sectionId",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "DeleteChapterSection",
Router: "/:projectId/chapter/:chapterId/section/:sectionId/delete",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "GetChapterSections",
Router: "/:projectId/chapter/:chapterId/sections",
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "ExchangeChapterSection",
Router: "/:projectId/chapter/:chapterId/sections/exchange",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "ExchangeProjectChapter",
Router: "/:projectId/chapters/exchange",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "RemoveStudent",
Router: "/:projectId/remove/:studentId",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "GetSectionDetail",
Router: "/:projectId/section/:sectionId",
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "GetSectionTasksDetail",
Router: "/:projectId/section/:sectionId/tasks",
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "UpdateSectionsMinute",
Router: "/:projectId/sections-minute",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "GetProjectStudents",
Router: "/:projectId/students",
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "CreateTask",
Router: "/:projectId/task",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "UpdateTask",
Router: "/:projectId/task/:taskId",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "DeleteTask",
Router: "/:projectId/task/:taskId/delete",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "CreateSubmit",
Router: "/:projectId/task/:taskId/submit",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "UpdateSubmit",
Router: "/:projectId/task/:taskId/submit/:submitId",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "CreateSurvey",
Router: "/:projectId/task/:taskId/survey",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "GetSurveyDetailByTaskId",
Router: "/:projectId/task/:taskId/survey",
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "UpdateSurvey",
Router: "/:projectId/task/:taskId/survey/:sid",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "CreateQuestion",
Router: "/:projectId/task/:taskId/survey/:surveyId/question",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "UpdateQuestion",
Router: "/:projectId/task/:taskId/survey/:surveyId/question/:questionId",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "DeleteQuestion",
Router: "/:projectId/task/:taskId/survey/:surveyId/question/:questionId/delete",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "ExchangeQuestion",
Router: "/:projectId/task/:taskId/survey/:surveyId/questions/exchange",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "GetProjectTasks",
Router: "/:projectId/tasks",
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "GetProjectTasksDetail",
Router: "/:projectId/tasks-detail",
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "ExchangeTask",
Router: "/:projectId/tasks/exchange",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectListController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectListController"],
beego.ControllerComments{
Method: "GetUserProjectList",
Router: "/:projectType",
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ResourceController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ResourceController"],
beego.ControllerComments{
Method: "CreateResource",
Router: "/",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ResourceController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ResourceController"],
beego.ControllerComments{
Method: "GetResource",
Router: "/:id",
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ResourceController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ResourceController"],
beego.ControllerComments{
Method: "UpdateResource",
Router: "/:id",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ResourceController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ResourceController"],
beego.ControllerComments{
Method: "UpdateResourceContent",
Router: "/:id/content",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:StudentController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:StudentController"],
beego.ControllerComments{
Method: "ExitProject",
Router: "/exit/:projectId",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:StudentController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:StudentController"],
beego.ControllerComments{
Method: "FinishedProject",
Router: "/finished",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:StudentController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:StudentController"],
beego.ControllerComments{
Method: "GetLastLearnSection",
Router: "/last-learn/project/:projectId",
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:StudentController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:StudentController"],
beego.ControllerComments{
Method: "LearnProject",
Router: "/learn/:projectId",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:StudentController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:StudentController"],
beego.ControllerComments{
Method: "GetLearnSection",
Router: "/project/:projectId/section/:sectionId",
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:StudentController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:StudentController"],
beego.ControllerComments{
Method: "UpdateLearnSection",
Router: "/project/:projectId/section/:sectionId",
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
}

View File

@ -1,15 +1,34 @@
package routers package routers
import ( import (
"OpenPBL/controllers"
"github.com/astaxie/beego/context" "github.com/astaxie/beego/context"
"net/http" "net/http"
"os" "os"
"strings" "strings"
) )
func apiFilter(ctx *context.Context) {
urlPath := ctx.Request.URL.Path
if strings.HasPrefix(urlPath, "/api/project-list") ||
strings.HasPrefix(urlPath, "/api/project") ||
strings.HasPrefix(urlPath, "/api/message") ||
strings.HasPrefix(urlPath, "/api/resource") ||
strings.HasPrefix(urlPath, "/api/student") {
user := ctx.Input.Session("user")
if user == nil {
ctx.Output.JSON(controllers.Response{
Code: 401,
Msg: "请先登录",
}, true, false)
}
}
}
func TransparentStatic(ctx *context.Context) { func TransparentStatic(ctx *context.Context) {
urlPath := ctx.Request.URL.Path urlPath := ctx.Request.URL.Path
if strings.HasPrefix(urlPath, "/api") { if strings.HasPrefix(urlPath, "/api") {
apiFilter(ctx)
return return
} }

View File

@ -5,3 +5,10 @@ import "github.com/casdoor/casdoor-go-sdk/auth"
func GetUserId(claims *auth.Claims) (id string) { func GetUserId(claims *auth.Claims) (id string) {
return claims.Name return claims.Name
} }
func IsStudent(claims *auth.Claims) (b bool) {
return claims.Tag != "老师"
}
func IsTeacher(claims *auth.Claims) (b bool) {
return claims.Tag == "老师"
}

View File

@ -32,7 +32,6 @@
"react-github-button": "^0.1.11", "react-github-button": "^0.1.11",
"react-lz-editor": "^0.12.1", "react-lz-editor": "^0.12.1",
"react-pdf": "^5.3.2", "react-pdf": "^5.3.2",
"react-redux": "^7.2.4",
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-scripts": "4.0.3", "react-scripts": "4.0.3",
"serve": "^12.0.0", "serve": "^12.0.0",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -2,14 +2,14 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <link rel="icon" href="https://cdn.open-ct.com/static/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta <meta
name="description" name="description"
content="Web site created using create-react-app" content="Web site created using create-react-app"
/> />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <link rel="apple-touch-icon" href="https://cdn.open-ct.com/static/favicon.ico" />
<!-- <!--
manifest.json provides metadata used when your web app is installed on a manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -1,17 +1,16 @@
import { Route, BrowserRouter, Switch } from "react-router-dom"; import { Route, BrowserRouter, Switch } from "react-router-dom";
import './App.less'; import './App.less';
import AuthCallback from "./pages/User/Auth/AuthCallback"; import AuthCallback from "./pages/User/Auth/AuthCallback";
import HeaderLayout from "./pages/component/Layout/HeaderLayout"; import HeaderLayout from "./pages/component/Layout/HeaderLayout";
function App() { function App() {
return ( return (
<div className="App"> <div className="App">
<BrowserRouter> <BrowserRouter>
<Route path="/" component={HeaderLayout} /> <Route path="/" component={HeaderLayout} />
<Route exact path="/callback" component={AuthCallback} /> <Route exact path="/callback" component={AuthCallback} />
</BrowserRouter> </BrowserRouter>
</div> </div>
); );
} }

View File

@ -69,10 +69,22 @@ const ProjectApi = {
}, },
updateWeight(pid, data) { updateWeight(pid, data) {
return request({ return request({
url: `project/${pid}/weight`, url: `/project/${pid}/weight`,
method: 'post', method: 'post',
data: qs.stringify(data) data: qs.stringify(data)
}) })
},
addFavourite(pid) {
return request({
url: `/project/${pid}/favourite/add`,
method: 'post',
})
},
removeFavourite(pid) {
return request({
url: `/project/${pid}/favourite/remove`,
method: 'post',
})
} }
} }

View File

@ -14,17 +14,17 @@ class CarouselPBL extends React.Component {
super(props); super(props);
this.imgArray = [ this.imgArray = [
{ {
img: require('../../Project/PublicProject/static/image/pbl1.png').default, img: 'https://cdn.open-ct.com/task-resources//carousel-top-1.png',
title: '', title: '',
text: '', text: '',
}, },
{ {
img: require('../../Project/PublicProject/static/image/pbl2.png').default, img: 'https://cdn.open-ct.com/task-resources//carousel-top-2.png',
title: '', title: '',
text: '', text: '',
}, },
{ {
img: require('../../Project/PublicProject/static/image/pbl3.png').default, img: 'https://cdn.open-ct.com/task-resources//carousel-top-3.png',
title: '', title: '',
text: '', text: '',
}, },

View File

@ -55,7 +55,7 @@ function LatestProject(obj) {
borderTopLeftRadius: '10px', borderTopLeftRadius: '10px',
borderTopRightRadius: '10px', borderTopRightRadius: '10px',
}} }}
fallback={require("../../assets/empty.png").default} fallback={"https://cdn.open-ct.com/task-resources//openpbl-empty-project.png"}
/> />
} }
> >

View File

@ -0,0 +1,13 @@
import React from 'react';
import ProjectList from '../component/ProjectList';
class FavouriteProject extends React.PureComponent {
render() {
return (
<ProjectList mode="favourite"/>
);
}
}
export default FavouriteProject;

View File

@ -1,20 +1,44 @@
import React from 'react'; import React from 'react';
import DocumentTitle from 'react-document-title'; import DocumentTitle from 'react-document-title';
import localStorage from "localStorage";
import {Link, Redirect, Route, Switch} from 'react-router-dom' import {Link, Redirect, Route, Switch} from 'react-router-dom'
import {CheckCircleOutlined, CheckOutlined, CopyOutlined, HighlightOutlined, SyncOutlined, StarFilled} from "@ant-design/icons";
import PublishedProject from "../PublishedProject"; import PublishedProject from "../PublishedProject";
import EditingProject from "../EditingProject"; import EditingProject from "../EditingProject";
import FinishedProject from "../FinishedProject"; import FinishedProject from "../FinishedProject";
import LearningProject from "../LearningProject"; import LearningProject from "../LearningProject";
import {Affix, Button, Layout, Menu} from "antd"; import {Affix, Button, Layout, Menu} from "antd";
import {CheckCircleOutlined, CheckOutlined, CopyOutlined, HighlightOutlined, SyncOutlined} from "@ant-design/icons";
import ProjectApi from "../../../api/ProjectApi"; import ProjectApi from "../../../api/ProjectApi";
import FavouriteProject from "../FavouriteProject";
class MyProject extends React.PureComponent { class MyProject extends React.PureComponent {
state = { state = {
type: localStorage.getItem('type'), menu: ''
} }
componentDidMount() {
this.changeMenu()
}
changeMenu = (e) => {
if (e !== undefined ) {
this.setState({menu: e.key})
return
}
const p = this.props.location.pathname
if (p.endsWith("/published")) {
this.setState({menu: 'published'})
} else if (p.endsWith("/editing")) {
this.setState({menu: 'editing'})
} else if (p.endsWith("/finished")) {
this.setState({menu: 'finished'})
} else if (p.endsWith("/learning")) {
this.setState({menu: 'learning'})
} else if (p.endsWith("/favourite")) {
this.setState({menu: 'favourite'})
}
}
createProject = e => { createProject = e => {
ProjectApi.createProject() ProjectApi.createProject()
.then((res) => { .then((res) => {
@ -28,7 +52,7 @@ class MyProject extends React.PureComponent {
} }
render() { render() {
const {type} = this.state const {menu} = this.state
return ( return (
<DocumentTitle title="My Project"> <DocumentTitle title="My Project">
<Layout style={{margin: '20px'}}> <Layout style={{margin: '20px'}}>
@ -39,10 +63,12 @@ class MyProject extends React.PureComponent {
theme="light" theme="light"
style={{backgroundColor: '#f2f4f5'}} style={{backgroundColor: '#f2f4f5'}}
> >
{type === 'teacher' ? {this.props.account.tag === '老师' ?
<Menu <Menu
defaultSelectedKeys={['published']} defaultSelectedKeys={['published']}
className="menu-bar" className="menu-bar"
selectedKeys={[menu]}
onClick={e=>this.changeMenu(e)}
mode="inline" mode="inline"
> >
<Menu.Item key="published" icon={<CheckCircleOutlined/>}> <Menu.Item key="published" icon={<CheckCircleOutlined/>}>
@ -60,11 +86,18 @@ class MyProject extends React.PureComponent {
已结束 已结束
</Link> </Link>
</Menu.Item> </Menu.Item>
<Menu.Item key="favourite" icon={<StarFilled />}>
<Link to="/my-project/favourite">
收藏夹
</Link>
</Menu.Item>
</Menu> </Menu>
: :
<Menu <Menu
defaultSelectedKeys={['learning']} defaultSelectedKeys={['learning']}
className="menu-bar" className="menu-bar"
selectedKeys={[menu]}
onClick={e=>this.changeMenu(e)}
mode="inline" mode="inline"
> >
<Menu.Item key="learning" icon={<SyncOutlined/>}> <Menu.Item key="learning" icon={<SyncOutlined/>}>
@ -77,9 +110,14 @@ class MyProject extends React.PureComponent {
已完成 已完成
</Link> </Link>
</Menu.Item> </Menu.Item>
<Menu.Item key="favourite" icon={<StarFilled />}>
<Link to="/my-project/favourite">
收藏夹
</Link>
</Menu.Item>
</Menu> </Menu>
} }
{type === 'teacher' ? {this.props.account.tag === '老师' ?
<Button <Button
type='primary' type='primary'
shape='round' shape='round'
@ -88,6 +126,7 @@ class MyProject extends React.PureComponent {
style={{ style={{
width: '180px', width: '180px',
margin: '10px', margin: '10px',
marginTop: '30px',
}} }}
>创建项目</Button> >创建项目</Button>
: :
@ -96,7 +135,7 @@ class MyProject extends React.PureComponent {
</Layout.Sider> </Layout.Sider>
</Affix> </Affix>
<Layout.Content style={{marginLeft: '10px'}}> <Layout.Content style={{marginLeft: '10px'}}>
{type === 'teacher' ? {this.props.account.tag === '老师' ?
<Switch> <Switch>
<Route exact path="/my-project" render={() => ( <Route exact path="/my-project" render={() => (
<Redirect to="/my-project/published"/> <Redirect to="/my-project/published"/>
@ -104,6 +143,7 @@ class MyProject extends React.PureComponent {
<Route exact path="/my-project/published" component={PublishedProject}/> <Route exact path="/my-project/published" component={PublishedProject}/>
<Route exact path="/my-project/editing" component={EditingProject}/> <Route exact path="/my-project/editing" component={EditingProject}/>
<Route exact path="/my-project/finished" component={FinishedProject}/> <Route exact path="/my-project/finished" component={FinishedProject}/>
<Route exact path="/my-project/favourite" component={FavouriteProject}/>
</Switch> </Switch>
: :
<Switch> <Switch>
@ -112,6 +152,7 @@ class MyProject extends React.PureComponent {
)}/> )}/>
<Route exact path="/my-project/learning" component={LearningProject}/> <Route exact path="/my-project/learning" component={LearningProject}/>
<Route exact path="/my-project/finished" component={FinishedProject}/> <Route exact path="/my-project/finished" component={FinishedProject}/>
<Route exact path="/my-project/favourite" component={FavouriteProject}/>
</Switch> </Switch>
} }
</Layout.Content> </Layout.Content>
@ -121,4 +162,4 @@ class MyProject extends React.PureComponent {
} }
} }
export default MyProject; export default MyProject

View File

@ -20,11 +20,15 @@ function ProjectEvaluation(obj) {
const pid = obj.project.id const pid = obj.project.id
const published = obj.project.published const published = obj.project.published
const type = localStorage.getItem("type") const type = localStorage.getItem("type")
const [chapters, setChapters] = useState([]) const [chapters, setChapters] = useState([])
const [loadChapters, setLoadChapters] = useState(false)
const [defaultOpenedKeys, setDefaultOpenedKeys] = useState([]) const [defaultOpenedKeys, setDefaultOpenedKeys] = useState([])
const [openedKeys, setOpenedKeys] = useState([]) const [openedKeys, setOpenedKeys] = useState([])
const [data, setData] = useState([]) const [data, setData] = useState([])
const [tasks, setTasks] = useState([]) const [tasks, setTasks] = useState([])
const [loadTasks, setLoadTasks] = useState(false)
const [learnMinuteWeight, setLearnMinuteWeight] = useState(obj.project.learnMinuteWeight) const [learnMinuteWeight, setLearnMinuteWeight] = useState(obj.project.learnMinuteWeight)
@ -36,8 +40,10 @@ function ProjectEvaluation(obj) {
getTasks() getTasks()
}, []); }, []);
const getTasks = () => { const getTasks = () => {
setLoadTasks(true)
TaskApi.getProjectTasks(pid) TaskApi.getProjectTasks(pid)
.then(res => { .then(res => {
setLoadTasks(false)
if (res.data.code === 200) { if (res.data.code === 200) {
if (res.data.data != null) { if (res.data.data != null) {
setTasks(res.data.data) setTasks(res.data.data)
@ -52,8 +58,10 @@ function ProjectEvaluation(obj) {
}) })
} }
const getChapters = () => { const getChapters = () => {
setLoadChapters(true)
ChapterApi.getProjectChapters(pid) ChapterApi.getProjectChapters(pid)
.then((res) => { .then((res) => {
setLoadChapters(false)
if (res.data.chapters === null) { if (res.data.chapters === null) {
setChapters([]) setChapters([])
setDefaultOpenedKeys(0) setDefaultOpenedKeys(0)
@ -223,7 +231,7 @@ function ProjectEvaluation(obj) {
}); });
return ( return (
<div style={{textAlign: 'left', marginBottom: '30px'}} key="1"> <div style={{textAlign: 'left', marginBottom: '30px'}} key="1">
<ReactEcharts option={getOptions()}/> <ReactEcharts option={getOptions()} showLoading={loadTasks}/>
<div> <div>
<Divider orientation="left"> <Divider orientation="left">
<p className="evidence-title">章节学习时长</p> <p className="evidence-title">章节学习时长</p>
@ -256,6 +264,8 @@ function ProjectEvaluation(obj) {
<List <List
size="large" size="large"
dataSource={item.sections} dataSource={item.sections}
locale={{emptyText: '空的'}}
loading={loadChapters}
renderItem={ renderItem={
(item, subIndex) => ( (item, subIndex) => (
<List.Item> <List.Item>
@ -317,6 +327,7 @@ function ProjectEvaluation(obj) {
</Row> </Row>
<Divider/> <Divider/>
<Table <Table
loading={loadTasks}
columns={getColumns()} columns={getColumns()}
dataSource={tasks} dataSource={tasks}
pagination={false} pagination={false}

View File

@ -2,14 +2,15 @@ import React, {useEffect, useState} from 'react';
import QueueAnim from 'rc-queue-anim'; import QueueAnim from 'rc-queue-anim';
import {Avatar, Button, message, Pagination, Popconfirm, Table} from "antd"; import {Avatar, Button, message, Pagination, Popconfirm, Table} from "antd";
import {DeleteOutlined} from "@ant-design/icons" import {DeleteOutlined} from "@ant-design/icons"
import {Link} from "react-router-dom";
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";
function StudentAdmin(obj) { function StudentAdmin(obj) {
const pid = obj.project.id const pid = obj.project.id
const [students, setStudents] = useState([]) const [students, setStudents] = useState([])
const [loadStudents, setLoadStudents] = useState(false)
const [total, setTotal] = useState(0) const [total, setTotal] = useState(0)
const [page, setPage] = useState(1) const [page, setPage] = useState(1)
@ -21,8 +22,10 @@ function StudentAdmin(obj) {
}, [pid]); }, [pid]);
const updateStudentList = () => { const updateStudentList = () => {
setLoadStudents(true)
ProjectApi.getProjectStudents(pid) ProjectApi.getProjectStudents(pid)
.then((res) => { .then((res) => {
setLoadStudents(false)
if (res.data.code === 200) { if (res.data.code === 200) {
setStudents(res.data.students); setStudents(res.data.students);
setTotal(res.data.count) setTotal(res.data.count)
@ -51,6 +54,7 @@ function StudentAdmin(obj) {
<QueueAnim> <QueueAnim>
<div style={{textAlign: 'left'}} key="1"> <div style={{textAlign: 'left'}} key="1">
<Table <Table
loading={loadStudents}
dataSource={students} dataSource={students}
columns={[ columns={[
{ {

View File

@ -1,9 +1,24 @@
import React from 'react'; import React from 'react';
import DocumentTitle from 'react-document-title'; import DocumentTitle from 'react-document-title';
import {Avatar, BackTop, Button, Card, Col, Divider, Image, Menu, message, PageHeader, Popconfirm, Row} from 'antd'; import {
Avatar,
BackTop,
Button,
Card,
Col,
Divider,
Image,
Menu,
message,
PageHeader,
Popconfirm,
Row,
Tag, Tooltip
} from 'antd';
import QueueAnim from 'rc-queue-anim'; import QueueAnim from 'rc-queue-anim';
import localStorage from 'localStorage';
import {Link} from 'react-router-dom'; import {Link} from 'react-router-dom';
import {DeleteOutlined, StarFilled, StarOutlined} from "@ant-design/icons";
import ProjectIntroduce from './component/ProjectIntroduce'; import ProjectIntroduce from './component/ProjectIntroduce';
import ProjectOutline from './component/ProjectOutline'; import ProjectOutline from './component/ProjectOutline';
@ -13,7 +28,6 @@ import ProjectApi from "../../../api/ProjectApi";
import StudentApi from "../../../api/StudentApi"; 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 util from "../../component/Util" import util from "../../component/Util"
import StudentEvidence from "../Evidence/component/StudentEvidence"; import StudentEvidence from "../Evidence/component/StudentEvidence";
@ -23,7 +37,6 @@ class ProjectInfo extends React.PureComponent {
const pid = this.props.match.params.id; const pid = this.props.match.params.id;
let url = new URLSearchParams(this.props.location.search) let url = new URLSearchParams(this.props.location.search)
let menu = url.get("menu") let menu = url.get("menu")
console.log(menu)
if (menu === undefined || menu === null) { if (menu === undefined || menu === null) {
menu = 'project-introduce' menu = 'project-introduce'
} }
@ -32,8 +45,8 @@ class ProjectInfo extends React.PureComponent {
project: {}, project: {},
teacher: {}, teacher: {},
menu: menu, menu: menu,
type: localStorage.getItem('type'), lastLearn: {},
lastLearn: {} favBtLoading: false
}; };
} }
@ -82,7 +95,7 @@ class ProjectInfo extends React.PureComponent {
} }
handleClick = (e) => { handleClick = (e) => {
if (this.state.type === 'student' && e.key === "student-evidence" && !this.state.project.learning) { if (this.props.account.tag === '学生' && e.key === "student-evidence" && !this.state.project.learning) {
message.warn("请先加入学习") message.warn("请先加入学习")
return return
} }
@ -91,7 +104,11 @@ class ProjectInfo extends React.PureComponent {
}); });
} }
back = e => { back = e => {
window.location.href = '/my-project' if (this.props.account.tag === '老师') {
window.location.href = '/my-project/published'
} else {
window.location.href = '/my-project/learning'
}
} }
learnProject = e => { learnProject = e => {
StudentApi.learnProject(this.state.pid) StudentApi.learnProject(this.state.pid)
@ -144,7 +161,11 @@ class ProjectInfo extends React.PureComponent {
StudentApi.exitProject(this.state.pid) StudentApi.exitProject(this.state.pid)
.then(res => { .then(res => {
if (res.data.code === 200) { if (res.data.code === 200) {
window.location.href = "/my-project" if (this.props.account.tag === '老师') {
window.location.href = '/my-project/published'
} else {
window.location.href = '/my-project/learning'
}
} else { } else {
message.error(res.data.msg) message.error(res.data.msg)
} }
@ -157,7 +178,11 @@ class ProjectInfo extends React.PureComponent {
ProjectApi.deleteProject(this.state.pid) ProjectApi.deleteProject(this.state.pid)
.then(res => { .then(res => {
if (res.data.code === 200) { if (res.data.code === 200) {
window.location.href = "/my-project" if (this.props.account === '老师') {
window.location.href = '/my-project/published'
} else {
window.location.href = '/my-project/learning'
}
} else { } else {
message.error(res.data.msg) message.error(res.data.msg)
} }
@ -166,6 +191,42 @@ class ProjectInfo extends React.PureComponent {
console.log(e) console.log(e)
}) })
} }
addFavourite = e => {
this.setState({
favBtLoading: true
})
ProjectApi.addFavourite(this.state.pid)
.then(res=>{
this.setState({
favBtLoading: false
})
if (res.data.code === 200) {
this.loadProjectDetail()
message.success(res.data.msg)
} else {
message.error(res.data.msg)
}
})
.catch(e=>{console.log(e)})
}
removeFavourite = e => {
this.setState({
favBtLoading: true
})
ProjectApi.removeFavourite(this.state.pid)
.then(res=>{
this.setState({
favBtLoading: false
})
if (res.data.code === 200) {
this.loadProjectDetail()
message.success(res.data.msg)
} else {
message.error(res.data.msg)
}
})
.catch(e=>{console.log(e)})
}
setProject = project => { setProject = project => {
this.setState({ this.setState({
@ -174,7 +235,7 @@ class ProjectInfo extends React.PureComponent {
} }
render() { render() {
const {project, teacher, menu, type, pid, lastLearn} = this.state; const {project, teacher, menu, pid, lastLearn, favBtLoading} = this.state;
const teacherBt = ( const teacherBt = (
<div style={{float: 'right'}}> <div style={{float: 'right'}}>
@ -332,12 +393,27 @@ class ProjectInfo extends React.PureComponent {
src={project.image} src={project.image}
placeholder placeholder
preview={false} preview={false}
fallback={require("../../assets/empty.png").default} fallback={"https://cdn.open-ct.com/task-resources//openpbl-empty-project.png"}
/> />
</Col> </Col>
<Col span={1}>&nbsp;</Col> <Col span={1}>&nbsp;</Col>
<Col flex="auto"> <Col flex="auto">
<p style={{fontSize: '20px'}}>{project.projectTitle}</p> <p style={{fontSize: '20px'}}>
{project.projectTitle}&nbsp;&nbsp;
{project.created ? <Tag color="geekblue">我创建的项目</Tag> : null}
{project.learning ? <Tag color="geekblue">正在学习</Tag> : null}
<span style={{float: 'right'}}>
{project.favourite ?
<Tooltip title="点击取消收藏">
<Button shape="circle" type="text" loading={favBtLoading} icon={<StarFilled/>} onClick={this.removeFavourite}/>
</Tooltip>
:
<Tooltip title="点击收藏">
<Button shape="circle" type="text" loading={favBtLoading} icon={<StarOutlined/>} onClick={this.addFavourite}/>
</Tooltip>
}
</span>
</p>
<p <p
style={{fontSize: '14px', color: 'gray'}} style={{fontSize: '14px', color: 'gray'}}
>发布时间{util.FilterTime(project.createAt)} >发布时间{util.FilterTime(project.createAt)}
@ -353,7 +429,16 @@ class ProjectInfo extends React.PureComponent {
</span> </span>
</div> </div>
<br/> <br/>
{type === 'student' ? studentBt : teacherBt} {this.props.account.tag === '学生' ?
studentBt
:
<>
{project.created ?
teacherBt
: null
}
</>
}
</Col> </Col>
</Row> </Row>
</Card> </Card>
@ -369,9 +454,9 @@ class ProjectInfo extends React.PureComponent {
<Menu.Item key="project-outline">项目大纲</Menu.Item> <Menu.Item key="project-outline">项目大纲</Menu.Item>
<Menu.Item key="project-evaluation">评价方案</Menu.Item> <Menu.Item key="project-evaluation">评价方案</Menu.Item>
{type === 'teacher' ? <Menu.Item key="student-admin">学生管理</Menu.Item> {project.created ? <Menu.Item key="student-admin">学生管理</Menu.Item>
: null} : null}
{type === 'student' ? <Menu.Item key="student-evidence">证据收集</Menu.Item> {project.learning ? <Menu.Item key="student-evidence">证据收集</Menu.Item>
: null} : null}
</Menu> </Menu>
<div style={{ <div style={{
@ -392,7 +477,6 @@ class ProjectInfo extends React.PureComponent {
} }
{menu === 'student-admin' ? <StudentAdmin project={project}/> : null} {menu === 'student-admin' ? <StudentAdmin project={project}/> : null}
{menu === 'student-evidence' ? <StudentEvidence project={project}/> : null} {menu === 'student-evidence' ? <StudentEvidence project={project}/> : null}
</div> </div>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 969 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 436 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 630 KiB

View File

@ -1,6 +1,5 @@
import React, {useEffect, useState} from 'react'; import React, {useEffect, useState} from 'react';
import QueueAnim from 'rc-queue-anim'; import {Card, Col, Divider, Empty, Image, Input, Pagination, Row, Select, Spin, Tag} from 'antd';
import {Card, Col, Divider, Empty, Image, Input, Pagination, Row, Select, Tag} from 'antd';
import {EyeOutlined, TeamOutlined} from '@ant-design/icons'; import {EyeOutlined, TeamOutlined} from '@ant-design/icons';
import {Link} from 'react-router-dom'; import {Link} from 'react-router-dom';
@ -20,6 +19,9 @@ const topColResponsiveProps = {
function ProjectList(obj) { function ProjectList(obj) {
const [learningProjectList, setLearningProjectList] = useState([]); const [learningProjectList, setLearningProjectList] = useState([]);
const [loadProjects, setLoadProjects] = useState(false)
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
const [size, setSize] = useState(10); const [size, setSize] = useState(10);
@ -44,8 +46,9 @@ function ProjectList(obj) {
} }
const updateProjectList = (p, size, subject, skill, text) => { const updateProjectList = (p, size, subject, skill, text) => {
setLoadProjects(true)
let q = { let q = {
page: p - 1, from: (p - 1)*size,
size: size, size: size,
orderBy: 'create_at', orderBy: 'create_at',
orderType: 'desc', orderType: 'desc',
@ -55,6 +58,7 @@ function ProjectList(obj) {
} }
ProjectListApi.getUserProjectList(mode, q) ProjectListApi.getUserProjectList(mode, q)
.then((res) => { .then((res) => {
setLoadProjects(false)
if (res.data.projects === null) { if (res.data.projects === null) {
setLearningProjectList([]) setLearningProjectList([])
} else { } else {
@ -90,7 +94,7 @@ function ProjectList(obj) {
updateProjectList(page, size, selectedSubjects.toString(), selectedSkills.toString(), v) updateProjectList(page, size, selectedSubjects.toString(), selectedSkills.toString(), v)
}; };
return ( return (
<QueueAnim delay={100} className="queue-simple"> <div>
<Card bordered={false} style={{backgroundColor: 'white', borderRadius: '4px', textAlign: 'left'}}> <Card bordered={false} style={{backgroundColor: 'white', borderRadius: '4px', textAlign: 'left'}}>
<Search <Search
size="large" size="large"
@ -142,8 +146,9 @@ function ProjectList(obj) {
</Row> </Row>
</Card> </Card>
<div key="1" style={{marginTop: '10px'}}> <div style={{marginTop: '10px', textAlign: 'center'}}>
<Row gutter={[20, 20]}> <Spin spinning={loadProjects} />
<Row gutter={[20, 20]} style={{textAlign: 'left'}}>
{ {
learningProjectList.map((item, index) => ( learningProjectList.map((item, index) => (
<Col key={index.toString()} {...topColResponsiveProps}> <Col key={index.toString()} {...topColResponsiveProps}>
@ -162,7 +167,7 @@ function ProjectList(obj) {
borderTopLeftRadius: '10px', borderTopLeftRadius: '10px',
borderTopRightRadius: '10px', borderTopRightRadius: '10px',
}} }}
fallback={require("../../assets/empty.png").default} fallback={"https://cdn.open-ct.com/task-resources//openpbl-empty-project.png"}
/> />
} }
> >
@ -231,7 +236,7 @@ function ProjectList(obj) {
</div> </div>
<br/> <br/>
</div> </div>
</QueueAnim> </div>
); );
} }

View File

@ -21,7 +21,6 @@ class AuthCallback extends React.Component {
AuthApi.login(params.get('code'), params.get('state')) AuthApi.login(params.get('code'), params.get('state'))
.then((res) => { .then((res) => {
if (res.data.code === 200) { if (res.data.code === 200) {
localStorage.setItem("type", res.data.data.tag)
message.success("登录成功,跳转主页"); message.success("登录成功,跳转主页");
window.location.href = "/home" window.location.href = "/home"
} else { } else {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 8.7 KiB

View File

@ -1,10 +1,8 @@
import React from "react"; import React from "react";
import {Avatar, Badge, Button, Col, Dropdown, Layout, Menu, Row} from "antd"; import {Avatar, Badge, Button, Col, Dropdown, Layout, Menu, Row, Tag, Image, message} from "antd";
import {Link, Redirect, Route, Switch} from "react-router-dom"; import {Link, Redirect, Route, Switch} from "react-router-dom";
import {BellOutlined, LogoutOutlined, SettingOutlined} from '@ant-design/icons'; import {BellOutlined, LogoutOutlined, SettingOutlined} from '@ant-design/icons';
import './index.less'
import * as Auth from "../../User/Auth/Auth" import * as Auth from "../../User/Auth/Auth"
import AuthApi from "../../../api/AuthApi" import AuthApi from "../../../api/AuthApi"
import Home from "../../Home"; import Home from "../../Home";
@ -20,11 +18,14 @@ import SurveyEditPage from "../../Project/CreateProject/Survey/SurveyEditPage";
import PreviewSection from "../../Project/PreviewProject/PreviewSection"; import PreviewSection from "../../Project/PreviewProject/PreviewSection";
const logo = "https://cdn.open-ct.com/logo/openct_logo_1082x328.png"
class HeaderLayout extends React.Component { class HeaderLayout extends React.Component {
state = { state = {
current: 'home', current: 'home',
account: null, account: null,
messageCount: 0, messageCount: 0,
menu: 'home'
} }
componentDidMount() { componentDidMount() {
@ -34,19 +35,41 @@ class HeaderLayout extends React.Component {
this.setState({ this.setState({
account: res.data.data account: res.data.data
}) })
localStorage.setItem("type", res.data.data.tag)
} else {
localStorage.setItem("type", "")
} }
}) })
.catch((e) => { .catch((e) => {console.log(e)})
console.log(e)
}) this.changeMenu()
}
changeMenu = (e) => {
if (e !== undefined ) {
this.setState({menu: e.key})
return
}
const p = this.props.location.pathname
if (p.startsWith('/home')) {
this.setState({menu: 'home'})
} else if (p.startsWith("/my-project")) {
this.setState({menu: 'my-project'})
} else if (p.startsWith("/public-project")) {
this.setState({menu: 'public-project'})
}
}
renderHomeIfLoggedIn(component) {
if (this.state.account === null) {
message.warn('请先登录')
return <Redirect to={'/home'} />
} else if (this.state.account === undefined) {
return null
} else {
return component
}
} }
handleRightDropdownClick(e) { handleRightDropdownClick(e) {
let account = this.state.account; let account = this.state.account;
console.log(account)
if (e.key === 'my-account') { if (e.key === 'my-account') {
window.open(Auth.getMyProfileUrl(account)); window.open(Auth.getMyProfileUrl(account));
} else if (e.key === 'logout') { } else if (e.key === 'logout') {
@ -56,13 +79,10 @@ class HeaderLayout extends React.Component {
this.setState({ this.setState({
account: null account: null
}) })
localStorage.setItem("type", "")
window.location.href = '/' window.location.href = '/'
} }
}) })
.catch(e => { .catch(e => {console.log(e)})
console.log(e)
})
} }
} }
@ -80,7 +100,7 @@ class HeaderLayout extends React.Component {
</Menu> </Menu>
) )
return ( return (
<Dropdown overlay={menu} placement="bottomRight"> <Dropdown overlay={menu} placement="bottomRight" trigger="click">
<div style={{cursor: 'pointer'}}> <div style={{cursor: 'pointer'}}>
<Avatar size="large" src={this.state.account.avatar}/>&nbsp; <Avatar size="large" src={this.state.account.avatar}/>&nbsp;
<span>{this.state.account.name}</span> <span>{this.state.account.name}</span>
@ -98,26 +118,36 @@ class HeaderLayout extends React.Component {
); );
} else { } else {
return ( return (
this.renderRightDropdown() <>
<span style={{float: 'left'}}>
<Tag>{this.state.account.tag}</Tag>
</span>
{this.renderRightDropdown()}
</>
) )
} }
} }
render() { render() {
const {current, messageCount} = this.state; const {menu, messageCount} = this.state;
return ( return (
<Layout style={{minHeight: '100vh', textAlign: 'left'}}> <Layout style={{minHeight: '100vh', textAlign: 'left'}}>
<Layout.Header style={{backgroundColor: 'white'}}> <Layout.Header style={{backgroundColor: 'white', paddingLeft: '4px', paddingRight: '4px'}}>
<Row> <Row>
<Col xxl={15} xl={11} lg={8} md={6} sm={6} xs={10}> <Col xxl={14} xl={10} lg={8} md={6} sm={6} xs={10}>
<Link to="/home"> <Link to="/home">
<div className="logo"> <Image height={50} width={200} style={{margin: '7px'}} src={logo} preview={false}/>
<span style={{fontSize: '25px', color: 'black', float: 'left', marginLeft: '80px'}}>OpenCT</span>
</div>
</Link> </Link>
</Col> </Col>
<Col xxl={6} xl={10} lg={12} md={14} sm={12} xs={6}> <Col xxl={6} xl={10} lg={10} md={10} sm={10} xs={3}>
<Menu theme="light" mode="horizontal" defaultSelectedKeys={[current]} style={{border: 0}}> <Menu
theme="light"
mode="horizontal"
style={{border: 0}}
defaultSelectedKeys={['home']}
selectedKeys={[menu]}
onClick={e=>this.changeMenu(e)}
>
<Menu.Item key="home"> <Menu.Item key="home">
<Link to="/home"> <Link to="/home">
首页 首页
@ -140,7 +170,7 @@ class HeaderLayout extends React.Component {
</Menu.Item> </Menu.Item>
</Menu> </Menu>
</Col> </Col>
<Col xxl={3} xl={3} lg={4} md={4} sm={6} xs={8}> <Col xxl={4} xl={4} lg={6} md={8} sm={8} xs={11}>
{ {
<> <>
<span style={{float: 'left', marginRight: '20px'}}> <span style={{float: 'left', marginRight: '20px'}}>
@ -169,20 +199,20 @@ class HeaderLayout extends React.Component {
<Redirect to="/home"/> <Redirect to="/home"/>
)}/> )}/>
<Route exact path="/home" component={Home}/> <Route exact path="/home" render={(props)=><Home account={this.state.account} {...props} />}/>
<Route exact path="/public-project" component={Project}/> <Route exact path="/public-project" render={(props)=>this.renderHomeIfLoggedIn(<Project account={this.state.account} {...props} />)} />
<Route path="/my-project" component={MyProject}/> <Route path="/my-project" render={(props)=>this.renderHomeIfLoggedIn(<MyProject account={this.state.account} {...props} />)} />
<Route path="/message" component={Message}/> <Route path="/message" render={(props)=>this.renderHomeIfLoggedIn(<Message account={this.state.account} {...props} />)}/>
<Route exact path="/project/:id/info" component={ProjectInfo}/> <Route exact path="/project/:id/info" render={(props)=>this.renderHomeIfLoggedIn(<ProjectInfo account={this.state.account} {...props} />)}/>
<Route exact path="/project/:id/info/edit" component={EditInfo}/> <Route exact path="/project/:id/info/edit" render={(props)=>this.renderHomeIfLoggedIn(<EditInfo account={this.state.account} {...props} />)}/>
<Route exact path="/project/:id/outline/edit" component={EditOutlined}/> <Route exact path="/project/:id/outline/edit" render={(props)=>this.renderHomeIfLoggedIn(<EditOutlined account={this.state.account} {...props} />)}/>
<Route exact path="/project/:pid/student/:sid/evidence" component={Evidence}/> <Route exact path="/project/:pid/student/:sid/evidence" render={(props)=>this.renderHomeIfLoggedIn(<Evidence account={this.state.account} {...props} />)}/>
<Route exact path="/project/:pid/section/:sid/edit" component={SectionEditPage}/> <Route exact path="/project/:pid/section/:sid/edit" render={(props)=>this.renderHomeIfLoggedIn(<SectionEditPage account={this.state.account} {...props} />)}/>
<Route exact path="/project/:pid/section/:sid/task/:tid/survey/edit" component={SurveyEditPage}/> <Route exact path="/project/:pid/section/:sid/task/:tid/survey/edit" render={(props)=>this.renderHomeIfLoggedIn(<SurveyEditPage account={this.state.account} {...props} />)}/>
<Route exact path="/project/:pid/section/:sid/preview" component={PreviewSection}/> <Route exact path="/project/:pid/section/:sid/preview" render={(props)=>this.renderHomeIfLoggedIn(<PreviewSection account={this.state.account} {...props} />)}/>
</Switch> </Switch>
</Layout.Content> </Layout.Content>
<Layout.Footer style={{textAlign: 'center'}}>OpenPBL</Layout.Footer> <Layout.Footer style={{textAlign: 'center'}}>OpenPBL</Layout.Footer>
@ -191,4 +221,4 @@ class HeaderLayout extends React.Component {
} }
} }
export default HeaderLayout; export default HeaderLayout

View File

@ -1,6 +0,0 @@
.logo {
background: url("../../assets/logo.svg");
background-size: contain;
height: 64px;
width: 64px;
}

View File

@ -1930,14 +1930,6 @@
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
"@types/hoist-non-react-statics@^3.3.0":
version "3.3.1"
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
dependencies:
"@types/react" "*"
hoist-non-react-statics "^3.3.0"
"@types/html-minifier-terser@^5.0.0": "@types/html-minifier-terser@^5.0.0":
version "5.1.1" version "5.1.1"
resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#3c9ee980f1a10d6021ae6632ca3e79ca2ec4fb50" resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#3c9ee980f1a10d6021ae6632ca3e79ca2ec4fb50"
@ -2005,35 +1997,11 @@
resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.2.1.tgz#374e31645d58cb18a07b3ecd8e9dede4deb2cccd" resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.2.1.tgz#374e31645d58cb18a07b3ecd8e9dede4deb2cccd"
integrity sha512-DxZZbyMAM9GWEzXL+BMZROWz9oo6A9EilwwOMET2UVu2uZTqMWS5S69KVtuVKaRjCUpcrOXRalet86/OpG4kqw== integrity sha512-DxZZbyMAM9GWEzXL+BMZROWz9oo6A9EilwwOMET2UVu2uZTqMWS5S69KVtuVKaRjCUpcrOXRalet86/OpG4kqw==
"@types/prop-types@*":
version "15.7.4"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11"
integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==
"@types/q@^1.5.1": "@types/q@^1.5.1":
version "1.5.4" version "1.5.4"
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24" resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24"
integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug== integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==
"@types/react-redux@^7.1.16":
version "7.1.18"
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.18.tgz#2bf8fd56ebaae679a90ebffe48ff73717c438e04"
integrity sha512-9iwAsPyJ9DLTRH+OFeIrm9cAbIj1i2ANL3sKQFATqnPWRbg+jEFXyZOKHiQK/N86pNRXbb4HRxAxo0SIX1XwzQ==
dependencies:
"@types/hoist-non-react-statics" "^3.3.0"
"@types/react" "*"
hoist-non-react-statics "^3.3.0"
redux "^4.0.0"
"@types/react@*":
version "17.0.14"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.14.tgz#f0629761ca02945c4e8fea99b8177f4c5c61fb0f"
integrity sha512-0WwKHUbWuQWOce61UexYuWTGuGY/8JvtUe/dtQ6lR4sZ3UiylHotJeWpf3ArP9+DSGUoLY3wbU59VyMrJps5VQ==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
csstype "^3.0.2"
"@types/resolve@0.0.8": "@types/resolve@0.0.8":
version "0.0.8" version "0.0.8"
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194"
@ -2041,11 +2009,6 @@
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
"@types/scheduler@*":
version "0.16.2"
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==
"@types/source-list-map@*": "@types/source-list-map@*":
version "0.1.2" version "0.1.2"
resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9"
@ -4465,11 +4428,6 @@ cssstyle@^2.2.0:
dependencies: dependencies:
cssom "~0.3.6" cssom "~0.3.6"
csstype@^3.0.2:
version "3.0.8"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.8.tgz#d2266a792729fb227cd216fb572f43728e1ad340"
integrity sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==
cyclist@^1.0.1: cyclist@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9"
@ -6297,7 +6255,7 @@ hoist-non-react-statics@1.x:
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb"
integrity sha1-qkSM8JhtVcxAdzsXF0t90GbLfPs= integrity sha1-qkSM8JhtVcxAdzsXF0t90GbLfPs=
hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: hoist-non-react-statics@^3.1.0:
version "3.3.2" version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
@ -11088,7 +11046,7 @@ react-github-button@^0.1.11:
dependencies: dependencies:
prop-types "^15.5.10" prop-types "^15.5.10"
react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1: react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1:
version "16.13.1" version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
@ -11139,18 +11097,6 @@ react-pdf@^5.3.2:
pdfjs-dist "2.6.347" pdfjs-dist "2.6.347"
prop-types "^15.6.2" prop-types "^15.6.2"
react-redux@^7.2.4:
version "7.2.4"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.4.tgz#1ebb474032b72d806de2e0519cd07761e222e225"
integrity sha512-hOQ5eOSkEJEXdpIKbnRyl04LhaWabkDPV+Ix97wqQX3T3d2NQ8DUblNXXtNMavc7DpswyQM6xfaN4HQDKNY2JA==
dependencies:
"@babel/runtime" "^7.12.1"
"@types/react-redux" "^7.1.16"
hoist-non-react-statics "^3.3.2"
loose-envify "^1.4.0"
prop-types "^15.7.2"
react-is "^16.13.1"
react-refresh@^0.8.3: react-refresh@^0.8.3:
version "0.8.3" version "0.8.3"
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f"
@ -11378,13 +11324,6 @@ redent@^3.0.0:
indent-string "^4.0.0" indent-string "^4.0.0"
strip-indent "^3.0.0" strip-indent "^3.0.0"
redux@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.0.tgz#eb049679f2f523c379f1aff345c8612f294c88d4"
integrity sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g==
dependencies:
"@babel/runtime" "^7.9.2"
regenerate-unicode-properties@^8.2.0: regenerate-unicode-properties@^8.2.0:
version "8.2.0" version "8.2.0"
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec"