|
|
@@ -0,0 +1,439 @@
|
|
|
+<template>
|
|
|
+ <div class="login_page" >
|
|
|
+ <div class="login_header">
|
|
|
+ <div class="header_left">
|
|
|
+ <img src="../../assets/login/logo.png" alt="">
|
|
|
+ <span style="margin-left: 10px;">客户管理系统</span>
|
|
|
+ </div>
|
|
|
+ <div class="header_right">
|
|
|
+ <div class="right_button" @click="GoWebsite">官方网站 </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="login_content" id="particles">
|
|
|
+ <div class="login_info">
|
|
|
+ <div class="login_info_title">
|
|
|
+ <p>HI~欢迎使用</p>
|
|
|
+ <p>客户管理系统平台</p>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="input_tips">请输入验证码</div>
|
|
|
+
|
|
|
+ <!-- <div class="login_info_message">校本选课系统登录</div> -->
|
|
|
+<!--
|
|
|
+ <div class="tab">
|
|
|
+ <span :class="!isStudentLogin ? 'selected': 'un_selected' " @click="HandleLoginChange(false)">教师</span>
|
|
|
+ <span :class="isStudentLogin ? 'selected': 'un_selected' " @click="HandleLoginChange(true)">学生</span>
|
|
|
+ </div> -->
|
|
|
+
|
|
|
+ <div class="login_info_input">
|
|
|
+ <el-form ref="userInfoForm" @submit.prevent="SubmitLogin">
|
|
|
+ <el-form-item :rules="phoneRules" prop="userName">
|
|
|
+ <el-input v-model="userName" placeholder="请输入手机号" @keyup.enter="SubmitLogin">
|
|
|
+ <template #prefix>
|
|
|
+ <i class="iconfont icon_zhanghao" />
|
|
|
+ </template>
|
|
|
+ <template #suffix>
|
|
|
+ <img @click.stop="ClearInput" :src="lineCloseIcon" alt="Clear Icon" style="width: 18px;height: 18px;cursor: pointer;">
|
|
|
+ </template>
|
|
|
+ </el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item prop="passWord">
|
|
|
+ <el-input v-model="passWord" :type="'text'" placeholder="请输入验证码" @keyup.enter="SubmitLogin">
|
|
|
+ <template #prefix>
|
|
|
+ <img :src="validateCodeIcon" alt="" style="width: 18px;height: 18px;">
|
|
|
+ </template>
|
|
|
+ <template #suffix>
|
|
|
+ <span style="z-index: 10 !important;" class="valid_code" >
|
|
|
+ 获取验证码
|
|
|
+ <!-- <i @click.down="showPass = !showPass" :class="['iconfont', {'icon_xianshimima':showPass},{'icon_buxianshimima':!showPass}]"></i> -->
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+ </el-input>
|
|
|
+ <!-- <el-input v-model="passWord" placeholder="请输入密码" :type="!showPass ? 'password' : 'text'">
|
|
|
+ <template #prefix>
|
|
|
+ <i class="iconfont icon_mima" />
|
|
|
+ </template>
|
|
|
+ </el-input> -->
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="login_info_item">
|
|
|
+ <div class="item_left">
|
|
|
+ <el-checkbox v-model="remeberPassWord">记住密码</el-checkbox>
|
|
|
+ </div>
|
|
|
+ <div class="item_right">忘记密码</div>
|
|
|
+ </div>
|
|
|
+ <div class="login_info_button">
|
|
|
+ <el-button style="width:100%;" @click="SubmitLogin()" :loading="loadingLogin">登 录</el-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+
|
|
|
+ <!-- <div class="login_other_type"> -->
|
|
|
+ <!-- <div class="other_login_line">
|
|
|
+ <span class="line"></span>
|
|
|
+ <span class="text">其他登录方式</span>
|
|
|
+ <span class="line"></span>
|
|
|
+ </div> -->
|
|
|
+ <!-- <div class="other_login_icon"> -->
|
|
|
+ <!-- <div class="icon_item">
|
|
|
+ <img src="../../assets/login/login_wechat.webp" alt=""></img>
|
|
|
+ <p>微信</p>
|
|
|
+ </div> -->
|
|
|
+ <!--
|
|
|
+ <div class="icon_item">
|
|
|
+ <img src="../../assets/login/login_feishu.webp" alt=""></img>
|
|
|
+ <p>钉钉</p>
|
|
|
+ </div>
|
|
|
+ <div class="icon_item">
|
|
|
+ <img src="../../assets/login/login_email.webp" alt=""></img>
|
|
|
+ <p>邮箱</p>
|
|
|
+ </div>
|
|
|
+ -->
|
|
|
+ <!-- </div> -->
|
|
|
+ <!-- </div> -->
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+<script setup>
|
|
|
+import { ref, onMounted, computed, watch } from 'vue'
|
|
|
+// import particles from 'particles.js'
|
|
|
+import { login,getUserInfo} from '@/api/login.ts'
|
|
|
+
|
|
|
+import { ElMessage } from 'element-plus' //
|
|
|
+import { useRouter } from 'vue-router'
|
|
|
+import { encrypt } from "@/utils/jsencrypt";
|
|
|
+import passwordIcon from '@/assets/icon/password.svg'
|
|
|
+import lineCloseIcon from '@/assets/icon/line_close_icon.webp'
|
|
|
+import validateCodeIcon from '@/assets/login/validate_code.png'
|
|
|
+
|
|
|
+const router = useRouter() // 获取路由实例
|
|
|
+// 响应式数据
|
|
|
+const userName = ref('')
|
|
|
+const passWord = ref('')
|
|
|
+const remeberPassWord = ref(false)
|
|
|
+const loadingLogin = ref(false)
|
|
|
+const showPass = ref(false)
|
|
|
+
|
|
|
+const isStudentLogin = ref(true)
|
|
|
+
|
|
|
+
|
|
|
+const userInfoForm = ref()
|
|
|
+
|
|
|
+// 粒子动画初始化
|
|
|
+const InitParticles = () => {
|
|
|
+ const particlesConfig = {
|
|
|
+ particles: {
|
|
|
+ number: {
|
|
|
+ value: 60,
|
|
|
+ density: {
|
|
|
+ enable: true,
|
|
|
+ value_area: 800
|
|
|
+ }
|
|
|
+ },
|
|
|
+ color: {
|
|
|
+ value: '#ffffff'
|
|
|
+ },
|
|
|
+ shape: {
|
|
|
+ type: ['circle'],
|
|
|
+ stroke: {
|
|
|
+ width: 0,
|
|
|
+ color: '#000000'
|
|
|
+ },
|
|
|
+ polygon: {
|
|
|
+ nb_sides: 5
|
|
|
+ },
|
|
|
+ image: {
|
|
|
+ src: 'img/github.svg',
|
|
|
+ width: 100,
|
|
|
+ height: 100
|
|
|
+ }
|
|
|
+ },
|
|
|
+ opacity: {
|
|
|
+ value: 0.5,
|
|
|
+ random: false,
|
|
|
+ anim: {
|
|
|
+ enable: false,
|
|
|
+ speed: 1,
|
|
|
+ opacity_min: 0.1,
|
|
|
+ sync: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ size: {
|
|
|
+ value: 3,
|
|
|
+ random: false,
|
|
|
+ anim: {
|
|
|
+ enable: true,
|
|
|
+ speed: 40,
|
|
|
+ size_min: 0.1,
|
|
|
+ sync: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ line_linked: {
|
|
|
+ enable: true,
|
|
|
+ distance: 150,
|
|
|
+ color: '#ffffff',
|
|
|
+ opacity: 0.4,
|
|
|
+ width: 1
|
|
|
+ },
|
|
|
+ move: {
|
|
|
+ enable: true,
|
|
|
+ speed: 6,
|
|
|
+ direction: 'none',
|
|
|
+ random: false,
|
|
|
+ straight: false,
|
|
|
+ out_mode: 'out',
|
|
|
+ bounce: false,
|
|
|
+ attract: {
|
|
|
+ enable: false,
|
|
|
+ rotateX: 600,
|
|
|
+ rotateY: 1200
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ interactivity: {
|
|
|
+ detect_on: 'canvas',
|
|
|
+ events: {
|
|
|
+ onhover: {
|
|
|
+ enable: true,
|
|
|
+ mode: 'grab'
|
|
|
+ },
|
|
|
+ onclick: {
|
|
|
+ enable: true,
|
|
|
+ mode: 'push'
|
|
|
+ },
|
|
|
+ resize: true
|
|
|
+ },
|
|
|
+ modes: {
|
|
|
+ grab: {
|
|
|
+ distance: 140,
|
|
|
+ line_linked: {
|
|
|
+ opacity: 1
|
|
|
+ }
|
|
|
+ },
|
|
|
+ bubble: {
|
|
|
+ distance: 400,
|
|
|
+ size: 40,
|
|
|
+ duration: 2,
|
|
|
+ opacity: 8,
|
|
|
+ speed: 3
|
|
|
+ },
|
|
|
+ repulse: {
|
|
|
+ distance: 200,
|
|
|
+ duration: 0.4
|
|
|
+ },
|
|
|
+ push: {
|
|
|
+ particles_nb: 4
|
|
|
+ },
|
|
|
+ remove: {
|
|
|
+ particles_nb: 2
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ retina_detect: true
|
|
|
+ }
|
|
|
+
|
|
|
+ particlesJS('particles', particlesConfig, () => {
|
|
|
+ console.log('粒子动画特效加载成功')
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const phoneValidatePass = (rule,value, callback) => {
|
|
|
+ if (value === '') {
|
|
|
+ callback(new Error('Please input the password again'))
|
|
|
+ } else {
|
|
|
+ callback()
|
|
|
+ }
|
|
|
+}
|
|
|
+const phoneRules = [
|
|
|
+ { required:true,trigger:'blur',message:'请输入手机号'},
|
|
|
+ // 动态提示
|
|
|
+ { validator: phoneValidatePass, trigger: 'blur' }
|
|
|
+]
|
|
|
+onMounted(() => {
|
|
|
+// InitParticles()
|
|
|
+ const storedUsername = localStorage.getItem('userName')
|
|
|
+ const storedPassword = localStorage.getItem('passWord')
|
|
|
+ const storedRememberMe = localStorage.getItem('rememberMe')
|
|
|
+
|
|
|
+ if (storedRememberMe === 'true') {
|
|
|
+ userName.value = storedUsername
|
|
|
+ passWord.value = storedPassword
|
|
|
+ remeberPassWord.value = true
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+const HandleLoginChange = (val)=>{
|
|
|
+ isStudentLogin.value = val
|
|
|
+}
|
|
|
+
|
|
|
+// 清空输入框
|
|
|
+const ClearInput = (event) => {
|
|
|
+ userName.value = ''
|
|
|
+}
|
|
|
+ const menuList = ref([])
|
|
|
+// 登录提交
|
|
|
+const SubmitLogin = async () => {
|
|
|
+ if(!userName.value || !passWord.value) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (remeberPassWord.value) {
|
|
|
+ localStorage.setItem('userName', userName.value)
|
|
|
+ localStorage.setItem('passWord', passWord.value)
|
|
|
+ localStorage.setItem('rememberMe', 'true')
|
|
|
+ } else {
|
|
|
+ localStorage.removeItem('userName')
|
|
|
+ localStorage.removeItem('passWord')
|
|
|
+ localStorage.setItem('rememberMe', 'false')
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ const params = {
|
|
|
+ username: userName.value.trim(),
|
|
|
+ password: encrypt(passWord.value.trim()),
|
|
|
+ deviceType:'PC',
|
|
|
+ }
|
|
|
+ loadingLogin.value = true
|
|
|
+ let res = undefined
|
|
|
+ try{
|
|
|
+ res = await login(params)
|
|
|
+ loadingLogin.value = false
|
|
|
+ if (res.code === 200) {
|
|
|
+ console.log("登录成功返回",res)
|
|
|
+ localStorage.setItem('token', res.data.tokenValue)
|
|
|
+ menuList.value = res.data.pcMenuVOS
|
|
|
+ localStorage.setItem('menuList', JSON.stringify(res.data.pcMenuVOS))
|
|
|
+ localStorage.setItem('permissions', JSON.stringify(res.data.permissions))
|
|
|
+
|
|
|
+ // 登录成功后调用获取用户信息接口
|
|
|
+ let userInfoRes = undefined
|
|
|
+ userInfoRes = await getUserInfo(res.data.token)
|
|
|
+ console.log("获取用户信息返回",userInfoRes)
|
|
|
+ if (userInfoRes?.code === 200) {
|
|
|
+ // 存储用户信息到 localStorage 或 Pinia
|
|
|
+ localStorage.setItem('userInfo', JSON.stringify(userInfoRes.data))
|
|
|
+ ElMessage.success('登录成功');
|
|
|
+
|
|
|
+ //根据不同的角色跳转不同的页面
|
|
|
+ // 管理员跳转
|
|
|
+ if(userInfoRes.data?.roleCodes?.includes('SCHOOL_MANAGER')){
|
|
|
+ router.push('/main')
|
|
|
+ }else{
|
|
|
+ router.push('/main/personalCenter')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }catch(err){
|
|
|
+ loadingLogin.value = false
|
|
|
+ console.error(err)
|
|
|
+ }
|
|
|
+ */
|
|
|
+
|
|
|
+ router.push('/main')
|
|
|
+}
|
|
|
+
|
|
|
+// 去往官网
|
|
|
+const GoWebsite = () => {
|
|
|
+ window.open('https://www.k12100.com/website')
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+@use "../../styles/login.scss" as *;
|
|
|
+
|
|
|
+.tab {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ margin:0 0 10px;
|
|
|
+ gap: 20px;
|
|
|
+ font-weight: bold;
|
|
|
+ line-height: 48px;
|
|
|
+ span{
|
|
|
+ padding:0 0 4px;
|
|
|
+ &:hover{
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .selected{
|
|
|
+ position: relative;
|
|
|
+ color: #2e64fa;
|
|
|
+ &::after{
|
|
|
+ position: absolute;
|
|
|
+ content: "";
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ top: 70%;
|
|
|
+ height: 2px;
|
|
|
+ background-color: #2e64fa;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.valid_code{
|
|
|
+ font-size: 12px;
|
|
|
+ color: #2E64FA;
|
|
|
+}
|
|
|
+
|
|
|
+.login_info{
|
|
|
+ .login_info_title{
|
|
|
+ margin-bottom: 32px !important;
|
|
|
+ }
|
|
|
+ .input_tips{
|
|
|
+ font-weight: 600;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #333;
|
|
|
+ margin-bottom: 26px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.login_info_input{
|
|
|
+ // border:solid red 1px;
|
|
|
+ .iconfont{
|
|
|
+ color:#c0c4cc;
|
|
|
+ }
|
|
|
+ .el-form{
|
|
|
+ .el-form-item{
|
|
|
+ // border:solid red 1px !important;
|
|
|
+ :deep(.el-form-item__content){
|
|
|
+ .el-input{
|
|
|
+ .el-input__wrapper{
|
|
|
+ border: none;
|
|
|
+ box-shadow: none;
|
|
|
+ padding: 0;
|
|
|
+ &::hover{
|
|
|
+ border:none;
|
|
|
+ box-shadow: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-input__prefix{
|
|
|
+ position: absolute;
|
|
|
+ left: 17px;
|
|
|
+ }
|
|
|
+ .el-input__suffix{
|
|
|
+ position: absolute;
|
|
|
+ right: 17px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-input__inner{
|
|
|
+ text-indent: 43px;
|
|
|
+ border:solid #dcdfe6 1px;
|
|
|
+ height: 100%;
|
|
|
+ border-radius: 4px;
|
|
|
+ &:hover{
|
|
|
+ border-color: #c0c4cc;
|
|
|
+ }
|
|
|
+ &:focus{
|
|
|
+ border-color: #2e64fa;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+</style>
|