@@ -38,11 +38,9 @@ body:
|
||||
- type: textarea
|
||||
id: info
|
||||
attributes:
|
||||
label: '☄️ 完整的 `tauri info` 输出'
|
||||
description: '请运行 “tauri info” 在控制台等待输出完毕,并将输出内容复制到此处'
|
||||
label: '☄️ 完整的 `pnpm tauri info` 输出'
|
||||
description: '请运行 “pnpm tauri info” 在控制台等待输出完毕,并将输出内容复制到此处'
|
||||
render: text
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
|
||||
6
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
6
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -38,11 +38,9 @@ body:
|
||||
- type: textarea
|
||||
id: info
|
||||
attributes:
|
||||
label: '☄️ intact `tauri info` output'
|
||||
description: 'Please run "tauri info" in the console and wait for the output to finish, then copy the output here'
|
||||
label: '☄️ intact `pnpm tauri info` output'
|
||||
description: 'Please run "pnpm tauri info" in the console and wait for the output to finish, then copy the output here'
|
||||
render: text
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
|
||||
6
.github/ISSUE_TEMPLATE/bug_report_cn.yml
vendored
6
.github/ISSUE_TEMPLATE/bug_report_cn.yml
vendored
@@ -38,11 +38,9 @@ body:
|
||||
- type: textarea
|
||||
id: info
|
||||
attributes:
|
||||
label: '☄️ 完整的 `tauri info` 输出'
|
||||
description: '请运行 “tauri info” 在控制台等待输出完毕,并将输出内容复制到此处'
|
||||
label: '☄️ 完整的 `pnpm tauri info` 输出'
|
||||
description: '请运行 “pnpm tauri info” 在控制台等待输出完毕,并将输出内容复制到此处'
|
||||
render: text
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"author": {
|
||||
"name": "HuLaSpark团队",
|
||||
"email": "2439646234@qq.com",
|
||||
"url": "https://github.com/HuLaSpark/HuLa"
|
||||
"url": "https://github.com/HuLaSpark"
|
||||
},
|
||||
"scripts": {
|
||||
"========= 启动vue(tauri项目会连带执行不需要单独执行) =========": "",
|
||||
@@ -28,8 +28,8 @@
|
||||
"tauri:build:debug": "tauri build --debug",
|
||||
"========= 生成icon =========": "",
|
||||
"tauri:icon": "tauri icon hula.png",
|
||||
"========= 安装依赖前执行校验包管理器 =========": "",
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"========= 安装依赖前执行 =========": "",
|
||||
"preinstall": "npx only-allow pnpm && node scripts/check-env.js",
|
||||
"========= 使用commit来进行代码提交 =========": "",
|
||||
"commit": "git add . && git-cz",
|
||||
"========= 校验代码规范 =========": "",
|
||||
|
||||
25
scripts/check-env.js
Normal file
25
scripts/check-env.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import { existsSync, writeFileSync } from 'fs'
|
||||
import { join } from 'path'
|
||||
|
||||
// 用于写入.env.local配置文件,该文件默认不会被git管理,所以不必担心会提交到远程仓库
|
||||
const envPath = join(process.cwd(), '.env.local')
|
||||
|
||||
if (!existsSync(envPath)) {
|
||||
const defaultEnvContent = `# 有道云翻译key
|
||||
VITE_YOUDAO_APP_KEY=
|
||||
VITE_YOUDAO_APP_SECRET=
|
||||
# 腾讯云翻译key
|
||||
VITE_TENCENT_API_KEY=
|
||||
VITE_TENCENT_SECRET_ID=
|
||||
`
|
||||
|
||||
try {
|
||||
writeFileSync(envPath, defaultEnvContent, 'utf8')
|
||||
console.log('✨ 成功创建.env.local文件')
|
||||
} catch (error) {
|
||||
console.error('❌ 创建.env.local文件失败:', error)
|
||||
process.exit(1)
|
||||
}
|
||||
} else {
|
||||
console.log('✅ .env.local文件已存在')
|
||||
}
|
||||
@@ -5,9 +5,11 @@
|
||||
<n-flex vertical :size="20" align="center">
|
||||
<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="" />
|
||||
<span>在线状态</span>
|
||||
<n-flex v-if="activeStatus" :size="6" align="center" style="margin-left: -4px" class="item-hover">
|
||||
<n-badge :color="activeStatus === OnlineEnum.ONLINE ? '#1ab292' : '#909090'" dot />
|
||||
<p class="text-(12px [--text-color])">
|
||||
{{ activeStatus === OnlineEnum.ONLINE ? '在线' : '离线' }}
|
||||
</p>
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
|
||||
@@ -57,9 +59,11 @@
|
||||
<script setup lang="ts">
|
||||
import { useBadgeInfo, useUserInfo } from '@/hooks/useCached.ts'
|
||||
import { AvatarUtils } from '@/utils/avatarUtils'
|
||||
import { OnlineEnum } from '@/enums/index.ts'
|
||||
|
||||
const { uid } = defineProps<{
|
||||
uid: number
|
||||
activeStatus?: OnlineEnum
|
||||
}>()
|
||||
const isCurrentUser = computed(() => useUserInfo(uid).value)
|
||||
const avatarSrc = computed(() => AvatarUtils.getAvatarUrl(useUserInfo(uid).value.avatar as string))
|
||||
|
||||
@@ -135,7 +135,9 @@
|
||||
<!-- 群聊成员列表 -->
|
||||
<div class="box-item cursor-default">
|
||||
<n-flex vertical justify="center" :size="16">
|
||||
<p class="text-(14px --text-color)">群成员</p>
|
||||
<p class="text-(14px --text-color)">
|
||||
{{ activeItem.hotFlag !== IsAllUserEnum.Yes ? '群成员' : '频道成员' }}
|
||||
</p>
|
||||
|
||||
<n-flex align="center" justify="start" :size="[24, 20]">
|
||||
<template v-for="(item, _index) in userList" :key="_index">
|
||||
@@ -149,7 +151,10 @@
|
||||
</n-flex>
|
||||
</div>
|
||||
|
||||
<div class="box-item cursor-pointer" @click="handleDelete(RoomActEnum.DELETE_RECORD)">
|
||||
<div
|
||||
v-if="activeItem.hotFlag !== IsAllUserEnum.Yes"
|
||||
class="box-item cursor-pointer"
|
||||
@click="handleDelete(RoomActEnum.DELETE_RECORD)">
|
||||
<p>删除聊天记录</p>
|
||||
</div>
|
||||
|
||||
@@ -160,7 +165,11 @@
|
||||
<p class="color-#d03553">退出群聊</p>
|
||||
</div>
|
||||
|
||||
<p class="m-[0_auto] text-(12px #13987f) mt-20px cursor-pointer">被骚扰了? 举报该群</p>
|
||||
<p
|
||||
v-if="activeItem.hotFlag !== IsAllUserEnum.Yes"
|
||||
class="m-[0_auto] text-(12px #13987f) mt-20px cursor-pointer">
|
||||
被骚扰了? 举报该群
|
||||
</p>
|
||||
</template>
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
@@ -79,18 +79,12 @@
|
||||
:special-menu="report">
|
||||
<n-flex @click="selectKey = item.uid" :key="item.uid" :size="10" align="center" class="item">
|
||||
<n-avatar
|
||||
lazy
|
||||
round
|
||||
class="grayscale"
|
||||
:class="{ 'grayscale-0': item.activeStatus === OnlineEnum.ONLINE }"
|
||||
:color="'#fff'"
|
||||
:size="24"
|
||||
:src="AvatarUtils.getAvatarUrl(item.avatar)"
|
||||
fallback-src="/logo.png"
|
||||
:render-placeholder="() => null"
|
||||
:intersection-observer-options="{
|
||||
root: '#image-chat-sidebar'
|
||||
}" />
|
||||
:src="AvatarUtils.getAvatarUrl(item.avatar)" />
|
||||
<p class="text-12px truncate flex-1">{{ item.name }}</p>
|
||||
<div
|
||||
v-if="item.roleId === RoleEnum.LORD"
|
||||
@@ -106,7 +100,7 @@
|
||||
</ContextMenu>
|
||||
</template>
|
||||
<!-- 用户个人信息框 -->
|
||||
<InfoPopover v-if="selectKey === item.uid" :uid="item.uid" />
|
||||
<InfoPopover v-if="selectKey === item.uid" :uid="item.uid" :activeStatus="item.activeStatus" />
|
||||
</n-popover>
|
||||
</template>
|
||||
</n-virtual-list>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<!-- 头部 -->
|
||||
<ChatHeader :active-item="activeItemRef as any" />
|
||||
<ChatHeader :active-item="activeItemRef" />
|
||||
<n-flex :class="{ 'shadow-inner': page.shadow }" :size="0" class="h-full">
|
||||
<n-flex vertical :size="0" class="flex-1 relative">
|
||||
<!-- 中间聊天框内容 -->
|
||||
<ChatMain :active-item="activeItemRef as any" />
|
||||
<ChatMain :active-item="activeItemRef" />
|
||||
<!-- 输入框和操作列表 -->
|
||||
<ChatFooter class="flex-1" />
|
||||
</n-flex>
|
||||
@@ -12,7 +12,7 @@
|
||||
</n-flex>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { MockItem } from '@/services/types.ts'
|
||||
import type { SessionItem } from '@/services/types.ts'
|
||||
import { WebviewWindow } from '@tauri-apps/api/webviewWindow'
|
||||
import { useSettingStore } from '@/stores/setting.ts'
|
||||
import { useTauriListener } from '@/hooks/useTauriListener'
|
||||
@@ -22,7 +22,7 @@ const settingStore = useSettingStore()
|
||||
const { page } = storeToRefs(settingStore)
|
||||
const appWindow = WebviewWindow.getCurrent()
|
||||
const { activeItem } = defineProps<{
|
||||
activeItem?: MockItem
|
||||
activeItem?: SessionItem
|
||||
}>()
|
||||
provide('activeItem', { ...activeItem! })
|
||||
const activeItemRef = ref({ ...activeItem! })
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import { emitTo, emit } from '@tauri-apps/api/event'
|
||||
import { emit } from '@tauri-apps/api/event'
|
||||
import { EventEnum } from '@/enums'
|
||||
import { useWindow } from '@/hooks/useWindow.ts'
|
||||
import { useGlobalStore } from '@/stores/global.ts'
|
||||
|
||||
export const useLogin = () => {
|
||||
const { resizeWindow } = useWindow()
|
||||
const globalStore = useGlobalStore()
|
||||
const { isTrayMenuShow } = storeToRefs(globalStore)
|
||||
/**
|
||||
* 设置登录状态(系统托盘图标,系统托盘菜单选项)
|
||||
*/
|
||||
@@ -11,7 +15,8 @@ export const useLogin = () => {
|
||||
if (localStorage.getItem('wsLogin')) {
|
||||
localStorage.removeItem('wsLogin')
|
||||
}
|
||||
await emitTo('tray', 'login_success')
|
||||
isTrayMenuShow.value = true
|
||||
await resizeWindow('tray', 130, 356)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -19,10 +24,11 @@ export const useLogin = () => {
|
||||
*/
|
||||
const logout = async () => {
|
||||
const { createWebviewWindow } = useWindow()
|
||||
isTrayMenuShow.value = false
|
||||
// todo 退出账号 需要关闭其他的全部窗口
|
||||
await createWebviewWindow('登录', 'login', 320, 448, 'home', false, 320, 448).then(async () => {
|
||||
await resizeWindow('tray', 130, 44)
|
||||
await emit(EventEnum.LOGOUT)
|
||||
await emitTo('tray', 'logout_success')
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -104,7 +104,8 @@ useMitt.on(WsResponseMessageType.MSG_RECALL, (data: RevokedMsgType) => {
|
||||
useMitt.on(WsResponseMessageType.RECEIVE_MESSAGE, async (data: MessageType) => {
|
||||
chatStore.pushMsg(data)
|
||||
console.log('接收消息', data)
|
||||
await emitTo('tray', 'show_tip')
|
||||
// 接收到通知就设置图标闪烁
|
||||
globalStore.setTipVisible(true)
|
||||
await emitTo('notify', 'notify_cotent', data)
|
||||
const username = useUserInfo(data.fromUser.uid).value.name!
|
||||
// 不是自己发的消息才通知
|
||||
|
||||
@@ -49,8 +49,10 @@ export const useGlobalStore = defineStore(
|
||||
selectedUid: []
|
||||
})
|
||||
|
||||
// 提示框显示状态
|
||||
/** 提示框显示状态 */
|
||||
const tipVisible = ref<boolean>(false)
|
||||
/** 系统托盘菜单显示的状态 */
|
||||
const isTrayMenuShow = ref<boolean>(false)
|
||||
|
||||
// 更新全局未读消息计数
|
||||
const updateGlobalUnreadCount = async () => {
|
||||
@@ -89,6 +91,7 @@ export const useGlobalStore = defineStore(
|
||||
currentReadUnreadList,
|
||||
createGroupModalInfo,
|
||||
tipVisible,
|
||||
isTrayMenuShow,
|
||||
setTipVisible,
|
||||
updateGlobalUnreadCount
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<n-flex v-if="!isLoginWin" vertical :size="6" class="tray">
|
||||
<n-flex v-if="isTrayMenuShow" vertical :size="6" class="tray">
|
||||
<n-flex vertical :size="6">
|
||||
<n-flex
|
||||
v-for="(item, index) in statusItem.slice(0, 6)"
|
||||
@@ -59,21 +59,18 @@ import { useSettingStore } from '@/stores/setting.ts'
|
||||
import { useGlobalStore } from '@/stores/global.ts'
|
||||
import { TrayIcon } from '@tauri-apps/api/tray'
|
||||
import { type } from '@tauri-apps/plugin-os'
|
||||
import { useTauriListener } from '@/hooks/useTauriListener'
|
||||
|
||||
const appWindow = WebviewWindow.getCurrent()
|
||||
const { checkWinExist, createWebviewWindow, resizeWindow } = useWindow()
|
||||
const { checkWinExist, createWebviewWindow } = useWindow()
|
||||
const OLStatusStore = onlineStatus()
|
||||
const settingStore = useSettingStore()
|
||||
const globalStore = useGlobalStore()
|
||||
const { lockScreen } = storeToRefs(settingStore)
|
||||
const { tipVisible } = storeToRefs(globalStore)
|
||||
const isLoginWin = ref(true)
|
||||
const { tipVisible, isTrayMenuShow } = storeToRefs(globalStore)
|
||||
const isFocused = ref(false)
|
||||
let home: WebviewWindow | null = null
|
||||
// 状态栏图标是否显示
|
||||
const iconVisible = ref(false)
|
||||
const { pushListeners } = useTauriListener()
|
||||
let interval: any
|
||||
|
||||
const division = () => {
|
||||
@@ -127,7 +124,6 @@ watch([isFocused, () => tipVisible.value], ([newFocused, newTipVisible]) => {
|
||||
onMounted(async () => {
|
||||
home = await WebviewWindow.getByLabel('home')
|
||||
isFocused.value = (await home?.isFocused()) || false
|
||||
|
||||
if (home) {
|
||||
// 监听窗口焦点变化
|
||||
home.listen('tauri://focus', () => {
|
||||
@@ -136,20 +132,6 @@ onMounted(async () => {
|
||||
home.listen('tauri://blur', () => {
|
||||
isFocused.value = false
|
||||
})
|
||||
await pushListeners([
|
||||
appWindow.listen('login_success', () => {
|
||||
isLoginWin.value = false
|
||||
resizeWindow('tray', 130, 356)
|
||||
}),
|
||||
appWindow.listen('logout_success', () => {
|
||||
isLoginWin.value = true
|
||||
resizeWindow('tray', 130, 44)
|
||||
}),
|
||||
appWindow.listen('show_tip', async () => {
|
||||
console.log('Received show_tip event')
|
||||
globalStore.setTipVisible(true)
|
||||
})
|
||||
])
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -174,12 +174,14 @@ onMounted(() => {
|
||||
useMitt.on(MittEnum.DELETE_SESSION, (roomId) => {
|
||||
handleMsgDelete(roomId)
|
||||
})
|
||||
useMitt.on(MittEnum.LOCATE_SESSION, (e) => {
|
||||
useMitt.on(MittEnum.LOCATE_SESSION, async (e) => {
|
||||
const index = sessionList.value.findIndex((item) => item.roomId === e.roomId)
|
||||
if (index !== -1) {
|
||||
msgScrollbar.value?.scrollTo({
|
||||
top: index * (75 + 5) - 264,
|
||||
behavior: 'smooth'
|
||||
await nextTick(() => {
|
||||
msgScrollbar.value?.scrollTo({
|
||||
top: index * (75 + 5) - 264,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user