feat(component): 新增默认头像 (#104)

This commit is contained in:
Dawn
2024-12-16 02:54:15 +08:00
committed by GitHub
parent 491860a85c
commit 5a4ff7065b
61 changed files with 147 additions and 372 deletions

1
.gitignore vendored
View File

@@ -19,6 +19,7 @@ dist-ssr
*.njsproj *.njsproj
*.sln *.sln
*.sw? *.sw?
.idea
src-tauri/target src-tauri/target

8
.idea/.gitignore generated vendored
View File

@@ -1,8 +0,0 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

12
.idea/HuLa.iml generated
View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="EMPTY_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src-tauri/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/src-tauri/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="ts-external-references" level="project" />
</component>
</module>

6
.idea/bun.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="BunSettings">
<option name="bunPath" value="$USER_HOME$/.bun/bin/bun" />
</component>
</project>

View File

@@ -1,62 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="LINE_SEPARATOR" value="&#10;" />
<HTMLCodeStyleSettings>
<option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
</HTMLCodeStyleSettings>
<JSCodeStyleSettings version="0">
<option name="USE_SEMICOLON_AFTER_STATEMENT" value="false" />
<option name="FORCE_SEMICOLON_STYLE" value="true" />
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
<option name="USE_DOUBLE_QUOTES" value="false" />
<option name="FORCE_QUOTE_STYlE" value="true" />
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
<option name="SPACES_WITHIN_IMPORTS" value="true" />
</JSCodeStyleSettings>
<TypeScriptCodeStyleSettings version="0">
<option name="USE_SEMICOLON_AFTER_STATEMENT" value="false" />
<option name="FORCE_SEMICOLON_STYLE" value="true" />
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
<option name="USE_DOUBLE_QUOTES" value="false" />
<option name="FORCE_QUOTE_STYlE" value="true" />
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
<option name="SPACES_WITHIN_IMPORTS" value="true" />
</TypeScriptCodeStyleSettings>
<VueCodeStyleSettings>
<option name="INTERPOLATION_NEW_LINE_AFTER_START_DELIMITER" value="false" />
<option name="INTERPOLATION_NEW_LINE_BEFORE_END_DELIMITER" value="false" />
</VueCodeStyleSettings>
<codeStyleSettings language="HTML">
<option name="SOFT_MARGINS" value="120" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="JavaScript">
<option name="SOFT_MARGINS" value="120" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="TypeScript">
<option name="SOFT_MARGINS" value="120" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="Vue">
<option name="SOFT_MARGINS" value="120" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>

View File

@@ -1,5 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GitToolBoxBlameSettings">
<option name="version" value="2" />
</component>
</project>

5
.idea/icon.svg generated

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 136 KiB

View File

@@ -1,6 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptLibraryMappings">
<file url="PROJECT" libraries="{ts-external-references}" />
</component>
</project>

View File

@@ -1,14 +0,0 @@
<component name="libraryTable">
<library name="ts-external-references" type="javaScript">
<properties>
<sourceFilesUrls>
<item url="file://$PROJECT_DIR$/node_modules/.pnpm/@rspack+core@1.1.0_@swc+helpers@0.5.15/node_modules/@rspack/core/module.d.ts" />
</sourceFilesUrls>
</properties>
<CLASSES>
<root url="file://$PROJECT_DIR$/node_modules/.pnpm/@rspack+core@1.1.0_@swc+helpers@0.5.15/node_modules/@rspack/core/module.d.ts" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

8
.idea/modules.xml generated
View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/HuLa.iml" filepath="$PROJECT_DIR$/.idea/HuLa.iml" />
</modules>
</component>
</project>

6
.idea/prettier.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PrettierConfiguration">
<option name="myConfigurationMode" value="AUTOMATIC" />
</component>
</project>

6
.idea/vcs.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

2
.npmrc
View File

@@ -1,2 +1,4 @@
# 配置npm镜像源 (华为云)
registry=https://repo.huaweicloud.com/repository/npm/ registry=https://repo.huaweicloud.com/repository/npm/
# 严格检查 package.json 中 "engines" 字段指定的版本要求
engine-strict=true engine-strict=true

View File

@@ -1,18 +0,0 @@
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.16.3
hooks:
- id: gitleaks
- repo: https://github.com/jumanjihouse/pre-commit-hooks
rev: 3.0.0
hooks:
- id: shellcheck
- repo: https://github.com/pre-commit/mirrors-eslint
rev: v8.38.0
hooks:
- id: eslint
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace

BIN
public/avatar/001.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

BIN
public/avatar/002.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

BIN
public/avatar/003.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

BIN
public/avatar/004.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

BIN
public/avatar/005.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

BIN
public/avatar/006.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

BIN
public/avatar/007.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

BIN
public/avatar/008.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

BIN
public/avatar/009.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

BIN
public/avatar/010.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

BIN
public/avatar/011.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

BIN
public/avatar/012.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

BIN
public/avatar/013.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

BIN
public/avatar/014.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

BIN
public/avatar/015.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

BIN
public/avatar/016.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

BIN
public/avatar/017.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

BIN
public/avatar/018.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

BIN
public/avatar/019.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

BIN
public/avatar/020.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

BIN
public/avatar/021.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 601 B

View File

@@ -28,10 +28,7 @@
<n-flex vertical justify="center" :size="20" class="p-20px"> <n-flex vertical justify="center" :size="20" class="p-20px">
<n-flex align="center" justify="center" :size="20"> <n-flex align="center" justify="center" :size="20">
<n-avatar v-if="userInfo.avatar" round size="large" :src="userInfo.avatar" /> <n-avatar round size="large" :src="avatarSrc" />
<n-avatar v-else round size="large" :src="userInfo.avatar">
{{ userInfo.name?.slice(0, 1) }}
</n-avatar>
<n-flex vertical :size="10"> <n-flex vertical :size="10">
<p class="text-[--text-color]">{{ userInfo.name }}</p> <p class="text-[--text-color]">{{ userInfo.name }}</p>
@@ -64,9 +61,11 @@ import { useUserInfo } from '@/hooks/useCached.ts'
import apis from '@/services/apis.ts' import apis from '@/services/apis.ts'
import { useCommon } from '@/hooks/useCommon.ts' import { useCommon } from '@/hooks/useCommon.ts'
import { useUserStore } from '@/stores/user.ts' import { useUserStore } from '@/stores/user.ts'
import { AvatarUtils } from '@/utils/avatarUtils'
const globalStore = useGlobalStore() const globalStore = useGlobalStore()
const userStore = useUserStore() const userStore = useUserStore()
const avatarSrc = computed(() => AvatarUtils.getAvatarUrl(userStore.userInfo.avatar as string))
const { countGraphemes } = useCommon() const { countGraphemes } = useCommon()
const userInfo = ref(useUserInfo(globalStore.addFriendModalInfo.uid).value) const userInfo = ref(useUserInfo(globalStore.addFriendModalInfo.uid).value)
const requestMsg = ref() const requestMsg = ref()

View File

@@ -3,24 +3,7 @@
<n-flex vertical :size="26" class="size-fit box-border rounded-8px relative min-h-[300px]"> <n-flex vertical :size="26" class="size-fit box-border rounded-8px relative min-h-[300px]">
<n-flex vertical :size="20" class="size-full p-10px box-border z-10"> <n-flex vertical :size="20" class="size-full p-10px box-border z-10">
<n-flex vertical :size="20" align="center"> <n-flex vertical :size="20" align="center">
<n-avatar <n-avatar :bordered="true" round :size="80" :src="avatarSrc" fallback-src="/logo.png" />
v-if="isCurrentUser.avatar"
:bordered="true"
round
:size="80"
:src="isCurrentUser.avatar"
fallback-src="/logo.png"></n-avatar>
<n-avatar
v-else
:bordered="true"
round
:color="'#909090'"
:size="80"
:src="isCurrentUser.avatar"
fallback-src="/logo.png">
{{ isCurrentUser.name }}
</n-avatar>
<n-flex :size="5" align="center" style="margin-left: -4px" class="item-hover"> <n-flex :size="5" align="center" style="margin-left: -4px" class="item-hover">
<img class="rounded-50% w-18px h-18px" src="/status/weather_3x.png" alt="" /> <img class="rounded-50% w-18px h-18px" src="/status/weather_3x.png" alt="" />
@@ -64,20 +47,22 @@
</n-flex> </n-flex>
<!-- 背景 --> <!-- 背景 -->
<img <n-avatar
:bordered="true"
class="size-full rounded-8px box-border p-20px absolute top-0 left-0 blur-xl opacity-80" class="size-full rounded-8px box-border p-20px absolute top-0 left-0 blur-xl opacity-80"
:src="isCurrentUser.avatar" :src="avatarSrc" />
alt="" />
</n-flex> </n-flex>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useBadgeInfo, useUserInfo } from '@/hooks/useCached.ts' import { useBadgeInfo, useUserInfo } from '@/hooks/useCached.ts'
import { AvatarUtils } from '@/utils/avatarUtils'
const { uid } = defineProps<{ const { uid } = defineProps<{
uid: number uid: number
}>() }>()
const isCurrentUser = computed(() => useUserInfo(uid).value) const isCurrentUser = computed(() => useUserInfo(uid).value)
const avatarSrc = computed(() => AvatarUtils.getAvatarUrl(useUserInfo(uid).value.avatar as string))
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -16,7 +16,7 @@
justify="space-between" justify="space-between"
class="bg-[--center-bg-color] rounded-10px p-20px box-border border-(1px solid [--bg-popover])"> class="bg-[--center-bg-color] rounded-10px p-20px box-border border-(1px solid [--bg-popover])">
<n-flex align="center" :size="10"> <n-flex align="center" :size="10">
<n-avatar round size="large" :src="useUserInfo(item.uid).value.avatar" class="mr-10px" /> <n-avatar round size="large" :src="avatarSrc(useUserInfo(item.uid).value.avatar)" class="mr-10px" />
<n-flex vertical :size="12"> <n-flex vertical :size="12">
<n-flex align="center" :size="10"> <n-flex align="center" :size="10">
<n-popover <n-popover
@@ -54,9 +54,12 @@
import { useContactStore } from '@/stores/contacts.ts' import { useContactStore } from '@/stores/contacts.ts'
import { useUserInfo } from '@/hooks/useCached.ts' import { useUserInfo } from '@/hooks/useCached.ts'
import { RequestFriendAgreeStatus } from '@/services/types.ts' import { RequestFriendAgreeStatus } from '@/services/types.ts'
import { AvatarUtils } from '@/utils/avatarUtils.ts'
const contactStore = useContactStore() const contactStore = useContactStore()
const currentUserId = ref(0) const currentUserId = ref(0)
const avatarSrc = (url: string) => AvatarUtils.getAvatarUrl(url)
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@@ -1,15 +1,7 @@
<template> <template>
<!-- 好友详情 --> <!-- 好友详情 -->
<n-flex v-if="content.type === RoomTypeEnum.SINGLE" vertical align="center" :size="30" class="mt-60px select-none"> <n-flex v-if="content.type === RoomTypeEnum.SINGLE" vertical align="center" :size="30" class="mt-60px select-none">
<n-avatar v-if="item.avatar" class="rounded-50% size-146px border-(2px solid #fff)" :src="item.avatar" /> <n-avatar class="rounded-50% size-146px border-(2px solid #fff)" :src="AvatarUtils.getAvatarUrl(item.avatar)" />
<n-avatar
v-else
:color="'#909090'"
class="rounded-50% size-146px text-28px border-(2px solid #fff)"
:src="item.avatar">
{{ item.name!.slice(0, 1) }}
</n-avatar>
<span class="text-(20px [--text-color])">{{ item.name }}</span> <span class="text-(20px [--text-color])">{{ item.name }}</span>
@@ -96,7 +88,7 @@
<template #avatar="{ option: { name, src } }"> <template #avatar="{ option: { name, src } }">
<n-tooltip> <n-tooltip>
<template #trigger> <template #trigger>
<n-avatar :src="src" /> <n-avatar :src="AvatarUtils.getAvatarUrl(src)" />
</template> </template>
{{ name }} {{ name }}
</n-tooltip> </n-tooltip>
@@ -115,6 +107,7 @@ import { RoomTypeEnum } from '@/enums'
import { lightTheme } from 'naive-ui' import { lightTheme } from 'naive-ui'
import { useBadgeInfo, useUserInfo } from '@/hooks/useCached.ts' import { useBadgeInfo, useUserInfo } from '@/hooks/useCached.ts'
import { useCommon } from '@/hooks/useCommon.ts' import { useCommon } from '@/hooks/useCommon.ts'
import { AvatarUtils } from '@/utils/avatarUtils'
const { openMsgSession } = useCommon() const { openMsgSession } = useCommon()
const { content } = defineProps<{ const { content } = defineProps<{

View File

@@ -42,31 +42,15 @@
align="center" align="center"
class="ait-item"> class="ait-item">
<n-avatar <n-avatar
v-if="item.avatar"
lazy lazy
round round
:size="22" :size="22"
:src="item.avatar" :src="AvatarUtils.getAvatarUrl(item.avatar)"
fallback-src="/logo.png" fallback-src="/logo.png"
:render-placeholder="() => null" :render-placeholder="() => null"
:intersection-observer-options="{ :intersection-observer-options="{
root: '#image-chat-msgInput' root: '#image-chat-msgInput'
}" /> }" />
<n-avatar
v-else
lazy
round
:color="'#909090'"
:size="22"
class="text-10px"
fallback-src="/logo.png"
:render-placeholder="() => null"
:intersection-observer-options="{
root: '#image-chat-msgInput'
}">
{{ item.name.slice(0, 1) }}
</n-avatar>
<span> {{ item.name }}</span> <span> {{ item.name }}</span>
</n-flex> </n-flex>
</template> </template>
@@ -148,6 +132,7 @@ import { onKeyStroke } from '@vueuse/core'
import { type } from '@tauri-apps/plugin-os' import { type } from '@tauri-apps/plugin-os'
import { useUserInfo } from '@/hooks/useCached.ts' import { useUserInfo } from '@/hooks/useCached.ts'
import { useMitt } from '@/hooks/useMitt.ts' import { useMitt } from '@/hooks/useMitt.ts'
import { AvatarUtils } from '@/utils/avatarUtils'
const settingStore = useSettingStore() const settingStore = useSettingStore()
const { themes } = storeToRefs(settingStore) const { themes } = storeToRefs(settingStore)

View File

@@ -100,7 +100,7 @@
<template v-else> <template v-else>
<div class="box-item cursor-default"> <div class="box-item cursor-default">
<n-flex align="center" :size="10"> <n-flex align="center" :size="10">
<n-avatar round :size="40" :src="activeItem.avatar" /> <n-avatar round :size="40" :src="AvatarUtils.getAvatarUrl(activeItem.avatar)" />
<p class="text-(14px --text-color)">{{ activeItem.name }}</p> <p class="text-(14px --text-color)">{{ activeItem.name }}</p>
@@ -122,16 +122,8 @@
<n-flex align="center" justify="center" :size="20"> <n-flex align="center" justify="center" :size="20">
<template v-for="(item, _index) in userList" :key="_index"> <template v-for="(item, _index) in userList" :key="_index">
<n-flex v-if="item.avatar" vertical justify="center" align="center" :size="10"> <n-flex vertical justify="center" align="center" :size="10">
<n-avatar round :size="30" :src="item.avatar" /> <n-avatar round :size="30" :src="AvatarUtils.getAvatarUrl(item.avatar)" />
<p class="text-(10px --text-color center) w-30px truncate">{{ item.name }}</p>
</n-flex>
<n-flex v-else vertical justify="center" align="center" :size="10">
<n-avatar class="text-10px" round :size="30">
{{ item.name.slice(0, 1) }}
</n-avatar>
<p class="text-(10px --text-color center) w-30px truncate">{{ item.name }}</p> <p class="text-(10px --text-color center) w-30px truncate">{{ item.name }}</p>
</n-flex> </n-flex>
@@ -191,6 +183,7 @@ import { useChatStore } from '@/stores/chat.ts'
import { useGroupStore } from '@/stores/group.ts' import { useGroupStore } from '@/stores/group.ts'
import { useUserInfo } from '@/hooks/useCached.ts' import { useUserInfo } from '@/hooks/useCached.ts'
import { useContactStore } from '@/stores/contacts.ts' import { useContactStore } from '@/stores/contacts.ts'
import { AvatarUtils } from '@/utils/avatarUtils'
// 使用useDisplayMedia获取屏幕共享的媒体流 // 使用useDisplayMedia获取屏幕共享的媒体流
const { stream, start, stop } = useDisplayMedia() const { stream, start, stop } = useDisplayMedia()

View File

@@ -122,28 +122,14 @@
:content="item" :content="item"
:menu="chatStore.isGroup ? optionsList : void 0" :menu="chatStore.isGroup ? optionsList : void 0"
:special-menu="report"> :special-menu="report">
<!-- 没有头像时候显示 -->
<n-avatar
round
v-if="avatarExists(item.fromUser.uid)"
:size="34"
:color="'#909090'"
@click="selectKey = item.message.id"
class="select-none"
:src="getAvatarSrc(item.fromUser.uid)"
:class="item.fromUser.uid === userUid ? '' : 'mr-10px'">
{{ avatarExists(item.fromUser.uid) }}
</n-avatar>
<!-- 存在头像时候显示 --> <!-- 存在头像时候显示 -->
<n-avatar <n-avatar
round round
v-else
:size="34" :size="34"
@click="selectKey = item.message.id" @click="selectKey = item.message.id"
class="select-none" class="select-none"
:src="getAvatarSrc(item.fromUser.uid)" :src="getAvatarSrc(item.fromUser.uid)"
:class="item.fromUser.uid === userUid ? '' : 'mr-10px'"> :class="item.fromUser.uid === userUid ? '' : 'mr-10px'" />
</n-avatar>
</ContextMenu> </ContextMenu>
</template> </template>
<!-- 用户个人信息框 --> <!-- 用户个人信息框 -->
@@ -393,6 +379,7 @@ import { useChatStore } from '@/stores/chat.ts'
import { type } from '@tauri-apps/plugin-os' import { type } from '@tauri-apps/plugin-os'
import { useUserStore } from '@/stores/user.ts' import { useUserStore } from '@/stores/user.ts'
import { useNetwork } from '@vueuse/core' import { useNetwork } from '@vueuse/core'
import { AvatarUtils } from '@/utils/avatarUtils'
const { activeItem } = defineProps<{ const { activeItem } = defineProps<{
activeItem: SessionItem activeItem: SessionItem
@@ -471,12 +458,8 @@ watch(chatMessageList, (value, oldValue) => {
/** 获取用户头像 */ /** 获取用户头像 */
const getAvatarSrc = (uid: number) => { const getAvatarSrc = (uid: number) => {
return uid === userUid.value ? userStore.userInfo.avatar : useUserInfo(uid).value.avatar const avatar = uid === userUid.value ? userStore.userInfo.avatar : useUserInfo(uid).value.avatar
} return AvatarUtils.getAvatarUrl(avatar as string)
/** 头像是否存在 */
const avatarExists = (uid: number) => {
return getAvatarSrc(uid) ? void 0 : useUserInfo(uid).value.name?.slice(0, 1)
} }
// 当鼠标进入时触发的处理函数 // 当鼠标进入时触发的处理函数

View File

@@ -71,36 +71,18 @@
:special-menu="report"> :special-menu="report">
<n-flex @click="selectKey = item.uid" :key="item.uid" :size="10" align="center" class="item"> <n-flex @click="selectKey = item.uid" :key="item.uid" :size="10" align="center" class="item">
<n-avatar <n-avatar
v-if="item.avatar"
lazy lazy
round round
class="grayscale" class="grayscale"
:class="{ 'grayscale-0': item.activeStatus === OnlineEnum.ONLINE }" :class="{ 'grayscale-0': item.activeStatus === OnlineEnum.ONLINE }"
:color="'#fff'" :color="'#fff'"
:size="24" :size="24"
:src="item.avatar" :src="AvatarUtils.getAvatarUrl(item.avatar)"
fallback-src="/logo.png" fallback-src="/logo.png"
:render-placeholder="() => null" :render-placeholder="() => null"
:intersection-observer-options="{ :intersection-observer-options="{
root: '#image-chat-sidebar' root: '#image-chat-sidebar'
}"></n-avatar> }" />
<n-avatar
v-else
lazy
round
class="grayscale text-10px"
:class="{ 'grayscale-0': item.activeStatus === OnlineEnum.ONLINE }"
:color="'rgba(19, 152, 127, 0.4)'"
:size="24"
:src="item.avatar"
fallback-src="/logo.png"
:render-placeholder="() => null"
:intersection-observer-options="{
root: '#image-chat-sidebar'
}">
{{ item.name?.slice(0, 1) }}
</n-avatar>
<span class="text-12px truncate flex-1">{{ item.name }}</span> <span class="text-12px truncate flex-1">{{ item.name }}</span>
<div v-if="item.uid === 1" class="flex p-4px rounded-4px bg-#f5dadf size-fit select-none"> <div v-if="item.uid === 1" class="flex p-4px rounded-4px bg-#f5dadf size-fit select-none">
<span class="text-(10px #d5304f)">群主</span> <span class="text-(10px #d5304f)">群主</span>
@@ -129,6 +111,7 @@ import { useUserInfo } from '@/hooks/useCached.ts'
import { useGlobalStore } from '@/stores/global.ts' import { useGlobalStore } from '@/stores/global.ts'
import type { UserItem } from '@/services/types.ts' import type { UserItem } from '@/services/types.ts'
import { useDebounceFn } from '@vueuse/core' import { useDebounceFn } from '@vueuse/core'
import { AvatarUtils } from '@/utils/avatarUtils'
const groupStore = useGroupStore() const groupStore = useGroupStore()
const globalStore = useGlobalStore() const globalStore = useGlobalStore()

View File

@@ -1,6 +1,6 @@
<template> <template>
<n-scrollbar style="max-height: 290px" class="p-[14px_14px_0_14px] box-border w-460px h-290px select-none"> <n-scrollbar style="max-height: 290px" class="p-[14px_14px_0_14px] box-border w-460px h-290px select-none">
<transition name="fade" mode="out-in" appear> <transition name="fade" mode="out-in">
<div :key="activeIndex" class="emoji-content"> <div :key="activeIndex" class="emoji-content">
<!-- 最近使用 --> <!-- 最近使用 -->
<div v-if="activeIndex === 0"> <div v-if="activeIndex === 0">

View File

@@ -25,23 +25,10 @@
<!-- 头像 --> <!-- 头像 -->
<n-flex justify="center"> <n-flex justify="center">
<n-avatar <n-avatar
v-if="editInfo.content.avatar"
:size="80" :size="80"
:src="editInfo.content.avatar" :src="AvatarUtils.getAvatarUrl(editInfo.content.avatar)"
round round
style="border: 3px solid #fff" /> style="border: 3px solid #fff" />
<n-avatar
v-else
:size="80"
:color="'#909090'"
:src="editInfo.content.avatar"
round
class="text-22px"
style="border: 3px solid #fff">
{{ localUserInfo.name?.slice(0, 1) }}
<!-- {{ editInfo.content.name?.slice(0, 1) }} -->
</n-avatar>
</n-flex> </n-flex>
<n-flex v-if="currentBadge" align="center" justify="center"> <n-flex v-if="currentBadge" align="center" justify="center">
<span class="text-(14px #707070)">当前佩戴的徽章:</span> <span class="text-(14px #707070)">当前佩戴的徽章:</span>
@@ -128,6 +115,7 @@ import { type } from '@tauri-apps/plugin-os'
import { useCommon } from '@/hooks/useCommon.ts' import { useCommon } from '@/hooks/useCommon.ts'
import { useUserStore } from '@/stores/user.ts' import { useUserStore } from '@/stores/user.ts'
import { UserInfoType } from '@/services/types' import { UserInfoType } from '@/services/types'
import { AvatarUtils } from '@/utils/avatarUtils'
let localUserInfo = ref<Partial<UserInfoType>>({}) let localUserInfo = ref<Partial<UserInfoType>>({})
const userStore = useUserStore() const userStore = useUserStore()

View File

@@ -8,17 +8,7 @@
<template #trigger> <template #trigger>
<!-- 头像 --> <!-- 头像 -->
<div class="relative size-34px rounded-50% cursor-pointer"> <div class="relative size-34px rounded-50% cursor-pointer">
<n-avatar <n-avatar :color="'#909090'" :size="34" :src="avatarSrc" fallback-src="/logo.png" round />
v-if="avatarExists"
:color="'#909090'"
:size="34"
:src="userStore.userInfo.avatar"
fallback-src="/logo.png"
round>
{{ avatarExists }}
</n-avatar>
<n-avatar v-else :size="34" :src="userStore.userInfo.avatar" fallback-src="/logo.png" round />
<div <div
class="bg-[--left-bg-color] text-10px rounded-50% size-12px absolute bottom--2px right--2px border-(2px solid [--left-bg-color])" class="bg-[--left-bg-color] text-10px rounded-50% size-12px absolute bottom--2px right--2px border-(2px solid [--left-bg-color])"
@@ -37,23 +27,11 @@
<n-flex :size="25" align="center" justify="space-between" class="select-none cursor-default"> <n-flex :size="25" align="center" justify="space-between" class="select-none cursor-default">
<n-flex> <n-flex>
<n-avatar <n-avatar
v-if="avatarExists"
:color="'#909090'" :color="'#909090'"
:src="userStore.userInfo.avatar" :src="avatarSrc"
round round
fallback-src="/logo.png" fallback-src="/logo.png"
class="size-68px text-20px select-none cursor-default"> class="size-68px text-20px select-none cursor-default" />
{{ avatarExists }}
</n-avatar>
<n-avatar
v-else
:color="'#909090'"
:src="userStore.userInfo.avatar"
round
fallback-src="/logo.png"
class="size-68px text-20px select-none cursor-default">
</n-avatar>
<n-flex :size="10" class="text-[--text-color]" justify="center" vertical> <n-flex :size="10" class="text-[--text-color]" justify="center" vertical>
<span class="text-18px">{{ userStore.userInfo.name }}</span> <span class="text-18px">{{ userStore.userInfo.name }}</span>
@@ -104,9 +82,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { leftHook } from '../hook.ts' import { leftHook } from '../hook.ts'
import { useUserStore } from '@/stores/user.ts' import { useUserStore } from '@/stores/user.ts'
import { AvatarUtils } from '@/utils/avatarUtils'
const userStore = useUserStore() const userStore = useUserStore()
const avatarExists = computed(() => (userStore.userInfo.avatar ? void 0 : userStore.userInfo.name?.slice(0, 1))) const avatarSrc = computed(() => AvatarUtils.getAvatarUrl(userStore.userInfo.avatar as string))
const { shrinkStatus, url, infoShow, bgColor, title, themeColor, openContent, handleEditing } = leftHook() const { shrinkStatus, url, infoShow, bgColor, title, themeColor, openContent, handleEditing } = leftHook()
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -3,7 +3,7 @@
<n-scrollbar style="max-height: 280px"> <n-scrollbar style="max-height: 280px">
<n-flex :size="26" class="z-10 p-[18px_18px_36px_18px] box-border w-full"> <n-flex :size="26" class="z-10 p-[18px_18px_36px_18px] box-border w-full">
<template v-for="(plugin, index) in allPlugins" :key="index"> <template v-for="(plugin, index) in allPlugins" :key="index">
<Transition name="fade" mode="out-in"> <Transition name="state-change" mode="out-in">
<!-- 未安装和下载中状态 --> <!-- 未安装和下载中状态 -->
<n-flex <n-flex
v-if="plugin.state === PluginEnum.NOT_INSTALLED || plugin.state === PluginEnum.DOWNLOADING" v-if="plugin.state === PluginEnum.NOT_INSTALLED || plugin.state === PluginEnum.DOWNLOADING"
@@ -233,7 +233,18 @@ onUnmounted(() => {
@use '@/styles/scss/global/variable.scss' as *; @use '@/styles/scss/global/variable.scss' as *;
.box { .box {
@apply relative select-none custom-shadow cursor-pointer size-fit w-100px h-100px rounded-8px overflow-hidden; @apply relative select-none custom-shadow cursor-pointer size-fit w-100px h-100px rounded-8px overflow-hidden;
transition: all 0.2s; transition: all 0.3s ease-in-out;
&.state-change-enter-active,
&.state-change-leave-active {
transition: all 0.3s ease-in-out;
}
&.state-change-enter-from,
&.state-change-leave-to {
opacity: 0;
transform: scale(0.9);
}
.flash { .flash {
position: absolute; position: absolute;

View File

@@ -40,7 +40,7 @@
<n-tabs <n-tabs
:value="viewMode" :value="viewMode"
:on-update:value="(v) => (viewMode = v)" :on-update:value="(v: any) => (viewMode = v)"
class="w-76px h-28px mr-22px" class="w-76px h-28px mr-22px"
type="segment" type="segment"
animated> animated>

View File

@@ -13,7 +13,7 @@
justify="center" justify="center"
:size="20" :size="20"
class="login-box relative h-160px w-full select-none"> class="login-box relative h-160px w-full select-none">
<n-avatar :size="120" round bordered :src="userStore.userInfo.avatar" /> <n-avatar :size="120" round bordered :src="AvatarUtils.getAvatarUrl(userStore.userInfo.avatar)" />
<n-flex vertical justify="center" :size="20"> <n-flex vertical justify="center" :size="20">
<p class="text-(24px [--chat-text-color]) font-500">{{ userStore.userInfo.name }}</p> <p class="text-(24px [--chat-text-color]) font-500">{{ userStore.userInfo.name }}</p>
@@ -119,7 +119,7 @@
<template #default="{ item }"> <template #default="{ item }">
<n-flex align="center" justify="space-between" class="mt-18px"> <n-flex align="center" justify="space-between" class="mt-18px">
<n-flex align="center"> <n-flex align="center">
<n-avatar :size="36" round bordered :src="item.avatar" /> <n-avatar :size="36" round bordered :src="AvatarUtils.getAvatarUrl(item.avatar)" />
<p>{{ item.user }}</p> <p>{{ item.user }}</p>
<p class="text-(12px #707070)">{{ item.content }}</p> <p class="text-(12px #707070)">{{ item.content }}</p>
</n-flex> </n-flex>
@@ -139,6 +139,7 @@ import { useWindowState } from '@/hooks/useWindowState.ts'
import { type } from '@tauri-apps/plugin-os' import { type } from '@tauri-apps/plugin-os'
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow' import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'
import { useUserStore } from '@/stores/user.ts' import { useUserStore } from '@/stores/user.ts'
import { AvatarUtils } from '@/utils/avatarUtils'
useWindowState(WebviewWindow.getCurrent().label) useWindowState(WebviewWindow.getCurrent().label)
const userStore = useUserStore() const userStore = useUserStore()

View File

@@ -23,7 +23,7 @@
<!-- 头像和插件 --> <!-- 头像和插件 -->
<n-flex align="center" justify="space-between" :size="0"> <n-flex align="center" justify="space-between" :size="0">
<n-flex align="center"> <n-flex align="center">
<n-avatar bordered round :src="userStore.userInfo.avatar" :size="48" /> <n-avatar bordered round :src="AvatarUtils.getAvatarUrl(userStore.userInfo.avatar)" :size="48" />
<n-flex vertical> <n-flex vertical>
<p class="text-(14px [--chat-text-color]) font-500">{{ userStore.userInfo.name }}</p> <p class="text-(14px [--chat-text-color]) font-500">{{ userStore.userInfo.name }}</p>
<p class="text-(12px #909090)">剩余28天过期</p> <p class="text-(12px #909090)">剩余28天过期</p>
@@ -141,6 +141,7 @@ import { useMitt } from '@/hooks/useMitt.ts'
import { VueDraggable } from 'vue-draggable-plus' import { VueDraggable } from 'vue-draggable-plus'
import router from '@/router' import router from '@/router'
import { useUserStore } from '@/stores/user.ts' import { useUserStore } from '@/stores/user.ts'
import { AvatarUtils } from '@/utils/avatarUtils'
const userStore = useUserStore() const userStore = useUserStore()
const activeItem = ref(0) const activeItem = ref(0)

View File

@@ -27,6 +27,8 @@ export type LoginUserReq = {
} }
export type RegisterUserReq = { export type RegisterUserReq = {
/** 默认随机头像 */
avatar: string
/** 昵称 */ /** 昵称 */
name: string name: string
/** 账号 */ /** 账号 */

41
src/utils/avatarUtils.ts Normal file
View File

@@ -0,0 +1,41 @@
/**
* 用于处理头像相关操作的实用类
*/
export class AvatarUtils {
private static readonly DEFAULT_AVATAR_RANGE = {
start: '001',
end: '021'
}
private static readonly RANGE_START = parseInt(AvatarUtils.DEFAULT_AVATAR_RANGE.start, 10)
private static readonly RANGE_END = parseInt(AvatarUtils.DEFAULT_AVATAR_RANGE.end, 10)
/**
* 检查头像字符串是否为默认头像 (001-021)
* @param avatar - 要检查的头像字符串
* @returns 布尔值指示是否是默认头像
*/
public static isDefaultAvatar(avatar: string): boolean {
// 快速判断如果为空或长度不是3直接返回false
if (!avatar || avatar.length !== 3) return false
// 检查是否全是数字
const num = parseInt(avatar, 10)
if (isNaN(num)) return false
// 数字范围检查 (001-021)
return num >= this.RANGE_START && num <= this.RANGE_END
}
/**
* 根据头像值获取头像URL
* @param avatar - 头像字符串或URL
* @returns 头像字符串或URL
*/
public static getAvatarUrl(avatar: string): string {
if (this.isDefaultAvatar(avatar)) {
return `/avatar/${avatar}.png`
}
return avatar
}
}

View File

@@ -47,7 +47,11 @@
:size="16" :size="16"
class="h-full backdrop-blur-md rounded-8px"> class="h-full backdrop-blur-md rounded-8px">
<n-flex vertical align="center" justify="center" :size="30" class="mt--75px"> <n-flex vertical align="center" justify="center" :size="30" class="mt--75px">
<n-avatar round style="border: 2px solid #f1f1f1" :size="120" :src="userStore.userInfo.avatar" /> <n-avatar
round
style="border: 2px solid #f1f1f1"
:size="120"
:src="AvatarUtils.getAvatarUrl(userStore.userInfo.avatar)" />
<p class="text-(24px #f1f1f1) font-500">{{ userStore.userInfo.name }}</p> <p class="text-(24px #f1f1f1) font-500">{{ userStore.userInfo.name }}</p>
<!-- 密码输入框 --> <!-- 密码输入框 -->
@@ -118,6 +122,7 @@ import { InputInst, lightTheme } from 'naive-ui'
import { getWeekday } from '@/utils/Day.ts' import { getWeekday } from '@/utils/Day.ts'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { useUserStore } from '@/stores/user.ts' import { useUserStore } from '@/stores/user.ts'
import { AvatarUtils } from '@/utils/avatarUtils'
const appWindow = WebviewWindow.getCurrent() const appWindow = WebviewWindow.getCurrent()
const settingStore = useSettingStore() const settingStore = useSettingStore()

View File

@@ -29,28 +29,14 @@
:key="item.uid"> :key="item.uid">
<n-flex align="center" :size="10" class="h-75px pl-6px pr-8px flex-1 truncate"> <n-flex align="center" :size="10" class="h-75px pl-6px pr-8px flex-1 truncate">
<n-avatar <n-avatar
v-if="useUserInfo(item.uid).value.avatar"
round round
bordered bordered
:size="44" :size="44"
class="grayscale" class="grayscale"
:class="{ 'grayscale-0': item.activeStatus === OnlineEnum.ONLINE }" :class="{ 'grayscale-0': item.activeStatus === OnlineEnum.ONLINE }"
:src="useUserInfo(item.uid).value.avatar" :src="AvatarUtils.getAvatarUrl(useUserInfo(item.uid).value.avatar)"
fallback-src="/logo.png" /> fallback-src="/logo.png" />
<n-avatar
v-else
round
bordered
:color="'#909090'"
:size="44"
class="grayscale"
:class="{ 'grayscale-0': item.activeStatus === OnlineEnum.ONLINE }"
:src="useUserInfo(item.uid).value.avatar"
fallback-src="/logo.png">
{{ useUserInfo(item.uid).value.name?.slice(0, 1) }}
</n-avatar>
<n-flex vertical justify="space-between" class="h-fit flex-1 truncate"> <n-flex vertical justify="space-between" class="h-fit flex-1 truncate">
<span class="text-14px leading-tight flex-1 truncate">{{ <span class="text-14px leading-tight flex-1 truncate">{{
useUserInfo(item.uid).value.name useUserInfo(item.uid).value.name
@@ -96,6 +82,7 @@ import { useMitt } from '@/hooks/useMitt.ts'
import { MittEnum, OnlineEnum, RoomTypeEnum } from '@/enums' import { MittEnum, OnlineEnum, RoomTypeEnum } from '@/enums'
import { useContactStore } from '@/stores/contacts.ts' import { useContactStore } from '@/stores/contacts.ts'
import { useUserInfo } from '@/hooks/useCached.ts' import { useUserInfo } from '@/hooks/useCached.ts'
import { AvatarUtils } from '@/utils/avatarUtils'
const menuList = ref([ const menuList = ref([
{ label: '添加分组', icon: 'plus' }, { label: '添加分组', icon: 'plus' },

View File

@@ -16,13 +16,14 @@
<template v-for="(item, _index) in historyList" :key="_index"> <template v-for="(item, _index) in historyList" :key="_index">
<n-flex align="center" :size="14" class="p-6px cursor-pointer rounded-8px hover:bg-[--list-hover-color]"> <n-flex align="center" :size="14" class="p-6px cursor-pointer rounded-8px hover:bg-[--list-hover-color]">
<n-avatar :size="38" round bordered :src="item.avatar" /> <n-avatar :size="38" round bordered :src="AvatarUtils.getAvatarUrl(item.avatar)" />
<p class="text-(14px [--text-color])">{{ item.name }}</p> <p class="text-(14px [--text-color])">{{ item.name }}</p>
</n-flex> </n-flex>
</template> </template>
</n-flex> </n-flex>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { AvatarUtils } from '@/utils/avatarUtils'
const historyList = [ const historyList = [
{ {
avatar: 'https://picsum.photos/140?1', avatar: 'https://picsum.photos/140?1',

View File

@@ -15,11 +15,7 @@
@dblclick="handleMsgDblclick(item)" @dblclick="handleMsgDblclick(item)"
@select="$event.click(item)"> @select="$event.click(item)">
<n-flex :size="10" align="center" class="h-75px pl-6px pr-8px flex-1"> <n-flex :size="10" align="center" class="h-75px pl-6px pr-8px flex-1">
<n-avatar v-if="item.avatar" :size="44" :src="item.avatar" bordered fallback-src="/logo.png" round /> <n-avatar :size="44" :src="AvatarUtils.getAvatarUrl(item.avatar)" bordered fallback-src="/logo.png" round />
<n-avatar v-else :color="'#909090'" :size="44" :src="item.avatar" bordered fallback-src="/logo.png" round>
{{ item.name?.slice(0, 1) }}
</n-avatar>
<n-flex class="h-fit flex-1 truncate" justify="space-between" vertical> <n-flex class="h-fit flex-1 truncate" justify="space-between" vertical>
<n-flex :size="4" align="center" class="flex-1 truncate" justify="space-between"> <n-flex :size="4" align="center" class="flex-1 truncate" justify="space-between">
@@ -66,6 +62,7 @@ import { useUserInfo } from '@/hooks/useCached.ts'
import { renderReplyContent } from '@/utils/RenderReplyContent.ts' import { renderReplyContent } from '@/utils/RenderReplyContent.ts'
import { useCommon } from '@/hooks/useCommon.ts' import { useCommon } from '@/hooks/useCommon.ts'
import SysNTF from '@/components/common/SystemNotification.tsx' import SysNTF from '@/components/common/SystemNotification.tsx'
import { AvatarUtils } from '@/utils/avatarUtils'
const chatStore = useChatStore() const chatStore = useChatStore()
const globalStore = useGlobalStore() const globalStore = useGlobalStore()

View File

@@ -9,13 +9,8 @@
<!-- 头像 --> <!-- 头像 -->
<n-flex justify="center" class="w-full pt-35px" data-tauri-drag-region> <n-flex justify="center" class="w-full pt-35px" data-tauri-drag-region>
<n-avatar <n-avatar
v-if="info.avatar"
class="size-80px rounded-50% bg-#b6d6d9ff border-(2px solid #fff)" class="size-80px rounded-50% bg-#b6d6d9ff border-(2px solid #fff)"
:src="info.avatar || '/logo.png'" /> :src="AvatarUtils.getAvatarUrl(info.avatar || '/logo.png')" />
<n-avatar v-else class="size-80px text-20px rounded-50% bg-#b6d6d9ff border-(2px solid #fff)">
{{ info.name.slice(0, 1) }}
</n-avatar>
</n-flex> </n-flex>
<!-- 登录菜单 --> <!-- 登录菜单 -->
@@ -54,10 +49,7 @@
@click="giveAccount(item)" @click="giveAccount(item)"
class="p-8px cursor-pointer hover:bg-#f3f3f3 hover:rounded-6px"> class="p-8px cursor-pointer hover:bg-#f3f3f3 hover:rounded-6px">
<div class="flex-between-center"> <div class="flex-between-center">
<n-avatar v-if="item.avatar" :src="item.avatar" class="size-28px bg-#ccc rounded-50%" /> <n-avatar :src="AvatarUtils.getAvatarUrl(item.avatar)" class="size-28px bg-#ccc rounded-50%" />
<n-avatar v-else :src="item.avatar" :color="'#909090'" class="size-28px text-10px bg-#ccc rounded-50%">
{{ item.name?.slice(0, 1) }}
</n-avatar>
<p class="text-14px color-#505050">{{ item.account }}</p> <p class="text-14px color-#505050">{{ item.account }}</p>
<svg @click.stop="delAccount(item)" class="w-12px h-12px"> <svg @click.stop="delAccount(item)" class="w-12px h-12px">
<use href="#close"></use> <use href="#close"></use>
@@ -115,7 +107,7 @@
:size="110" :size="110"
:color="'#fff'" :color="'#fff'"
class="border-(2px solid #fff)" class="border-(2px solid #fff)"
:src="userStore.userInfo.avatar || '/logo.png'" /> :src="AvatarUtils.getAvatarUrl(userStore.userInfo.avatar || '/logo.png')" />
</n-flex> </n-flex>
<n-flex justify="center"> <n-flex justify="center">
@@ -174,6 +166,7 @@ import { useUserStore } from '@/stores/user.ts'
import { UserInfoType } from '@/services/types.ts' import { UserInfoType } from '@/services/types.ts'
import { useSettingStore } from '@/stores/setting.ts' import { useSettingStore } from '@/stores/setting.ts'
import { invoke } from '@tauri-apps/api/core' import { invoke } from '@tauri-apps/api/core'
import { AvatarUtils } from '@/utils/avatarUtils'
const settingStore = useSettingStore() const settingStore = useSettingStore()
const userStore = useUserStore() const userStore = useUserStore()

View File

@@ -107,7 +107,8 @@ import Validation from '@/components/common/Validation.vue'
/** 账号信息 */ /** 账号信息 */
const info = unref( const info = unref(
ref({ ref<RegisterUserReq>({
avatar: '',
account: '', account: '',
password: '', password: '',
name: '' name: ''
@@ -176,24 +177,33 @@ const register = async () => {
btnEnable.value = true btnEnable.value = true
loading.value = true loading.value = true
btnText.value = '注册中...' btnText.value = '注册中...'
// 注册 // 随机生成头像编号
apis const avatarNum = Math.floor(Math.random() * 21) + 1
.register({ ...info } as RegisterUserReq) const avatarId = avatarNum.toString().padStart(3, '0')
.then(() => { info.avatar = avatarId
window.$message.success('注册成功') // 更新按钮文本
btnText.value = '注册' btnText.value = '正在分配默认头像...'
setTimeout(() => { // 模拟头像分配延迟
WebviewWindow.getByLabel('login').then((win) => { setTimeout(() => {
win?.setFocus() // 注册
}) apis
WebviewWindow.getCurrent().close() .register({ ...info })
}, 600) .then(() => {
}) window.$message.success('注册成功')
.finally(() => { btnText.value = '注册'
loading.value = false setTimeout(() => {
btnEnable.value = false WebviewWindow.getByLabel('login').then((win) => {
btnText.value = '注册' win?.setFocus()
}) })
WebviewWindow.getCurrent().close()
}, 600)
})
.finally(() => {
loading.value = false
btnEnable.value = false
btnText.value = '注册'
})
}, 800) // 添加800ms延迟来展示头像分配过程
} }
}) })
} }