mirror of
https://github.com/HuLaSpark/HuLa.git
synced 2026-08-28 19:11:16 +08:00
feat(component): ✨ 增加表情包功能
This commit is contained in:
@@ -1,45 +0,0 @@
|
||||
name: Codecov
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
paths:
|
||||
- 'src/**'
|
||||
- 'test/**'
|
||||
|
||||
jobs:
|
||||
codecov:
|
||||
# 跳过 Renovate PR
|
||||
if: |
|
||||
github.actor != 'renovate[bot]' &&
|
||||
github.actor != 'renovate-preview[bot]'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# 首先安装 pnpm
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
run_install: false
|
||||
|
||||
# 然后设置 Node.js
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Run tests with coverage
|
||||
run: pnpm coverage
|
||||
|
||||
- name: Upload results to Codecov
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
slug: HuLaSpark/HuLa
|
||||
+1
-3
@@ -5,9 +5,6 @@
|
||||
<p align="center">An Instant Messaging System Built with Tauri, Vite 6, Vue 3, and TypeScript</p>
|
||||
|
||||
<div align="center">
|
||||
<a href="https://codecov.io/gh/HuLaSpark/HuLa" >
|
||||
<img src="https://codecov.io/gh/HuLaSpark/HuLa/branch/fix%2Fglobal/graph/badge.svg?token=NM0Z13M8AZ"/>
|
||||
</a>
|
||||
<a href="https://app.fossa.com/projects/git%2Bgithub.com%2FHuLaSpark%2FHuLa?ref=badge_shield"><img src="https://app.fossa.com/api/projects/git%2Bgithub.com%2FHuLaSpark%2FHuLa.svg?type=shield" alt=""></a>
|
||||
<a href="https://www.bestpractices.dev/zh-CN/projects/9692"><img src="https://bestpractices.coreinfrastructure.org/projects/9692/badge" alt="CI"></a>
|
||||
<img src="https://img.shields.io/badge/TypeScript-blue?logo=Typescript&style=flat&logoColor=fff">
|
||||
@@ -89,6 +86,7 @@ HuLa is an instant messaging system developed with Tauri, Vite 6, Vue 3, and Typ
|
||||
| | Message Recall | ✅ Completed |
|
||||
| | @Mention, Reply Function | ✅ Completed |
|
||||
| | Message Read Status | ✅ Completed |
|
||||
| | Emoji Function | ✅ Completed |
|
||||
| | Context Menu Based on Message Type | ✅ Completed |
|
||||
| 👥 **Contact & Group Management** | Friend Add/Remove | ✅ Completed |
|
||||
| | Friend Search | ✅ Completed |
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
<p align="center">一款基于Tauri、Vite 6、Vue 3 和 TypeScript 构建的即时通讯系统</p>
|
||||
|
||||
<div align="center">
|
||||
<a href="https://codecov.io/gh/HuLaSpark/HuLa" >
|
||||
<img src="https://codecov.io/gh/HuLaSpark/HuLa/branch/fix%2Fglobal/graph/badge.svg?token=NM0Z13M8AZ"/>
|
||||
</a>
|
||||
<a href="https://app.fossa.com/projects/git%2Bgithub.com%2FHuLaSpark%2FHuLa?ref=badge_shield"><img src="https://app.fossa.com/api/projects/git%2Bgithub.com%2FHuLaSpark%2FHuLa.svg?type=shield" alt=""></a>
|
||||
<a href="https://www.bestpractices.dev/zh-CN/projects/9692"><img src="https://bestpractices.coreinfrastructure.org/projects/9692/badge" alt="CI"></a>
|
||||
<img src="https://img.shields.io/badge/TypeScript-blue?logo=Typescript&style=flat&logoColor=fff">
|
||||
@@ -89,6 +86,7 @@ HuLa 是一款基于 Tauri、Vite 6、Vue 3 和 TypeScript 构建的即时通讯
|
||||
| | 消息撤回 | ✅ 已完成 |
|
||||
| | @提醒、回复功能 | ✅ 已完成 |
|
||||
| | 消息已读状态 | ✅ 已完成 |
|
||||
| | 表情包功能 | ✅ 已完成 |
|
||||
| | 根据消息类型右键菜单 | ✅ 已完成 |
|
||||
| 👥 **联系人、群聊管理** | 好友添加与删除 | ✅ 已完成 |
|
||||
| | 好友搜索 | ✅ 已完成 |
|
||||
|
||||
@@ -57,7 +57,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/github": "^6.0.0",
|
||||
"@codecov/vite-plugin": "^1.6.0",
|
||||
"@fingerprintjs/fingerprintjs": "^4.6.0",
|
||||
"@tauri-apps/api": "2.3.0",
|
||||
"@tauri-apps/plugin-autostart": "2.2.0",
|
||||
|
||||
Generated
-62
@@ -11,9 +11,6 @@ importers:
|
||||
'@actions/github':
|
||||
specifier: ^6.0.0
|
||||
version: 6.0.0
|
||||
'@codecov/vite-plugin':
|
||||
specifier: ^1.6.0
|
||||
version: 1.7.0(vite@6.2.2(@types/node@22.10.7)(jiti@2.4.2)(sass@1.83.0)(terser@5.37.0)(tsx@4.19.2)(yaml@2.6.1))
|
||||
'@fingerprintjs/fingerprintjs':
|
||||
specifier: ^4.6.0
|
||||
version: 4.6.0
|
||||
@@ -240,21 +237,12 @@ importers:
|
||||
|
||||
packages:
|
||||
|
||||
'@actions/core@1.11.1':
|
||||
resolution: {integrity: sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==}
|
||||
|
||||
'@actions/exec@1.1.1':
|
||||
resolution: {integrity: sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==}
|
||||
|
||||
'@actions/github@6.0.0':
|
||||
resolution: {integrity: sha512-alScpSVnYmjNEXboZjarjukQEzgCRmjMv6Xj47fsdnqGS73bjJNDpiiXmp8jr0UZLdUB6d9jW63IcmddUP+l0g==}
|
||||
|
||||
'@actions/http-client@2.2.3':
|
||||
resolution: {integrity: sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==}
|
||||
|
||||
'@actions/io@1.1.3':
|
||||
resolution: {integrity: sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==}
|
||||
|
||||
'@ampproject/remapping@2.3.0':
|
||||
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
@@ -443,16 +431,6 @@ packages:
|
||||
resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@codecov/bundler-plugin-core@1.7.0':
|
||||
resolution: {integrity: sha512-QsLwtwfy9KEe0CjqNE2Z/SPiCMn4CHAJ9cqTosZCX9YMKPi/WyFivv0pYE7CXA8ntG0l4Xc9kr36DUCuNRW0LQ==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
'@codecov/vite-plugin@1.7.0':
|
||||
resolution: {integrity: sha512-Cy/NxuEiGCf9X62dKewxnFf6Uv6CxfCCJAd8AfbOYbg96vwjwuq6BMoCIAk9gUFmwurw9EOKGPwoW0lIrUMIzA==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
peerDependencies:
|
||||
vite: 4.x || 5.x || 6.x
|
||||
|
||||
'@commitlint/cli@19.6.1':
|
||||
resolution: {integrity: sha512-8hcyA6ZoHwWXC76BoC8qVOSr8xHy00LZhZpauiD0iO0VYbVhMnED0da85lTfIULxl7Lj4c6vZgF0Wu/ed1+jlQ==}
|
||||
engines: {node: '>=v18'}
|
||||
@@ -4810,10 +4788,6 @@ packages:
|
||||
'@nuxt/kit':
|
||||
optional: true
|
||||
|
||||
unplugin@1.16.0:
|
||||
resolution: {integrity: sha512-5liCNPuJW8dqh3+DM6uNM2EI3MLLpCKp/KY+9pB5M2S2SR2qvvDHhKgBOaTWEbZTAws3CXfB0rKTIolWKL05VQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
unplugin@1.16.1:
|
||||
resolution: {integrity: sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
@@ -5127,20 +5101,8 @@ packages:
|
||||
resolution: {integrity: sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
zod@3.24.1:
|
||||
resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==}
|
||||
|
||||
snapshots:
|
||||
|
||||
'@actions/core@1.11.1':
|
||||
dependencies:
|
||||
'@actions/exec': 1.1.1
|
||||
'@actions/http-client': 2.2.3
|
||||
|
||||
'@actions/exec@1.1.1':
|
||||
dependencies:
|
||||
'@actions/io': 1.1.3
|
||||
|
||||
'@actions/github@6.0.0':
|
||||
dependencies:
|
||||
'@actions/http-client': 2.2.3
|
||||
@@ -5153,8 +5115,6 @@ snapshots:
|
||||
tunnel: 0.0.6
|
||||
undici: 5.28.5
|
||||
|
||||
'@actions/io@1.1.3': {}
|
||||
|
||||
'@ampproject/remapping@2.3.0':
|
||||
dependencies:
|
||||
'@jridgewell/gen-mapping': 0.3.8
|
||||
@@ -5433,21 +5393,6 @@ snapshots:
|
||||
|
||||
'@bcoe/v8-coverage@1.0.2': {}
|
||||
|
||||
'@codecov/bundler-plugin-core@1.7.0':
|
||||
dependencies:
|
||||
'@actions/core': 1.11.1
|
||||
'@actions/github': 6.0.0
|
||||
chalk: 4.1.2
|
||||
semver: 7.7.1
|
||||
unplugin: 1.16.0
|
||||
zod: 3.24.1
|
||||
|
||||
'@codecov/vite-plugin@1.7.0(vite@6.2.2(@types/node@22.10.7)(jiti@2.4.2)(sass@1.83.0)(terser@5.37.0)(tsx@4.19.2)(yaml@2.6.1))':
|
||||
dependencies:
|
||||
'@codecov/bundler-plugin-core': 1.7.0
|
||||
unplugin: 1.16.0
|
||||
vite: 6.2.2(@types/node@22.10.7)(jiti@2.4.2)(sass@1.83.0)(terser@5.37.0)(tsx@4.19.2)(yaml@2.6.1)
|
||||
|
||||
'@commitlint/cli@19.6.1(@types/node@22.10.7)(typescript@5.7.2)':
|
||||
dependencies:
|
||||
'@commitlint/format': 19.5.0
|
||||
@@ -10061,11 +10006,6 @@ snapshots:
|
||||
- rollup
|
||||
- supports-color
|
||||
|
||||
unplugin@1.16.0:
|
||||
dependencies:
|
||||
acorn: 8.14.0
|
||||
webpack-virtual-modules: 0.6.2
|
||||
|
||||
unplugin@1.16.1:
|
||||
dependencies:
|
||||
acorn: 8.14.0
|
||||
@@ -10416,5 +10356,3 @@ snapshots:
|
||||
yocto-queue@1.1.1: {}
|
||||
|
||||
yoctocolors-cjs@2.1.2: {}
|
||||
|
||||
zod@3.24.1: {}
|
||||
|
||||
@@ -537,6 +537,7 @@ defineExpose<VirtualListExpose>({
|
||||
padding-right: 6px;
|
||||
/* 兼容性写法,确保在各种浏览器中都有一致的滚动条空间 */
|
||||
overflow-y: scroll;
|
||||
overscroll-behavior: none; /* 禁止mac的“触底反弹”效果 */
|
||||
|
||||
/* 滚动条样式 */
|
||||
&::-webkit-scrollbar {
|
||||
|
||||
@@ -28,13 +28,33 @@
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
box-shadow: 2px 2px 12px 2px var(--box-shadow-color);
|
||||
border: 1px solid var(--box-shadow-color);
|
||||
width: auto;
|
||||
">
|
||||
<template #trigger>
|
||||
<n-popover trigger="hover" :show-arrow="false" placement="bottom">
|
||||
<n-popover
|
||||
v-model:show="recentlyTip"
|
||||
trigger="hover"
|
||||
:delay="800"
|
||||
:duration="100"
|
||||
:show-arrow="false"
|
||||
:disabled="emojiShow"
|
||||
placement="top">
|
||||
<template #trigger>
|
||||
<svg class="mr-18px"><use href="#smiling-face"></use></svg>
|
||||
</template>
|
||||
<span>表情</span>
|
||||
<div v-if="recentEmojis.length > 0" class="p-4px">
|
||||
<div class="text-xs text-gray-500 mb-4px">最近使用</div>
|
||||
<div class="flex flex-wrap gap-8px max-w-212px">
|
||||
<div
|
||||
v-for="(emoji, index) in recentEmojis"
|
||||
:key="index"
|
||||
class="emoji-item cursor-pointer flex-center"
|
||||
@click="emojiHandle(emoji, checkIsUrl(emoji) ? 'emoji-url' : 'emoji')">
|
||||
<img v-if="checkIsUrl(emoji)" :src="emoji" class="size-24px" />
|
||||
<span v-else class="text-18px">{{ emoji }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</n-popover>
|
||||
</template>
|
||||
<Emoticon @emojiHandle="emojiHandle" :all="false" />
|
||||
@@ -109,17 +129,36 @@ import { emitTo } from '@tauri-apps/api/event'
|
||||
import { useGlobalStore } from '@/stores/global.ts'
|
||||
import type { ContactItem, SessionItem } from '@/services/types'
|
||||
import { useContactStore } from '@/stores/contacts'
|
||||
import { useHistoryStore } from '@/stores/history'
|
||||
|
||||
const { id } = defineProps<{
|
||||
id: SessionItem['id']
|
||||
}>()
|
||||
const globalStore = useGlobalStore()
|
||||
const contactStore = useContactStore()
|
||||
const historyStore = useHistoryStore()
|
||||
const { open, onChange, reset } = useFileDialog()
|
||||
const MsgInputRef = ref()
|
||||
const msgInputDom = ref<HTMLInputElement | null>(null)
|
||||
const emojiShow = ref()
|
||||
const emojiShow = ref(false)
|
||||
const recentlyTip = ref(false)
|
||||
const recentEmojis = computed(() => {
|
||||
return historyStore.emoji.slice(0, 15)
|
||||
})
|
||||
const { insertNodeAtRange, triggerInputEvent, imgPaste, FileOrVideoPaste } = useCommon()
|
||||
|
||||
/**
|
||||
* 检查字符串是否为URL
|
||||
*/
|
||||
const checkIsUrl = (str: string) => {
|
||||
try {
|
||||
new URL(str)
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否为单聊
|
||||
const isSingleChat = computed(() => {
|
||||
return globalStore.currentSession?.type === RoomTypeEnum.SINGLE
|
||||
@@ -131,6 +170,13 @@ const isFriend = computed(() => {
|
||||
return contactStore.contactsList.some((contact: ContactItem) => contact.uid === id)
|
||||
})
|
||||
|
||||
// 监听emojiShow的变化,当emojiShow为true时关闭recentlyTip
|
||||
watch(emojiShow, (newValue) => {
|
||||
if (newValue === true) {
|
||||
recentlyTip.value = false
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 选择表情,并把表情插入输入框
|
||||
* @param item 选择的表情
|
||||
@@ -145,16 +191,6 @@ const emojiHandle = (item: string, type: 'emoji' | 'emoji-url' = 'emoji') => {
|
||||
// 确保输入框有焦点
|
||||
inp.focus()
|
||||
|
||||
// 检查是否为 URL
|
||||
const isUrl = (str: string) => {
|
||||
try {
|
||||
new URL(str)
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 尝试获取最后的编辑范围
|
||||
let lastEditRange: SelectionRange | null = MsgInputRef.value?.getLastEditRange()
|
||||
|
||||
@@ -186,7 +222,7 @@ const emojiHandle = (item: string, type: 'emoji' | 'emoji-url' = 'emoji') => {
|
||||
}
|
||||
|
||||
// 根据内容类型插入不同的节点
|
||||
if (isUrl(item)) {
|
||||
if (checkIsUrl(item)) {
|
||||
// 如果是URL,创建图片元素并插入
|
||||
const imgElement = document.createElement('img')
|
||||
imgElement.src = item
|
||||
@@ -215,6 +251,23 @@ const emojiHandle = (item: string, type: 'emoji' | 'emoji-url' = 'emoji') => {
|
||||
|
||||
// 保持焦点在输入框
|
||||
inp.focus()
|
||||
|
||||
// 添加到最近使用表情列表
|
||||
updateRecentEmojis(item)
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新最近使用的表情列表
|
||||
*/
|
||||
const updateRecentEmojis = (emoji: string) => {
|
||||
const currentEmojis = [...historyStore.emoji]
|
||||
const index = currentEmojis.indexOf(emoji)
|
||||
if (index !== -1) {
|
||||
currentEmojis.splice(index, 1)
|
||||
}
|
||||
currentEmojis.unshift(emoji)
|
||||
const updatedEmojis = currentEmojis.slice(0, 15)
|
||||
historyStore.setEmoji(updatedEmojis)
|
||||
}
|
||||
|
||||
const handleCap = async () => {
|
||||
@@ -250,7 +303,7 @@ onChange((files) => {
|
||||
reset()
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
if (MsgInputRef.value) {
|
||||
msgInputDom.value = MsgInputRef.value.messageInputDom
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
align="center"
|
||||
justify="center"
|
||||
class="emoji-item"
|
||||
v-for="(item, index) in [...new Set(emojiRef.historyList)]"
|
||||
v-for="(item, index) in [...new Set(emojiRef.historyList)].filter((emoji) => !checkIsUrl(emoji))"
|
||||
:key="index"
|
||||
@click.stop="chooseEmoji(item)">
|
||||
{{ item }}
|
||||
@@ -64,7 +64,36 @@
|
||||
|
||||
<!-- 我的喜欢页面 -->
|
||||
<div v-else>
|
||||
<span>暂无实现</span>
|
||||
<div v-if="emojiStore.emojiList?.length > 0">
|
||||
<span class="text-12px text-[--text-color]">我的表情包</span>
|
||||
<n-flex align="center" class="mx-6px my-12px">
|
||||
<n-flex
|
||||
align="center"
|
||||
justify="center"
|
||||
class="emoji-item"
|
||||
v-for="(item, index) in emojiStore.emojiList"
|
||||
:key="index"
|
||||
@click.stop="chooseEmoji(item.expressionUrl, 'url')">
|
||||
<n-popover trigger="hover" :delay="300" :duration="300" :show-arrow="false" placement="top">
|
||||
<template #trigger>
|
||||
<n-image
|
||||
preview-disabled
|
||||
:src="item.expressionUrl"
|
||||
class="size-full object-contain rounded-8px transition duration-300 ease-in-out transform-gpu" />
|
||||
</template>
|
||||
<n-button quaternary size="tiny" @click.stop="deleteMyEmoji(item.id)">
|
||||
删除
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<svg><use href="#delete"></use></svg>
|
||||
</n-icon>
|
||||
</template>
|
||||
</n-button>
|
||||
</n-popover>
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
</div>
|
||||
<span v-else>暂无表情包</span>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
@@ -101,6 +130,7 @@
|
||||
<script setup lang="ts">
|
||||
import { getAllTypeEmojis } from '@/utils/Emoji.ts'
|
||||
import { useHistoryStore } from '@/stores/history.ts'
|
||||
import { useEmojiStore } from '@/stores/emoji'
|
||||
import HulaEmojis from 'hula-emojis'
|
||||
|
||||
type EmojiType = {
|
||||
@@ -126,10 +156,11 @@ const emit = defineEmits(['emojiHandle'])
|
||||
const props = defineProps<{
|
||||
all: boolean
|
||||
}>()
|
||||
const { emoji, setEmoji } = useHistoryStore()
|
||||
const { emoji, setEmoji, lastEmojiTabIndex, setLastEmojiTabIndex } = useHistoryStore()
|
||||
const emojiStore = useEmojiStore()
|
||||
/** 获取米游社的表情包 */
|
||||
const emojisBbs = HulaEmojis.MihoyoBbs
|
||||
const activeIndex = ref(0)
|
||||
const activeIndex = ref(lastEmojiTabIndex)
|
||||
const currentSeriesIndex = ref(0)
|
||||
|
||||
// 生成选项卡数组
|
||||
@@ -180,6 +211,32 @@ const emojiRef = reactive<{
|
||||
allEmoji: emojiObj.value
|
||||
})
|
||||
|
||||
/**
|
||||
* 检查字符串是否为URL
|
||||
*/
|
||||
const checkIsUrl = (str: string) => {
|
||||
try {
|
||||
new URL(str)
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除我的表情包
|
||||
* @param id 表情包ID
|
||||
*/
|
||||
const deleteMyEmoji = async (id: string) => {
|
||||
try {
|
||||
await emojiStore.deleteEmoji(id)
|
||||
window.$message.success('删除表情成功')
|
||||
} catch (error) {
|
||||
console.error('删除表情失败:', error)
|
||||
window.$message.error('删除表情失败')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择表情
|
||||
* @param item
|
||||
@@ -214,6 +271,7 @@ const handleTabChange = (index: number) => {
|
||||
if (index === 1) {
|
||||
currentSeriesIndex.value = 0
|
||||
}
|
||||
setLastEmojiTabIndex(index)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -222,9 +280,10 @@ const handleTabChange = (index: number) => {
|
||||
const selectSeries = (index: number) => {
|
||||
currentSeriesIndex.value = index
|
||||
activeIndex.value = index + 1
|
||||
setLastEmojiTabIndex(index + 1)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
// try {
|
||||
// const file = await create('emoji-test.txt', { baseDir: BaseDirectory.App })
|
||||
// await file.write(new TextEncoder().encode('Hello world'))
|
||||
@@ -232,6 +291,12 @@ onMounted(() => {
|
||||
// } catch (error) {
|
||||
// console.error('Error handling file:', error)
|
||||
// }
|
||||
// 获取我的表情包列表
|
||||
await emojiStore.getEmojiList()
|
||||
// 如果上次选择的是表情包系列,设置正确的currentSeriesIndex
|
||||
if (activeIndex.value > 0) {
|
||||
currentSeriesIndex.value = activeIndex.value - 1
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import { save } from '@tauri-apps/plugin-dialog'
|
||||
import { useDownload } from '@/hooks/useDownload'
|
||||
import { useGroupStore } from '@/stores/group'
|
||||
import { useWindow } from './useWindow'
|
||||
import { useEmojiStore } from '@/stores/emoji'
|
||||
|
||||
export const useChatMain = () => {
|
||||
const { removeTag, openMsgSession, userUid } = useCommon()
|
||||
@@ -24,6 +25,7 @@ export const useChatMain = () => {
|
||||
const globalStore = useGlobalStore()
|
||||
const groupStore = useGroupStore()
|
||||
const chatStore = useChatStore()
|
||||
const emojiStore = useEmojiStore()
|
||||
const userStore = useUserStore()?.userInfo
|
||||
const { downloadFile } = useDownload()
|
||||
// const userInfo = useUserStore()?.userInfo
|
||||
@@ -51,9 +53,17 @@ export const useChatMain = () => {
|
||||
{
|
||||
label: '转发',
|
||||
icon: 'share',
|
||||
click: () => {}
|
||||
click: () => {
|
||||
window.$message.warning('暂未实现')
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '收藏',
|
||||
icon: 'collection-files',
|
||||
click: () => {
|
||||
window.$message.warning('暂未实现')
|
||||
}
|
||||
},
|
||||
{ label: '收藏', icon: 'collection-files' },
|
||||
{
|
||||
label: '回复',
|
||||
icon: 'reply',
|
||||
@@ -110,6 +120,9 @@ export const useChatMain = () => {
|
||||
} else {
|
||||
delete item.message.body.translatedText
|
||||
}
|
||||
},
|
||||
visible: (item: MessageType) => {
|
||||
return item.message.type === MsgEnum.TEXT
|
||||
}
|
||||
},
|
||||
...commonMenuList.value
|
||||
@@ -146,13 +159,6 @@ export const useChatMain = () => {
|
||||
])
|
||||
/** 图片类型右键菜单 */
|
||||
const imageMenuList = ref<OPT.RightMenu[]>([
|
||||
{
|
||||
label: '添加到表情',
|
||||
icon: 'add-expression',
|
||||
click: (item: any) => {
|
||||
console.log(item)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '复制',
|
||||
icon: 'copy',
|
||||
@@ -188,6 +194,18 @@ export const useChatMain = () => {
|
||||
window.$message.error('保存图片失败')
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '添加到表情',
|
||||
icon: 'add-expression',
|
||||
click: async (item: MessageType) => {
|
||||
const imageUrl = item.message.body.url
|
||||
if (!imageUrl) {
|
||||
window.$message.error('获取图片地址失败')
|
||||
return
|
||||
}
|
||||
await emojiStore.addEmoji(imageUrl)
|
||||
}
|
||||
}
|
||||
// {
|
||||
// label: '在文件夹中显示',
|
||||
|
||||
@@ -70,7 +70,7 @@ export default {
|
||||
/** 上传头像 */
|
||||
uploadAvatar: (data: { avatar: string }) => POST<void>(urls.uploadAvatar, data),
|
||||
/** 新增表情包 */
|
||||
addEmoji: (data: { uid: string; expressionUrl: string }) => POST<MessageType>(urls.addEmoji, data),
|
||||
addEmoji: (data: { expressionUrl: string }) => POST<MessageType>(urls.addEmoji, data),
|
||||
/** 获取表情 **/
|
||||
getEmoji: (params: { uid: string }) => GET<EmojiItem[]>(urls.getEmoji, { params }),
|
||||
/** 删除Emoji */
|
||||
|
||||
+2
-2
@@ -27,9 +27,9 @@ export const useEmojiStore = defineStore(StoresEnum.EMOJI, () => {
|
||||
const addEmoji = async (emojiUrl: string) => {
|
||||
const { uid } = userStore.userInfo
|
||||
if (!uid || !emojiUrl) return
|
||||
apis.addEmoji({ uid, expressionUrl: emojiUrl }).then((res) => {
|
||||
apis.addEmoji({ expressionUrl: emojiUrl }).then((res) => {
|
||||
if (res) {
|
||||
window.$message.success('添加成功')
|
||||
window.$message.success('添加表情成功')
|
||||
}
|
||||
})
|
||||
await getEmojiList()
|
||||
|
||||
+10
-1
@@ -5,14 +5,23 @@ export const useHistoryStore = defineStore(
|
||||
StoresEnum.HISTORY,
|
||||
() => {
|
||||
const emoji = ref<string[]>([])
|
||||
// 记录上次选择的表情选项卡索引
|
||||
const lastEmojiTabIndex = ref<number>(0)
|
||||
|
||||
const setEmoji = (item: string[]) => {
|
||||
emoji.value = item
|
||||
}
|
||||
|
||||
// 设置上次选择的表情选项卡索引
|
||||
const setLastEmojiTabIndex = (index: number) => {
|
||||
lastEmojiTabIndex.value = index
|
||||
}
|
||||
|
||||
return {
|
||||
emoji,
|
||||
setEmoji
|
||||
setEmoji,
|
||||
lastEmojiTabIndex,
|
||||
setLastEmojiTabIndex
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -7,7 +7,6 @@ import { getRootPath, getSrcPath } from './build/config/getPath'
|
||||
import vueJsx from '@vitejs/plugin-vue-jsx'
|
||||
import UnoCSS from '@unocss/vite'
|
||||
import terser from '@rollup/plugin-terser'
|
||||
import { codecovVitePlugin } from '@codecov/vite-plugin'
|
||||
import VueSetupExtend from 'vite-plugin-vue-setup-extend'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
@@ -57,12 +56,6 @@ export default defineConfig(({ mode }: ConfigEnv) => {
|
||||
resolvers: [NaiveUiResolver()],
|
||||
dts: 'src/typings/components.d.ts'
|
||||
}),
|
||||
/** 代码覆盖率插件 */
|
||||
codecovVitePlugin({
|
||||
enableBundleAnalysis: process.env.CODECOV_TOKEN !== undefined,
|
||||
bundleName: 'hula',
|
||||
uploadToken: process.env.CODECOV_TOKEN
|
||||
}),
|
||||
/** 压缩代码 */
|
||||
terser({
|
||||
format: {
|
||||
|
||||
Reference in New Issue
Block a user