Commit 57fa177a authored by Ruizi Yu's avatar Ruizi Yu
Browse files

nealy finshed

parent 58b938ad
......@@ -4,7 +4,6 @@ body {
background: url('https://pica.zhimg.com/80/v2-6751d05491af76c00c1a2a9102ac2cc4_1440w.webp?source=1940ef5c') no-repeat center center fixed;
background-size: cover;
overflow-x: hidden;
}
.container
......@@ -17,7 +16,6 @@ body {
{
width: 25%;
border: 2px solid rgba(255, 255, 255, 0.5);
background: transparent;
backdrop-filter: blur(8px);
......@@ -52,9 +50,13 @@ body {
border-radius: 5px;
color: aliceblue;
margin: 5px;
padding-bottom: 5px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
/* text-overflow: ellipsis; */
border-bottom: 2px solid rgba(255, 255, 255, 0.5);
border-right: 2px solid rgba(255, 255, 255, 0.5);
height:100px;
}
/* .room_message
{
......@@ -64,12 +66,31 @@ body {
{
display:flex;
justify-content: space-between;
height:60%;
}
.room p
{
margin-left: 10px;
margin-right: 10px;
}
.room h3
{
margin-left: 10px;
margin-right: 10px;
width: 40%;
overflow: hidden;
text-overflow: ellipsis;
}
.room-time {
color: rgb(143, 144, 144);
font-size: 0.9em;
overflow: hidden;
text-overflow: ellipsis;
}
.room-message {
overflow: hidden;
text-overflow: ellipsis;
}
.room.clicked
{
background-color:#ffffff40;
......@@ -87,12 +108,21 @@ body {
/* background-color:#ffffffc1; */
color: aliceblue;
padding-left: 10px;
height:60px;
}
.listTitle.room_list
{
display:flex;
justify-content: space-between;
white-space: nowrap;
/* overflow: hidden;
text-overflow: ellipsis; */
}
.listTitle.room_list h3 {
width: 70%;
overflow: hidden;
text-overflow: ellipsis;
}
.add_room
......@@ -102,10 +132,15 @@ body {
background: transparent;
background-color:#ffffffa2;
background-color:#ffffff40;
margin-top: 6px;
margin-bottom: 6px;
margin-right: 7px;
padding-bottom: 0;
padding-top: 0;
line-height: 1;
color: aliceblue;
overflow: hidden;
text-overflow: ellipsis;
}
.add_room:hover
......@@ -115,19 +150,22 @@ body {
.chatroom
{
height:80vh;
/* height:80vh; */
flex:1;
border-bottom:2px solid rgba(255, 255, 255, 0.5);
overflow: auto;
padding-bottom: 10px;
}
.input
{
flex:1;
/* flex:1; */
background: transparent;
background-color:#ffffff40;
padding:2vh;
padding:10px;
display:flex;
justify-content: space-between;
/* height:60px; */
}
.input_blank
......@@ -135,6 +173,7 @@ body {
background: transparent;
border-radius: 1vh;
width:90%;
height: 30px;
}
.input_blank:hover
......@@ -153,6 +192,7 @@ body {
padding-top: 0;
line-height: 1;
color: aliceblue;
height: 30px;
}
.submit:hover
......@@ -164,28 +204,42 @@ body {
{
display:flex;
}
.message_item.host
{
display:flex;
flex-direction: row-reverse;
justify-content: flex-start;
}
.head_photo
{
background-color: aliceblue;
margin: 10px;
text-align: center;
border-radius: 4px;
height: 8vh;
width: 8vh;
height: 50px;
width: 50px;
}
.head
{
flex:1;
display:flex;
flex-direction: column;
}
.nickname
.head.host
{
flex:1;
display:flex;
flex-direction: column;
align-items: flex-end
}
.nickname
{
/* flex:1; */
color: aliceblue;
font-size: 0.9em;
display: flex;
justify-content: space-between;
padding-right: 20px;
/* justify-content: space-between; */
/* padding-right: 20px; */
}
.message_time
{
......@@ -193,13 +247,14 @@ body {
}
.message
{
margin-right: 20px;
/* margin-right: 20px; */
display: inline-block;
background-color: #f2f2f2;
padding-left: 10px;
padding-right: 10px;
border-radius: 4px;
min-width: 50px;
max-width: 450px;
}
.context-menu
......@@ -276,4 +331,21 @@ input:valid ~ label {
font-size: 1em;
padding: 0 35px 0 5px;
color: #fff;
}
.add-windows h2 {
color: #fff;
text-align: center;
}
.chatroom_empty-roomId {
flex:1;
display: flex;
justify-content: center;
align-items: center;
}
.chatroom_empty-roomId h2{
color: #fff;
text-align: center;
}
\ No newline at end of file
import React , { useEffect, useState } from "react";
import "./ChatRoom.css";
//房间组件
interface RoomEntryProps {
roomId: number;
roomName: string;
lastMessage: MessageProps | null;
onDelete: (index: number) => void;
selectedRoomId:number;
setSelectedRoomId: React.Dispatch<React.SetStateAction<number>>;
}
function RoomEntry (props:RoomEntryProps) {
const [isContextMenuVisible, setContextMenuVisible] = useState(false);
const [contextMenuStyle, setContextMenuStyle] = useState({});
// const [deleteId,setDeleteId] = useState<number | null>(null);
import useSWR from "swr";
import useSWRMutation from "swr/mutation";
//右键点击
function handleContextMenu(e: { preventDefault: () => void; button: number; clientY: any; clientX: any; }) {
e.preventDefault(); // 阻止默认的右键菜单
import "./ChatRoom.css";
import { RoomEntry } from "./RoomEntry";
import {MessageItem} from "./MessageItem";
if (e.button === 2) {
const style = {
top: `${e.clientY}px`,
left: `${e.clientX}px`,
};
import { getFetcher } from "../../util";
import { postFetcher } from "../../util";
// 显示右键菜单
setContextMenuStyle(style);
setContextMenuVisible(true);
import { RoomAddArgs } from "../../vite-env";
import { RoomAddRes } from "../../vite-env";
import { RoomListRes } from "../../vite-env";
import { RoomDeleteArgs } from "../../vite-env";
import { MessageAddArgs } from "../../vite-env";
import { RoomMessageListArgs } from "../../vite-env";
import { RoomMessageListRes } from "../../vite-env";
import { RoomMessageGetUpdateArgs } from "../../vite-env";
import { RoomMessageGetUpdateRes } from "../../vite-env";
// setDeleteId(props.roomId);
}
}
//左键点击
function handleRoomClick () {
props.setSelectedRoomId(props.roomId);
}
//删除房间
function handleDeleteRoom() {
setContextMenuVisible(false);
props.onDelete(props.roomId);
if (props.selectedRoomId === props.roomId) {
props.setSelectedRoomId(-1);
}
}
return(
<>
{/* 判断该房间是否为选中的房间 */}
<div className={`room ${props.selectedRoomId === props.roomId ? "clicked" : ""}`} onContextMenu={handleContextMenu} onClick={handleRoomClick}>
<div>
<p>{props.roomName}</p>
<p>{props.lastMessage?.time??'刚刚'}</p>
</div>
<p>{props.lastMessage?.sender??'[新建了一个房间]'}</p>
</div>
{isContextMenuVisible && (
<div className="context-menu" style={contextMenuStyle}>
<div onClick={()=>handleDeleteRoom()}>删除房间</div>
</div>
)}
</>
);
}
export default function ChatRoom () {
//消息组件
interface MessageProps {
messageId: number;
roomId: number;
sender: string;
content: string;
time: number;
}
function MessageItem (props:MessageProps) {
const formattedTime = new Date(props.time).toLocaleString();
//定义部分
return(
<>
<div className="message_item">
<div className="head_photo">
<p>头像</p>
</div>
<div className="head">
<div className="nickname">
<p>{props.sender}:</p>
<p className="message_time">{formattedTime}</p>
</div>
<div>
<div className="message">
<p>{props.content}</p>
</div>
</div>
</div>
</div>
</>
);
const [roomId, setRoomId] = useState<number | null>(null);//定义“全局变量”roomId,选中房间时更改
const [isAddingRoom,setIsAddingRoom]=useState(false);//添加房间弹窗定义
const nickname = localStorage.getItem('nickname')??'';//昵称
var text = "";
var room_text = "";
}
export default function ChatRoom () {
//post请求(借助trigger)
//创建房间
const { trigger: addTrigger, isMutating } = useSWRMutation <
{ roomId: number },
null,
string,
{
user: string;
roomName: string;
}
>("/api/room/add", postFetcher);
//获取房间列表
const{
data:roomData,
// error:roomError,
// isLoading:roomIsLoading,
} = useSWR<RoomListRes>("/api/room/list",getFetcher, {
refreshInterval: 1000,
});
// if(roomIsLoading)return<Loading />;
// if(roomError)return<Errorwindow />;
// const roomList = roomData?.rooms;
//get请求获取聊天房间列表
//删除房间
const { trigger: deleteTrigger } = useSWRMutation <
null,
null,
string,
{
user: string;
roomId: number | null;
}
>("/api/room/delete", postFetcher);
//选择的房间的状态定义
const [selectedRoomId, setSelectedRoomId] = useState(-1);
// 房间组件定义
type Entry = {
roomname:string;
};
const [roomEntries, setRoomEntries] = useState<Entry[]>([]);
var room_text = "";
//消息组件定义
type Messages = {
//添加一条消息
const { trigger: messageTrigger } = useSWRMutation <
null,
null,
string,
{
roomId: number | null;
content: string;
time: number;
roomId:number;
};
const [messages, setMessages] = useState<Messages[]>([]);
var text = "";
sender: string;
}
>("/api/message/add", postFetcher);
//获取某一房间的历史消息记录
const {
data:messageListData,
// error:messageListError,
// isLoading:messageListIsLoading,
} = useSWR<RoomMessageListRes>(
() => {
//有依赖的数据请求
if (roomId === null) return false;
return "/api/room/message/list?roomId=" + roomId;
},
getFetcher,
{
refreshInterval: 1000,
}
);
//添加房间弹窗定义
const[isAddingRoom,setIsAddingRoom]=useState(false);
//函数部分
//添加房间
function addRoom(event: { preventDefault: () => void; }) {
event.preventDefault();
setIsAddingRoom(true);
// setRoomEntries(prevEntries => [...prevEntries, prevEntries.length]);
}
function handleRoomNameChange(event: {
preventDefault(): unknown; target: { value: string; }
}) {
function handleRoomNameChange(event: {preventDefault(): unknown; target: { value: string; }}) {
room_text = event.target.value;
event.preventDefault();
}
function addWindowsSubmit() {
const newEntry = {
roomname:room_text
}
setRoomEntries(prevEntries => [...prevEntries, newEntry]);
async function addWindowsSubmit() {
const newId = await addTrigger({ user:nickname, roomName:room_text });
// if(newId) setRoomId(Number(newId));
// console.log(roomId);
setIsAddingRoom(false);
}
// useEffect(() => {
// console.log(roomId); // 可以在控制台打印最新的 roomId
// // 进行其他操作或触发重新渲染
// }, [roomId]);
// function updateRoomId(newId:number) {
// setRoomId(newId);
// console.log(roomId);
// }
//删除房间
function handleDeleteRoom(index: number) {
setRoomEntries(prevEntries => prevEntries.filter((_, i) => i !== index)); // 通过过滤删除指定索引的房间
async function handleDeleteRoom(deleteRoomId: number) {
await deleteTrigger({ user:nickname, roomId:deleteRoomId });
}
//消息框内容改变监测函数
//发送消息
function messageChange(event: { target: { value: string; }; preventDefault: () => void; }) {
text = event.target.value;
event.preventDefault();
}
//提交函数
function handleSubmit(event: { preventDefault: () => void; }) {
const currentTime = Date.now();
const newMessage = {
content:text,
time:currentTime,
roomId:selectedRoomId
}
event.preventDefault();
async function handleSubmit(event: { preventDefault: () => void; }) {
setMessages(prevMessages => [...prevMessages, newMessage]);
console.log(messages);
await messageTrigger({ roomId:roomId, content:text, sender:nickname});
event.preventDefault();
const inputElement = document.querySelector('.input_blank') as HTMLInputElement;
if (inputElement) {
inputElement.value = '';
}
}
// useEffect(() => {
// const interval = setInterval(() => {
// setMessages(prevMessages => [...prevMessages, newMessage]);
// },1000);
// return () => {clearInterval(interval);}
// },[selectedRoomId])
//渲染内容
//渲染内容
return(
<>
<div className="container">
{/* 消息列表 */}
<div className = "roomList">
<div className="listTitle room_list">
<h3>昵称</h3>
<h3>Hello! {nickname}</h3>
<button className="add_room" onClick={addRoom}>新建房间</button>
</div>
{/* 渲染房间 */}
<div className = "roomlist">
{roomEntries.map((entry,index) => (
{roomData?.rooms.map((entry,_) => (
<RoomEntry
key={index}
roomId={index}
roomId={entry.roomId}
roomName={entry.roomName}
lastMessage={entry.lastMessage}
onDelete={handleDeleteRoom}
roomName={entry.roomname}
lastMessage={null}
setSelectedRoomId={setSelectedRoomId}
selectedRoomId={selectedRoomId}
setSelectedRoomId={setRoomId}
selectedRoomId={roomId}
/>
))}
</div>
</div>
{/* 聊天房间页面 */}
<div className = "messagelist">
{roomId && <div className = "messagelist">
<div className="listTitle">
<h3>房间一</h3>
<h3>
{
roomData?.rooms.map((entry,_) => {
if(entry.roomId === roomId) {
return (
entry.roomName
)
}
})
}
</h3>
</div>
<div className='chatroom'>
{messages.map((message, index) => {
if (message.roomId === selectedRoomId) {
return (
<MessageItem
key={index}
messageId={index}
roomId={message.roomId}
sender={"昵称"}
content={message.content}
time={message.time}
/>
);
} else {
return null;
}
{messageListData?.messages.map((message, _) => {
return (
<MessageItem
messageId={message.messageId}
roomId={message.roomId}
sender={message.sender}
content={message.content}
time={message.time}
user={nickname}
/>
);
})}
</div>
......@@ -250,7 +216,15 @@ export default function ChatRoom () {
<input type="text" required className="input_blank" onChange={messageChange} />
<button className="submit" onClick={handleSubmit}>发送</button>
</div>
</div>}
{!roomId &&
<div className="chatroom_empty-roomId">
<h2>
请点击左侧房间开始聊天!
</h2>
</div>
}
{isAddingRoom && (
<div className="add-windows">
......@@ -265,4 +239,17 @@ export default function ChatRoom () {
</div>
</>
);
}
\ No newline at end of file
}
function Loading() {
return(
window.prompt("Loading...")
);
}
function Errorwindow() {
return(
window.prompt("Error!")
);
}
import React , { useEffect, useState } from "react";
import "./ChatRoom.css";
import {MessageProps} from "../../vite-env";
export function MessageItem (props:MessageProps) {
const formattedTime = new Date(props.time).toLocaleString();
const nickname = props.sender;
const firstCharacter = nickname.charAt(0);
return(
<>
<div className={`message_item ${props.user === nickname ? "host" : ""}`}>
<div className="head_photo">
<p>{firstCharacter}</p>
</div>
<div className={`head ${props.user === nickname ? "host" : ""}`}>
<div className="nickname">
<p>{props.sender}:</p>
<p className="message_time">{formattedTime}</p>
</div>
<div>
<div className="message">
<p>{props.content}</p>
</div>
</div>
</div>
</div>
</>
);
}
\ No newline at end of file
import React , { useEffect, useState } from "react";
import "./ChatRoom.css";
import {RoomEntryProps} from "../../vite-env";
export function RoomEntry (props:RoomEntryProps) {
const [isContextMenuVisible, setContextMenuVisible] = useState(false);
const [contextMenuStyle, setContextMenuStyle] = useState({});
let formattedTime;
if (props.lastMessage?.time !== undefined) {
formattedTime = new Date(props.lastMessage?.time).toLocaleString();
}
// const [deleteId,setDeleteId] = useState<number | null>(null);
//右键点击
function handleContextMenu(e: { preventDefault: () => void; button: number; clientY: any; clientX: any; }) {
e.preventDefault(); // 阻止默认的右键菜单
if (e.button === 2) {
const style = {
top: `${e.clientY}px`,
left: `${e.clientX}px`,
};
// 显示右键菜单
setContextMenuStyle(style);
setContextMenuVisible(true);
// setDeleteId(props.roomId);
}
}
//左键点击
function handleRoomClick () {
props.setSelectedRoomId(props.roomId);
}
//删除房间
function handleDeleteRoom() {
setContextMenuVisible(false);
props.onDelete(props.roomId);
if (props.selectedRoomId === props.roomId) {
props.setSelectedRoomId(null);
}
}
return(
<>
{/* 判断该房间是否为选中的房间 */}
<div className={`room ${props.selectedRoomId === props.roomId ? "clicked" : ""}`} onContextMenu={handleContextMenu} onClick={handleRoomClick}>
<div>
<h3>{props.roomName}</h3>
<p className="room-time">
{formattedTime}
{/* {props.lastMessage?.time === undefined && '刚刚'} */}
</p>
</div>
<p className="room-message">{props.lastMessage?.sender??'系统'} : { props.lastMessage?.content??'无消息'}</p>
</div>
{isContextMenuVisible && (
<div className="context-menu" style={contextMenuStyle}>
<div onClick={()=>handleDeleteRoom()}>删除房间</div>
</div>
)}
</>
);
}
\ No newline at end of file
......@@ -33,7 +33,7 @@ section {
align-items: center;
}
h2 {
.form-value h2 {
font-size: 30px;
color: #fff;
text-align: center;
......
......@@ -4,15 +4,20 @@ import { Link } from 'react-router-dom';
export default function Setname() {
const [nickname, setNickname] = useState("");
// const [nickname, setNickname] = useState("");
var value = "";
function handleNicknameChange(event: { target: { value: any; }; }) {
setNickname(event.target.value);
function handleNicknameChange(event: {
preventDefault(): unknown; target: { value: string; };
}) {
value = event.target.value;
event.preventDefault();
}
// function handleSubmit() {
// window.location.href = "/index";
// }
function handleSubmit() {
// setNickname(value);
localStorage.setItem('nickname', value);
}
return(
<>
......@@ -22,7 +27,7 @@ export default function Setname() {
<form action=''>
<h2>欢迎</h2>
<div className="inputbox">
<input type="text" value={nickname} onChange={handleNicknameChange} required />
<input type="text" onChange={handleNicknameChange} required />
<label htmlFor="">昵称</label>
</div>
{/* <div className='inputbox'>
......@@ -30,7 +35,7 @@ export default function Setname() {
<label htmlFor="">密码</label>
</div> */}
<Link to = "/index">
<button className='setname-button'>登录</button>
<button onClick={handleSubmit} className='setname-button'>登录</button>
</Link>
</form>
</div>
......@@ -38,4 +43,4 @@ export default function Setname() {
</section>
</>
)
}
\ No newline at end of file
}
/// <reference types="vite/client" />
//默认返回
export interface Response<T> {
message: string;
code: number;
data: T | null;
}
export interface RoomEntryProps {
roomId: number;
roomName: string;
lastMessage: MessageProps | null;
onDelete: (index: number) => void;
selectedRoomId:number | null;
setSelectedRoomId: React.Dispatch<React.SetStateAction<number | null>>;
}
export interface MessageProps {
messageId: number;
roomId: number;
sender: string;
content: string;
time: number;
user: string;
}
export interface Message {
messageId: number;
roomId: number;
sender: string;
content: string;
time: number;
}
export interface RoomPreviewInfo {
roomId: number;
roomName: string;
lastMessage: MessageProps | null;
}
//创建房间
export interface RoomAddArgs {
user: string;
roomName: string;
}
export interface RoomAddRes {
roomId: number;
}
//获取房间列表
export interface RoomListRes {
rooms: RoomPreviewInfo[];
}
//删除房间
export interface RoomDeleteArgs {
user: string;
roomId: number;
}
//添加一条消息
export interface MessageAddArgs {
roomId: number;
content: string;
sender: string;
}
//获取某一房间的历史消息记录
export interface RoomMessageListArgs {
roomId: number;
}
export interface RoomMessageListRes {
messages: Message[];
}
//更新消息列表
export interface RoomMessageGetUpdateArgs {
roomId: number;
sinceMessageId: number;
}
export interface RoomMessageGetUpdateRes {
messages: Message[];
}
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment