feat(system): 新增群聊侧边栏

This commit is contained in:
nongyehong 2024-03-22 23:58:54 +08:00
parent d139a3694e
commit 4f81f50e13
24 changed files with 300 additions and 132 deletions

View File

@ -1,2 +1,3 @@
pub mod tray;
pub mod window;
pub mod window;
pub mod plugins;

View 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)
}

View File

@ -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(),

View File

@ -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();

View File

@ -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)
}

View File

@ -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 = ''
}

View File

@ -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]">

View File

@ -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)

View 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>

View File

@ -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>

View File

@ -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 {

View File

@ -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
}
/** 关闭窗口的行为 */

View File

@ -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
})

View File

@ -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>

View File

@ -79,7 +79,7 @@ const moreList = ref<OPT.L.MoreList[]>([
/* 给一点延迟,不然创建登录窗口后还没有来得及设置阴影和圆角效果 */
delay(async () => {
/* 通知全部打开的窗口然后关闭 */
await emit(EventEnum.EXIT)
await emit(EventEnum.LOGOUT)
}, 300)
})
}

View File

@ -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) => {

View File

@ -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
})

View File

@ -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 {

View File

@ -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;

View File

@ -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']
}
}

View File

@ -41,6 +41,12 @@ declare namespace OPT {
click?: (...args: any[]) => void
}
/* 详情页选项 */
type Details = {
url: string
click: (...args: any[]) => void
}
/* 在线状态 */
type Online = {
url: string

View File

@ -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>

View File

@ -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)

View File

@ -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(() => {