feat: show student evidence

This commit is contained in:
lbaf23 2021-08-03 16:25:28 +08:00
parent 735dc1365f
commit 64fa6bc603
9 changed files with 299 additions and 138 deletions

View File

@ -38,7 +38,7 @@ func (p *ProjectController) GetSectionTasksDetail() {
learning = false
}
uid := user.Username
pid, err := p.GetInt64(":projectId")
pid := p.GetString(":projectId")
learning = models.IsLearningProject(pid, uid)
tasks, err := models.GetSectionTasks(sid, uid, learning)
if err != nil {
@ -83,7 +83,7 @@ func (p *ProjectController) GetProjectTasks() {
}
pid := p.GetString(":projectId")
tasks, err := models.GetProjectTasks(pid, "")
tasks, err := models.GetProjectTasks(pid)
if err != nil {
p.Data["json"] = Response{
Code: 400,
@ -98,44 +98,51 @@ func (p *ProjectController) GetProjectTasks() {
p.ServeJSON()
}
// GetProjectTasksAndSubmits
// GetProjectTasksDetail
// @Title
// @Description get all the tasks of a section
// @Param sid path string true ""
// @Success 200 {object}
// @Failure 400
// @router /:projectId/tasks-submits [get]
func (p *ProjectController) GetProjectTasksAndSubmits() {
// @router /:projectId/tasks-detail [get]
func (p *ProjectController) GetProjectTasksDetail() {
var resp TaskResponse
var learning bool
user := p.GetSessionUser()
if user == nil {
p.Data["json"] = TaskResponse{
resp = TaskResponse{
Response: Response{
Code: 401,
Msg: "请先登录",
},
}
p.Data["json"] = resp
p.ServeJSON()
return
}
uid := ""
if user.Tag == "student" {
uid = user.Username
} else if user.Tag == "teacher" {
uid = p.GetString("StudentId")
if user.Tag != "student" {
learning = false
}
uid := user.Username
pid := p.GetString(":projectId")
tasks, err := models.GetProjectTasks(pid, uid)
learning = models.IsLearningProject(pid, uid)
tasks, err := models.GetProjectTasksDetail(pid, uid, learning)
if err != nil {
p.Data["json"] = Response{
Code: 400,
Msg: err.Error(),
p.Data["json"] = TaskResponse{
Response: Response{
Code: 400,
Msg: err.Error(),
},
Tasks: nil,
Learning: false,
}
} else {
p.Data["json"] = Response{
Code: 200,
Data: tasks,
p.Data["json"] = TaskResponse{
Response: Response{
Code: 200,
},
Tasks: tasks,
Learning: learning,
}
}
p.ServeJSON()

View File

@ -1,6 +1,7 @@
package models
import (
"strconv"
"time"
"xorm.io/xorm"
)
@ -55,11 +56,12 @@ func (l *LearnProject) Delete() (err error) {
return
}
func IsLearningProject(pid int64, uid string) (e bool) {
func IsLearningProject(pid string, uid string) (e bool) {
var err error
id, err := strconv.ParseInt(pid, 10, 64)
e, err = (&LearnProject{}).GetEngine().Exist(&LearnProject{
StudentId: uid,
ProjectId: pid,
ProjectId: id,
Learning: true,
})
if err != nil {

View File

@ -22,10 +22,9 @@ type Task struct {
}
type TaskEvaluate struct {
Task `xorm:"extends"`
Score int `json:"score"`
Scored bool `json:"scored"`
SubmitId int64 `json:"submitId"`
Task `xorm:"extends"`
Submitted bool `json:"submitted"`
Submit Submit `json:"submit"`
}
type TaskDetail struct {
@ -66,11 +65,11 @@ func GetSectionTasks(sid string, uid string, learning bool) (t []TaskDetail, err
Where("section_id = ?", sid).
Asc("task_order").
Find(&t)
var s Survey
var qs []Question
var c []Choice
var b bool
for i := 0; i < len(t); i ++ {
var s Survey
var qs []Question
var c []Choice
if t[i].TaskType == "survey" {
var m Submit
_, err = (&Survey{}).GetEngine().
@ -123,22 +122,72 @@ func ExchangeTasks(cid1 string, cid2 string) (err error) {
return
}
func GetProjectTasks(pid string, uid string) (t []TaskEvaluate, err error) {
if uid == "" {
err = (&Task{}).GetEngine().
Where("project_id = ?", pid).
Asc("chapter_number").
Asc("section_number").
Asc("task_order").
Find(&t)
} else {
err = (&Task{}).GetEngine().
Where("task.project_id = ?", pid).
Join("LEFT OUTER", "submit", "task.id = submit.task_id").
Asc("chapter_number").
Asc("section_number").
Asc("task_order").
Find(&t)
func GetProjectTasksDetail(sid string, uid string, learning bool) (t []TaskDetail, err error) {
err = (&Task{}).GetEngine().
Where("project_id = ?", sid).
Asc("chapter_number").
Asc("section_number").
Asc("task_order").
Find(&t)
var b bool
for i := 0; i < len(t); i ++ {
var s Survey
var qs []Question
var c []Choice
if t[i].TaskType == "survey" {
var m Submit
b, err = (&Survey{}).GetEngine().
Where("task_id = ?", t[i].Id).
Get(&s)
if b {
err = (&Question{}).GetEngine().
Where("survey_id = ?", s.Id).
Asc("question_order").
Find(&qs)
t[i].Questions = qs
}
t[i].Survey = s
if learning {
b, err = (&Submit{}).GetEngine().
Where("task_id = ?", t[i].Id).
Where("student_id = ?", uid).
Get(&m)
if b {
t[i].Submitted = true
err = (&Choice{}).GetEngine().
Where("submit_id = ?", m.Id).
Asc("choice_order").
Find(&c)
t[i].Choices = c
}
t[i].Submit = m
}
} else {
var m Submit
if learning {
b, err = (&Submit{}).GetEngine().
Where("task_id = ?", t[i].Id).
Where("student_id = ?", uid).
Get(&m)
t[i].Submit = m
if b {
t[i].Submitted = true
}
}
}
}
return
}
func GetProjectTasks(pid string) (t []TaskEvaluate, err error) {
err = (&Task{}).GetEngine().
Where("project_id = ?", pid).
Asc("chapter_number").
Asc("section_number").
Asc("task_order").
Find(&t)
return
}

View File

@ -14,9 +14,9 @@ const TaskApi = {
method: 'get',
})
},
getProjectTasksAndSubmits(pid) {
getProjectTasksDetail(pid) {
return request({
url: `/project/${pid}/tasks-submits`,
url: `/project/${pid}/tasks-detail`,
method: 'get',
})
},

View File

@ -11,7 +11,7 @@ import FillSurvey from "./component/FillSurvey";
import SubmitApi from "../../../api/SubmitApi";
import util from "../component/Util"
import StudentApi from "../../../api/StudentApi";
import TaskCard from "./component/TaskCard";
function PreviewSection(obj) {
let url = new URLSearchParams(obj.location.search)
@ -127,11 +127,11 @@ function PreviewSection(obj) {
window.location.href = backUrl
}
}
const changeComment = (v, index) => {
/* const changeComment = (v, index) => {
tasks[index].submit.submitContent = v.target.value
setTasks([...tasks])
}
const submitComment = (item, index) => {
}*/
/* const submitComment = (item, index) => {
item.submit.submitType = item.taskType
SubmitApi.createSubmit(pid, item.id, item.submit)
.then(res=>{
@ -143,8 +143,8 @@ function PreviewSection(obj) {
}
})
.catch(e=>{console.log(e)})
}
const updateComment = (item, index) => {
}*/
/* const updateComment = (item, index) => {
SubmitApi.updateSubmit(pid, item.id, item.submit.id, item.submit)
.then(res=>{
if (res.data.code === 200) {
@ -155,32 +155,12 @@ function PreviewSection(obj) {
}
})
.catch(e=>{console.log(e)})
}
}*/
const setTaskItem = (item, index) => {
tasks[index] = item
setTasks([...tasks])
}
const props = {
name: 'file',
multiple: true,
action: '',
onChange(info) {
const { status } = info.file;
if (status !== 'uploading') {
console.log(info.file, info.fileList);
}
if (status === 'done') {
message.success(`${info.file.name} 上传成功`);
} else if (status === 'error') {
message.error(`${info.file.name} 上传失败`);
}
},
onDrop(e) {
console.log('Dropped files', e.dataTransfer.files);
},
};
return (
<DocumentTitle title="Project">
<div style={{backgroundColor: '#f2f4f5', minHeight: '100vh'}}>
@ -218,45 +198,16 @@ function PreviewSection(obj) {
</span>
}
</p>
<p className="task-title">{item.taskTitle}</p>
<p>{item.taskIntroduce}</p>
{item.taskType === 'file' ?
<div>
<Upload.Dragger {...props} disabled={!learning}>
<p className="ant-upload-drag-icon">
<InboxOutlined />
</p>
<p className="ant-upload-text">点击或拖动文件上传</p>
<p className="ant-upload-hint">hint
</p>
</Upload.Dragger>
</div>
: null
}
{item.taskType === 'comment' ?
<div>
<Input.TextArea value={item.submit.submitContent} onChange={v=>changeComment(v, index)} />
{item.submitted ?
<Button type="primary" onClick={e=>updateComment(item, index)}
style={{float: 'right', marginTop: '10px'}}>更新</Button>
:
<Button disabled={!learning} type="primary" onClick={e => submitComment(item, index)}
style={{float: 'right', marginTop: '10px'}}>提交</Button>
}
</div>
: null
}
{item.taskType === 'survey' ?
<FillSurvey
pid={pid}
item={item}
index={index}
getTasks={getTasks}
learning={learning}
setTaskItem={setTaskItem}
/>
: null
}
<TaskCard
pid={pid}
item={item}
index={index}
learning={learning}
setTaskItem={setTaskItem}
getTasks={getTasks}
/>
</Card>
))
}

View File

@ -125,13 +125,13 @@ function FillSurvey(obj) {
</div>
))}
</div>
{obj.item.submitted ?
<Button type="primary" onClick={updateSurvey}
style={{float: 'right', marginTop: '10px'}}>更新</Button>
:
<Button disabled={!obj.learning} type="primary" onClick={submitSurvey}
style={{float: 'right', marginTop: '10px'}}>提交</Button>
}
<div style={{textAlign: 'right', marginTop: '10px'}}>
{obj.item.submitted ?
<Button type="primary" onClick={updateSurvey}>更新</Button>
:
<Button disabled={!obj.learning} type="primary" onClick={submitSurvey}>提交</Button>
}
</div>
</div>
)
}

View File

@ -0,0 +1,105 @@
import React from "react";
import {Button, Input, message, Upload} from "antd";
import {InboxOutlined} from "@ant-design/icons";
import FillSurvey from "./FillSurvey";
import SubmitApi from "../../../../api/SubmitApi";
function TaskCard(obj) {
const updateComment = (item, index) => {
SubmitApi.updateSubmit(obj.pid, item.id, item.submit.id, item.submit)
.then(res=>{
if (res.data.code === 200) {
message.success(res.data.msg)
obj.getTasks()
} else {
message.error(res.data.msg)
}
})
.catch(e=>{console.log(e)})
}
const submitComment = (item, index) => {
item.submit.submitType = item.taskType
SubmitApi.createSubmit(obj.pid, item.id, item.submit)
.then(res=>{
if (res.data.code === 200) {
message.success(res.data.msg)
obj.getTasks()
} else {
message.error(res.data.msg)
}
})
.catch(e=>{console.log(e)})
}
const changeComment = (v, index) => {
obj.item.submit.submitContent = v.target.value
obj.setTaskItem(obj.item, index)
}
const props = {
name: 'file',
multiple: true,
action: '',
onChange(info) {
const { status } = info.file;
if (status !== 'uploading') {
console.log(info.file, info.fileList);
}
if (status === 'done') {
message.success(`${info.file.name} 上传成功`);
} else if (status === 'error') {
message.error(`${info.file.name} 上传失败`);
}
},
onDrop(e) {
console.log('Dropped files', e.dataTransfer.files);
},
};
return (
<>
<p className="task-title">{obj.item.taskTitle}</p>
<p>{obj.item.taskIntroduce}</p>
{obj.item.taskType === 'file' ?
<div>
<Upload.Dragger {...props} disabled={!obj.learning}>
<p className="ant-upload-drag-icon">
<InboxOutlined />
</p>
<p className="ant-upload-text">点击或拖动文件上传</p>
<p className="ant-upload-hint">hint
</p>
</Upload.Dragger>
</div>
: null
}
{obj.item.taskType === 'comment' ?
<div>
<Input.TextArea value={obj.item.submit.submitContent} onChange={v=>changeComment(v, obj.index)} />
<div style={{textAlign: 'right', marginTop: '10px'}}>
{obj.item.submitted ?
<Button type="primary" onClick={e=>updateComment(obj.item, obj.index)}>更新</Button>
:
<Button disabled={!obj.learning} type="primary" onClick={e => submitComment(obj.item, obj.index)}>提交</Button>
}
</div>
</div>
: null
}
{obj.item.taskType === 'survey' ?
<FillSurvey
pid={obj.pid}
item={obj.item}
index={obj.index}
getTasks={obj.getTasks}
learning={obj.learning}
setTaskItem={obj.setTaskItem}
/>
: null
}
</>
)
}
export default TaskCard

View File

@ -3,11 +3,13 @@ import {Col, Collapse, Divider, List, Progress, Row, Table} from "antd";
import TaskApi from "../../../../api/TaskApi";
import ChapterApi from "../../../../api/ChapterApi";
import TaskCard from "../../PreviewProject/component/TaskCard";
function StudentEvidence(obj) {
const pid = obj.project.id
const [tasks, setTasks] = useState([])
const [learning, setLearning] = useState(false)
const [chapters, setChapters] = useState([])
useEffect(() => {
@ -29,11 +31,37 @@ function StudentEvidence(obj) {
})
}
const getTasks = () => {
TaskApi.getProjectTasksAndSubmits(pid)
TaskApi.getProjectTasksDetail(pid)
.then(res => {
if (res.data.code === 200) {
if (res.data.data != null) {
setTasks(res.data.data)
if (res.data.tasks === null) {
setTasks([])
} else {
let t = res.data.tasks
for (let i = 0; i < t.length; i++) {
if (t[i].questions !== undefined && t[i].questions != null) {
for (let j = 0; j < t[i].questions.length; j++) {
t[i].questions[j].questionOptions = t[i].questions[j].questionOptions.split(",")
}
} else {
t[i].questions = []
}
if (t[i].choices !== undefined && t[i].choices != null) {
for (let j = 0; j < t[i].choices.length; j++) {
t[i].choices[j].choiceOptions = t[i].choices[j].choiceOptions.split(",")
}
} else {
t[i].choices = []
for (let j=0; j<t[i].questions.length; j++) {
t[i].choices.push({
choiceOptions: [],
choiceOrder: j
})
}
}
}
setTasks(t)
setLearning(res.data.learning)
}
}
})
@ -93,6 +121,10 @@ function StudentEvidence(obj) {
const getScore = (score, weight) => {
return (score * weight / 100).toFixed(2)
}
const setTaskItem = (item, index) => {
tasks[index] = item
setTasks([...tasks])
}
return (
<div>
<Divider orientation="left">
@ -151,31 +183,46 @@ function StudentEvidence(obj) {
<>
{item.taskTitle}
<span style={{float: 'right', marginRight: '20px'}}>
{item.scored ?
{item.submit.scored ?
<span style={{color: 'green'}}>已打分</span>
:
<span>未打分</span>
}
</span>
<span style={{float: 'right', marginRight: '20px'}}>
{item.submitted ?
<span style={{color: 'green'}}>已提交</span>
:
<span>未提交</span>
}
</span>
<span style={{float: 'right', marginRight: '20px'}}>
权重{item.taskWeight}
</span>
<span style={{float: 'right', marginRight: '20px'}}>
得分{getScore(item.score, item.taskWeight)}&nbsp;/&nbsp;{item.taskWeight}
得分{getScore(item.submit.score, item.taskWeight)}&nbsp;/&nbsp;{item.taskWeight}
</span>
</>
}
>
neironog
<TaskCard
pid={pid}
item={item}
index={index}
learning={learning}
setTaskItem={setTaskItem}
getTasks={getTasks}
/>
</Collapse.Panel>
))}
</Collapse>
<Table
{/* <Table
columns={getColumns()}
dataSource={tasks}
pagination={false}
/>
/>*/}
</div>
)
}

View File

@ -45,18 +45,18 @@ func init() {
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "UpdateProject",
Method: "GetProjectDetail",
Router: "/:id",
AllowHTTPMethods: []string{"post"},
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "GetProjectDetail",
Method: "UpdateProject",
Router: "/:id",
AllowHTTPMethods: []string{"get"},
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
@ -279,18 +279,18 @@ func init() {
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "GetSurveyDetailByTaskId",
Method: "CreateSurvey",
Router: "/:projectId/task/:taskId/survey",
AllowHTTPMethods: []string{"get"},
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",
Method: "GetSurveyDetailByTaskId",
Router: "/:projectId/task/:taskId/survey",
AllowHTTPMethods: []string{"post"},
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
@ -351,8 +351,8 @@ func init() {
beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"] = append(beego.GlobalControllerRouter["OpenPBL/controllers:ProjectController"],
beego.ControllerComments{
Method: "GetProjectTasksAndSubmits",
Router: "/:projectId/tasks-submits",
Method: "GetProjectTasksDetail",
Router: "/:projectId/tasks-detail",
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Filters: nil,