feat(component): ✨ 新增默认头像 (#104)
1
.gitignore
vendored
@@ -19,6 +19,7 @@ dist-ssr
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
.idea
|
||||
|
||||
src-tauri/target
|
||||
|
||||
|
||||
8
.idea/.gitignore
generated
vendored
@@ -1,8 +0,0 @@
|
||||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 基于编辑器的 HTTP 客户端请求
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
12
.idea/HuLa.iml
generated
@@ -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
@@ -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>
|
||||
62
.idea/codeStyles/Project.xml
generated
@@ -1,62 +0,0 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<option name="LINE_SEPARATOR" value=" " />
|
||||
<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>
|
||||
5
.idea/codeStyles/codeStyleConfig.xml
generated
@@ -1,5 +0,0 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
||||
6
.idea/git_toolbox_blame.xml
generated
@@ -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
|
Before Width: | Height: | Size: 136 KiB |
6
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -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>
|
||||
6
.idea/jsLibraryMappings.xml
generated
@@ -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>
|
||||
14
.idea/libraries/ts_external_references.xml
generated
@@ -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
@@ -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
@@ -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
@@ -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
@@ -1,2 +1,4 @@
|
||||
# 配置npm镜像源 (华为云)
|
||||
registry=https://repo.huaweicloud.com/repository/npm/
|
||||
# 严格检查 package.json 中 "engines" 字段指定的版本要求
|
||||
engine-strict=true
|
||||
@@ -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
|
After Width: | Height: | Size: 201 KiB |
BIN
public/avatar/002.png
Normal file
|
After Width: | Height: | Size: 207 KiB |
BIN
public/avatar/003.png
Normal file
|
After Width: | Height: | Size: 186 KiB |
BIN
public/avatar/004.png
Normal file
|
After Width: | Height: | Size: 206 KiB |
BIN
public/avatar/005.png
Normal file
|
After Width: | Height: | Size: 227 KiB |
BIN
public/avatar/006.png
Normal file
|
After Width: | Height: | Size: 204 KiB |
BIN
public/avatar/007.png
Normal file
|
After Width: | Height: | Size: 191 KiB |
BIN
public/avatar/008.png
Normal file
|
After Width: | Height: | Size: 204 KiB |
BIN
public/avatar/009.png
Normal file
|
After Width: | Height: | Size: 200 KiB |
BIN
public/avatar/010.png
Normal file
|
After Width: | Height: | Size: 210 KiB |
BIN
public/avatar/011.png
Normal file
|
After Width: | Height: | Size: 193 KiB |
BIN
public/avatar/012.png
Normal file
|
After Width: | Height: | Size: 181 KiB |
BIN
public/avatar/013.png
Normal file
|
After Width: | Height: | Size: 212 KiB |
BIN
public/avatar/014.png
Normal file
|
After Width: | Height: | Size: 209 KiB |
BIN
public/avatar/015.png
Normal file
|
After Width: | Height: | Size: 192 KiB |
BIN
public/avatar/016.png
Normal file
|
After Width: | Height: | Size: 188 KiB |
BIN
public/avatar/017.png
Normal file
|
After Width: | Height: | Size: 212 KiB |
BIN
public/avatar/018.png
Normal file
|
After Width: | Height: | Size: 208 KiB |
BIN
public/avatar/019.png
Normal file
|
After Width: | Height: | Size: 202 KiB |
BIN
public/avatar/020.png
Normal file
|
After Width: | Height: | Size: 210 KiB |
BIN
public/avatar/021.png
Normal file
|
After Width: | Height: | Size: 211 KiB |
BIN
public/msg.png
|
Before Width: | Height: | Size: 601 B |
@@ -28,10 +28,7 @@
|
||||
|
||||
<n-flex vertical justify="center" :size="20" class="p-20px">
|
||||
<n-flex align="center" justify="center" :size="20">
|
||||
<n-avatar v-if="userInfo.avatar" round size="large" :src="userInfo.avatar" />
|
||||
<n-avatar v-else round size="large" :src="userInfo.avatar">
|
||||
{{ userInfo.name?.slice(0, 1) }}
|
||||
</n-avatar>
|
||||
<n-avatar round size="large" :src="avatarSrc" />
|
||||
|
||||
<n-flex vertical :size="10">
|
||||
<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 { useCommon } from '@/hooks/useCommon.ts'
|
||||
import { useUserStore } from '@/stores/user.ts'
|
||||
import { AvatarUtils } from '@/utils/avatarUtils'
|
||||
|
||||
const globalStore = useGlobalStore()
|
||||
const userStore = useUserStore()
|
||||
const avatarSrc = computed(() => AvatarUtils.getAvatarUrl(userStore.userInfo.avatar as string))
|
||||
const { countGraphemes } = useCommon()
|
||||
const userInfo = ref(useUserInfo(globalStore.addFriendModalInfo.uid).value)
|
||||
const requestMsg = ref()
|
||||
|
||||
@@ -3,24 +3,7 @@
|
||||
<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" align="center">
|
||||
<n-avatar
|
||||
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-avatar :bordered="true" round :size="80" :src="avatarSrc" fallback-src="/logo.png" />
|
||||
|
||||
<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="" />
|
||||
@@ -64,20 +47,22 @@
|
||||
</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"
|
||||
:src="isCurrentUser.avatar"
|
||||
alt="" />
|
||||
:src="avatarSrc" />
|
||||
</n-flex>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useBadgeInfo, useUserInfo } from '@/hooks/useCached.ts'
|
||||
import { AvatarUtils } from '@/utils/avatarUtils'
|
||||
|
||||
const { uid } = defineProps<{
|
||||
uid: number
|
||||
}>()
|
||||
const isCurrentUser = computed(() => useUserInfo(uid).value)
|
||||
const avatarSrc = computed(() => AvatarUtils.getAvatarUrl(useUserInfo(uid).value.avatar as string))
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
justify="space-between"
|
||||
class="bg-[--center-bg-color] rounded-10px p-20px box-border border-(1px solid [--bg-popover])">
|
||||
<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 align="center" :size="10">
|
||||
<n-popover
|
||||
@@ -54,9 +54,12 @@
|
||||
import { useContactStore } from '@/stores/contacts.ts'
|
||||
import { useUserInfo } from '@/hooks/useCached.ts'
|
||||
import { RequestFriendAgreeStatus } from '@/services/types.ts'
|
||||
import { AvatarUtils } from '@/utils/avatarUtils.ts'
|
||||
|
||||
const contactStore = useContactStore()
|
||||
const currentUserId = ref(0)
|
||||
|
||||
const avatarSrc = (url: string) => AvatarUtils.getAvatarUrl(url)
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
<template>
|
||||
<!-- 好友详情 -->
|
||||
<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
|
||||
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>
|
||||
<n-avatar class="rounded-50% size-146px border-(2px solid #fff)" :src="AvatarUtils.getAvatarUrl(item.avatar)" />
|
||||
|
||||
<span class="text-(20px [--text-color])">{{ item.name }}</span>
|
||||
|
||||
@@ -96,7 +88,7 @@
|
||||
<template #avatar="{ option: { name, src } }">
|
||||
<n-tooltip>
|
||||
<template #trigger>
|
||||
<n-avatar :src="src" />
|
||||
<n-avatar :src="AvatarUtils.getAvatarUrl(src)" />
|
||||
</template>
|
||||
{{ name }}
|
||||
</n-tooltip>
|
||||
@@ -115,6 +107,7 @@ import { RoomTypeEnum } from '@/enums'
|
||||
import { lightTheme } from 'naive-ui'
|
||||
import { useBadgeInfo, useUserInfo } from '@/hooks/useCached.ts'
|
||||
import { useCommon } from '@/hooks/useCommon.ts'
|
||||
import { AvatarUtils } from '@/utils/avatarUtils'
|
||||
|
||||
const { openMsgSession } = useCommon()
|
||||
const { content } = defineProps<{
|
||||
|
||||
@@ -42,31 +42,15 @@
|
||||
align="center"
|
||||
class="ait-item">
|
||||
<n-avatar
|
||||
v-if="item.avatar"
|
||||
lazy
|
||||
round
|
||||
:size="22"
|
||||
:src="item.avatar"
|
||||
:src="AvatarUtils.getAvatarUrl(item.avatar)"
|
||||
fallback-src="/logo.png"
|
||||
:render-placeholder="() => null"
|
||||
:intersection-observer-options="{
|
||||
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>
|
||||
</n-flex>
|
||||
</template>
|
||||
@@ -148,6 +132,7 @@ import { onKeyStroke } from '@vueuse/core'
|
||||
import { type } from '@tauri-apps/plugin-os'
|
||||
import { useUserInfo } from '@/hooks/useCached.ts'
|
||||
import { useMitt } from '@/hooks/useMitt.ts'
|
||||
import { AvatarUtils } from '@/utils/avatarUtils'
|
||||
|
||||
const settingStore = useSettingStore()
|
||||
const { themes } = storeToRefs(settingStore)
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
<template v-else>
|
||||
<div class="box-item cursor-default">
|
||||
<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>
|
||||
|
||||
@@ -122,16 +122,8 @@
|
||||
|
||||
<n-flex align="center" justify="center" :size="20">
|
||||
<template v-for="(item, _index) in userList" :key="_index">
|
||||
<n-flex v-if="item.avatar" vertical justify="center" align="center" :size="10">
|
||||
<n-avatar round :size="30" :src="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>
|
||||
<n-flex vertical justify="center" align="center" :size="10">
|
||||
<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>
|
||||
@@ -191,6 +183,7 @@ import { useChatStore } from '@/stores/chat.ts'
|
||||
import { useGroupStore } from '@/stores/group.ts'
|
||||
import { useUserInfo } from '@/hooks/useCached.ts'
|
||||
import { useContactStore } from '@/stores/contacts.ts'
|
||||
import { AvatarUtils } from '@/utils/avatarUtils'
|
||||
|
||||
// 使用useDisplayMedia获取屏幕共享的媒体流
|
||||
const { stream, start, stop } = useDisplayMedia()
|
||||
|
||||
@@ -122,28 +122,14 @@
|
||||
:content="item"
|
||||
:menu="chatStore.isGroup ? optionsList : void 0"
|
||||
: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
|
||||
round
|
||||
v-else
|
||||
:size="34"
|
||||
@click="selectKey = item.message.id"
|
||||
class="select-none"
|
||||
:src="getAvatarSrc(item.fromUser.uid)"
|
||||
:class="item.fromUser.uid === userUid ? '' : 'mr-10px'">
|
||||
</n-avatar>
|
||||
:class="item.fromUser.uid === userUid ? '' : 'mr-10px'" />
|
||||
</ContextMenu>
|
||||
</template>
|
||||
<!-- 用户个人信息框 -->
|
||||
@@ -393,6 +379,7 @@ import { useChatStore } from '@/stores/chat.ts'
|
||||
import { type } from '@tauri-apps/plugin-os'
|
||||
import { useUserStore } from '@/stores/user.ts'
|
||||
import { useNetwork } from '@vueuse/core'
|
||||
import { AvatarUtils } from '@/utils/avatarUtils'
|
||||
|
||||
const { activeItem } = defineProps<{
|
||||
activeItem: SessionItem
|
||||
@@ -471,12 +458,8 @@ watch(chatMessageList, (value, oldValue) => {
|
||||
|
||||
/** 获取用户头像 */
|
||||
const getAvatarSrc = (uid: number) => {
|
||||
return uid === userUid.value ? userStore.userInfo.avatar : useUserInfo(uid).value.avatar
|
||||
}
|
||||
|
||||
/** 头像是否存在 */
|
||||
const avatarExists = (uid: number) => {
|
||||
return getAvatarSrc(uid) ? void 0 : useUserInfo(uid).value.name?.slice(0, 1)
|
||||
const avatar = uid === userUid.value ? userStore.userInfo.avatar : useUserInfo(uid).value.avatar
|
||||
return AvatarUtils.getAvatarUrl(avatar as string)
|
||||
}
|
||||
|
||||
// 当鼠标进入时触发的处理函数
|
||||
|
||||
@@ -71,36 +71,18 @@
|
||||
:special-menu="report">
|
||||
<n-flex @click="selectKey = item.uid" :key="item.uid" :size="10" align="center" class="item">
|
||||
<n-avatar
|
||||
v-if="item.avatar"
|
||||
lazy
|
||||
round
|
||||
class="grayscale"
|
||||
:class="{ 'grayscale-0': item.activeStatus === OnlineEnum.ONLINE }"
|
||||
:color="'#fff'"
|
||||
:size="24"
|
||||
:src="item.avatar"
|
||||
:src="AvatarUtils.getAvatarUrl(item.avatar)"
|
||||
fallback-src="/logo.png"
|
||||
:render-placeholder="() => null"
|
||||
:intersection-observer-options="{
|
||||
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>
|
||||
<div v-if="item.uid === 1" class="flex p-4px rounded-4px bg-#f5dadf size-fit select-none">
|
||||
<span class="text-(10px #d5304f)">群主</span>
|
||||
@@ -129,6 +111,7 @@ import { useUserInfo } from '@/hooks/useCached.ts'
|
||||
import { useGlobalStore } from '@/stores/global.ts'
|
||||
import type { UserItem } from '@/services/types.ts'
|
||||
import { useDebounceFn } from '@vueuse/core'
|
||||
import { AvatarUtils } from '@/utils/avatarUtils'
|
||||
|
||||
const groupStore = useGroupStore()
|
||||
const globalStore = useGlobalStore()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<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 v-if="activeIndex === 0">
|
||||
|
||||
@@ -25,23 +25,10 @@
|
||||
<!-- 头像 -->
|
||||
<n-flex justify="center">
|
||||
<n-avatar
|
||||
v-if="editInfo.content.avatar"
|
||||
:size="80"
|
||||
:src="editInfo.content.avatar"
|
||||
:src="AvatarUtils.getAvatarUrl(editInfo.content.avatar)"
|
||||
round
|
||||
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 v-if="currentBadge" align="center" justify="center">
|
||||
<span class="text-(14px #707070)">当前佩戴的徽章:</span>
|
||||
@@ -128,6 +115,7 @@ import { type } from '@tauri-apps/plugin-os'
|
||||
import { useCommon } from '@/hooks/useCommon.ts'
|
||||
import { useUserStore } from '@/stores/user.ts'
|
||||
import { UserInfoType } from '@/services/types'
|
||||
import { AvatarUtils } from '@/utils/avatarUtils'
|
||||
|
||||
let localUserInfo = ref<Partial<UserInfoType>>({})
|
||||
const userStore = useUserStore()
|
||||
|
||||
@@ -8,17 +8,7 @@
|
||||
<template #trigger>
|
||||
<!-- 头像 -->
|
||||
<div class="relative size-34px rounded-50% cursor-pointer">
|
||||
<n-avatar
|
||||
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 />
|
||||
<n-avatar :color="'#909090'" :size="34" :src="avatarSrc" fallback-src="/logo.png" round />
|
||||
|
||||
<div
|
||||
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>
|
||||
<n-avatar
|
||||
v-if="avatarExists"
|
||||
:color="'#909090'"
|
||||
:src="userStore.userInfo.avatar"
|
||||
:src="avatarSrc"
|
||||
round
|
||||
fallback-src="/logo.png"
|
||||
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>
|
||||
class="size-68px text-20px select-none cursor-default" />
|
||||
|
||||
<n-flex :size="10" class="text-[--text-color]" justify="center" vertical>
|
||||
<span class="text-18px">{{ userStore.userInfo.name }}</span>
|
||||
@@ -104,9 +82,10 @@
|
||||
<script setup lang="ts">
|
||||
import { leftHook } from '../hook.ts'
|
||||
import { useUserStore } from '@/stores/user.ts'
|
||||
import { AvatarUtils } from '@/utils/avatarUtils'
|
||||
|
||||
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()
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<n-scrollbar style="max-height: 280px">
|
||||
<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">
|
||||
<Transition name="fade" mode="out-in">
|
||||
<Transition name="state-change" mode="out-in">
|
||||
<!-- 未安装和下载中状态 -->
|
||||
<n-flex
|
||||
v-if="plugin.state === PluginEnum.NOT_INSTALLED || plugin.state === PluginEnum.DOWNLOADING"
|
||||
@@ -233,7 +233,18 @@ onUnmounted(() => {
|
||||
@use '@/styles/scss/global/variable.scss' as *;
|
||||
.box {
|
||||
@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 {
|
||||
position: absolute;
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
<n-tabs
|
||||
:value="viewMode"
|
||||
:on-update:value="(v) => (viewMode = v)"
|
||||
:on-update:value="(v: any) => (viewMode = v)"
|
||||
class="w-76px h-28px mr-22px"
|
||||
type="segment"
|
||||
animated>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
justify="center"
|
||||
:size="20"
|
||||
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">
|
||||
<p class="text-(24px [--chat-text-color]) font-500">{{ userStore.userInfo.name }}</p>
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
<template #default="{ item }">
|
||||
<n-flex align="center" justify="space-between" class="mt-18px">
|
||||
<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 class="text-(12px #707070)">{{ item.content }}</p>
|
||||
</n-flex>
|
||||
@@ -139,6 +139,7 @@ import { useWindowState } from '@/hooks/useWindowState.ts'
|
||||
import { type } from '@tauri-apps/plugin-os'
|
||||
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'
|
||||
import { useUserStore } from '@/stores/user.ts'
|
||||
import { AvatarUtils } from '@/utils/avatarUtils'
|
||||
|
||||
useWindowState(WebviewWindow.getCurrent().label)
|
||||
const userStore = useUserStore()
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<!-- 头像和插件 -->
|
||||
<n-flex align="center" justify="space-between" :size="0">
|
||||
<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>
|
||||
<p class="text-(14px [--chat-text-color]) font-500">{{ userStore.userInfo.name }}</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 router from '@/router'
|
||||
import { useUserStore } from '@/stores/user.ts'
|
||||
import { AvatarUtils } from '@/utils/avatarUtils'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const activeItem = ref(0)
|
||||
|
||||
@@ -27,6 +27,8 @@ export type LoginUserReq = {
|
||||
}
|
||||
|
||||
export type RegisterUserReq = {
|
||||
/** 默认随机头像 */
|
||||
avatar: string
|
||||
/** 昵称 */
|
||||
name: string
|
||||
/** 账号 */
|
||||
|
||||
41
src/utils/avatarUtils.ts
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,11 @@
|
||||
:size="16"
|
||||
class="h-full backdrop-blur-md rounded-8px">
|
||||
<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>
|
||||
|
||||
<!-- 密码输入框 -->
|
||||
@@ -118,6 +122,7 @@ import { InputInst, lightTheme } from 'naive-ui'
|
||||
import { getWeekday } from '@/utils/Day.ts'
|
||||
import dayjs from 'dayjs'
|
||||
import { useUserStore } from '@/stores/user.ts'
|
||||
import { AvatarUtils } from '@/utils/avatarUtils'
|
||||
|
||||
const appWindow = WebviewWindow.getCurrent()
|
||||
const settingStore = useSettingStore()
|
||||
|
||||
@@ -29,28 +29,14 @@
|
||||
:key="item.uid">
|
||||
<n-flex align="center" :size="10" class="h-75px pl-6px pr-8px flex-1 truncate">
|
||||
<n-avatar
|
||||
v-if="useUserInfo(item.uid).value.avatar"
|
||||
round
|
||||
bordered
|
||||
:size="44"
|
||||
class="grayscale"
|
||||
: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" />
|
||||
|
||||
<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">
|
||||
<span class="text-14px leading-tight flex-1 truncate">{{
|
||||
useUserInfo(item.uid).value.name
|
||||
@@ -96,6 +82,7 @@ import { useMitt } from '@/hooks/useMitt.ts'
|
||||
import { MittEnum, OnlineEnum, RoomTypeEnum } from '@/enums'
|
||||
import { useContactStore } from '@/stores/contacts.ts'
|
||||
import { useUserInfo } from '@/hooks/useCached.ts'
|
||||
import { AvatarUtils } from '@/utils/avatarUtils'
|
||||
|
||||
const menuList = ref([
|
||||
{ label: '添加分组', icon: 'plus' },
|
||||
|
||||
@@ -16,13 +16,14 @@
|
||||
|
||||
<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-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>
|
||||
</n-flex>
|
||||
</template>
|
||||
</n-flex>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { AvatarUtils } from '@/utils/avatarUtils'
|
||||
const historyList = [
|
||||
{
|
||||
avatar: 'https://picsum.photos/140?1',
|
||||
|
||||
@@ -15,11 +15,7 @@
|
||||
@dblclick="handleMsgDblclick(item)"
|
||||
@select="$event.click(item)">
|
||||
<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 v-else :color="'#909090'" :size="44" :src="item.avatar" bordered fallback-src="/logo.png" round>
|
||||
{{ item.name?.slice(0, 1) }}
|
||||
</n-avatar>
|
||||
<n-avatar :size="44" :src="AvatarUtils.getAvatarUrl(item.avatar)" bordered fallback-src="/logo.png" round />
|
||||
|
||||
<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">
|
||||
@@ -66,6 +62,7 @@ import { useUserInfo } from '@/hooks/useCached.ts'
|
||||
import { renderReplyContent } from '@/utils/RenderReplyContent.ts'
|
||||
import { useCommon } from '@/hooks/useCommon.ts'
|
||||
import SysNTF from '@/components/common/SystemNotification.tsx'
|
||||
import { AvatarUtils } from '@/utils/avatarUtils'
|
||||
|
||||
const chatStore = useChatStore()
|
||||
const globalStore = useGlobalStore()
|
||||
|
||||
@@ -9,13 +9,8 @@
|
||||
<!-- 头像 -->
|
||||
<n-flex justify="center" class="w-full pt-35px" data-tauri-drag-region>
|
||||
<n-avatar
|
||||
v-if="info.avatar"
|
||||
class="size-80px rounded-50% bg-#b6d6d9ff border-(2px solid #fff)"
|
||||
:src="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>
|
||||
:src="AvatarUtils.getAvatarUrl(info.avatar || '/logo.png')" />
|
||||
</n-flex>
|
||||
|
||||
<!-- 登录菜单 -->
|
||||
@@ -54,10 +49,7 @@
|
||||
@click="giveAccount(item)"
|
||||
class="p-8px cursor-pointer hover:bg-#f3f3f3 hover:rounded-6px">
|
||||
<div class="flex-between-center">
|
||||
<n-avatar v-if="item.avatar" :src="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>
|
||||
<n-avatar :src="AvatarUtils.getAvatarUrl(item.avatar)" class="size-28px bg-#ccc rounded-50%" />
|
||||
<p class="text-14px color-#505050">{{ item.account }}</p>
|
||||
<svg @click.stop="delAccount(item)" class="w-12px h-12px">
|
||||
<use href="#close"></use>
|
||||
@@ -115,7 +107,7 @@
|
||||
:size="110"
|
||||
:color="'#fff'"
|
||||
class="border-(2px solid #fff)"
|
||||
:src="userStore.userInfo.avatar || '/logo.png'" />
|
||||
:src="AvatarUtils.getAvatarUrl(userStore.userInfo.avatar || '/logo.png')" />
|
||||
</n-flex>
|
||||
|
||||
<n-flex justify="center">
|
||||
@@ -174,6 +166,7 @@ import { useUserStore } from '@/stores/user.ts'
|
||||
import { UserInfoType } from '@/services/types.ts'
|
||||
import { useSettingStore } from '@/stores/setting.ts'
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
import { AvatarUtils } from '@/utils/avatarUtils'
|
||||
|
||||
const settingStore = useSettingStore()
|
||||
const userStore = useUserStore()
|
||||
|
||||
@@ -107,7 +107,8 @@ import Validation from '@/components/common/Validation.vue'
|
||||
|
||||
/** 账号信息 */
|
||||
const info = unref(
|
||||
ref({
|
||||
ref<RegisterUserReq>({
|
||||
avatar: '',
|
||||
account: '',
|
||||
password: '',
|
||||
name: ''
|
||||
@@ -176,9 +177,17 @@ const register = async () => {
|
||||
btnEnable.value = true
|
||||
loading.value = true
|
||||
btnText.value = '注册中...'
|
||||
// 随机生成头像编号
|
||||
const avatarNum = Math.floor(Math.random() * 21) + 1
|
||||
const avatarId = avatarNum.toString().padStart(3, '0')
|
||||
info.avatar = avatarId
|
||||
// 更新按钮文本
|
||||
btnText.value = '正在分配默认头像...'
|
||||
// 模拟头像分配延迟
|
||||
setTimeout(() => {
|
||||
// 注册
|
||||
apis
|
||||
.register({ ...info } as RegisterUserReq)
|
||||
.register({ ...info })
|
||||
.then(() => {
|
||||
window.$message.success('注册成功')
|
||||
btnText.value = '注册'
|
||||
@@ -194,6 +203,7 @@ const register = async () => {
|
||||
btnEnable.value = false
|
||||
btnText.value = '注册'
|
||||
})
|
||||
}, 800) // 添加800ms延迟来展示头像分配过程
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||