Browse Source

change setting

master
godo 9 months ago
parent
commit
c36c7ee7cc
  1. 4
      CHANGELOG.md
  2. 150
      frontend/src/components/localchat/ChatDomain.vue
  3. 23
      frontend/src/stores/localchat.ts
  4. 12
      frontend/src/system/config.ts
  5. 16
      godo/libs/chatip.go
  6. 7
      godo/localchat/server.go

4
CHANGELOG.md

@ -1,4 +1,8 @@
## 变更记录 ## 变更记录
- 2024-09-10
1. 重构本地聊天,修改发现机制(基于ip扫描和arp过滤)
2. 本地聊天可批量发送图片/文件夹,修改发送机制,消息基于udp发送,文件基于tcp发送
-2024-09-04 -2024-09-04
1. 修复word导入格式丢失问题 1. 修复word导入格式丢失问题
-2024-09-03 -2024-09-03

150
frontend/src/components/localchat/ChatDomain.vue

@ -2,57 +2,48 @@
<div class="win11-msg-container"> <div class="win11-msg-container">
<el-scrollbar> <el-scrollbar>
<div v-if="store.navId < 2" class="user-list-area"> <div v-if="store.navId < 2" class="user-list-area">
<el-row <el-row class="user-list" justify="space-around" v-for="(msg, key) in store.contentList" :key="key"
class="user-list" v-if="store.contentList.length > 0">
justify="space-around"
v-for="(msg, key) in store.contentList"
:key="key"
v-if="store.contentList.length > 0"
>
<!-- <el-col :span="5" class="avatar-col"> <!-- <el-col :span="5" class="avatar-col">
<el-icon :size="22" class="avatar"> <el-icon :size="22" class="avatar">
<Place /> <Place />
</el-icon> </el-icon>
</el-col> --> </el-col> -->
<el-col :span="22" :class="msg.targetIp == store.chatTargetIp ? 'user-item active' : 'user-item'" @click="store.setChatId(msg.targetIp)"> <el-col :span="22" :class="msg.targetIp == store.chatTargetIp ? 'user-item active' : 'user-item'"
@click="store.setChatId(msg.targetIp)">
<span class="username"> <span class="username">
<el-icon :size="12"> <el-icon :size="12">
<Place /> <Place />
</el-icon> </el-icon>
{{ msg.reciperInfo ? msg.reciperInfo.hostname : '' }} {{ msg.reciperInfo ? msg.reciperInfo.hostname : '' }}
</span> </span>
<span class="msg">{{ msg.content }}</span> <span class="msg">{{ msg.content }}</span>
<span class="userip" v-if="msg.readNum > 0"> <span class="userip" v-if="msg.readNum > 0">
<el-badge :value="msg.readNum" :offset="[-3,8]"> <el-badge :value="msg.readNum" :offset="[-3, 8]">
{{ formatChatTime(msg.createdAt) }}</el-badge> {{ formatChatTime(msg.createdAt) }}</el-badge>
</span> </span>
<span class="userip" v-else> <span class="userip" v-else>
{{ formatChatTime(msg.createdAt) }} {{ formatChatTime(msg.createdAt) }}
</span> </span>
</el-col> </el-col>
</el-row> </el-row>
<el-empty v-else :image-size="100" description="消息列表为空" /> <el-empty v-else :image-size="100" description="消息列表为空" />
</div> </div>
<div v-else class="user-list-area"> <div v-else class="user-list-area">
<el-row justify="space-between"> <el-row justify="space-between">
<el-icon :size="18" @click="store.refreshUserList"> <el-icon :size="18" @click="store.refreshUserList">
<RefreshRight /> <RefreshRight />
</el-icon> </el-icon>
<el-icon :size="18" @click="store.showAddUser = true"> <el-icon :size="18" @click="store.showAddUser = true">
<CirclePlusFilled /> <Tools />
</el-icon> </el-icon>
</el-row> </el-row>
<el-row <el-row class="user-list" justify="space-around" v-for="(user, key) in store.userList" :key="key"
class="user-list" v-if="store.userList.length > 0">
justify="space-around"
v-for="(user, key) in store.userList"
:key="key"
v-if="store.userList.length > 0"
>
<el-col :span="5" class="avatar-col"> <el-col :span="5" class="avatar-col">
<el-icon :size="22" class="avatar"> <el-icon :size="22" class="avatar">
<Monitor /> <Monitor />
@ -73,16 +64,45 @@
</div> </div>
</el-scrollbar> </el-scrollbar>
</div> </div>
<el-dialog v-model="store.showAddUser" title="添加用户" width="500"> <el-dialog v-model="store.showAddUser" title="系统设置" width="500">
<el-form> <el-form>
<el-form-item :label-width="0">
<el-input v-model="userIp" autocomplete="off" placeholder="输入用户IP 例如:192.168.1.16"/> <el-form-item label="IP段第一位">
<el-input v-model="conf.first" autocomplete="off" placeholder="输入ip段第一位 例如:192" />
</el-form-item>
<el-form-item label="IP段第二位">
<el-input v-model="conf.second" autocomplete="off" placeholder="输入IP段第二位 例如:168" />
</el-form-item>
<el-form-item label="IP段第三位">
<el-col :span="11">
<el-input v-model="conf.thirdStart" placeholder="第三位开始" style="width: 100%" />
</el-col>
<el-col :span="2" class="text-center">
<span class="text-gray-500">-</span>
</el-col>
<el-col :span="11">
<el-input v-model="conf.thirdEnd" placeholder="第三位结束" style="width: 100%" />
</el-col>
</el-form-item>
<el-form-item label="IP段第四位">
<el-col :span="11">
<el-input v-model="conf.fourthStart" placeholder="第四位开始" style="width: 100%" />
</el-col>
<el-col :span="2" class="text-center">
<span class="text-gray-500">-</span>
</el-col>
<el-col :span="11">
<el-input v-model="conf.fourthEnd" placeholder="第四位结束" style="width: 100%" />
</el-col>
</el-form-item>
<el-form-item label="扫描间隔(秒)">
<el-input v-model="conf.checkTime" autocomplete="off" placeholder="输入扫描间隔 例如:30" />
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
<el-button type="primary" @click="store.addUser(userIp)"> <el-button type="primary" @click="store.saveConfig(conf)">
添加 保存
</el-button> </el-button>
</div> </div>
</template> </template>
@ -92,66 +112,84 @@
<script setup lang="ts"> <script setup lang="ts">
import { useLocalChatStore } from "@/stores/localchat"; import { useLocalChatStore } from "@/stores/localchat";
import { formatChatTime } from "@/util/common"; import { formatChatTime } from "@/util/common";
import { getSystemKey } from "@/system/config";
const store = useLocalChatStore(); const store = useLocalChatStore();
const userIp = ref('') const conf = ref(getSystemKey('chatConf'))
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.win11-msg-container { .win11-msg-container {
height: 100vh; /* 假设顶部有100px的导航栏 */ height: 100vh;
/* 假设顶部有100px的导航栏 */
width: 100%; width: 100%;
border-right: 1px solid rgba(238, 238, 238, 0.5); /* 更柔和的边框 */ border-right: 1px solid rgba(238, 238, 238, 0.5);
/* 更柔和的边框 */
border-top: 1px solid rgba(238, 238, 238, 0.5); border-top: 1px solid rgba(238, 238, 238, 0.5);
border-radius: 0 12px 0 0; /* Win11风格的圆角 */ border-radius: 0 12px 0 0;
background-color: #f8f8f8; /* 使用更亮的淡灰色背景 */ /* Win11风格的圆角 */
overflow: hidden; /* 清除滚动条溢出 */ background-color: #f8f8f8;
/* 使用更亮的淡灰色背景 */
overflow: hidden;
/* 清除滚动条溢出 */
} }
.el-scrollbar__wrap { .el-scrollbar__wrap {
padding: 16px; /* 内容区域的内边距 */ padding: 16px;
/* 内容区域的内边距 */
} }
.message-item { .message-item {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
&.self { &.self {
justify-content: flex-end; /* 自身消息右对齐 */ justify-content: flex-end;
/* 自身消息右对齐 */
} }
} }
.bubble { .bubble {
padding: 8px 12px; padding: 8px 12px;
border-radius: 12px; /* 圆角 */ border-radius: 12px;
/* 圆角 */
max-width: 75%; max-width: 75%;
background-color: #ffffff; background-color: #ffffff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
&.bubble--right { &.bubble--right {
background-color: #e8eaed; /* 更接近Win11的发送方消息背景色 */ background-color: #e8eaed;
/* 更接近Win11的发送方消息背景色 */
} }
} }
.user-list-area { .user-list-area {
width: 94%; width: 94%;
margin: 3%; margin: 3%;
} }
.user-list { .user-list {
background-color: #f8f8f8; // background-color: #f8f8f8; //
border-radius: 8px; // border-radius: 8px; //
margin-bottom: 12px; margin-bottom: 12px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); // box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); //
.avatar-col { .avatar-col {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; // align-items: center; //
} }
.active{
.active {
background-color: #e8eaed; background-color: #e8eaed;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
} }
.user-item { .user-item {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
flex-direction: column; /* 改变为列方向布局 */ flex-direction: column;
gap: 4px; /* 行间间距 */ /* 改变为列方向布局 */
gap: 4px;
/* 行间间距 */
padding: 4px 0; padding: 4px 0;
cursor: pointer; cursor: pointer;
transition: background-color 0.3s; transition: background-color 0.3s;
@ -161,7 +199,8 @@ const userIp = ref('')
} }
.avatar { .avatar {
border-radius: 50%; /* 头像圆角 */ border-radius: 50%;
/* 头像圆角 */
} }
.username { .username {
@ -169,16 +208,17 @@ const userIp = ref('')
font-size: 12px; font-size: 12px;
color: #333; color: #333;
overflow: hidden; overflow: hidden;
width:95%; width: 95%;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
.msg { .msg {
text-align: left; // username text-align: left; // username
font-size: 11px; font-size: 11px;
color: #666; color: #666;
overflow: hidden; overflow: hidden;
width:95%; width: 95%;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
@ -195,9 +235,10 @@ const userIp = ref('')
white-space: nowrap; white-space: nowrap;
} }
} }
.status-icon { .status-icon {
margin-left: 2px; // margin-left: 2px; //
margin-top:12px; margin-top: 12px;
} }
.online { .online {
@ -213,4 +254,7 @@ const userIp = ref('')
.el-empty { .el-empty {
margin: auto; margin: auto;
} }
.text-center{
text-align: center;
}
</style> </style>

23
frontend/src/stores/localchat.ts

@ -2,7 +2,7 @@ import { defineStore } from 'pinia'
import emojiList from "@/assets/emoji.json" import emojiList from "@/assets/emoji.json"
import { ref, toRaw } from "vue"; import { ref, toRaw } from "vue";
import { db } from './db' import { db } from './db'
import { getSystemConfig } from "@/system/config"; import { getSystemConfig, setSystemKey } from "@/system/config";
import { isValidIP } from "@/util/common"; import { isValidIP } from "@/util/common";
import { notifyError, notifySuccess } from "@/util/msg"; import { notifyError, notifySuccess } from "@/util/msg";
export const useLocalChatStore = defineStore('localChatStore', () => { export const useLocalChatStore = defineStore('localChatStore', () => {
@ -449,6 +449,24 @@ export const useLocalChatStore = defineStore('localChatStore', () => {
//notifySuccess("确认成功!") //notifySuccess("确认成功!")
} }
} }
async function saveConfig(conf:any){
conf = toRaw(conf)
//console.log(conf)
const postUrl = `${config.apiUrl}/localchat/setting`
const coms = await fetch(postUrl, {
method: "POST",
body: JSON.stringify(conf),
})
if (!coms.ok) {
//console.log(coms)
notifyError("保存失败!")
} else {
setSystemKey('chatConf', conf)
notifySuccess("保存成功!")
showAddUser.value = false
}
}
return { return {
userList, userList,
@ -476,6 +494,7 @@ export const useLocalChatStore = defineStore('localChatStore', () => {
clearMsg, clearMsg,
handlerMessage, handlerMessage,
cannelFile, cannelFile,
accessFile accessFile,
saveConfig
} }
}) })

12
frontend/src/system/config.ts

@ -123,7 +123,17 @@ export const getSystemConfig = (ifset = false) => {
dbname: '' dbname: ''
}; };
} }
if (!config.chatConf) {
config.chatConf = {
'checkTime': '15',
'first': '192',
'second': '168',
'thirdStart': '1',
'thirdEnd': '1',
'fourthStart': '2',
'fourthEnd': '254'
}
}
// 初始化桌面快捷方式列表,若本地存储中已存在则不进行覆盖 // 初始化桌面快捷方式列表,若本地存储中已存在则不进行覆盖
if (!config.desktopList) { if (!config.desktopList) {
config.desktopList = []; config.desktopList = [];

16
godo/libs/chatip.go

@ -29,18 +29,18 @@ import (
) )
type UserChatIpSetting struct { type UserChatIpSetting struct {
CheckTime int `json:"CheckTime"` CheckTime string `json:"checkTime"`
First string `json:"First"` First string `json:"first"`
Second string `json:"Second"` Second string `json:"second"`
ThirdStart string `json:"ThirdStart"` ThirdStart string `json:"thirdStart"`
ThirdEnd string `json:"ThirdEnd"` ThirdEnd string `json:"thirdEnd"`
FourthStart string `json:"FourthStart"` FourthStart string `json:"fourthStart"`
FourthEnd string `json:"FourthEnd"` FourthEnd string `json:"fourthEnd"`
} }
func GetDefaultChatIpSetting() UserChatIpSetting { func GetDefaultChatIpSetting() UserChatIpSetting {
return UserChatIpSetting{ return UserChatIpSetting{
CheckTime: 30, CheckTime: "15",
First: "192", First: "192",
Second: "168", Second: "168",
ThirdStart: "1", ThirdStart: "1",

7
godo/localchat/server.go

@ -28,6 +28,7 @@ import (
"godo/libs" "godo/libs"
"log" "log"
"net" "net"
"strconv"
"time" "time"
) )
@ -60,7 +61,11 @@ func init() {
func CheckOnlines() { func CheckOnlines() {
//CheckOnline() //CheckOnline()
chatIpSetting := libs.GetChatIpSetting() chatIpSetting := libs.GetChatIpSetting()
checkTimeDuration := time.Duration(chatIpSetting.CheckTime) * time.Second cktime, err := strconv.Atoi(chatIpSetting.CheckTime)
if err != nil {
cktime = 15
}
checkTimeDuration := time.Duration(cktime) * time.Second
ticker := time.NewTicker(checkTimeDuration) ticker := time.NewTicker(checkTimeDuration)
defer ticker.Stop() defer ticker.Stop()

Loading…
Cancel
Save