Admin
2022-09-20 23f1bf22c42a904c05cee63e10c9fd8b60dfe8f5
src/views/loginPage/component/accountLogin.vue
@@ -1,47 +1,75 @@
<template>
   <el-form size="large" class="login-content-form">
      <el-form-item class="login-animation1">
         <el-input type="text" :placeholder="$t('message.account.accountPlaceholder1')" v-model="ruleForm.username" clearable autocomplete="off" size="large">
            <template #prefix>
               <el-icon class="el-input__icon" style="margin-right: 20px"><img src="../../../assets/loginPage/login_icon_user.png" style="width: 24px;height: 24px"></el-icon>
            </template>
         </el-input>
      </el-form-item>
      <el-form-item class="login-animation2">
         <el-input
            :type="isShowPassword ? 'text' : 'password'"
            :placeholder="$t('message.account.accountPlaceholder2')"
            v-model="ruleForm.password"
            autocomplete="off"
            size="large"
         >
            <template #prefix>
               <el-icon class="el-input__icon" style="margin-right: 20px"><img src="../../../assets/loginPage/login_icon_password.png" style="width: 24px;height: 24px"></el-icon>
            </template>
            <template #suffix>
               <i
                  class="iconfont el-input__icon login-content-password"
                  :class="isShowPassword ? 'icon-yincangmima' : 'icon-xianshimima'"
                  @click="isShowPassword = !isShowPassword"
               >
               </i>
            </template>
         </el-input>
      </el-form-item>
      <el-form-item class="login-animation4 codeDeal">
         <el-checkbox v-model="saveCode" label="记住密码" size="large" />
         <span class="forgetCode">忘记密码?</span>
      </el-form-item>
      <el-form-item class="login-animation4">
         <el-button type="primary" class="login-content-submit" round @click="onSignIn" :loading="loading.signIn">
            <span>登录系统</span>
         </el-button>
      </el-form-item>
   </el-form>
    <el-form size="large" class="login-content-form">
        <el-form-item class="login-animation1">
            <el-input type="text" :placeholder="$t('message.account.accountPlaceholder1')" v-model="ruleForm.username" clearable autocomplete="off" size="large">
                <template #prefix>
                    <el-icon class="el-input__icon" style="margin-right: 20px"><img src="../../../assets/loginPage/login_icon_user.png" style="width: 24px; height: 24px" /></el-icon>
                </template>
            </el-input>
        </el-form-item>
        <el-form-item class="login-animation2">
            <el-input :type="isShowPassword ? 'text' : 'password'" :placeholder="$t('message.account.accountPlaceholder2')" v-model="ruleForm.password" autocomplete="off" size="large" @keyup.enter.native="onSignIn">
                <template #prefix>
                    <el-icon class="el-input__icon" style="margin-right: 20px"><img src="../../../assets/loginPage/login_icon_password.png" style="width: 24px; height: 24px" /></el-icon>
                </template>
                <template #suffix>
                    <i class="iconfont el-input__icon login-content-password" :class="isShowPassword ? 'icon-yincangmima' : 'icon-xianshimima'" @click="isShowPassword = !isShowPassword"> </i>
                </template>
            </el-input>
        </el-form-item>
        <el-form-item class="login-animation4 codeDeal">
            <el-checkbox v-model="saveCode" label="记住密码" size="large" />
            <span class="forgetCode" @click="identify">忘记密码?</span>
        </el-form-item>
        <el-form-item class="login-animation4">
            <el-button type="primary" class="login-content-submit" round @click="onSignIn" :loading="loading.signIn">
                <span>登录系统</span>
            </el-button>
        </el-form-item>
    </el-form>
    <el-dialog v-model="identifyDialog" title="重置密码须进行身份校验(仅供测试)" width="30%" center @close="clearIdentity">
        <el-form :model="identity" label-width="80px" ref="identifyRef" :rules="identityRules">
            <el-form-item label="姓名" prop="userName">
                <el-input v-model="identity.userName"/>
            </el-form-item>
            <el-form-item label="身份证号" prop="ID">
                <el-input v-model="identity.ID"/>
            </el-form-item>
            <el-form-item label="手机号" prop="phone">
                <el-input v-model="identity.phone"/>
            </el-form-item>
        </el-form>
        <template #footer>
              <span class="dialog-footer">
                <el-button type="warning" @click="identifyDialog = false" size="default">取消</el-button>
                <el-button type="primary" @click="confirmIdentity(identifyRef)" size="default">确认</el-button>
              </span>
        </template>
    </el-dialog>
    <el-dialog v-model="changeDialog" title="修改密码" width="30%" center @close="clearCode">
        <el-form :model="codeForm" label-width="80px" ref="codeRef" :rules="codeRules">
            <el-form-item label="密码" prop="pass">
                <el-input v-model="codeForm.pass" type="password" autocomplete="off" />
            </el-form-item>
            <el-form-item label="确认密码" prop="checkPass">
                <el-input
                        v-model="codeForm.checkPass"
                        type="password"
                        autocomplete="off"
                />
            </el-form-item>
        </el-form>
        <template #footer>
              <span class="dialog-footer">
                <el-button type="warning" @click="changeDialog = false" size="default">取消</el-button>
                <el-button type="primary" @click="confirmChange(codeRef)" size="default">确认修改</el-button>
              </span>
        </template>
    </el-dialog>
</template>
<script lang="ts">
import { toRefs, reactive, defineComponent, computed } from 'vue';
import {toRefs, reactive, defineComponent, computed, ref, onMounted} from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { ElMessage } from 'element-plus';
import { useI18n } from 'vue-i18n';
@@ -54,158 +82,307 @@
import { formatAxis } from '/@/utils/formatTime';
import { NextLoading } from '/@/utils/loading';
import { useLoginApi } from '/@/api/login';
import {useUserInfo} from "/@/stores/userInfo";
import { useUserInfo } from '/@/stores/userInfo';
import type { FormInstance, FormRules } from 'element-plus'
import {workApplyApi} from "/@/api/specialWorkSystem/workApply";
import {verifyPhone,verifyIdCard} from "/@/utils/toolsValidate"
import { Base64 } from 'js-base64'
export default defineComponent({
   name: 'accountLogin',
   setup() {
      const { t } = useI18n();
      const userInfo = useUserInfo()
      const { userInfos } = storeToRefs(userInfo);
      const storesThemeConfig = useThemeConfig();
      const { themeConfig } = storeToRefs(storesThemeConfig);
      const route = useRoute();
      const router = useRouter();
      const state = reactive({
         isShowPassword: false,
         ruleForm: {
            username: 'admin',
            password: '123456',
         },
         loading: {
            signIn: false,
         },
      });
      // 时间获取
      const currentTime = computed(() => {
         return formatAxis(new Date());
      });
      // 登录
      const onSignIn = async () => {
         state.loading.signIn = true;
         // 存储 token 到浏览器缓存
         let res = await useLoginApi().signIn(state.ruleForm)
         if(res.data.code === '200'){
            Session.set('ifMenu',false)
            Session.set('projectId','')
            Session.set('token', res.data.data.accessToken);
            Session.set('sign',res.data.data.id)
            await initFrontEndControlRoutes();
            signInSuccess();
         }else{
            state.loading.signIn = false
            ElMessage({
               type:'warning',
               message:res.data.msg
            })
         }
         // Session.set('token', Math.random().toString(36).substr(0));
         // // 模拟数据,对接接口时,记得删除多余代码及对应依赖的引入。用于 `/src/stores/userInfo.ts` 中不同用户登录判断(模拟数据)
         // Cookies.set('userName', state.ruleForm.username);
         // if (!themeConfig.value.isRequestRoutes) {
         //    // 前端控制路由,2、请注意执行顺序
         //    await initFrontEndControlRoutes();
         //    signInSuccess();
         // } else {
         //    // 模拟后端控制路由,isRequestRoutes 为 true,则开启后端控制路由
         //    // 添加完动态路由,再进行 router 跳转,否则可能报错 No match found for location with path "/"
         //    await initBackEndControlRoutes();
         //    // 执行完 initBackEndControlRoutes,再执行 signInSuccess
         //    signInSuccess();
         // }
      };
      // 登录成功后的跳转
      const signInSuccess = async () => {
         // 初始化登录成功时间问候语
         let currentTimeInfo = currentTime.value;
         // 登录成功,跳到转首页
         // 如果是复制粘贴的路径,非首页/登录页,那么登录成功后重定向到对应的路径中
         if (route.query?.redirect) {
            router.push('/menu');
            // router.push({
            //    path: <string>route.query?.redirect,
            //    query: Object.keys(<string>route.query?.params).length > 0 ? JSON.parse(<string>route.query?.params) : '',
            // });
         } else {
            router.push('/login');
         }
         state.loading.signIn = true;
         const signInText = t('message.signInText');
         ElMessage.success(`${currentTimeInfo},${signInText}`);
         // 登录成功提示
         // 关闭 loading
         // 添加 loading,防止第一次进入界面时出现短暂空白
         // NextLoading.start();
      };
      return {
         onSignIn,
         ...toRefs(state),
      };
   },
    name: 'accountLogin',
    setup() {
        const { t } = useI18n();
        const userInfo = useUserInfo();
        const route = useRoute();
        const router = useRouter();
        const state = reactive({
            isShowPassword: false,
            saveCode: false,
            ruleForm: {
                username: '',
                password: ''
            },
            loading: {
                signIn: false
            },
            identity:{
                name: '',
                ID: '',
                phone: ''
            },
            codeForm:{
                pass: '',
                checkPass: ''
            },
            identifyDialog: false,
            changeDialog: false
        });
        const identifyRef = ref<FormInstance>()
        const codeRef = ref<FormInstance>()
        // 页面载入时执行方法
        onMounted(() => {
            hasUserCodeOrPassword()
            // getAllDepartment();
        });
        const hasUserCodeOrPassword =()=> {
            if (localStorage.getItem('userCode') && localStorage.getItem('userPassword')) {
                state.ruleForm.username = localStorage.getItem('userCode')
                state.ruleForm.password = Base64.decode(localStorage.getItem('userPassword'))//解密
                state.saveCode = true
            }
        }
        const checkCode = (rule: any, value: any, callback: any) => {
            if (value == '') {
                return callback(new Error('该内容不能为空'))
            }
            setTimeout(() => {
                if (!verifyIdCard(value)) {
                    callback(new Error('身份证格式不正确'))
                }else callback();
            }, 400)
        }
        const checkPhone = (rule: any, value: any, callback: any) => {
            if (value == '') {
                return callback(new Error('该内容不能为空'))
            }
            setTimeout(() => {
                if (!verifyPhone(value)) {
                    callback(new Error('手机号格式不正确'))
                }else callback();
            }, 400)
        }
        const identityRules = reactive({
            userName: [{ required: true, message: '该内容不能为空', trigger: 'blur' }],
            ID: [{ required: true, validator: checkCode, trigger: 'blur'}],
            phone: [{ required: true, validator: checkPhone, trigger: 'blur' }]
        });
        // 时间获取
        const currentTime = computed(() => {
            return formatAxis(new Date());
        });
        // 登录
        const onSignIn = async () => {
            state.loading.signIn = true;
            // 存储 token 到浏览器缓存
            let res = await useLoginApi().signIn(state.ruleForm);
            if (res.data.code === '200') {
                await userInfo.setUserInfos(res.data.data);
                Cookies.set('token', res.data.data.accessToken);
                Cookies.set('projectId', '');
                Cookies.set('uid', res.data.data.uid);
                // Session.set('token', res.data.data.accessToken);
                // Session.set('projectId', '');
                // Session.set('uid', res.data.data.uid);
                if (state.saveCode) {
                    localStorage.setItem('userCode', state.ruleForm.username)
                    localStorage.setItem('userPassword', Base64.encode(state.ruleForm.password),)
                } else {
                    localStorage.removeItem('userCode')
                    localStorage.removeItem('userPassword')
                }
                await signInSuccess();
            } else {
                state.loading.signIn = false;
                ElMessage({
                    type: 'warning',
                    message: res.data.msg
                });
            }
            state.loading.signIn = false;
            // Session.set('token', Math.random().toString(36).substr(0));
            // // 模拟数据,对接接口时,记得删除多余代码及对应依赖的引入。用于 `/src/stores/userInfo.ts` 中不同用户登录判断(模拟数据)
            // Cookies.set('userName', state.ruleForm.username);
            // if (!themeConfig.value.isRequestRoutes) {
            //    // 前端控制路由,2、请注意执行顺序
            //    await initFrontEndControlRoutes();
            //    signInSuccess();
            // } else {
            //    // 模拟后端控制路由,isRequestRoutes 为 true,则开启后端控制路由
            //    // 添加完动态路由,再进行 router 跳转,否则可能报错 No match found for location with path "/"
            //    await initBackEndControlRoutes();
            //    // 执行完 initBackEndControlRoutes,再执行 signInSuccess
            //    signInSuccess();
            // }
        };
        // 登录成功后的跳转
        const signInSuccess = async () => {
            // 初始化登录成功时间问候语
            let currentTimeInfo = currentTime.value;
            // 登录成功,跳到转首页
            // 如果是复制粘贴的路径,非首页/登录页,那么登录成功后重定向到对应的路径中
            // if (route.query?.redirect) {
            router.push('/newMenu');
            // router.push({
            //    path: <string>route.query?.redirect,
            //    query: Object.keys(<string>route.query?.params).length > 0 ? JSON.parse(<string>route.query?.params) : '',
            // });
            // } else {
            //     router.push('/loginPage');
            // }
            state.loading.signIn = true;
            const signInText = t('message.signInText');
            ElMessage.success(`${currentTimeInfo},${signInText}`);
            // 登录成功提示
            // 关闭 loading
            // 添加 loading,防止第一次进入界面时出现短暂空白
            // NextLoading.start();
        };
        // 修改密码
        const identify =()=>{
            state.identifyDialog = true
        }
        // 提交验证
        const confirmIdentity = (formEl: FormInstance | undefined) => {
            if (!formEl) return
            formEl.validate((valid) => {
                if (valid) {
                    state.identifyDialog = false
                    state.changeDialog = true
                } else {
                    console.log('error submit!')
                    return false
                }
            })
        }
        const clearIdentity = ()=>{
            state.identity = {
                name: '',
                ID: '',
                phone: ''
            }
        }
        // 修改密码
        const validatePass = (rule: any, value: any, callback: any) => {
            if (value === '') {
                callback(new Error('请输入密码'))
            } else {
                if (state.codeForm.checkPass !== '') {
                    if (!codeRef.value) return
                    codeRef.value.validateField('checkPass', () => null)
                }
                callback()
            }
        }
        const validatePass2 = (rule: any, value: any, callback: any) => {
            if (value === '') {
                callback(new Error('请输入密码'))
            } else if (value !== state.codeForm.pass) {
                callback(new Error("两次输入的密码不一致!"))
            } else {
                callback()
            }
        }
        const codeRules = reactive({
            pass: [{ required: true, validator: validatePass, trigger: 'blur' }],
            checkPass: [{ required: true, validator: validatePass2, trigger: 'blur' }]
        })
        const confirmChange = (formEl: FormInstance | undefined) => {
            if (!formEl) return
            formEl.validate((valid) => {
                if (valid) {
                    ElMessage({
                        type: 'success',
                        message: '修改成功,请使用新密码登录'
                    });
                    state.changeDialog = false
                    router.push('/login');
                } else {
                    console.log('error submit!')
                    return false
                }
            })
        }
        const clearCode=()=>{
            state.codeForm = {
                pass: '',
                checkPass: ''
            }
        }
        return {
            identifyRef,
            codeRef,
            identityRules,
            codeRules,
            clearIdentity,
            onSignIn,
            identify,
            confirmIdentity,
            confirmChange,
            clearCode,
            validatePass,
            validatePass2,
            ...toRefs(state)
        };
    }
});
</script>
<style scoped lang="scss">
.login-content-form {
   margin-top: 40px;
   width: 420px;
    margin-top: 40px;
    width: 100%;
   .el-input::v-deep .el-input__wrapper{
      height: 56px;
      border-radius: 28px;
      padding: 0 30px;
      background: #F2F2F2;
      &:focus-within{
         border: 1px solid #2053D7;
      }
   }
   @for $i from 1 through 4 {
      .login-animation#{$i} {
         opacity: 0;
         animation-name: error-num;
         animation-duration: 0.5s;
         animation-fill-mode: forwards;
         animation-delay: calc($i/10) + s;
      }
   }
   .codeDeal::v-deep .el-form-item__content{
      display: flex;
      justify-content: space-between;
    .el-input::v-deep .el-input__wrapper {
        height: 56px;
        border-radius: 28px;
        padding: 0 30px;
        background: #f2f2f2;
        &:focus-within {
            border: 1px solid #2053d7;
        }
    }
    @for $i from 1 through 4 {
        .login-animation#{$i} {
            opacity: 0;
            animation-name: error-num;
            animation-duration: 0.5s;
            animation-fill-mode: forwards;
            animation-delay: calc($i/10) + s;
        }
    }
    .codeDeal::v-deep .el-form-item__content {
        display: flex;
        justify-content: space-between;
      .forgetCode{
         color: #2053D7;
         cursor: pointer;
      }
   }
   .login-content-password {
      width: 100%;
      display: inline-block;
      width: 20px;
      cursor: pointer;
      &:hover {
         color: #909399;
      }
   }
   .login-content-code {
      width: 100%;
      padding: 0;
      font-weight: bold;
      letter-spacing: 5px;
   }
   .login-content-submit {
      width: 100%;
      height: 56px;
      font-size: 16px;
      border-radius: 28px;
      letter-spacing: 4px;
      font-weight: 300;
      margin-top: 15px;
      background: #2053D7;
      transition: .3s;
      &:hover{
         letter-spacing: 6px;
         background: #4E7AEC;
      }
   }
        .forgetCode {
            color: #2053d7;
            cursor: pointer;
        }
    }
    .login-content-password {
        width: 100%;
        display: inline-block;
        cursor: pointer;
        &:hover {
            color: #909399;
        }
    }
    .login-content-code {
        width: 100%;
        padding: 0;
        font-weight: bold;
        letter-spacing: 5px;
    }
    .login-content-submit {
        width: 100%;
        height: 56px;
        font-size: 16px;
        border-radius: 28px;
        letter-spacing: 4px;
        font-weight: 300;
        margin-top: 15px;
        background: #2053d7;
        transition: 0.3s;
        &:hover {
            letter-spacing: 6px;
            background: #4e7aec;
        }
    }
}
</style>