更新chat的ui界面
This commit is contained in:
1 parent
530e54a596
commit
709cac04f6
6 files changed
+111
-60
No files matched your search
@@ -377,6 +377,7 @@ function createGroupTableDB(gID, verify) {
|
|||||||
`CREATE TABLE IF NOT EXISTS ${gID} (
|
`CREATE TABLE IF NOT EXISTS ${gID} (
|
||||||
message TEXT NOT NULL,
|
message TEXT NOT NULL,
|
||||||
type TEXT NOT NULL,
|
type TEXT NOT NULL,
|
||||||
|
type1 TEXT NOT NULL,
|
||||||
sender TEXT NOT NULL,
|
sender TEXT NOT NULL,
|
||||||
timestamp INT NOT NULL
|
timestamp INT NOT NULL
|
||||||
);`
|
);`
|
||||||
@@ -385,11 +386,11 @@ function createGroupTableDB(gID, verify) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 插入信息
|
// 插入信息
|
||||||
function insertMessageByGID(gID, msg, from, timestamp) {
|
function insertMessageByGID(gID, msg,type1, from, timestamp) {
|
||||||
if (!generateStmt_insertMessage_map[gID]) {
|
if (!generateStmt_insertMessage_map[gID]) {
|
||||||
generateStmt_insertMessage_map[gID] = db.prepare(`INSERT INTO ${gID} (message,type,sender, timestamp) VALUES (?, ?, ?, ?)`);
|
generateStmt_insertMessage_map[gID] = db.prepare(`INSERT INTO ${gID} (message,type,type1,sender, timestamp) VALUES (?, ?, ?, ?, ?)`);
|
||||||
}
|
}
|
||||||
generateStmt_insertMessage_map[gID].run(msg, "gMsg", from, timestamp);
|
generateStmt_insertMessage_map[gID].run(msg, "gMsg",type1, from, timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateActiveTimestamp(gID) {
|
function updateActiveTimestamp(gID) {
|
||||||
@@ -423,14 +424,14 @@ function getHistory(gID) {
|
|||||||
return groupsMap[gID].msgHistory;
|
return groupsMap[gID].msgHistory;
|
||||||
}
|
}
|
||||||
|
|
||||||
function broadcastMsg(gID, msg, from) {
|
function broadcastMsg(gID, msg,type1, from) {
|
||||||
const timestamp = parseInt(Date.now());
|
const timestamp = parseInt(Date.now());
|
||||||
initMsgHistory(gID);
|
initMsgHistory(gID);
|
||||||
updateActiveTimestamp(gID);
|
updateActiveTimestamp(gID);
|
||||||
insertMessageByGID(gID, msg, from, timestamp);
|
insertMessageByGID(gID, msg,type1, from, timestamp);
|
||||||
|
|
||||||
let bmsg = JSON.stringify({ type: "gMsg", gID, msg, from, timestamp });
|
let bmsg = JSON.stringify({ type: `gMsg`,type1, gID, msg, from, timestamp });
|
||||||
groupsMap[gID].msgHistory.push({ type: "gMsg", msg, from, timestamp });
|
groupsMap[gID].msgHistory.push({ type: `gMsg`,type1, msg, from, timestamp });
|
||||||
for (let socket of groupsMap[gID].member) {
|
for (let socket of groupsMap[gID].member) {
|
||||||
socket.send(bmsg);
|
socket.send(bmsg);
|
||||||
}
|
}
|
||||||
@@ -490,7 +491,7 @@ wss.on("connection", socket => {
|
|||||||
}
|
}
|
||||||
} else if (type === "message") {
|
} else if (type === "message") {
|
||||||
let gID = msg.gID;
|
let gID = msg.gID;
|
||||||
broadcastMsg(gID, msg.msg, uuid);
|
broadcastMsg(gID, msg.msg,msg.type1, uuid);
|
||||||
} else if (type === "heartbeat") {
|
} else if (type === "heartbeat") {
|
||||||
socket.send(JSON.stringify({ type: "sMsg", type1: "heartbeat" }));
|
socket.send(JSON.stringify({ type: "sMsg", type1: "heartbeat" }));
|
||||||
} else if (type === "uuid") {
|
} else if (type === "uuid") {
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<template>
|
||||||
|
<!-- <div style="border: 1px solid rgb(239, 239, 245);border-radius: 5px;position: relative;"> -->
|
||||||
|
<n-scrollbar style="padding: 10px;padding-right: 15px; border: 1px solid rgb(239, 239, 245);border-radius: 5px;position: relative;">
|
||||||
|
<div v-for="msg of props.messages">
|
||||||
|
<div style="color:slategrey;">{{ `${msg.from.split('-')[0]} ${msg.timestampString}` }}</div>
|
||||||
|
<div
|
||||||
|
style="background-color: rgb(239, 239, 245); padding: 2px 7px; width: fit-content; border-radius: 5px; white-space: pre-wrap;">
|
||||||
|
{{ msg.msg }}</div>
|
||||||
|
</div>
|
||||||
|
<n-empty description="无可显示消息" v-show="props.messages.length === 0" style="margin-top: 25vh;">
|
||||||
|
<template #extra>
|
||||||
|
</template>
|
||||||
|
</n-empty>
|
||||||
|
<div style="height: 30px;" v-show="props.messages.length !== 0"></div>
|
||||||
|
</n-scrollbar>
|
||||||
|
<!-- </div> -->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { NScrollbar,NEmpty } from 'naive-ui'
|
||||||
|
const props = defineProps({
|
||||||
|
messages: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
||||||
+1
-1
@@ -25,7 +25,7 @@ export const useSettingStore = defineStore("setting", {
|
|||||||
activeKeyMap:JSON.parse(activeKeyMap),
|
activeKeyMap:JSON.parse(activeKeyMap),
|
||||||
serverPort:config.PORT,
|
serverPort:config.PORT,
|
||||||
token,userID,userGroup
|
token,userID,userGroup
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
// double: state => state.count * 2
|
// double: state => state.count * 2
|
||||||
},
|
},
|
||||||
|
|||||||
+70
-50
@@ -1,52 +1,58 @@
|
|||||||
<template>
|
<template>
|
||||||
<n-flex style="padding-top: 10px;padding-bottom: 10px;">
|
<n-flex vertical>
|
||||||
<n-input v-model:value="groupCode" type="text" placeholder="输入邀请码" style="flex:1">
|
<n-flex style="padding-top: 10px;">
|
||||||
<template #suffix>
|
<n-input v-model:value="groupCode" type="text" placeholder="输入邀请码" style="flex:1">
|
||||||
<n-icon :component="CopyOutline" style="cursor: pointer;" @click='toClipboard(groupCode)' />
|
<template #suffix>
|
||||||
</template>
|
<n-icon :component="CopyOutline" style="cursor: pointer;" @click='toClipboard(groupCode)' />
|
||||||
</n-input>
|
</template>
|
||||||
<n-flex>
|
</n-input>
|
||||||
<n-button @click="createGroup" :disabled="groupCode !== ''" :type="groupCode !== '' ? 'default' : 'primary'"
|
<n-flex>
|
||||||
ghost>
|
<n-button @click="createGroup" :disabled="groupCode !== ''" :type="groupCode !== '' ? 'default' : 'primary'"
|
||||||
创建群组
|
ghost>
|
||||||
</n-button>
|
创建群组
|
||||||
<n-button @click="joinGroup(groupCode)" :disabled="groupCode === ''"
|
</n-button>
|
||||||
:type="groupCode === '' ? 'default' : 'primary'" ghost>
|
<n-button @click="joinGroup(groupCode)" :disabled="groupCode === ''"
|
||||||
加入群组
|
:type="groupCode === '' ? 'default' : 'primary'" ghost>
|
||||||
</n-button>
|
加入群组
|
||||||
|
</n-button>
|
||||||
|
<n-button @click="shareWithQR()" :disabled="activeGID === null" v-show="activeGID !== null"
|
||||||
|
:type="activeGID === null ? 'default' : 'primary'">
|
||||||
|
分享群组
|
||||||
|
</n-button>
|
||||||
|
<n-select v-model:value="activeGID" :options="joinedGroup.map(gid => { return { label: gid, value: gid } })" v-show="activeGID !== null"
|
||||||
|
placeholder="未加入群组" style="flex:1;user-select: none;" />
|
||||||
|
</n-flex>
|
||||||
</n-flex>
|
</n-flex>
|
||||||
|
<!-- <n-flex style="padding-top: 10px;padding-bottom: 10px;">
|
||||||
|
<n-select v-model:value="activeGID" :options="joinedGroup.map(gid => { return { label: gid, value: gid } })"
|
||||||
|
placeholder="选择当前查看群组" style="flex:1" />
|
||||||
|
<n-button @click="shareWithQR()" :disabled="activeGID === null"
|
||||||
|
:type="activeGID === null ? 'default' : 'primary'">
|
||||||
|
分享群组
|
||||||
|
</n-button>
|
||||||
|
</n-flex> -->
|
||||||
|
<!-- <n-data-table :columns="columns"
|
||||||
|
:data="activeGID ? Messages[activeGID].map(v => { v.timestampString = new Date(v.timestamp).toLocaleString(); return v }).reverse() : []"
|
||||||
|
:row-props="null" :bordered="false" :single-line="false" :max-height="400" /> -->
|
||||||
|
<div style="flex:1; position: relative;min-height: none;">
|
||||||
|
<chatui style="margin-bottom: 10px; height: 65vh"
|
||||||
|
:messages="activeGID ? Messages[activeGID].map(v => { v.timestampString = new Date(v.timestamp).toLocaleString(); return v }).reverse() : []"/>
|
||||||
|
|
||||||
|
<n-input v-model:value="msg" type="textarea" placeholder="发送信息" :autosize="{
|
||||||
|
minRows: 1,
|
||||||
|
maxRows: 2
|
||||||
|
}" @keydown="handleKeyDown">
|
||||||
|
<template #suffix>
|
||||||
|
<n-icon :component="SendOutline" style="cursor: pointer;" @click='sendMsg(activeGID, msg)'/>
|
||||||
|
</template>
|
||||||
|
</n-input>
|
||||||
|
|
||||||
|
<!-- <n-button @click="sendMsg(activeGID, msg)" :disabled="msg === '' || activeGID === null"
|
||||||
|
:type="msg === '' || activeGID === null ? 'default' : 'primary'">
|
||||||
|
发送消息
|
||||||
|
</n-button> -->
|
||||||
|
</div>
|
||||||
</n-flex>
|
</n-flex>
|
||||||
<!-- <n-text> createTest gID:{{ gID }}<br />key:{{ key }}<br />code:{{ gID+key }}</n-text>
|
|
||||||
<n-input
|
|
||||||
v-model:value="codeInput"
|
|
||||||
type="textarea"
|
|
||||||
placeholder="测试加入群组"
|
|
||||||
/>
|
|
||||||
<n-button @click="joinGroup(codeInput)">
|
|
||||||
joinTest
|
|
||||||
</n-button> -->
|
|
||||||
<n-input v-model:value="msg" type="textarea" placeholder="测试发送信息" :autosize="{
|
|
||||||
minRows: 3,
|
|
||||||
maxRows: 3
|
|
||||||
}" />
|
|
||||||
<n-flex style="padding-top: 10px;padding-bottom: 10px;">
|
|
||||||
<n-select v-model:value="activeGID" :options="joinedGroup.map(gid => { return { label: gid, value: gid } })"
|
|
||||||
placeholder="选择当前查看群组" style="flex:1" />
|
|
||||||
<n-button @click="sendMsg(activeGID, msg)" :disabled="msg === '' || activeGID === null"
|
|
||||||
:type="msg === '' || activeGID === null ? 'default' : 'primary'">
|
|
||||||
发送消息
|
|
||||||
</n-button>
|
|
||||||
<n-button @click="shareWithQR()" :disabled="activeGID === null"
|
|
||||||
:type="activeGID === null ? 'default' : 'primary'">
|
|
||||||
分享群组
|
|
||||||
</n-button>
|
|
||||||
</n-flex>
|
|
||||||
<!-- <n-button @click="dataTest.length = 0">
|
|
||||||
clearMsg
|
|
||||||
</n-button> -->
|
|
||||||
<n-data-table :columns="columns"
|
|
||||||
:data="activeGID ? Messages[activeGID].map(v => { v.timestampString = new Date(v.timestamp).toLocaleString(); return v }).reverse() : []"
|
|
||||||
:row-props="null" :bordered="false" :single-line="false" :max-height="400" />
|
|
||||||
|
|
||||||
|
|
||||||
<n-modal v-model:show="showModal">
|
<n-modal v-model:show="showModal">
|
||||||
@@ -58,7 +64,9 @@
|
|||||||
role="dialog"
|
role="dialog"
|
||||||
aria-modal="true"
|
aria-modal="true"
|
||||||
>
|
>
|
||||||
<n-qr-code :value="QRCodeData" style="padding: 0;" :size="256" error-correction-level="Q" :v-if="showModal" :icon-src='QRIconUrl' :icon-size="128"/>
|
<n-qr-code :value="QRCodeData" style="padding: 0;" :size="256" error-correction-level="Q" :v-if="showModal"
|
||||||
|
:icon-src='0?QRIconUrl:null'
|
||||||
|
:icon-size="128"/>
|
||||||
</n-card>
|
</n-card>
|
||||||
</n-modal>
|
</n-modal>
|
||||||
</template>
|
</template>
|
||||||
@@ -72,8 +80,9 @@ import { useSettingStore } from "@/pinia/store";
|
|||||||
import { generateKey, encryptString } from '@/func/upload';
|
import { generateKey, encryptString } from '@/func/upload';
|
||||||
import { decryptString } from '@/func/download';
|
import { decryptString } from '@/func/download';
|
||||||
import WebsocketHeartbeatJs from 'websocket-heartbeat-js';
|
import WebsocketHeartbeatJs from 'websocket-heartbeat-js';
|
||||||
import { CopyOutline } from '@vicons/ionicons5'
|
import { CopyOutline,SendOutline } from '@vicons/ionicons5'
|
||||||
import getQueryString from '@/func/getQuery'
|
import getQueryString from '@/func/getQuery'
|
||||||
|
import chatui from "@/components/chatui.vue"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -122,6 +131,10 @@ const columnsTest = [
|
|||||||
key: "msg"
|
key: "msg"
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
function handleKeyDown(e){
|
||||||
|
console.log(e)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// 用于二维码分享
|
// 用于二维码分享
|
||||||
const showModal = ref(false)
|
const showModal = ref(false)
|
||||||
@@ -212,7 +225,7 @@ socket.onmessage = (event) => {
|
|||||||
} else if (type === 'gMsg') {
|
} else if (type === 'gMsg') {
|
||||||
let gID = msg.gID
|
let gID = msg.gID
|
||||||
let key = gID2key[gID].key
|
let key = gID2key[gID].key
|
||||||
Messages.value[msg.gID].push({ type: msg.type, msg: decryptString(key, msg.msg), from: msg.from, timestamp: msg.timestamp })
|
Messages.value[msg.gID].push({ type: msg.type,type1:msg.type1, msg: decryptString(key, msg.msg), from: msg.from, timestamp: msg.timestamp })
|
||||||
// console.log(Messages.value)
|
// console.log(Messages.value)
|
||||||
dataTest.value.push({ from: 'decrypt', msg: decryptString(key, msg.msg) })
|
dataTest.value.push({ from: 'decrypt', msg: decryptString(key, msg.msg) })
|
||||||
}
|
}
|
||||||
@@ -261,11 +274,18 @@ function joinGroup_Verify(gID) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function sendMsg(gID, msg) {
|
function sendMsg(gID, msg) {
|
||||||
|
if(msg === '' || activeGID.value === null)return
|
||||||
let key = gID2key[gID].key
|
let key = gID2key[gID].key
|
||||||
msg = encryptString(key, msg, setting)
|
msg = encryptString(key, msg, setting)
|
||||||
socket.send(JSON.stringify({ type: 'message', msg, gID }))
|
socket.send(JSON.stringify({ type: 'message',type1:'text', msg, gID }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sendImg(gID,code){
|
||||||
|
if(msg === '' || activeGID.value === null)return
|
||||||
|
let key = gID2key[gID].key
|
||||||
|
msg = encryptString(key, msg, setting)
|
||||||
|
socket.send(JSON.stringify({ type: 'message',type1:'img', msg, gID }))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 通过地址传参并加入传入的群组
|
// 通过地址传参并加入传入的群组
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ async function login() {
|
|||||||
settingData.setJWT(data.token,keepTokenLocal)
|
settingData.setJWT(data.token,keepTokenLocal)
|
||||||
settingData.setUserID(userIDInput.value,keepTokenLocal)
|
settingData.setUserID(userIDInput.value,keepTokenLocal)
|
||||||
settingData.setUserGroup(data.userGroup,keepTokenLocal)
|
settingData.setUserGroup(data.userGroup,keepTokenLocal)
|
||||||
|
message.success(`登录成功`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
isLogining.value = false
|
isLogining.value = false
|
||||||
message.error(`登录失败`);
|
message.error(`登录失败`);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<n-text style="font-size: 16px;user-select: none;">点击此处或者拖动文件到该区域来上传</n-text>
|
<n-text style="font-size: 16px;user-select: none;">点击此处或者拖动文件到该区域来上传</n-text>
|
||||||
<n-p depth="3" style="margin: 8px 0 0 0;user-select: none;">
|
<n-p depth="3" style="margin: 8px 0 0 0;user-select: none;">
|
||||||
最大支持200MB大小文件,其实只是懒得做分片上传而已
|
最大支持200MB大小文件,其实只是懒得做分片上传而已
|
||||||
<br />虽然理论上没有人有能力审查你上传的东西
|
<!-- <br />虽然理论上没有人有能力审查你上传的东西 -->
|
||||||
<br />反正没人用写这么多干什么。。。
|
<br />反正没人用写这么多干什么。。。
|
||||||
</n-p>
|
</n-p>
|
||||||
</n-upload-dragger>
|
</n-upload-dragger>
|
||||||
|
|||||||
Reference in new issue
Block a user