mirror of
https://github.com/continew-org/continew-admin-ui.git
synced 2025-09-10 18:58:37 +08:00
refactor: 优化个人中心部分代码
This commit is contained in:
@@ -8,7 +8,7 @@ export interface UserInfo {
|
|||||||
phone: string
|
phone: string
|
||||||
avatar: string
|
avatar: string
|
||||||
pwdResetTime: string
|
pwdResetTime: string
|
||||||
passwordExpired: boolean
|
pwdExpired: boolean
|
||||||
registrationDate: string
|
registrationDate: string
|
||||||
deptName: string
|
deptName: string
|
||||||
roles: string[]
|
roles: string[]
|
||||||
|
@@ -19,12 +19,12 @@ export function updateUserPassword(data: { oldPassword: string; newPassword: str
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @desc 修改手机号 */
|
/** @desc 修改手机号 */
|
||||||
export function updateUserPhone(data: { newPhone: string; captcha: string; currentPassword: string }) {
|
export function updateUserPhone(data: { phone: string; captcha: string; oldPassword: string }) {
|
||||||
return http.patch(`${BASE_URL}/phone`, data)
|
return http.patch(`${BASE_URL}/phone`, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @desc 修改邮箱 */
|
/** @desc 修改邮箱 */
|
||||||
export function updateUserEmail(data: { newEmail: string; captcha: string; currentPassword: string }) {
|
export function updateUserEmail(data: { email: string; captcha: string; oldPassword: string }) {
|
||||||
return http.patch(`${BASE_URL}/email`, data)
|
return http.patch(`${BASE_URL}/email`, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 846 B After Width: | Height: | Size: 846 B |
@@ -51,7 +51,7 @@
|
|||||||
</a-row>
|
</a-row>
|
||||||
<template #content>
|
<template #content>
|
||||||
<a-doption @click="router.push('/setting/profile')">
|
<a-doption @click="router.push('/setting/profile')">
|
||||||
<span>账号管理</span>
|
<span>个人中心</span>
|
||||||
</a-doption>
|
</a-doption>
|
||||||
<a-divider :margin="0" />
|
<a-divider :margin="0" />
|
||||||
<a-doption @click="logout">
|
<a-doption @click="logout">
|
||||||
@@ -98,16 +98,14 @@ const logout = () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
|
||||||
checkPasswordExpired()
|
|
||||||
})
|
|
||||||
const checkPasswordExpired = () => {
|
const checkPasswordExpired = () => {
|
||||||
if (!userStore.passwordExpiredShow || !userStore.userInfo.passwordExpired) {
|
if (!userStore.pwdExpiredShow || !userStore.userInfo.pwdExpired) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: '提示',
|
title: '提示',
|
||||||
content: '密码已过期,是否去修改?',
|
content: '密码已过期,需要跳转到修改密码页面?',
|
||||||
hideCancel: false,
|
hideCancel: false,
|
||||||
closable: true,
|
closable: true,
|
||||||
onBeforeOk: async () => {
|
onBeforeOk: async () => {
|
||||||
@@ -120,10 +118,14 @@ const checkPasswordExpired = () => {
|
|||||||
},
|
},
|
||||||
onCancel: () => {
|
onCancel: () => {
|
||||||
// 当前登录会话不再提示
|
// 当前登录会话不再提示
|
||||||
userStore.passwordExpiredShow = false
|
userStore.pwdExpiredShow = false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
checkPasswordExpired()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@@ -61,7 +61,7 @@ export const constantRoutes: RouteRecordRaw[] = [
|
|||||||
path: '/setting/profile',
|
path: '/setting/profile',
|
||||||
name: 'SettingProfile',
|
name: 'SettingProfile',
|
||||||
component: () => import('@/views/setting/profile/index.vue'),
|
component: () => import('@/views/setting/profile/index.vue'),
|
||||||
meta: { title: '账号管理', showInTabs: false }
|
meta: { title: '个人中心', showInTabs: false }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@@ -27,7 +27,7 @@ const storeSetup = () => {
|
|||||||
phone: '',
|
phone: '',
|
||||||
avatar: '',
|
avatar: '',
|
||||||
pwdResetTime: '',
|
pwdResetTime: '',
|
||||||
passwordExpired: false,
|
pwdExpired: false,
|
||||||
registrationDate: '',
|
registrationDate: '',
|
||||||
deptName: '',
|
deptName: '',
|
||||||
roles: [],
|
roles: [],
|
||||||
@@ -37,7 +37,7 @@ const storeSetup = () => {
|
|||||||
const avatar = computed(() => userInfo.avatar)
|
const avatar = computed(() => userInfo.avatar)
|
||||||
|
|
||||||
const token = ref(getToken() || '')
|
const token = ref(getToken() || '')
|
||||||
const passwordExpiredShow = ref<boolean>(true)
|
const pwdExpiredShow = ref<boolean>(true)
|
||||||
const roles = ref<string[]>([]) // 当前用户角色
|
const roles = ref<string[]>([]) // 当前用户角色
|
||||||
const permissions = ref<string[]>([]) // 当前角色权限标识集合
|
const permissions = ref<string[]>([]) // 当前角色权限标识集合
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ const storeSetup = () => {
|
|||||||
const logoutCallBack = async () => {
|
const logoutCallBack = async () => {
|
||||||
roles.value = []
|
roles.value = []
|
||||||
permissions.value = []
|
permissions.value = []
|
||||||
passwordExpiredShow.value = true
|
pwdExpiredShow.value = true
|
||||||
resetToken()
|
resetToken()
|
||||||
resetRouter()
|
resetRouter()
|
||||||
}
|
}
|
||||||
@@ -114,7 +114,7 @@ const storeSetup = () => {
|
|||||||
token,
|
token,
|
||||||
roles,
|
roles,
|
||||||
permissions,
|
permissions,
|
||||||
passwordExpiredShow,
|
pwdExpiredShow,
|
||||||
accountLogin,
|
accountLogin,
|
||||||
emailLogin,
|
emailLogin,
|
||||||
phoneLogin,
|
phoneLogin,
|
||||||
@@ -127,5 +127,5 @@ const storeSetup = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const useUserStore = defineStore('user', storeSetup, {
|
export const useUserStore = defineStore('user', storeSetup, {
|
||||||
persist: { paths: ['token', 'roles', 'permissions', 'passwordExpiredShow'], storage: localStorage }
|
persist: { paths: ['token', 'roles', 'permissions', 'pwdExpiredShow'], storage: localStorage }
|
||||||
})
|
})
|
||||||
|
@@ -19,15 +19,21 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// import { getSmsCaptcha, getEmailCaptcha, updateUserEmail, updateUserPhone } from '@/apis'
|
// import { getSmsCaptcha, getEmailCaptcha, updateUserEmail, updateUserPhone } from '@/apis'
|
||||||
|
import { updateUserPassword } from '@/apis'
|
||||||
import { Message } from '@arco-design/web-vue'
|
import { Message } from '@arco-design/web-vue'
|
||||||
// import { encryptByRsa } from '@/utils/encrypt'
|
import { encryptByRsa } from '@/utils/encrypt'
|
||||||
import { useUserStore } from '@/stores'
|
import { useUserStore } from '@/stores'
|
||||||
import { type Columns, GiForm } from '@/components/GiForm'
|
import { type Columns, GiForm } from '@/components/GiForm'
|
||||||
import { useForm } from '@/hooks'
|
import { useForm } from '@/hooks'
|
||||||
import * as Regexp from '@/utils/regexp'
|
import * as Regexp from '@/utils/regexp'
|
||||||
|
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const userInfo = computed(() => userStore.userInfo)
|
||||||
|
|
||||||
const verifyType = ref()
|
const verifyType = ref()
|
||||||
const title = computed(() => (verifyType.value === 'phone' ? '修改手机号' : '修改邮箱'))
|
const title = computed(
|
||||||
|
() => `修改${verifyType.value === 'phone' ? '手机号' : verifyType.value === 'email' ? '邮箱' : '密码'}`
|
||||||
|
)
|
||||||
const formRef = ref<InstanceType<typeof GiForm>>()
|
const formRef = ref<InstanceType<typeof GiForm>>()
|
||||||
|
|
||||||
const options: Options = {
|
const options: Options = {
|
||||||
@@ -39,7 +45,7 @@ const options: Options = {
|
|||||||
const columns: Columns = [
|
const columns: Columns = [
|
||||||
{
|
{
|
||||||
label: '手机号',
|
label: '手机号',
|
||||||
field: 'newPhone',
|
field: 'phone',
|
||||||
type: 'input',
|
type: 'input',
|
||||||
rules: [
|
rules: [
|
||||||
{ required: true, message: '请输入手机号' },
|
{ required: true, message: '请输入手机号' },
|
||||||
@@ -65,21 +71,50 @@ const columns: Columns = [
|
|||||||
label: '验证码',
|
label: '验证码',
|
||||||
field: 'captcha',
|
field: 'captcha',
|
||||||
type: 'input',
|
type: 'input',
|
||||||
rules: [{ required: true, message: '请输入验证码' }]
|
rules: [{ required: true, message: '请输入验证码' }],
|
||||||
|
hide: () => {
|
||||||
|
return !['phone', 'email'].includes(verifyType.value)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '当前密码',
|
label: '当前密码',
|
||||||
field: 'currentPassword',
|
field: 'oldPassword',
|
||||||
type: 'input',
|
type: 'input-password',
|
||||||
rules: [{ required: true, message: '请输入当前密码' }]
|
rules: [{ required: true, message: '请输入当前密码' }],
|
||||||
|
hide: () => {
|
||||||
|
return !userInfo.value.pwdResetTime
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '新密码',
|
||||||
|
field: 'newPassword',
|
||||||
|
type: 'input-password',
|
||||||
|
rules: [{ required: true, message: '请输入新密码' }],
|
||||||
|
hide: () => {
|
||||||
|
return verifyType.value !== 'password'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '确认新密码',
|
||||||
|
field: 'rePassword',
|
||||||
|
type: 'input-password',
|
||||||
|
rules: [{ required: true, message: '请再次输入新密码' }],
|
||||||
|
props: {
|
||||||
|
placeholder: '请再次输入新密码'
|
||||||
|
},
|
||||||
|
hide: () => {
|
||||||
|
return verifyType.value !== 'password'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const { form, resetForm } = useForm({
|
const { form, resetForm } = useForm({
|
||||||
newPhone: '',
|
phone: '',
|
||||||
|
email: '',
|
||||||
captcha: '',
|
captcha: '',
|
||||||
currentPassword: '',
|
oldPassword: '',
|
||||||
email: ''
|
newPassword: '',
|
||||||
|
rePassword: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
// 重置
|
// 重置
|
||||||
@@ -112,7 +147,7 @@ const onCaptcha = async () => {
|
|||||||
captchaBtnName.value = '发送中...'
|
captchaBtnName.value = '发送中...'
|
||||||
if (verifyType.value === 'phone') {
|
if (verifyType.value === 'phone') {
|
||||||
// await getSmsCaptcha({
|
// await getSmsCaptcha({
|
||||||
// phone: form.newPhone
|
// phone: form.phone
|
||||||
// })
|
// })
|
||||||
} else if (verifyType.value === 'email') {
|
} else if (verifyType.value === 'email') {
|
||||||
// await getEmailCaptcha({
|
// await getEmailCaptcha({
|
||||||
@@ -138,24 +173,36 @@ const onCaptcha = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const userStore = useUserStore()
|
|
||||||
// 保存
|
// 保存
|
||||||
const save = async () => {
|
const save = async () => {
|
||||||
const isInvalid = await formRef.value?.formRef?.validate()
|
const isInvalid = await formRef.value?.formRef?.validate()
|
||||||
if (isInvalid) return false
|
if (isInvalid) return false
|
||||||
try {
|
try {
|
||||||
if (verifyType.value === 'phone') {
|
if (verifyType.value === 'phone') {
|
||||||
// await updateUserEmail({
|
// await updateUserPhone({
|
||||||
// newEmail: form.email,
|
// phone: form.phone,
|
||||||
// captcha: form.captcha,
|
// captcha: form.captcha,
|
||||||
// currentPassword: encryptByRsa(form.currentPassword) as string
|
// oldPassword: encryptByRsa(form.oldPassword) as string
|
||||||
// })
|
// })
|
||||||
} else if (verifyType.value === 'email') {
|
} else if (verifyType.value === 'email') {
|
||||||
// await updateUserPhone({
|
// await updateUserEmail({
|
||||||
// newPhone: form.email,
|
// email: form.email,
|
||||||
// captcha: form.captcha,
|
// captcha: form.captcha,
|
||||||
// currentPassword: encryptByRsa(form.currentPassword) as string
|
// oldPassword: encryptByRsa(form.oldPassword) as string
|
||||||
// })
|
// })
|
||||||
|
} else if (verifyType.value === 'password') {
|
||||||
|
if (form.newPassword !== form.rePassword) {
|
||||||
|
Message.error('两次新密码不一致')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (form.newPassword === form.oldPassword) {
|
||||||
|
Message.error('新密码与旧密码不能相同')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
await updateUserPassword({
|
||||||
|
oldPassword: encryptByRsa(form.oldPassword) || '',
|
||||||
|
newPassword: encryptByRsa(form.newPassword) || ''
|
||||||
|
})
|
||||||
}
|
}
|
||||||
Message.success('修改成功')
|
Message.success('修改成功')
|
||||||
// 修改成功后,重新获取用户信息
|
// 修改成功后,重新获取用户信息
|
||||||
|
@@ -1,178 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a-card title="密码策略" bordered class="gradient-card">
|
|
||||||
<div class="item">
|
|
||||||
<div class="icon-wrapper"><GiSvgIcon name="password" :size="26" /></div>
|
|
||||||
<div class="info">
|
|
||||||
<div class="info-top">
|
|
||||||
<span class="label">登录密码</span>
|
|
||||||
</div>
|
|
||||||
<div class="info-desc">为了您的账号安全,建议定期修改密码</div>
|
|
||||||
</div>
|
|
||||||
<div class="btn-wrapper">
|
|
||||||
<a-button class="btn" @click="onUpdate">修改</a-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="detail">
|
|
||||||
<div class="sub-text-wrapper">
|
|
||||||
<div class="sub-text">
|
|
||||||
密码至少包含
|
|
||||||
<span class="sub-text-value">大写字母</span>
|
|
||||||
<span class="sub-text-value">小写字母</span>
|
|
||||||
<span class="sub-text-value">数字</span>
|
|
||||||
<span class="sub-text-value" v-if="securityConfig.password_special_char.value == 1">特殊字符</span>
|
|
||||||
</div>
|
|
||||||
<div class="sub-text" v-if="securityConfig.password_contain_name.value == 1">
|
|
||||||
密码不能包含<span class="sub-text-value">正反序用户名</span>
|
|
||||||
</div>
|
|
||||||
<div class="sub-text">
|
|
||||||
密码长度至少
|
|
||||||
<span class="sub-text-value">
|
|
||||||
{{ securityConfig.password_min_length.value }}
|
|
||||||
</span>
|
|
||||||
位
|
|
||||||
</div>
|
|
||||||
<div class="sub-text">
|
|
||||||
<div v-if="securityConfig.password_expiration_days.value == 0">未设置密码有效期</div>
|
|
||||||
<div v-else>
|
|
||||||
密码有效期
|
|
||||||
<span class="sub-text-value">
|
|
||||||
{{ securityConfig.password_expiration_days.value }}
|
|
||||||
</span>
|
|
||||||
天
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="sub-text">
|
|
||||||
连续密码错误可重试
|
|
||||||
<span class="sub-text-value">
|
|
||||||
{{ securityConfig.password_error_count.value }}
|
|
||||||
</span>
|
|
||||||
次
|
|
||||||
</div>
|
|
||||||
<div class="sub-text">
|
|
||||||
超过错误密码重试次数账号将被锁定
|
|
||||||
<span class="sub-text-value">
|
|
||||||
{{ securityConfig.password_lock_minutes.value }}
|
|
||||||
</span>
|
|
||||||
分钟
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-card>
|
|
||||||
|
|
||||||
<a-modal v-model:visible="visible" title="修改密码" @before-ok="save" @close="reset">
|
|
||||||
<GiForm ref="formRef" v-model="form" :options="options" :columns="columns" />
|
|
||||||
</a-modal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { listOption, type OptionResp, type SecurityConfigResp, updateUserPassword } from '@/apis'
|
|
||||||
import { Message } from '@arco-design/web-vue'
|
|
||||||
import { encryptByRsa } from '@/utils/encrypt'
|
|
||||||
import { type Columns, GiForm } from '@/components/GiForm'
|
|
||||||
import { useForm } from '@/hooks'
|
|
||||||
import { useUserStore } from '@/stores'
|
|
||||||
|
|
||||||
const userStore = useUserStore()
|
|
||||||
const userInfo = computed(() => userStore.userInfo)
|
|
||||||
const formRef = ref<InstanceType<typeof GiForm>>()
|
|
||||||
|
|
||||||
const options: Options = {
|
|
||||||
form: {},
|
|
||||||
col: { xs: 24, sm: 24, md: 24, lg: 24, xl: 24, xxl: 24 },
|
|
||||||
btns: { hide: true }
|
|
||||||
}
|
|
||||||
|
|
||||||
const columns: Columns = [
|
|
||||||
{
|
|
||||||
label: '当前密码',
|
|
||||||
field: 'oldPassword',
|
|
||||||
type: 'input-password',
|
|
||||||
rules: [{ required: true, message: '密码长度不正确', maxLength: 32, minLength: 6 }],
|
|
||||||
hide: () => {
|
|
||||||
return userInfo.pwdResetTime
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '新密码',
|
|
||||||
field: 'newPassword',
|
|
||||||
type: 'input-password',
|
|
||||||
rules: [{ required: true, message: '密码长度不正确', maxLength: 32, minLength: 6 }]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '确认新密码',
|
|
||||||
field: 'rePassword',
|
|
||||||
type: 'input-password',
|
|
||||||
rules: [{ required: true, message: '密码长度不正确', maxLength: 32, minLength: 6 }],
|
|
||||||
props: {
|
|
||||||
placeholder: '请再次输入新密码'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const { form, resetForm } = useForm({
|
|
||||||
oldPassword: '',
|
|
||||||
newPassword: '',
|
|
||||||
rePassword: ''
|
|
||||||
})
|
|
||||||
|
|
||||||
// 重置
|
|
||||||
const reset = () => {
|
|
||||||
formRef.value?.formRef?.resetFields()
|
|
||||||
resetForm()
|
|
||||||
}
|
|
||||||
|
|
||||||
const visible = ref(false)
|
|
||||||
// 修改
|
|
||||||
const onUpdate = async () => {
|
|
||||||
reset()
|
|
||||||
visible.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存
|
|
||||||
const save = async () => {
|
|
||||||
const isInvalid = await formRef.value?.formRef?.validate()
|
|
||||||
if (isInvalid) return false
|
|
||||||
if (form.newPassword !== form.rePassword) {
|
|
||||||
Message.error('两次新密码不一致')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (form.newPassword === form.oldPassword) {
|
|
||||||
Message.error('新密码与旧密码不能相同')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
await updateUserPassword({
|
|
||||||
oldPassword: encryptByRsa(form.oldPassword) || '',
|
|
||||||
newPassword: encryptByRsa(form.newPassword) || ''
|
|
||||||
})
|
|
||||||
Message.success('修改成功')
|
|
||||||
return true
|
|
||||||
} catch (error) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const securityConfig = ref<SecurityConfigResp>({
|
|
||||||
password_contain_name: {},
|
|
||||||
password_error_count: {},
|
|
||||||
password_expiration_days: {},
|
|
||||||
password_lock_minutes: {},
|
|
||||||
password_min_length: {},
|
|
||||||
password_special_char: {},
|
|
||||||
password_update_interval: {}
|
|
||||||
})
|
|
||||||
|
|
||||||
// 查询列表数据
|
|
||||||
const getDataList = async () => {
|
|
||||||
const { data } = await listOption({ code: Object.keys(securityConfig.value) })
|
|
||||||
securityConfig.value = data.reduce((obj: SecurityConfigResp, option: OptionResp) => {
|
|
||||||
obj[option.code] = { ...option, value: parseInt(option.value) }
|
|
||||||
return obj
|
|
||||||
}, {})
|
|
||||||
}
|
|
||||||
onMounted(() => {
|
|
||||||
getDataList()
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
|
109
src/views/setting/profile/Security.vue
Normal file
109
src/views/setting/profile/Security.vue
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
<template>
|
||||||
|
<a-card title="安全设置" bordered class="gradient-card">
|
||||||
|
<div v-for="item in modeList" :key="item.title">
|
||||||
|
<div class="item">
|
||||||
|
<div class="icon-wrapper"><GiSvgIcon :name="item.icon" :size="26" /></div>
|
||||||
|
<div class="info">
|
||||||
|
<div class="info-top">
|
||||||
|
<span class="label">{{ item.title }}</span>
|
||||||
|
<span class="bind">
|
||||||
|
<icon-check-circle-fill v-if="item.status" :size="14" class="success" />
|
||||||
|
<icon-exclamation-circle-fill v-else :size="14" class="warning" />
|
||||||
|
<span style="font-size: 12px" :class="item.status ? 'success' : 'warning'">{{ item.statusString }}</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-desc">
|
||||||
|
<span class="value">{{ item.value }}</span>
|
||||||
|
{{ item.subtitle }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="btn-wrapper">
|
||||||
|
<a-button
|
||||||
|
v-if="item.jumpMode == 'modal'"
|
||||||
|
class="btn"
|
||||||
|
:type="item.status ? 'secondary' : 'primary'"
|
||||||
|
@click="onUpdate(item.type, item.status)"
|
||||||
|
>
|
||||||
|
{{ ['password'].includes(item.type) || item.status ? '修改' : '绑定' }}
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
|
||||||
|
<VerifyModel ref="verifyModelRef" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { listOption, type OptionResp, type SecurityConfigResp } from '@/apis'
|
||||||
|
import type { ModeItem } from '../type'
|
||||||
|
import VerifyModel from '../components/VerifyModel.vue'
|
||||||
|
import { useUserStore } from '@/stores'
|
||||||
|
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const userInfo = computed(() => userStore.userInfo)
|
||||||
|
|
||||||
|
const modeList = ref<ModeItem[]>([])
|
||||||
|
modeList.value = [
|
||||||
|
{
|
||||||
|
title: '安全手机',
|
||||||
|
icon: 'phone-color',
|
||||||
|
value: `${userInfo.value.phone + ' ' || '手机号'}`,
|
||||||
|
subtitle: `可用于身份验证、密码找回、通知接收`,
|
||||||
|
type: 'phone',
|
||||||
|
jumpMode: 'modal',
|
||||||
|
status: !!userInfo.value.phone,
|
||||||
|
statusString: userInfo.value.phone ? '已绑定' : '未绑定'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '安全邮箱',
|
||||||
|
icon: 'email-color',
|
||||||
|
value: `${userInfo.value.email + ' ' || '邮箱'}`,
|
||||||
|
subtitle: `可用于身份验证、密码找回、通知接收`,
|
||||||
|
type: 'email',
|
||||||
|
jumpMode: 'modal',
|
||||||
|
status: !!userInfo.value.email,
|
||||||
|
statusString: userInfo.value.email ? '已绑定' : '未绑定'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '登录密码',
|
||||||
|
icon: 'password-color',
|
||||||
|
subtitle: userInfo.value.pwdResetTime ? `为了您的账号安全,建议定期修改密码` : '请设置密码,可通过账号+密码登录',
|
||||||
|
type: 'password',
|
||||||
|
jumpMode: 'modal',
|
||||||
|
status: !!userInfo.value.pwdResetTime,
|
||||||
|
statusString: userInfo.value.pwdResetTime ? '已设置' : '未设置'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const verifyModelRef = ref<InstanceType<typeof VerifyModel>>()
|
||||||
|
// 修改
|
||||||
|
const onUpdate = (type: string) => {
|
||||||
|
verifyModelRef.value?.open(type)
|
||||||
|
}
|
||||||
|
|
||||||
|
const securityConfig = ref<SecurityConfigResp>({
|
||||||
|
password_contain_name: {},
|
||||||
|
password_error_count: {},
|
||||||
|
password_expiration_days: {},
|
||||||
|
password_lock_minutes: {},
|
||||||
|
password_min_length: {},
|
||||||
|
password_special_char: {},
|
||||||
|
password_update_interval: {}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 查询列表数据
|
||||||
|
const getDataList = async () => {
|
||||||
|
const { data } = await listOption({ code: Object.keys(securityConfig.value) })
|
||||||
|
securityConfig.value = data.reduce((obj: SecurityConfigResp, option: OptionResp) => {
|
||||||
|
obj[option.code] = { ...option, value: parseInt(option.value) }
|
||||||
|
return obj
|
||||||
|
}, {})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getDataList()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-card title="登录方式" bordered class="gradient-card">
|
<a-card title="第三方账号" bordered class="gradient-card">
|
||||||
<div v-for="item in modeList" :key="item.title">
|
<div v-for="item in modeList" :key="item.title">
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<div class="icon-wrapper"><GiSvgIcon :name="item.icon" :size="26" /></div>
|
<div class="icon-wrapper"><GiSvgIcon :name="item.icon" :size="26" /></div>
|
||||||
@@ -55,24 +55,6 @@ const userInfo = computed(() => userStore.userInfo)
|
|||||||
const socialList = ref<any>([])
|
const socialList = ref<any>([])
|
||||||
const modeList = ref<ModeItem[]>([])
|
const modeList = ref<ModeItem[]>([])
|
||||||
modeList.value = [
|
modeList.value = [
|
||||||
{
|
|
||||||
title: '绑定手机',
|
|
||||||
icon: 'phone-color',
|
|
||||||
value: `${userInfo.value.phone + ' ' || '绑定后,'}`,
|
|
||||||
subtitle: `可通过手机验证码快捷登录`,
|
|
||||||
type: 'phone',
|
|
||||||
jumpMode: 'modal',
|
|
||||||
status: !!userInfo.value.phone
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '绑定邮箱',
|
|
||||||
icon: 'email-color',
|
|
||||||
value: `${userInfo.value.email + ' ' || '绑定后,'}`,
|
|
||||||
subtitle: `可通过邮箱验证码进行登录`,
|
|
||||||
type: 'email',
|
|
||||||
jumpMode: 'modal',
|
|
||||||
status: !!userInfo.value.email
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: '绑定 Gitee',
|
title: '绑定 Gitee',
|
||||||
icon: 'gitee',
|
icon: 'gitee',
|
@@ -17,9 +17,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import LeftBox from './LeftBox.vue'
|
import LeftBox from './BasicInfo.vue'
|
||||||
import RightBox from './RightBox.vue'
|
import RightBox from './Social.vue'
|
||||||
import PasswordPolicy from './PasswordPolicy.vue'
|
import PasswordPolicy from './Security.vue'
|
||||||
|
|
||||||
defineOptions({ name: 'SettingProfile' })
|
defineOptions({ name: 'SettingProfile' })
|
||||||
</script>
|
</script>
|
||||||
|
@@ -6,4 +6,5 @@ export interface ModeItem {
|
|||||||
type: 'phone' | 'email' | 'gitee' | 'github'
|
type: 'phone' | 'email' | 'gitee' | 'github'
|
||||||
jumpMode?: 'link' | 'modal'
|
jumpMode?: 'link' | 'modal'
|
||||||
status: boolean
|
status: boolean
|
||||||
|
statusString: string
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user