Skip to content

Commit d252a25

Browse files
committed
feat: chat left menu avatar
1 parent fe8f878 commit d252a25

File tree

4 files changed

+160
-28
lines changed

4 files changed

+160
-28
lines changed

ui/src/api/chat/chat.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
} from '@/request/chat/index'
1212
import { type ChatProfile } from '@/api/type/chat'
1313
import { type Ref } from 'vue'
14+
import type { ResetPasswordRequest } from "@/api/type/user.ts";
1415

1516
import useStore from '@/stores'
1617
import type { LoginRequest } from '@/api/type/user'
@@ -201,6 +202,23 @@ const pageChatRecord: (
201202
loading,
202203
)
203204
}
205+
206+
/**
207+
* 登出
208+
*/
209+
const logout: (loading?: Ref<boolean>) => Promise<Result<boolean>> = (loading) => {
210+
return post('/auth/logout', undefined, undefined, loading)
211+
}
212+
213+
/**
214+
* 重置密码
215+
*/
216+
const resetCurrentPassword: (
217+
request: ResetPasswordRequest,
218+
loading?: Ref<boolean>
219+
) => Promise<Result<boolean>> = (request, loading) => {
220+
return post('/chat_user/current/reset_password', request, undefined, loading)
221+
}
204222
export default {
205223
open,
206224
chat,
@@ -221,4 +239,6 @@ export default {
221239
vote,
222240
pageChat,
223241
pageChatRecord,
242+
logout,
243+
resetCurrentPassword
224244
}

ui/src/layout/layout-header/avatar/ResetPassword.vue

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ import useStore from '@/stores'
5252
import { useRouter } from 'vue-router'
5353
import { t } from '@/locales'
5454
55+
const props = defineProps<{
56+
emitConfirm?: boolean; // 在父级调接口
57+
}>()
58+
59+
const emit = defineEmits<{
60+
(e: 'confirm', value: ResetCurrentUserPasswordRequest): void;
61+
}>();
62+
5563
const router = useRouter()
5664
const { login } = useStore()
5765
@@ -133,10 +141,14 @@ const open = () => {
133141
}
134142
const resetPassword = () => {
135143
resetPasswordFormRef1.value?.validate().then(() => {
136-
return UserApi.resetCurrentPassword(resetPasswordForm.value).then(() => {
137-
login.logout()
138-
router.push({ name: 'login' })
139-
})
144+
if(props.emitConfirm) {
145+
emit('confirm', resetPasswordForm.value)
146+
} else {
147+
return UserApi.resetCurrentPassword(resetPasswordForm.value).then(() => {
148+
login.logout()
149+
router.push({ name: 'login' })
150+
})
151+
}
140152
})
141153
}
142154
const close = () => {

ui/src/stores/modules/chat-user.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,14 @@ const useChatUserStore = defineStore('chat-user', {
9292
return this.token
9393
})
9494
},
95+
logout() {
96+
return ChatAPI.logout().then(() => {
97+
sessionStorage.removeItem(`${this.accessToken}-accessToken`)
98+
localStorage.removeItem(`${this.accessToken}-accessToken`)
99+
this.token = undefined
100+
return true
101+
})
102+
},
95103
},
96104
})
97105

ui/src/views/chat/pc/index.vue

Lines changed: 116 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,28 +20,28 @@
2020
:size="32"
2121
style="background: none"
2222
>
23-
<img :src="applicationDetail?.icon" alt="" />
24-
</el-avatar>
25-
<LogoIcon v-else height="28px" style="width: 28px; height: 28px; display: block" />
23+
<img :src="applicationDetail?.icon" alt="" />
24+
</el-avatar>
25+
<LogoIcon v-else height="28px" style="width: 28px; height: 28px; display: block" />
26+
</div>
27+
<h4 v-show="!isPcCollapse">{{ applicationDetail?.name }}</h4>
2628
</div>
27-
<h4 v-show="!isPcCollapse">{{ applicationDetail?.name }}</h4>
28-
</div>
29-
<el-button v-show="!isPcCollapse" class="add-button w-full primary" @click="newChat">
30-
<AppIcon iconName="app-create-chat"></AppIcon>
31-
<span class="ml-4">{{ $t('chat.createChat') }}</span>
32-
</el-button>
33-
<p v-show="!isPcCollapse" class="mt-20 mb-8">{{ $t('chat.history') }}</p>
29+
<el-button v-show="!isPcCollapse" class="add-button w-full primary" @click="newChat">
30+
<AppIcon iconName="app-create-chat"></AppIcon>
31+
<span class="ml-4">{{ $t('chat.createChat') }}</span>
32+
</el-button>
33+
<p v-show="!isPcCollapse" class="mt-20 mb-8">{{ $t('chat.history') }}</p>
3434
</div>
3535
<div v-show="!isPcCollapse" class="left-height pt-0">
3636
<el-scrollbar>
3737
<div class="p-8 pt-0">
3838
<common-list
3939
:style="{
40-
'--el-color-primary': applicationDetail?.custom_theme?.theme_color,
41-
'--el-color-primary-light-9': hexToRgba(
42-
applicationDetail?.custom_theme?.theme_color,
43-
0.1,
44-
),
40+
'--el-color-primary': applicationDetail?.custom_theme?.theme_color,
41+
'--el-color-primary-light-9': hexToRgba(
42+
applicationDetail?.custom_theme?.theme_color,
43+
0.1,
44+
),
4545
}"
4646
:data="chatLogData"
4747
class="mt-8"
@@ -135,10 +135,46 @@
135135
<el-text type="info">{{ $t('chat.noHistory') }}</el-text>
136136
</div>
137137
</el-sub-menu>
138+
<el-dropdown trigger="click" type="primary" class="w-full">
139+
<div class="flex align-center user-info">
140+
<el-avatar :size="32">
141+
<img src="@/assets/user-icon.svg" style="width: 54%" alt="" />
142+
</el-avatar>
143+
<!-- TODO -->
144+
<span v-show="!isPcCollapse" class="ml-8 color-text-primary">{{ 222 }}</span>
145+
</div>
146+
147+
<template #dropdown>
148+
<el-dropdown-menu class="avatar-dropdown">
149+
<div class="flex align-center" style="padding: 12px;">
150+
<div class="mr-8 flex align-center">
151+
<el-avatar :size="40">
152+
<img src="@/assets/user-icon.svg" style="width: 54%" alt="" />
153+
</el-avatar>
154+
</div>
155+
<div>
156+
<!-- TODO -->
157+
<h4 class="medium mb-4">{{ 111 }}</h4>
158+
<div class="color-secondary">{{ `${t('common.username')}: 222` }}</div>
159+
</div>
160+
</div>
161+
<el-dropdown-item class="border-t" style="padding-top: 8px; padding-bottom: 8px;" @click="openResetPassword">
162+
<AppIcon iconName="app-export" />
163+
{{ $t('views.login.resetPassword') }}
164+
</el-dropdown-item>
165+
<el-dropdown-item class="border-t" @click="logout">
166+
<AppIcon iconName="app-export" />
167+
{{ $t('layout.logout') }}
168+
</el-dropdown-item>
169+
</el-dropdown-menu>
170+
</template>
171+
</el-dropdown>
172+
138173
</el-menu>
139-
<el-button v-if="!common.isMobile()" class="pc-collapse" circle size="small" @click="isPcCollapse = !isPcCollapse">
174+
<el-button v-if="!common.isMobile()" class="pc-collapse" circle size="small"
175+
@click="isPcCollapse = !isPcCollapse">
140176
<el-icon>
141-
<component :is=" isPcCollapse ? 'Fold' : 'Expand'" />
177+
<component :is="isPcCollapse ? 'Fold' : 'Expand'" />
142178
</el-icon>
143179
</el-button>
144180
</div>
@@ -200,6 +236,7 @@
200236
</div>
201237

202238
<EditTitleDialog ref="EditTitleDialogRef" @refresh="refreshFieldTitle" />
239+
<ResetPassword ref="resetPasswordRef" emitConfirm @confirm="handleResetPassword"></ResetPassword>
203240
</div>
204241
</template>
205242

@@ -213,21 +250,43 @@ import useStore from '@/stores'
213250
import useResize from '@/layout/hooks/useResize'
214251
import { hexToRgba } from '@/utils/theme'
215252
import EditTitleDialog from './EditTitleDialog.vue'
253+
import { useRouter } from 'vue-router'
254+
import ResetPassword from '@/layout/layout-header/avatar/ResetPassword.vue'
216255
import { t } from '@/locales'
256+
import type { ResetCurrentUserPasswordRequest } from '@/api/type/user'
257+
217258
useResize()
218259
219-
const { user, chatLog, common } = useStore()
260+
const { user, chatLog, common, chatUser } = useStore()
261+
const router = useRouter()
220262
221263
const EditTitleDialogRef = ref()
222264
223265
const isCollapse = ref(false)
224266
const isPcCollapse = ref(false)
225-
watch(()=> common.device, () => {
226-
if(common.isMobile()) {
267+
watch(() => common.device, () => {
268+
if (common.isMobile()) {
227269
isPcCollapse.value = false
228270
}
229271
})
230272
273+
const logout = () => {
274+
chatUser.logout().then(() => {
275+
router.push({ name: 'login' })
276+
})
277+
}
278+
279+
const resetPasswordRef = ref<InstanceType<typeof ResetPassword>>()
280+
const openResetPassword = () => {
281+
resetPasswordRef.value?.open()
282+
}
283+
284+
const handleResetPassword = (param: ResetCurrentUserPasswordRequest) => {
285+
chatAPI.resetCurrentPassword(param).then(() => {
286+
logout()
287+
})
288+
}
289+
231290
const customStyle = computed(() => {
232291
return {
233292
background: applicationDetail.value?.custom_theme?.theme_color,
@@ -472,6 +531,8 @@ onMounted(() => {
472531
position: relative;
473532
474533
.el-menu {
534+
display: flex;
535+
flex-direction: column;
475536
background:
476537
linear-gradient(187.61deg, rgba(235, 241, 255, 0.5) 39.6%, rgba(231, 249, 255, 0.5) 94.3%),
477538
#eef1f4;
@@ -484,12 +545,31 @@ onMounted(() => {
484545
background: transparent;
485546
}
486547
548+
.el-dropdown {
549+
margin-top: auto;
550+
.user-info {
551+
width: 100%;
552+
cursor: pointer;
553+
border-radius: 6px;
554+
padding: 4px 8px;
555+
margin: 16px;
556+
box-sizing: border-box;
557+
&:hover {
558+
background-color: #1F23291A;
559+
}
560+
}
561+
}
562+
487563
&.el-menu--collapse {
488-
.el-menu-item,.el-menu-tooltip__trigger,.el-sub-menu__title {
564+
565+
.el-menu-item,
566+
.el-menu-tooltip__trigger,
567+
.el-sub-menu__title {
489568
padding: 0;
490569
}
491570
492-
.el-menu-item .el-menu-tooltip__trigger,.el-sub-menu__title {
571+
.el-menu-item .el-menu-tooltip__trigger,
572+
.el-sub-menu__title {
493573
position: static;
494574
width: 40px;
495575
height: 40px;
@@ -498,9 +578,15 @@ onMounted(() => {
498578
justify-content: center;
499579
margin: 0 auto;
500580
}
501-
.el-menu-item:hover .el-menu-tooltip__trigger,.el-sub-menu__title:hover {
581+
582+
.el-menu-item:hover .el-menu-tooltip__trigger,
583+
.el-sub-menu__title:hover {
502584
background-color: #1F23291A;
503585
}
586+
587+
.user-info {
588+
margin: 16px 8px;
589+
}
504590
}
505591
}
506592
@@ -509,7 +595,7 @@ onMounted(() => {
509595
}
510596
511597
.left-height {
512-
height: calc(100vh - 140px);
598+
height: calc(100vh - 212px);
513599
}
514600
515601
.pc-collapse {
@@ -633,3 +719,9 @@ onMounted(() => {
633719
}
634720
}
635721
</style>
722+
723+
<style lang="scss" scoped>
724+
.avatar-dropdown {
725+
min-width: 240px;
726+
}
727+
</style>

0 commit comments

Comments
 (0)