加入修改单位密码功能;

加入登录背景图;
修改部分细节
This commit is contained in:
471615499@qq.com 2024-10-30 20:37:38 +08:00
parent 34563b19e6
commit a3f2edf6a9
7 changed files with 361 additions and 140 deletions

View File

@ -31,4 +31,17 @@ export function delMeetingUto (parameter) {
}) })
} }
/**
* 更改单位密码
* @param parameter
* @returns {AxiosPromise}
*/
export function changePswd(parameter) {
return axios({
url: '/admin/mr/changePswd',
method: 'post',
data: parameter
})
}
export const meetingUtoExport = api.meetingUto + '/export' export const meetingUtoExport = api.meetingUto + '/export'

Binary file not shown.

After

Width:  |  Height:  |  Size: 745 KiB

View File

@ -6,7 +6,7 @@
</span> </span>
<template v-slot:overlay> <template v-slot:overlay>
<a-menu class="ant-pro-drop-down menu" :selected-keys="[]"> <a-menu class="ant-pro-drop-down menu" :selected-keys="[]">
<a-menu-item v-if="menu" key="center" @click="handleToCenter"> <a-menu-item v-if="menu" key="center" @click="handleToCenter" style='display: none'>
<a-icon type="user" />{{ i18nRender('menu.account.center') }} <a-icon type="user" />{{ i18nRender('menu.account.center') }}
</a-menu-item> </a-menu-item>
<a-menu-item v-if="menu" key="settings" @click="handleToSettings"> <a-menu-item v-if="menu" key="settings" @click="handleToSettings">

View File

@ -0,0 +1,176 @@
<template>
<div class="account-settings-info-view">
<a-row :gutter="16">
<a-col :md="24" :lg="16">
<a-form @submit="handleSubmit" :form="form" layout="vertical">
<a-form-item>
<a-input-password placeholder="单位帐号" v-decorator="['loginName', {rules: [{ required: true, message: '请选录入旧密码' }]}]"/>
</a-form-item>
<a-form-item>
<a-input-password placeholder="旧密码" v-decorator="['password', {rules: [{ required: true, message: '请选录入旧密码' }]}]"/>
</a-form-item>
<a-popover
placement="rightTop"
:trigger="['focus']"
:getPopupContainer="(trigger) => trigger.parentElement"
v-model="state.passwordLevelChecked">
<template slot="content">
<div :style="{ width: '240px' }" >
<div :class="['user-register', passwordLevelClass]">强度<span>{{ passwordLevelName }}</span></div>
<a-progress :percent="state.percent" :showInfo="false" :strokeColor=" passwordLevelColor " />
<div style="margin-top: 10px;">
<span>请至少输入 6 个字符请不要使用容易被猜到的密码</span>
</div>
</div>
</template>
<a-form-item>
<a-input-password
@click="handlePasswordInputClick"
placeholder="新密码至少6位密码区分大小写"
v-decorator="['newPassword', {rules: [{ required: true, message: '新密码至少6位密码区分大小写'}, { validator: this.handlePasswordLevel }], validateTrigger: ['change', 'blur']}]"
></a-input-password>
</a-form-item>
</a-popover>
<a-form-item>
<a-input-password
placeholder="重复新密码"
v-decorator="['rePassword', {rules: [{ required: true, message: '新密码至少6位密码区分大小写' }, { validator: this.handlePasswordCheck }], validateTrigger: ['change', 'blur']}]"
></a-input-password>
</a-form-item>
<a-form-item>
<a-button htmlType="submit" type="primary">修改密码</a-button>
</a-form-item>
</a-form>
</a-col>
</a-row>
</div>
</template>
<script>
import { changePswd } from '@/api/admin/meeting/uto'
const levelNames = {
0: '低',
1: '低',
2: '中',
3: '强'
}
const levelClass = {
0: 'error',
1: 'error',
2: 'warning',
3: 'success'
}
const levelColor = {
0: '#ff0000',
1: '#ff0000',
2: '#ff7e05',
3: '#52c41a'
}
export default {
data () {
return {
state: {
passwordLevel: 0,
passwordLevelChecked: false,
percent: 10
},
form: this.$form.createForm(this)
}
},
computed: {
passwordLevelClass () {
return levelClass[this.state.passwordLevel]
},
passwordLevelName () {
return levelNames[this.state.passwordLevel]
},
passwordLevelColor () {
return levelColor[this.state.passwordLevel]
}
},
methods: {
handlePasswordLevel (rule, value, callback) {
let level = 0
//
if (/[0-9]/.test(value)) {
level++
}
//
if (/[a-zA-Z]/.test(value)) {
level++
}
//
if (/[^0-9a-zA-Z_]/.test(value)) {
level++
}
this.state.passwordLevel = level
this.state.percent = level * 30
if (level >= 2) {
if (level >= 3) {
this.state.percent = 100
}
callback()
} else {
if (level === 0) {
this.state.percent = 10
}
callback(new Error('密码强度不够'))
}
},
handlePasswordCheck (rule, value, callback) {
const password = this.form.getFieldValue('newPassword')
if (value === undefined) {
callback(new Error('请输入密码'))
}
if (value && password && value.trim() !== password.trim()) {
callback(new Error('两次密码不一致'))
}
callback()
},
handlePasswordInputClick () {
if (!this.isMobile) {
this.state.passwordLevelChecked = true
return
}
this.state.passwordLevelChecked = false
},
// handler
handleSubmit (e) {
e.preventDefault()
this.form.validateFields((err, values) => {
if (!err) {
// eslint-disable-next-line no-console
console.log('Received values of form: ', values)
changePswd(values).then(res => {
if (res.code === 0) {
this.$message.success('修改成功')
this.$emit('ok')
this.visible = false
} else {
this.$message.error('修改错误,请检查帐号或密码!')
}
}).catch(() => {
this.$message.error('系统错误,请稍后再试')
}).finally(() => {
this.confirmLoading = false
})
}
})
},
watch: {
'state.passwordLevel' (val) {
console.log(val)
}
}
}
}
</script>
<style scoped>
</style>

View File

@ -1,44 +1,49 @@
<template> <template>
<div class="page-header-index-wide"> <div class='page-header-index-wide'>
<a-card :bordered="false" :bodyStyle="{ padding: '16px 0', height: '100%' }" :style="{ height: '100%' }"> <a-card :bordered='false' :bodyStyle="{ padding: '16px 0', height: '100%' }" :style="{ height: '100%' }">
<div class="account-settings-info-main" :class="{ 'mobile': isMobile }"> <div class='account-settings-info-main' :class="{ 'mobile': isMobile }">
<div class="account-settings-info-left"> <div class='account-settings-info-left'>
<a-menu <a-menu
:mode="isMobile ? 'horizontal' : 'inline'" :mode="isMobile ? 'horizontal' : 'inline'"
:style="{ border: '0', width: isMobile ? '560px' : 'auto'}" :style="{ border: '0', width: isMobile ? '560px' : 'auto'}"
:selectedKeys="selectedKeys" :selectedKeys='selectedKeys'
type="inner" type='inner'
@openChange="onOpenChange" @openChange='onOpenChange'
> >
<!-- <a-menu-item key="/account/settings/base">--> <!-- <a-menu-item key="/account/settings/base">-->
<!-- <router-link :to="{ name: 'base' }">--> <!-- <router-link :to="{ name: 'base' }">-->
<!-- {{ i18nRender('menu.account.settings.base') }}--> <!-- {{ i18nRender('menu.account.settings.base') }}-->
<!-- </router-link>--> <!-- </router-link>-->
<!-- </a-menu-item>--> <!-- </a-menu-item>-->
<a-menu-item key="/account/settings/security"> <a-menu-item key='/account/settings/security' v-if='changePwd'>
<router-link :to="{ name: 'security' }"> <router-link :to="{ name: 'security' }">
{{ i18nRender('menu.account.settings.security') }} 登录密码修改
</router-link> </router-link>
</a-menu-item> </a-menu-item>
<!-- <a-menu-item key="/account/settings/custom">--> <a-menu-item key='/account/settings/depPwd'>
<!-- <router-link :to="{ name: 'custom' }">--> <router-link :to="{ path: '/account/settings/depPwd' }">
<!-- {{ i18nRender('menu.account.settings.custom') }}--> 单位密码修改
<!-- </router-link>--> </router-link>
<!-- </a-menu-item>--> </a-menu-item>
<!-- <a-menu-item key="/account/settings/binding">--> <!-- <a-menu-item key="/account/settings/custom">-->
<!-- <router-link :to="{ name: 'binding' }">--> <!-- <router-link :to="{ name: 'custom' }">-->
<!-- {{ i18nRender('menu.account.settings.binding') }}--> <!-- {{ i18nRender('menu.account.settings.custom') }}-->
<!-- </router-link>--> <!-- </router-link>-->
<!-- </a-menu-item>--> <!-- </a-menu-item>-->
<!-- <a-menu-item key="/account/settings/notification">--> <!-- <a-menu-item key="/account/settings/binding">-->
<!-- <router-link :to="{ name: 'notification' }">--> <!-- <router-link :to="{ name: 'binding' }">-->
<!-- {{ i18nRender('menu.account.settings.notification') }}--> <!-- {{ i18nRender('menu.account.settings.binding') }}-->
<!-- </router-link>--> <!-- </router-link>-->
<!-- </a-menu-item>--> <!-- </a-menu-item>-->
<!-- <a-menu-item key="/account/settings/notification">-->
<!-- <router-link :to="{ name: 'notification' }">-->
<!-- {{ i18nRender('menu.account.settings.notification') }}-->
<!-- </router-link>-->
<!-- </a-menu-item>-->
</a-menu> </a-menu>
</div> </div>
<div class="account-settings-info-right"> <div class='account-settings-info-right'>
<div class="account-settings-info-title"> <div class='account-settings-info-title'>
<span>{{ i18nRender($route.meta.title) }}</span> <span>{{ i18nRender($route.meta.title) }}</span>
</div> </div>
<route-view></route-view> <route-view></route-view>
@ -52,6 +57,7 @@
import { RouteView } from '@/layouts' import { RouteView } from '@/layouts'
import { baseMixin } from '@/store/app-mixin' import { baseMixin } from '@/store/app-mixin'
import { i18nRender } from '@/locales' import { i18nRender } from '@/locales'
import { checkPermission } from '@/utils/permissions'
export default { export default {
components: { components: {
@ -59,7 +65,7 @@ export default {
i18nRender i18nRender
}, },
mixins: [baseMixin], mixins: [baseMixin],
data () { data() {
return { return {
// horizontal inline // horizontal inline
mode: 'inline', mode: 'inline',
@ -86,122 +92,127 @@ export default {
}, },
pageTitle: '', pageTitle: '',
base: 'base' base: 'base',
changePwd: checkPermission('system:profile:password')
} }
}, },
mounted () { mounted() {
this.updateMenu() this.updateMenu()
}, },
methods: { methods: {
onOpenChange (openKeys) { onOpenChange(openKeys) {
this.openKeys = openKeys this.openKeys = openKeys
}, },
updateMenu () { updateMenu() {
const routes = this.$route.matched.concat() const routes = this.$route.matched.concat()
this.selectedKeys = [ routes.pop().path ] this.selectedKeys = [routes.pop().path]
// console.log('selectedKeys', this.selectedKeys) // console.log('selectedKeys', this.selectedKeys)
}, },
i18nRender (key) { i18nRender(key) {
return i18nRender(key) return i18nRender(key)
} }
}, },
watch: { watch: {
'$route' (val) { '$route'(val) {
this.updateMenu() this.updateMenu()
} }
} }
} }
</script> </script>
<style lang="less" scoped> <style lang='less' scoped>
.account-settings-info-main { .account-settings-info-main {
width: 100%; width: 100%;
display: flex; display: flex;
height: 100%; height: 100%;
overflow: auto; overflow: auto;
&.mobile { &.mobile {
display: block; display: block;
.account-settings-info-left {
border-right: unset;
border-bottom: 1px solid #e8e8e8;
width: 100%;
height: 50px;
overflow-x: auto;
overflow-y: scroll;
}
.account-settings-info-right {
padding: 20px 40px;
}
}
.account-settings-info-left { .account-settings-info-left {
border-right: 1px solid #e8e8e8; border-right: unset;
width: 224px; border-bottom: 1px solid #e8e8e8;
width: 100%;
height: 50px;
overflow-x: auto;
overflow-y: scroll;
} }
.account-settings-info-right { .account-settings-info-right {
flex: 1 1; padding: 20px 40px;
padding: 8px 40px;
.account-settings-info-title {
color: rgba(0, 0, 0, 0.85);
font-size: 20px;
font-weight: 500;
line-height: 28px;
margin-bottom: 12px;
}
.account-settings-info-view {
padding-top: 12px;
}
} }
} }
</style> .account-settings-info-left {
<style lang="less" scoped> border-right: 1px solid #e8e8e8;
.account-settings-info-main { width: 224px;
width: 100%; }
display: flex;
height: 100%;
overflow: auto;
&.mobile { .account-settings-info-right {
display: block; flex: 1 1;
padding: 8px 40px;
.account-settings-info-left { .account-settings-info-title {
border-right: unset; color: rgba(0, 0, 0, 0.85);
border-bottom: 1px solid #e8e8e8; font-size: 20px;
width: 100%; font-weight: 500;
height: 50px; line-height: 28px;
overflow-x: auto; margin-bottom: 12px;
overflow-y: scroll;
}
.account-settings-info-right {
padding: 20px 40px;
}
} }
.account-settings-info-view {
padding-top: 12px;
}
}
}
</style>
<style lang='less' scoped>
.account-settings-info-main {
width: 100%;
display: flex;
height: 100%;
overflow: auto;
&.mobile {
display: block;
.account-settings-info-left { .account-settings-info-left {
border-right: 1px solid #e8e8e8; border-right: unset;
width: 224px; border-bottom: 1px solid #e8e8e8;
width: 100%;
height: 50px;
overflow-x: auto;
overflow-y: scroll;
} }
.account-settings-info-right { .account-settings-info-right {
flex: 1 1; padding: 20px 40px;
padding: 8px 40px;
.account-settings-info-title {
color: rgba(0,0,0,.85);
font-size: 20px;
font-weight: 500;
line-height: 28px;
margin-bottom: 12px;
}
.account-settings-info-view {
padding-top: 12px;
}
} }
} }
.account-settings-info-left {
border-right: 1px solid #e8e8e8;
width: 224px;
}
.account-settings-info-right {
flex: 1 1;
padding: 8px 40px;
.account-settings-info-title {
color: rgba(0, 0, 0, .85);
font-size: 20px;
font-weight: 500;
line-height: 28px;
margin-bottom: 12px;
}
.account-settings-info-view {
padding-top: 12px;
}
}
}
</style> </style>

View File

@ -1,29 +1,30 @@
<template> <template>
<div class="account-settings-info-view"> <div class='account-settings-info-view'>
<a-row :gutter="16"> <a-row :gutter='16'>
<a-col :md="24" :lg="16"> <a-col :md='24' :lg='16'>
<a-form @submit="handleSubmit" :form="form" layout="vertical"> <a-form @submit='handleSubmit' :form='form' layout='vertical'>
<a-form-item> <a-form-item>
<a-input-password placeholder="旧密码" v-decorator="['password', {rules: [{ required: true, message: '请选录入旧密码' }]}]"/> <a-input-password placeholder='旧密码'
v-decorator="['password', {rules: [{ required: true, message: '请选录入旧密码' }]}]" />
</a-form-item> </a-form-item>
<a-popover <a-popover
placement="rightTop" placement='rightTop'
:trigger="['focus']" :trigger="['focus']"
:getPopupContainer="(trigger) => trigger.parentElement" :getPopupContainer='(trigger) => trigger.parentElement'
v-model="state.passwordLevelChecked"> v-model='state.passwordLevelChecked'>
<template slot="content"> <template slot='content'>
<div :style="{ width: '240px' }" > <div :style="{ width: '240px' }">
<div :class="['user-register', passwordLevelClass]">强度<span>{{ passwordLevelName }}</span></div> <div :class="['user-register', passwordLevelClass]">强度<span>{{ passwordLevelName }}</span></div>
<a-progress :percent="state.percent" :showInfo="false" :strokeColor=" passwordLevelColor " /> <a-progress :percent='state.percent' :showInfo='false' :strokeColor=' passwordLevelColor ' />
<div style="margin-top: 10px;"> <div style='margin-top: 10px;'>
<span>请至少输入 6 个字符请不要使用容易被猜到的密码</span> <span>请至少输入 6 个字符请不要使用容易被猜到的密码</span>
</div> </div>
</div> </div>
</template> </template>
<a-form-item> <a-form-item>
<a-input-password <a-input-password
@click="handlePasswordInputClick" @click='handlePasswordInputClick'
placeholder="新密码至少6位密码区分大小写" placeholder='新密码至少6位密码区分大小写'
v-decorator="['newPassword', {rules: [{ required: true, message: '新密码至少6位密码区分大小写'}, { validator: this.handlePasswordLevel }], validateTrigger: ['change', 'blur']}]" v-decorator="['newPassword', {rules: [{ required: true, message: '新密码至少6位密码区分大小写'}, { validator: this.handlePasswordLevel }], validateTrigger: ['change', 'blur']}]"
></a-input-password> ></a-input-password>
</a-form-item> </a-form-item>
@ -31,12 +32,12 @@
<a-form-item> <a-form-item>
<a-input-password <a-input-password
placeholder="重复新密码" placeholder='重复新密码'
v-decorator="['rePassword', {rules: [{ required: true, message: '新密码至少6位密码区分大小写' }, { validator: this.handlePasswordCheck }], validateTrigger: ['change', 'blur']}]" v-decorator="['rePassword', {rules: [{ required: true, message: '新密码至少6位密码区分大小写' }, { validator: this.handlePasswordCheck }], validateTrigger: ['change', 'blur']}]"
></a-input-password> ></a-input-password>
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<a-button htmlType="submit" type="primary">修改密码</a-button> <a-button htmlType='submit' type='primary'>修改密码</a-button>
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-col> </a-col>
@ -46,6 +47,7 @@
<script> <script>
import { updataPassword } from '@/api/system' import { updataPassword } from '@/api/system'
import { checkPermission } from '@/utils/permissions'
const levelNames = { const levelNames = {
0: '低', 0: '低',
@ -67,29 +69,35 @@ const levelColor = {
} }
export default { export default {
data () { data() {
return { return {
state: { state: {
passwordLevel: 0, passwordLevel: 0,
passwordLevelChecked: false, passwordLevelChecked: false,
percent: 10 percent: 10
}, },
form: this.$form.createForm(this) form: this.$form.createForm(this),
changePwd: checkPermission('system:profile:password')
}
},
mounted() {
if (!this.changePwd) {
this.$router.push({ path: '/account/settings/depPwd' })
} }
}, },
computed: { computed: {
passwordLevelClass () { passwordLevelClass() {
return levelClass[this.state.passwordLevel] return levelClass[this.state.passwordLevel]
}, },
passwordLevelName () { passwordLevelName() {
return levelNames[this.state.passwordLevel] return levelNames[this.state.passwordLevel]
}, },
passwordLevelColor () { passwordLevelColor() {
return levelColor[this.state.passwordLevel] return levelColor[this.state.passwordLevel]
} }
}, },
methods: { methods: {
handlePasswordLevel (rule, value, callback) { handlePasswordLevel(rule, value, callback) {
let level = 0 let level = 0
// //
@ -118,7 +126,7 @@ export default {
callback(new Error('密码强度不够')) callback(new Error('密码强度不够'))
} }
}, },
handlePasswordCheck (rule, value, callback) { handlePasswordCheck(rule, value, callback) {
const password = this.form.getFieldValue('newPassword') const password = this.form.getFieldValue('newPassword')
if (value === undefined) { if (value === undefined) {
callback(new Error('请输入密码')) callback(new Error('请输入密码'))
@ -128,7 +136,7 @@ export default {
} }
callback() callback()
}, },
handlePasswordInputClick () { handlePasswordInputClick() {
if (!this.isMobile) { if (!this.isMobile) {
this.state.passwordLevelChecked = true this.state.passwordLevelChecked = true
return return
@ -136,7 +144,7 @@ export default {
this.state.passwordLevelChecked = false this.state.passwordLevelChecked = false
}, },
// handler // handler
handleSubmit (e) { handleSubmit(e) {
e.preventDefault() e.preventDefault()
this.form.validateFields((err, values) => { this.form.validateFields((err, values) => {
if (!err) { if (!err) {
@ -159,7 +167,7 @@ export default {
}) })
}, },
watch: { watch: {
'state.passwordLevel' (val) { 'state.passwordLevel'(val) {
console.log(val) console.log(val)
} }
} }

View File

@ -1,8 +1,8 @@
<template> <template>
<div class='main' style='text-align: center'> <div class='main' style='text-align: center'>
<vue-qr v-if='!isLogin' <vue-qr style='margin-top: 40px' v-if='!isLogin'
:text='loginUrl' :text='loginUrl'
:size='250' :size='200'
></vue-qr> ></vue-qr>
<a-button v-if='isLogin' @click='goIndex()' type="primary" style='margin-top: 20px'> <a-button v-if='isLogin' @click='goIndex()' type="primary" style='margin-top: 20px'>
访问系统 访问系统
@ -74,4 +74,17 @@ export default {
} }
} }
</script> </script>
<style>
#app {
/* 加载背景图 */
background-image: url(~@/assets/login-code-bg.jpg);
/* 背景图垂直、水平均居中 */
background-position: center center;
/* 背景图不平铺 */
background-repeat: no-repeat;
/* 当内容高度大于图片高度时背景图像的位置相对于viewport固定 */
background-attachment: fixed;
/* 让背景图基于容器大小伸缩 */
background-size: cover;
}
</style>