Procházet zdrojové kódy

[新增]基本界面组成 && 基本布局

WuXinyu před 7 roky
rodič
revize
eea8e86055

+ 4 - 0
src/assets/scss/app.scss

@@ -7,6 +7,10 @@
 @import "~bulma";
 @import "~buefy/src/scss/buefy";
 
+
+$border-color:#b9c7d8;
+$default-border:1px solid #c9d8ea;
+
 .has-text-primary{
   color:#209cee !important;
 }

+ 4 - 1
src/components/Card/index.vue

@@ -24,12 +24,15 @@ export default {
 </script>
 
 <style lang="scss" scoped>
+@import "../../assets/scss/app";
+
 .custom-card {
   width: 100%;
   height: 100%;
   position: relative;
   background: #ffffff;
-  border: 2px solid #b9c7d8;
+  border: $default-border;
+  color: #152935;
 }
 
 .hoverable {

+ 3 - 1
src/layouts/HomeLayout/HomeHeader/index.vue

@@ -55,8 +55,10 @@ export default {
 </script>
 
 <style lang="scss" scoped>
+@import "../../../assets/scss/app";
+
 .nav-section {
-  border-bottom: 2px solid #b9c7d8;
+  border-bottom: $default-border;
 }
 
 @media screen and (min-width: 1088px) {

+ 104 - 0
src/layouts/courseLayouts/LayoutStructure.vue

@@ -0,0 +1,104 @@
+<template>
+  <div class="course-layout">
+    <div class="menu-section">
+      <div class="menu-sticky">
+        <div class="header-logo">MOOC</div>
+        <div class="course-detail">
+          {{ course.name }}
+          <b-loading :is-full-page="false" :active.sync="isLoading"></b-loading>
+        </div>
+        <slot />
+      </div>
+    </div>
+    <div class="router-section"><router-view /></div>
+  </div>
+</template>
+
+<script>
+import { FETCH_CURRENT_COURSE } from "@/store/type/actions.type";
+import { mapState } from "vuex";
+
+export default {
+  computed: {
+    ...mapState({
+      course: state => state.course.currentCourse
+    })
+  },
+  data() {
+    return {
+      isLoading: false
+    };
+  },
+  async mounted() {
+    const { courseId } = this.$route.params;
+    this.isLoading = true;
+    await this.$store.dispatch(FETCH_CURRENT_COURSE, courseId);
+    this.isLoading = false;
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+@import "../../assets/scss/app.scss";
+
+$menu-width: 300px;
+$menu-padding: 24px;
+$screen-width: 1450px;
+$left-padding: "(100% -" #{$screen-width} "-" #{$menu-padding} "* 2) / 2";
+$left-width: #{$left-padding} + #{$menu-width};
+$left-padding-calc: calc(#{$left-padding});
+$left-width-calc: calc(#{$left-width});
+$top-section-height: 4.25rem;
+
+.course-layout {
+  display: flex;
+  min-height: 100vh;
+  justify-content: stretch;
+  position: relative;
+}
+
+.router-section {
+  padding: 24px;
+  flex-grow: 1;
+  max-width: 1000px;
+}
+.menu-section {
+  min-width: $menu-width;
+  width: $left-width-calc;
+  background: white;
+  border-right: 1px solid #c9d8ea;
+  padding-left: $left-padding-calc;
+  .menu-sticky {
+    width: $menu-width;
+    position: sticky;
+    overflow-y: auto;
+    padding: 0 $menu-padding;
+    top: 0;
+    height: 100vh;
+
+    .header-logo {
+      font-family: "IBM Plex Sans", -apple-system, BlinkMacSystemFont,
+        "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue",
+        Helvetica, Arial, sans-serif;
+      font-weight: bold;
+      font-size: 1.7em;
+      color: #3d70b2;
+      padding-right: 20px;
+      line-height: $top-section-height;
+      a {
+        color: #3d70b2;
+      }
+    }
+    .course-detail {
+      position: relative;
+      padding: 15px;
+      background: #f4f7fb;
+      border: 1px solid #c9d8ea;
+      border-radius: 3px;
+      box-shadow: 0 1px 2px rgba(201, 216, 234, 0.5);
+      margin-bottom: 1em;
+      min-height: 54px;
+    }
+  }
+}
+</style>

+ 15 - 0
src/layouts/courseLayouts/StudentCourseLayout.vue

@@ -0,0 +1,15 @@
+<template>
+  <layout-structure> <student-menu /></layout-structure>
+</template>
+
+<script>
+import StudentMenu from "./StudentMenu";
+import LayoutStructure from "./LayoutStructure";
+
+export default {
+  components: {
+    StudentMenu,
+    LayoutStructure
+  }
+};
+</script>

+ 48 - 0
src/layouts/courseLayouts/StudentMenu.vue

@@ -0,0 +1,48 @@
+<template>
+  <aside class="menu">
+    <p class="menu-label">总览</p>
+    <ul class="menu-list">
+      <li>
+        <router-link active-class="is-active" :to="`${prefix}/dashboard`">
+          工作台
+        </router-link>
+      </li>
+    </ul>
+    <p class="menu-label">作业</p>
+    <ul class="menu-list">
+      <li>
+        <router-link active-class="is-active" :to="`${prefix}/code`">
+          代码作业
+        </router-link>
+      </li>
+      <li>
+        <router-link active-class="is-active" :to="`${prefix}/document`"
+          >文档作业</router-link
+        >
+      </li>
+      <li>
+        <router-link active-class="is-active" :to="`${prefix}/review`"
+          >评审作业</router-link
+        >
+      </li>
+    </ul>
+    <p class="menu-label">小组</p>
+    <ul class="menu-list">
+      <li>
+        <router-link active-class="is-active" :to="`${prefix}/group`"
+          >我的小组</router-link
+        >
+      </li>
+    </ul>
+  </aside>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      prefix: `/course-student/${this.$route.params.courseId}`
+    };
+  }
+};
+</script>

+ 15 - 0
src/layouts/courseLayouts/TeacherCourseLayout.vue

@@ -0,0 +1,15 @@
+<template>
+  <layout-structure> <teacher-menu /></layout-structure>
+</template>
+
+<script>
+import TeacherMenu from "./TeacherMenu";
+import LayoutStructure from "./LayoutStructure";
+
+export default {
+  components: {
+    TeacherMenu,
+    LayoutStructure
+  }
+};
+</script>

+ 40 - 0
src/layouts/courseLayouts/TeacherMenu.vue

@@ -0,0 +1,40 @@
+<template>
+  <aside class="menu">
+    <p class="menu-label">总览</p>
+    <ul class="menu-list">
+      <li>
+        <router-link active-class="is-active" :to="`${prefix}`"
+          >工作台</router-link
+        >
+      </li>
+    </ul>
+    <p class="menu-label">作业</p>
+    <ul class="menu-list">
+      <li>
+        <router-link active-class="is-active" :to="`${prefix}/code`"
+          >代码作业</router-link
+        >
+      </li>
+      <li>
+        <router-link active-class="is-active" :to="`${prefix}/document`"
+          >文档作业</router-link
+        >
+      </li>
+      <li>
+        <router-link active-class="is-active" :to="`${prefix}/review`"
+          >评审作业</router-link
+        >
+      </li>
+    </ul>
+  </aside>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      prefix: `/course-teacher/${this.$route.params.courseId}`
+    };
+  }
+};
+</script>

+ 1 - 1
src/router/name.js

@@ -4,4 +4,4 @@ export const HOME = "HOME";
 export const TEACHER = "TEACHER";
 export const STUDENT = "STUDENT";
 export const TEACHER_COURSE = "TEACHER_COURSE";
-export const STUDENT_COURSE = "TEACHER_COURSE";
+export const STUDENT_COURSE = "STUDENT_COURSE";

+ 46 - 22
src/router/routes.js

@@ -1,20 +1,16 @@
-import { HOME, LOGIN, REGISTER, STUDENT, TEACHER } from "@/router/name";
+import {
+  HOME,
+  LOGIN,
+  REGISTER,
+  STUDENT,
+  STUDENT_COURSE,
+  TEACHER,
+  TEACHER_COURSE
+} from "@/router/name";
 import { judgeLogin } from "@/util/auth";
 import { getUserProfile } from "@/util/profileStorage";
 
 export default [
-  {
-    path: "/",
-    name: HOME,
-    redirect: () => {
-      if (judgeLogin()) {
-        const { role } = getUserProfile();
-        return { name: role };
-      } else {
-        return { name: LOGIN };
-      }
-    }
-  },
   {
     path: "/login",
     component: () => import("@/layouts/LoginLayout"),
@@ -45,26 +41,42 @@ export default [
     ]
   },
   {
-    path: "/teacher-course",
-    component: () => import("@/layouts/HomeLayout"),
+    path: "/course-teacher/:courseId",
+    component: () => import("@/layouts/courseLayouts/StudentCourseLayout.vue"),
     meta: { requiresAuth: true },
     children: [
       {
-        name: TEACHER,
+        name: TEACHER_COURSE,
         path: "",
-        component: () => import("@/views/teacher/Home")
+        component: () => import("@/views/teacher/Dashboard")
       }
     ]
   },
   {
-    path: "/student-course",
-    component: () => import("@/layouts/HomeLayout"),
+    path: "/course-student/:courseId",
+    component: () => import("@/layouts/courseLayouts/StudentCourseLayout.vue"),
     meta: { requiresAuth: true },
     children: [
       {
-        name: TEACHER,
-        path: "",
-        component: () => import("@/views/teacher/Home")
+        name: STUDENT_COURSE,
+        path: "dashboard",
+        component: () => import("@/views/student/Dashboard")
+      },
+      {
+        path: "code",
+        component: () => import("@/views/student/Code")
+      },
+      {
+        path: "document",
+        component: () => import("@/views/student/Document")
+      },
+      {
+        path: "review",
+        component: () => import("@/views/student/Review")
+      },
+      {
+        path: "code",
+        component: () => import("@/views/student/Code")
       }
     ]
   },
@@ -79,5 +91,17 @@ export default [
         component: () => import("@/views/student/Home")
       }
     ]
+  },
+  {
+    path: "/",
+    name: HOME,
+    redirect: () => {
+      if (judgeLogin()) {
+        const { role } = getUserProfile();
+        return { name: role };
+      } else {
+        return { name: LOGIN };
+      }
+    }
   }
 ];

+ 3 - 1
src/store/index.js

@@ -2,11 +2,13 @@ import Vue from "vue";
 import Vuex from "vuex";
 
 import user from "./modules/user.module";
+import course from "./modules/course.module";
 
 Vue.use(Vuex);
 
 export default new Vuex.Store({
   modules: {
-    user
+    user,
+    course
   }
 });

+ 26 - 0
src/store/modules/course.module.js

@@ -0,0 +1,26 @@
+import * as ACTIONS from "@/store/type/actions.type";
+import * as MUTATIONS from "@/store/type/mutations.type.js";
+import { getCourseDetail } from "@/api/course";
+
+const courseState = {
+  currentCourse: {}
+};
+
+const actions = {
+  async [ACTIONS.FETCH_CURRENT_COURSE](context, courseId) {
+    const { data } = await getCourseDetail(courseId);
+    context.commit(MUTATIONS.SET_CURRENT_COURSE, data);
+  }
+};
+
+const mutations = {
+  [MUTATIONS.SET_CURRENT_COURSE](state, courseSerializer = {}) {
+    state.currentCourse = courseSerializer;
+  }
+};
+
+export default {
+  state: courseState,
+  actions,
+  mutations
+};

+ 1 - 0
src/store/type/actions.type.js

@@ -1 +1,2 @@
 export const FETCH_PROFILE = "fetchProfile";
+export const FETCH_CURRENT_COURSE = "fetchCurrentCourse";

+ 1 - 0
src/store/type/mutations.type.js

@@ -1 +1,2 @@
 export const SET_PROFILE = "setProfile";
+export const SET_CURRENT_COURSE = "setCurrentCourse";

+ 3 - 0
src/views/student/Code/index.vue

@@ -0,0 +1,3 @@
+<template>
+  <div></div>
+</template>

+ 3 - 0
src/views/student/Dashboard/index.vue

@@ -0,0 +1,3 @@
+<template>
+  <div></div>
+</template>

+ 3 - 0
src/views/student/Document/index.vue

@@ -0,0 +1,3 @@
+<template>
+  <div></div>
+</template>

+ 3 - 0
src/views/student/Group/index.vue

@@ -0,0 +1,3 @@
+<template>
+  <div></div>
+</template>

+ 3 - 1
src/views/student/Home/index.vue

@@ -11,7 +11,9 @@
     <div class="container">
       <div class="columns is-multiline is-desktop">
         <div :key="item.id" v-for="item in courses" class="column is-4">
-          <card hoverable>{{ item.name }}</card>
+          <router-link :to="`/course-student/${item.id}/dashboard`">
+            <card hoverable>{{ item.name }}</card>
+          </router-link>
         </div>
       </div>
     </div>

+ 68 - 0
src/views/student/Review/index.vue

@@ -0,0 +1,68 @@
+<template>
+  <div>
+    <nav class="breadcrumb" aria-label="breadcrumbs">
+      <ul>
+        <li><router-link :to="{ name: 'HOME' }">所有课程</router-link></li>
+        <li>
+          <router-link :to="`/student-course/${course.id}/dashboard`">{{
+            course.name
+          }}</router-link>
+        </li>
+        <li class="is-active">
+          <router-link :to="`/student-course/${course.id}/review`"
+            >评审作业</router-link
+          >
+        </li>
+      </ul>
+    </nav>
+    <div style="margin: 30px 0">
+      <h1 class="title">评审作业</h1>
+      <div class="subtitle">您仍剩余 {{ review.length }} 份评审作业待完成</div>
+    </div>
+
+    <div class="tabs">
+      <ul>
+        <li class="is-active"><a>待完成</a></li>
+        <li><a>需复合</a></li>
+      </ul>
+    </div>
+    <div class="columns is-multiline is-desktop">
+      <div :key="item.id" v-for="item in review" class="column is-4">
+        <card hoverable>{{ item.name }}</card>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapState } from "vuex";
+import { getStudentCourseReviewList } from "@/api/review";
+import Card from "@/components/Card";
+export default {
+  components: {
+    Card
+  },
+  computed: {
+    ...mapState({
+      course: state => state.course.currentCourse
+    })
+  },
+  data() {
+    return {
+      courses: [],
+      review: []
+    };
+  },
+  mounted() {
+    getStudentCourseReviewList(this.courses.id).then(
+      value => (this.review = value.data)
+    );
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.top-nav-section {
+  padding: 0 40px;
+}
+</style>

+ 3 - 0
src/views/teacher/Dashboard/index.vue

@@ -0,0 +1,3 @@
+<template>
+  <div></div>
+</template>

+ 3 - 1
src/views/teacher/Home/index.vue

@@ -11,7 +11,9 @@
     <div class="container">
       <div class="columns is-multiline is-desktop">
         <div :key="item.id" v-for="item in courses" class="column is-4">
-          <card hoverable>{{ item.name }}</card>
+          <router-link :to="`/course-teacher/${item.id}/dashboard`">
+            <card hoverable>{{ item.name }}</card>
+          </router-link>
         </div>
       </div>
     </div>