Parcourir la source

邮箱验证码 超时退出

dusenyao il y a 2 ans
Parent
commit
c7e1d2fab9

+ 33 - 5
src/App.vue

@@ -11,6 +11,9 @@
 </template>
 
 <script>
+import { getConfig, removeToken } from '@/utils/auth';
+import Cookies from 'js-cookie';
+
 import ProgressBar from '@/common/progress_bar/index.vue';
 
 export default {
@@ -27,15 +30,24 @@ export default {
   data() {
     return {
       dir: 'ltr',
-      userAgentTipShow: false
+      userAgentTipShow: false,
+      timeOut: null
     };
   },
   created() {
-    // const lang_type = this.$store.state.user.language_type;
-    // if (lang_type === 'AR') {
-    //   this.dir = 'rtl';
-    // }
     this.handleUserAgentRoot();
+    ['click', 'mousewheel', 'mousemove'].forEach((item) => {
+      window.addEventListener(item, () => {
+        sessionStorage.setItem('lastClickTime', new Date().getTime());
+      });
+    });
+  },
+  mounted() {
+    sessionStorage.setItem('lastClickTime', new Date().getTime());
+    this.isTimeOut();
+  },
+  beforeDestroy() {
+    clearInterval(this.timeOut);
   },
   methods: {
     handleUserAgentRoot() {
@@ -46,6 +58,22 @@ export default {
     handleClickUserAgent() {
       sessionStorage.setItem('useragent_root_close', true);
       this.userAgentTipShow = false;
+    },
+    isTimeOut() {
+      clearInterval(this.timeOut);
+      this.timeOut = setInterval(() => {
+        let nowTime = new Date().getTime();
+        let { token } = getConfig();
+        let { user_connection_timeout_duration, sys_home_url } = token;
+        if (nowTime - Number(sessionStorage.getItem('lastClickTime')) > 1000 * user_connection_timeout_duration) {
+          clearInterval(this.timeOut);
+          sessionStorage.removeItem('SysList');
+          removeToken();
+          Cookies.remove('JSESSIONID');
+          sessionStorage.removeItem('useragent_root_close');
+          window.location.href = sys_home_url;
+        }
+      }, 1000);
     }
   }
 };

+ 13 - 0
src/api/user.js

@@ -115,3 +115,16 @@ export function GetMyGoodsBuyInfo(data) {
     data
   });
 }
+
+/**
+ * 发送验证码
+ * @param {Object} data
+ */
+export function SendVerificationCode(data) {
+  return request({
+    method: 'post',
+    url: process.env.VUE_APP_FileServer,
+    params: getRequestParams('user_manager-SendVerificationCode'),
+    data
+  });
+}

+ 62 - 68
src/components/select/SelectTeacher.vue

@@ -17,7 +17,7 @@
     </el-form>
 
     <!--表格-->
-    <el-table ref="teacherTable" :data="teacherList" height="35vh" @selection-change="handleSelectionChange">
+    <el-table ref="teacherTable" :data="list" height="35vh" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" />
       <el-table-column prop="user_name" :label="$t('Key191')" width="120" />
       <el-table-column prop="user_real_name" :label="$t('Key27')" width="120" />
@@ -31,10 +31,10 @@
       layout="prev, pager, next, total, sizes, jumper"
       :total="total_count"
       :current-page="cur_page"
-      @prev-click="changePage"
-      @next-click="changePage"
-      @current-change="changePage"
-      @size-change="changePageSize"
+      @prev-click="changePage($event, getTeacherUserList)"
+      @next-click="changePage($event, getTeacherUserList)"
+      @current-change="changePage($event, getTeacherUserList)"
+      @size-change="changePageSize($event, getTeacherUserList)"
     />
 
     <div slot="footer">
@@ -52,71 +52,65 @@
 import { PageQueryOrgTeacherUserList } from '@/api/list';
 
 export default {
-  name: 'SelectTeacher',
-  props: {
-    dialogVisible: {
-      default: false,
-      type: Boolean
-    },
-    orgId: {
-      default: '',
-      type: String
-    }
-  },
-  data() {
-    return {
-      cur_page: 1,
-      total_count: 0,
-      page_capacity: 10,
-      teacherList: [],
-      orgList: [],
-      searchForm: {
-        user_name: '',
-        user_real_name: ''
-      }
-    };
-  },
-  created() {
-    this.getTeacherUserList();
+  name: 'SelectTeacher'
+};
+</script>
+
+<script setup>
+import { ref } from 'vue';
+import { useList } from '@/utils/list';
+
+const props = defineProps({
+  dialogVisible: {
+    default: false,
+    type: Boolean
   },
-  methods: {
-    getTeacherUserList() {
-      const data = {
-        org_id: this.orgId,
-        user_name: this.searchForm.user_name,
-        user_real_name: this.searchForm.user_real_name,
-        page_capacity: this.page_capacity,
-        cur_page: this.cur_page,
-        is_valid: true,
-        is_audited: true
-      };
-
-      PageQueryOrgTeacherUserList(data).then(({ cur_page, total_count, org_teacher_user_list }) => {
-        this.cur_page = cur_page;
-        this.total_count = total_count;
-        this.teacherList = org_teacher_user_list;
-      });
-    },
-    dialogClose() {
-      this.$emit('dialogClose');
-      this.$refs.teacherTable.clearSelection();
-    },
-    handleSelectionChange(arr) {
-      this.orgList = arr.map(({ user_id }) => user_id);
-    },
-    changePage(newPage) {
-      this.cur_page = newPage;
-      this.getTeacherUserList();
-    },
-    changePageSize(pageSize) {
-      this.page_capacity = pageSize;
-      this.getTeacherUserList();
-    },
-    confirmTeacher() {
-      this.$emit('selectTeaher', this.orgList);
-    }
+  orgId: {
+    default: '',
+    type: String
   }
-};
+});
+
+const emits = defineEmits(['dialogClose', 'selectTeaher']);
+
+let searchForm = ref({
+  user_name: '',
+  user_real_name: ''
+});
+
+let { changePage, changePageSize, cur_page, list, page_capacity, total_count } = useList();
+
+function getTeacherUserList() {
+  PageQueryOrgTeacherUserList({
+    org_id: props.orgId,
+    user_name: searchForm.value.user_name,
+    user_real_name: searchForm.value.user_real_name,
+    page_capacity: page_capacity.value,
+    cur_page: cur_page.value,
+    is_valid: true,
+    is_audited: true
+  }).then(({ cur_page: cur, total_count: total, org_teacher_user_list }) => {
+    cur_page.value = cur;
+    total_count.value = total;
+    list.value = org_teacher_user_list;
+  });
+}
+getTeacherUserList();
+
+let teacherTable = ref();
+function dialogClose() {
+  emits('dialogClose');
+  teacherTable.value.clearSelection();
+}
+
+let selectTidList = ref([]); // 选中教师id列表
+function handleSelectionChange(arr) {
+  selectTidList.value = arr.map(({ user_id }) => user_id);
+}
+
+function confirmTeacher() {
+  emits('selectTeaher', selectTidList.value);
+}
 </script>
 
 <style lang="scss">

+ 61 - 63
src/components/select/SelectTemplate.vue

@@ -23,7 +23,7 @@
 
     <el-table
       ref="templateTable"
-      :data="courseList"
+      :data="list"
       height="40vh"
       highlight-current-row
       @current-change="handleCurrentChange"
@@ -51,10 +51,10 @@
       layout="prev, pager, next, total, sizes, jumper"
       :total="total_count"
       :current-page="cur_page"
-      @prev-click="changePage"
-      @next-click="changePage"
-      @current-change="changePage"
-      @size-change="changePageSize"
+      @prev-click="changePage($event, queryCourseList)"
+      @next-click="changePage($event, queryCourseList)"
+      @current-change="changePage($event, queryCourseList)"
+      @size-change="changePageSize($event, queryCourseList)"
     />
 
     <div slot="footer">
@@ -69,67 +69,65 @@
 </template>
 
 <script>
+export default {
+  name: 'SelectTemplate'
+};
+</script>
+
+<script setup>
+import { ref, inject } from 'vue';
+import { useList } from '@/utils/list';
 import { PageQueryCourseList } from '@/api/table';
+import { Message } from 'element-ui';
 
-export default {
-  props: {
-    dialogVisible: {
-      default: false,
-      type: Boolean
-    }
-  },
-  data() {
-    return {
-      cur_page: 1,
-      total_count: 0,
-      page_capacity: 10,
-      searchForm: {
-        name: ''
-      },
-      courseList: [],
-      currentRow: null
-    };
-  },
-  created() {
-    this.queryCourseList();
-  },
-  methods: {
-    queryCourseList() {
-      const queryCriteria = {
-        is_template: true,
-        name: this.searchForm.name,
-        page_capacity: this.page_capacity,
-        cur_page: this.cur_page,
-        release_status: 1
-      };
-      PageQueryCourseList(queryCriteria).then(({ course_list, total_count }) => {
-        this.courseList = course_list;
-        this.total_count = total_count;
-      });
-    },
-    changePage(newPage) {
-      this.cur_page = newPage;
-      this.queryCourseList();
-    },
-    changePageSize(pageSize) {
-      this.page_capacity = pageSize;
-      this.queryCourseList();
-    },
-    handleCurrentChange(val) {
-      this.currentRow = val;
-    },
-    dialogClose() {
-      this.$emit('dialogClose');
-      this.$refs.templateTable.clearSelection();
-    },
-    confirmTemplate() {
-      if (!this.currentRow) {
-        return this.$message.warning(this.$i18n.t('Key340'));
-      }
-      this.$emit('confirmTemplate', this.currentRow.id);
-    }
+defineProps({
+  dialogVisible: {
+    default: false,
+    type: Boolean
   }
-};
+});
+
+const emits = defineEmits(['dialogClose', 'confirmTemplate']);
+
+let searchForm = ref({
+  name: ''
+});
+
+let { cur_page, list, page_capacity, total_count, changePage, changePageSize } = useList();
+
+function queryCourseList() {
+  const queryCriteria = {
+    is_template: true,
+    name: searchForm.value.name,
+    page_capacity: page_capacity.value,
+    cur_page: cur_page.value,
+    release_status: 1
+  };
+  PageQueryCourseList(queryCriteria).then(({ course_list, total_count: total }) => {
+    list.value = course_list;
+    total_count.value = total;
+  });
+}
+queryCourseList();
+
+let templateTable = ref();
+function dialogClose() {
+  emits('dialogClose');
+  templateTable.value.clearSelection();
+}
+
+let currentRow = ref(null);
+function handleCurrentChange(val) {
+  currentRow.value = val;
+}
+
+const $t = inject('$t');
+function confirmTemplate() {
+  if (!currentRow.value) {
+    return Message.warning($t('Key340'));
+  }
+  emits('confirmTemplate', currentRow.value.id);
+}
 </script>
 
 <style lang="scss">

+ 2 - 1
src/utils/auth.js

@@ -1,7 +1,6 @@
 import Cookies from 'js-cookie';
 
 const TokenKey = 'GCLS_Token';
-const ConfigKey = 'GCLS_Config';
 
 export function getSessionID() {
   const token = Cookies.get(TokenKey);
@@ -28,6 +27,8 @@ export function removeToken() {
 }
 
 // 系统信息
+const ConfigKey = 'GCLS_Config';
+
 export function getConfig() {
   const token = Cookies.get(ConfigKey);
   if (token) {

+ 86 - 4
src/views/login/index.vue

@@ -43,6 +43,17 @@
         />
       </el-form-item>
 
+      <el-form-item class="dynamic_verification_code" prop="dynamic_verification_code">
+        <el-input v-model="loginForm.dynamic_verification_code" placeholder="邮箱验证码" />
+        <div
+          class="verificationCode-btn"
+          :class="VerificationCodeShow ? 'waitTime' : 'getVerification'"
+          @click="getVerificationCode"
+        >
+          {{ VerificationCodeShow ? time + 's' : '获取' }}
+        </div>
+      </el-form-item>
+
       <el-row>
         <el-col :span="12">
           <el-button
@@ -72,6 +83,7 @@
 
 <script>
 import { GetVerificationCodeImage } from '@/api/app';
+import { SendVerificationCode } from '@/api/user';
 import { getConfigInformation } from '@/utils/index';
 import md5 from 'md5';
 
@@ -102,7 +114,7 @@ export default {
         verification_code_image_text: '',
         dynamic_verification_type: 'EMAIL',
         phone_or_email: '',
-        dynamic_verification_code: '1234567a'
+        dynamic_verification_code: ''
       },
       loginRules: {
         user_name: [{ trigger: 'blur', validator: validateUsername }],
@@ -111,7 +123,9 @@ export default {
       },
       loading: false,
       redirect: null,
-      image_content_base64: ''
+      image_content_base64: '',
+      VerificationCodeShow: false,
+      time: 60
     };
   },
   watch: {
@@ -137,11 +151,41 @@ export default {
       });
     },
 
+    getVerificationCode() {
+      if (this.time !== 60) return;
+
+      if (!this.loginForm.user_name) {
+        this.$message.warning('请先输入邮箱或手机号码');
+        return;
+      }
+      this.VerificationCodeShow = true;
+      let timer = null;
+      timer = setInterval(() => {
+        this.time -= 1;
+        if (this.time === 0) {
+          this.VerificationCodeShow = false;
+          clearInterval(timer);
+          timer = null;
+          this.time = 60;
+        }
+      }, 1000);
+      SendVerificationCode({
+        verification_type: 'EMAIL',
+        phone_or_email: this.loginForm.user_name
+      }).catch(() => {
+        this.VerificationCodeShow = false;
+        clearInterval(timer);
+        timer = null;
+        this.time = 60;
+      });
+    },
+
     handleLogin(user_type) {
       this.$refs.loginForm.validate((valid) => {
         if (!valid) return false;
 
         this.loginForm.user_type = user_type;
+        this.loginForm.phone_or_email = this.loginForm.user_name;
         this.loading = true;
         const loginForm = { ...this.loginForm };
         loginForm.password = md5(loginForm.password).toUpperCase();
@@ -189,12 +233,19 @@ export default {
     overflow: hidden;
 
     .verification-code {
+      .el-form-item__content {
+        display: flex;
+        column-gap: 5px;
+        align-items: center;
+      }
+
       .el-input {
-        width: 120px;
+        flex: 1;
       }
 
       .el-image {
-        margin-left: 24px;
+        width: 90px;
+        height: 40px;
         vertical-align: bottom;
         cursor: pointer;
 
@@ -203,6 +254,37 @@ export default {
         }
       }
     }
+
+    .dynamic_verification_code {
+      .el-form-item__content {
+        display: flex;
+        column-gap: 5px;
+        align-items: center;
+      }
+
+      .el-input {
+        flex: 1;
+      }
+
+      .verificationCode-btn {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        width: 90px;
+        height: 34px;
+        font-size: 14px;
+        font-weight: 700;
+        color: #fff;
+        cursor: pointer;
+        background: #f90;
+        border-radius: 4px;
+
+        &.waitTime {
+          color: #6c6c6c;
+          background: #f0f0f0;
+        }
+      }
+    }
   }
 
   .login-button {

+ 7 - 0
src/views/new_task_view/components/student/index.vue

@@ -0,0 +1,7 @@
+<template>
+  <div></div>
+</template>
+
+<script setup></script>
+
+<style lang="scss" scoped></style>

+ 0 - 0
src/components/StepBar.vue → src/views/teacher/create_course/StepBar.vue


+ 23 - 22
src/views/teacher/create_course/index.vue

@@ -23,36 +23,37 @@
     </div>
 
     <!-- 选择模板 -->
-    <select-template :dialog-visible="dialogVisible" @dialogClose="dialogClose" @confirmTemplate="confirmTemplate" />
+    <SelectTemplate :dialog-visible="dialogVisible" @dialogClose="dialogClose" @confirmTemplate="confirmTemplate" />
   </div>
 </template>
 
 <script>
-import SelectTemplate from '@/components/select/SelectTemplate.vue';
-
 export default {
-  name: 'CreateCourse',
-  components: { SelectTemplate },
-  data() {
-    return {
-      dialogVisible: false
-    };
-  },
-  methods: {
-    selectTemplate() {
-      this.dialogVisible = true;
-    },
-    dialogClose() {
-      this.dialogVisible = false;
-    },
-    confirmTemplate(id) {
-      this.dialogVisible = false;
-      this.$router.push(`/create_course_step_table/course_info?is_use_template=true&template_id=${id}`);
-    }
-  }
+  name: 'CreateCourse'
 };
 </script>
 
+<script setup>
+import { ref } from 'vue';
+import { useRouter } from 'vue-router/composables';
+
+import SelectTemplate from '@/components/select/SelectTemplate.vue';
+
+let dialogVisible = ref(false);
+function selectTemplate() {
+  dialogVisible.value = true;
+}
+function dialogClose() {
+  dialogVisible.value = false;
+}
+
+const router = useRouter();
+function confirmTemplate(id) {
+  dialogVisible.value = false;
+  router.push(`/create_course_step_table/course_info?is_use_template=true&template_id=${id}`);
+}
+</script>
+
 <style lang="scss" scoped>
 @import '~@/styles/mixin';
 

+ 1 - 1
src/views/teacher/create_course/step_one/CourseInfo.vue

@@ -126,7 +126,7 @@ import { twoDecimal } from '@/utils/validate';
 import { getMyOrgList } from '@/api/list';
 import { GetUserListByIDList } from '@/api/user';
 
-import StepBar from '@/components/StepBar.vue';
+import StepBar from '@/views/teacher/create_course/StepBar.vue';
 import SelectTeacher from '@/components/select/SelectTeacher.vue';
 
 export default {

+ 1 - 1
src/views/teacher/create_course/step_three_old/CreateTask.vue

@@ -322,7 +322,7 @@
 </template>
 
 <script>
-import StepBar from '@/components/StepBar.vue';
+import StepBar from '@/views/teacher/create_course/StepBar.vue';
 import AddItem from './AddItem.vue';
 import { fileUpload } from '@/api/app';
 import {

+ 1 - 1
src/views/teacher/create_course/step_two/SelectBook.vue

@@ -84,7 +84,7 @@ import { useList } from '@/utils/list';
 import { Message } from 'element-ui';
 
 import store from '@/store';
-import StepBar from '@/components/StepBar.vue';
+import StepBar from '@/views/teacher/create_course/StepBar.vue';
 
 const route = useRoute();
 const router = useRouter();