152
社区成员




目录
这个作业属于哪个课程 | 2023-计算机学院-软件工程 |
---|---|
这个作业要求在哪里 | 团队作业——站立式会议+alpha冲刺 |
这个作业的目标 | No.1-南波兔 冲刺随笔 Day6 |
团队名称 | No.1-南波兔 |
团队项目 | 小福出行 |
团队置顶集合随笔链接 | No.1-南波兔——Alpha 冲刺随笔置顶 |
成员 | 任务 | 存在的问题/遇到的困难 | 从现在到明天站立式会议的安排 | 心得体会 |
102101108徐悦昕 | 优化功能,开发聊天页面后端,设计相关接口 | 对于框架并不是很熟悉,刚开始开发的时候产生了许多bug | 继续完善相关内容 | 还需要继续学习 |
102101206陈妍 | 完善帖子页面的部分后端代码,优化功能 | 无 | 继续完善帖子页面的相关后端代码 | 在项目开发过程中,我们要注重良好的前后端交流。 |
102101310黃心怡 | 整合代码 | 代码不够规范 | 继续完善相关内容 | 代码规范很重要 |
102101602杜雅婷 | 完善页面,测试相关功能 | 发现bug,进行处理 | 继续完善相关内容 | 加强沟通,和组员多交流代码中的问题 |
102101603李欣妍 | 完善广场及编辑帖子页面 | 无 | 完善广场及编辑帖子页面 | 继续加油 |
102101604杨嘉鑫 | 设计聊天前端页面,开发我的管理模块 | 无 | 继续完善聊天前端页面,开发我的管理模块-我的拼车前端页面 | 良好的代码质量和规范对项目的成功至关重要 |
102101605林盈盈 | 编写接口,完善数据库设计 | 交互 | 继续完善相关内容 | 和组员的沟通很重要 |
102101607郭紫莹 | 设计用户界面相关接口,实现部分功能 | 调试 | 继续学习,完善相关内容 | 在前后端交互的过程中,数据的传输和处理是非常重要的。需要注意数据的格式、编码问题 |
102101622何卓穎 | 完善修改密码前端页面 | 无 | 继续完善完善登录注册及修改密码前端页面 | 项目的编写需要尽早开始,留足时间做测试、优化和修改 |
消息界面与我的管理模块
前端:
<template>
<view class="chat-page">
<scroll-view class="chat-list" scroll-y>
<view v-for="(message, index) in messages" :key="index">
<view class="messageLeft" v-show="message.huiFlag"> {{ message.msg }} </view>
<view class="messageRight" v-show="message.faFlag"> {{ message.msg }} </view>
</view>
</scroll-view>
<view class="text-input-wrapper">
<input class="text-input" type="text" v-model="inputText" placeholder="请输入消息内容" />
<view class="send-button" @click="sendMessage">发送</view>
</view>
</view>
</template>
<script>
import mqtt from "mqtt";
import {MQTT_IP, MQTT_OPTIONS} from "@/common/mqtt";
let client;
export default {
data() {
return {
topic : "PCAR-CHAT",
userId : "",
messages: [{
msg : "",
huiFlag : false,
faFlag : false
}
],
inputText: ''
};
},
onLoad() {
this.userId = this.$route.query.id;
if(client == null){
this.connect();
}
this.init()
},
methods: {
init(){
this.$u.api.chatList({
toUserId : this.userId,
fromUserId : localStorage.getItem("tokenId")
}).then(res =>{
if(res){
this.messages = [];
for (const resKey of res) {
let obj={};
obj.msg = resKey.msg;
if(resKey.toUserId == localStorage.getItem("tokenId")){
obj.huiFlag = true
obj.faFlag = false
}else {
obj.huiFlag = false
obj.faFlag = true
}
this.messages.push(obj);
}
}
})
},
connect() {
MQTT_OPTIONS.clientId = "PCAR_CHAT_"+localStorage.getItem("tokenId")
const that = this;
client = mqtt.connect('ws://' + MQTT_IP, MQTT_OPTIONS);
client.on('connect', function() {
console.log('连接成功')
client.subscribe(that.topic+"-"+that.userId,function (err){
if (!err) {
console.log(that.topic+"-"+that.userId+'订阅成功')
}
})
}).on('reconnect', function(error) {
console.log('正在重连...', that.topic)
}).on('error', function(error) {
console.log('连接失败...', error)
}).on('end', function() {
console.log('连接断开')
}).on('message', function(topic, message) {
// if(topic != (that.topic+"-"+that.userId)){
that.init();
console.log(topic+'接收推送信息:', message.toString())
// }
})
},
sendMessage() {
if (this.inputText === '') {
return; // 如果输入内容为空,则不发送
}
this.$u.api.addChat({
toUserId : this.userId,
fromUserId : localStorage.getItem("tokenId"),
msg : this.inputText
}).then(res =>{
if(res){
this.init();
this.inputText = '';
}
})
// this.messages.push({
// huiFlag : false,
// faFlag : true,
// fromUserId : localStorage.getItem("tokenId"),
// toUserId : this.userId,
// msg: this.inputText
// });
}
}
};
</script>
<style>
.chat-page {
margin-top: 10px;
display: flex;
flex-direction: column;
height: 90vh;
}
.chat-list {
flex: 1;
padding: 10px;
}
.messageLeft {
margin-bottom: 10px;
padding: 10px;
background-color: #e7e7e7;
border-radius: 5px;
}
.messageRight{
margin-bottom: 10px;
margin-right: 10px;
padding: 10px;
background-color: #e7e7e7;
border-radius: 5px;
text-align: right
}
.text-input-wrapper {
display: flex;
align-items: center;
padding: 10px;
background-color: #f5f5f5;
}
.text-input {
flex: 1;
height: 40px;
margin-right: 10px;
padding: 5px 10px;
background-color: #ffffff;
border-radius: 4px;
border: 1px solid #ccc;
}
.send-button {
width: 60px;
height: 40px;
line-height: 40px;
text-align: center;
background-color: #007aff;
color: #ffffff;
border-radius: 4px;
}
</style>
<template>
<view>
<view class="my-page">
<image class="avatar" src="" />
<text class="nickname">{{ nickname }} {{account}}</text>
<navigator url="/pages/posts/addPosts" hover-class="navigator-hover">
<view class="module">
<text class="module-title">发起拼车</text>
</view>
</navigator>
<navigator url="/pages/posts/myIndex" hover-class="navigator-hover">
<view class="module">
<text class="module-title">我的发帖</text>
</view>
</navigator>
<navigator url="/pages/msg/index" hover-class="navigator-hover">
<view class="module">
<text class="module-title">我的消息</text>
</view>
</navigator>
<navigator url="/pages/my/userInfo" hover-class="navigator-hover">
<view class="module">
<text class="module-title">我的资料</text>
</view>
</navigator>
<button class="logout-btn" @click="logout">退出登录</button>
</view>
<Foot/>
</view>
</template>
<script>
import Foot from "@/components/foot.vue";
export default {
components: {
Foot
},
data() {
return {
account: localStorage.getItem("token"),
nickname: ""
}
},
onLoad() {
this.$u.api.userInfo({
id : localStorage.getItem("tokenId")
}).then(res => {
if(res){
this.nickname = res.nickname;
}
});
},
methods: {
logout() {
localStorage.removeItem("token");
localStorage.removeItem("tokenId");
uni.redirectTo({
url: '/pages/index/index'
})
}
}
}
</script>
<style scoped>
.my-page {
padding: 20px;
font-size: 16px;
}
.avatar {
width: 100px;
height: 100px;
border-radius: 50%;
}
.nickname {
font-size: 20px;
margin-top: 10px;
}
.module {
margin-top: 20px;
border-bottom: 1px solid #ccc;
padding-bottom: 20px;
}
.module-title {
font-size: 18px;
font-weight: bold;
margin-bottom: 10px;
}
.logout-btn {
width: 100%;
height: 40px;
background: #ff4d4f;
border: none;
border-radius: 5px;
color: #fff;
font-size: 16px;
margin-top: 20px;
}
</style>
后端
package com.han.app.controller;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.han.app.config.Result;
import com.han.app.controller.dto.ChatDto;
import com.han.app.controller.vo.ChatInfoVo;
import com.han.app.entity.ChatInfo;
import com.han.app.entity.Post;
import com.han.app.entity.User;
import com.han.app.mqtt.MqttPushClient;
import com.han.app.service.ChatInfoService;
import com.han.app.service.UserService;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.*;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/Chat")
@RequiredArgsConstructor
public class ChatController {
private final MqttPushClient mqttPushClient;
private final ChatInfoService chatInfoService;
private final UserService userService;
@PostMapping("/SendMsg")
public Result sendMsg(@RequestBody ChatInfo dto){
dto.setFromToUserId(dto.getFromUserId()+"-"+dto.getToUserId());
if(dto.getFromUserId() > dto.getToUserId()){
dto.setFromToUserId(dto.getToUserId()+"-"+dto.getFromUserId());
}
dto.setAddTime(new Date());
chatInfoService.save(dto);
System.out.println("给 PCAR-CHAT-"+dto.getToUserId()+" 发送 "+dto.getMsg());
mqttPushClient.publish("PCAR-CHAT-"+dto.getToUserId(),dto.getMsg());
return Result.ok("ok");
}
@PostMapping("/ChatList")
public Result chatList(@RequestBody ChatDto dto){
String key = dto.getFromUserId()+"-"+dto.getToUserId();
if(dto.getFromUserId() > dto.getToUserId()){
key = (dto.getToUserId()+"-"+dto.getFromUserId());
}
LambdaQueryWrapper<ChatInfo> lqw = new LambdaQueryWrapper<>();
lqw.eq(ChatInfo::getFromToUserId,key).orderByDesc(ChatInfo::getAddTime).last(" limit 10");
List<ChatInfo> list = chatInfoService.list(lqw);
List<ChatInfo> collect = list.stream().sorted(Comparator.comparing(ChatInfo::getId)).collect(Collectors.toList());
return Result.ok(collect);
}
@PostMapping("/DeleteChat")
public Result deleteChat(@RequestBody ChatDto dto){
String key = dto.getFromUserId()+"-"+dto.getToUserId();
if(dto.getFromUserId() > dto.getToUserId()){
key = (dto.getToUserId()+"-"+dto.getFromUserId());
}
LambdaQueryWrapper<ChatInfo> lqw = new LambdaQueryWrapper<>();
lqw.eq(ChatInfo::getFromToUserId,key);
chatInfoService.remove(lqw);
return Result.ok("ok");
}
@PostMapping("/ChatUserList")
public Result chatUserList(@RequestBody ChatDto dto){
LambdaQueryWrapper<ChatInfo> lqw = new LambdaQueryWrapper<>();
lqw.like(ChatInfo::getFromToUserId,dto.getFromUserId()).groupBy(ChatInfo::getFromToUserId).orderByAsc(ChatInfo::getAddTime);
List<ChatInfo> list = chatInfoService.list(lqw);
ArrayList<ChatInfoVo> resList = new ArrayList<>();
if(CollUtil.isNotEmpty(list)){
HashSet<Integer> set = new HashSet<>();
for (ChatInfo chatInfo : list) {
set.add(chatInfo.getFromUserId());
set.add(chatInfo.getToUserId());
}
LambdaQueryWrapper<User> userLqw = new LambdaQueryWrapper<>();
userLqw.in(User::getId,set);
List<User> userList = userService.list(userLqw);
Map<Integer, String> collect = userList.stream().collect(Collectors.toMap(User::getId, User::getAccount));
for (ChatInfo chatInfo : list) {
ChatInfoVo vo = new ChatInfoVo();
vo.setMsg(chatInfo.getMsg());
if(NumberUtil.equals(chatInfo.getFromUserId(),dto.getFromUserId()) ){
vo.setUserName(collect.getOrDefault(chatInfo.getToUserId(),""));
vo.setUserId(chatInfo.getToUserId());
}else {
vo.setUserName(collect.getOrDefault(chatInfo.getFromUserId(),""));
vo.setUserId(chatInfo.getFromUserId());
}
resList.add(vo);
}
}
return Result.ok(resList);
}
}
package com.han.app.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
/**
*
* @TableName chat_info
*/
@TableName(value ="chat_info")
@Data
public class ChatInfo implements Serializable {
/**
*
*/
@TableId(type = IdType.AUTO)
private Integer id;
/**
*
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date addTime;
/**
*
*/
private Integer fromUserId;
/**
*
*/
private Integer toUserId;
/**
*
*/
private String msg;
/**
*
*/
private String fromToUserId;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}