Jelajahi Sumber

Merge branch 'feature/review-bay' of SEEC-II-FrontEnd-Team/SEEC-II-FrontEnd into develop

WuXinyu 7 tahun lalu
induk
melakukan
df1d6943ac

+ 3 - 3
mock/modules/auth/index.js

@@ -1,6 +1,6 @@
 const express = require("express");
 const router = express.Router();
-const UserSerializer = require("../../serializers/user/UserSerializer");
+const userSerializer = require("../../serializers/user/UserSerializer");
 
 router.route("/login").post((req, res) => {
   //登录
@@ -8,7 +8,7 @@ router.route("/login").post((req, res) => {
   const setSendValue = role => {
     res.append("Authorization", token);
     res.send({
-      data: UserSerializer(role)
+      data: userSerializer(role)
     });
   };
   const { body = {} } = req;
@@ -30,7 +30,7 @@ router.route("/login").post((req, res) => {
 
 router.route("/register").post((req, res) => {
   //注册
-  res.send({ data: UserSerializer() });
+  res.send({ data: userSerializer() });
   // res.status(418).send({ message: '用户名已存在' });
 });
 

+ 11 - 5
mock/modules/course/index.js

@@ -1,17 +1,17 @@
 const express = require("express");
 const router = express.Router();
-const CourseSerializer = require("../../serializers/course/CourseSerializer");
+const courseSerializer = require("../../serializers/course/CourseSerializer");
 
 router
   .route("/teacher")
   .get((req, res) => {
     res.send({
-      data: [CourseSerializer(), CourseSerializer()]
+      data: [courseSerializer(), courseSerializer()]
     });
   })
   .post((req, res) => {
     res.send({
-      data: CourseSerializer()
+      data: courseSerializer()
     });
   });
 
@@ -20,14 +20,20 @@ router
   .get((req, res) => {
     //修改用户信息
     res.send({
-      data: [CourseSerializer(), CourseSerializer()]
+      data: [courseSerializer(), courseSerializer()]
     });
   })
   .post((req, res) => {
     //修改用户信息
     res.send({
-      data: CourseSerializer()
+      data: courseSerializer()
     });
   });
 
+router.route("/course/:courseId").get((req, res) => {
+  res.send({
+    data: courseSerializer()
+  });
+});
+
 module.exports = router;

+ 0 - 57
mock/modules/doc/index.js

@@ -1,57 +0,0 @@
-const express = require("express");
-const router = express.Router();
-const DocSimpleSerializer = require("../../serializers/DocSimpleSerializer");
-const DocSerializer = require("../../serializers/DocSerializer");
-const DocResultSerializer = require("../../serializers/review/ReviewResultSerializer");
-const CheckListItemSerializer = require("../../serializers/review/CheckListItemSerializer");
-
-router.route("").get((req, res) => {
-  //获得文档列表
-  res.send({
-    data: [
-      DocSimpleSerializer(req.query.self),
-      DocSimpleSerializer(),
-      DocSimpleSerializer(),
-      DocSimpleSerializer(),
-      DocSimpleSerializer()
-    ]
-  });
-});
-
-router.route("/:docId").get((req, res) => {
-  //获得文档详情
-  res.send({
-    data: DocSerializer()
-  });
-});
-
-router
-  .route("/:docId/checklist")
-  .get((req, res) => {
-    res.send({
-      data: [
-        CheckListItemSerializer(),
-        CheckListItemSerializer(),
-        CheckListItemSerializer(),
-        CheckListItemSerializer()
-      ]
-    });
-  })
-  .post((req, res) => {
-    res.send({
-      data: [
-        CheckListItemSerializer(),
-        CheckListItemSerializer(),
-        CheckListItemSerializer(),
-        CheckListItemSerializer()
-      ]
-    });
-  });
-
-router.route("/:docId/result").get((req, res) => {
-  res.send({
-    data: [DocResultSerializer(), DocResultSerializer(true)] //Result
-  });
-});
-
-module.exports = router;

+ 4 - 4
mock/modules/group/index.js

@@ -1,22 +1,22 @@
 const express = require("express");
 const router = express.Router();
-const GroupSerializer = require("../../serializers/course/GroupSerializer");
+const groupSerializer = require("../../serializers/course/GroupSerializer");
 
 router
   .route("")
   .get((req, res) =>
     res.send({
-      data: [GroupSerializer()]
+      data: [groupSerializer()]
     })
   )
   .post((req, res) =>
     res.send({
-      data: GroupSerializer()
+      data: groupSerializer()
     })
   )
   .put((req, res) =>
     res.send({
-      data: GroupSerializer()
+      data: groupSerializer()
     })
   );
 

+ 89 - 0
mock/modules/review/index.js

@@ -0,0 +1,89 @@
+const express = require("express");
+const router = express.Router();
+const reviewSimpleSerializer = require("../../serializers/review/ReviewSimpleSerializer");
+const reviewDetailSerializer = require("../../serializers/review/ReviewDetailSerializer");
+const checkListItemSerializer = require("../../serializers/review/CheckListItemSerializer");
+const reviewResultSerializer = require("../../serializers/review/ReviewResultSerializer");
+
+router.route("/review").post((req, res) =>
+  res.send({
+    data: reviewSimpleSerializer()
+  })
+);
+
+router.route("/argue").post((req, res) => res.send({}));
+
+router.route("/teacher/course/:courseId/review").get((req, res) =>
+  res.send({
+    data: [reviewSimpleSerializer(), reviewSimpleSerializer()]
+  })
+);
+
+router.route("/teacher/review/:reviewId").get((req, res) =>
+  res.send({
+    data: reviewDetailSerializer()
+  })
+);
+
+router.route("/student/course/:courseId/review").get((req, res) =>
+  res.send({
+    data: [reviewSimpleSerializer(), reviewSimpleSerializer()]
+  })
+);
+
+router
+  .route("/student/review/:reviewId")
+  .get((req, res) =>
+    res.send({
+      data: reviewDetailSerializer()
+    })
+  )
+  .post((req, res) =>
+    res.send({
+      data: [checkListItemSerializer(), checkListItemSerializer()]
+    })
+  );
+
+router.route("/student/course/:courseId/result").get((req, res) =>
+  res.send({
+    data: [reviewSimpleSerializer(), reviewSimpleSerializer()]
+  })
+);
+
+router.route("/student/review/:reviewId/result").get((req, res) =>
+  res.send({
+    data: reviewResultSerializer()
+  })
+);
+
+router.route("/sum/:reviewId").get((req, res) =>
+  res.send({
+    detail: reviewDetailSerializer(),
+    finishPercentage: 0.7,
+    studentIdCheckListAcceptNumMap: {
+      1: 1,
+      2: 3
+    }
+  })
+);
+
+router.route("/sum/:reviewId/level").post((req, res) => {
+  res.send({});
+});
+
+router.route("/sum/:reviewId/argue").get((req, res) =>
+  res.send({
+    data: [reviewSimpleSerializer(), reviewSimpleSerializer()]
+  })
+);
+
+router
+  .route("/sum/:reviewId/argue/:groupId")
+  .get((req, res) =>
+    res.send({
+      data: reviewResultSerializer()
+    })
+  )
+  .post((req, res) => res.send({}));
+
+module.exports = router;

+ 0 - 12
mock/modules/tag/index.js

@@ -1,12 +0,0 @@
-const express = require("express");
-const router = express.Router();
-const TagSerializer = require("../../serializers/TagSerializer");
-
-router.route("").get((req, res) => {
-  //获得用户标签列表
-  res.send({
-    data: [TagSerializer(), TagSerializer(), TagSerializer()]
-  });
-});
-
-module.exports = router;

+ 3 - 3
mock/modules/user/index.js

@@ -1,11 +1,11 @@
 const express = require("express");
 const router = express.Router();
-const UserSerializer = require("../../serializers/user/UserSerializer");
+const userSerializer = require("../../serializers/user/UserSerializer");
 
 router.route("/:userId").get((req, res) => {
   //获得用户信息
   res.send({
-    data: UserSerializer(),
+    data: userSerializer(),
     abilities: {
       update: true
     }
@@ -15,7 +15,7 @@ router.route("/:userId").get((req, res) => {
 router.route("/:userId").post((req, res) => {
   //修改用户信息
   res.send({
-    data: UserSerializer(),
+    data: userSerializer(),
     abilities: {
       update: true
     }

+ 1 - 2
mock/routes.js

@@ -3,9 +3,8 @@ const router = express.Router();
 
 router.use("/login", require("./modules/auth"));
 router.use("/user", require("./modules/user"));
-// router.use("/tag", require("./modules/tag"));
-// router.use("/doc", require("./modules/doc"));
 router.use("/course", require("./modules/course"));
 router.use("/group", require("./modules/group"));
+router.use("/review", require("./modules/review"));
 
 module.exports = router;

+ 0 - 67
mock/serializers/DocSerializer.js

@@ -1,67 +0,0 @@
-const makeId = require("../util/makeId");
-const tagSerializer = require("./TagSerializer");
-
-module.exports = (filename = "需求规格说明文档") => {
-  return {
-    id: makeId(),
-    filename,
-    owner: tagSerializer(),
-    content:
-      "# 需求规格说明文档\n\n" +
-      "> 参照语雀API基本要求\n" +
-      "\n" +
-      "## 基本路径\n" +
-      "* `/api/v2/`\n" +
-      "\n" +
-      "## HTTP Verbs\n" +
-      "\n" +
-      "| Verb | Description |\n" +
-      "| :--- | :--- |\n" +
-      "| GET | 用于获取数据 |\n" +
-      "| POST | 用于创建数据 |\n" +
-      "| PUT | 用于修改部分数据,例如一个文档标题,正文 |\n" +
-      "| DELETE | 用于删除数据 |\n" +
-      "\n" +
-      "## 用户认证\n" +
-      "使用 Token 机制来实现用户认证。\n" +
-      "在请求的 HTTP Headers 传入 `Authorization` 带入用户的 Token 信息,用于认证。\n" +
-      "\n" +
-      "文档会在需要用户权限的api中标识 __[需要认证] __\n" +
-      "\n" +
-      "## HTTP 状态码\n" +
-      "* 200 - 成功\n" +
-      "* 400 - 请求的参数不正确,或缺少必要信息,请对比文档\n" +
-      "* 401 - 需要用户认证的接口用户信息不正确,即__Token错__\n" +
-      "* 403 - 缺少对应功能的权限,即__权限不足__\n" +
-      "* 404 - 数据不存在,或未开放\n" +
-      "* 500 - 服务器异常\n" +
-      "\n" +
-      "## 返回数据格式[示例]\n" +
-      "* JSON 格式\n" +
-      "\n" +
-      "```json\n" +
-      "{\n" +
-      '    "data": {\n' +
-      '        "id": 10,\n' +
-      '        "slug": "weekly",\n' +
-      '        "name": "技术周刊",\n' +
-      "     },\n" +
-      '    "abilities": {\n' +
-      '        "update": false,\n' +
-      '        "destroy": false\n' +
-      "    },\n" +
-      '    "meta": {\n' +
-      '        "liked": false,\n' +
-      '        "followed": false,\n' +
-      "    }\n" +
-      "}\n" +
-      "```\n" +
-      "\n" +
-      "* id: 每个数据都会有的,Resource 的唯一编号,后续很多地方你可能需要用它查询\n" +
-      "* abilities: 表述当前登陆者对于此资源的权限\n" +
-      "* meta: 一些附加信息,例如是否赞过,是否关注过\n" +
-      "\n" +
-      "## DateTime 格式\n" +
-      "DateTime 使用 [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) 标准格式,请按照标准方式进行转换。\n"
-  };
-};

+ 0 - 10
mock/serializers/DocSimpleSerializer.js

@@ -1,10 +0,0 @@
-const makeId = require("../util/makeId");
-const tagSerializer = require("./TagSerializer");
-
-module.exports = (filename = "需求规格说明文档") => {
-  return {
-    id: makeId(),
-    filename,
-    owner: tagSerializer()
-  };
-};

+ 0 - 15
mock/serializers/TagSerializer.js

@@ -1,15 +0,0 @@
-const makeId = require("../util/makeId");
-const userSerializer = require("./user/UserSerializer");
-
-module.exports = (type = "GROUP", name = "TagBaker") => {
-  return {
-    id: makeId(),
-    type,
-    shareLink:
-      "https://bequank.oss-cn-beijing.aliyuncs.com/web-gallery/pixiv39957555.jpg?x-oss-process=style/avatar",
-    name,
-    owner: [userSerializer(), userSerializer()],
-    createdAt: "2010-10-21",
-    updatedAt: "2010-11-21"
-  };
-};

+ 2 - 0
mock/serializers/review/ReviewResultSerializer.js

@@ -8,6 +8,7 @@ const checkListItemSerializer = require("./CheckListItemSerializer");
  * @property {number|string} id ReviewResultSerializer
  * @property {ReviewDetailSerializerType} detail 文档详情
  * @property {string} level 文档等级
+ * @property {number} score 文档分数
  * @property {CheckListResult[]} checkListResult 互评作业的结果
  */
 
@@ -58,6 +59,7 @@ const reviewResultSerializer = () => {
     id: makeId(),
     detail: reviewDetailSerializer(),
     level: "A",
+    score: 80,
     checkListResult: [checkListResultItem(), checkListResultItem()]
   };
 };

+ 4 - 1
mock/serializers/review/ReviewSimpleSerializer.js

@@ -1,6 +1,7 @@
 const makeId = require("../../util/makeId");
 const courseSerializer = require("../course/CourseSerializer");
 const dayjs = require("dayjs");
+const groupSerializer = require("../course/GroupSerializer");
 
 /**
  * @description 互评checkListItem详细实体类
@@ -10,6 +11,7 @@ const dayjs = require("dayjs");
  * @property {CourseSerializerType} course 所属课程
  * @property {number} beginAt 开始时间
  * @property {number} endAt 截止时间
+ * @property {GroupSerializerType} group 所属小组
  */
 
 /**
@@ -22,7 +24,8 @@ const reviewSimpleSerializer = () => {
     name: "该项评价的内容, String",
     course: courseSerializer(),
     beginAt: dayjs("2018-10-21").unix(),
-    endAt: dayjs("2018-12-21").unix()
+    endAt: dayjs("2018-12-21").unix(),
+    group: groupSerializer()
   };
 };
 

+ 1 - 0
src/api/_prefix.js

@@ -6,3 +6,4 @@ export const PHOTO_MODULE = `${API_VERSION}/photo`;
 export const TAG_MODULE = `${API_VERSION}/tag`;
 export const COURSE_MODULE = `${API_VERSION}/course`;
 export const GROUP_MODULE = `${API_VERSION}/group`;
+export const REVIEW_MODULE = `${API_VERSION}/review`;

+ 11 - 0
src/api/course.js

@@ -22,6 +22,7 @@ export const getStudentCourses = () => {
  * @param {string} name
  * @param {string} code
  * @returns {Promise<{data:CourseSerializerType}>}
+ * @throws {StatusException} "课程名重复" | "课程选课码重复"
  */
 export const postTeacherCourse = ({ name, code }) => {
   return request(`${COURSE_MODULE}/teacher`, {
@@ -37,6 +38,7 @@ export const postTeacherCourse = ({ name, code }) => {
  * 学生加入课程
  * @param {string} code
  * @returns {Promise<{data:CourseSerializerType}>}
+ * @throws {StatusException} "选课码不存在" | "已经加入课程"
  */
 export const postStudentCourse = code => {
   return request(`${COURSE_MODULE}/student`, {
@@ -46,3 +48,12 @@ export const postStudentCourse = code => {
     }
   });
 };
+
+/**
+ * 获得课程详情
+ * @param courseId
+ * @returns {Promise<{data:CourseSerializerType}>}
+ */
+export const getCourseDetail = courseId => {
+  return request(`${COURSE_MODULE}/course/${courseId}`);
+};

+ 150 - 0
src/api/review.js

@@ -0,0 +1,150 @@
+import request from "@/util/request";
+import { REVIEW_MODULE } from "./_prefix";
+
+/**
+ * 新建互评作业
+ * @param {number} homeworkId 作业id
+ * @param {number} beginAt 开始时间
+ * @param {number} endAt 截止时间
+ * @param {number} taskNumber 互评任务数
+ * @returns {Promise<ReviewSimpleSerializerType>}
+ * @throws {StatusException} 输入不合法
+ */
+export const createReview = ({ homeworkId, beginAt, endAt, taskNumber }) => {
+  return request(`${REVIEW_MODULE}/review`, {
+    method: "POST",
+    body: { homeworkId, beginAt, endAt, taskNumber }
+  });
+};
+
+/**
+ * 学生申请解释互评作业
+ * @param homeworkId
+ * @param checkListItemId
+ * @param judgeItemId
+ * @param remark
+ * @returns {Promise<{}>}
+ * @throws {StatusException} 输入不合法
+ */
+export const argueReviewHomework = ({
+  homeworkId,
+  checkListItemId,
+  judgeItemId,
+  remark
+}) => {
+  return request(`${REVIEW_MODULE}/argue`, {
+    method: "POST",
+    body: { homeworkId, checkListItemId, judgeItemId, remark }
+  });
+};
+
+/**
+ * 老师查看互评作业列表
+ * @param {string|number} courseId
+ * @return {Promise<{data:ReviewSimpleSerializerType[]}>}
+ */
+export const getTeacherCourseReviewList = courseId => {
+  return request(`${REVIEW_MODULE}/teacher/course/${courseId}/review`);
+};
+
+/**
+ * 老师查看互评作业详情
+ * @param {string|number} reviewId
+ * @return {Promise<{data:ReviewDetailSerializerType}>}
+ */
+export const getReviewDetail = reviewId => {
+  return request(`${REVIEW_MODULE}/teacher/review/${reviewId}`);
+};
+
+/**
+ * 学生查看互评作业列表
+ * @param {string|number} courseId
+ * @return {Promise<{data:ReviewSimpleSerializerType[]}>}
+ */
+export const getStudentCourseReviewList = courseId => {
+  return request(`${REVIEW_MODULE}/student/course/${courseId}/review`);
+};
+
+/**
+ * 学生做互评作业
+ * @param {string|number} reviewId
+ * @param {{data:CheckListItemSerializerType}} checkListBody
+ * @return {Promise<{data:CheckListItemSerializerType[]}>}
+ * @throws {StatusException} 输入不合法
+ */
+export const postStudentReviewWork = (reviewId, checkListBody) => {
+  return request(`${REVIEW_MODULE}/student/review/${reviewId}`, {
+    method: "POST",
+    body: checkListBody
+  });
+};
+
+/**
+ * 学生查看互评结果列表
+ * @param {string|number} courseId
+ * @return {Promise<{data:ReviewSimpleSerializerType[]}>}
+ */
+export const getStudentReviewResultList = courseId => {
+  return request(`${REVIEW_MODULE}/student/course/${courseId}/result`);
+};
+
+/**
+ * 学生查看某次互评结果
+ * @param {string|number} reviewId
+ * @return {Promise<{data:ReviewResultSerializerType}>}
+ */
+export const getStudentReviewResultDetail = reviewId => {
+  return request(`${REVIEW_MODULE}/student/review/${reviewId}/result`);
+};
+
+/**
+ * 老师查看互评作业汇总结果
+ * @param {string|number} reviewId
+ * @return {Promise<{detail:ReviewDetailSerializerType,finishPercentage:number,studentIdCheckListAcceptNumMap:*}>}
+ */
+export const getReviewSumResult = reviewId => {
+  return request(`${REVIEW_MODULE}/sum/${reviewId}`);
+};
+
+/**
+ * 老师更新作业评分标准
+ * @param {string|number} reviewId
+ * @param {*} level
+ * @return {Promise<{}>}
+ * @throws {StatusException} 输入不合法
+ */
+export const postReviewSumLevel = (reviewId, level) => {
+  return request(`${REVIEW_MODULE}/sum/${reviewId}/level`, {
+    method: "POST",
+    body: level
+  });
+};
+
+/**
+ * 老师获得需要人工复核的文档列表
+ * @param {string|number} reviewId
+ * @return {Promise<ReviewSimpleSerializerType[]>}
+ */
+export const getTeacherArgueList = reviewId => {
+  return request(`${REVIEW_MODULE}/sum/${reviewId}/argue`);
+};
+
+/**
+ * 老师获得需要人工复核的文档详情
+ * @param {string|number} reviewId
+ * @param {string|number} groupId
+ * @return {Promise<{data:ReviewResultSerializerType}>}
+ */
+export const getTeacherArgueDetail = (reviewId, groupId) => {
+  return request(`${REVIEW_MODULE}/sum/${reviewId}/argue/${groupId}`);
+};
+
+/**
+ * 老师提交需要复核文档的结果
+ * @param {string|number} reviewId
+ * @param {string|number} groupId
+ * @return {Promise<{}>}
+ */
+export const postTeacherArgueResult = (reviewId, groupId) => {
+  return request(`${REVIEW_MODULE}/sum/${reviewId}/argue/${groupId}`);
+};

+ 15 - 19
src/util/request.js

@@ -3,30 +3,25 @@ import "whatwg-fetch";
 import router from "@/router";
 import { LOGIN_ROUTER } from "@/router/name";
 
-const codeMessage = {
-  200: "服务器成功返回请求的数据。",
-  201: "新建或修改数据成功。",
-  202: "一个请求已经进入后台排队(异步任务)。",
-  204: "删除数据成功。",
-  400: "发出的请求有错误,服务器没有进行新建或修改数据的操作。",
-  401: "用户没有权限(令牌、用户名、密码错误)。",
-  403: "用户得到授权,但是访问是被禁止的。",
-  404: "发出的请求针对的是不存在的记录,服务器没有进行操作。",
-  406: "请求的格式不可得。",
-  410: "请求的资源被永久删除,且不会再得到的。",
-  422: "当创建一个对象时,发生一个验证错误。",
-  500: "服务器发生错误,请检查服务器。",
-  502: "网关错误。",
-  503: "服务不可用,服务器暂时过载或维护。",
-  504: "网关超时。"
-};
+/**
+ * @description error
+ * @typedef {Object} StatusException
+ * @property {string} name status code
+ * @property {string} message 消息
+ * @property {{code:string,message:string}} response 返回值
+ */
 
+/**
+ * 判断是否抛异常
+ * @param response
+ * @returns {*}
+ * @throws StatusException
+ */
 function checkStatus(response) {
   if (response.status >= 200 && response.status < 300) {
     return response;
   }
-  const errortext = codeMessage[response.status] || response.message;
-  const error = new Error(errortext);
+  const error = new Error(response.message);
   error.name = response.status;
   error.response = response;
   throw error;
@@ -38,6 +33,7 @@ function checkStatus(response) {
  * @param  {string} url       The URL we want to request
  * @param  {{method:string,body}} [options] The options we want to pass to "fetch"
  * @return {Promise<*>}           An object containing either "data" or "err"
+ * @throws StatusException
  */
 export default async function request(url, options) {
   const defaultOptions = {