Browse Source

主页修改

zhangjie 3 years ago
parent
commit
118a26ca24

+ 2 - 0
package.json

@@ -14,6 +14,7 @@
     "format": "prettier --ignore-path .gitignore .  --write"
   },
   "dependencies": {
+    "@chenfengyuan/vue-qrcode": "^2.0.0",
     "@vitejs/plugin-legacy": "^1.7.1",
     "axios": "^0.26.0",
     "axios-progress-bar": "^1.2.0",
@@ -23,6 +24,7 @@
     "moment": "^2.29.1",
     "naive-ui": "^2.26.1",
     "pinia": "^2.0.11",
+    "qrcode": "^1.5.0",
     "tailwindcss": "^3.0.23",
     "ua-parser-js": "^1.0.2",
     "vfonts": "^0.0.3",

+ 0 - 9
src/App.vue

@@ -40,15 +40,6 @@ watchEffect(() => {
 </template>
 
 <style>
-#app {
-  font-family: Avenir, Helvetica, Arial, sans-serif;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-  text-align: center;
-  color: #2c3e50;
-  margin-top: 60px;
-}
-
 .global-mask {
   position: absolute;
   top: 0;

+ 4 - 5
src/api/changePwd.ts

@@ -2,9 +2,8 @@ import { httpApp } from "@/plugins/axiosApp";
 
 /** 修改密码 */
 export async function changePwdApi(password: string, newPassword: string) {
-  return httpApp.put<any, { data: { content: any } }>(
-    "/api/ecs_core/student/password",
-    null,
-    { params: { password, newPassword } }
-  );
+  return httpApp.put<any>("/api/ecs_core/student/password", null, {
+    params: { password, newPassword },
+    setGlobalMask: true,
+  });
 }

+ 32 - 0
src/api/mainLayout.ts

@@ -0,0 +1,32 @@
+import { httpApp } from "@/plugins/axiosApp";
+
+/** 获取app下载地址 */
+export async function appDownloadApi() {
+  return httpApp.get<string>(
+    "/api/ecs_core/systemProperty/APP_DOWNLOAD_URL",
+    {}
+  );
+}
+/** 获取app是否可用 */
+export async function appEnableApi(rootOrgId: number) {
+  return httpApp.get<boolean>(
+    `/api/ecs_core/org/property/${rootOrgId}/APP_ENABLED`,
+    {}
+  );
+}
+
+interface StuMenuOption {
+  id: string;
+  name: string;
+  routeCode: string;
+  weight: number;
+  [propName: any]: any;
+}
+/** 获取用户菜单 */
+export async function studentClientMenuApi(rootOrgId: number) {
+  return httpApp.get<any, { data: StuMenuOption[] }>(
+    "/api/ecs_core/rolePrivilege/getStudentClientMenu",
+    null,
+    { params: { rootOrgId } }
+  );
+}

+ 147 - 44
src/components/MainLayout/MainLayout.vue

@@ -1,47 +1,132 @@
 <script lang="ts" setup>
-import { onMounted } from "vue";
-import menuData from "./menu.json";
-console.log(menuData);
+import { computed, onMounted, watch } from "vue";
+import { store } from "@/store/store";
+import {
+  appDownloadApi,
+  appEnableApi,
+  studentClientMenuApi,
+} from "@/api/mainLayout";
+import { useRoute, useRouter } from "vue-router";
+import QM_LOGO from "./qm-logo.png";
+import VueQrcode from "@chenfengyuan/vue-qrcode";
 
-type MenuOption = {
+const router = useRouter();
+const route = useRoute();
+
+const user = store.user;
+
+// computed
+const customMenuLogo = computed(() =>
+  store.QECSConfig.IS_CUSTOM_MENU_LOGO
+    ? store.QECSConfig.CUS_MENU_LOGO_FILE_URL
+    : QM_LOGO
+);
+const bindUserQrcodeUrl = computed(() => {
+  const { rootOrgId, studentCodeList, identityNumber } = store.user;
+  return JSON.stringify({
+    rootOrgId,
+    studentCode: studentCodeList.join(),
+    identityNumber,
+  });
+});
+
+let appDownloadUrl = $ref("");
+let appEnable = $ref(false);
+// 页面初始化
+const initData = async () => {
+  const res1 = await appEnableApi(user.rootOrgId);
+  appEnable = res1.data;
+  if (appEnable) {
+    const res2 = await appDownloadApi();
+    appDownloadUrl = res2.data;
+  }
+};
+// 菜单相关
+interface MenuOption {
   id: string;
-  code: string;
   name: string;
-  routeCode: string;
+  routeName: string;
+}
+const menuRouterDict: Record<string, string> = {
+  STU_ONLINE_EXAM: "/online-exam",
+  STU_ONLINE_HOMEWORK: "/online-homework",
+  STU_ONLINE_PRACTICE: "/online-practice",
+  STU_OFFLINE_EXAM: "/offline-exam",
+  STU_NOTICE: "/site-message",
+  STU_MODIFY_PWD: "ChangePassword",
 };
-
 let curMenu = $ref("");
-let menuOptions = $ref<any[]>([]);
+let menuOptions = $ref<MenuOption[]>([]);
+let curMenuOption = $ref<MenuOption | undefined>();
+let breadcrumbs = $ref<MenuOption[]>([]);
 
-const getMenus = () => {
-  menuOptions = menuData.map((item) => {
-    return { ...item };
-  });
+const getMenus = async () => {
+  const res = await studentClientMenuApi(store.user.rootOrgId);
+  menuOptions = res.data
+    .sort((a, b) => b.weight - a.weight)
+    .map((item) => {
+      return {
+        id: item.id,
+        name: item.name,
+        routeName: menuRouterDict[item.routeCode.toUpperCase()],
+      };
+    });
 };
 const swithMenu = (menu: MenuOption) => {
   // console.log(menu);
-  curMenu = menu.routeCode;
-  console.log(curMenu);
+  console.log(menu.routeName);
+  void router.push({ name: menu.routeName });
 };
 
-const breadcrumbs = $ref([
-  {
-    id: "1",
-    url: "1",
-    name: "考试",
-  },
-]);
+// route change
+const routerChange = () => {
+  curMenuOption = menuOptions.find((item) => item.routeName === route.name);
+  if (!curMenuOption) return;
+  curMenu = curMenuOption.routeName;
+  breadcrumbs = [{ ...curMenuOption }];
+};
 
 const toModifyPwd = () => {
-  console.log("logout");
+  logger({
+    cnl: ["console"],
+    pgn: curMenuOption?.name,
+    act: "点击",
+    stk: "修改密码",
+  });
+
+  void router.push({ name: "ChangePassword" });
 };
 const toLogout = () => {
-  console.log("logout");
+  logger({
+    cnl: ["console"],
+    pgn: curMenuOption?.name,
+    act: "点击",
+    stk: "退出登录",
+  });
 };
 
-onMounted(() => {
-  getMenus();
+onMounted(async () => {
+  void initData();
+  await getMenus();
+  console.log(route.name);
+
+  if (menuOptions.length && route.name === "MainLayout") {
+    void router.push({ name: menuOptions.slice(-1)[0].routeName });
+    // void router.push({ name: menuOptions[0].routeName });
+    return;
+  }
+  routerChange();
 });
+
+watch(
+  () => route,
+  (val) => {
+    console.log(val);
+
+    if (val.name === "MainLayout") return;
+    routerChange();
+  }
+);
 </script>
 
 <template>
@@ -49,7 +134,7 @@ onMounted(() => {
     <!-- header -->
     <div class="home-header">
       <div class="header-infos">
-        <div class="header-info">
+        <div v-if="appEnable" class="header-info">
           <n-popover placement="bottom" trigger="hover">
             <template #trigger>
               <p class="header-info-cont">手机端登录(Android)</p>
@@ -58,12 +143,18 @@ onMounted(() => {
               <n-tabs type="segment">
                 <n-tab-pane name="android" tab="下载安卓Apk">
                   <div class="qr-code">
-                    <img src="" alt="" />
+                    <vue-qrcode
+                      :value="appDownloadUrl"
+                      :options="{ width: 200 }"
+                    ></vue-qrcode>
                   </div>
                 </n-tab-pane>
                 <n-tab-pane name="bindUser" tab="绑定用户">
                   <div class="qr-code">
-                    <img src="" alt="" />
+                    <vue-qrcode
+                      :value="bindUserQrcodeUrl"
+                      :options="{ width: 200 }"
+                    ></vue-qrcode>
                   </div>
                 </n-tab-pane>
               </n-tabs>
@@ -73,24 +164,28 @@ onMounted(() => {
         <div class="header-info">
           <n-popover placement="bottom" trigger="hover">
             <template #trigger>
-              <p class="header-info-cont">username</p>
+              <p class="header-info-cont">{{ user.displayName }}</p>
             </template>
             <div class="user-info">
               <div class="user-info-item">
                 <span>底照</span>
-                <img class="user-avatar" src="" alt="" />
+                <img
+                  class="user-avatar"
+                  :src="user.photoPath"
+                  :alt="user.displayName"
+                />
               </div>
               <div class="user-info-item">
                 <span>学号</span>
-                <span>学号1212</span>
+                <span>{{ user.studentCodeList.join() }}</span>
               </div>
               <div class="user-info-item">
                 <span>身份证号</span>
-                <span>身份证号11</span>
+                <span>{{ user.identityNumber }}</span>
               </div>
               <div class="user-info-item">
                 <span>学习中心</span>
-                <span>学习中心11</span>
+                <span>{{ user.orgName }}</span>
               </div>
               <div class="user-info-item">
                 <n-button type="success" block @click="toModifyPwd"
@@ -108,16 +203,14 @@ onMounted(() => {
     <!-- navs -->
     <div class="home-navs">
       <div class="home-logo">
-        <div class="home-logo-content">
-          <!-- <img v-if="schoolLogo" :src="schoolLogo" alt="知学知考" /> -->
-        </div>
+        <img :src="customMenuLogo" />
       </div>
       <div class="home-menu">
         <div v-for="menu in menuOptions" :key="menu.id" class="home-menu-item">
           <div
             :class="[
               'home-menu-content',
-              { 'is-active': curMenu === menu.routeCode },
+              { 'is-active': curMenu === menu.routeName },
             ]"
             @click="swithMenu(menu)"
           >
@@ -134,7 +227,10 @@ onMounted(() => {
         </span>
         <div class="breadcrumb-body">
           <n-breadcrumb>
-            <n-breadcrumb-item v-for="bread in breadcrumbs" :key="bread.url">
+            <n-breadcrumb-item
+              v-for="bread in breadcrumbs"
+              :key="bread.routeName"
+            >
               {{ bread.name }}
             </n-breadcrumb-item>
           </n-breadcrumb>
@@ -181,7 +277,7 @@ onMounted(() => {
   vertical-align: middle;
   font-size: var(--app-font-size);
   position: relative;
-  padding: 0 15px;
+  padding: 0 20px;
   cursor: pointer;
 }
 .header-info-cont:hover {
@@ -205,14 +301,16 @@ onMounted(() => {
   display: flex;
   align-items: center;
   justify-content: space-between;
-  padding: 10px 0;
+  padding: 12px 0;
+}
+.user-info-item:not(:last-child) {
   border-bottom: 1px solid var(--app-color-border);
 }
 .user-avatar {
   display: block;
   width: 80px;
   height: 80px;
-  box-shadow: 0 0 1px var(--app-color-border);
+  box-shadow: 0 0 1px var(--app-color-border-dark);
 }
 .qr-list {
   width: 240px;
@@ -221,7 +319,7 @@ onMounted(() => {
   width: 200px;
   height: 200px;
   margin: 0 auto;
-  padding: 10px 0;
+  padding: 0 0 20px;
 }
 .qr-code > img {
   display: block;
@@ -244,11 +342,16 @@ onMounted(() => {
 }
 .home-logo {
   width: 80px;
-  height: 68px;
+  min-height: 62px;
+  max-height: 100px;
   margin: 30px auto;
-  background-color: var(--app-color-white);
   border-radius: var(--app-border-radius);
 }
+.home-logo > img {
+  display: block;
+  width: 100%;
+  height: auto;
+}
 .home-menu {
   color: var(--app-color-white);
 }

+ 0 - 140
src/components/MainLayout/menu.json

@@ -1,140 +0,0 @@
-[
-  {
-    "id": 6555,
-    "code": "stu_online_exam_0",
-    "name": "在线考试1343",
-    "parentId": null,
-    "groupId": 20,
-    "groupCode": "STUDENT_CLIENT_MENU_0",
-    "hasPrivilege": true,
-    "description": "在线考试3243",
-    "updateTime": "2020-05-27 16:18:35",
-    "creationTime": "2020-05-13 18:09:54",
-    "weight": 6,
-    "ext1": "ONLINE",
-    "ext2": null,
-    "ext3": null,
-    "ext4": null,
-    "ext5": null,
-    "routeCode": "stu_online_exam",
-    "nodeName": "在线考试1343",
-    "nodeCode": "stu_online_exam_0",
-    "parentNodeId": null,
-    "nodeId": "6555"
-  },
-  {
-    "id": 6556,
-    "code": "stu_online_homework_0",
-    "name": "在线作业",
-    "parentId": null,
-    "groupId": 20,
-    "groupCode": "STUDENT_CLIENT_MENU_0",
-    "hasPrivilege": true,
-    "description": "在线作业",
-    "updateTime": "2020-05-13 18:09:54",
-    "creationTime": "2020-05-13 18:09:54",
-    "weight": 5,
-    "ext1": null,
-    "ext2": null,
-    "ext3": null,
-    "ext4": null,
-    "ext5": null,
-    "routeCode": "stu_online_homework",
-    "nodeName": "在线作业",
-    "nodeCode": "stu_online_homework_0",
-    "parentNodeId": null,
-    "nodeId": "6556"
-  },
-  {
-    "id": 6557,
-    "code": "stu_online_practice_0",
-    "name": "在线练习3",
-    "parentId": null,
-    "groupId": 20,
-    "groupCode": "STUDENT_CLIENT_MENU_0",
-    "hasPrivilege": true,
-    "description": "在线练习",
-    "updateTime": "2020-05-27 16:18:42",
-    "creationTime": "2020-05-13 18:09:54",
-    "weight": 4,
-    "ext1": null,
-    "ext2": null,
-    "ext3": null,
-    "ext4": null,
-    "ext5": null,
-    "routeCode": "stu_online_practice",
-    "nodeName": "在线练习3",
-    "nodeCode": "stu_online_practice_0",
-    "parentNodeId": null,
-    "nodeId": "6557"
-  },
-  {
-    "id": 6558,
-    "code": "stu_offline_exam_0",
-    "name": "离线考试",
-    "parentId": null,
-    "groupId": 20,
-    "groupCode": "STUDENT_CLIENT_MENU_0",
-    "hasPrivilege": true,
-    "description": "离线考试",
-    "updateTime": "2020-05-13 18:09:54",
-    "creationTime": "2020-05-13 18:09:54",
-    "weight": 3,
-    "ext1": null,
-    "ext2": null,
-    "ext3": null,
-    "ext4": null,
-    "ext5": null,
-    "routeCode": "stu_offline_exam",
-    "nodeName": "离线考试",
-    "nodeCode": "stu_offline_exam_0",
-    "parentNodeId": null,
-    "nodeId": "6558"
-  },
-  {
-    "id": 6559,
-    "code": "stu_notice_0",
-    "name": "公告通知",
-    "parentId": null,
-    "groupId": 20,
-    "groupCode": "STUDENT_CLIENT_MENU_0",
-    "hasPrivilege": true,
-    "description": "公告通知",
-    "updateTime": "2020-05-13 18:09:54",
-    "creationTime": "2020-05-13 18:09:54",
-    "weight": 2,
-    "ext1": null,
-    "ext2": null,
-    "ext3": null,
-    "ext4": null,
-    "ext5": null,
-    "routeCode": "stu_notice",
-    "nodeName": "公告通知",
-    "nodeCode": "stu_notice_0",
-    "parentNodeId": null,
-    "nodeId": "6559"
-  },
-  {
-    "id": 6560,
-    "code": "stu_modify_pwd_0",
-    "name": "修改密码",
-    "parentId": null,
-    "groupId": 20,
-    "groupCode": "STUDENT_CLIENT_MENU_0",
-    "hasPrivilege": true,
-    "description": "修改密码",
-    "updateTime": "2020-05-13 18:09:54",
-    "creationTime": "2020-05-13 18:09:54",
-    "weight": 1,
-    "ext1": null,
-    "ext2": null,
-    "ext3": null,
-    "ext4": null,
-    "ext5": null,
-    "routeCode": "stu_modify_pwd",
-    "nodeName": "修改密码",
-    "nodeCode": "stu_modify_pwd_0",
-    "parentNodeId": null,
-    "nodeId": "6560"
-  }
-]

BIN
src/components/MainLayout/qm-logo.png


+ 8 - 8
src/features/ChangePassword/ChangePassword.vue

@@ -3,7 +3,6 @@ import { FormInst, FormItemRule, FormRules, useMessage } from "naive-ui";
 import { changePwdApi } from "@/api/changePwd";
 const modelFormRef = $ref<FormInst | null>(null);
 const message = useMessage();
-let loading: boolean = $ref(false);
 
 type FormModel = {
   password: string;
@@ -51,10 +50,7 @@ const inputChange = async () => {
 const toSubmit = async () => {
   await modelFormRef?.validate();
 
-  if (loading) return;
-  loading = true;
-  const res = await changePwdApi(formModel.password, formModel.newPassword);
-  console.log(res.data);
+  await changePwdApi(formModel.password, formModel.newPassword);
   message.success("修改成功!");
 };
 </script>
@@ -71,28 +67,32 @@ const toSubmit = async () => {
       <n-form-item label="旧秘密" path="password">
         <n-input
           v-model:value="formModel.password"
+          type="password"
           placeholder="请输入旧秘密"
+          clearable
           @change="inputChange"
         />
       </n-form-item>
       <n-form-item label="新密码" path="newPassword">
         <n-input
           v-model:value="formModel.newPassword"
+          type="password"
           placeholder="请输入新密码(6到18位的数字或字母)"
+          clearable
           @change="inputChange"
         />
       </n-form-item>
       <n-form-item label="新密码" path="renewPassword">
         <n-input
           v-model:value="formModel.renewPassword"
+          type="password"
           placeholder="请再次输入新密码"
+          clearable
           @change="inputChange"
         />
       </n-form-item>
       <n-form-item>
-        <n-button type="primary" :disabled="loading" @click="toSubmit">
-          保存
-        </n-button>
+        <n-button type="primary" @click="toSubmit"> 保存 </n-button>
       </n-form-item>
     </n-form>
   </div>