13个文件已删除
18个文件已修改
2个文件已添加
| New file |
| | |
| | | [ |
| | | { |
| | | "label": "居民身份证", |
| | | "value": 1 |
| | | }, |
| | | { |
| | | "label": "台港澳证件居民来往内地通行证", |
| | | "value": 2 |
| | | } |
| | | ] |
| | |
| | | export default { |
| | | |
| | | sex: { |
| | | key_1: '男', |
| | | key_0: '女' |
| | | }, |
| | | idCardType: { |
| | | key_1: '居民身份证', |
| | | key_2: '台港澳证件居民来往内地通行证' |
| | | } |
| | | } |
| | |
| | | app.component('UploadBtn', UploadBtn) |
| | | |
| | | app.use(ElementPlus, { |
| | | locale: zhCn |
| | | locale: zhCn, |
| | | |
| | | }) |
| | | const pinia = createPinia() |
| | | pinia.use(piniaPluginPersistedstate) |
| | |
| | | import authPage from '@/router/auth/index.js' |
| | | import errorPage from '@/router/error/index.js' |
| | | import mainPage from '@/router/main/index.js' |
| | | import h5 from '@/router/h5/router.js' |
| | | |
| | | import { useLoginStore } from '@/stores/login.js' |
| | | import { useSessionStore } from '@/stores/session.js' |
| | | const router = createRouter({ |
| | | history: createWebHistory(import.meta.env.BASE_URL), |
| | | routes: [...mainPage, ...authPage, ...errorPage, ...h5], |
| | | routes: [...mainPage, ...authPage, ...errorPage], |
| | | }) |
| | | |
| | | router.beforeEach((to, from, next) => { |
| | |
| | | next({ path: '/error/404', query: { errorUrl: to.path } }) |
| | | } |
| | | } else { |
| | | next() |
| | | if (to.meta.loginRequired) { |
| | | const { userInfo } = useSessionStore() |
| | | const { setLoginDialogVisible } = useLoginStore() |
| | | if (userInfo.id) { |
| | | next() |
| | | } else { |
| | | setLoginDialogVisible(true) |
| | | next(false) |
| | | } |
| | | } else { |
| | | next() |
| | | } |
| | | } |
| | | }) |
| | | |
| | |
| | | name: '评价计划', |
| | | component: () => import('@/views/main/appraisalPlan/index.vue'), |
| | | }, |
| | | { |
| | | path: 'appraisalPlan/signup/:id', |
| | | name: '评价计划报名', |
| | | component: () => import('@/views/main/appraisalPlan/index.vue'), |
| | | }, |
| | | ] |
| | | |
| | | export default appraisalPlan |
| | |
| | | path: 'center', |
| | | name: '个人中心', |
| | | component: () => import('@/views/main/center/index.vue'), |
| | | meta: { |
| | | loginRequired: false |
| | | } |
| | | }, |
| | | ] |
| | | |
| | |
| | | path: 'certificate', |
| | | name: '证书查询', |
| | | component: () => import('@/views/main/certificate/index.vue'), |
| | | meta: { |
| | | loginRequired: true |
| | | } |
| | | }, |
| | | ] |
| | | |
| | |
| | | path: 'examTicket', |
| | | name: '准考证查询', |
| | | component: () => import('@/views/main/examTicket/index.vue'), |
| | | meta: { |
| | | loginRequired: true |
| | | } |
| | | }, |
| | | ] |
| | | |
| | |
| | | path: 'home', |
| | | name: '首页', |
| | | component: () => import('@/views/main/home/index.vue'), |
| | | meta: { |
| | | loginRequired: false |
| | | } |
| | | }, |
| | | ] |
| | | |
| | |
| | | path: 'noticeList', |
| | | name: '公告列表', |
| | | component: () => import('@/views/main/notice/list.vue'), |
| | | meta: { |
| | | loginRequired: false |
| | | } |
| | | }, |
| | | { |
| | | path: 'noticeDetail/:id', |
| | | name: '公告详情', |
| | | component: () => import('@/views/main/notice/detail.vue'), |
| | | meta: { |
| | | loginRequired: false |
| | | } |
| | | }, |
| | | ] |
| | | |
| | |
| | | path: 'score', |
| | | name: '成绩查询', |
| | | component: () => import('@/views/main/score/index.vue'), |
| | | meta: { |
| | | loginRequired: true |
| | | } |
| | | }, |
| | | ] |
| | | |
| | |
| | | import { ref } from 'vue' |
| | | import { defineStore } from 'pinia' |
| | | export const useSessionStore = defineStore('session', () => { |
| | | const userInfo = ref({}) |
| | | const userInfo = ref({ |
| | | id: '', |
| | | nickName: '', |
| | | idCard: '', |
| | | idCardType: '', |
| | | mobile: '', |
| | | sex: '', |
| | | avatar: '', |
| | | idCardFrontImg: '', |
| | | idCardBackImg: '' |
| | | }) |
| | | |
| | | function setUserInfo(data) { |
| | | userInfo.value = data |
| | |
| | | export const ruleGenerator = { |
| | | // 必填字段 |
| | | required(message = '此字段为必填项') { |
| | | return { required: true, message, trigger: 'blur' } |
| | | return { required: true, message, trigger: ['blur', 'change'] } |
| | | }, |
| | | |
| | | // 长度限制 |
| | |
| | | callback(new Error('请输入正确的手机号码')) |
| | | } |
| | | }, |
| | | trigger: ['blur', 'change'] |
| | | trigger: ['blur'] |
| | | } |
| | | }, |
| | | //验证码验证 |
| | |
| | | trigger: ['blur', 'change'] |
| | | } |
| | | }, |
| | | |
| | | // 多选框验证 |
| | | checkbox(message) { |
| | | return { |
| | | validator: (rule, value, callback) => { |
| | | if (!value) { |
| | | callback(new Error(message)); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }, |
| | | trigger: 'change' |
| | | } |
| | | }, |
| | | |
| | | |
| | | // 邮箱验证 |
| | | email() { |
| | | return { |
| | |
| | | }, |
| | | trigger: 'blur' |
| | | } |
| | | } |
| | | }, |
| | | |
| | | // 大于等于0的正整数验证 |
| | | positiveInteger(min = 0) { |
| | | return { |
| | | validator: (rule, value, callback) => { |
| | | if (!value) { |
| | | callback() |
| | | } else { |
| | | // 检查是否为正整数且大于等于min |
| | | const num = Number(value) |
| | | const isPositiveInteger = Number.isInteger(num) && num >= min && num >= 0 |
| | | if (isPositiveInteger) { |
| | | callback() |
| | | } else { |
| | | callback(new Error(min === 0 ? '请输入大于等于0的正整数' : `请输入大于等于${min}的正整数`)) |
| | | } |
| | | } |
| | | }, |
| | | trigger: ['blur', 'change'] |
| | | } |
| | | }, |
| | | |
| | | // 身份证号验证 |
| | | idCard() { |
| | | return { |
| | | validator: (rule, value, callback) => { |
| | | if (!value) { |
| | | callback() |
| | | return |
| | | } |
| | | |
| | | // 18位身份证正则表达式 |
| | | const reg18 = /^[1-9]\d{5}(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/ |
| | | // 15位身份证正则表达式(老式) |
| | | const reg15 = /^[1-9]\d{5}\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}$/ |
| | | |
| | | if (reg18.test(value)) { |
| | | // 18位身份证校验码验证 |
| | | const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2] |
| | | const checkCodes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'] |
| | | let sum = 0 |
| | | for (let i = 0; i < 17; i++) { |
| | | sum += parseInt(value[i]) * weights[i] |
| | | } |
| | | const checkCode = checkCodes[sum % 11] |
| | | if (checkCode.toUpperCase() === value[17].toUpperCase()) { |
| | | callback() |
| | | } else { |
| | | callback(new Error('请输入正确的身份证号码')) |
| | | } |
| | | } else if (reg15.test(value)) { |
| | | // 15位身份证校验通过 |
| | | callback() |
| | | } else { |
| | | callback(new Error('请输入正确的身份证号码')) |
| | | } |
| | | }, |
| | | trigger: ['blur', 'change'] |
| | | } |
| | | }, |
| | | |
| | | // 统一社会信用代码验证 |
| | | creditCode() { |
| | | return { |
| | | validator: (rule, value, callback) => { |
| | | if (!value) { |
| | | callback() |
| | | return |
| | | } |
| | | |
| | | // 统一社会信用代码由18位字符组成:1位登记管理部门代码 + 1位机构类别代码 + 6位登记管理机关行政区划码 + 9位主体识别码(组织机构代码) + 1位校验码 |
| | | const reg = /^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$/ |
| | | |
| | | if (!reg.test(value)) { |
| | | callback(new Error('请输入正确的统一社会信用代码')) |
| | | return |
| | | } |
| | | |
| | | // 校验码计算 |
| | | const weights = [1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, 30, 28] |
| | | const checkCodes = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'T', 'U', 'W', 'X', 'Y'] |
| | | |
| | | let sum = 0 |
| | | for (let i = 0; i < 17; i++) { |
| | | const char = value[i] |
| | | // 将字符转换为对应的数值 |
| | | const num = char >= '0' && char <= '9' ? parseInt(char) : char.charCodeAt(0) - 55 |
| | | sum += num * weights[i] |
| | | } |
| | | |
| | | const mod = 31 |
| | | const remainder = sum % mod |
| | | const checkCode = checkCodes[(mod - remainder) % mod] |
| | | |
| | | if (checkCode === value[17].toUpperCase()) { |
| | | callback() |
| | | } else { |
| | | callback(new Error('请输入正确的统一社会信用代码')) |
| | | } |
| | | }, |
| | | trigger: ['blur', 'change'] |
| | | } |
| | | }, |
| | | |
| | | // 金额验证(保留2位小数) |
| | | money(min = 0) { |
| | | return { |
| | | validator: (rule, value, callback) => { |
| | | if (!value) { |
| | | callback() |
| | | return |
| | | } |
| | | |
| | | // 金额正则:整数部分不限位数,小数部分最多2位 |
| | | const reg = /^(0|[1-9]\d*)(\.\d{1,2})?$/ |
| | | |
| | | if (!reg.test(value)) { |
| | | callback(new Error('请输入正确的金额')) |
| | | return |
| | | } |
| | | |
| | | const num = parseFloat(value) |
| | | if (num < min) { |
| | | callback(new Error(`金额不能小于${min}`)) |
| | | } else { |
| | | callback() |
| | | } |
| | | }, |
| | | trigger: ['blur', 'change'] |
| | | } |
| | | }, |
| | | // 多选框验证 |
| | | checkbox(message) { |
| | | return { |
| | | validator: (rule, value, callback) => { |
| | | if (!value) { |
| | | callback(new Error(message)); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }, |
| | | trigger: 'change' |
| | | } |
| | | }, |
| | | } |
| | |
| | | </template> |
| | | </el-input> |
| | | </el-form-item> |
| | | <el-form-item prop="agreement" style="height: 30px;"> |
| | | <!-- <el-form-item prop="agreement" style="height: 30px;"> |
| | | <el-checkbox v-model="form.agreement" label="同意xxx服务协议" size="large" /> |
| | | </el-form-item> |
| | | </el-form-item> --> |
| | | |
| | | <el-button class="mt-1" @click="submitLogin()" :loading="loginLoading" type="primary" size="large" style="width: 100%;"> |
| | | <el-button |
| | | class="mt-3" |
| | | @click="submitLogin()" |
| | | :loading="loginLoading" |
| | | type="primary" size="large" |
| | | style="width: 100%;" |
| | | > |
| | | <el-text class="text-lg text-white">登录</el-text> |
| | | </el-button> |
| | | </el-form> |
| | |
| | | <el-radio :value="0">女</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | <el-form-item prop="idCard"> |
| | | <el-input v-model="form.idCard" placeholder="请输入身份证号" /> |
| | | <el-form-item prop="idCardType"> |
| | | <el-select v-model="form.idCardType" placeholder="证件类型"> |
| | | <el-option |
| | | v-for="item in idCardTypeItems" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item prop="idCard" :rules="[$rules.required('请输入证件号码'), form.idCardType == 1 ? $rules.idCard('请输入正确的身份证号'): '' ]"> |
| | | <el-input v-model="form.idCard" placeholder="请输入证件号码" /> |
| | | </el-form-item> |
| | | <el-form-item prop="mobile"> |
| | | <el-input v-model="form.mobile" placeholder="请输入手机号" /> |
| | |
| | | </template> |
| | | </el-input> |
| | | </el-form-item> |
| | | <el-form-item prop="agreement" style="height: 30px;"> |
| | | <!-- <el-form-item prop="agreement" style="height: 30px;"> |
| | | <el-checkbox v-model="form.agreement" label="同意xxx服务协议" size="large" /> |
| | | </el-form-item> |
| | | </el-form-item> --> |
| | | |
| | | <el-button class="mt-1" @click="submitRegister()" type="primary" size="large" style="width: 100%;"> |
| | | <el-button |
| | | class="mt-5" |
| | | :loading="registerLoading" |
| | | @click="submitRegister()" |
| | | type="primary" size="large" |
| | | style="width: 100%;" |
| | | > |
| | | <el-text class="text-lg text-white">注册</el-text> |
| | | </el-button> |
| | | </el-form> |
| | |
| | | <el-row class="mt-7" justify="center"> |
| | | <el-button v-if="loginType!='register'" text type="primary" @click="changeLoginType('register')">注册账号</el-button> |
| | | <el-divider v-if="loginType!='register'" direction="vertical" class="m-0 mt-1 mx-4" style="height: 24px !important" /> |
| | | <el-button v-if="loginType!='qrCode'" text type="primary" @click="changeLoginType('qrCode')">二维码登录</el-button> |
| | | <el-button v-if="loginType!='qrCode'" text type="primary" @click="changeLoginType('qrCode')">微信扫码登录</el-button> |
| | | <el-divider v-if="loginType=='register'" direction="vertical" class="m-0 mt-1 mx-4" style="height: 24px !important" /> |
| | | <el-button v-if="loginType!='mobile'" text type="primary" @click="changeLoginType('mobile')">手机号登录</el-button> |
| | | </el-row> |
| | |
| | | import { useLoginStore } from '@/stores/login.js' |
| | | import { useSessionStore } from '@/stores/session.js' |
| | | import { storeToRefs } from 'pinia'; |
| | | import idCardTypeItems from '@/assets/json/idCardTypeItems.json' |
| | | import { tokenUtils } from '@/utils/axios.js'; |
| | | export default { |
| | | components: {}, |
| | | setup() { |
| | |
| | | form: { |
| | | name: '', |
| | | sex: 1, |
| | | idCardType: 1, |
| | | idCard: '', |
| | | mobile: '13537719675', |
| | | mobile: '', |
| | | code: '', |
| | | agreement: false |
| | | }, |
| | | idCardTypeItems: idCardTypeItems, |
| | | rules: { |
| | | name: [ this.$rules.required('请输入姓名') ], |
| | | idCard: [ this.$rules.required('请输入身份证号') ], |
| | | mobile: [ this.$rules.required('请输入手机号'), this.$rules.phone() ], |
| | | code: [ this.$rules.required('请填写验证码'), this.$rules.code() ], |
| | | agreement: [ this.$rules.checkbox('请阅读并勾选同意协议') ] |
| | |
| | | countdown: 180, |
| | | countdownInterval: null, |
| | | sendCodeLoading: false, |
| | | loginLoading: false |
| | | loginLoading: false, |
| | | registerLoading: false |
| | | } |
| | | }, |
| | | computed: { |
| | |
| | | this.clearCountdownInterval() |
| | | }, |
| | | watch: { |
| | | |
| | | loginDialogVisible: function(val) { |
| | | if (!val) { |
| | | this.clearCountdownInterval() |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | | async sendCode() { |
| | | try { |
| | | await this.$refs.accountForm.validateField('mobile') |
| | | this.startCountdownInterval() |
| | | this.$message.success('已发送验证码,请注意查收') |
| | | let ref = null |
| | | let scene = 0 |
| | | if (this.loginType == 'mobile') { |
| | | ref = this.$refs.accountForm |
| | | scene = 33 |
| | | } else if (this.loginType == 'register') { |
| | | ref = this.$refs.registerForm |
| | | scene = 32 |
| | | } |
| | | const validate = await ref.validateField('mobile') |
| | | if (validate) { |
| | | const data = { |
| | | captchaVerification: '', |
| | | mobile: this.form.mobile, |
| | | scene: scene, |
| | | } |
| | | this.sendCodeLoading = true |
| | | this.$axios.post('/system/auth/send-sms-code', data).then(res => { |
| | | if (res.data.code == 0) { |
| | | this.startCountdownInterval() |
| | | this.$message.success('已发送验证码,请注意查收') |
| | | } else { |
| | | this.$message.error(res.data.msg || '获取验证码失败') |
| | | } |
| | | }).finally(() => { |
| | | this.sendCodeLoading = false |
| | | }) |
| | | } |
| | | } catch (error) { |
| | | console.log(error) |
| | | this.$message.error('请输入手机号码') |
| | | } |
| | | }, |
| | |
| | | try { |
| | | await this.$refs.accountForm.validate() |
| | | this.loginLoading = true |
| | | setTimeout(() => { |
| | | localStorage.setItem('accessToken', '123456') |
| | | this.getUserInfo() |
| | | this.$message.success('登录成功') |
| | | this.loginDialogVisible = false |
| | | const data = { |
| | | mobile: this.form.mobile, |
| | | code: this.form.code |
| | | } |
| | | this.$axios.post('/system/kw/examinee/login', data).then(res => { |
| | | if (res.data.code == 0) { |
| | | const resData = res.data.data || {} |
| | | tokenUtils.setTokens(resData.accessToken, resData.refreshToken) |
| | | this.getUserInfo() |
| | | this.$message.success('登录成功') |
| | | this.loginDialogVisible = false |
| | | } else { |
| | | this.$message.error(res.data.msg) |
| | | } |
| | | }).finally(() => { |
| | | this.loginLoading = false |
| | | |
| | | }, 1000) |
| | | }) |
| | | } catch (error) { |
| | | console.log() |
| | | } |
| | | }, |
| | | getUserInfo() { |
| | | this.setUserInfo({ |
| | | id: '123456', |
| | | username: '黄婷婷', |
| | | this.$axios.get('/system/kw/examinee/profile').then(res => { |
| | | if (res.data.code == 0) { |
| | | const resData = res.data.data || {} |
| | | this.setUserInfo(resData) |
| | | } else { |
| | | this.$message.error(res.data.msg) |
| | | } |
| | | }) |
| | | }, |
| | | async submitRegister() { |
| | | try { |
| | | await this.$refs.registerForm.validate() |
| | | const validate = await this.$refs.registerForm.validate() |
| | | if (validate) { |
| | | const data = { ...this.form } |
| | | this.$axios.post('/system/kw/examinee/register', data).then(res => { |
| | | if (res.data.code == 0) { |
| | | const resData = res.data.data || {} |
| | | tokenUtils.setTokens(resData.accessToken, resData.refreshToken) |
| | | this.getUserInfo() |
| | | this.$message.success('注册成功') |
| | | this.loginDialogVisible = false |
| | | } else { |
| | | this.$message.error(res.data.msg) |
| | | } |
| | | }) |
| | | } |
| | | } catch (error) { |
| | | console.log() |
| | | console.log(error) |
| | | this.$message.error('请检查必填字段') |
| | | } |
| | | }, |
| | | changeLoginType(type) { |
| | |
| | | computed: { |
| | | filterList() { |
| | | return this.planList.slice((this.filter.pageNo-1)*this.filter.pageSize, this.filter.pageNo*this.filter.pageSize) |
| | | }, |
| | | query() { |
| | | return this.$route.query |
| | | } |
| | | }, |
| | | watch: { |
| | | signupDialogVisible: { |
| | | handler: function(val) { |
| | | if (!val) { |
| | | this.$router.replace({ path: this.$route.path }) |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | created() { |
| | | this.getPlanList() |
| | | |
| | | }, |
| | | mounted() { |
| | | if (this.query.signupDialogFlag == '1') { |
| | | this.signup({ id: this.query.appraisalId }) |
| | | } |
| | | }, |
| | | methods: { |
| | | getPlanList() { |
| | |
| | | }, 400) |
| | | }, |
| | | signup(item) { |
| | | if (this.userInfo.id) { |
| | | this.signupDialogVisible = true |
| | | this.currentPlan = item |
| | | } else { |
| | | this.loginDialogVisible = true |
| | | this.$message.primary('请先登录') |
| | | } |
| | | this.signupDialogVisible = true |
| | | this.currentPlan = item |
| | | this.$router.replace({ path: this.$route.path, query: { appraisalId: item.id, signupDialogFlag: 1 } }) |
| | | // if (this.userInfo.id) { |
| | | // this.signupDialogVisible = true |
| | | // this.currentPlan = item |
| | | // this.$router.replace({ path: this.$route.path, query: { appraisalId: item.id, signupDialogFlag: 1 } }) |
| | | // } |
| | | // else { |
| | | // this.loginDialogVisible = true |
| | | // this.$message.primary('请先登录') |
| | | // } |
| | | } |
| | | } |
| | | } |
| | |
| | | <el-col :span="22"> |
| | | <div v-if="activeTab=='toExam'" class="p-4 px-6"> |
| | | <el-row align="middle"> |
| | | <el-text class="font-medium">姓名:{{ form.name }}</el-text> |
| | | <el-text class="font-medium">姓名:{{ userInfo.nickname }}</el-text> |
| | | <el-button text class="ml-2"> |
| | | <Icon icon="ix:pen-filled" width="18" height="18" style="color: black" /> |
| | | </el-button> |
| | | </el-row> |
| | | <el-row align="middle"> |
| | | <el-text class="font-medium">性别:{{ form.gender }}</el-text> |
| | | <el-text class="font-medium">性别:{{ sexText }}</el-text> |
| | | <el-button text class="ml-2"> |
| | | <Icon icon="ix:pen-filled" width="18" height="18" style="color: black" /> |
| | | </el-button> |
| | | </el-row> |
| | | <el-row align="middle"> |
| | | <el-text class="font-medium">手机号:{{ form.mobilePhone }}</el-text> |
| | | <el-text class="font-medium">手机号:{{ userInfo.mobile }}</el-text> |
| | | <el-button text class="ml-2"> |
| | | <Icon icon="ix:pen-filled" width="18" height="18" style="color: black" /> |
| | | </el-button> |
| | | </el-row> |
| | | <el-row align="middle" class="my-1"> |
| | | <el-text class="font-medium">证件类型:{{ idCardTypeText }}</el-text> |
| | | </el-row> |
| | | <el-row align="middle"> |
| | | <el-text class="font-medium">身份证号:{{ form.idCard }}</el-text> |
| | | <el-text class="font-medium">证件正反面:{{ userInfo.idCard }}</el-text> |
| | | <el-button text class="ml-2"> |
| | | <Icon icon="ix:pen-filled" width="18" height="18" style="color: black" /> |
| | | </el-button> |
| | |
| | | <el-text class="font-medium">身份证正反面:</el-text> |
| | | </el-row> |
| | | <el-row> |
| | | <UploadIdCard v-model="form.idCardFace" :accept="['jpg', 'png']" type="face"></UploadIdCard> |
| | | <UploadIdCard v-model="form.idCardEmblem" :accept="['jpg', 'png']" type="emblem"></UploadIdCard> |
| | | <UploadIdCard v-model="userInfo.idCardFace" :accept="['jpg', 'png']" type="face"></UploadIdCard> |
| | | <UploadIdCard v-model="userInfo.idCardEmblem" :accept="['jpg', 'png']" type="emblem"></UploadIdCard> |
| | | </el-row> |
| | | <el-row align="middle" class="mt-2"> |
| | | <el-text class="font-medium">证书/准考证头像:</el-text> |
| | | </el-row> |
| | | <UploadBtn v-model="form.certificateAvatar" listType="picture-card" :accept="['jpg', 'png']" ></UploadBtn> |
| | | <UploadBtn v-model="userInfo.certificateAvatar" listType="picture-card" :accept="['jpg', 'png']" ></UploadBtn> |
| | | |
| | | <el-row class="mt-5"> |
| | | <el-text>绑定微信:暂未绑定微信</el-text> |
| | |
| | | } |
| | | }, |
| | | computed: { |
| | | |
| | | sexText() { |
| | | return this.$property.sex[`key_${this.userInfo.sex}`] |
| | | }, |
| | | idCardTypeText() { |
| | | return this.$property.idCardType[`key_${this.userInfo.idCardType}`] |
| | | } |
| | | }, |
| | | watch: { |
| | | activeTab: { |
| New file |
| | |
| | | <template> |
| | | <div class="loading-content"> |
| | | <div class="loading-spinner"> |
| | | <div class="spinner-ring"></div> |
| | | <div class="spinner-ring"></div> |
| | | <div class="spinner-ring"></div> |
| | | </div> |
| | | <div class="loading-text">加载中...</div> |
| | | </div> |
| | | </template> |
| | | |
| | | <style> |
| | | .loading-container { |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | } |
| | | |
| | | .loading-content { |
| | | text-align: center; |
| | | } |
| | | |
| | | .loading-spinner { |
| | | position: relative; |
| | | width: 60px; |
| | | height: 60px; |
| | | margin: 0 auto 16px; |
| | | } |
| | | |
| | | .spinner-ring { |
| | | position: absolute; |
| | | width: 100%; |
| | | height: 100%; |
| | | border: 3px solid transparent; |
| | | border-top-color: #007aff; |
| | | border-radius: 50%; |
| | | animation: spin 1.2s linear infinite; |
| | | } |
| | | |
| | | .spinner-ring:nth-child(1) { |
| | | animation-delay: 0s; |
| | | } |
| | | |
| | | .spinner-ring:nth-child(2) { |
| | | width: 80%; |
| | | height: 80%; |
| | | top: 10%; |
| | | left: 10%; |
| | | animation-delay: 0.15s; |
| | | border-top-color: #66b1ff; |
| | | } |
| | | |
| | | .spinner-ring:nth-child(3) { |
| | | width: 60%; |
| | | height: 60%; |
| | | top: 20%; |
| | | left: 20%; |
| | | animation-delay: 0.3s; |
| | | border-top-color: #a0cfff; |
| | | } |
| | | |
| | | @keyframes spin { |
| | | from { |
| | | transform: rotate(0deg); |
| | | } |
| | | to { |
| | | transform: rotate(360deg); |
| | | } |
| | | } |
| | | |
| | | .loading-text { |
| | | font-size: 14px; |
| | | color: #666; |
| | | animation: pulse 1.5s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes pulse { |
| | | 0%, 100% { |
| | | opacity: 0.6; |
| | | } |
| | | 50% { |
| | | opacity: 1; |
| | | } |
| | | } |
| | | |
| | | </style> |
| | |
| | | <template> |
| | | <div class="custom-footer"> |
| | | <el-row justify="center"> |
| | | <!-- <el-row justify="center"> |
| | | <el-select |
| | | v-for="(item,index) in selectList" |
| | | v-model="item.value" |
| | |
| | | :value="item.value" |
| | | /> |
| | | </el-select> |
| | | </el-row> |
| | | </el-row> --> |
| | | <el-row> |
| | | <el-text class="text-white font-medium text-default"> |
| | | ©2025 深圳市企鹅网络科技有限公司 粤ICP备15026064号 粤公网安备 44030502007327 号 |
| | |
| | | <style scoped> |
| | | .custom-footer { |
| | | width: 100%; |
| | | min-height: 185px !important; |
| | | min-height: 60px !important; |
| | | display: flex; |
| | | padding: 20px; |
| | | flex-direction: column; |
| | |
| | | <el-dropdown v-if="userInfo.id" placement="bottom"> |
| | | <el-row align="middle"> |
| | | <Icon icon="fa:user-circle" width="22" height="22" class="mr-2" style="color: #fff" /> |
| | | <el-text class="text-white cursor-p text-lg font-bold">黄婷婷</el-text> |
| | | <el-text class="text-white cursor-p text-lg font-bold">{{ userInfo.nickname }}</el-text> |
| | | <Icon icon="flowbite:caret-down-solid" width="22" height="22" class="ml-2" style="color: #fff" /> |
| | | </el-row> |
| | | <template #dropdown> |
| | |
| | | </el-dropdown-menu> |
| | | </template> |
| | | </el-dropdown> |
| | | <el-button v-else color="#007AFF"> |
| | | <el-text class="text-white cursor-p text-lg font-bold" @click="login">登 录</el-text> |
| | | <el-button @click="login" v-else color="#007AFF"> |
| | | <el-text class="text-white cursor-p text-lg font-bold">登 录</el-text> |
| | | </el-button> |
| | | </el-row> |
| | | </div> |
| | |
| | | import { useSessionStore } from '@/stores/session.js' |
| | | import { useLoginStore } from '@/stores/login.js' |
| | | import { storeToRefs } from 'pinia'; |
| | | |
| | | import { tokenUtils } from '@/utils/axios.js' |
| | | export default { |
| | | setup() { |
| | | const { loginDialogVisible } = storeToRefs(useLoginStore()) |
| | |
| | | }, |
| | | data() { |
| | | return { |
| | | |
| | | } |
| | | }, |
| | | created() { |
| | | const token = localStorage.getItem('accessToken') |
| | | if (token) { |
| | | if (tokenUtils.getAccessToken()) { |
| | | this.getUserInfo() |
| | | } else { |
| | | this.$emit('getUserInfoFlag') |
| | | } |
| | | }, |
| | | methods: { |
| | |
| | | this.loginDialogVisible = true |
| | | }, |
| | | getUserInfo() { |
| | | setTimeout(() => { |
| | | this.setUserInfo({ |
| | | id: '12345', |
| | | username: '黄婷婷' |
| | | }) |
| | | }, 1000) |
| | | this.$axios.get('/system/kw/examinee/profile').then(res => { |
| | | if (res.data.code == 0) { |
| | | const resData = res.data.data || {} |
| | | this.setUserInfo(resData) |
| | | } else { |
| | | this.$message.error(res.data.msg) |
| | | } |
| | | }).finally(() => { |
| | | this.$emit('getUserInfoFlag') |
| | | }) |
| | | }, |
| | | gotoCenter() { |
| | | this.$router.push('/main/center') |
| | |
| | | this.$messageBox.confirm('确定要退出登录吗', '提示', |
| | | { confirmButtonText: '确定', cancelButtonText: '取消', type: 'error' }).then(res => { |
| | | if (res == 'confirm') { |
| | | localStorage.removeItem('accessToken') |
| | | tokenUtils.clearTokens() |
| | | this.setUserInfo({}) |
| | | this.$message.success('退出登录') |
| | | if (this.$route.meta.loginRequired) { |
| | | this.$router.replace('/main/home') |
| | | } |
| | | } |
| | | }) |
| | | } |
| | |
| | | <template> |
| | | <el-container direction="vertical" style="height: 100vh;"> |
| | | <el-header class="p-0"> |
| | | <MyHeader></MyHeader> |
| | | <MyHeader @getUserInfoFlag="getUserInfoFlag=true"></MyHeader> |
| | | </el-header> |
| | | <el-main :style="{height: mainHeight}" class="custom-main p-0" > |
| | | <div> |
| | | <div v-if="getUserInfoFlag"> |
| | | <router-view></router-view> |
| | | </div> |
| | | <div v-else :style="{'min-height': `${height-150}px`}" class="loading-container"> |
| | | <CustomLoading /> |
| | | </div> |
| | | <MyFooter></MyFooter> |
| | | </el-main> |
| | | |
| | | <LoginDialog /> |
| | | </el-container> |
| | | </template> |
| | |
| | | import MyHeader from '@/views/main/components/MyHeader.vue' |
| | | import MyFooter from '@/views/main/components/MyFooter.vue' |
| | | import LoginDialog from '@/views/login/index.vue' |
| | | import CustomLoading from '@/views/main/components/CustomLoading.vue' |
| | | export default { |
| | | components: { |
| | | MyHeader, |
| | | MyFooter, |
| | | LoginDialog |
| | | LoginDialog, |
| | | CustomLoading |
| | | }, |
| | | setup() { |
| | | const { height } = useWindowSize() |
| | | return { height } |
| | | }, |
| | | data() { |
| | | return { |
| | | getUserInfoFlag: false |
| | | } |
| | | }, |
| | | computed: { |
| | | mainHeight: function() { |
| | | return `${this.height - 60}px` |
| | | } |
| | | }, |
| | | created() { |
| | | this.getUserInfo() |
| | | }, |
| | | methods: { |
| | | getUserInfo() { |
| | | |
| | | } |
| | | } |
| | | |
| | | } |
| | | </script> |
| | | |