mirror of
https://gitee.com/HuLaSpark/HuLa.git
synced 2024-12-01 19:28:07 +08:00
✨ feat(system): 新增群聊侧边栏
This commit is contained in:
parent
d139a3694e
commit
4f81f50e13
@ -1,2 +1,3 @@
|
||||
pub mod tray;
|
||||
pub mod window;
|
||||
pub mod window;
|
||||
pub mod plugins;
|
34
src-tauri/src/common/plugins.rs
Normal file
34
src-tauri/src/common/plugins.rs
Normal file
@ -0,0 +1,34 @@
|
||||
use tauri::{AppHandle, Manager, Runtime};
|
||||
use window_shadows::set_shadow;
|
||||
|
||||
/// 重新设置窗口属性
|
||||
#[tauri::command]
|
||||
pub fn reset_set_window<R: Runtime>(app: tauri::AppHandle<R>, label: String) {
|
||||
let window = app.get_window(&label).unwrap();
|
||||
#[cfg(any(windows, target_os = "macos"))]
|
||||
set_shadow(&window, true).unwrap();
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
window_vibrancy::apply_vibrancy(&window, NSVisualEffectMaterial::Sidebar)
|
||||
.expect("Unsupported platform! 'apply_vibrancy' is only supported on macOS");
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
window_vibrancy::apply_acrylic(&window, Some((255, 255, 255, 1)))
|
||||
.expect("Unsupported platform! 'apply_blur' is only supported on Windows");
|
||||
}
|
||||
|
||||
/// 设置托盘图标
|
||||
#[tauri::command]
|
||||
pub fn set_tray_icon(app: AppHandle) {
|
||||
app.tray_handle()
|
||||
.set_icon(tauri::Icon::Raw(
|
||||
include_bytes!("../../../public/msg.png").to_vec(),
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// 退出程序
|
||||
#[tauri::command]
|
||||
pub fn exit(app: AppHandle) {
|
||||
app.exit(0)
|
||||
}
|
@ -3,7 +3,7 @@ use tauri::{AppHandle, Manager, PhysicalPosition, SystemTrayEvent, WindowEvent};
|
||||
|
||||
|
||||
/// 打开主页
|
||||
pub fn open_home(app: &AppHandle) {
|
||||
fn open_home(app: &AppHandle) {
|
||||
let window = app.get_window("home").unwrap();
|
||||
let hide = window.is_visible().unwrap();
|
||||
let min = window.is_minimized().unwrap();
|
||||
@ -17,7 +17,7 @@ pub fn open_home(app: &AppHandle) {
|
||||
}
|
||||
|
||||
/// 还原图标
|
||||
pub fn red_icon(app: &AppHandle) {
|
||||
fn red_icon(app: &AppHandle) {
|
||||
app.tray_handle()
|
||||
.set_icon(tauri::Icon::Raw(
|
||||
include_bytes!("../../icons/icon.ico").to_vec(),
|
||||
|
@ -1,43 +1,12 @@
|
||||
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
use tauri::{AppHandle, Manager, Runtime, SystemTray};
|
||||
use window_shadows::set_shadow;
|
||||
use tauri::{SystemTray};
|
||||
use crate::common::window::set_window_attribute;
|
||||
use crate::common::plugins::{ exit, reset_set_window, set_tray_icon };
|
||||
|
||||
mod common;
|
||||
|
||||
/// 重新设置窗口属性
|
||||
#[tauri::command]
|
||||
fn reset_set_window<R: Runtime>(app: tauri::AppHandle<R>, label: String) {
|
||||
let window = app.get_window(&label).unwrap();
|
||||
#[cfg(any(windows, target_os = "macos"))]
|
||||
set_shadow(&window, true).unwrap();
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
window_vibrancy::apply_vibrancy(&window, NSVisualEffectMaterial::Sidebar)
|
||||
.expect("Unsupported platform! 'apply_vibrancy' is only supported on macOS");
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
window_vibrancy::apply_acrylic(&window, Some((255, 255, 255, 1)))
|
||||
.expect("Unsupported platform! 'apply_blur' is only supported on Windows");
|
||||
}
|
||||
|
||||
/// 设置托盘图标
|
||||
#[tauri::command]
|
||||
fn set_tray_icon(app: AppHandle) {
|
||||
app.tray_handle()
|
||||
.set_icon(tauri::Icon::Raw(
|
||||
include_bytes!("../../public/msg.png").to_vec(),
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// 退出程序
|
||||
#[tauri::command]
|
||||
fn exit(app: AppHandle) {
|
||||
app.exit(0)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let context = tauri::generate_context!();
|
||||
@ -50,7 +19,7 @@ fn main() {
|
||||
.menu(tauri::Menu::new())// 使用空菜单来替换默认的操作系统菜单
|
||||
.system_tray(system_tray)// 将 `tauri.conf.json` 上配置的图标添加到系统托盘
|
||||
.on_system_tray_event(common::tray::handler) // 注册系统托盘事件处理程序
|
||||
.invoke_handler(tauri::generate_handler![reset_set_window, set_tray_icon, exit])
|
||||
.invoke_handler(tauri::generate_handler![reset_set_window, set_tray_icon, exit]) // 使用定义的插件
|
||||
.on_window_event(|event| match event.event() {
|
||||
tauri::WindowEvent::CloseRequested { api, .. } => {
|
||||
event.window().hide().unwrap();
|
||||
|
@ -1,56 +1,77 @@
|
||||
<template>
|
||||
<!-- 好友详情 -->
|
||||
<div v-if="item.type === RoomTypeEnum.SINGLE" class="flex flex-col items-center mt-60px gap-30px select-none">
|
||||
<n-image width="146px" height="146px" class="rounded-50%" :src="item.avatar" alt="" />
|
||||
<n-flex v-if="item.type === RoomTypeEnum.SINGLE" vertical align="center" :size="30" class="mt-60px select-none">
|
||||
<n-image
|
||||
width="146px"
|
||||
height="146px"
|
||||
style="border: 2px solid #fff"
|
||||
class="rounded-50%"
|
||||
:src="item.avatar"
|
||||
alt="" />
|
||||
|
||||
<span class="text-20px">{{ item.accountName }}</span>
|
||||
<span class="text-20px text-[--text-color]">{{ item.accountName }}</span>
|
||||
|
||||
<span class="text-14px color-#909090">这个人很高冷,暂时没有留下什么</span>
|
||||
<span class="text-14px text-#909090">这个人很高冷,暂时没有留下什么</span>
|
||||
|
||||
<n-flex align="center" justify="space-between" :size="30" class="color-#606060">
|
||||
<n-flex align="center" justify="space-between" :size="30" class="text-#606060">
|
||||
<span>性别:男</span>
|
||||
<span>电话:13213213213</span>
|
||||
</n-flex>
|
||||
<!-- 选项按钮 -->
|
||||
<n-flex align="center" justify="space-between" :size="60">
|
||||
<n-icon-wrapper
|
||||
v-for="(item, index) in footerOptions"
|
||||
:key="index"
|
||||
@click="() => item.click()"
|
||||
class="cursor-pointer"
|
||||
:size="28"
|
||||
:border-radius="10"
|
||||
:color="'rgba(5, 150, 105, 0.8)'">
|
||||
<n-icon :size="20">
|
||||
<svg><use :href="item.url"></use></svg>
|
||||
</n-icon>
|
||||
</n-icon-wrapper>
|
||||
</n-flex>
|
||||
</div>
|
||||
<n-config-provider :theme="lightTheme">
|
||||
<n-flex align="center" justify="space-between" :size="60">
|
||||
<n-icon-wrapper
|
||||
v-for="(item, index) in footerOptions"
|
||||
:key="index"
|
||||
@click="item.click()"
|
||||
class="cursor-pointer"
|
||||
:size="28"
|
||||
:border-radius="10"
|
||||
:color="'rgba(5, 150, 105, 0.8)'">
|
||||
<n-icon :size="20">
|
||||
<svg><use :href="`#${item.url}`"></use></svg>
|
||||
</n-icon>
|
||||
</n-icon-wrapper>
|
||||
</n-flex>
|
||||
</n-config-provider>
|
||||
</n-flex>
|
||||
|
||||
<!-- 群聊详情 -->
|
||||
<div v-else class="flex flex-col flex-1 mt-60px gap-30px select-none p-[0_40px] box-border">
|
||||
<!-- 群聊头像以及简介 -->
|
||||
<n-flex align="center" justify="space-between">
|
||||
<n-flex align="center">
|
||||
<n-image width="120px" height="120px" class="rounded-50%" :src="item.avatar" alt="" />
|
||||
<n-image
|
||||
width="120px"
|
||||
height="120px"
|
||||
style="border: 2px solid #fff"
|
||||
class="rounded-50%"
|
||||
:src="item.avatar"
|
||||
alt="" />
|
||||
|
||||
<n-flex vertical :size="16" justify="space-between" class="text-14px color-#909090">
|
||||
<span class="text-16px color-[--text-color]">{{ item.accountName }}</span>
|
||||
<span class="text-16px text-[--text-color]">{{ item.accountName }}</span>
|
||||
<span>群号:1235873897182</span>
|
||||
<span>创建时间:2021-01-01</span>
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
|
||||
<n-icon-wrapper class="cursor-pointer" :size="40" :border-radius="10" :color="'rgba(5, 150, 105, 0.8)'">
|
||||
<n-icon :size="22">
|
||||
<svg><use href="#message"></use></svg>
|
||||
</n-icon>
|
||||
</n-icon-wrapper>
|
||||
<n-config-provider :theme="lightTheme">
|
||||
<n-icon-wrapper
|
||||
@click="footerOptions[0].click()"
|
||||
class="cursor-pointer"
|
||||
:size="40"
|
||||
:border-radius="10"
|
||||
:color="'rgba(5, 150, 105, 0.8)'">
|
||||
<n-icon :size="22">
|
||||
<svg><use href="#message"></use></svg>
|
||||
</n-icon>
|
||||
</n-icon-wrapper>
|
||||
</n-config-provider>
|
||||
</n-flex>
|
||||
|
||||
<n-flex vertical :size="20">
|
||||
<span>群成员:({{ options.length }}人)</span>
|
||||
<span class="text-[--text-color]">群成员:({{ options.length }}人)</span>
|
||||
|
||||
<n-avatar-group :options="options" :size="40" :max="4">
|
||||
<template #avatar="{ option: { name, src } }">
|
||||
@ -72,7 +93,10 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { MockItem } from '@/services/types.ts'
|
||||
import { RoomTypeEnum } from '@/enums'
|
||||
import { MittEnum, RoomTypeEnum } from '@/enums'
|
||||
import { lightTheme } from 'naive-ui'
|
||||
import router from '@/router'
|
||||
import Mitt from '@/utils/Bus.ts'
|
||||
|
||||
const props = defineProps<{
|
||||
content: any[]
|
||||
@ -82,25 +106,22 @@ const item = computed<MockItem>(() => {
|
||||
return content.value[0]
|
||||
})
|
||||
|
||||
type FooterOption = {
|
||||
url: string
|
||||
click: (...args: any[]) => void
|
||||
}
|
||||
const footerOptions = ref<FooterOption[]>([
|
||||
const footerOptions = ref<OPT.Details[]>([
|
||||
{
|
||||
url: '#message',
|
||||
url: 'message',
|
||||
click: () => {
|
||||
router.push('/message')
|
||||
Mitt.emit(MittEnum.TO_SEND_MSG, { url: 'message', id: item.value.accountId })
|
||||
}
|
||||
},
|
||||
{
|
||||
url: 'phone-telephone',
|
||||
click: () => {
|
||||
console.log(123)
|
||||
}
|
||||
},
|
||||
{
|
||||
url: '#phone-telephone',
|
||||
click: () => {
|
||||
console.log(123)
|
||||
}
|
||||
},
|
||||
{
|
||||
url: '#video-one',
|
||||
url: 'video-one',
|
||||
click: () => {
|
||||
console.log(123)
|
||||
}
|
||||
|
@ -37,7 +37,7 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { lightTheme } from 'naive-ui'
|
||||
import { MsgEnum } from '@/enums'
|
||||
import { MittEnum, MsgEnum } from '@/enums'
|
||||
import Mitt from '@/utils/Bus.ts'
|
||||
import { createFileOrVideoDom } from '@/utils/CreateDom.ts'
|
||||
|
||||
@ -221,7 +221,7 @@ const send = () => {
|
||||
window.$message.error('暂不支持混合类型消息发送')
|
||||
return
|
||||
}
|
||||
Mitt.emit('handleSendMessage', msg)
|
||||
Mitt.emit(MittEnum.SEND_MESSAGE, msg)
|
||||
msgInput.value = ''
|
||||
messageInputDom.value.innerHTML = ''
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
<!-- 顶部操作栏和显示用户名 -->
|
||||
<main
|
||||
style="box-shadow: 0 4px 4px var(--box-shadow-color)"
|
||||
class="relative z-20 flex-y-center justify-between p-[8px_20px_12px] select-none">
|
||||
class="relative z-30 flex-y-center justify-between p-[8px_20px_12px] select-none">
|
||||
<div class="color-[--text-color]">{{ activeItem.accountName }}</div>
|
||||
<!-- 顶部右边选项栏 -->
|
||||
<nav class="options flex-y-center gap-20px color-[--icon-color]">
|
||||
|
@ -2,7 +2,8 @@
|
||||
<!-- 中间聊天内容(使用虚拟列表) -->
|
||||
<n-virtual-list
|
||||
ref="virtualListInst"
|
||||
style="max-height: calc(100vh - 260px); position: relative"
|
||||
class="relative h-100vh"
|
||||
style="max-height: calc(100vh - 260px)"
|
||||
item-resizable
|
||||
padding-bottom="10px"
|
||||
:item-size="42"
|
||||
@ -101,7 +102,7 @@
|
||||
</n-modal>
|
||||
|
||||
<!-- 悬浮按钮提示(头部悬浮) // TODO 要结合已读未读功能来判断之前的信息有多少没有读,当现在的距离没有到最底部并且又有新消息来未读的时候显示下标的更多信息 (nyh -> 2024-03-07 01:27:22)-->
|
||||
<header class="float-header">
|
||||
<header class="float-header" :class="activeItem.type === RoomTypeEnum.GROUP ? 'right-220px' : 'right-50px'">
|
||||
<div class="float-box">
|
||||
<n-flex justify="space-between" align="center">
|
||||
<n-icon :color="'rgba(5,150,105,0.5)'">
|
||||
@ -113,7 +114,10 @@
|
||||
</header>
|
||||
|
||||
<!-- 悬浮按钮提示(底部悬浮) -->
|
||||
<footer class="float-footer" v-if="floatFooter && newMsgNum > 0">
|
||||
<footer
|
||||
class="float-footer"
|
||||
v-if="floatFooter && newMsgNum > 0"
|
||||
:class="activeItem.type === RoomTypeEnum.GROUP ? 'right-220px' : 'right-50px'">
|
||||
<div class="float-box" :class="{ max: newMsgNum > 99 }" @click="scrollBottom">
|
||||
<n-flex justify="space-between" align="center">
|
||||
<n-icon :color="newMsgNum > 99 ? '#ce304f' : 'rgba(5,150,105,0.5)'">
|
||||
@ -127,7 +131,7 @@
|
||||
</footer>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { MsgEnum, RoomTypeEnum } from '@/enums'
|
||||
import { MittEnum, MsgEnum, RoomTypeEnum } from '@/enums'
|
||||
import { MockItem } from '@/services/types.ts'
|
||||
import Mitt from '@/utils/Bus.ts'
|
||||
import { VirtualListInst } from 'naive-ui'
|
||||
@ -159,7 +163,7 @@ const newMsgNum = ref(0)
|
||||
const itemComputed = computed(() => {
|
||||
return items.value.filter((item) => item.accountId !== userId.value).length
|
||||
})
|
||||
/* 虚拟列表的距离 */
|
||||
/* 虚拟列表 */
|
||||
const virtualListInst = ref<VirtualListInst>()
|
||||
const { activeItem } = defineProps<{
|
||||
activeItem: MockItem
|
||||
@ -390,7 +394,7 @@ onMounted(() => {
|
||||
invoke('set_tray_icon').catch((error) => {
|
||||
console.error('设置图标失败:', error)
|
||||
})
|
||||
Mitt.on('handleSendMessage', (event) => {
|
||||
Mitt.on(MittEnum.SEND_MESSAGE, (event) => {
|
||||
handleSendMessage(event)
|
||||
})
|
||||
window.addEventListener('click', closeMenu, true)
|
||||
|
86
src/components/rightBox/chatBox/ChatSidebar.vue
Normal file
86
src/components/rightBox/chatBox/ChatSidebar.vue
Normal file
@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<!--! 这里最好不要使用n-flex,滚动高度会有问题 -->
|
||||
<main
|
||||
v-if="activeItem?.type === RoomTypeEnum.GROUP"
|
||||
style="border-left: 1px solid var(--line-color)"
|
||||
class="item-box">
|
||||
<n-flex v-if="!isSearch" align="center" justify="space-between" class="pr-8px pl-8px h-42px">
|
||||
<span class="text-14px">群聊成员</span>
|
||||
<svg @click="handleSearch" class="size-14px"><use href="#search"></use></svg>
|
||||
</n-flex>
|
||||
|
||||
<n-flex v-else align="center" class="pr-8px h-42px">
|
||||
<n-input
|
||||
@blur="isSearch = false"
|
||||
ref="inputInstRef"
|
||||
v-model:value="searchRef"
|
||||
autofocus
|
||||
placeholder="搜索"
|
||||
type="text"
|
||||
size="tiny"
|
||||
class="h-26px w-95% lh-26px rounded-6px">
|
||||
<template #prefix>
|
||||
<svg class="w-12px h-12px"><use href="#search"></use></svg>
|
||||
</template>
|
||||
</n-input>
|
||||
</n-flex>
|
||||
|
||||
<n-virtual-list
|
||||
ref="virtualListInst"
|
||||
style="max-height: calc(100vh - 130px)"
|
||||
item-resizable
|
||||
:item-size="42"
|
||||
:items="MockList">
|
||||
<template #default="{ item }">
|
||||
<n-flex :key="item.key" :size="10" align="center" class="item">
|
||||
<n-avatar lazy round :size="24" :src="item.avatar"></n-avatar>
|
||||
<span class="text-12px">{{ item.accountName }}</span>
|
||||
</n-flex>
|
||||
</template>
|
||||
</n-virtual-list>
|
||||
</main>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { RoomTypeEnum } from '@/enums'
|
||||
import { MockItem } from '@/services/types.ts'
|
||||
import { MockList } from '@/mock'
|
||||
import { InputInst } from 'naive-ui'
|
||||
|
||||
const isSearch = ref(false)
|
||||
const searchRef = ref('')
|
||||
const inputInstRef = ref<InputInst | null>(null)
|
||||
const { activeItem } = defineProps<{
|
||||
activeItem?: MockItem
|
||||
}>()
|
||||
|
||||
const handleSearch = () => {
|
||||
isSearch.value = !isSearch.value
|
||||
nextTick(() => {
|
||||
inputInstRef.value?.select()
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.item-box {
|
||||
@apply flex flex-col w-180px h-100vh z-20 p-[12px_0_12px_6px] box-border select-none text-[--text-color];
|
||||
.item {
|
||||
height: 42px;
|
||||
padding-left: 4px;
|
||||
width: 95%;
|
||||
box-sizing: border-box;
|
||||
border-radius: 6px;
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
background-color: var(--bg-group-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*! 修改naive-ui虚拟列表滚动条的宽度 */
|
||||
:deep(
|
||||
.n-scrollbar > .n-scrollbar-rail.n-scrollbar-rail--vertical,
|
||||
.n-scrollbar + .n-scrollbar-rail.n-scrollbar-rail--vertical
|
||||
) {
|
||||
width: 6px;
|
||||
}
|
||||
</style>
|
@ -1,15 +1,17 @@
|
||||
<template>
|
||||
<!-- 头部 -->
|
||||
<ChatHeader :active-item="activeItemRef" />
|
||||
<!-- 中间聊天框内容 -->
|
||||
<ChatMain :active-item="activeItemRef" />
|
||||
<!-- 输入框和操作列表 -->
|
||||
<ChatFooter />
|
||||
<n-flex :size="0" class="h-full">
|
||||
<n-flex vertical :size="0" class="flex-1">
|
||||
<!-- 中间聊天框内容 -->
|
||||
<ChatMain :active-item="activeItemRef" />
|
||||
<!-- 输入框和操作列表 -->
|
||||
<ChatFooter class="flex-1" />
|
||||
</n-flex>
|
||||
<ChatSidebar :active-item="activeItemRef" />
|
||||
</n-flex>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import ChatFooter from './ChatFooter.vue'
|
||||
import ChatHeader from './ChatHeader.vue'
|
||||
import ChatMain from './ChatMain.vue'
|
||||
import { MockItem } from '@/services/types.ts'
|
||||
import { listen } from '@tauri-apps/api/event'
|
||||
import { appWindow } from '@tauri-apps/api/window'
|
||||
@ -27,3 +29,12 @@ listen(appWindow.label, (e) => {
|
||||
activeItemRef.value = e.payload as any
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
/*! 修改naive-ui虚拟列表滚动条的间距 */
|
||||
:deep(
|
||||
.n-scrollbar > .n-scrollbar-rail.n-scrollbar-rail--vertical,
|
||||
.n-scrollbar + .n-scrollbar-rail.n-scrollbar-rail--vertical
|
||||
) {
|
||||
right: 0;
|
||||
}
|
||||
</style>
|
||||
|
@ -83,7 +83,7 @@ import { useWindow } from '@/hooks/useWindow.ts'
|
||||
import { alwaysOnTop } from '@/stores/alwaysOnTop.ts'
|
||||
import { setting } from '@/stores/setting.ts'
|
||||
import { emit, listen } from '@tauri-apps/api/event'
|
||||
import { CloseBxEnum, EventEnum } from '@/enums'
|
||||
import { CloseBxEnum, EventEnum, MittEnum } from '@/enums'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { PersistedStateOptions } from 'pinia-plugin-persistedstate'
|
||||
import { invoke } from '@tauri-apps/api/tauri'
|
||||
@ -132,14 +132,17 @@ watchEffect(() => {
|
||||
if (alwaysOnTopStatus.value) {
|
||||
appWindow.setAlwaysOnTop(alwaysOnTopStatus.value as boolean)
|
||||
}
|
||||
listen(EventEnum.EXIT, async () => {
|
||||
listen(EventEnum.LOGOUT, async () => {
|
||||
/* 退出账号前把窗口全部关闭 */
|
||||
if (appWindow.label !== 'login') {
|
||||
await invoke('exit').catch((error) => {
|
||||
console.error('退出失败:', error)
|
||||
})
|
||||
await appWindow.close()
|
||||
}
|
||||
})
|
||||
listen(EventEnum.EXIT, async () => {
|
||||
await invoke('exit').catch((error) => {
|
||||
console.error('退出失败:', error)
|
||||
})
|
||||
})
|
||||
listen(EventEnum.CLOSE_HOME, (e) => {
|
||||
trayRef.type = (e.payload as STO.Setting['tray']).type
|
||||
trayRef.notTips = (e.payload as STO.Setting['tray']).notTips
|
||||
@ -186,7 +189,7 @@ const restoreWindow = async () => {
|
||||
/* 收缩窗口 */
|
||||
const shrinkWindow = async () => {
|
||||
/*使用mitt给兄弟组件更新*/
|
||||
Mitt.emit('shrinkWindow', shrinkStatus.value)
|
||||
Mitt.emit(MittEnum.SHRINK_WINDOW, shrinkStatus.value)
|
||||
if (shrinkStatus.value) {
|
||||
await resizeWindow('home', 310, 700)
|
||||
} else {
|
||||
|
@ -17,13 +17,6 @@ export enum RCodeEnum {
|
||||
/**业务出现问题*/
|
||||
BUSINESS_EXCEPTION = '600'
|
||||
}
|
||||
/**URL*/
|
||||
export enum URLEnum {
|
||||
/**用户*/
|
||||
USER = '/user',
|
||||
/**文章*/
|
||||
ARTICLE = '/article'
|
||||
}
|
||||
|
||||
/** tauri原生跨窗口通信时传输的类型 */
|
||||
export enum EventEnum {
|
||||
@ -35,6 +28,8 @@ export enum EventEnum {
|
||||
WIN_SHOW = 'winShow',
|
||||
/** 退出程序 */
|
||||
EXIT = 'exit',
|
||||
/** 退出账号 */
|
||||
LOGOUT = 'logout',
|
||||
/** 设置在线状态 */
|
||||
SET_OL_STS = 'setOnlineStatus',
|
||||
/** 独立窗口 */
|
||||
@ -43,6 +38,22 @@ export enum EventEnum {
|
||||
CLOSE_HOME = 'closeHome'
|
||||
}
|
||||
|
||||
/** Mitt兄弟组件通信 */
|
||||
export enum MittEnum {
|
||||
/** 更新消息数量 */
|
||||
UPDATE_MSG_TOTAL = 'updateMsgTotal',
|
||||
/** 显示消息框 */
|
||||
MSG_BOX_SHOW = 'msgBoxShow',
|
||||
/** 发送消息 */
|
||||
SEND_MESSAGE = 'sendMessage',
|
||||
/** 跳到发送信息 */
|
||||
TO_SEND_MSG = 'toSendMsg',
|
||||
/** 缩小窗口 */
|
||||
SHRINK_WINDOW = 'shrinkWindow',
|
||||
/** 详情页面显示 */
|
||||
DETAILS_SHOW = 'detailsShow'
|
||||
}
|
||||
|
||||
/** 主题类型 */
|
||||
export enum ThemeEnum {
|
||||
/** 亮色 */
|
||||
@ -55,11 +66,11 @@ export enum ThemeEnum {
|
||||
|
||||
/* pinia存储的名称 */
|
||||
export enum StoresEnum {
|
||||
/* 置顶 */
|
||||
/** 置顶 */
|
||||
ALWAYS_ON_TOP = 'alwaysOnTop',
|
||||
/* 设置 */
|
||||
/** 设置 */
|
||||
SETTING = 'setting',
|
||||
/* 在线状态 */
|
||||
/** 在线状态 */
|
||||
ONLINE_STATUS = 'onlineStatus'
|
||||
}
|
||||
|
||||
@ -90,7 +101,7 @@ export enum RoomTypeEnum {
|
||||
/** 1群聊 */
|
||||
GROUP = 1,
|
||||
/** 2单聊 */
|
||||
SINGLE
|
||||
SINGLE = 2
|
||||
}
|
||||
|
||||
/** 关闭窗口的行为 */
|
||||
|
@ -40,6 +40,7 @@
|
||||
<script setup lang="ts">
|
||||
import Mitt from '@/utils/Bus.ts'
|
||||
import router from '@/router'
|
||||
import { MittEnum } from '@/enums'
|
||||
|
||||
// const minWidth = 160 // 设置最小宽度
|
||||
// const maxWidth = 320 // 设置最大宽度
|
||||
@ -50,7 +51,7 @@ const width = ref(250) // 初始化宽度
|
||||
const shrinkStatus = ref(false)
|
||||
|
||||
// todo 1.了解这里是怎么实现的 2.修改拖拽放大缩小的事件
|
||||
Mitt.on('shrinkWindow', (event) => {
|
||||
Mitt.on(MittEnum.SHRINK_WINDOW, (event) => {
|
||||
shrinkStatus.value = event as boolean
|
||||
width.value = 250
|
||||
})
|
||||
|
@ -11,6 +11,7 @@ import Center from './center/index.vue'
|
||||
import Left from './left/index.vue'
|
||||
import Right from './right/index.vue'
|
||||
import Mitt from '@/utils/Bus'
|
||||
import { MittEnum } from '@/enums'
|
||||
|
||||
/* todo home窗口创建的时候已经设置了resizable: true,可以调整大小了,但是还是不可以调整大小 */
|
||||
const shrinkStatus = ref(false)
|
||||
@ -18,7 +19,7 @@ const shrinkStatus = ref(false)
|
||||
* event默认如果没有传递值就为true,所以shrinkStatus的值为false就会发生值的变化
|
||||
* 因为shrinkStatus的值为false,所以v-if="!shrinkStatus" 否则right组件刚开始渲染的时候不会显示
|
||||
* */
|
||||
Mitt.on('shrinkWindow', (event) => {
|
||||
Mitt.on(MittEnum.SHRINK_WINDOW, (event) => {
|
||||
shrinkStatus.value = event as boolean
|
||||
})
|
||||
</script>
|
||||
|
@ -79,7 +79,7 @@ const moreList = ref<OPT.L.MoreList[]>([
|
||||
/* 给一点延迟,不然创建登录窗口后还没有来得及设置阴影和圆角效果 */
|
||||
delay(async () => {
|
||||
/* 通知全部打开的窗口然后关闭 */
|
||||
await emit(EventEnum.EXIT)
|
||||
await emit(EventEnum.LOGOUT)
|
||||
}, 300)
|
||||
})
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ import { delay } from 'lodash-es'
|
||||
import { useWindow } from '@/hooks/useWindow.ts'
|
||||
import router from '@/router'
|
||||
import Mitt from '@/utils/Bus.ts'
|
||||
import { EventEnum, ThemeEnum } from '@/enums'
|
||||
import { EventEnum, MittEnum, ThemeEnum } from '@/enums'
|
||||
import { listen } from '@tauri-apps/api/event'
|
||||
import { itemsTop, itemsBottom, moreList } from './config.ts'
|
||||
import { onlineStatus } from '@/stores/onlineStatus.ts'
|
||||
@ -170,13 +170,16 @@ const followOS = () => {
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
Mitt.on('updateMsgTotal', (event) => {
|
||||
Mitt.on(MittEnum.UPDATE_MSG_TOTAL, (event) => {
|
||||
itemsTop.value.find((item) => {
|
||||
if (item.url === 'message') {
|
||||
item.badge = event as number
|
||||
}
|
||||
})
|
||||
})
|
||||
Mitt.on(MittEnum.TO_SEND_MSG, (event: any) => {
|
||||
activeItem.value = event.url
|
||||
})
|
||||
if (themes.value.pattern === ThemeEnum.OS) {
|
||||
followOS()
|
||||
prefers.addEventListener('change', followOS)
|
||||
@ -226,7 +229,7 @@ onMounted(async () => {
|
||||
pageJumps(activeItem.value)
|
||||
window.addEventListener('click', closeMenu, true)
|
||||
|
||||
Mitt.on('shrinkWindow', (event) => {
|
||||
Mitt.on(MittEnum.SHRINK_WINDOW, (event) => {
|
||||
shrinkStatus.value = event as boolean
|
||||
})
|
||||
await listen(EventEnum.WIN_SHOW, (e) => {
|
||||
|
@ -18,7 +18,7 @@ import Mitt from '@/utils/Bus.ts'
|
||||
import router from '@/router'
|
||||
import { setting } from '@/stores/setting.ts'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { EventEnum, ThemeEnum } from '@/enums'
|
||||
import { EventEnum, MittEnum, ThemeEnum } from '@/enums'
|
||||
import { listen } from '@tauri-apps/api/event'
|
||||
import { appWindow } from '@tauri-apps/api/window'
|
||||
|
||||
@ -67,14 +67,14 @@ watchEffect(() => {
|
||||
|
||||
onMounted(() => {
|
||||
if (isChat) {
|
||||
Mitt.on('msgBoxShow', (event: any) => {
|
||||
Mitt.on(MittEnum.MSG_BOX_SHOW, (event: any) => {
|
||||
msgBoxShow.value = event.msgBoxShow
|
||||
activeItem.value = event.item
|
||||
})
|
||||
}
|
||||
|
||||
if (isDetails) {
|
||||
Mitt.on('detailsShow', (event: any) => {
|
||||
Mitt.on(MittEnum.DETAILS_SHOW, (event: any) => {
|
||||
DetailsContent.value = event.data
|
||||
detailsShow.value = event.detailsShow as boolean
|
||||
})
|
||||
|
@ -9,9 +9,9 @@
|
||||
}
|
||||
@mixin float($position: top) {
|
||||
@if $position == bottom {
|
||||
@apply fixed z-10 bottom-210px right-50px w-fit select-none text-#059669 cursor-pointer;
|
||||
@apply fixed z-10 bottom-210px w-fit select-none text-#059669 cursor-pointer;
|
||||
} @else {
|
||||
@apply fixed z-10 top-80px right-50px w-fit select-none text-#059669 cursor-pointer;
|
||||
@apply fixed z-10 top-80px w-fit select-none text-#059669 cursor-pointer;
|
||||
}
|
||||
}
|
||||
.chat-single:first-child {
|
||||
|
@ -48,6 +48,8 @@
|
||||
// 系统托盘hover样式
|
||||
--tray-hover: #eee;
|
||||
--tray-hover-e: #f5dce1;
|
||||
// 群聊列表hover颜色
|
||||
--bg-group-hover: #e3e3e3;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] {
|
||||
@ -99,6 +101,8 @@ html[data-theme='dark'] {
|
||||
// 系统托盘hover样式
|
||||
--tray-hover: #3b3b3b;
|
||||
--tray-hover-e: #bb8188;
|
||||
// 群聊列表hover颜色
|
||||
--bg-group-hover: #3f3f3f;
|
||||
}
|
||||
/*! end */
|
||||
// 线性动画
|
||||
@ -160,13 +164,18 @@ html[data-theme='dark'] {
|
||||
}
|
||||
/*!end*/
|
||||
|
||||
/*! 修改复选框的样式 */
|
||||
/*! 修改naive-ui复选框的样式 */
|
||||
:deep(.n-checkbox .n-checkbox-box) {
|
||||
border-radius: 50%;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
/*! 修改naive-ui滚动条的间距 */
|
||||
:deep(.n-scrollbar > .n-scrollbar-rail.n-scrollbar-rail--vertical, .n-scrollbar + .n-scrollbar-rail.n-scrollbar-rail--vertical) {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
/*! 通用菜单项目样式 */
|
||||
@mixin menu-item-style($position: fixed) {
|
||||
position: $position;
|
||||
|
2
src/typings/components.d.ts
vendored
2
src/typings/components.d.ts
vendored
@ -12,6 +12,7 @@ declare module 'vue' {
|
||||
ChatFooter: typeof import('./../components/rightBox/chatBox/ChatFooter.vue')['default']
|
||||
ChatHeader: typeof import('./../components/rightBox/chatBox/ChatHeader.vue')['default']
|
||||
ChatMain: typeof import('./../components/rightBox/chatBox/ChatMain.vue')['default']
|
||||
ChatSidebar: typeof import('./../components/rightBox/chatBox/ChatSidebar.vue')['default']
|
||||
ContextMenu: typeof import('./../components/common/ContextMenu.vue')['default']
|
||||
Details: typeof import('./../components/rightBox/Details.vue')['default']
|
||||
Image: typeof import('./../components/rightBox/renderMessage/Image.vue')['default']
|
||||
@ -55,5 +56,6 @@ declare module 'vue' {
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
Text: typeof import('./../components/rightBox/renderMessage/Text.vue')['default']
|
||||
UserSidebar: typeof import('./../components/rightBox/chatBox/UserSidebar.vue')['default']
|
||||
}
|
||||
}
|
||||
|
6
src/typings/options.d.ts
vendored
6
src/typings/options.d.ts
vendored
@ -41,6 +41,12 @@ declare namespace OPT {
|
||||
click?: (...args: any[]) => void
|
||||
}
|
||||
|
||||
/* 详情页选项 */
|
||||
type Details = {
|
||||
url: string
|
||||
click: (...args: any[]) => void
|
||||
}
|
||||
|
||||
/* 在线状态 */
|
||||
type Online = {
|
||||
url: string
|
||||
|
@ -82,6 +82,7 @@
|
||||
<script setup lang="ts">
|
||||
import Mitt from '@/utils/Bus.ts'
|
||||
import { MockList } from '@/mock/index.ts'
|
||||
import { MittEnum } from '@/enums'
|
||||
|
||||
const menuList = ref([
|
||||
{ label: '添加分组', icon: 'plus' },
|
||||
@ -106,7 +107,7 @@ const handleClick = (index: number, type: number) => {
|
||||
: friendsList.value.filter((item) => item.key === index),
|
||||
detailsShow: detailsShow.value
|
||||
}
|
||||
Mitt.emit('detailsShow', data)
|
||||
Mitt.emit(MittEnum.DETAILS_SHOW, data)
|
||||
}
|
||||
// todo 需要循环数组来展示分组
|
||||
const showMenu = (event: MouseEvent) => {
|
||||
@ -119,7 +120,7 @@ const handleSelect = (event: MouseEvent) => {
|
||||
|
||||
onUnmounted(() => {
|
||||
detailsShow.value = false
|
||||
Mitt.emit('detailsShow', detailsShow.value)
|
||||
Mitt.emit(MittEnum.DETAILS_SHOW, detailsShow.value)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -3,7 +3,7 @@ import Mitt from '@/utils/Bus.ts'
|
||||
import { useWindow } from '@/hooks/useWindow.ts'
|
||||
import { MockItem } from '@/services/types.ts'
|
||||
import { emit, listen } from '@tauri-apps/api/event'
|
||||
import { EventEnum } from '@/enums'
|
||||
import { EventEnum, MittEnum } from '@/enums'
|
||||
import { WebviewWindow } from '@tauri-apps/api/window'
|
||||
import { delay } from 'lodash-es'
|
||||
|
||||
@ -20,7 +20,7 @@ watchEffect(async () => {
|
||||
await listen(EventEnum.WIN_CLOSE, (e) => {
|
||||
aloneWin.value.delete(e.payload)
|
||||
})
|
||||
Mitt.on('shrinkWindow', async (event) => {
|
||||
Mitt.on(MittEnum.SHRINK_WINDOW, async (event) => {
|
||||
shrinkStatus.value = event as boolean
|
||||
})
|
||||
})
|
||||
@ -30,12 +30,12 @@ const handleMsgClick = (item: MockItem) => {
|
||||
msgBoxShow.value = true
|
||||
activeItem.value = item.key
|
||||
const data = { msgBoxShow, item }
|
||||
Mitt.emit('msgBoxShow', data)
|
||||
Mitt.emit(MittEnum.MSG_BOX_SHOW, data)
|
||||
// 判断是否打开了独立的窗口
|
||||
if (aloneWin.value.has(EventEnum.ALONE + item.key)) {
|
||||
checkWinExist(EventEnum.ALONE + item.key).then()
|
||||
activeItem.value = -1
|
||||
Mitt.emit('msgBoxShow', { item: -1 })
|
||||
Mitt.emit(MittEnum.MSG_BOX_SHOW, { item: -1 })
|
||||
}
|
||||
// 如果是收缩页面状态点击消息框就直接变成独立窗口
|
||||
if (shrinkStatus.value) {
|
||||
@ -54,7 +54,7 @@ const handleMsgDblclick = (item: MockItem) => {
|
||||
const openAloneWin = async (item: MockItem) => {
|
||||
if (activeItem.value === item.key) {
|
||||
activeItem.value = -1
|
||||
Mitt.emit('msgBoxShow', { item: -1 })
|
||||
Mitt.emit(MittEnum.MSG_BOX_SHOW, { item: -1 })
|
||||
}
|
||||
// TODO 传递用户信息(这里的label最好使用用户唯一的id来代替) (nyh -> 2024-03-18 12:18:10)
|
||||
await createWebviewWindow(item.accountName, EventEnum.ALONE + item.key, 720, 800)
|
||||
|
@ -46,11 +46,16 @@ import Mitt from '@/utils/Bus.ts'
|
||||
import { VueDraggable } from 'vue-draggable-plus'
|
||||
import { MockList } from '@/mock'
|
||||
import { activeItem, handleMsgClick, menuList, specialMenuList, handleMsgDblclick } from './config.ts'
|
||||
import { MittEnum } from '@/enums'
|
||||
|
||||
const msgTotal = ref(0)
|
||||
|
||||
watchEffect(() => {
|
||||
Mitt.emit('updateMsgTotal', msgTotal.value)
|
||||
Mitt.emit(MittEnum.UPDATE_MSG_TOTAL, msgTotal.value)
|
||||
Mitt.on(MittEnum.TO_SEND_MSG, (event: any) => {
|
||||
// TODO 如果当前信息栏中没有该信息就创建一条 (nyh -> 2024-03-22 01:05:22)
|
||||
activeItem.value = event.id
|
||||
})
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
|
Loading…
Reference in New Issue
Block a user