Sfoglia il codice sorgente

pad端退出登录、样式修改

liurongli 2 settimane fa
parent
commit
a1bbba1aaa

BIN
src/assets/tabbar/personal_center.png


BIN
src/assets/tabbar/personal_center_cur.png


BIN
src/assets/tabbar/report.png


BIN
src/assets/tabbar/report_cur.png


BIN
src/assets/tabbar/set.png


BIN
src/assets/tabbar/target.png


BIN
src/assets/tabbar/target_cur.png


BIN
src/assets/tabbar/teach_homework.png


BIN
src/assets/tabbar/teach_homework_cur.png


+ 27 - 0
src/http/common/http.js

@@ -87,6 +87,7 @@ service1.interceptors.response.use(
         // Message({message: res.data.msg,type: 'warning'})
       }
       if (res.data.code === 401) {
+        notifyPadAppLogout();// 通知App壳端退出登录(仅APP环境生效)
         //未登录  跳转到登录页
         let url=process.env.VUE_APP_BASE+'/marking/#/login';//退出到考阅登录页
         window.location.href = url;
@@ -332,3 +333,29 @@ export function deleteRequest(url, params = {}, type, useService1 = false) {
   })
 
 }
+//通知App(pad)端退出登录:
+//H5环境:web端处于markPaper-pad H5的iframe中,通过postMessage通知父页面退出登录
+function notifyPadAppLogout() {
+  try {
+    if (window.plus && plus.webview) {
+      if (window.uni) {
+          PadLogoutSendMsg()
+        } else {
+          // 等待JS桥准备完成再发消息,防止路由守卫触发太早uni不存在
+          document.addEventListener('UniAppJSBridgeReady', PadLogoutSendMsg, {once:true})
+        }
+    } else {
+      // H5:通知父级iframe页面(markPaper-pad H5)退出登录
+      // const baseUrl = process.env.NODE_ENV === 'development' ? '*' : process.env.VUE_APP_BASE;
+      window.parent.postMessage({ type: 'logout' }, '*');
+    }
+  } catch (e) {
+    console.error('通知App端退出登录失败', e);
+  }
+}
+//通知App端退出登录
+function PadLogoutSendMsg() {
+    uni.postMessage({
+        data: {type: 'logout'}
+    })
+}

+ 16 - 8
src/router/index.js

@@ -172,13 +172,6 @@ let studentAnalysisReport = {
                     meta: {
                         title: "一生一案",
                     },
-                },
-                {
-                    path: "studentReport",
-                    component: () => import("@/views/analysisReport/studentPage/downloadPdf/studentReport"),
-                    meta: {
-                        title: "一生一案",
-                    },
                 }
             ],
         },
@@ -249,7 +242,22 @@ router.beforeEach((to, from, next) => {
     next();
 });
 // 路由后置守卫:添加统计脚本
-router.afterEach(() => {
+router.afterEach((to) => {
+    // pad端-------隐藏、显示侧边栏
+    if(window.__IS_PAD_APP__){
+        const hideMenuPaths = [
+            '/studentAnalysisReport/reportDetails/scrolReport',
+            '/studentAnalysisReport/reportDetails/studentReport',
+            '/studentAnalysisReport/reportDetails/studentCase',
+        ];
+        if(hideMenuPaths.includes(to.path)){
+            store.commit('user/SET_SHOW_HEADER', false);
+        }else{
+            store.commit('user/SET_SHOW_HEADER', true);
+        }
+    }else{
+        store.commit('user/SET_SHOW_HEADER', true);
+    }
     // 添加统计分析脚本
     addAnalyticsScript()
 });

+ 6 - 0
src/store/modules/user.js

@@ -43,6 +43,7 @@ const state = {
     }
   })(),
   permissions:localStorage.getItem('user_permissions') || [],//从本地获取权限信息
+  showHeader:localStorage.getItem('showHeader') || true,//pad端是否显示侧边栏 pc端永远显示
 }
 
 const mutations = {
@@ -97,6 +98,11 @@ const mutations = {
     state.schoolWebSiteId = schoolWebSiteId;
     localStorage.setItem('user_schoolWebSiteId', schoolWebSiteId);//存储到本地
   },
+  //设置pad端是否显示侧边栏
+  SET_SHOW_HEADER: (state, showHeader) => {
+    state.showHeader = showHeader;
+    localStorage.setItem('showHeader', showHeader);//存储到本地
+  },
 }
 let logoutInProgress = false;
 const actions = {

+ 1 - 0
src/styles/common.scss

@@ -1,5 +1,6 @@
 @use "./normalize.scss";
 @use "./report.scss"; //分析报告相关的公共样式
+@use './pad_common.scss';//pad通用样式
 
 ul,
 li {

+ 331 - 0
src/styles/pad_common.scss

@@ -0,0 +1,331 @@
+// 全局修改pad端样式
+.pad_container_layout {
+  .layout {
+    display: flex;
+    width: 100%;
+    padding-bottom: 0;
+  }
+  .header {
+    width: 66px !important;
+    height: 100% !important;
+    padding-top: 18px;
+    box-sizing: border-box;
+    z-index: 999 !important;
+    position: relative !important;
+    .headerBox {
+      height: 100% !important;
+      flex-direction: column;
+      padding: 0;
+      .logo {
+        min-width: auto;
+        margin-right: 0;
+        .top_title_blod,
+        .version_icon {
+          display: none;
+        }
+      }
+      .headerMenu {
+        margin-top: 5px;
+      }
+      .menuList {
+        width: 100%;
+        height: 100%;
+        overflow: auto;
+        .el-menu-wrap {
+          width: 100%;
+          height: auto;
+          li {
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            justify-content: center;
+            margin-top: 10px;
+            height: 60px;
+            width: 100%;
+            box-sizing: border-box;
+            flex-shrink: 0;
+            padding: 0;
+            line-height: normal;
+            &.is-active {
+              background-color: #e2eaff !important;
+              .menuName {
+                color: #2e64fa;
+              }
+            }
+            .menu_item_icon {
+              width: 20px;
+              height: 20px;
+            }
+
+            .menuName {
+              font-weight: 400;
+              font-size: 13px;
+              color: #ffffff;
+              margin-top: 10px;
+            }
+          }
+        }
+      }
+    }
+  }
+  .app_main {
+    padding-top: 0;
+    height: 100%;
+    flex: 1;
+    .analysis_main {
+      min-width: auto;
+      .main_content {
+        .mm_body {
+          .left {
+            width: 150px;
+            padding: 10px;
+          }
+          .right {
+            width: calc(100% - 160px);
+            .subject_score_chart {
+              .no_content_data {
+                background-size: 260px auto;
+              }
+            }
+            .subject_score_content {
+              .score_item {
+                height: 58px;
+                span {
+                  font-size: 12px;
+                  &.value {
+                    font-size: 14px;
+                    margin-top: 5px;
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    //分析报告任务列表
+    .page_report_main {
+      width: calc(100% - 20px);
+      min-width: auto;
+      min-height: calc(100vh - 20px);
+      margin-top: 10px;
+      margin-bottom: 10px;
+    }
+  }
+  .layout_main {
+    height: 100% !important;
+  }
+  .container_layout {
+    display: flex;
+    .layout_header {
+      width: 66px !important;
+      height: 100%;
+    }
+    .user_main {
+      flex-direction: column;
+      padding: 0 0 10px;
+      .user_main_left {
+        width: 100% !important;
+        height: 48px;
+        .side_bar {
+          width: 100% !important;
+          border-radius: 0;
+          padding-bottom: 0;
+          .nav_menu {
+            width: calc(100% - 20px);
+            border-radius: 0;
+            margin-top: 0;
+            .el-menu-item {
+              height: 48px;
+              width: auto;
+              margin-left: 24px;
+              padding: 0;
+              margin-bottom: 0 !important;
+              &.is-active {
+                background: transparent;
+                color: #2e64fa !important;
+                .menu_one_title {
+                  span {
+                    color: #2e64fa !important;
+                    font-weight: 600;
+                    font-size: 16px;
+                  }
+                }
+              }
+              .menu_one_title {
+                .iconfont {
+                  display: none;
+                }
+                span {
+                  font-size: 14px;
+                }
+              }
+            }
+          }
+        }
+      }
+      .user_main_right {
+        width: calc(100% - 20px) !important;
+        flex: 1;
+        margin: 10px 10px 0;
+        overflow: hidden;
+        .page_search {
+          .center_list {
+            height: calc(100vh - 150px);
+          }
+        }
+      }
+    }
+    .layout_know_main {
+      height: 100% !important;
+    }
+    .layout_main {
+      height: 100% !important;
+      .user_mains {
+        flex-direction: column;
+        padding: 0 0 10px;
+        box-sizing: border-box;
+        .user_main_lefts {
+          width: 100% !important;
+          height: 48px;
+          .side_bar {
+            width: auto !important;
+            border-radius: 0;
+            padding-bottom: 0;
+            left: 66px;
+            right: 0;
+            .target_nav_menu {
+              width: calc(100% - 20px);
+              border-radius: 0;
+              margin-top: 0;
+              .el-menu-item {
+                display: inline-flex;
+                padding-left: 24px !important;
+                height: 48px;
+                width: auto;
+                border-radius: 0;
+                border: 0;
+                margin-bottom: 0 !important;
+                &.is-active {
+                  background: transparent;
+                  .menu_one_title {
+                    .menu_one_title_text {
+                      span {
+                        font-size: 16px;
+                        font-weight: 600;
+                      }
+                    }
+                  }
+                }
+                .menu_one_title {
+                  .icon_box {
+                    display: none;
+                  }
+                  .menu_one_title_text {
+                    span {
+                      font-size: 14px;
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+        .user_main_rights {
+          width: calc(100% - 20px) !important;
+          flex: 1;
+          margin: 10px 10px 0;
+          height: calc(100% - 10px) !important;
+          .target_step {
+            .step_item {
+              width: auto;
+              min-width: auto;
+              flex: 1;
+              gap: 7px;
+              &.js-practice-answer-step {
+                padding: 0 7px;
+              }
+            }
+            .step_line {
+              width: auto;
+              flex: 1;
+              background-size: 90% 20px;
+            }
+          }
+          .practice_answer {
+            .el-container {
+              padding: 0;
+            }
+          }
+          .region_container {
+            gap: 5px;
+            .region_section {
+              padding: 6px 6px 4px;
+              .region_header {
+                .region_header_main {
+                  gap: 5px;
+                  .region_title {
+                    font-size: 22px;
+                  }
+                }
+                .region_desc {
+                  font-size: 12px;
+                }
+              }
+              .knowledge_row {
+                gap: 5px;
+                padding: 5px;
+                .row_left {
+                  .kp_name {
+                    margin-bottom: 4px;
+                    font-size: 12px;
+                  }
+                  .kp_meta {
+                    gap: 4px;
+                  }
+                }
+                .row_right {
+                  .add_btn {
+                    padding: 7px 2px;
+                    font-size: 12px;
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    .layout_footer {
+      display: none;
+      height: 0;
+    }
+  }
+  //个人中心
+  .el-container {
+    padding: 10px;
+    .container_main {
+      width: 100%;
+      min-width: auto;
+      border-radius: 10px;
+      margin-top: 0px;
+      height: 100%;
+      .page_user {
+        .user_module {
+          .user_info {
+            flex: 1;
+            width: auto;
+            .info_item {
+              margin-right: 0;
+              width: 30%;
+            }
+          }
+        }
+      }
+    }
+    .footer {
+      display: none;
+      height: 0 !important;
+    }
+  }
+}

+ 126 - 14
src/views/layout/components/Header.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="header" ref="headerMenu">
+  <div class="header" v-show="showHeader" ref="headerMenu">
     
     <el-dialog title="绑定邮箱" center width="450px" :visible.sync="bindEmailData.dialogShow">
       <bindEmail
@@ -114,22 +114,26 @@
               :class="{report:item.versions}"
               :key="index"
               >
+              <img :src="item.externalLink === activeMenuName ? item.iconCur : item.icon" class="menu_item_icon" v-if="padApp" />
               <span class="menuName">{{ item.menuName }}</span>
               <!-- <div class="versions" v-if="item.versions"><span>V</span><span>{{ item.versions }}</span></div> -->
             </el-menu-item>
           </el-menu>
         </div>
       </div>
-      <div class="user_info">
+      <div :class="['user_info', {'pad_user_info': padApp}]">
         <el-dropdown
           @command="UserCommand"
           placement="top-start"
          trigger="click"
         >
           <span class="user_name">
-            {{ studentName }}<i class="el-icon-arrow-down"></i>
+            <template v-if="!padApp">
+              {{ studentName }}<i class="el-icon-arrow-down"></i>
+            </template>
+            <img src="@/assets/tabbar/set.png" class="set_icon" v-else />
           </span>
-          <el-dropdown-menu slot="dropdown">
+          <el-dropdown-menu slot="dropdown" :class="{ 'custom_pad_set_dropdown': padApp }">
             <!-- <el-dropdown-item command="bindUserEmail">绑定邮箱</el-dropdown-item> -->
             <el-dropdown-item command="setPassWord">修改密码</el-dropdown-item>
             <el-dropdown-item command="logout">退出登录</el-dropdown-item>
@@ -143,7 +147,14 @@
 import { mapGetters } from "vuex";
 import bindEmail from "@/views/userInfo/components/userSetting/bindEmail.vue";
 import { encrypt } from "@/utils/jsencrypt";
-import { removeToken } from "@/utils/auth";
+import teachHomework from '@/assets/tabbar/teach_homework.png';
+import teachHomeworkCur from '@/assets/tabbar/teach_homework_cur.png';
+import report from '@/assets/tabbar/report.png';
+import reportCur from '@/assets/tabbar/report_cur.png';
+import target from '@/assets/tabbar/target.png';
+import targetCur from '@/assets/tabbar/target_cur.png';
+import personalCenter from '@/assets/tabbar/personal_center.png';
+import personalCenterCur from '@/assets/tabbar/personal_center_cur.png';
 export default {
   computed: {
     ...mapGetters(["userInfo"]),
@@ -158,7 +169,11 @@ export default {
 
     schoolLogo() {
       return this.$store.state.user.schoolLogo || "";
-    }
+    },
+    // pad端-------侧边栏是否显示
+    showHeader() {
+      return this.$store.state.user.showHeader;
+    },
   },
   components: {
     bindEmail,
@@ -192,12 +207,14 @@ export default {
       },
       rowsData: {},
       menuList: [],
-
+      // App(pad)环境标识:true 时显示pad端样式
+      padApp: !!window.__IS_PAD_APP__,
 
     };
   },
   created() {
-
+    //监听壳token就绪事件(覆盖Header先于setToken挂载、__IS_PAD_APP__尚未设置的时序)
+    window.addEventListener('padAppTokenReady', this.onPadTokenReady);
     this.activeMenu();
 
     //学生端默认菜单
@@ -205,29 +222,42 @@ export default {
       {
         menuName: "教辅作业",
         externalLink: "/teachingHomework",
+        icon: teachHomework,
+			  iconCur: teachHomeworkCur,
         feature: "teachingHomework", // 生产环境隐藏的未完成模块
       },
       {
         menuName: "分析报告",
+        icon: report,
+			  iconCur: reportCur,
         externalLink: "/jointStudentAnalysisReport/list",
       },
       {
         menuName: "靶向提升",
+        icon: target,
+			  iconCur: targetCur,
         externalLink: "/targetImprove",
       },
       
       {
         menuName: "个人中心",
+        icon: personalCenter,
+			  iconCur: personalCenterCur,
         externalLink: "/userInfo",
       },
     ];
 
     // 带 feature 标识的菜单(未完成模块),生产环境隐藏,测试/开发环境显示
     this.menuList = baseMenuList.filter(item => !item.feature || this.$feature.isShow());
-    
+  },
+  beforeDestroy() {
+    window.removeEventListener('padAppTokenReady', this.onPadTokenReady);
   },
   methods: {
-
+    //App(pad)端壳token就绪:更新pad环境标识,启用pad端样式
+    onPadTokenReady() {
+      this.padApp = true;
+    },
     updateShowEmailSuccess(show) {
       this.$refs.headerMenu.style.zIndex = 600;
       this.bindEmailData.dialogShow = show;
@@ -311,13 +341,42 @@ export default {
 
     // 退出登录
     Logout() {
+      // 通知App壳端退出登录(仅APP环境生效)
+      this.notifyPadAppLogout('logout');
       this.$store.dispatch("user/logout");
       localStorage.clear();
-      let url=process.env.VUE_APP_BASE+'/marking/#/login';//退出到考阅登录页
-      window.location.replace(url)
-      window.parent.location.href = `${process.env.VUE_APP_BASE}/marking/#/login`;//兼容父级iframe
+      if(!this.padApp){
+        let url=process.env.VUE_APP_BASE+'/marking/#/login';//退出到考阅登录页
+        window.location.replace(url)
+        window.parent.location.href = `${process.env.VUE_APP_BASE}/marking/#/login`;//兼容父级iframe
+      }
+    },
+    //通知App(pad)端退出登录:
+    //H5环境:web端处于markPaper-pad H5的iframe中,通过postMessage通知父页面退出登录
+    notifyPadAppLogout(type) {
+      try {
+        if (window.plus && plus.webview) {
+          if (window.uni) {
+              this.PadLogoutSendMsg(type)
+            } else {
+              // 等待JS桥准备完成再发消息,防止路由守卫触发太早uni不存在
+              document.addEventListener('UniAppJSBridgeReady', () => { this.PadLogoutSendMsg(type)}, {once:true})
+            }
+        } else {
+          // H5:通知父级iframe页面(markPaper-pad H5)退出登录
+          // const baseUrl = process.env.NODE_ENV === 'development' ? '*' : process.env.VUE_APP_BASE;
+          window.parent.postMessage({ type: type}, '*');
+        }
+      } catch (e) {
+        console.error('通知App端退出登录失败', e);
+      }
+    },
+    //通知App端退出登录
+    PadLogoutSendMsg(type) {
+        uni.postMessage({
+            data: {type: type}
+        })
     },
-
     //打开修改密码弹窗
     OpenUpdatePassWord() 
     {
@@ -514,6 +573,15 @@ export default {
   // background-color: red;
   // margin-right: -10px;
   line-height: 30px;
+  &.pad_user_info{
+    width: 100%;
+    height: 80px;
+    display: flex;
+    flex-shrink: 0;
+    justify-content: center;
+    align-items: center;
+    line-height: normal;
+  }
   .user_name
   {
     font-size: 15px;
@@ -525,6 +593,10 @@ export default {
       margin-left: 10px;
     }
   }
+  .set_icon {
+    width: 20px;
+    height: 20px;
+  }
 }
 .el-dropdown-menu {
   left: auto !important; /* 取消默认左对齐 */
@@ -565,3 +637,43 @@ button.el-button {
   }
 }
 </style>
+<style lang="scss">
+/* ============ App(pad)端:设置按钮触发的头部下拉弹框样式 ============
+   原理:el-dropdown-menu 渲染出的 <ul> 由 popper 挂载到 document.body
+   (vue-popper 的 appendToBody 默认开启),它不在 .el-dropdown 外层容器内,
+   所以 scoped 样式和「.custom_pad_set_dropdown 子孙选择器」都无法命中菜单。
+   必须写成全局样式,并用「.el-dropdown-menu.custom_pad_set_dropdown」组合选择器
+   只命中 pad 模式下加到菜单上的 class,避免影响其它页面的 el-dropdown。 */
+.el-dropdown-menu.custom_pad_set_dropdown {
+  top: auto !important; // 覆盖 popper 内联设置的 top
+  left: 76px !important; // 左侧栏宽66px,76px=贴着侧边栏右侧弹出
+  bottom: 8px !important; // 贴近屏幕底部,与设置按钮垂直位置对齐
+  width: 98px !important;
+  min-width: 98px !important;
+  padding: 4px 0 !important;
+  margin: 0 !important; // 去掉 popper 默认 5px 间隙,保证底部定位精确
+  border: 1px solid #EBEEF5 !important;
+  border-radius: 6px !important;
+  box-shadow: 2px 2px 8px 4px rgba(0,0,0,0.08) !important;
+  .popper__arrow{
+    display: none;
+  }
+  .el-dropdown-menu__item {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    height: 40px;
+    line-height: 40px;
+    font-size: 14px;
+    color: #666666;
+    padding: 0;
+    background-color: transparent;
+
+    &:hover,
+    &:focus {
+      background-color: #F5F7FA;
+      color: #666666;
+    }
+  }
+}
+</style>

+ 1 - 0
src/views/targetImprove/components/TargetSubject.vue

@@ -119,5 +119,6 @@ export default {
     padding-right: 10px;
     padding-top: 2px;
     margin-bottom: 10px;
+    box-sizing: border-box;
 }
 </style>

+ 6 - 1
src/views/targetImprove/practice/knowledgeGraph.vue

@@ -571,7 +571,12 @@ export default {
         // 获取容器距离视口顶部的距离
         const rect = this.$refs.knowledgeGraph.getBoundingClientRect();
         // 计算容器最大高度:窗口高度 - 容器距离顶部的距离 - 底部留白
-        const maxHeight = window.innerHeight - rect.top - 20;
+        let maxHeight = 0;
+        if(window.__IS_PAD_APP__){//ipad
+          maxHeight = window.innerHeight - rect.top - 10;
+        }else{
+          maxHeight = window.innerHeight - rect.top - 20;
+        }
         // 设置最小高度为400px
         this.containerHeight = Math.max(maxHeight, 400);
       }