Merge pull request #22 from lbaf23/feat/export-document
feat: export evidence
This commit is contained in:
commit
a454cedb18
|
@ -562,3 +562,29 @@ func (p *ProjectController) ViewProject() {
|
|||
}
|
||||
p.ServeJSON()
|
||||
}
|
||||
|
||||
// CloneProject
|
||||
// @Title
|
||||
// @Description create project
|
||||
// @Success 200 {object} Response
|
||||
// @Failure 401
|
||||
// @Failure 400
|
||||
// @Failure 403
|
||||
// @router /:id/clone [post]
|
||||
func (p *ProjectController) CloneProject() {
|
||||
pid, err := p.GetInt64(":id")
|
||||
uid := util.GetUserId(p.GetSessionUser())
|
||||
err = models.CloneProject(uid, pid)
|
||||
if err != nil {
|
||||
p.Data["json"] = Response{
|
||||
Code: 400,
|
||||
Msg: err.Error(),
|
||||
}
|
||||
} else {
|
||||
p.Data["json"] = Response{
|
||||
Code: 200,
|
||||
Msg: "复制成功,请到未发布项目中查看",
|
||||
}
|
||||
}
|
||||
p.ServeJSON()
|
||||
}
|
|
@ -77,6 +77,7 @@ func (p *ProjectController) CreateChapterSection() {
|
|||
SectionName: p.GetString("sectionName"),
|
||||
SectionNumber: sectionNumber,
|
||||
ChapterNumber: chapterNumber,
|
||||
SectionMinute: 1,
|
||||
}
|
||||
if err != nil {
|
||||
p.Data["json"] = Response{
|
||||
|
|
|
@ -33,9 +33,6 @@ func (p *Chapter) Delete() (err error) {
|
|||
session := adapter.Engine.NewSession()
|
||||
defer session.Close()
|
||||
session.Begin()
|
||||
|
||||
fmt.Println(p.ProjectId, p.ChapterNumber)
|
||||
|
||||
_, err = session.
|
||||
Exec("update chapter set chapter_number = chapter_number - 1 " +
|
||||
"where project_id = ? and chapter_number > ?", p.ProjectId, p.ChapterNumber)
|
||||
|
@ -76,3 +73,30 @@ func GetChaptersByPid(pid string, uid string) (outline []Outline, err error) {
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
func DeleteProjectChapters(pid int64) (err error) {
|
||||
var chapters []Chapter
|
||||
err = (&Chapter{}).GetEngine().Where("project_id = ?", pid).Find(&chapters)
|
||||
for i:=0; i< len(chapters); i++ {
|
||||
c := chapters[i]
|
||||
cid := c.Id
|
||||
_, err = (&Chapter{}).GetEngine().ID(cid).Delete(&Chapter{})
|
||||
err = DeleteChapterSections(cid)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func CloneProjectChapters(pid int64, newPid int64) (err error) {
|
||||
var chapters []Chapter
|
||||
err = (&Chapter{}).GetEngine().Where("project_id = ?", pid).Find(&chapters)
|
||||
for i:=0; i< len(chapters); i++ {
|
||||
c := chapters[i]
|
||||
cid := c.Id
|
||||
c.Id = 0
|
||||
c.ProjectId = newPid
|
||||
_, err = (&Chapter{}).GetEngine().Insert(&c)
|
||||
newCid := c.Id
|
||||
err = CloneChapterSections(newPid, cid, newCid)
|
||||
}
|
||||
return
|
||||
}
|
|
@ -165,16 +165,9 @@ func (p *Project) UpdateInfo(subjects []*ProjectSubject, skills []*ProjectSkill)
|
|||
}
|
||||
|
||||
func (p *Project) Delete() (err error) {
|
||||
pid := p.Id
|
||||
_, err = p.GetEngine().ID(p.Id).Delete(p)
|
||||
return
|
||||
}
|
||||
|
||||
func GetOutlineByPid(pid string) (c []Outline, err error) {
|
||||
err = adapter.Engine.
|
||||
SQL("select * from chapter left join section s on chapter.id = s.chapter_id where chapter.project_id = 1").
|
||||
// Where("project_id = ?", pid).
|
||||
// Asc("chapter_number").
|
||||
Find(&c)
|
||||
err = DeleteProjectChapters(pid)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -230,4 +223,21 @@ func ViewProject(pid string) (err error) {
|
|||
_, err = adapter.Engine.
|
||||
Exec("update project set read_num = read_num + 1 where id = ?", pid)
|
||||
return
|
||||
}
|
||||
|
||||
func CloneProject(uid string, pid int64) (err error) {
|
||||
var project Project
|
||||
_, err = (&Project{}).GetEngine().ID(pid).Get(&project)
|
||||
project.TeacherId = uid
|
||||
project.Id = 0
|
||||
project.Closed = false
|
||||
project.Published = false
|
||||
project.CreateAt = time.Now()
|
||||
project.ReadNum = 0
|
||||
project.JoinNum = 0
|
||||
project.ProjectTitle = project.ProjectTitle + "-副本"
|
||||
_, err = (&Project{}).GetEngine().Insert(&project)
|
||||
newPid := project.Id
|
||||
err = CloneProjectChapters(pid, newPid)
|
||||
return
|
||||
}
|
|
@ -33,4 +33,18 @@ func GetResourceById(id string) (r Resource, err error) {
|
|||
ID(id).
|
||||
Get(&r)
|
||||
return
|
||||
}
|
||||
|
||||
func DeleteSectionResource(sid int64) (err error) {
|
||||
_, err = (&Resource{}).GetEngine().Where("section_id = ?", sid).Delete(&Resource{})
|
||||
return
|
||||
}
|
||||
|
||||
func CloneSectionResource(sid int64, newSid int64) (err error) {
|
||||
var resource Resource
|
||||
_, err = (&Resource{}).GetEngine().Where("section_id = ?", sid).Get(&resource)
|
||||
resource.SectionId = newSid
|
||||
resource.Id = 0
|
||||
_, err = (&Resource{}).GetEngine().Insert(&resource)
|
||||
return
|
||||
}
|
|
@ -12,7 +12,7 @@ type Section struct {
|
|||
SectionNumber int `json:"sectionNumber" xorm:"index"`
|
||||
ChapterNumber int `json:"chapterNumber" xorm:"index"`
|
||||
|
||||
SectionMinute int `json:"sectionMinute" xorm:"default 10"`
|
||||
SectionMinute int `json:"sectionMinute" xorm:"default 1"`
|
||||
}
|
||||
|
||||
type SectionMinute struct {
|
||||
|
@ -91,4 +91,33 @@ func GetSectionDetailById(sid string) (s SectionDetail, err error) {
|
|||
Join("INNER", "resource", "resource.section_id = section.id").
|
||||
Get(&s)
|
||||
return
|
||||
}
|
||||
|
||||
func DeleteChapterSections(cid int64) (err error) {
|
||||
var sections []Section
|
||||
err = (&Section{}).GetEngine().Where("chapter_id = ?", cid).Find(§ions)
|
||||
for i:=0; i< len(sections); i++ {
|
||||
s := sections[i]
|
||||
sid := s.Id
|
||||
_, err = (&Section{}).GetEngine().ID(sid).Delete(&Section{})
|
||||
err = DeleteSectionResource(sid)
|
||||
err = DeleteTasks(sid)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func CloneChapterSections(newPid int64, cid int64, newCid int64) (err error) {
|
||||
var sections []Section
|
||||
err = (&Section{}).GetEngine().Where("chapter_id = ?", cid).Find(§ions)
|
||||
for i:=0; i< len(sections); i++ {
|
||||
s := sections[i]
|
||||
sid := s.Id
|
||||
s.Id = 0
|
||||
s.ChapterId = newCid
|
||||
_, err = (&Section{}).GetEngine().Insert(&s)
|
||||
newSid := s.Id
|
||||
err = CloneSectionResource(sid, newSid)
|
||||
err = CloneTasks(newPid, sid, newSid)
|
||||
}
|
||||
return
|
||||
}
|
|
@ -73,4 +73,33 @@ func ExchangeQuestion(id1 string, id2 string) (err error) {
|
|||
Exec("update question t1 join question t2 on (t1.id = ? and t2.id = ?) " +
|
||||
"set t1.question_order = t2.question_order, t2.question_order = t1.question_order", id1, id2)
|
||||
return
|
||||
}
|
||||
|
||||
func DeleteSurvey(tid int64) (err error) {
|
||||
var survey Survey
|
||||
_, err = (&Survey{}).GetEngine().Where("task_id = ?", tid).Get(&survey)
|
||||
suid := survey.Id
|
||||
_, err = (&Survey{}).GetEngine().ID(suid).Delete(&Survey{})
|
||||
_, err = (&Question{}).GetEngine().Where("survey_id = ?", suid).Delete(&Question{})
|
||||
return
|
||||
}
|
||||
|
||||
func CloneSurvey(tid int64, newTid int64) (err error) {
|
||||
var survey Survey
|
||||
_, err = (&Survey{}).GetEngine().Where("task_id = ?", tid).Get(&survey)
|
||||
suid := survey.Id
|
||||
survey.Id = 0
|
||||
survey.TaskId = newTid
|
||||
_, err = (&Survey{}).GetEngine().Insert(&survey)
|
||||
newSuid := survey.Id
|
||||
var questions []Question
|
||||
err = (&Question{}).GetEngine().Where("survey_id = ?", suid).Find(&questions)
|
||||
for i:=0; i< len(questions); i++ {
|
||||
q := questions[i]
|
||||
q.Id = 0
|
||||
q.SurveyId = newSuid
|
||||
q.QuestionCount = ""
|
||||
_, err = (&Question{}).GetEngine().Insert(&q)
|
||||
}
|
||||
return
|
||||
}
|
|
@ -190,4 +190,36 @@ func GetProjectTasks(pid string) (t []TaskEvaluate, err error) {
|
|||
Asc("task_order").
|
||||
Find(&t)
|
||||
return
|
||||
}
|
||||
|
||||
func DeleteTasks(sid int64) (err error) {
|
||||
var tasks []Task
|
||||
err = (&Task{}).GetEngine().Where("section_id = ?", sid).Find(&tasks)
|
||||
for i:=0; i<len(tasks); i++ {
|
||||
t := tasks[i]
|
||||
tid := t.Id
|
||||
_, err = (&Task{}).GetEngine().ID(tid).Delete(&Task{})
|
||||
if t.TaskType == "survey" {
|
||||
err = DeleteSurvey(tid)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func CloneTasks(newPid int64, sid int64, newSid int64) (err error) {
|
||||
var tasks []Task
|
||||
err = (&Task{}).GetEngine().Where("section_id = ?", sid).Find(&tasks)
|
||||
for i:=0; i<len(tasks); i++ {
|
||||
t := tasks[i]
|
||||
tid := t.Id
|
||||
t.Id = 0
|
||||
t.ProjectId = newPid
|
||||
t.SectionId = newSid
|
||||
_, err = (&Task{}).GetEngine().Insert(&t)
|
||||
newTid := t.Id
|
||||
if t.TaskType == "survey" {
|
||||
err = CloneSurvey(tid, newTid)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
|
@ -18,6 +18,8 @@
|
|||
"echarts": "^5.1.2",
|
||||
"echarts-for-react": "^3.0.1",
|
||||
"enquire-js": "^0.2.1",
|
||||
"file-saver": "^2.0.5",
|
||||
"html-docx-js": "^0.3.1",
|
||||
"localStorage": "^1.0.4",
|
||||
"lodash": "^4.17.21",
|
||||
"prop-types": "^15.7.2",
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
import { Route, BrowserRouter, Switch } from "react-router-dom";
|
||||
import {Route, BrowserRouter, Switch, Redirect} from "react-router-dom";
|
||||
import './App.less';
|
||||
import AuthCallback from "./pages/User/Auth/AuthCallback";
|
||||
import HeaderLayout from "./pages/component/Layout/HeaderLayout";
|
||||
import StudentEvidenceContent from "./pages/Project/Evidence/component/StudentEvidenceContent";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div className="App">
|
||||
<BrowserRouter>
|
||||
<Route path="/" component={HeaderLayout} />
|
||||
<Route exact path="/callback" component={AuthCallback} />
|
||||
<Route exact path="/" render={() => (
|
||||
<Redirect to="/home"/>
|
||||
)}/>
|
||||
<Route path="/home" component={HeaderLayout} />
|
||||
<Route exact path="/export/project/:projectId/student/:studentId/evidence" component={StudentEvidenceContent} />
|
||||
<Route exact path="/callback" component={AuthCallback} />
|
||||
</BrowserRouter>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -97,6 +97,12 @@ const ProjectApi = {
|
|||
url: `/project/${pid}/view`,
|
||||
method: 'post'
|
||||
})
|
||||
},
|
||||
cloneProject(pid) {
|
||||
return request({
|
||||
url: `/project/${pid}/clone`,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ function LatestProject(obj) {
|
|||
{
|
||||
projects.map((item, index) => (
|
||||
<Col key={index.toString()} {...topColResponsiveProps}>
|
||||
<Link to={`/project/${item.id}/info`}>
|
||||
<Link to={`/home/project/${item.id}/info`}>
|
||||
<Card
|
||||
hoverable
|
||||
bordered={false}
|
||||
|
|
|
@ -22,17 +22,17 @@ class Message extends React.Component {
|
|||
<Layout.Sider breakpoint="lg" collapsedWidth="0">
|
||||
<Menu theme="light" mode="inline" defaultSelectedKeys={['all-message']}>
|
||||
<Menu.Item key="all-message">
|
||||
<Link to="/message/all">
|
||||
<Link to="/home/message/all">
|
||||
全部消息
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="unread-message">
|
||||
<Link to="/message/unread">
|
||||
<Link to="/home/message/unread">
|
||||
未读消息
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="read-message">
|
||||
<Link to="/message/read">
|
||||
<Link to="/home/message/read">
|
||||
已读消息
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
|
@ -41,12 +41,12 @@ class Message extends React.Component {
|
|||
</Affix>
|
||||
<Layout.Content style={{backgroundColor: 'white', marginLeft: '10px'}}>
|
||||
<Switch>
|
||||
<Route exact path="/message" render={() => (
|
||||
<Redirect to="/message/all"/>
|
||||
<Route exact path="/home/message" render={() => (
|
||||
<Redirect to="/home/message/all"/>
|
||||
)}/>
|
||||
<Route exact path="/message/all" component={AllMessage}/>
|
||||
<Route exact path="/message/unread" component={UnreadMessage}/>
|
||||
<Route exact path="/message/read" component={ReadMessage}/>
|
||||
<Route exact path="/home/message/all" component={AllMessage}/>
|
||||
<Route exact path="/home/message/unread" component={UnreadMessage}/>
|
||||
<Route exact path="/home/message/read" component={ReadMessage}/>
|
||||
</Switch>
|
||||
</Layout.Content>
|
||||
</Layout>
|
||||
|
|
|
@ -52,11 +52,11 @@ function InfoEditPage(obj) {
|
|||
|
||||
const loadSubjectsAndSkills = () => {
|
||||
ProjectApi.getSubjectsAndSkills(pid)
|
||||
.then(res=>{
|
||||
.then(res => {
|
||||
if (res.data.code === 200) {
|
||||
if (res.data.subjects !== null) {
|
||||
let s = res.data.subjects
|
||||
for (let i=0; i<iniSubjects.length; i++) {
|
||||
for (let i = 0; i < iniSubjects.length; i++) {
|
||||
if (s.indexOf(iniSubjects[i]) < 0) {
|
||||
s.push(iniSubjects[i])
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ function InfoEditPage(obj) {
|
|||
}
|
||||
if (res.data.skills !== null) {
|
||||
let s = res.data.skills
|
||||
for (let i=0; i<iniSkills.length; i++) {
|
||||
for (let i = 0; i < iniSkills.length; i++) {
|
||||
if (s.indexOf(iniSkills[i]) < 0) {
|
||||
s.push(iniSkills[i])
|
||||
}
|
||||
|
@ -74,7 +74,9 @@ function InfoEditPage(obj) {
|
|||
}
|
||||
}
|
||||
})
|
||||
.catch(e=>{console.log(e)})
|
||||
.catch(e => {
|
||||
console.log(e)
|
||||
})
|
||||
}
|
||||
|
||||
const changeTitle = value => {
|
||||
|
@ -146,7 +148,7 @@ function InfoEditPage(obj) {
|
|||
if (res.data.code === 200) {
|
||||
message.success(res.data.msg)
|
||||
setTimeout(() => {
|
||||
window.location.href = `/project/${pid}/outline/edit`
|
||||
window.location.href = `/home/project/${pid}/outline/edit`
|
||||
}, 200)
|
||||
}
|
||||
})
|
||||
|
@ -161,7 +163,7 @@ function InfoEditPage(obj) {
|
|||
onFinish();
|
||||
} else {
|
||||
setNextPageLoading(false)
|
||||
window.location.href = `/project/${pid}/outline/edit`
|
||||
window.location.href = `/home/project/${pid}/outline/edit`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ class EditInfo extends React.PureComponent {
|
|||
}
|
||||
|
||||
back = e => {
|
||||
window.location.href = `/project/${this.state.pid}/info`
|
||||
window.location.href = `/home/project/${this.state.pid}/info`
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
|
@ -27,6 +27,8 @@ function OutlineEditPage(obj) {
|
|||
const [chapterName, setChapterName] = useState('')
|
||||
const [sectionName, setSectionName] = useState('')
|
||||
|
||||
const [btLoading, setBtLoading] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
getChapters()
|
||||
}, [])
|
||||
|
@ -105,6 +107,7 @@ function OutlineEditPage(obj) {
|
|||
return
|
||||
}
|
||||
if (opt === 'modify') {
|
||||
setBtLoading(true)
|
||||
let c = {
|
||||
id: chapter.id,
|
||||
projectId: chapter.projectId,
|
||||
|
@ -113,6 +116,7 @@ function OutlineEditPage(obj) {
|
|||
}
|
||||
ChapterApi.updateProjectChapter(c)
|
||||
.then((res) => {
|
||||
setBtLoading(false)
|
||||
if (res.data.code === 200) {
|
||||
setChapterModalVisible(false)
|
||||
message.success(res.data.msg)
|
||||
|
@ -126,6 +130,7 @@ function OutlineEditPage(obj) {
|
|||
console.log(e)
|
||||
})
|
||||
} else if (opt === 'add') {
|
||||
setBtLoading(true)
|
||||
let len = chapters.length
|
||||
let l = 0
|
||||
if (len > 0) {
|
||||
|
@ -134,6 +139,7 @@ function OutlineEditPage(obj) {
|
|||
let cp = {chapterName: chapterName, chapterNumber: l, projectId: pid}
|
||||
ChapterApi.createProjectChapter(cp)
|
||||
.then((res) => {
|
||||
setBtLoading(false)
|
||||
setChapterModalVisible(false)
|
||||
setChapterName('')
|
||||
if (res.data.code === 200) {
|
||||
|
@ -153,6 +159,7 @@ function OutlineEditPage(obj) {
|
|||
return
|
||||
}
|
||||
if (opt === 'modify') {
|
||||
setBtLoading(true)
|
||||
let s = {
|
||||
id: section.id,
|
||||
chapterId: section.chapterId,
|
||||
|
@ -162,9 +169,9 @@ function OutlineEditPage(obj) {
|
|||
}
|
||||
SectionApi.updateChapterSection(pid, s)
|
||||
.then((res) => {
|
||||
setBtLoading(false)
|
||||
if (res.data.code === 200) {
|
||||
setSectionModalVisible(false)
|
||||
|
||||
chapters[index].sections[subIndex].sectionName = sectionName
|
||||
setChapters([...chapters])
|
||||
setSectionName('')
|
||||
|
@ -174,6 +181,7 @@ function OutlineEditPage(obj) {
|
|||
console.log(e)
|
||||
})
|
||||
} else if (opt === 'add') {
|
||||
setBtLoading(true)
|
||||
let l = 0
|
||||
if (chapters[index].sections !== undefined && chapters[index].sections !== null) {
|
||||
let len = chapters[index].sections.length
|
||||
|
@ -189,6 +197,8 @@ function OutlineEditPage(obj) {
|
|||
}
|
||||
SectionApi.createChapterSection(pid, sec)
|
||||
.then((res) => {
|
||||
setBtLoading(false)
|
||||
|
||||
setSectionModalVisible(false)
|
||||
setSectionName('')
|
||||
if (res.data.code === 200) {
|
||||
|
@ -291,7 +301,7 @@ function OutlineEditPage(obj) {
|
|||
<Menu.Item key={index.toString() + subIndex.toString()}>
|
||||
{util.FormatSectionName(subItem.sectionName, subItem.chapterNumber, subItem.sectionNumber)}
|
||||
<span style={{float: 'right', marginRight: '20px'}}>
|
||||
<Link to={`/project/${pid}/section/${subItem.id}/edit`}>
|
||||
<Link to={`/home/project/${pid}/section/${subItem.id}/edit`}>
|
||||
<Button type="text">编辑资源</Button>
|
||||
</Link>
|
||||
|
||||
|
@ -321,15 +331,16 @@ function OutlineEditPage(obj) {
|
|||
<Button type="round" style={{margin: '5px'}} onClick={addChapter}>添加章节</Button>
|
||||
</div>
|
||||
<div style={{textAlign: 'right', marginTop: '20px', marginRight: '20px'}}>
|
||||
<Link to={`/project/${pid}/info`}>
|
||||
<Link to={`/home/project/${pid}/info`}>
|
||||
<Button type="primary" size="middle" style={{float: 'right'}}>完成</Button>
|
||||
</Link>
|
||||
<Link to={`/project/${pid}/info/edit`}>
|
||||
<Link to={`/home/project/${pid}/info/edit`}>
|
||||
<Button size="middle" style={{float: 'right', marginRight: '20px'}}>上一页</Button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<Modal title="" visible={chapterModalVisible} onOk={doChapter} onCancel={cancelDoChapter}>
|
||||
<Modal title="" visible={chapterModalVisible} onOk={doChapter} confirmLoading={btLoading}
|
||||
onCancel={cancelDoChapter}>
|
||||
<br/>
|
||||
<Row>
|
||||
<Col span={3}>
|
||||
|
@ -341,7 +352,7 @@ function OutlineEditPage(obj) {
|
|||
</Row>
|
||||
</Modal>
|
||||
|
||||
<Modal visible={sectionModalVisible} onOk={doSection} onCancel={cancelDoSection}>
|
||||
<Modal visible={sectionModalVisible} onOk={doSection} confirmLoading={btLoading} onCancel={cancelDoSection}>
|
||||
<br/>
|
||||
<Row>
|
||||
<Col span={3}>
|
||||
|
|
|
@ -19,7 +19,7 @@ class EditOutline extends React.PureComponent {
|
|||
}
|
||||
|
||||
back = e => {
|
||||
this.props.history.push(`/project/${this.state.pid}/info/`)
|
||||
this.props.history.push(`/home/project/${this.state.pid}/info/`)
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
|
@ -27,7 +27,7 @@ function SectionEditPage(obj) {
|
|||
|
||||
|
||||
const back = e => {
|
||||
window.location.href = `/project/${pid}/outline/edit`
|
||||
window.location.href = `/home/project/${pid}/outline/edit`
|
||||
}
|
||||
|
||||
|
||||
|
@ -49,7 +49,7 @@ function SectionEditPage(obj) {
|
|||
<StudentTask section={section} pid={pid}/>
|
||||
</div>
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<Link to={`/project/${pid}/section/${sid}/preview?back=/project/${pid}/section/${sid}/edit`}>
|
||||
<Link to={`/home/project/${pid}/section/${sid}/preview?back=/project/${pid}/section/${sid}/edit`}>
|
||||
<Button style={{marginBottom: '20px'}}>预览</Button>
|
||||
</Link>
|
||||
</div>
|
||||
|
|
|
@ -102,7 +102,7 @@ function StudentTask(obj) {
|
|||
}
|
||||
const gotoSurvey = (item, index) => {
|
||||
saveContent(item, index)
|
||||
window.location.href = `/project/${pid}/section/${obj.section.id}/task/${item.id}/survey/edit`
|
||||
window.location.href = `/home/project/${pid}/section/${obj.section.id}/task/${item.id}/survey/edit`
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -146,7 +146,7 @@ function SurveyEditPage(obj) {
|
|||
setEditing([...editing])
|
||||
}
|
||||
const back = e => {
|
||||
window.location.href = `/project/${pid}/section/${sid}/edit`
|
||||
window.location.href = `/home/project/${pid}/section/${sid}/edit`
|
||||
}
|
||||
|
||||
const getType = t => {
|
||||
|
|
|
@ -121,6 +121,7 @@ function StudentEvidence(obj) {
|
|||
<List
|
||||
size="large"
|
||||
dataSource={item.sections}
|
||||
locale={{emptyText: '--'}}
|
||||
renderItem={
|
||||
item => (
|
||||
<List.Item>
|
||||
|
|
|
@ -0,0 +1,261 @@
|
|||
import React, {useEffect, useState} from "react";
|
||||
import {Button, Checkbox, Divider, List, Radio} from "antd";
|
||||
|
||||
import TaskApi from "../../../../api/TaskApi";
|
||||
import ChapterApi from "../../../../api/ChapterApi";
|
||||
import util from "../../../component/Util"
|
||||
import htmlDocx from 'html-docx-js/dist/html-docx';
|
||||
import saveAs from 'file-saver';
|
||||
import Question from "../../CreateProject/Survey/component/Question";
|
||||
|
||||
const blank = Question.blank
|
||||
|
||||
|
||||
function StudentEvidenceContent(obj) {
|
||||
const pid = obj.match.params.projectId
|
||||
const studentId = obj.match.params.studentId
|
||||
const [tasks, setTasks] = useState([])
|
||||
const [learning, setLearning] = useState(false)
|
||||
const [editable, setEditable] = useState(false)
|
||||
const [teacherScore, setTeacherScore] = useState(false)
|
||||
const [showCount, setShowCount] = useState(false)
|
||||
const [chapters, setChapters] = useState([])
|
||||
const [showMinute, setShowMinute] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
getChapters()
|
||||
getTasks()
|
||||
setTimeout(() => {
|
||||
saveFile()
|
||||
}, 500)
|
||||
}, []);
|
||||
const getChapters = () => {
|
||||
ChapterApi.getProjectChapters(pid, studentId)
|
||||
.then((res) => {
|
||||
if (res.data.chapters === null) {
|
||||
setChapters([])
|
||||
} else {
|
||||
setChapters(res.data.chapters)
|
||||
setShowMinute(res.data.showMinute)
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e)
|
||||
})
|
||||
}
|
||||
const getTasks = () => {
|
||||
TaskApi.getProjectTasksDetail(pid, studentId)
|
||||
.then(res => {
|
||||
if (res.data.code === 200) {
|
||||
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)
|
||||
setEditable(res.data.editable)
|
||||
setTeacherScore(res.data.teacherScore)
|
||||
setShowCount(res.data.showCount)
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e)
|
||||
})
|
||||
}
|
||||
|
||||
const getScore = (score, weight) => {
|
||||
return (score * weight / 100).toFixed(2)
|
||||
}
|
||||
const getPercent = (item) => {
|
||||
let p = ((item.learnMinute + item.learnSecond / 60) / item.sectionMinute * 100).toFixed(1)
|
||||
if (p > 100) {
|
||||
return 100
|
||||
}
|
||||
return p
|
||||
}
|
||||
const saveFile = () => {
|
||||
let content = document.getElementById("evidence").innerHTML
|
||||
let page = `<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body>${content}</body></html>`
|
||||
const converted = htmlDocx.asBlob(page)
|
||||
saveAs(converted, `${studentId}.docx`)
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{padding: '40px'}}>
|
||||
<div style={{float: 'right'}}><Button onClick={saveFile}>保存</Button></div>
|
||||
|
||||
<div id="evidence">
|
||||
<h2>一、章节学习时长</h2>
|
||||
{chapters.map((item, index) => (
|
||||
<div key={index.toString()} style={{textAlign: 'left'}}>
|
||||
<p style={{fontWeight: 'bold', fontSize: '16px'}}>
|
||||
{util.FormatChapterName(item.chapterName, item.chapterNumber)}
|
||||
</p>
|
||||
{(item.sections === null || item.sections === undefined) ?
|
||||
null
|
||||
:
|
||||
<>
|
||||
<List
|
||||
size="large"
|
||||
dataSource={item.sections}
|
||||
locale={{emptyText: '--'}}
|
||||
renderItem={
|
||||
item => (
|
||||
<List.Item>
|
||||
<p>{util.FormatSectionName(item.sectionName, item.chapterNumber, item.sectionNumber)}</p>
|
||||
要求学习时长:{item.sectionMinute}分钟,
|
||||
学生学习时长:{item.learnMinute}分{item.learnSecond}秒,
|
||||
学习进度:{getPercent(item)}%
|
||||
</List.Item>
|
||||
)
|
||||
}
|
||||
/><br/>
|
||||
</>
|
||||
}
|
||||
</div>
|
||||
))}
|
||||
|
||||
<h2>二、学生任务</h2>
|
||||
|
||||
<List
|
||||
size="large"
|
||||
dataSource={tasks}
|
||||
locale={{emptyText: '--'}}
|
||||
renderItem={
|
||||
item => (
|
||||
<List.Item>
|
||||
<div style={{textAlign: 'left'}}>
|
||||
<div>
|
||||
<p
|
||||
style={{fontWeight: 'bold'}}>{util.FormatSectionName(item.taskTitle, item.chapterNumber, item.sectionNumber)}</p>
|
||||
{item.submitted ?
|
||||
<span style={{color: 'green'}}>已提交</span>
|
||||
:
|
||||
<span>未提交</span>
|
||||
},
|
||||
{item.submit.scored ?
|
||||
<span style={{color: 'green'}}>已打分</span>
|
||||
:
|
||||
<span>未打分</span>
|
||||
}
|
||||
任务权重:{item.taskWeight}%,
|
||||
学生得分:{getScore(item.submit.score, item.taskWeight)}/{item.taskWeight}
|
||||
</div>
|
||||
<div>
|
||||
标题:
|
||||
<p>{item.taskTitle}</p>
|
||||
描述:
|
||||
<p>{item.taskIntroduce}</p>
|
||||
{item.taskType === 'file' ?
|
||||
<div>
|
||||
<p>{item.submit.submitContent}</p>
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
{item.taskType === 'comment' ?
|
||||
<div>
|
||||
学生提交:<br/>{item.submit.submitContent}
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
{item.taskType === 'survey' ?
|
||||
<>学生提交:<br/>
|
||||
<h2 style={{textAlign: 'center'}}>{item.survey.surveyTitle}</h2>
|
||||
<div style={{marginLeft: '20px', marginRight: '20px'}}>
|
||||
{item.questions.map((subItem, subIndex) => (
|
||||
<div key={subIndex.toString()}>
|
||||
{subItem.questionType === 'singleChoice' || subItem.questionType === 'scale5' || subItem.questionType === 'scale7' ?
|
||||
<div style={{textAlign: "left", marginTop: '10px'}}>
|
||||
<p>{subItem.questionTitle}</p>
|
||||
<Radio.Group value={item.choices[subIndex].choiceOptions[0]}>
|
||||
{subItem.questionOptions.map((optItem, optIndex) => (
|
||||
<div style={{marginTop: '10px'}} key={optIndex.toString()}>
|
||||
<Radio value={optIndex.toString()}>
|
||||
{optItem}
|
||||
</Radio>
|
||||
</div>
|
||||
))}
|
||||
</Radio.Group>
|
||||
</div>
|
||||
: null}
|
||||
{subItem.questionType === 'multipleChoice' ?
|
||||
<div style={{textAlign: "left", marginTop: '10px'}}>
|
||||
<p>{subItem.questionTitle}</p>
|
||||
<Checkbox.Group value={item.choices[subIndex].choiceOptions}>
|
||||
{subItem.questionOptions.map((optItem, optIndex) => (
|
||||
<div key={optIndex.toString()} style={{marginTop: '10px'}}>
|
||||
<Checkbox value={optIndex.toString()}>
|
||||
{optItem}
|
||||
</Checkbox>
|
||||
</div>
|
||||
))}
|
||||
</Checkbox.Group>
|
||||
</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'}}>
|
||||
<u> {item.choices[subIndex].choiceOptions[optIndex]} </u>
|
||||
</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>
|
||||
{item.choices[subIndex].choiceOptions[0]}
|
||||
</div>
|
||||
: null}
|
||||
|
||||
<Divider/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
</>
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</List.Item>
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default StudentEvidenceContent
|
|
@ -1,8 +1,9 @@
|
|||
import React, {useEffect} from "react";
|
||||
import {Card, PageHeader} from "antd";
|
||||
import {Button, Card, PageHeader} from "antd";
|
||||
import DocumentTitle from 'react-document-title';
|
||||
import StudentEvidence from "./component/StudentEvidence";
|
||||
|
||||
|
||||
function Evidence(obj) {
|
||||
const pid = obj.match.params.pid
|
||||
const sid = obj.match.params.sid
|
||||
|
@ -11,9 +12,12 @@ function Evidence(obj) {
|
|||
}, [])
|
||||
|
||||
const back = e => {
|
||||
window.location.href = `/project/${pid}/info?menu=student-admin`
|
||||
window.location.href = `/home/project/${pid}/info?menu=student-admin`
|
||||
}
|
||||
|
||||
const exportFile = e => {
|
||||
window.open(`/export/project/${pid}/student/${sid}/evidence`)
|
||||
}
|
||||
return (
|
||||
<DocumentTitle title="Project">
|
||||
<div style={{backgroundColor: '#f2f4f5', minHeight: '100vh'}}>
|
||||
|
@ -41,12 +45,17 @@ function Evidence(obj) {
|
|||
maxWidth: '1200px',
|
||||
}}
|
||||
>
|
||||
<Card>
|
||||
<StudentEvidence
|
||||
pid={pid}
|
||||
studentId={sid}
|
||||
/>
|
||||
</Card>
|
||||
<div style={{padding: '10px', textAlign: 'center'}}>
|
||||
<Button onClick={exportFile}>导出</Button>
|
||||
</div>
|
||||
<div>
|
||||
<Card>
|
||||
<StudentEvidence
|
||||
pid={pid}
|
||||
studentId={sid}
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
import React from 'react';
|
||||
import DocumentTitle from 'react-document-title';
|
||||
import {Link, Redirect, Route, Switch} from 'react-router-dom'
|
||||
import {CheckCircleOutlined, CheckOutlined, CopyOutlined, HighlightOutlined, SyncOutlined, StarFilled} from "@ant-design/icons";
|
||||
import {
|
||||
CheckCircleOutlined,
|
||||
CheckOutlined,
|
||||
CopyOutlined,
|
||||
HighlightOutlined,
|
||||
StarFilled,
|
||||
SyncOutlined
|
||||
} from "@ant-design/icons";
|
||||
|
||||
import PublishedProject from "../PublishedProject";
|
||||
import EditingProject from "../EditingProject";
|
||||
|
@ -21,7 +28,7 @@ class MyProject extends React.PureComponent {
|
|||
}
|
||||
|
||||
changeMenu = (e) => {
|
||||
if (e !== undefined ) {
|
||||
if (e !== undefined) {
|
||||
this.setState({menu: e.key})
|
||||
return
|
||||
}
|
||||
|
@ -43,7 +50,7 @@ class MyProject extends React.PureComponent {
|
|||
ProjectApi.createProject()
|
||||
.then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
window.open(`/project/${res.data.data}/info/edit`)
|
||||
window.open(`/home/project/${res.data.data}/info/edit`)
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
|
@ -68,26 +75,26 @@ class MyProject extends React.PureComponent {
|
|||
defaultSelectedKeys={['published']}
|
||||
className="menu-bar"
|
||||
selectedKeys={[menu]}
|
||||
onClick={e=>this.changeMenu(e)}
|
||||
onClick={e => this.changeMenu(e)}
|
||||
mode="inline"
|
||||
>
|
||||
<Menu.Item key="published" icon={<CheckCircleOutlined/>}>
|
||||
<Link to="/my-project/published">
|
||||
<Link to="/home/my-project/published">
|
||||
已发布
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="editing" icon={<HighlightOutlined/>}>
|
||||
<Link to="/my-project/editing">
|
||||
<Link to="/home/my-project/editing">
|
||||
未发布
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="finished" icon={<CopyOutlined/>}>
|
||||
<Link to="/my-project/finished">
|
||||
<Link to="/home/my-project/finished">
|
||||
已结束
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="favourite" icon={<StarFilled />}>
|
||||
<Link to="/my-project/favourite">
|
||||
<Menu.Item key="favourite" icon={<StarFilled/>}>
|
||||
<Link to="/home/my-project/favourite">
|
||||
收藏夹
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
|
@ -97,21 +104,21 @@ class MyProject extends React.PureComponent {
|
|||
defaultSelectedKeys={['learning']}
|
||||
className="menu-bar"
|
||||
selectedKeys={[menu]}
|
||||
onClick={e=>this.changeMenu(e)}
|
||||
onClick={e => this.changeMenu(e)}
|
||||
mode="inline"
|
||||
>
|
||||
<Menu.Item key="learning" icon={<SyncOutlined/>}>
|
||||
<Link to="/my-project/learning">
|
||||
<Link to="/home/my-project/learning">
|
||||
进行中
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="finished" icon={<CheckOutlined/>}>
|
||||
<Link to="/my-project/finished">
|
||||
<Link to="/home/my-project/finished">
|
||||
已完成
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="favourite" icon={<StarFilled />}>
|
||||
<Link to="/my-project/favourite">
|
||||
<Menu.Item key="favourite" icon={<StarFilled/>}>
|
||||
<Link to="/home/my-project/favourite">
|
||||
收藏夹
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
|
@ -137,22 +144,22 @@ class MyProject extends React.PureComponent {
|
|||
<Layout.Content style={{marginLeft: '10px'}}>
|
||||
{this.props.account.tag === '老师' ?
|
||||
<Switch>
|
||||
<Route exact path="/my-project" render={() => (
|
||||
<Redirect to="/my-project/published"/>
|
||||
<Route exact path="/home/my-project" render={() => (
|
||||
<Redirect to="/home/my-project/published"/>
|
||||
)}/>
|
||||
<Route exact path="/my-project/published" component={PublishedProject}/>
|
||||
<Route exact path="/my-project/editing" component={EditingProject}/>
|
||||
<Route exact path="/my-project/finished" component={FinishedProject}/>
|
||||
<Route exact path="/my-project/favourite" component={FavouriteProject}/>
|
||||
<Route exact path="/home/my-project/published" component={PublishedProject}/>
|
||||
<Route exact path="/home/my-project/editing" component={EditingProject}/>
|
||||
<Route exact path="/home/my-project/finished" component={FinishedProject}/>
|
||||
<Route exact path="/home/my-project/favourite" component={FavouriteProject}/>
|
||||
</Switch>
|
||||
:
|
||||
<Switch>
|
||||
<Route exact path="/my-project" render={() => (
|
||||
<Redirect to="/my-project/learning"/>
|
||||
<Route exact path="/home/my-project" render={() => (
|
||||
<Redirect to="/home/my-project/learning"/>
|
||||
)}/>
|
||||
<Route exact path="/my-project/learning" component={LearningProject}/>
|
||||
<Route exact path="/my-project/finished" component={FinishedProject}/>
|
||||
<Route exact path="/my-project/favourite" component={FavouriteProject}/>
|
||||
<Route exact path="/home/my-project/learning" component={LearningProject}/>
|
||||
<Route exact path="/home/my-project/finished" component={FinishedProject}/>
|
||||
<Route exact path="/home/my-project/favourite" component={FavouriteProject}/>
|
||||
</Switch>
|
||||
}
|
||||
</Layout.Content>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, {useEffect, useState} from "react";
|
||||
import React from "react";
|
||||
import {BackTop, Card, PageHeader} from "antd";
|
||||
import DocumentTitle from 'react-document-title';
|
||||
|
||||
|
@ -10,64 +10,64 @@ 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)
|
||||
const backUrl = url.get('back')
|
||||
|
||||
const sid = obj.match.params.sid
|
||||
const pid = obj.match.params.pid
|
||||
const [section, setSection] = useState({resource: {}})
|
||||
const [tasks, setTasks] = useState([])
|
||||
const [learning, setLearning] = useState(false)
|
||||
const [editable, setEditable] = useState(false)
|
||||
const [showCount, setShowCount] = useState(false)
|
||||
|
||||
const [minute, setMinute] = useState(0)
|
||||
const [second, setSecond] = useState(0)
|
||||
const [timer, setTimer] = useState(null)
|
||||
let s = 0
|
||||
let m = 0
|
||||
|
||||
useEffect(() => {
|
||||
getSectionDetail()
|
||||
getTasks()
|
||||
}, [])
|
||||
useEffect(() => {
|
||||
if (learning) {
|
||||
window.onbeforeunload = leave
|
||||
class PreviewSection extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
let url = new URLSearchParams(this.props.location.search)
|
||||
const backUrl = url.get('back')
|
||||
this.state = {
|
||||
backUrl: backUrl,
|
||||
sid: this.props.match.params.sid,
|
||||
pid: this.props.match.params.pid,
|
||||
section: {resource: {}},
|
||||
tasks: [],
|
||||
learning: false,
|
||||
editable: false,
|
||||
showCount: false,
|
||||
timer: null,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
}
|
||||
}, [learning])
|
||||
const leave = () => {
|
||||
if (timer != null) {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
let data = {
|
||||
learnMinute: m,
|
||||
learnSecond: s
|
||||
}
|
||||
StudentApi.updateLearnSection(pid, sid, data)
|
||||
.then(res => {
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e)
|
||||
})
|
||||
window.removeEventListener("onbeforeunload", leave)
|
||||
}
|
||||
|
||||
const getSectionDetail = () => {
|
||||
SectionApi.getSectionDetail(sid, pid)
|
||||
componentDidMount() {
|
||||
this.getSectionDetail()
|
||||
this.getTasks()
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.state.learning) {
|
||||
if (this.state.timer != null) {
|
||||
clearTimeout(this.state.timer)
|
||||
}
|
||||
let data = {
|
||||
learnMinute: this.state.minute,
|
||||
learnSecond: this.state.second
|
||||
}
|
||||
StudentApi.updateLearnSection(this.state.pid, this.state.sid, data)
|
||||
.then(res => {
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
getSectionDetail = () => {
|
||||
SectionApi.getSectionDetail(this.state.sid, this.state.pid)
|
||||
.then(res => {
|
||||
setSection(res.data.section)
|
||||
this.setState({
|
||||
section: res.data.section
|
||||
})
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e)
|
||||
})
|
||||
}
|
||||
const getTasks = () => {
|
||||
TaskApi.getSectionTasks(sid, pid)
|
||||
getTasks = () => {
|
||||
TaskApi.getSectionTasks(this.state.sid, this.state.pid)
|
||||
.then(res => {
|
||||
if (res.data.tasks === null) {
|
||||
setTasks([])
|
||||
} else {
|
||||
let t = res.data.tasks
|
||||
for (let i = 0; i < t.length; i++) {
|
||||
|
@ -93,118 +93,133 @@ function PreviewSection(obj) {
|
|||
}
|
||||
}
|
||||
}
|
||||
setTasks(t)
|
||||
this.setState({
|
||||
tasks: t
|
||||
})
|
||||
}
|
||||
setLearning(res.data.learning)
|
||||
setEditable(res.data.editable)
|
||||
setShowCount(res.data.showCount)
|
||||
this.setState({
|
||||
learning: res.data.learning,
|
||||
editable: res.data.editable,
|
||||
showCount: res.data.showCount
|
||||
})
|
||||
|
||||
if (res.data.learning) {
|
||||
getTimer()
|
||||
if (res.data.learning && this.state.timer === null) {
|
||||
this.setTimer()
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e)
|
||||
})
|
||||
}
|
||||
const getTimer = () => {
|
||||
StudentApi.getLearnSection(pid, sid)
|
||||
setTimer = () => {
|
||||
StudentApi.getLearnSection(this.state.pid, this.state.sid)
|
||||
.then(res => {
|
||||
if (res.data.code === 200) {
|
||||
setSecond(res.data.data.learnSecond)
|
||||
setMinute(res.data.data.learnMinute)
|
||||
s = res.data.data.learnSecond
|
||||
m = res.data.data.learnMinute
|
||||
let m = res.data.data.learnMinute
|
||||
let s = res.data.data.learnSecond
|
||||
this.setState({
|
||||
minute: m,
|
||||
second: s
|
||||
})
|
||||
if (this.state.timer !== null) {
|
||||
clearTimeout(this.state.timer)
|
||||
}
|
||||
this.state.timer = setTimeout(this.count, 1000)
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e)
|
||||
})
|
||||
|
||||
setTimeout(count, 1000)
|
||||
}
|
||||
const count = () => {
|
||||
if (s === 30) {
|
||||
s = 0
|
||||
m++
|
||||
setMinute(m)
|
||||
count = () => {
|
||||
if (this.state.second >= 60) {
|
||||
this.setState({
|
||||
second: 0,
|
||||
minute: ++this.state.minute
|
||||
})
|
||||
} else {
|
||||
s++
|
||||
this.setState({
|
||||
second: ++this.state.second
|
||||
})
|
||||
}
|
||||
setSecond(s)
|
||||
setTimeout(count, 1000)
|
||||
this.state.timer = setTimeout(this.count, 1000)
|
||||
}
|
||||
const back = e => {
|
||||
if (backUrl === undefined || backUrl === null) {
|
||||
window.location.href = `/project/${pid}/section/${sid}/edit`
|
||||
back = e => {
|
||||
if (this.state.backUrl === undefined || this.state.backUrl === null) {
|
||||
this.props.history.push(`/project/${this.state.pid}/section/${this.state.sid}/edit`)
|
||||
} else {
|
||||
window.location.href = backUrl
|
||||
this.props.history.push(this.state.backUrl)
|
||||
}
|
||||
}
|
||||
const setTaskItem = (item, index) => {
|
||||
tasks[index] = item
|
||||
setTasks([...tasks])
|
||||
setTaskItem = (item, index) => {
|
||||
this.state.tasks[index] = item
|
||||
this.setState({
|
||||
tasks: [...this.state.tasks]
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<DocumentTitle title="Project">
|
||||
<div style={{backgroundColor: '#f2f4f5', minHeight: '100vh'}}>
|
||||
<BackTop/>
|
||||
<PageHeader
|
||||
className="site-page-header"
|
||||
onBack={back}
|
||||
title="返回"
|
||||
subTitle="我的项目"
|
||||
/>
|
||||
<div style={{padding: '20px', margin: 'auto'}}>
|
||||
<Card>
|
||||
<h2 style={{fontWeight: 'bold'}}>
|
||||
{util.FormatSectionName(section.sectionName, section.chapterNumber, section.sectionNumber)}
|
||||
</h2>
|
||||
{learning ?
|
||||
<span style={{float: 'right'}}>{minute} : {second}</span>
|
||||
: null}
|
||||
</Card>
|
||||
<Card className="resource-card">
|
||||
<div dangerouslySetInnerHTML={{__html: section.resource.content}}/>
|
||||
</Card>
|
||||
<Card className="resource-card">
|
||||
<p className="card-title">文件资源</p>
|
||||
<p>{section.resource.fileTitle}</p>
|
||||
<p>{section.resource.fileIntroduce}</p>
|
||||
</Card>
|
||||
{tasks.map((item, index) => (
|
||||
<Card className="resource-card" key={index.toString()}>
|
||||
<p className="card-title">学生任务
|
||||
{item.submitted ?
|
||||
<span className="submit-status" style={{color: 'green'}}>
|
||||
权重占比 {item.taskWeight} % 已提交 {util.FilterTime(item.submit.createAt)}
|
||||
</span>
|
||||
:
|
||||
<span className="submit-status" style={{color: 'gray'}}>
|
||||
权重占比 {item.taskWeight} % 未提交
|
||||
</span>
|
||||
}
|
||||
</p>
|
||||
|
||||
<TaskCard
|
||||
pid={pid}
|
||||
item={item}
|
||||
index={index}
|
||||
learning={learning}
|
||||
editable={editable}
|
||||
showCount={showCount}
|
||||
setTaskItem={setTaskItem}
|
||||
getTasks={getTasks}
|
||||
/>
|
||||
render() {
|
||||
const {section, tasks, learning, pid, editable, showCount, minute, second} = this.state
|
||||
return (
|
||||
<DocumentTitle title="Project">
|
||||
<div style={{backgroundColor: '#f2f4f5', minHeight: '100vh'}}>
|
||||
<BackTop/>
|
||||
<PageHeader
|
||||
className="site-page-header"
|
||||
onBack={this.back}
|
||||
title="返回"
|
||||
subTitle="我的项目"
|
||||
/>
|
||||
<div style={{padding: '20px', margin: 'auto'}}>
|
||||
<Card>
|
||||
<h2 style={{fontWeight: 'bold'}}>
|
||||
{util.FormatSectionName(section.sectionName, section.chapterNumber, section.sectionNumber)}
|
||||
</h2>
|
||||
{learning ?
|
||||
<span style={{float: 'right'}}>{minute} : {second}</span>
|
||||
: null}
|
||||
</Card>
|
||||
))
|
||||
}
|
||||
<Card className="resource-card">
|
||||
<div dangerouslySetInnerHTML={{__html: section.resource.content}}/>
|
||||
</Card>
|
||||
<Card className="resource-card">
|
||||
<p className="card-title">文件资源</p>
|
||||
<p>{section.resource.fileTitle}</p>
|
||||
<p>{section.resource.fileIntroduce}</p>
|
||||
</Card>
|
||||
{tasks.map((item, index) => (
|
||||
<Card className="resource-card" key={index.toString()}>
|
||||
<p className="card-title">学生任务
|
||||
{item.submitted ?
|
||||
<span className="submit-status" style={{color: 'green'}}>
|
||||
权重占比 {item.taskWeight} % 已提交 {util.FilterTime(item.submit.createAt)}
|
||||
</span>
|
||||
:
|
||||
<span className="submit-status" style={{color: 'gray'}}>
|
||||
权重占比 {item.taskWeight} % 未提交
|
||||
</span>
|
||||
}
|
||||
</p>
|
||||
|
||||
<TaskCard
|
||||
pid={pid}
|
||||
item={item}
|
||||
index={index}
|
||||
learning={learning}
|
||||
editable={editable}
|
||||
showCount={showCount}
|
||||
setTaskItem={this.setTaskItem}
|
||||
getTasks={this.getTasks}
|
||||
/>
|
||||
</Card>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
<br/>
|
||||
</div>
|
||||
<br/>
|
||||
</div>
|
||||
</DocumentTitle>
|
||||
)
|
||||
</DocumentTitle>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default PreviewSection
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import React, {useEffect, useState} from 'react';
|
||||
import {Avatar, Button, Comment, Form, Input, Pagination, message, Tooltip, Popconfirm, Switch} from 'antd';
|
||||
import {Avatar, Button, Comment, Form, Input, message, Pagination, Popconfirm, Switch, Tooltip} from 'antd';
|
||||
import {DeleteOutlined} from "@ant-design/icons"
|
||||
import QueueAnim from 'rc-queue-anim';
|
||||
|
||||
import CommentApi from "../../../../api/CommentApi"
|
||||
import util from "../../../component/Util"
|
||||
|
||||
const {TextArea} = Input;
|
||||
|
||||
|
||||
|
@ -21,13 +22,13 @@ function ProjectComment(obj) {
|
|||
|
||||
const updateCommentList = (p, size, isTeacher) => {
|
||||
let query = {
|
||||
from: (p-1)*size,
|
||||
from: (p - 1) * size,
|
||||
size: size,
|
||||
text: '',
|
||||
isTeacher: isTeacher,
|
||||
}
|
||||
CommentApi.getProjectComments(obj.project.id, query)
|
||||
.then(res=>{
|
||||
.then(res => {
|
||||
if (res.data.code === 200) {
|
||||
if (res.data.comments !== null) {
|
||||
setCommentList(res.data.comments)
|
||||
|
@ -35,7 +36,9 @@ function ProjectComment(obj) {
|
|||
}
|
||||
}
|
||||
})
|
||||
.catch(e=>{console.log(e)})
|
||||
.catch(e => {
|
||||
console.log(e)
|
||||
})
|
||||
|
||||
setPage(p);
|
||||
};
|
||||
|
@ -50,11 +53,11 @@ function ProjectComment(obj) {
|
|||
}
|
||||
setSubmitting(true);
|
||||
let c = {
|
||||
content: value,
|
||||
content: value,
|
||||
projectId: obj.project.id,
|
||||
}
|
||||
CommentApi.createComment(obj.project.id, c)
|
||||
.then(res=>{
|
||||
.then(res => {
|
||||
setSubmitting(false);
|
||||
if (res.data.code === 200) {
|
||||
message.success(res.data.msg)
|
||||
|
@ -64,11 +67,13 @@ function ProjectComment(obj) {
|
|||
message.error(res.data.msg)
|
||||
}
|
||||
})
|
||||
.catch(e=>{console.log(e)})
|
||||
.catch(e => {
|
||||
console.log(e)
|
||||
})
|
||||
};
|
||||
const deleteComment = (item) => {
|
||||
CommentApi.deleteComment(obj.project.id, item.id)
|
||||
.then(res=>{
|
||||
.then(res => {
|
||||
if (res.data.code === 200) {
|
||||
message.success(res.data.msg)
|
||||
updateCommentList(page, pageSize, isTeacher)
|
||||
|
@ -76,7 +81,9 @@ function ProjectComment(obj) {
|
|||
message.error(res.data.msg)
|
||||
}
|
||||
})
|
||||
.catch(e=>{console.log(e)})
|
||||
.catch(e => {
|
||||
console.log(e)
|
||||
})
|
||||
}
|
||||
|
||||
const onChange = (v) => {
|
||||
|
@ -120,8 +127,8 @@ function ProjectComment(obj) {
|
|||
</>,
|
||||
<>
|
||||
{obj.account.name === item.userId ?
|
||||
<Popconfirm title="确定删除留言?" onConfirm={e=>deleteComment(item)}>
|
||||
<Button type="text" shape="circle" icon={<DeleteOutlined />} />
|
||||
<Popconfirm title="确定删除留言?" onConfirm={e => deleteComment(item)}>
|
||||
<Button type="text" shape="circle" icon={<DeleteOutlined/>}/>
|
||||
</Popconfirm>
|
||||
: null
|
||||
}
|
||||
|
@ -144,9 +151,8 @@ function ProjectComment(obj) {
|
|||
/>
|
||||
))
|
||||
}<br/>
|
||||
<div>
|
||||
<div style={{textAlign: 'right', marginRight: '40px'}}>
|
||||
<Pagination
|
||||
hideOnSinglePage
|
||||
total={total}
|
||||
showTotal={t => `共${total}项内容`}
|
||||
current={page}
|
||||
|
|
|
@ -35,7 +35,7 @@ function ProjectOutline(obj) {
|
|||
message.warn("请先加入学习")
|
||||
return
|
||||
}
|
||||
window.open(`/project/${pid}/section/${subItem.id}/preview?back=/project/${pid}/info?menu=project-outline`)
|
||||
window.open(`/home/project/${pid}/section/${subItem.id}/preview?back=/project/${pid}/info?menu=project-outline`)
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -82,7 +82,7 @@ function StudentAdmin(obj) {
|
|||
title: '',
|
||||
dataIndex: 'showEvidence',
|
||||
render: (text, item, index) => (
|
||||
<Link to={`/project/${pid}/student/${item.studentId}/evidence`}>
|
||||
<Link to={`/home/project/${pid}/student/${item.studentId}/evidence`}>
|
||||
<Button type="text">查看学习证据</Button>
|
||||
</Link>
|
||||
)
|
||||
|
|
|
@ -13,7 +13,8 @@ import {
|
|||
PageHeader,
|
||||
Popconfirm,
|
||||
Row,
|
||||
Tag, Tooltip
|
||||
Tag,
|
||||
Tooltip
|
||||
} from 'antd';
|
||||
import QueueAnim from 'rc-queue-anim';
|
||||
import {Link} from 'react-router-dom';
|
||||
|
@ -49,7 +50,9 @@ class ProjectInfo extends React.PureComponent {
|
|||
favBtLoading: false,
|
||||
learnBtLoading: false,
|
||||
exitBtLoading: false,
|
||||
closeBtLoading: false
|
||||
closeBtLoading: false,
|
||||
cloneBtLoading: false,
|
||||
deleteBtLoading: false
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -108,9 +111,9 @@ class ProjectInfo extends React.PureComponent {
|
|||
}
|
||||
back = e => {
|
||||
if (this.props.account.tag === '老师') {
|
||||
window.location.href = '/my-project/published'
|
||||
window.location.href = '/home/my-project/published'
|
||||
} else {
|
||||
window.location.href = '/my-project/learning'
|
||||
window.location.href = '/home/my-project/learning'
|
||||
}
|
||||
}
|
||||
learnProject = e => {
|
||||
|
@ -183,9 +186,9 @@ class ProjectInfo extends React.PureComponent {
|
|||
})
|
||||
if (res.data.code === 200) {
|
||||
if (this.props.account.tag === '老师') {
|
||||
window.location.href = '/my-project/published'
|
||||
window.location.href = '/home/my-project/published'
|
||||
} else {
|
||||
window.location.href = '/my-project/learning'
|
||||
window.location.href = '/home/my-project/learning'
|
||||
}
|
||||
} else {
|
||||
message.error(res.data.msg)
|
||||
|
@ -196,13 +199,15 @@ class ProjectInfo extends React.PureComponent {
|
|||
})
|
||||
}
|
||||
deleteProject = e => {
|
||||
this.setState({deleteBtLoading: true})
|
||||
ProjectApi.deleteProject(this.state.pid)
|
||||
.then(res => {
|
||||
this.setState({deleteBtLoading: false})
|
||||
if (res.data.code === 200) {
|
||||
if (this.props.account.tag === '老师') {
|
||||
window.location.href = '/my-project/published'
|
||||
window.location.href = '/home/my-project/published'
|
||||
} else {
|
||||
window.location.href = '/my-project/learning'
|
||||
window.location.href = '/home/my-project/learning'
|
||||
}
|
||||
} else {
|
||||
message.error(res.data.msg)
|
||||
|
@ -217,7 +222,7 @@ class ProjectInfo extends React.PureComponent {
|
|||
favBtLoading: true
|
||||
})
|
||||
ProjectApi.addFavourite(this.state.pid)
|
||||
.then(res=>{
|
||||
.then(res => {
|
||||
this.setState({
|
||||
favBtLoading: false
|
||||
})
|
||||
|
@ -228,14 +233,16 @@ class ProjectInfo extends React.PureComponent {
|
|||
message.error(res.data.msg)
|
||||
}
|
||||
})
|
||||
.catch(e=>{console.log(e)})
|
||||
.catch(e => {
|
||||
console.log(e)
|
||||
})
|
||||
}
|
||||
removeFavourite = e => {
|
||||
this.setState({
|
||||
favBtLoading: true
|
||||
})
|
||||
ProjectApi.removeFavourite(this.state.pid)
|
||||
.then(res=>{
|
||||
.then(res => {
|
||||
this.setState({
|
||||
favBtLoading: false
|
||||
})
|
||||
|
@ -246,7 +253,9 @@ class ProjectInfo extends React.PureComponent {
|
|||
message.error(res.data.msg)
|
||||
}
|
||||
})
|
||||
.catch(e=>{console.log(e)})
|
||||
.catch(e => {
|
||||
console.log(e)
|
||||
})
|
||||
}
|
||||
|
||||
setProject = project => {
|
||||
|
@ -265,30 +274,79 @@ class ProjectInfo extends React.PureComponent {
|
|||
return "( 编辑中 )"
|
||||
}
|
||||
}
|
||||
cloneProject = () => {
|
||||
this.setState({
|
||||
cloneBtLoading: true
|
||||
})
|
||||
ProjectApi.cloneProject(this.state.pid)
|
||||
.then(res => {
|
||||
this.setState({
|
||||
cloneBtLoading: false
|
||||
})
|
||||
if (res.data.code === 200) {
|
||||
message.success(res.data.msg)
|
||||
} else {
|
||||
message.error(res.data.msg)
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e)
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const {project, teacher, menu, pid, lastLearn, favBtLoading, learnBtLoading, exitBtLoading, closeBtLoading} = this.state;
|
||||
const {
|
||||
project,
|
||||
teacher,
|
||||
menu,
|
||||
pid,
|
||||
lastLearn,
|
||||
favBtLoading,
|
||||
learnBtLoading,
|
||||
exitBtLoading,
|
||||
closeBtLoading,
|
||||
cloneBtLoading,
|
||||
deleteBtLoading
|
||||
} = this.state;
|
||||
|
||||
const teacherBt = (
|
||||
<div style={{float: 'right'}}>
|
||||
{project.published && !project.closed ?
|
||||
<Popconfirm
|
||||
title="确定结束项目?"
|
||||
placement="topRight"
|
||||
onConfirm={this.closeProject}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Button
|
||||
shape="round"
|
||||
size="middle"
|
||||
danger
|
||||
style={{margin: '5px'}}
|
||||
loading={closeBtLoading}
|
||||
<>
|
||||
<Popconfirm
|
||||
title="确定结束项目?"
|
||||
placement="topRight"
|
||||
onConfirm={this.closeProject}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
结束项目
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
<Button
|
||||
shape="round"
|
||||
size="middle"
|
||||
danger
|
||||
style={{margin: '5px'}}
|
||||
loading={closeBtLoading}
|
||||
>
|
||||
结束项目
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
<Popconfirm
|
||||
title="确定复制项目?"
|
||||
placement="topRight"
|
||||
onConfirm={this.cloneProject}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Button
|
||||
shape="round"
|
||||
size="middle"
|
||||
style={{margin: '5px'}}
|
||||
loading={cloneBtLoading}
|
||||
>
|
||||
复制项目
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
</>
|
||||
: null}
|
||||
{!project.published ?
|
||||
<div>
|
||||
|
@ -307,7 +365,7 @@ class ProjectInfo extends React.PureComponent {
|
|||
发布项目
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
<Link to={`/project/${pid}/info/edit`} target="_blank">
|
||||
<Link to={`/home/project/${pid}/info/edit`} target="_blank">
|
||||
<Button
|
||||
shape="round"
|
||||
size="middle"
|
||||
|
@ -316,6 +374,22 @@ class ProjectInfo extends React.PureComponent {
|
|||
编辑项目
|
||||
</Button>
|
||||
</Link>
|
||||
<Popconfirm
|
||||
title="确定复制项目?"
|
||||
placement="topRight"
|
||||
onConfirm={this.cloneProject}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Button
|
||||
shape="round"
|
||||
size="middle"
|
||||
style={{margin: '5px'}}
|
||||
loading={cloneBtLoading}
|
||||
>
|
||||
复制项目
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
<Popconfirm
|
||||
title="确定删除项目?删除后不能恢复"
|
||||
onConfirm={this.deleteProject}
|
||||
|
@ -325,6 +399,7 @@ class ProjectInfo extends React.PureComponent {
|
|||
shape="circle"
|
||||
size="middle"
|
||||
type="danger"
|
||||
loading={deleteBtLoading}
|
||||
style={{marginTop: '5px', marginLeft: '20px', marginBottom: '5px', marginRight: '5px'}}
|
||||
icon={<DeleteOutlined/>}
|
||||
/>
|
||||
|
@ -332,6 +407,22 @@ class ProjectInfo extends React.PureComponent {
|
|||
</div> : null}
|
||||
{project.closed ?
|
||||
<div>
|
||||
<Popconfirm
|
||||
title="确定复制项目?"
|
||||
placement="topRight"
|
||||
onConfirm={this.cloneProject}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Button
|
||||
shape="round"
|
||||
size="middle"
|
||||
style={{margin: '5px'}}
|
||||
loading={cloneBtLoading}
|
||||
>
|
||||
复制项目
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
<Popconfirm
|
||||
title="确定删除项目?删除后不能恢复"
|
||||
onConfirm={this.deleteProject}
|
||||
|
@ -353,7 +444,7 @@ class ProjectInfo extends React.PureComponent {
|
|||
<div style={{float: 'right'}}>
|
||||
{project.learning ?
|
||||
<>
|
||||
<Link to={`/project/${project.id}/section/${lastLearn.id}/preview?back=/project/${project.id}/info`}>
|
||||
<Link to={`/home/project/${project.id}/section/${lastLearn.id}/preview?back=/project/${project.id}/info`}>
|
||||
|
||||
{lastLearn.last ?
|
||||
<span>
|
||||
|
@ -447,11 +538,13 @@ class ProjectInfo extends React.PureComponent {
|
|||
<span style={{float: 'right'}}>
|
||||
{project.favourite ?
|
||||
<Tooltip title="点击取消收藏">
|
||||
<Button shape="circle" type="text" loading={favBtLoading} icon={<StarFilled/>} onClick={this.removeFavourite}/>
|
||||
<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}/>
|
||||
<Button shape="circle" type="text" loading={favBtLoading} icon={<StarOutlined/>}
|
||||
onClick={this.addFavourite}/>
|
||||
</Tooltip>
|
||||
}
|
||||
</span>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React, {useEffect, useState} from 'react';
|
||||
import {Card, Col, Divider, Empty, Image, Input, Pagination, Row, Select, Spin, Tag} from 'antd';
|
||||
import {Card, Col, Divider, Image, Input, Pagination, Row, Select, Spin, Tag} from 'antd';
|
||||
import {EyeOutlined, TeamOutlined} from '@ant-design/icons';
|
||||
|
||||
import './project-list.less';
|
||||
|
@ -47,7 +47,7 @@ function ProjectList(obj) {
|
|||
const updateProjectList = (p, size, subject, skill, text) => {
|
||||
setLoadProjects(true)
|
||||
let q = {
|
||||
from: (p - 1)*size,
|
||||
from: (p - 1) * size,
|
||||
size: size,
|
||||
orderBy: 'create_at',
|
||||
orderType: 'desc',
|
||||
|
@ -78,11 +78,11 @@ function ProjectList(obj) {
|
|||
|
||||
const loadSubjectsAndSkills = () => {
|
||||
ProjectApi.getSubjectsAndSkills(obj.pid)
|
||||
.then(res=>{
|
||||
.then(res => {
|
||||
if (res.data.code === 200) {
|
||||
if (res.data.subjects !== null) {
|
||||
let s = res.data.subjects
|
||||
for (let i=0; i<iniSubjects.length; i++) {
|
||||
for (let i = 0; i < iniSubjects.length; i++) {
|
||||
if (s.indexOf(iniSubjects[i]) < 0) {
|
||||
s.push(iniSubjects[i])
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ function ProjectList(obj) {
|
|||
}
|
||||
if (res.data.skills !== null) {
|
||||
let s = res.data.skills
|
||||
for (let i=0; i<iniSkills.length; i++) {
|
||||
for (let i = 0; i < iniSkills.length; i++) {
|
||||
if (s.indexOf(iniSkills[i]) < 0) {
|
||||
s.push(iniSkills[i])
|
||||
}
|
||||
|
@ -100,7 +100,9 @@ function ProjectList(obj) {
|
|||
}
|
||||
}
|
||||
})
|
||||
.catch(e=>{console.log(e)})
|
||||
.catch(e => {
|
||||
console.log(e)
|
||||
})
|
||||
}
|
||||
|
||||
const handleSubjectsChange = selected => {
|
||||
|
@ -119,7 +121,7 @@ function ProjectList(obj) {
|
|||
.catch(e => {
|
||||
})
|
||||
}
|
||||
window.location.href = `/project/${item.id}/info`
|
||||
window.location.href = `/home/project/${item.id}/info`
|
||||
}
|
||||
|
||||
const onSearch = (v) => {
|
||||
|
@ -180,75 +182,74 @@ function ProjectList(obj) {
|
|||
</Card>
|
||||
|
||||
<div style={{marginTop: '10px', textAlign: 'center'}}>
|
||||
<Spin spinning={loadProjects} />
|
||||
<Spin spinning={loadProjects}/>
|
||||
<Row gutter={[20, 20]} style={{textAlign: 'left'}}>
|
||||
{
|
||||
learningProjectList.map((item, index) => (
|
||||
<Col key={index.toString()} {...topColResponsiveProps}>
|
||||
<Card
|
||||
hoverable
|
||||
bordered={false}
|
||||
onClick={e=>viewProject(item)}
|
||||
style={{
|
||||
borderRadius: '10px',
|
||||
}}
|
||||
cover={
|
||||
<Image
|
||||
src={item.image}
|
||||
preview={false}
|
||||
style={{
|
||||
borderTopLeftRadius: '10px',
|
||||
borderTopRightRadius: '10px',
|
||||
}}
|
||||
fallback={"https://cdn.open-ct.com/task-resources//openpbl-empty-project.png"}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Meta
|
||||
title={
|
||||
item.projectTitle === '' ? "无": item.projectTitle
|
||||
}
|
||||
description={
|
||||
<div>
|
||||
<span className="des-text">{item.subjects === '' ? '--' : item.subjects}</span><br/>
|
||||
<span className="des-text">{item.skills === '' ? '--' : item.skills}</span>
|
||||
{item.learning ?
|
||||
<Tag color="geekblue" style={{zIndex: '999', float: 'right'}}>学习中</Tag> : null}
|
||||
{item.teacherId === uid && type === 'teacher' ?
|
||||
<Tag color="geekblue" style={{zIndex: '999', float: 'right'}}>我的项目</Tag> : null}
|
||||
</div>
|
||||
}
|
||||
<Card
|
||||
hoverable
|
||||
bordered={false}
|
||||
onClick={e => viewProject(item)}
|
||||
style={{
|
||||
borderRadius: '10px',
|
||||
}}
|
||||
cover={
|
||||
<Image
|
||||
src={item.image}
|
||||
preview={false}
|
||||
style={{
|
||||
borderTopLeftRadius: '10px',
|
||||
borderTopRightRadius: '10px',
|
||||
}}
|
||||
fallback={"https://cdn.open-ct.com/task-resources//openpbl-empty-project.png"}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Meta
|
||||
title={
|
||||
item.projectTitle === '' ? "无" : item.projectTitle
|
||||
}
|
||||
description={
|
||||
<div>
|
||||
<span className="des-text">{item.subjects === '' ? '--' : item.subjects}</span>
|
||||
{item.learning ?
|
||||
<Tag color="geekblue" style={{zIndex: '999', float: 'right'}}>学习中</Tag> : null}
|
||||
{item.teacherId === uid && type === 'teacher' ?
|
||||
<Tag color="geekblue" style={{zIndex: '999', float: 'right'}}>我的项目</Tag> : null}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
<span
|
||||
style={{
|
||||
color: 'gray',
|
||||
fontSize: 'small',
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
color: 'gray',
|
||||
fontSize: 'small',
|
||||
}}
|
||||
>
|
||||
<EyeOutlined/>
|
||||
{item.readNum}
|
||||
{item.readNum}
|
||||
</span>
|
||||
<Divider type="vertical"/>
|
||||
<span
|
||||
style={{
|
||||
color: 'gray',
|
||||
fontSize: 'small',
|
||||
}}
|
||||
>
|
||||
<Divider type="vertical"/>
|
||||
<span
|
||||
style={{
|
||||
color: 'gray',
|
||||
fontSize: 'small',
|
||||
}}
|
||||
>
|
||||
<TeamOutlined/>
|
||||
{item.joinNum}
|
||||
{item.joinNum}
|
||||
</span>
|
||||
<span
|
||||
style={{
|
||||
color: 'gray',
|
||||
fontSize: 'small',
|
||||
float: 'right',
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
color: 'gray',
|
||||
fontSize: 'small',
|
||||
float: 'right',
|
||||
}}
|
||||
>
|
||||
{util.FilterMoment(item.createAt)}
|
||||
</span>
|
||||
</Card>
|
||||
</Card>
|
||||
</Col>
|
||||
))
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from "react";
|
||||
import {Avatar, Badge, Button, Col, Dropdown, Layout, Menu, Row, Tag, Image, message} from "antd";
|
||||
import {Avatar, Badge, Button, Col, Dropdown, Image, Layout, Menu, message, Row, Tag} from "antd";
|
||||
import {Link, Redirect, Route, Switch} from "react-router-dom";
|
||||
import {BellOutlined, LogoutOutlined, SettingOutlined} from '@ant-design/icons';
|
||||
|
||||
|
@ -35,23 +35,25 @@ class HeaderLayout extends React.Component {
|
|||
account: res.data.data
|
||||
})
|
||||
})
|
||||
.catch((e) => {console.log(e)})
|
||||
.catch((e) => {
|
||||
console.log(e)
|
||||
})
|
||||
|
||||
this.changeMenu()
|
||||
}
|
||||
|
||||
changeMenu = (e) => {
|
||||
if (e !== undefined ) {
|
||||
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")) {
|
||||
if (p.startsWith("/home/my-project")) {
|
||||
this.setState({menu: 'my-project'})
|
||||
} else if (p.startsWith("/public-project")) {
|
||||
} else if (p.startsWith("/home/public-project")) {
|
||||
this.setState({menu: 'public-project'})
|
||||
} else {
|
||||
this.setState({menu: 'home'})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,7 +62,7 @@ class HeaderLayout extends React.Component {
|
|||
|
||||
if (this.state.account === null) {
|
||||
message.warn('请先登录')
|
||||
return <Redirect to={'/home'} />
|
||||
return <Redirect to={'/home'}/>
|
||||
} else if (this.state.account === undefined) {
|
||||
return null
|
||||
} else {
|
||||
|
@ -82,7 +84,9 @@ class HeaderLayout extends React.Component {
|
|||
window.location.href = '/'
|
||||
}
|
||||
})
|
||||
.catch(e => {console.log(e)})
|
||||
.catch(e => {
|
||||
console.log(e)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,7 +150,7 @@ class HeaderLayout extends React.Component {
|
|||
style={{border: 0}}
|
||||
defaultSelectedKeys={['home']}
|
||||
selectedKeys={[menu]}
|
||||
onClick={e=>this.changeMenu(e)}
|
||||
onClick={e => this.changeMenu(e)}
|
||||
>
|
||||
<Menu.Item key="home">
|
||||
<Link to="/home">
|
||||
|
@ -154,27 +158,22 @@ class HeaderLayout extends React.Component {
|
|||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="public-project">
|
||||
<Link to="/public-project">
|
||||
<Link to="/home/public-project">
|
||||
公共项目
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="my-project">
|
||||
<Link to="/my-project">
|
||||
<Link to="/home/my-project">
|
||||
我的空间
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="bbs">
|
||||
<a href="https://bbs.open-ct.com">
|
||||
在线论坛
|
||||
</a>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
</Col>
|
||||
<Col xxl={4} xl={4} lg={6} md={8} sm={8} xs={11}>
|
||||
{
|
||||
<>
|
||||
<span style={{float: 'left', marginRight: '20px'}}>
|
||||
<Link to="/message">
|
||||
<Link to="/home/message">
|
||||
<Button
|
||||
shape="circle"
|
||||
type="text"
|
||||
|
@ -195,24 +194,34 @@ class HeaderLayout extends React.Component {
|
|||
</Layout.Header>
|
||||
<Layout.Content>
|
||||
<Switch>
|
||||
<Route exact path="/" render={() => (
|
||||
<Redirect to="/home"/>
|
||||
)}/>
|
||||
<Route exact path="/home" render={(props) => <Home account={this.state.account} {...props} />}/>
|
||||
<Route exact path="/home/public-project"
|
||||
render={(props) => this.renderHomeIfLoggedIn(<Project account={this.state.account} {...props} />)}/>
|
||||
<Route path="/home/my-project" render={(props) => this.renderHomeIfLoggedIn(<MyProject
|
||||
account={this.state.account} {...props} />)}/>
|
||||
<Route path="/home/message"
|
||||
render={(props) => this.renderHomeIfLoggedIn(<Message account={this.state.account} {...props} />)}/>
|
||||
|
||||
<Route exact path="/home" render={(props)=><Home account={this.state.account} {...props} />}/>
|
||||
<Route exact path="/public-project" render={(props)=>this.renderHomeIfLoggedIn(<Project account={this.state.account} {...props} />)} />
|
||||
<Route path="/my-project" render={(props)=>this.renderHomeIfLoggedIn(<MyProject account={this.state.account} {...props} />)} />
|
||||
<Route path="/message" render={(props)=>this.renderHomeIfLoggedIn(<Message account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/home/project/:id/info" render={(props) => this.renderHomeIfLoggedIn(<ProjectInfo
|
||||
account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/home/project/:id/info/edit"
|
||||
render={(props) => this.renderHomeIfLoggedIn(<EditInfo account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/home/project/:id/outline/edit"
|
||||
render={(props) => this.renderHomeIfLoggedIn(<EditOutlined
|
||||
account={this.state.account} {...props} />)}/>
|
||||
|
||||
<Route exact path="/project/:id/info" render={(props)=>this.renderHomeIfLoggedIn(<ProjectInfo account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/project/:id/info/edit" render={(props)=>this.renderHomeIfLoggedIn(<EditInfo account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/project/:id/outline/edit" render={(props)=>this.renderHomeIfLoggedIn(<EditOutlined account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/home/project/:pid/student/:sid/evidence"
|
||||
render={(props) => this.renderHomeIfLoggedIn(<Evidence account={this.state.account} {...props} />)}/>
|
||||
|
||||
<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" render={(props)=>this.renderHomeIfLoggedIn(<SectionEditPage account={this.state.account} {...props} />)}/>
|
||||
<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" render={(props)=>this.renderHomeIfLoggedIn(<PreviewSection account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/home/project/:pid/section/:sid/edit"
|
||||
render={(props) => this.renderHomeIfLoggedIn(<SectionEditPage
|
||||
account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/home/project/:pid/section/:sid/task/:tid/survey/edit"
|
||||
render={(props) => this.renderHomeIfLoggedIn(<SurveyEditPage
|
||||
account={this.state.account} {...props} />)}/>
|
||||
<Route exact path="/home/project/:pid/section/:sid/preview"
|
||||
render={(props) => this.renderHomeIfLoggedIn(<PreviewSection
|
||||
account={this.state.account} {...props} />)}/>
|
||||
</Switch>
|
||||
</Layout.Content>
|
||||
<Layout.Footer style={{textAlign: 'center'}}>OpenPBL</Layout.Footer>
|
||||
|
|
128
web/yarn.lock
128
web/yarn.lock
|
@ -5668,6 +5668,11 @@ file-loader@^6.0.0:
|
|||
loader-utils "^2.0.0"
|
||||
schema-utils "^3.0.0"
|
||||
|
||||
file-saver@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-2.0.5.tgz#d61cfe2ce059f414d899e9dd6d4107ee25670c38"
|
||||
integrity sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==
|
||||
|
||||
file-uri-to-path@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
|
||||
|
@ -6297,6 +6302,15 @@ html-comment-regex@^1.1.0:
|
|||
resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7"
|
||||
integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==
|
||||
|
||||
html-docx-js@^0.3.1:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/html-docx-js/-/html-docx-js-0.3.1.tgz#9713f6587a08d1f0c87a801fe7649a4d0ab07d76"
|
||||
integrity sha1-lxP2WHoI0fDIeoAf52SaTQqwfXY=
|
||||
dependencies:
|
||||
jszip "^2.3.0"
|
||||
lodash.escape "^3.0.0"
|
||||
lodash.merge "^3.2.0"
|
||||
|
||||
html-encoding-sniffer@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3"
|
||||
|
@ -7678,6 +7692,13 @@ jstoxml@^0.2.3:
|
|||
array-includes "^3.1.2"
|
||||
object.assign "^4.1.2"
|
||||
|
||||
jszip@^2.3.0:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.yarnpkg.com/jszip/-/jszip-2.6.1.tgz#b88f3a7b2e67a2a048152982c7a3756d9c4828f0"
|
||||
integrity sha1-uI86ey5noqBIFSmCx6N1bZxIKPA=
|
||||
dependencies:
|
||||
pako "~1.0.2"
|
||||
|
||||
killable@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"
|
||||
|
@ -7866,21 +7887,72 @@ locate-path@^5.0.0:
|
|||
dependencies:
|
||||
p-locate "^4.1.0"
|
||||
|
||||
lodash._arraycopy@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1"
|
||||
integrity sha1-due3wfH7klRzdIeKVi7Qaj5Q9uE=
|
||||
|
||||
lodash._arrayeach@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz#bab156b2a90d3f1bbd5c653403349e5e5933ef9e"
|
||||
integrity sha1-urFWsqkNPxu9XGU0AzSeXlkz754=
|
||||
|
||||
lodash._basecopy@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36"
|
||||
integrity sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=
|
||||
|
||||
lodash._basefor@^3.0.0:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2"
|
||||
integrity sha1-dVC06SGO8J+tJDQ7YSAhx5tMIMI=
|
||||
|
||||
lodash._bindcallback@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e"
|
||||
integrity sha1-5THCdkTPi1epnhftlbNcdIeJOS4=
|
||||
|
||||
lodash._createassigner@^3.0.0:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11"
|
||||
integrity sha1-g4pbri/aymOsIt7o4Z+k5taXCxE=
|
||||
dependencies:
|
||||
lodash._bindcallback "^3.0.0"
|
||||
lodash._isiterateecall "^3.0.0"
|
||||
lodash.restparam "^3.0.0"
|
||||
|
||||
lodash._getnative@^3.0.0:
|
||||
version "3.9.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
|
||||
integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=
|
||||
|
||||
lodash._isiterateecall@^3.0.0:
|
||||
version "3.0.9"
|
||||
resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c"
|
||||
integrity sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=
|
||||
|
||||
lodash._reinterpolate@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
|
||||
integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=
|
||||
|
||||
lodash._root@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692"
|
||||
integrity sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=
|
||||
|
||||
lodash.debounce@^4.0.0, lodash.debounce@^4.0.8:
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
|
||||
integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168=
|
||||
|
||||
lodash.escape@^3.0.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698"
|
||||
integrity sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=
|
||||
dependencies:
|
||||
lodash._root "^3.0.0"
|
||||
|
||||
lodash.get@^4.4.2:
|
||||
version "4.4.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
|
||||
|
@ -7896,7 +7968,21 @@ lodash.isarray@^3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55"
|
||||
integrity sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=
|
||||
|
||||
lodash.keys@^3.1.2:
|
||||
lodash.isplainobject@^3.0.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz#9a8238ae16b200432960cd7346512d0123fbf4c5"
|
||||
integrity sha1-moI4rhayAEMpYM1zRlEtASP79MU=
|
||||
dependencies:
|
||||
lodash._basefor "^3.0.0"
|
||||
lodash.isarguments "^3.0.0"
|
||||
lodash.keysin "^3.0.0"
|
||||
|
||||
lodash.istypedarray@^3.0.0:
|
||||
version "3.0.6"
|
||||
resolved "https://registry.yarnpkg.com/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz#c9a477498607501d8e8494d283b87c39281cef62"
|
||||
integrity sha1-yaR3SYYHUB2OhJTSg7h8OSgc72I=
|
||||
|
||||
lodash.keys@^3.0.0, lodash.keys@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a"
|
||||
integrity sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=
|
||||
|
@ -7905,11 +7991,41 @@ lodash.keys@^3.1.2:
|
|||
lodash.isarguments "^3.0.0"
|
||||
lodash.isarray "^3.0.0"
|
||||
|
||||
lodash.keysin@^3.0.0:
|
||||
version "3.0.8"
|
||||
resolved "https://registry.yarnpkg.com/lodash.keysin/-/lodash.keysin-3.0.8.tgz#22c4493ebbedb1427962a54b445b2c8a767fb47f"
|
||||
integrity sha1-IsRJPrvtsUJ5YqVLRFssinZ/tH8=
|
||||
dependencies:
|
||||
lodash.isarguments "^3.0.0"
|
||||
lodash.isarray "^3.0.0"
|
||||
|
||||
lodash.memoize@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
||||
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
|
||||
|
||||
lodash.merge@^3.2.0:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-3.3.2.tgz#0d90d93ed637b1878437bb3e21601260d7afe994"
|
||||
integrity sha1-DZDZPtY3sYeEN7s+IWASYNev6ZQ=
|
||||
dependencies:
|
||||
lodash._arraycopy "^3.0.0"
|
||||
lodash._arrayeach "^3.0.0"
|
||||
lodash._createassigner "^3.0.0"
|
||||
lodash._getnative "^3.0.0"
|
||||
lodash.isarguments "^3.0.0"
|
||||
lodash.isarray "^3.0.0"
|
||||
lodash.isplainobject "^3.0.0"
|
||||
lodash.istypedarray "^3.0.0"
|
||||
lodash.keys "^3.0.0"
|
||||
lodash.keysin "^3.0.0"
|
||||
lodash.toplainobject "^3.0.0"
|
||||
|
||||
lodash.restparam@^3.0.0:
|
||||
version "3.6.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
|
||||
integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=
|
||||
|
||||
lodash.sortby@^4.7.0:
|
||||
version "4.7.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
|
||||
|
@ -7935,6 +8051,14 @@ lodash.throttle@^4.0.0:
|
|||
resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4"
|
||||
integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=
|
||||
|
||||
lodash.toplainobject@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz#28790ad942d293d78aa663a07ecf7f52ca04198d"
|
||||
integrity sha1-KHkK2ULSk9eKpmOgfs9/UsoEGY0=
|
||||
dependencies:
|
||||
lodash._basecopy "^3.0.0"
|
||||
lodash.keysin "^3.0.0"
|
||||
|
||||
lodash.uniq@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
|
||||
|
@ -8928,7 +9052,7 @@ pac-resolver@^4.1.0:
|
|||
ip "^1.1.5"
|
||||
netmask "^2.0.1"
|
||||
|
||||
pako@~1.0.5:
|
||||
pako@~1.0.2, pako@~1.0.5:
|
||||
version "1.0.11"
|
||||
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
|
||||
integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
|
||||
|
|
Loading…
Reference in New Issue