Merge branch 'feature-nxdev' of https://gitea.nxsir.cn/code/IM into feature-nxdev
This commit is contained in:
commit
536b360127
@ -14,7 +14,11 @@ using System.Reflection;
|
||||
[assembly: System.Reflection.AssemblyCompanyAttribute("IMTest")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
<<<<<<< HEAD
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+eb8455e141ea496a2134ad7c7d9b759b6029dd75")]
|
||||
=======
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+f7223dc5904286fdf8e117b56c37f58dc431d68b")]
|
||||
>>>>>>> eb8455e141ea496a2134ad7c7d9b759b6029dd75
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("IMTest")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("IMTest")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
@ -1 +1,5 @@
|
||||
<<<<<<< HEAD
|
||||
546570633bb9288fc2957cbb29a807a45f3e48ba127ec13bc3956d28f5e6ed5b
|
||||
=======
|
||||
3c0a5335719f892c65744a9df7eae9fd7b12de9067131f5c9f4cb65f2b27b8d4
|
||||
>>>>>>> eb8455e141ea496a2134ad7c7d9b759b6029dd75
|
||||
|
||||
@ -22,7 +22,7 @@ namespace IM_API.Application.EventHandlers.FriendAddHandler
|
||||
var usersList = new List<string> {
|
||||
@event.RequestUserId.ToString(), @event.ResponseUserId.ToString()
|
||||
};
|
||||
var res = new HubResponse<MessageBaseDto>("Event", new MessageBaseDto()
|
||||
var res = new HubResponse<MessageBaseDto>(HubResponseType.FriendAccepted, new MessageBaseDto()
|
||||
{
|
||||
ChatType = ChatType.PRIVATE,
|
||||
Content = "您有新的好友关系已添加",
|
||||
|
||||
@ -39,11 +39,44 @@ namespace IM_API.Dtos
|
||||
Message = codeDefine.Message;
|
||||
Data = data;
|
||||
}
|
||||
public HubResponse(HubResponseType type, T? data)
|
||||
{
|
||||
Code = CodeDefine.SUCCESS.Code;
|
||||
Method = "Event";
|
||||
Type = type;
|
||||
Data = data;
|
||||
}
|
||||
}
|
||||
public enum HubResponseType
|
||||
{
|
||||
ChatMsg = 1, // 聊天内容
|
||||
SystemNotice = 2, // 系统通知(如:申请好友成功)
|
||||
ActionStatus = 3 // 状态变更(如:对方正在输入、已读回执)
|
||||
// --- 基础聊天 (10-19) ---
|
||||
ChatMsg = 1, // 普通消息
|
||||
|
||||
// --- 系统与通知 (20-29) ---
|
||||
SystemNotice = 2, // 通用系统通知
|
||||
FriendRequest = 21, // 好友申请消息
|
||||
FriendAccepted = 22, // 好友通过通知
|
||||
UserInLine = 23, // 好友上线/下线通知
|
||||
|
||||
// --- 状态变更与交互 (30-39) ---
|
||||
ActionStatus = 3, // 通用状态(正在输入等)
|
||||
MsgReadReceipt = 31, // 已读回执
|
||||
MsgRevoke = 32, // 消息撤回
|
||||
MsgEdit = 33, // 消息二次编辑更新
|
||||
|
||||
// --- 群组管理 (40-49) ---
|
||||
GroupInvited = 41, // 被邀请入群
|
||||
GroupMemberUpdate = 42, // 群成员变动(进群/退群)
|
||||
GroupAnnouncement = 43, // 群公告更新
|
||||
GroupDismissed = 44, // 群组解散
|
||||
|
||||
// --- 实时通信控制 (50-59) ---
|
||||
RTC_CallRequest = 51, // 音视频通话邀请
|
||||
RTC_CallHandled = 52, // 音视频接听/挂断/取消状态
|
||||
|
||||
// --- 异常与安全 (90-99) ---
|
||||
ErrorInternal = 91, // 服务器内部错误
|
||||
TokenExpired = 92, // 登录过期,强制下线
|
||||
KickedOut = 93 // 被挤下线(异地登录)
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,7 +146,8 @@ namespace IM_API.Services
|
||||
|
||||
public async Task MakeConversationAsync(int userAId, int userBId, ChatType chatType)
|
||||
{
|
||||
var userAcExist = await _context.Conversations.AnyAsync(x => x.UserId == userAId && x.TargetId == userBId);
|
||||
var userAcExist = await _context.Conversations.AnyAsync(
|
||||
x => x.UserId == userAId && x.TargetId == userBId && x.ChatType == chatType);
|
||||
if (userAcExist) return;
|
||||
var streamKey = chatType == ChatType.PRIVATE ?
|
||||
StreamKeyBuilder.Private(userAId, userBId) : StreamKeyBuilder.Group(userBId);
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
# VITE_API_BASE_URL = http://localhost:5202/api
|
||||
# VITE_SIGNALR_BASE_URL = http://localhost:5202/chat/
|
||||
VITE_API_BASE_URL = http://localhost:5202/api
|
||||
VITE_SIGNALR_BASE_URL = http://localhost:5202/chat/
|
||||
# VITE_API_BASE_URL = https://im.test.nxsir.cn/api
|
||||
# VITE_SIGNALR_BASE_URL = https://im.test.nxsir.cn/chat/
|
||||
|
||||
|
||||
VITE_API_BASE_URL = http://192.168.5.116:7070/api
|
||||
VITE_SIGNALR_BASE_URL = http://192.168.5.116:7070/chat/
|
||||
# VITE_API_BASE_URL = http://192.168.5.116:7070/api
|
||||
# VITE_SIGNALR_BASE_URL = http://192.168.5.116:7070/chat/
|
||||
|
||||
@ -26,7 +26,7 @@ function createWindow() {
|
||||
createTry(mainWindow);
|
||||
|
||||
mainWindow.on('ready-to-show', () => {
|
||||
mainWindow.show()
|
||||
// mainWindow.show()
|
||||
})
|
||||
|
||||
|
||||
|
||||
@ -25,7 +25,9 @@ export function registerWindowHandler() {
|
||||
changeSize: () => {
|
||||
win.setSize(data.width, data.height, true)
|
||||
win.setResizable(data.resizable)
|
||||
}
|
||||
win.center()
|
||||
},
|
||||
show: () => win.show()
|
||||
}
|
||||
actions[action]?.()
|
||||
})
|
||||
|
||||
@ -8,6 +8,7 @@ const api = {
|
||||
maximize: () => ipcRenderer.send('window-action', 'maximize'),
|
||||
close: () => ipcRenderer.send('window-action', 'close'),
|
||||
closeThis: () => ipcRenderer.send('window-action', 'closeThis'),
|
||||
show: () => ipcRenderer.send('window-action', 'show'),
|
||||
isMaximized: () => ipcRenderer.send('window-action', 'isMaximized'),
|
||||
newWindow: (route, data, width, height) => ipcRenderer.send('window-new', { route, data, width, height }),
|
||||
getWindowData: (winId) => ipcRenderer.invoke('get-window-data', winId),
|
||||
|
||||
@ -50,6 +50,7 @@ function toggleMaximize() {
|
||||
function close() {
|
||||
window.api.window.close()
|
||||
emits('close')
|
||||
emits('close')
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
export const NOTIFICATION_TYPE = Object.freeze({
|
||||
// --- 基础聊天 (10-19) ---
|
||||
ChatMsg: 1,
|
||||
FileMsg: 11,
|
||||
EmojiSticker: 12,
|
||||
ForwardMsg: 13,
|
||||
|
||||
// --- 系统与通知 (20-29) ---
|
||||
SystemNotice: 2,
|
||||
FriendRequest: 21,
|
||||
FriendAccepted: 22,
|
||||
UserInLine: 23,
|
||||
|
||||
// --- 状态变更与交互 (30-39) ---
|
||||
ActionStatus: 3,
|
||||
MsgReadReceipt: 31,
|
||||
MsgRevoke: 32,
|
||||
MsgEdit: 33,
|
||||
|
||||
// --- 群组管理 (40-49) ---
|
||||
GroupInvited: 41,
|
||||
GroupMemberUpdate: 42,
|
||||
GroupAnnouncement: 43,
|
||||
GroupDismissed: 44,
|
||||
|
||||
// --- 实时通信控制 (50-59) ---
|
||||
RTC_CallRequest: 51,
|
||||
RTC_CallHandled: 52,
|
||||
|
||||
// --- 异常与安全 (90-99) ---
|
||||
ErrorInternal: 91,
|
||||
TokenExpired: 92,
|
||||
KickedOut: 93
|
||||
})
|
||||
@ -1,22 +1,28 @@
|
||||
import { useBrowserNotification } from "@/services/useBrowserNotification";
|
||||
import { useBrowserNotification } from '@/services/useBrowserNotification'
|
||||
|
||||
import { useChatStore } from "@/stores/chat";
|
||||
import { useChatStore } from '@/stores/chat'
|
||||
|
||||
import { messageHandler } from "@/handler/messageHandler";
|
||||
import { generateSessionId } from "../sessionIdTools";
|
||||
import { useConversationStore } from "@/stores/conversation";
|
||||
import { MESSAGE_TYPE } from "@/constants/MessageType";
|
||||
import { messageHandler } from '@/handler/messageHandler'
|
||||
import { generateSessionId } from '../sessionIdTools'
|
||||
import { useConversationStore } from '@/stores/conversation'
|
||||
import { MESSAGE_TYPE } from '@/constants/MessageType'
|
||||
import { NOTIFICATION_TYPE } from '../../constants/notificationType'
|
||||
|
||||
export const SignalRMessageHandler = (data) => {
|
||||
const msg = data.data;
|
||||
const chatStore = useChatStore()
|
||||
const browserNotification = useBrowserNotification();
|
||||
const sessionId = generateSessionId(msg.senderId, msg.receiverId, msg.chatType == MESSAGE_TYPE.GROUP);
|
||||
messageHandler(msg);
|
||||
chatStore.pushAndSortMessagesAsync([msg], sessionId);
|
||||
const conversation = useConversationStore().conversations.find(x => x.targetId == msg.senderId);
|
||||
browserNotification.send(`${conversation.targetName}发来一条消息`, {
|
||||
body: msg.content,
|
||||
icon: conversation.targetAvatar
|
||||
});
|
||||
}
|
||||
const msg = data.data
|
||||
const type = data.type
|
||||
const chatStore = useChatStore()
|
||||
const browserNotification = useBrowserNotification()
|
||||
const sessionId = generateSessionId(
|
||||
msg.senderId,
|
||||
msg.receiverId,
|
||||
msg.chatType == MESSAGE_TYPE.GROUP
|
||||
)
|
||||
messageHandler(msg)
|
||||
chatStore.pushAndSortMessagesAsync([msg], sessionId)
|
||||
const conversation = useConversationStore().conversations.find((x) => x.targetId == msg.senderId)
|
||||
browserNotification.send(`${conversation.targetName}发来一条消息`, {
|
||||
body: msg.content,
|
||||
icon: conversation.targetAvatar
|
||||
})
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<div class="im-container">
|
||||
<nav class="nav-sidebar">
|
||||
<div class="user-self">
|
||||
<async-image :raw-url="myInfo?.avatar" class="avatar-std"/>
|
||||
<async-image :raw-url="myInfo?.avatar" class="avatar-std" />
|
||||
<!-- <img :src="myInfo?.avatar ?? defaultAvatar" class="avatar-std" /> -->
|
||||
</div>
|
||||
<router-link class="nav-item" to="/messages" active-class="active">
|
||||
@ -26,6 +26,7 @@ import { useAuthStore } from '@/stores/auth';
|
||||
import { useRouter } from 'vue-router';
|
||||
import feather from 'feather-icons';
|
||||
import AsyncImage from '../components/AsyncImage.vue';
|
||||
import { isElectron } from '../utils/electronHelper';
|
||||
|
||||
const router = useRouter();
|
||||
const authStore = useAuthStore();
|
||||
@ -46,11 +47,14 @@ function handleStartChat(contact) {
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
window.api.window.setMainSize(900, 670)
|
||||
if (isElectron()) {
|
||||
window.api.window.setMainSize(900, 670)
|
||||
window.api.window.show()
|
||||
}
|
||||
const { useSignalRStore } = await import('../stores/signalr');
|
||||
const authStore = useAuthStore();
|
||||
const signalRStore = useSignalRStore();
|
||||
if(authStore.token){
|
||||
if (authStore.token) {
|
||||
signalRStore.initSignalR();
|
||||
}
|
||||
})
|
||||
@ -66,7 +70,7 @@ onMounted(async () => {
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 12px 48px rgba(0,0,0,0.1);
|
||||
box-shadow: 0 12px 48px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* 导航栏 */
|
||||
@ -90,8 +94,11 @@ onMounted(async () => {
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
.user-self { margin-bottom: 10px;/* 允许拖动整个窗口 */
|
||||
-webkit-app-region:no-drag; }
|
||||
.user-self {
|
||||
margin-bottom: 10px;
|
||||
/* 允许拖动整个窗口 */
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
/* 2. 列表区修复 */
|
||||
.list-panel {
|
||||
@ -107,6 +114,7 @@ onMounted(async () => {
|
||||
.search-section {
|
||||
padding: 20px 12px 10px 12px;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -115,7 +123,12 @@ onMounted(async () => {
|
||||
border-radius: 4px;
|
||||
gap: 5px;
|
||||
}
|
||||
.search-icon { font-size: 12px; color: #666; }
|
||||
|
||||
.search-icon {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.search-box input {
|
||||
background: transparent;
|
||||
border: none;
|
||||
@ -124,7 +137,10 @@ onMounted(async () => {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.scroll-area { flex: 1; overflow-y: auto; }
|
||||
.scroll-area {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* 3. 聊天主面板修复 */
|
||||
.chat-panel {
|
||||
@ -159,7 +175,9 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
/* 别人发的:默认靠左 */
|
||||
.msg.other { flex-direction: row; }
|
||||
.msg.other {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
/* 本人发的:翻转排列方向,靠右显示 */
|
||||
.msg.mine {
|
||||
@ -184,11 +202,18 @@ onMounted(async () => {
|
||||
line-height: 1.6;
|
||||
word-break: break-all;
|
||||
position: relative;
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.05);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.other .bubble { background: #fff; color: #333; }
|
||||
.mine .bubble { background: #95ec69; color: #000; }
|
||||
.other .bubble {
|
||||
background: #fff;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.mine .bubble {
|
||||
background: #95ec69;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.msg-time {
|
||||
font-size: 11px;
|
||||
@ -197,11 +222,26 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
/* 头像样式统一 */
|
||||
:deep(.avatar-std) { width: 40px; height: 40px; border-radius: 4px; object-fit: cover; }
|
||||
.avatar-chat { width: 38px; height: 38px; border-radius: 4px; object-fit: cover; flex-shrink: 0; }
|
||||
:deep(.avatar-std) {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 4px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.avatar-chat {
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
border-radius: 4px;
|
||||
object-fit: cover;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 未读气泡 */
|
||||
.avatar-container { position: relative; }
|
||||
.avatar-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.unread-badge {
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
@ -229,8 +269,20 @@ onMounted(async () => {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.toolbar { display: flex; gap: 12px; margin-bottom: 5px; font-size: 20px; color: #666; }
|
||||
.toolbar button { background: none; border: none; cursor: pointer; opacity: 0.7; }
|
||||
.toolbar {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-bottom: 5px;
|
||||
font-size: 20px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.toolbar button {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
textarea {
|
||||
flex: 1;
|
||||
@ -242,7 +294,11 @@ textarea {
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
.send-row { display: flex; justify-content: flex-end; }
|
||||
.send-row {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.send-btn {
|
||||
background: #f5f5f5;
|
||||
color: #07c160;
|
||||
@ -252,18 +308,67 @@ textarea {
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
}
|
||||
.send-btn:hover { background: #e2e2e2; }
|
||||
|
||||
.send-btn:hover {
|
||||
background: #e2e2e2;
|
||||
}
|
||||
|
||||
/* 列表美化 */
|
||||
.list-item { display: flex; padding: 12px; gap: 12px; cursor: pointer; }
|
||||
.list-item.active { background: #c6c6c6; }
|
||||
.list-item:hover:not(.active) { background: #ddd; }
|
||||
.info { flex: 1; overflow: hidden; }
|
||||
.name-row { display: flex; justify-content: space-between; align-items: center; }
|
||||
.name { font-size: 14px; font-weight: 500; }
|
||||
.time { font-size: 11px; color: #999; }
|
||||
.last-msg { font-size: 12px; color: #888; margin-top: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.list-item {
|
||||
display: flex;
|
||||
padding: 12px;
|
||||
gap: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.nav-item { font-size: 24px; cursor: pointer; opacity: 0.5; background-color: #fff; border-radius: 5px; text-decoration: none;}
|
||||
.nav-item.active { opacity: 1; }
|
||||
.list-item.active {
|
||||
background: #c6c6c6;
|
||||
}
|
||||
|
||||
.list-item:hover:not(.active) {
|
||||
background: #ddd;
|
||||
}
|
||||
|
||||
.info {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.name-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.name {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.time {
|
||||
font-size: 11px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.last-msg {
|
||||
font-size: 12px;
|
||||
color: #888;
|
||||
margin-top: 4px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
opacity: 0.5;
|
||||
background-color: #fff;
|
||||
border-radius: 5px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.nav-item.active {
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<div class="login-container">
|
||||
|
||||
<div class="login-box">
|
||||
<WindowControls :resizable="false"/>
|
||||
<WindowControls :resizable="false" />
|
||||
<div class="window-header">
|
||||
<div class="brand">
|
||||
<span class="logo-dot"></span>
|
||||
@ -20,19 +20,9 @@
|
||||
|
||||
<form @submit.prevent="handleLogin" class="form-body">
|
||||
<div class="input-area">
|
||||
<input
|
||||
type="text"
|
||||
v-model="form.username"
|
||||
placeholder="账号/邮箱"
|
||||
class="classic-input"
|
||||
/>
|
||||
<input type="text" v-model="form.username" placeholder="账号/邮箱" class="classic-input" />
|
||||
<div class="divider"></div>
|
||||
<input
|
||||
type="password"
|
||||
v-model="form.password"
|
||||
placeholder="密码"
|
||||
class="classic-input"
|
||||
/>
|
||||
<input type="password" v-model="form.password" placeholder="密码" class="classic-input" />
|
||||
</div>
|
||||
|
||||
<div class="options">
|
||||
@ -67,6 +57,7 @@ import useVuelidate from '@vuelidate/core'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { useSignalRStore } from '@/stores/signalr'
|
||||
import WindowControls from '../../components/WindowControls.vue'
|
||||
import { isElectron } from '../../utils/electronHelper'
|
||||
|
||||
const message = useMessage();
|
||||
const router = useRouter();
|
||||
@ -80,48 +71,52 @@ const form = reactive({
|
||||
})
|
||||
|
||||
const rules = {
|
||||
username:{
|
||||
required:helpers.withMessage('用户名不能为空', required),
|
||||
maxLength:helpers.withMessage('用户名最大20字符', maxLength(20))
|
||||
username: {
|
||||
required: helpers.withMessage('用户名不能为空', required),
|
||||
maxLength: helpers.withMessage('用户名最大20字符', maxLength(20))
|
||||
},
|
||||
password:{
|
||||
required:helpers.withMessage('密码不能为空', required),
|
||||
maxLength:helpers.withMessage('密码最大50字符', maxLength(50))
|
||||
password: {
|
||||
required: helpers.withMessage('密码不能为空', required),
|
||||
maxLength: helpers.withMessage('密码最大50字符', maxLength(50))
|
||||
}
|
||||
};
|
||||
|
||||
const v$ = useVuelidate(rules,form);
|
||||
const v$ = useVuelidate(rules, form);
|
||||
|
||||
const handleLogin = async () => {
|
||||
const isFormCorrect = await v$.value.$validate()
|
||||
if (!isFormCorrect) {
|
||||
if (v$.value.$errors.length > 0) {
|
||||
message.error(v$.value.$errors[0].$message)
|
||||
}
|
||||
return
|
||||
if (v$.value.$errors.length > 0) {
|
||||
message.error(v$.value.$errors[0].$message)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
try{
|
||||
try {
|
||||
loading.value = true;
|
||||
const res = await authService.login(form);
|
||||
if(res.code === 0){ // Assuming 0 is success
|
||||
if (res.code === 0) { // Assuming 0 is success
|
||||
message.success('登录成功')
|
||||
authStore.setLoginInfo(res.data.token, res.data.refreshToken, res.data.userInfo);
|
||||
signalRStore.initSignalR();
|
||||
router.push('/messages')
|
||||
}else{
|
||||
} else {
|
||||
message.error(res.message || '登录失败')
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
} finally{
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
window.api.window.setMainSize(360, 532, false)
|
||||
if (isElectron()) {
|
||||
window.api.window.setMainSize(360, 532, false)
|
||||
window.api.window.show()
|
||||
}
|
||||
feather.replace()
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -140,29 +135,37 @@ onMounted(() => {
|
||||
/* 2. 核心登录框:双端适配的关键 */
|
||||
.login-box {
|
||||
width: 100%;
|
||||
max-width: 420px; /* Web 端限制最大宽度 */
|
||||
max-width: 420px;
|
||||
/* Web 端限制最大宽度 */
|
||||
height: 100%;
|
||||
max-height: 540px; /* Web 端限制最大高度 */
|
||||
max-height: 540px;
|
||||
/* Web 端限制最大高度 */
|
||||
background: #ffffff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.05); /* Web 端浮动感 */
|
||||
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.05);
|
||||
/* Web 端浮动感 */
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
/* 3. 桌面端(Electron)适配:当窗口较小时(即客户端模式) */
|
||||
@media (max-width: 480px) or (max-height: 580px) {
|
||||
.login-container {
|
||||
background-color: #fff; /* 客户端通常不需要容器背景 */
|
||||
background-color: #fff;
|
||||
/* 客户端通常不需要容器背景 */
|
||||
}
|
||||
|
||||
.login-box {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
box-shadow: none; /* 客户端全屏模式不需要投影 */
|
||||
box-shadow: none;
|
||||
/* 客户端全屏模式不需要投影 */
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.window-header {
|
||||
display: flex; /* 客户端显示拖拽区 */
|
||||
display: flex;
|
||||
/* 客户端显示拖拽区 */
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,7 +173,8 @@ onMounted(() => {
|
||||
.window-header {
|
||||
height: 40px;
|
||||
padding: 0 16px;
|
||||
display: none; /* Web 端默认隐藏 */
|
||||
display: none;
|
||||
/* Web 端默认隐藏 */
|
||||
align-items: center;
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
@ -208,7 +212,8 @@ onMounted(() => {
|
||||
height: 72px;
|
||||
background: #f0f7ff;
|
||||
color: #0099ff;
|
||||
border-radius: 20px; /* 稍微方圆一点更现代 */
|
||||
border-radius: 20px;
|
||||
/* 稍微方圆一点更现代 */
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user