Browse Source

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

WuXinyu 7 năm trước cách đây
mục cha
commit
4251056720

+ 1 - 1
mock/serializers/user/UserSerializer.js

@@ -14,7 +14,7 @@ const makeId = require("../../util/makeId");
  * @param role
  * @returns {UserSerializerType}
  */
-module.exports = (role = "TEACHER") => {
+module.exports = (role = "STUDENT") => {
   return {
     id: makeId(),
     role: role,

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
src/assets/undraw_having_fun.svg


+ 0 - 2
src/layouts/TeacherMainLayout.vue

@@ -4,5 +4,3 @@
     <router-view></router-view>
   </div>
 </template>
-
-<style lang="scss"></style>

+ 4 - 0
src/router/routes.js

@@ -178,6 +178,10 @@ export default [
       {
         path: "code",
         component: () => import("@/views/student/Code")
+      },
+      {
+        path: "group",
+        component: () => import("@/views/student/Group")
       }
     ]
   },

+ 0 - 2
src/views/student/Code/detail.vue

@@ -47,5 +47,3 @@ export default {
   }
 };
 </script>
-
-<style scoped></style>

+ 247 - 1
src/views/student/Group/index.vue

@@ -1,3 +1,249 @@
 <template>
-  <div></div>
+  <div>
+    <page-header :routes="[{ name: '我的小组' }]">
+      <template slot="title">
+        我的小组 {{ this.groups.length > 0 && `「${this.groups[0].name}」` }}
+      </template>
+    </page-header>
+    <page-body>
+      <div v-if="groups.length > 0">
+        <div class="page-section">
+          <div class="columns is-desktop">
+            <div class="column">
+              <h5 class="title is-5">id:</h5>
+              <div class="subtitle is-6">{{ groups[0].id }}</div>
+            </div>
+            <div class="column">
+              <h5 class="title is-5">名称:</h5>
+              <div class="subtitle is-6">{{ groups[0].name }}</div>
+            </div>
+            <div class="column">
+              <h5 class="title is-5">选组码:</h5>
+              <div class="subtitle is-6">{{ groups[0].code }}</div>
+            </div>
+          </div>
+        </div>
+        <div class="divider">
+          <div class="columns is-multiline is-desktop">
+            <div
+              class="column is-3"
+              :key="member.id"
+              v-for="member in groups[0].members"
+            >
+              <card>
+                <h5 class="title is-5">成员:「{{ member.nickname }}」</h5>
+                <div class="subtitle is-6">{{ member.username }}</div>
+              </card>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <div
+        v-if="!isLoadingGroup && groups.length === 0"
+        style="padding: 50px"
+        class="columns is-desktop  is-vcentered"
+      >
+        <div class="column is-three-fifths-desktop">
+          <img src="@/assets/undraw_having_fun.svg" alt="" />
+        </div>
+        <div class="column">
+          <div class="title is-spaced">您还尚未加入任何小组</div>
+          <p class="subtitle">加入或创建小组,一起迎接挑战!</p>
+          <div class="buttons">
+            <a
+              @click="() => (this.showCreateModal = true)"
+              class="button is-primary"
+              >创建小组
+            </a>
+            <a
+              @click="() => (this.showJoinModal = true)"
+              class="button is-primary is-outlined"
+              >加入小组
+            </a>
+          </div>
+        </div>
+      </div>
+    </page-body>
+    <b-modal :active.sync="showCreateModal" :width="400">
+      <div class="card">
+        <div class="title">创建小组</div>
+        <b-notification type="is-danger" :active.sync="isServerError">
+          {{ errorMassage }}
+        </b-notification>
+        <div class="content">
+          <b-field
+            label="名称"
+            :type="$v.name.$error ? 'is-danger' : ''"
+            :message="
+              $v.name.$error
+                ? [
+                    !$v.name.basicChar
+                      ? '名称只能由大小写字母,数字,- 与 _ 组成'
+                      : undefined,
+                    !$v.name.required ? '请输入名称' : undefined
+                  ]
+                : ''
+            "
+          >
+            <b-input maxlength="50" v-model="$v.name.$model"></b-input>
+          </b-field>
+
+          <a
+            class="button is-primary"
+            :class="{ 'is-loading': submitLoading }"
+            @click="createGroup()"
+          >
+            创建小组
+          </a>
+        </div>
+      </div>
+    </b-modal>
+    <b-modal :active.sync="showJoinModal" :width="400">
+      <div class="card">
+        <div class="title">加入小组</div>
+        <b-notification type="is-danger" :active.sync="isServerError">
+          {{ errorMassage }}
+        </b-notification>
+        <div class="content">
+          <b-field
+            label="选组码"
+            :type="$v.code.$error ? 'is-danger' : ''"
+            :message="
+              $v.name.$error
+                ? [!$v.code.required ? '请输入选组码' : undefined]
+                : ''
+            "
+          >
+            <b-input v-model="$v.code.$model"></b-input>
+          </b-field>
+          <a
+            class="button is-primary"
+            :class="{ 'is-loading': submitLoading }"
+            @click="joinGroup()"
+          >
+            申请加入小组
+          </a>
+        </div>
+      </div>
+    </b-modal>
+  </div>
 </template>
+<script>
+import PageHeader from "@/components/PageHeader";
+import PageBody from "@/components/PageBody/index";
+import Card from "@/components/Card";
+import { required } from "vuelidate/lib/validators";
+import {
+  getStudentGroup,
+  postStudentGroup,
+  putStudentGroup
+} from "@/api/group";
+export default {
+  components: { PageBody, PageHeader, Card },
+  data() {
+    return {
+      showCreateModal: false,
+      showJoinModal: false,
+      name: "",
+      code: "",
+      isServerError: false,
+      errorMassage: "",
+      submitLoading: false,
+      isLoadingGroup: false,
+      groups: []
+    };
+  },
+  validations: {
+    name: {
+      required,
+      basicChar: name => /^[a-zA-Z0-9_-]*$/.test(name)
+    },
+    code: {
+      required
+    }
+  },
+  watch: {
+    showCreateModal(newValue) {
+      if (newValue === false) {
+        this.onModalClosed();
+      }
+    },
+    showJoinModal(newValue) {
+      if (newValue === false) {
+        this.onModalClosed();
+      }
+    }
+  },
+  mounted() {
+    this.loadGroup();
+  },
+  methods: {
+    async createGroup() {
+      this.$v.$touch();
+      if (!this.$v.name.$invalid) {
+        try {
+          this.submitLoading = true;
+          this.isServerError = false;
+          await postStudentGroup(this.name);
+          this.$toast.open({
+            message: `小组「${this.name}」创建成功`,
+            type: "is-success"
+          });
+          this.showCreateModal = false;
+          this.loadGroup();
+        } catch (e) {
+          this.errorMassage = e.message;
+          this.isServerError = true;
+        } finally {
+          this.submitLoading = false;
+        }
+      }
+    },
+    async joinGroup() {
+      this.$v.$touch();
+      if (!this.$v.code.$invalid) {
+        try {
+          this.submitLoading = true;
+          this.isServerError = false;
+          await putStudentGroup(this.code);
+          this.$toast.open({
+            message: `小组加入成功`,
+            type: "is-success"
+          });
+          this.showJoinModal = false;
+          this.loadGroup();
+        } catch (e) {
+          this.errorMassage = e.message;
+          this.isServerError = true;
+        } finally {
+          this.submitLoading = false;
+        }
+      }
+    },
+    onModalClosed() {
+      this.isServerError = false;
+      this.submitLoading = false;
+    },
+    async loadGroup() {
+      this.isLoadingGroup = true;
+      const { courseId } = this.$route.params;
+      const { data } = await getStudentGroup(courseId);
+      this.groups = data;
+      this.isLoadingGroup = false;
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+@import "../../../assets/scss/app";
+.card {
+  padding: $default-margin-between;
+  border-radius: $default-radius;
+}
+
+.divider {
+  padding-top: $default-margin-between;
+}
+</style>

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác