feat: preview questionnaire

This commit is contained in:
lbaf23 2021-07-27 18:14:30 +08:00
parent 6b8e2da89b
commit eef35b3f7d
9 changed files with 204 additions and 21 deletions

View File

@ -16,9 +16,9 @@ func (p *ProjectController) GetSectionTasks() {
sid := p.GetString(":sid")
tasks, err := models.GetSectionTasks(sid)
if err != nil {
p.Data["json"] = map[string][]models.Task{"tasks": nil}
p.Data["json"] = map[string][]models.TaskDetail{"tasks": nil}
} else {
p.Data["json"] = map[string][]models.Task{"tasks": tasks}
p.Data["json"] = map[string][]models.TaskDetail{"tasks": tasks}
}
p.ServeJSON()
}

View File

@ -21,7 +21,7 @@ type Question struct {
QuestionCount string `json:"question" xorm:"text"`
}
type SurveyDetail struct {
Survey `xorm:"extends"`
Survey `json:"survey" xorm:"extends"`
Questions []Question `json:"questions" xorm:"extends"`
}

View File

@ -14,6 +14,12 @@ type Task struct {
TaskType string `json:"taskType" xorm:"index"`
}
type TaskDetail struct {
Task `xorm:"extends"`
SurveyDetail `xorm:"extends"`
}
func (t *Task) GetEngine() *xorm.Session {
return adapter.Engine.Table(t)
}
@ -40,11 +46,26 @@ func (t *Task) Delete() (err error) {
return
}
func GetSectionTasks(sid string) (t []Task, err error) {
func GetSectionTasks(sid string) (t []TaskDetail, err error) {
err = (&Task{}).GetEngine().
Where("section_id = ?", sid).
Asc("task_order").
Find(&t)
var s Survey
var qs []Question
for i := 0; i < len(t); i ++ {
if t[i].TaskType == "survey" {
_, err = (&Survey{}).GetEngine().
Where("task_id = ?", t[i].Id).
Get(&s)
err = (&Question{}).GetEngine().
Where("survey_id = ?", s.Id).
Asc("question_order").
Find(&qs)
t[i].Survey = s
t[i].Questions = qs
}
}
return
}

View File

@ -39,8 +39,9 @@
"web-vitals": "^1.0.1"
},
"scripts": {
"analyze": "source-map-explorer 'build/static/js/*.js'",
"start": "craco start",
"build": "craco --max_old_space_size=2048 build",
"build": "craco build",
"test": "craco test",
"eject": "react-scripts eject"
},

View File

@ -1,26 +1,72 @@
import React, {useEffect, useState} from "react";
import {Card, PageHeader} from "antd";
import {Card, PageHeader, Input, Upload, message, Button, Collapse, Spin, Radio, Divider} from "antd";
import DocumentTitle from 'react-document-title';
import {InboxOutlined} from '@ant-design/icons'
import SectionApi from "../../../api/SectionApi";
import "./section-edit.less"
import "./preview.less"
import TaskApi from "../../../api/TaskApi";
import FillSurvey from "./component/FillSurvey";
function PreviewResource(obj) {
const sid = obj.match.params.sid
const pid = obj.match.params.pid
const [section, setSection] = useState({resource:{}})
const [tasks, setTasks] = useState([])
useEffect(()=>{
getSectionResource()
getTasks()
}, [])
const getSectionResource = () => {
SectionApi.getSectionDetail(sid)
.then(res=>{
setSection(res.data.section)
})
.catch(e=>{console.log(e)})
}, [])
}
const getTasks = () => {
TaskApi.getSectionTasks(sid)
.then(res=>{
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(",")
}
}
}
setTasks(t)
}
})
.catch(e=>{console.log(e)})
}
const back = e => {
window.location.href = '/project/edit/section/' + pid + '/' + sid
}
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">
@ -31,7 +77,7 @@ function PreviewResource(obj) {
title="返回"
subTitle="我的项目"
/>
<div style={{ padding: '20px', margin: 'auto', maxWidth: '1200px'}}>
<div style={{ padding: '20px', margin: 'auto'}}>
<Card>
<h2 style={{ fontWeight: 'bold' }}>{section.sectionName}</h2>
</Card>
@ -39,18 +85,45 @@ function PreviewResource(obj) {
<div dangerouslySetInnerHTML={{__html: section.resource.content}}/>
</Card>
<Card className="resource-card">
<p className="card-title">文件</p>
<p className="card-title">文件资源</p>
<p>{section.resource.fileTitle}</p>
<p>{section.resource.fileIntroduce}</p>
</Card>
{section.resource.hasHomeWork ?
<Card className="resource-card">
{tasks.map((item, index)=>(
<Card className="resource-card" key={index.toString()}>
<p className="card-title">学生任务</p>
<p>{section.resource.homeWorkTitle}</p>
<p>{section.resource.homeWorkIntroduce}</p>
</Card>
: null}
<p className="task-title">{item.taskTitle}</p>
<p>{item.taskIntroduce}</p>
{item.taskType === 'file' ?
<div>
<Upload.Dragger {...props}>
<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 />
<Button type="primary" style={{float: 'right', marginTop: '10px'}}>提交</Button>
</div>
: null
}
{item.taskType === 'survey' ?
<FillSurvey
item={item}
/>
: null
}
</Card>
))
}
</div><br/>
</div>
</DocumentTitle>
)

View File

@ -0,0 +1,80 @@
import React from "react";
import {Button, Checkbox, Divider, Input, Radio} from "antd";
import Question from "../Question"
import "../preview.less"
import "../section-edit.less"
const blank = Question.blank
function FillSurvey(obj) {
const submitSurvey = e => {
}
return (
<div className="survey">
<h2 style={{textAlign: 'center'}}>{obj.item.survey.surveyTitle}</h2>
<Divider />
<div style={{marginLeft: '20px', marginRight: '20px'}}>
{obj.item.questions.map((subItem, subIndex)=>(
<div key={subIndex.toString()}>
{subItem.questionType==='singleChoice' ?
<div style={{textAlign: "left", marginTop: '10px'}}>
<p>{subItem.questionTitle}</p>
<Radio.Group>
{subItem.questionOptions.map((optItem, optIndex) => (
<div style={{marginTop: '10px'}} key={optIndex.toString()}>
<Radio value={optIndex}>
{optItem}
</Radio>
</div>
))}
</Radio.Group>
</div>
: null}
{subItem.questionType==='multipleChoice' ?
<div style={{textAlign: "left", marginTop: '10px'}}>
<p>{subItem.questionTitle}</p>
{subItem.questionOptions.map((optItem, optIndex) => (
<div style={{marginTop: '10px'}} key={optIndex.toString()}>
<Checkbox>
{optItem}
</Checkbox>
</div>
))}
</div>
: null}
{subItem.questionType==='blankFill' ?
<div style={{textAlign: "left", marginTop: '10px'}}>
<p>{subItem.questionTitle}</p>
{subItem.questionOptions.map((optItem, optIndex) => (
<div style={{marginTop: '10px'}} key={optIndex.toString()}>
{optItem === blank ?
<span style={{float: 'left', margin: '5px'}}>
<Input style={{borderBottom: '2px solid black'}} bordered={false}/>
</span>
:
<span style={{float: 'left', margin: '5px'}}>{optItem}</span>}
</div>
))}
</div>
: null}
{subItem.questionType==='briefAnswer' ?
<div style={{textAlign: "left", marginTop: '10px'}}>
<p>{subItem.questionOptions[0]}</p>
<Input.TextArea/>
</div>
: null}
<Divider/>
</div>
))}
</div>
<Button type="primary" onClick={{submitSurvey}} style={{float: 'right', marginTop: '10px'}}>提交</Button>
</div>
)
}
export default FillSurvey

View File

@ -0,0 +1,7 @@
.survey{
max-width: 1200px;
padding: 20px;
margin: auto;
background-color: rgba(244, 231, 174, 0.07);
border-radius: 10px;
}

View File

@ -9,5 +9,6 @@
}
.task-title{
text-align: left;
font-weight: bold;
font-size: 16px;
}

View File

@ -88,9 +88,9 @@ function MultipleChoice(obj) {
<Radio.Group>
{obj.item.questionOptions.map((subItem, subIndex) => (
<div style={{marginTop: '10px'}} key={subIndex.toString()}>
<Radio value={subIndex}>
<Checkbox>
{subItem}
</Radio>
</Checkbox>
</div>
))}
</Radio.Group>