refactor: 优化账号管理
61
pnpm-lock.yaml
generated
@@ -63,8 +63,8 @@ dependencies:
|
||||
specifier: ^4.17.21
|
||||
version: 4.17.21
|
||||
md-editor-v3:
|
||||
specifier: ^4.6.2
|
||||
version: 4.12.1(@codemirror/view@6.26.0)(@lezer/common@1.2.1)(vue@3.4.21)
|
||||
specifier: ^4.13.4
|
||||
version: 4.13.4(@codemirror/view@6.26.0)(@lezer/common@1.2.1)(vue@3.4.21)
|
||||
mitt:
|
||||
specifier: ^3.0.0
|
||||
version: 3.0.1
|
||||
@@ -619,6 +619,18 @@ packages:
|
||||
- '@codemirror/view'
|
||||
dev: false
|
||||
|
||||
/@codemirror/lang-go@6.0.0(@codemirror/view@6.26.0):
|
||||
resolution: {integrity: sha512-mMT4YeYdKGjnffDBOhr1ur1glee4oV/rfMe28vzazNHZkSt7vSiuHiBcgr3L/79Cl2RIjFdpQ1XMD0/T8Rx64g==}
|
||||
dependencies:
|
||||
'@codemirror/autocomplete': 6.15.0(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.0)(@lezer/common@1.2.1)
|
||||
'@codemirror/language': 6.10.1
|
||||
'@codemirror/state': 6.4.1
|
||||
'@lezer/common': 1.2.1
|
||||
'@lezer/go': 1.0.0
|
||||
transitivePeerDependencies:
|
||||
- '@codemirror/view'
|
||||
dev: false
|
||||
|
||||
/@codemirror/lang-html@6.4.8:
|
||||
resolution: {integrity: sha512-tE2YK7wDlb9ZpAH6mpTPiYm6rhfdQKVDa5r9IwIFlwwgvVaKsCfuKKZoJGWsmMZIf3FQAuJ5CHMPLymOtg1hXw==}
|
||||
dependencies:
|
||||
@@ -684,8 +696,8 @@ packages:
|
||||
'@lezer/lr': 1.4.0
|
||||
dev: false
|
||||
|
||||
/@codemirror/lang-markdown@6.2.4:
|
||||
resolution: {integrity: sha512-UghkA1vSMs8bT7RSZM6vsIocigyah2bV00eRQuZy76401UmFZdsTsbQNBGdyxRQDOLeEvF5iFwap0BM8LKyd+g==}
|
||||
/@codemirror/lang-markdown@6.2.5:
|
||||
resolution: {integrity: sha512-Hgke565YcO4fd9pe2uLYxnMufHO5rQwRr+AAhFq8ABuhkrjyX8R5p5s+hZUTdV60O0dMRjxKhBLxz8pu/MkUVA==}
|
||||
dependencies:
|
||||
'@codemirror/autocomplete': 6.15.0(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.0)(@lezer/common@1.2.1)
|
||||
'@codemirror/lang-html': 6.4.8
|
||||
@@ -793,19 +805,20 @@ packages:
|
||||
- '@codemirror/view'
|
||||
dev: false
|
||||
|
||||
/@codemirror/language-data@6.4.1(@codemirror/view@6.26.0):
|
||||
resolution: {integrity: sha512-NYhC3NvEMwUxSWS1sB5AePUtr5g2ASSYOZ37YixicDG8PWHslDV9mmXIX0KvmtEm50V8FT4F5i4HAsk/7i78LA==}
|
||||
/@codemirror/language-data@6.5.1(@codemirror/view@6.26.0):
|
||||
resolution: {integrity: sha512-0sWxeUSNlBr6OmkqybUTImADFUP0M3P0IiSde4nc24bz/6jIYzqYSgkOSLS+CBIoW1vU8Q9KUWXscBXeoMVC9w==}
|
||||
dependencies:
|
||||
'@codemirror/lang-angular': 0.1.3
|
||||
'@codemirror/lang-cpp': 6.0.2
|
||||
'@codemirror/lang-css': 6.2.1(@codemirror/view@6.26.0)
|
||||
'@codemirror/lang-go': 6.0.0(@codemirror/view@6.26.0)
|
||||
'@codemirror/lang-html': 6.4.8
|
||||
'@codemirror/lang-java': 6.0.1
|
||||
'@codemirror/lang-javascript': 6.2.2
|
||||
'@codemirror/lang-json': 6.0.1
|
||||
'@codemirror/lang-less': 6.0.2(@codemirror/view@6.26.0)
|
||||
'@codemirror/lang-liquid': 6.2.1
|
||||
'@codemirror/lang-markdown': 6.2.4
|
||||
'@codemirror/lang-markdown': 6.2.5
|
||||
'@codemirror/lang-php': 6.0.1
|
||||
'@codemirror/lang-python': 6.1.4(@codemirror/view@6.26.0)
|
||||
'@codemirror/lang-rust': 6.0.1
|
||||
@@ -816,7 +829,7 @@ packages:
|
||||
'@codemirror/lang-xml': 6.1.0
|
||||
'@codemirror/lang-yaml': 6.0.0(@codemirror/view@6.26.0)
|
||||
'@codemirror/language': 6.10.1
|
||||
'@codemirror/legacy-modes': 6.3.3
|
||||
'@codemirror/legacy-modes': 6.4.0
|
||||
transitivePeerDependencies:
|
||||
- '@codemirror/view'
|
||||
dev: false
|
||||
@@ -832,8 +845,8 @@ packages:
|
||||
style-mod: 4.1.2
|
||||
dev: false
|
||||
|
||||
/@codemirror/legacy-modes@6.3.3:
|
||||
resolution: {integrity: sha512-X0Z48odJ0KIoh/HY8Ltz75/4tDYc9msQf1E/2trlxFaFFhgjpVHjZ/BCXe1Lk7s4Gd67LL/CeEEHNI+xHOiESg==}
|
||||
/@codemirror/legacy-modes@6.4.0:
|
||||
resolution: {integrity: sha512-5m/K+1A6gYR0e+h/dEde7LoGimMjRtWXZFg4Lo70cc8HzjSdHe3fLwjWMR0VRl5KFT1SxalSap7uMgPKF28wBA==}
|
||||
dependencies:
|
||||
'@codemirror/language': 6.10.1
|
||||
dev: false
|
||||
@@ -1186,6 +1199,14 @@ packages:
|
||||
'@lezer/lr': 1.4.0
|
||||
dev: false
|
||||
|
||||
/@lezer/go@1.0.0:
|
||||
resolution: {integrity: sha512-co9JfT3QqX1YkrMmourYw2Z8meGC50Ko4d54QEcQbEYpvdUvN4yb0NBZdn/9ertgvjsySxHsKzH3lbm3vqJ4Jw==}
|
||||
dependencies:
|
||||
'@lezer/common': 1.2.1
|
||||
'@lezer/highlight': 1.2.0
|
||||
'@lezer/lr': 1.4.0
|
||||
dev: false
|
||||
|
||||
/@lezer/highlight@1.2.0:
|
||||
resolution: {integrity: sha512-WrS5Mw51sGrpqjlh3d4/fOwpEV2Hd3YOkp9DBt4k8XZQcoTHZFB7sx030A6OcahF4J1nDQAa3jXlTVVYH50IFA==}
|
||||
dependencies:
|
||||
@@ -1477,8 +1498,8 @@ packages:
|
||||
resolution: {integrity: sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==}
|
||||
dev: true
|
||||
|
||||
/@types/markdown-it@13.0.7:
|
||||
resolution: {integrity: sha512-U/CBi2YUUcTHBt5tjO2r5QV/x0Po6nsYwQU4Y04fBS6vfoImaiZ6f8bi3CjTCxBPQSO1LMyUqkByzi8AidyxfA==}
|
||||
/@types/markdown-it@14.0.1:
|
||||
resolution: {integrity: sha512-6WfOG3jXR78DW8L5cTYCVVGAsIFZskRHCDo5tbqa+qtKVt4oDRVH7hyIWu1SpDQJlmIoEivNQZ5h+AGAOrgOtQ==}
|
||||
dependencies:
|
||||
'@types/linkify-it': 3.0.5
|
||||
'@types/mdurl': 1.0.5
|
||||
@@ -1696,8 +1717,8 @@ packages:
|
||||
nanoid: 3.3.7
|
||||
dev: false
|
||||
|
||||
/@vavt/util@1.5.0:
|
||||
resolution: {integrity: sha512-GJ3q7yJp4mjVVjT1PgbyayJu8q6dYpS0H2ojIcd3k7fEyG4sZhjepjmtA12J1n8Cs5HtkHtqdewCH4U5owytQw==}
|
||||
/@vavt/util@1.5.1:
|
||||
resolution: {integrity: sha512-/q/ilzRwZZJlnDAl6DGZ8pinOSAjR91dcck79bi1ujrqYlPaFVHnbmkDeGPuLub6A821rXvtPXVRXULrfMN03Q==}
|
||||
dev: false
|
||||
|
||||
/@vitejs/plugin-vue-jsx@3.1.0(vite@5.1.6)(vue@3.4.21):
|
||||
@@ -4584,15 +4605,15 @@ packages:
|
||||
uc.micro: 2.1.0
|
||||
dev: false
|
||||
|
||||
/md-editor-v3@4.12.1(@codemirror/view@6.26.0)(@lezer/common@1.2.1)(vue@3.4.21):
|
||||
resolution: {integrity: sha512-TbGsqWTnKQkQWnm1oAGm8yH+OD5zHTa49Um6WMcS+Y+M4fLl0gWZbz7NzeyOPtrEU13NlPY6c3IZcWAwdmZdiA==}
|
||||
/md-editor-v3@4.13.4(@codemirror/view@6.26.0)(@lezer/common@1.2.1)(vue@3.4.21):
|
||||
resolution: {integrity: sha512-Db53oV0Ei7s8orNkDOK+nsemqINf0cdY6aAjVOIX4ze+vCTVIdjq4To/6TbIcXPdRIaTcBYFHkP6uV+z0dnWXw==}
|
||||
peerDependencies:
|
||||
vue: ^3.2.47
|
||||
dependencies:
|
||||
'@codemirror/lang-markdown': 6.2.4
|
||||
'@codemirror/language-data': 6.4.1(@codemirror/view@6.26.0)
|
||||
'@types/markdown-it': 13.0.7
|
||||
'@vavt/util': 1.5.0
|
||||
'@codemirror/lang-markdown': 6.2.5
|
||||
'@codemirror/language-data': 6.5.1(@codemirror/view@6.26.0)
|
||||
'@types/markdown-it': 14.0.1
|
||||
'@vavt/util': 1.5.1
|
||||
codemirror: 6.0.1(@lezer/common@1.2.1)
|
||||
copy-to-clipboard: 3.3.3
|
||||
lru-cache: 10.2.0
|
||||
|
Before Width: | Height: | Size: 491 B After Width: | Height: | Size: 491 B |
Before Width: | Height: | Size: 332 B After Width: | Height: | Size: 332 B |
Before Width: | Height: | Size: 407 B After Width: | Height: | Size: 407 B |
Before Width: | Height: | Size: 407 B After Width: | Height: | Size: 407 B |
@@ -1,5 +0,0 @@
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.00033 1.16666C10.222 1.16666 12.8337 3.77833 12.8337 6.99999C12.8337 10.2217 10.222 12.8333 7.00033 12.8333C3.77867 12.8333 1.16699 10.2217 1.16699 6.99999C1.16699 3.77833 3.77867 1.16666 7.00033 1.16666Z" fill="#00B42A"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.14096 5.01194L9.47611 5.29316C9.66128 5.44838 9.68542 5.72433 9.53011 5.90943C9.53008 5.90946 9.53006 5.90949 9.52994 5.90944L6.60396 9.39457C6.44853 9.57951 6.17264 9.60361 5.9875 9.44842L5.31721 8.88598L8.52451 5.06578C8.67993 4.88084 8.95583 4.85674 9.14096 5.01194Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.19314 7.32433L4.48668 6.99832C4.64581 6.82159 4.91696 6.80433 5.09721 6.95947L7.15505 8.73065L6.59516 9.40433C6.44073 9.59016 6.16489 9.6156 5.97906 9.46117C5.97677 9.45926 5.9745 9.45733 5.97225 9.45538L4.23181 7.94776C4.04918 7.78956 4.02938 7.51326 4.18758 7.33063C4.18941 7.32851 4.19126 7.32641 4.19314 7.32433Z" fill="white"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 437 B After Width: | Height: | Size: 437 B |
Before Width: | Height: | Size: 420 B After Width: | Height: | Size: 420 B |
@@ -1,5 +0,0 @@
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect opacity="0.01" x="0.333333" y="0.333333" width="13.3333" height="13.3333" stroke="#F0F0F0" stroke-width="0.666667"/>
|
||||
<path d="M6.99995 13.4159C3.45612 13.4159 0.583282 10.543 0.583282 6.99919C0.583282 3.45536 3.45612 0.58252 6.99995 0.58252C10.5438 0.58252 13.4166 3.45536 13.4166 6.99919C13.4166 10.543 10.5438 13.4159 6.99995 13.4159Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.99995 13.4159C3.45612 13.4159 0.583282 10.543 0.583282 6.99919C0.583282 3.45536 3.45612 0.58252 6.99995 0.58252C10.5438 0.58252 13.4166 3.45536 13.4166 6.99919C13.4166 10.543 10.5438 13.4159 6.99995 13.4159ZM6.1833 10.1492C6.1833 9.69815 6.54893 9.33252 6.99996 9.33252C7.45099 9.33252 7.81663 9.69815 7.81663 10.1492C7.81663 10.6002 7.45099 10.9659 6.99996 10.9659C6.54893 10.9659 6.1833 10.6002 6.1833 10.1492ZM6.21963 3.68084C6.1833 3.75214 6.1833 3.84548 6.1833 4.03217V7.92384C6.1833 8.11052 6.1833 8.20386 6.21963 8.27517C6.25158 8.33789 6.30258 8.38888 6.3653 8.42084C6.4366 8.45717 6.52994 8.45717 6.71663 8.45717H7.2833C7.46998 8.45717 7.56332 8.45717 7.63463 8.42084C7.69735 8.38888 7.74834 8.33789 7.7803 8.27517C7.81663 8.20386 7.81663 8.11052 7.81663 7.92384V4.03217C7.81663 3.84548 7.81663 3.75214 7.7803 3.68084C7.74834 3.61812 7.69735 3.56712 7.63463 3.53517C7.56332 3.49884 7.46998 3.49884 7.2833 3.49884H6.71663C6.52994 3.49884 6.4366 3.49884 6.3653 3.53517C6.30258 3.56712 6.25158 3.61812 6.21963 3.68084Z" fill="#FF8B07"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -21,19 +21,4 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.arco-icon.success {
|
||||
color: rgb(var(--success-6));
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.arco-icon.warning {
|
||||
color: rgb(var(--warning-6));
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.arco-icon.danger {
|
||||
color: rgb(var(--danger-6));
|
||||
margin-right: 4px;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped></style>
|
||||
|
@@ -50,9 +50,12 @@
|
||||
<icon-down />
|
||||
</a-row>
|
||||
<template #content>
|
||||
<a-doption @click="toUser">
|
||||
<a-doption @click="router.push('/setting/profile')">
|
||||
<span>账号管理</span>
|
||||
</a-doption>
|
||||
<a-doption @click="router.push('/setting/security')">
|
||||
<span>安全设置</span>
|
||||
</a-doption>
|
||||
<a-divider :margin="0" />
|
||||
<a-doption @click="logout">
|
||||
<span>退出登录</span>
|
||||
@@ -80,11 +83,6 @@ const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
const SettingDrawerRef = ref<InstanceType<typeof SettingDrawer>>()
|
||||
|
||||
// 跳转基本信息
|
||||
const toUser = () => {
|
||||
router.push('/setting/profile')
|
||||
}
|
||||
|
||||
// 退出登录
|
||||
const logout = () => {
|
||||
Modal.warning({
|
||||
|
@@ -70,19 +70,13 @@ export const constantRoutes: RouteRecordRaw[] = [
|
||||
path: '/setting/profile',
|
||||
component: () => import('@/views/setting/profile/index.vue'),
|
||||
name: 'Profile',
|
||||
meta: { title: '基本信息', hidden: false }
|
||||
meta: { title: '账号管理', hidden: false, showInTabs: false }
|
||||
},
|
||||
{
|
||||
path: '/setting/security',
|
||||
component: () => import('@/views/setting/security/index.vue'),
|
||||
name: 'Security',
|
||||
meta: { title: '安全设置', hidden: false }
|
||||
},
|
||||
{
|
||||
path: '/setting/notice',
|
||||
component: () => import('@/views/setting/notice/index.vue'),
|
||||
name: 'Notification',
|
||||
meta: { title: '消息中心', hidden: false }
|
||||
meta: { title: '安全设置', hidden: false, showInTabs: false }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -56,3 +56,16 @@ body {
|
||||
.arco-checkbox-label {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.success {
|
||||
color: rgb(var(--success-6));
|
||||
margin-right: 4px;
|
||||
}
|
||||
.warning {
|
||||
color: rgb(var(--warning-6));
|
||||
margin-right: 4px;
|
||||
}
|
||||
.danger {
|
||||
color: rgb(var(--danger-6));
|
||||
margin-right: 4px;
|
||||
}
|
@@ -261,6 +261,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 渐变卡片
|
||||
.gradient-card {
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--color-neutral-3);
|
||||
& > .arco-card-header {
|
||||
border: none;
|
||||
background: linear-gradient(180deg, rgba(232, 244, 255, 0.5), hsla(0, 0%, 100%, 0));
|
||||
}
|
||||
}
|
||||
|
||||
// 通用描述
|
||||
.general-description {
|
||||
position: relative;
|
||||
@@ -277,21 +287,3 @@
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.arco-table-cell {
|
||||
.circle {
|
||||
display: inline-block;
|
||||
margin-right: 4px;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background-color: rgb(var(--blue-6));
|
||||
vertical-align: middle;
|
||||
&.pass {
|
||||
background-color: rgb(var(--green-6));
|
||||
}
|
||||
&.fail {
|
||||
background-color: rgb(var(--red-6));
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,19 +1,6 @@
|
||||
<template>
|
||||
<div class="setting" :class="{ 'setting--h5': !isDesktop }">
|
||||
<div class="setting__tabs">
|
||||
<a-tabs hide-content size="medium" :active-key="selectedKeys" @change="(key) => toPage(String(key))">
|
||||
<a-tab-pane v-for="item in list" :key="item.path" :title="item.name"> </a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
|
||||
<div class="setting__main">
|
||||
<div class="setting__main__menu">
|
||||
<a-menu :selected-keys="selectedKeys">
|
||||
<a-menu-item v-for="item in list" :key="item.path" @click="toPage(item.path)">
|
||||
<span>{{ item.name }}</span>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</div>
|
||||
<div class="setting__main__content">
|
||||
<ParentView></ParentView>
|
||||
</div>
|
||||
@@ -26,29 +13,7 @@ import { useDevice } from '@/hooks'
|
||||
|
||||
defineOptions({ name: 'Setting' })
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const { isDesktop } = useDevice()
|
||||
|
||||
const selectedKeys = ref('')
|
||||
watch(
|
||||
() => route.path,
|
||||
(newPath) => {
|
||||
selectedKeys.value = newPath
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
const list = [
|
||||
{ name: '基本信息', value: 1, path: '/setting/profile' },
|
||||
{ name: '安全设置', value: 2, path: '/setting/security' },
|
||||
{ name: '消息中心', value: 3, path: '/setting/notice' }
|
||||
]
|
||||
|
||||
const toPage = (path: string) => {
|
||||
router.push({ path: path })
|
||||
selectedKeys.value = path
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -58,20 +23,11 @@ const toPage = (path: string) => {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
&__tabs {
|
||||
display: none;
|
||||
background-color: var(--color-bg-1);
|
||||
}
|
||||
|
||||
&__main {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
&__menu {
|
||||
width: 200px;
|
||||
margin-top: $margin;
|
||||
margin-left: $margin;
|
||||
}
|
||||
&__content {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
@@ -85,15 +41,5 @@ const toPage = (path: string) => {
|
||||
|
||||
.setting--h5 {
|
||||
flex-direction: column;
|
||||
.setting__tabs {
|
||||
display: block;
|
||||
}
|
||||
.setting__main__menu {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.arco-menu-vertical .arco-menu-inner) {
|
||||
padding: 8px;
|
||||
}
|
||||
</style>
|
||||
|
@@ -1,19 +0,0 @@
|
||||
<template>
|
||||
<div class="page"></div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
|
||||
defineOptions({ name: 'Notification' })
|
||||
|
||||
const route = useRoute()
|
||||
const form = reactive({ name: '' })
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page {
|
||||
padding: $padding;
|
||||
background-color: var(--color-bg-1);
|
||||
}
|
||||
</style>
|
@@ -1,65 +1,49 @@
|
||||
<template>
|
||||
<Card style="height: 600px">
|
||||
<template #header> 主账号信息 </template>
|
||||
<template #body>
|
||||
<div class="body">
|
||||
<section>
|
||||
<div class="avatar">
|
||||
<img :src="userStore.avatar" alt="avatar" />
|
||||
</div>
|
||||
<div class="name">
|
||||
<span style="margin-right: 10px">{{ userInfo.nickname }}</span>
|
||||
<icon-edit :size="16" class="btn" @click="onEditNickName" />
|
||||
</div>
|
||||
<div class="id">
|
||||
<GiSvgIcon name="id" :size="16" />
|
||||
<span style="margin-left: 10px">{{ userInfo.id }}</span>
|
||||
</div>
|
||||
</section>
|
||||
<footer>
|
||||
<div class="footer_item">
|
||||
<div>
|
||||
<span style="margin-right: 10px">安全手机</span>
|
||||
<span>{{ userInfo.phone }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span
|
||||
><GiSvgIcon :name="userInfo.email ? 'success' : 'warning'" :size="14" /><span
|
||||
style="margin-left: 5px; font-size: 12px"
|
||||
>{{ userInfo.phone ? '已绑定' : '未绑定' }}</span
|
||||
></span
|
||||
>
|
||||
<a-divider direction="vertical" />
|
||||
<icon-edit :size="16" class="btn" @click="openVerifyModel('phone')" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer_item">
|
||||
<div>
|
||||
<span style="margin-right: 10px">安全邮箱</span>
|
||||
<span>{{ userInfo.email }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span
|
||||
><GiSvgIcon :name="userInfo.email ? 'success' : 'warning'" :size="14" /><span
|
||||
style="margin-left: 5px; font-size: 12px"
|
||||
>{{ userInfo.email ? '已绑定' : '未绑定' }}</span
|
||||
></span
|
||||
>
|
||||
<a-divider direction="vertical" />
|
||||
<icon-edit :size="16" class="btn" @click="openVerifyModel('email')" />
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<div class="footer">注册于 {{ userInfo.registrationDate }}</div>
|
||||
</template>
|
||||
</Card>
|
||||
<a-card title="基本信息" bordered class="gradient-card">
|
||||
<div class="body">
|
||||
<section>
|
||||
<div class="avatar">
|
||||
<img :src="userStore.avatar" alt="avatar" />
|
||||
</div>
|
||||
<div class="name">
|
||||
<span style="margin-right: 10px">{{ userInfo.nickname }}</span>
|
||||
<icon-edit :size="16" class="btn" @click="onEditNickName" />
|
||||
</div>
|
||||
<div class="id">
|
||||
<GiSvgIcon name="id" :size="16" />
|
||||
<span>{{ userInfo.id }}</span>
|
||||
</div>
|
||||
</section>
|
||||
<footer>
|
||||
<a-descriptions column="4" size="large">
|
||||
<a-descriptions-item label="性别" :span="4">
|
||||
{{ userInfo.nickname }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :span="4">
|
||||
<template #label> <icon-phone /><span style="margin-left: 5px">手机</span></template>
|
||||
{{ userInfo.phone }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :span="4">
|
||||
<template #label> <icon-email /><span style="margin-left: 5px">邮箱</span></template>
|
||||
{{ userInfo.email }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :span="4">
|
||||
<template #label> <icon-mind-mapping /><span style="margin-left: 5px">部门</span></template>
|
||||
{{ userInfo.nickname }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :span="4">
|
||||
<template #label> <icon-user-group /><span style="margin-left: 5px">角色</span></template>
|
||||
{{ userInfo.nickname }}
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</footer>
|
||||
</div>
|
||||
<div class="footer">注册于 {{ userInfo.registrationDate }}</div>
|
||||
</a-card>
|
||||
<VerifyModel ref="verifyModelRef" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Card from '../components/Card.vue'
|
||||
import { updateUserBaseInfo } from '@/apis'
|
||||
import VerifyModel from '../components/VerifyModel.vue'
|
||||
import { useUserStore } from '@/stores'
|
||||
@@ -73,20 +57,23 @@ const openVerifyModel = (type: 'phone' | 'email') => {
|
||||
verifyModelRef.value?.open(type)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
padding: 28px 10px 20px 10px;
|
||||
.btn {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
& > section {
|
||||
flex: 1;
|
||||
flex: 1 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 32px 0 50px;
|
||||
.avatar > img {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
@@ -96,18 +83,30 @@ const openVerifyModel = (type: 'phone' | 'email') => {
|
||||
font-size: 20px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.id {
|
||||
span {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
padding: 0 6px;
|
||||
color: var(--color-text-3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& > footer .footer_item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
padding: 15px 28px;
|
||||
margin: 0 -16px;
|
||||
padding-top: 16px;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
border-top: 1px solid var(--color-neutral-2);
|
||||
border-top: 1px solid var(--color-border-2);
|
||||
}
|
||||
</style>
|
||||
|
@@ -1,54 +1,55 @@
|
||||
<template>
|
||||
<Card>
|
||||
<template #header> 登录方式 </template>
|
||||
<template #body>
|
||||
<div class="mode-list">
|
||||
<div v-for="item in modeList" :key="item.title" class="mode-item">
|
||||
<div class="mode-item-box">
|
||||
<div class="mode-item-icon">
|
||||
<GiSvgIcon :name="item.icon" :size="50" />
|
||||
</div>
|
||||
<div class="mode-item-content">
|
||||
<div class="mode-item-title">
|
||||
<div>{{ item.title }}</div>
|
||||
<div style="margin-left: 10px">
|
||||
<GiSvgIcon :name="item.status ? 'success' : 'warning'" :size="14" /><span
|
||||
style="margin-left: 5px; font-size: 12px"
|
||||
>{{ item.status ? '已绑定' : '未绑定' }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mode-item-subtitle">{{ item.subtitle }}</div>
|
||||
</div>
|
||||
<a-card title="登录方式" bordered class="gradient-card">
|
||||
<div class="mode-list">
|
||||
<div v-for="item in modeList" :key="item.title" class="mode-item">
|
||||
<div class="mode-item-box">
|
||||
<div class="mode-item-box__icon">
|
||||
<GiSvgIcon :name="item.icon" :size="48" />
|
||||
</div>
|
||||
<div class="model-item-btn">
|
||||
<a-button @click="openVerifyModel(item.type, item.status)" v-if="item.jumpMode == 'modal'">{{
|
||||
item.status ? '修改' : '绑定'
|
||||
}}</a-button>
|
||||
<a-button @click="onBinding(item.type, item.status)" v-else-if="item.jumpMode == 'link'">{{
|
||||
item.status ? '解绑' : '绑定'
|
||||
}}</a-button>
|
||||
<div class="mode-item-box__content">
|
||||
<div class="title">
|
||||
<div>{{ item.title }}</div>
|
||||
<div style="margin-left: 10px">
|
||||
<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.status ? '已绑定' : '未绑定'
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mode-item-box__subtitle">{{ item.subtitle }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<a-button
|
||||
v-if="item.jumpMode == 'modal'"
|
||||
class="btn"
|
||||
:type="item.status ? 'secondary' : 'primary'"
|
||||
@click="openVerifyModel(item.type, item.status)"
|
||||
>
|
||||
{{ item.status ? '修改' : '绑定' }}
|
||||
</a-button>
|
||||
<a-button
|
||||
v-else-if="item.jumpMode == 'link'"
|
||||
class="btn"
|
||||
:type="item.status ? 'secondary' : 'primary'"
|
||||
@click="onBinding(item.type, item.status)"
|
||||
>
|
||||
{{ item.status ? '解绑' : '绑定' }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Card>
|
||||
</div>
|
||||
</a-card>
|
||||
<VerifyModel ref="verifyModelRef" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useUserStore } from '@/stores'
|
||||
import Card from '../components/Card.vue'
|
||||
import VerifyModel from '../components/VerifyModel.vue'
|
||||
import { socialAuth, getSocialAccount, unbindSocialAccount } from '@/apis'
|
||||
interface ModeItem {
|
||||
title: string
|
||||
icon: string
|
||||
subtitle: string
|
||||
type: 'phone' | 'email' | 'gitee' | 'github'
|
||||
jumpMode: 'link' | 'modal'
|
||||
status: boolean
|
||||
}
|
||||
import type { ModeItem } from './type'
|
||||
import { useUserStore } from '@/stores'
|
||||
import VerifyModel from '../components/VerifyModel.vue'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const userInfo = computed(() => userStore.userInfo)
|
||||
const verifyModelRef = ref<InstanceType<typeof VerifyModel>>()
|
||||
@@ -56,36 +57,37 @@ const openVerifyModel = (type: 'phone' | 'email') => {
|
||||
verifyModelRef.value?.open(type)
|
||||
}
|
||||
const socialList = ref<any>([])
|
||||
|
||||
const modeList = ref<ModeItem[]>([])
|
||||
modeList.value = [
|
||||
{
|
||||
title: '绑定手机号',
|
||||
icon: 'Tel',
|
||||
subtitle: `${userInfo.value.phone || '绑定后'},可通过手机验证码快捷登录`,
|
||||
title: '绑定手机',
|
||||
icon: userInfo.value.phone ? 'tel' : 'tel-unbind',
|
||||
subtitle: `${userInfo.value.phone || '绑定后'},可通过手机验证码快捷登录`,
|
||||
type: 'phone',
|
||||
jumpMode: 'modal',
|
||||
status: userInfo.value.phone ? true : false
|
||||
status: !!userInfo.value.phone
|
||||
},
|
||||
{
|
||||
title: '绑定邮箱',
|
||||
icon: 'Mail',
|
||||
subtitle: `${userInfo.value.email || '绑定后'},可通过邮箱验证码进行登录`,
|
||||
icon: userInfo.value.email ? 'mail' : 'mail-unbind',
|
||||
subtitle: `${userInfo.value.email || '绑定后'},可通过邮箱验证码进行登录`,
|
||||
type: 'email',
|
||||
jumpMode: 'modal',
|
||||
status: userInfo.value.email ? true : false
|
||||
status: !!userInfo.value.email
|
||||
},
|
||||
{
|
||||
title: '绑定Gitee',
|
||||
title: '绑定 Gitee',
|
||||
icon: 'gitee',
|
||||
subtitle: '绑定后,可通过Gitee进行登录',
|
||||
subtitle: '绑定后,可通过 Gitee 进行登录',
|
||||
jumpMode: 'link',
|
||||
type: 'gitee',
|
||||
status: socialList.value.some((el) => el == 'gitee')
|
||||
},
|
||||
{
|
||||
title: '绑定GitHub',
|
||||
title: '绑定 GitHub',
|
||||
icon: 'github',
|
||||
subtitle: '绑定后,可通过github进行登录',
|
||||
subtitle: '绑定后,可通过 GitHub 进行登录',
|
||||
type: 'github',
|
||||
jumpMode: 'link',
|
||||
status: socialList.value.some((el) => el == 'github')
|
||||
@@ -96,9 +98,7 @@ const initData = () => {
|
||||
socialList.value = res.data.map((el) => el.source)
|
||||
})
|
||||
}
|
||||
onMounted(() => {
|
||||
initData()
|
||||
})
|
||||
|
||||
const onBinding = (type: string, status: boolean) => {
|
||||
if (!status) {
|
||||
socialAuth(type).then((res) => {
|
||||
@@ -112,6 +112,10 @@ const onBinding = (type: string, status: boolean) => {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -119,21 +123,29 @@ const onBinding = (type: string, status: boolean) => {
|
||||
.mode-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
.mode-item-box {
|
||||
&-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.mode-item-icon {
|
||||
&__icon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.mode-item-content > div {
|
||||
line-height: 26px;
|
||||
}
|
||||
.mode-item-content .mode-item-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&__content {
|
||||
div {
|
||||
line-height: 26px;
|
||||
}
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
.btn {
|
||||
height: 28px;
|
||||
margin-left: 10px;
|
||||
width: 56px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -1,40 +1,25 @@
|
||||
<template>
|
||||
<div class="user">
|
||||
<div class="user__info">
|
||||
<a-row justify="space-between">
|
||||
<a-col :span="7" style="padding-right: 20px">
|
||||
<LeftBox />
|
||||
</a-col>
|
||||
<a-col :span="17">
|
||||
<RightBox />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
<div class="gi_page">
|
||||
<a-row wrap :gutter="16">
|
||||
<a-col :xs="24" :sm="24" :md="10" :lg="10" :xl="7" :xxl="7">
|
||||
<LeftBox />
|
||||
</a-col>
|
||||
<a-col :xs="24" :sm="24" :md="14" :lg="14" :xl="17" :xxl="17">
|
||||
<RightBox />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
import { useUserStore } from '@/stores'
|
||||
import RightBox from './RightBox.vue'
|
||||
import LeftBox from './LeftBox.vue'
|
||||
defineOptions({ name: 'Profile' })
|
||||
import RightBox from './RightBox.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const userStore = useUserStore()
|
||||
defineOptions({ name: 'Profile' })
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.user {
|
||||
// background-color: var(--color-bg-1);
|
||||
&__alert {
|
||||
padding: $padding;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
&__info {
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
// display: flex;
|
||||
}
|
||||
.gi_page {
|
||||
background-color: var(--color-bg-1);
|
||||
}
|
||||
</style>
|
||||
|
8
src/views/setting/profile/type.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export interface ModeItem {
|
||||
title: string
|
||||
icon: string
|
||||
subtitle: string
|
||||
type: 'phone' | 'email' | 'gitee' | 'github'
|
||||
jumpMode: 'link' | 'modal'
|
||||
status: boolean
|
||||
}
|
@@ -24,7 +24,7 @@
|
||||
</div>
|
||||
<div>
|
||||
<div class="content_title">
|
||||
<div class="icon"><GiSvgIcon name="loginProtect" :size="36" /></div>
|
||||
<div class="icon"><GiSvgIcon name="login-protect" :size="36" /></div>
|
||||
<div>
|
||||
<div style="font-size: 14px; font-weight: 500; line-height: 28px">操作保护</div>
|
||||
<div style="font-size: 12px">进行敏感操作时需进行二次身份校验</div>
|
||||
@@ -50,7 +50,7 @@ interface ModeItem {
|
||||
}
|
||||
const modeList = ref<ModeItem[]>([])
|
||||
modeList.value = [
|
||||
{ title: '登录保护', icon: 'loginProtect', subtitle: '开启登录保护后,账号登录需进行二次身份验证', status: false }
|
||||
{ title: '登录保护', icon: 'login-protect', subtitle: '开启登录保护后,账号登录需进行二次身份验证', status: false }
|
||||
]
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
|
@@ -38,8 +38,8 @@ interface ModeItem {
|
||||
}
|
||||
const modeList = ref<ModeItem[]>([])
|
||||
modeList.value = [
|
||||
{ title: '绑定手机号', icon: 'Tel', subtitle: '+86******88888可通过手机验证码快捷登录', type: 'phone', status: true },
|
||||
{ title: '绑定邮箱', icon: 'Mail', subtitle: '邮箱可用于身份验证、密码找回、通知接收', type: 'email', status: true }
|
||||
{ title: '绑定手机号', icon: 'tel', subtitle: '+86******88888可通过手机验证码快捷登录', type: 'phone', status: true },
|
||||
{ title: '绑定邮箱', icon: 'mail', subtitle: '邮箱可用于身份验证、密码找回、通知接收', type: 'email', status: true }
|
||||
]
|
||||
const verifyModelRef = ref<InstanceType<typeof VerifyModel>>()
|
||||
const openVerifyModel = (type: 'phone' | 'email') => {
|
||||
|
@@ -3,7 +3,7 @@
|
||||
<template #header> 登录会话设置 </template>
|
||||
<template #body>
|
||||
<div class="content_title">
|
||||
<div class="icon"><GiSvgIcon name="loginStatus" :size="36" /></div>
|
||||
<div class="icon"><GiSvgIcon name="login-status" :size="36" /></div>
|
||||
<div>
|
||||
<div style="font-size: 14px; font-weight: 500; line-height: 28px">登录态保持时间设置</div>
|
||||
<div style="font-size: 12px">保持登录状态的限制</div>
|
||||
|