浏览代码

完成主页的layout

Michael Wang 7 年之前
父节点
当前提交
6e0e9034a9

+ 102 - 0
src/components/MainLayout/MainLayout.vue

@@ -0,0 +1,102 @@
+<template>
+  <div class="main-layout">
+    <header class="header qm-primary-text">
+      <!-- TODO: avatar -->
+      <span>{{user.name}}</span>
+      <span style="margin: auto 20px">|</span>
+      <span style="display: inline-block; margin-right: 20px; text-align: center;">退出登录</span>
+    </header>
+    <main class="content">
+      <slot></slot>
+    </main>
+    <nav class="nav">
+      <img src="./qm-logo.png" class="qm-logo" />
+      <ul>
+        <li>
+          <router-link class="link" to="/online-exam">在线考试&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</router-link>
+        </li>
+        <li>
+          <router-link class="link" to="/online-practice">在线练习&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</router-link>
+        </li>
+        <li>
+          <router-link class="link" to="/offline-exam">离线考试&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</router-link>
+        </li>
+        <li>
+          <router-link class="link" to="/password">修改密码&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</router-link>
+        </li>
+      </ul>
+    </nav>
+    <footer class="footer">©️2018 启明泰和</footer>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "MainLayout",
+  data() {
+    return {
+      user: window.wk_user
+    };
+  }
+};
+</script>
+
+<style scoped>
+.main-layout {
+  display: grid;
+  grid-template-areas: "nav header" "nav content" "nav footer";
+  min-height: 100vh;
+  grid-template-columns: 180px 1fr;
+  grid-template-rows: auto 1fr auto;
+}
+
+.header {
+  grid-area: header;
+  height: 50px;
+  background-color: #ffffff;
+  box-shadow: 0px 1px 0px 0px #eeeeee;
+
+  text-align: right;
+  line-height: 50px;
+}
+
+.nav {
+  grid-area: nav;
+  background-image: url(./nav-bg.jpg);
+  width: 180px;
+  height: 100vh;
+
+  display: flex;
+  flex-direction: column;
+}
+
+.qm-logo {
+  width: 80px;
+  height: 68;
+  margin: 30px auto;
+}
+
+.link {
+  background-image: url(./link.png);
+  background-repeat: no-repeat;
+  background-position: 30px 50%;
+  /* margin-left: -40px; */
+  line-height: 40px;
+  width: 100%;
+  display: inline-block;
+
+  color: #ffffff;
+}
+
+.router-link-active,
+.link:hover {
+  background-image: url(./link-active.png);
+  background-color: rgba(255, 255, 255, 0.5);
+  color: #fafafa;
+}
+
+.footer {
+  grid-area: footer;
+  margin-bottom: 10px;
+}
+</style>

二进制
src/components/MainLayout/link-active.png


二进制
src/components/MainLayout/link.png


二进制
src/components/MainLayout/nav-bg.jpg


二进制
src/components/MainLayout/qm-logo.png


+ 8 - 5
src/features/OnlineExam/OnlineExamHome.vue

@@ -1,7 +1,10 @@
 <template>
-  <div class="home">
-    <Table border :columns="columns" :data="courses"></Table>
-  </div>
+  <main-layout>
+    <div class="home">
+      <i-table border :columns="columns" :data="courses"></i-table>
+
+    </div>
+  </main-layout>
 </template>
 
 <script>
@@ -11,7 +14,7 @@ export default {
     return {
       columns: [
         {
-          title: "课程名称",
+          title: "课程",
           key: "courseName"
         },
         {
@@ -49,4 +52,4 @@ export default {
 </script>
 
 <style scoped>
-</style>
+</style>

+ 8 - 0
src/features/login/Login.vue

@@ -100,6 +100,14 @@ export default {
         //缓存用户信息
         window.localStorage.setItem("token", data.token);
         window.localStorage.setItem("key", data.key);
+
+        //FIXME: vuex
+        window.wk_user = {
+          name: data.displayName,
+          code: data.studentCode,
+          orgName: data.orgName
+        };
+        this.$router.push("/online-exam");
       } else {
         this.errorInfo = data.desc;
       }

+ 23 - 5
src/main.js

@@ -10,21 +10,26 @@ import "./styles/global.css";
 
 import axiosPlugin from "./utils/axios";
 
+import MainLayout from "@/components/MainLayout/MainLayout.vue";
+
 Vue.use(iView);
 Vue.use(axiosPlugin);
 
 Vue.config.productionTip = false;
 
-new Vue({
-  router,
-  store,
-  render: h => h(App)
-}).$mount("#app");
+Vue.component("main-layout", MainLayout);
 
 if (process.env.NODE_ENV === "development") {
   console.log("非生产环境,自动登录");
   (async () => {
     if (window.localStorage.getItem("token")) {
+      //FIXME: vuex
+      window.wk_user = {
+        name: "mock name",
+        code: "mock code",
+        orgName: "mock org name"
+      };
+      console.log("非生产环境: mock user name");
       return;
     }
     const response = await fetch("/api/ecs_core/auth/login", {
@@ -43,8 +48,21 @@ if (process.env.NODE_ENV === "development") {
     if (data.token) {
       window.localStorage.setItem("token", data.token);
       window.localStorage.setItem("key", data.key);
+
+      //FIXME: vuex
+      window.wk_user = {
+        name: data.displayName,
+        code: data.studentCode,
+        orgName: data.orgName
+      };
     } else {
       console.log(data.desc);
     }
   })();
 }
+
+new Vue({
+  router,
+  store,
+  render: h => h(App)
+}).$mount("#app");

+ 7 - 0
src/utils/axios.js

@@ -6,6 +6,13 @@ import router from "../router";
 
 //请求拦截
 
+/**
+ * A. token lifecycle
+ * 1. /login UI => localStorage.removeItem('token') && localStorage.setItem('token')
+ * 2. non /login UI => axios if(!wk_token) wk_token = window.localStorage.getItem("token"), send request
+ * 3. if axios request fail with 401/403, wk_token = null, redirect to /login removeItem('token')
+ * */
+
 let wk_token, wk_key;
 Axios.interceptors.request.use(
   config => {