Skip to content

Commit

Permalink
完成答题模块,能够进行答题后的学习路径推荐
Browse files Browse the repository at this point in the history
  • Loading branch information
oopp1800 committed Apr 19, 2019
1 parent 6bd9b08 commit 598a7eb
Show file tree
Hide file tree
Showing 100 changed files with 2,683 additions and 25,666 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"history": "^4.7.2",
"jquery": "^3.3.1",
"jquery-mousewheel": "^3.1.13",
"katex": "^0.10.1",
"query-string": "^6.1.0",
"react": "^16.2.0",
"react-bootstrap": "^0.32.1",
Expand All @@ -19,6 +20,7 @@
"react-graph-vis": "^1.0.2",
"react-infinite-scroller": "^1.1.4",
"react-pdf": "^3.0.5",
"react-quill": "^1.3.3",
"react-router-dom": "^4.2.2",
"react-scripts": "1.1.1",
"reqwest": "^2.0.5",
Expand Down
2 changes: 2 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css" integrity="sha384-dbVIfZGuN1Yq7/1Ocstc1lUEm+AT+/rCkibIcC/OmWo5f0EA48Vf8CytHzGrSwbQ" crossorigin="anonymous">
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.js" integrity="sha384-2BKqo+exmr9su6dir+qCw08N2ZKRucY4PrGQPPWU1A7FtlCGjmEGFqXCv5nyM5Ij" crossorigin="anonymous"></script>
<title>众智化教学平台</title>
</head>
<body>
Expand Down
9 changes: 5 additions & 4 deletions server/database/models/mOnlineEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ module.exports = {
// _id: {type: String, required: true}, // MongoDB 默认生成 _id
userId: {type: String, required: true},
type: {type: String, required: true},
keyword: {type: String, required: true},
url: {type: String, required: true},
size: {type: String, required: true},
description: {type: String, required: true},
keyword: {type: String},
url: {type: String},
size: {type: String},
description: {type: String},
thumbnailUrl: {type: String, required: true},
uniqueData: {type: Object},
learningTime: {type: String},
Expand All @@ -17,6 +17,7 @@ module.exports = {
language: {type: String},
applicableObject: {type: Object},
duration: {type: Number},
quiz: {type: Object},
},
tProject: {
_id: {type: String, required: true},
Expand Down
Binary file added server/public/resource/default-thumbnail.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions server/routes/api/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const knowledgePoints = require('./knowledgePoints');
const service = require('./service');

module.exports = {
knowledgePoints,
service,
};
104 changes: 104 additions & 0 deletions server/routes/api/knowledgePoints/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
const { createInModel, findInModel, findOneInModel } = require('../../../database/model-operations');
const { pyRequest } = require('../../utils/pyRequest');
const { getUserInfoFromReq } = require('../../utils/token');

async function get(req, res, next) {
const { courseId, knowledgeId } = req.params;
if (!courseId || !knowledgeId) {
return res.sendStatus(400);
}

try {
const NecessaryInfo = [getUserInfoFromReq(req), findOneInModel('tProject', {_id: courseId})];
const [user, course] = await Promise.all(NecessaryInfo);
if (course.publishStatus !== 'publish' && course.userId !== user._id) {
return res.sendStatus(401);
}

if (!Array.isArray(course.data)) return res.sendStatus(500);
let knowledgePoint = course.data.filter(k => k._id === knowledgeId)[0];
knowledgePoint.course = {
_id: course._id,
title: course.projectName,
};

return res.json({
status: 'success',
data: knowledgePoint,
});
} catch (error) {
res.sendStatus(500).send({message: error});
}
}

async function _getLearningActivities(userId, courseId) {
const docs = await findInModel('tUserActivity', {
userId,
'activity.action': 'answer-question',
});
return docs.map(doc => doc.activity).filter(activity => activity.courseId === courseId);
}

async function _insertLearningActivity(userId, courseId, knowledgeId, correct) {
return createInModel('tUserActivity', {
userId,
activity: {
action: 'answer-question',
courseId,
knowledgeId,
correct,
},
});
}

async function answer(req, res, next) {
const { courseId, knowledgeId } = req.params;
let recommendedKnowledge = null;

try {
const { correct } = req.body.currentLearning;
const [course, user] = await Promise.all([
findOneInModel('tProject', { _id: courseId }),
getUserInfoFromReq(req),
]);

await _insertLearningActivity(user._id, courseId, knowledgeId, correct);
const activities = await _getLearningActivities(user._id, courseId);
const learningHistory = activities.map(activity => ({
name: course.data.filter(knowledge => knowledge._id === activity.knowledgeId)[0].title,
correct: activity.correct,
}));

const recommendedKnowledgeTitle = await pyRequest('/learning-path-recommendation', {
body: {
learningHistory,
course: course.projectName,
}
}, 'POST');
recommendedKnowledge = course.data.filter(knowledge => knowledge.title === recommendedKnowledgeTitle)[0];

if (!recommendedKnowledge) {
return res.status(500).json({
status: 'error',
message: '找不到推荐知识点!',
})
}
} catch(err) {
return res.status(500).json({
status: 'error',
message: err,
})
}

return res.json({
status: 'success',
data: {
recommendedKnowledge,
}
});
}

module.exports = {
get,
answer,
};
62 changes: 62 additions & 0 deletions server/routes/api/service/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
const { getUserInfoFromReq } = require('../../utils/token');
const { createInModel, findInModel, findOneInModel } = require('../../../database/model-operations');
const { pyRequest } = require('../../utils/pyRequest');


async function _getLearningActivities(userId, courseId) {
const docs = await findInModel('tUserActivity', {
userId,
'activity.action': 'answer-question',
});
return docs.map(doc => doc.activity).filter(activity => activity.courseId === courseId);
}

async function learningPathRecommendation(req, res, next) {
const { courseId } = req.params;
let recommendedKnowledge = null;

try {
const [course, user] = await Promise.all([
findOneInModel('tProject', { _id: courseId }),
getUserInfoFromReq(req),
]);

const activities = await _getLearningActivities(user._id, courseId);
const learningHistory = activities.map(activity => ({
name: course.data.filter(knowledge => knowledge._id === activity.knowledgeId)[0].title,
correct: activity.correct,
}));

const recommendedKnowledgeTitle = await pyRequest('/learning-path-recommendation', {
body: {
learningHistory,
course: course.projectName,
}
}, 'POST');
recommendedKnowledge = course.data.filter(knowledge => knowledge.title === recommendedKnowledgeTitle)[0];

if (!recommendedKnowledge) {
return res.status(500).json({
status: 'error',
message: '找不到推荐知识点!',
})
}
} catch(err) {
return res.status(500).json({
status: 'error',
message: err,
})
}


return res.json({
status: 'success',
data: {
recommendedKnowledge,
}
});
}

module.exports = {
learningPathRecommendation,
};
13 changes: 12 additions & 1 deletion server/routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ let material = require('./material');
let course = require('./course');
let search = require('./search');
let log = require('./log');
let api = require('./api');

let tokenObj = require('./utils/token');

Expand All @@ -30,13 +31,23 @@ router.post('/deleteProject', tokenObj.checkToken, project.deleteProject);
router.post('/getCourse', tokenObj.checkToken, course.getCourse);
router.post('/publishCourse', tokenObj.checkToken, course.publishCourse);

/* 课程学习 */
/* 课程学习(图搜索 API,含图信息) */
router.get('/getCourse', tokenObj.checkToken, course.getCourse);
router.get('/getAllCourses', tokenObj.checkToken, course.getAllCourses);
router.get('/getKnowledge', tokenObj.checkToken, course.getKnowledge);
router.get('/getKunit', tokenObj.checkToken, course.getKunit);
router.get('/getMcourse', tokenObj.checkToken, course.getMcourse);
router.get('/getAcourse', tokenObj.checkToken, course.getAcourse);
/* 课程学习(数据库检索 API) */
router.get('/api/v1/courses/:courseId/knowledge-points/:knowledgeId',
tokenObj.checkToken,
api.knowledgePoints.get);
router.post('/api/v1/courses/:courseId/knowledge-points/:knowledgeId/answer',
tokenObj.checkToken,
api.knowledgePoints.answer);
router.get('/api/v1/courses/:courseId/learning-path-recommendation',
tokenObj.checkToken,
api.service.learningPathRecommendation);

/* 资源 */
router.post('/upload', tokenObj.checkToken, material.uploadMaterial);
Expand Down
48 changes: 17 additions & 31 deletions server/routes/material/uploadMaterial.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ const formatParser = require('../utils/format-parser');
const updateGraph = require('../utils/updateGraph');
const { createInModel, findOneInModel } = require('../../database/model-operations');

const DEFAULT_THUMBNAIL = {
default: '/resource/default-thumbnail.png',
};

/**
* 上传文件并返回文件相关属性
* @param file
Expand Down Expand Up @@ -115,6 +119,7 @@ const getInfoFromReq = function (req) {
description,
keyword,
language,
quiz,
} = req.body;

let materialInfo = {
Expand All @@ -124,6 +129,8 @@ const getInfoFromReq = function (req) {
description,
keyword,
language,
quiz,
thumbnailUrl: DEFAULT_THUMBNAIL.default,
};

let files = [];
Expand All @@ -141,7 +148,7 @@ const getInfoFromReq = function (req) {
.then(fileInfo => Object.assign(materialInfo, fileInfo))
}
else if (files.length === 0) {
return Promise.reject('请上传文件!');
return Promise.resolve(materialInfo);
}
else {
return Promise.reject('一次只能上传一个文件!');
Expand All @@ -153,51 +160,30 @@ const uploadMaterial = function (req, res, next) {
let materialInfo = {};

// 成功返回素材信息
const onSuccess = data =>
res.json({
material: {
duration: data.duration,
source: data.url,
thumbnail: data.thumbnailUrl,
title: data.name,
type: data.type,
id: data._id,
keyword: data.keyword,
size: data.size,
description: data.description
}
const onSuccess = material => {
return res.json({
material,
});
// res.json({
// status: 'success',
// data
// });
};

// 失败返回错误信息
const onError = err => {
console.log(err);
console.error(err);
res.json({
status: 'error',
message: err.toString(),
});
};

const uploadToDatabaseAndGraph= function() {
const pUploadToDatabase = createInModel('tMaterial', materialInfo);
const pUploadToGraph = Promise.resolve(updateGraph(materialInfo, 'material'));

return Promise.all([pUploadToDatabase, pUploadToGraph]);
};

const getUserId = function(username) {
const getUser = function(username) {
return findOneInModel('tUser', { name: username });
};

getInfoFromReq(req)
.then(info => { materialInfo = info; return getUserId(username); })
.then(info => { materialInfo = info; return getUser(username); })
.then(user => { materialInfo.userId = user._id; })
.then(uploadToDatabaseAndGraph)
.then(([resOfDatabase, resOfGraph]) => resOfDatabase) // 一次只上传一个 Material
.then(onSuccess)
.then(() => createInModel('tMaterial', materialInfo))
.then(data => onSuccess(data._doc))
.catch(onError);

};
Expand Down
Loading

0 comments on commit 598a7eb

Please sign in to comment.