| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494 |
- <template>
- <view class="page">
- <!-- 头部 -->
- <view class="header">
- <view class="back-button" @click="goBack()">
- <image src="/static/img/tabbar/out.png" alt="Back" />
- </view>
- <view class="title">
- {{ chaterName }}
- </view>
- </view>
- <!-- 消息展示区 -->
- <view class="message-area">
- <scroll-view :scroll-y="true" :scroll-top="scrollPosition.top" @scroll="handleScroll" ref="msgList">
- <view v-for="(message, index) in messages" :key="index"
- :class="['message', message.isMe ? 'me' : 'other']">
- <!-- 头像 (对方发送的消息) -->
- <view v-if="!message.isMe" class="avatar other-avatar">
- <image :src="message.avatar" alt="Avatar" />
- </view>
-
- <!-- 用户名和时间 -->
- <view class="username-time">
-
- <view v-if="!message.isMe" class="username">{{ message.username }}</view>
- <view v-if="!message.isMe" class="time">{{ message.time }}</view>
- <view v-if="message.isMe" class="username">{{ message.username }}</view>
- <view v-if="message.isMe" class="time">{{ message.time }}</view>
-
-
- <view class="message-content">
- <text>{{ message.content }}</text>
- </view>
- </view>
-
- <!-- 头像 (自己发送的消息) -->
- <view v-if="message.isMe" class="avatar me-avatar">
- <image :src="message.avatar" alt="Avatar" />
- </view>
- </view>
- </scroll-view>
- </view>
-
- <!-- 底部输入和工具栏 -->
- <view class="footer">
- <!-- 输入框 -->
- <view class="input-wrap">
- <input v-model="inputContent" type="text" :focus="isInputFocused" @confirm="sendConsultation" />
- </view>
-
- <!-- 工具栏 -->
- <view class="tools-wrap">
- <image src="/static/img/tabbar/guanzhu.png" @tap="openTools('emoji')" />
- <image src="/static/img/tabbar/guanzhu.png" @tap="openTools('plus')" />
- </view>
-
- <!-- 表情选择器 -->
- <view v-if="showEmojiPicker" class="emoji-picker-wrap">
- <tools ref="tools" />
- </view>
-
- <!-- 发送按钮 -->
- <view class="send-button">
- <button @click="sendConsultation">
- 发送
- </button>
- </view>
-
- </view>
- </view>
- </template>
-
-
- <script>
- import Tools from './Tools.vue'; // 引入工具栏组件
- import io from 'socket.io-client';
-
- export default {
- components: {
- Tools
- },
- data() {
- return {
- messages: [],
- scrollPosition: {
- top: 0
- },
- inputContent: '',
- isInputFocused: false,
- showEmojiPicker: false,
- meUserInfo: {
- avatar: '',
- username: '',
- userId: ''
- },
- otherUserInfo: {
- avatar: '',
- username: '',
- userId: ''
- },
- chaterId: '',
- chaterName: ''
-
- };
- },
- onLoad() {
- // 加载时的初始化
- const userInfo = uni.getStorageSync('userInfo');
- if (userInfo) {
- this.meUserInfo = {
- ...userInfo
- };
- }
- const chaterId = uni.getStorageSync('chaterId');
- const chaterName = uni.getStorageSync('chaterName');
- if (chaterId && chaterName) {
- this.chaterName = chaterName;
- this.chaterId = chaterId;
-
- // 添加这一行:强制更新,确保 created 中能访问到最新数据
- this.$nextTick(() => {});
- }
- },
- onShow: async function() {
- if (this.chaterId == "000") {
- try {
- await this.fetchMsgInfoAll();
- } catch (error) {
- console.error('Failed to load msg info all:', error);
- }
- return;
- } else {
- try {
- await this.fetchMsgInfoOne();
- } catch (error) {
- console.error('Failed to load msg info one:', error);
- }
- return;
- }
-
- },
- created() {
- this.socket = io('https://afanai.top:8089');
- // 确保在数据完全就绪后再继续执行
- this.$nextTick(() => {
- if (this.chaterId !== undefined) {
- // console.log(this.chaterId);
-
- if (this.chaterId === "000") {
- this.socket.on('responseMsg_all', this.handleResponseMsg);
- } else {
- this.socket.on('responseMsg_one2one', this.handleResponseMsg);
- }
- } else {
- console.warn("chaterId has not been set yet.");
- }
- });
- },
- destroyed() {
- if (this.chaterId == "000") {
- this.socket.off('responseMsg_all', this.handleResponseMsg);
- } else {
- this.socket.off('responseMsg_one2one', this.handleResponseMsg);
- }
- this.socket.disconnect();
- },
- methods: {
- handleScroll(event) {
- // console.log(event.detail);
- this.scrollPosition.top = event.detail.scrollTop;
- },
- sendConsultation() {
- // 发送咨询逻辑
- this.inputContent = (this.inputContent == '') ? "..." : this.inputContent;
- const date = this.formatDate(new Date(), "yyyy-MM-dd hh:mm:ss");
- // console.log(date);
- const newMessage = {
- isMe: true,
- avatar: this.meUserInfo.avatar,
- content: this.inputContent,
- username: this.meUserInfo.username,
- time: date
- };
- this.messages.push(newMessage);
- // 发送消息
- const roomId = (this.chaterId == "000") ? 'all' : 'one2one';
- const sendUserId = this.meUserInfo.userId;
- const msg2server = {
- roomId: roomId,
- sendUserId: sendUserId,
- resUserId: this.chaterId,
- content: newMessage.content,
- time: date,
- avatar: this.meUserInfo.avatar,
- username: this.meUserInfo.username,
- }
- this.socket.emit('message', msg2server);
- this.inputContent = ''; // 清空输入框
- this.scrollToBottom();
- },
- handleResponseMsg(rspData) {
- // console.log("收到消息:", rspData.sendUserId);
- const isMeSned = rspData.sendUserId == this.meUserInfo.userId;
- if (isMeSned) {
- return;
- }
- const newMessage = {
- isMe: isMeSned,
- avatar: rspData.avatar,
- content: rspData.content,
- username: rspData.username,
- time: rspData.time
- };
- this.messages.push(newMessage);
- },
- openTools(type) {
- if (type === 'emoji') {
- this.showEmojiPicker = true;
- this.$nextTick(() => {
- this.$refs.tools.showEmojiPicker();
- });
- } else if (type === 'plus') {
- this.$refs.tools.showPlusMenu();
- }
- },
- scrollToBottom() {
- // console.log(this.$refs.msgList);
- // 滚动到底部的逻辑
- this.scrollPosition.top = this.$refs.msgList.scrollHeight;
- },
- goBack() {
- uni.navigateBack();
- },
- formatDate(date, fmt) {
- var o = {
- "M+": date.getMonth() + 1, //月份
- "d+": date.getDate(), //日
- "h+": date.getHours(), //小时
- "m+": date.getMinutes(), //分
- "s+": date.getSeconds(), //秒
- "q+": Math.floor((date.getMonth() + 3) / 3), //季度
- "S": date.getMilliseconds() //毫秒
- };
- if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
- for (var k in o)
- if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[
- k]) : (("00" + o[k]).substr(("" + o[k]).length)));
- return fmt;
- },
- async fetchMsgInfoAll() {
- const response = await uni.request({
- url: 'https://afanai.top:8089/v1/chatMsg/get/all',
- method: 'GET',
- });
- this.InitMsgList(response);
- },
- async fetchMsgInfoOne() {
- const response = await uni.request({
- url: 'https://afanai.top:8089/v1/chatMsg/get/one2one/' + this.meUserInfo.userId + '/' +
- this.chaterId,
- method: 'GET',
- });
- this.InitMsgList(response);
- },
- InitMsgList(response) {
- // console.log(response.data);
- this.messages = [];
- for (var obj of response.data) {
- // console.log(obj);
- const isMeSned = obj.sendUserId == this.meUserInfo.userId;
- const newMessage = {
- isMe: isMeSned,
- avatar: obj.avatar,
- content: obj.content,
- username: obj.username,
- time: obj.time
- };
- this.messages.push(newMessage);
- }
- }
-
- },
- };
- </script>
-
- <!-- 使用Flex布局和定位来实现 -->
- <style scoped>
- .header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 10rpx 20rpx;
- background-color: #fff;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
- position: fixed;
- /* 添加 */
- top: 40px;
- /* 添加 */
- left: 0;
- right: 0;
- z-index: 1;
- /* 确保头部在内容上方 */
- }
-
- .back-button {
- width: 40upx;
- /* 图标大小 */
- height: 40upx;
- }
-
- .back-button image {
- width: 100%;
- height: 100%;
- }
-
- .title {
- font-size: 36rpx;
- font-weight: bold;
- margin: 0 auto;
- }
-
- .page {
- display: flex;
- flex-direction: column;
- min-height: 100vh;
- }
-
- /* 消息展示区的样式 */
- .message-area {
- flex: 1;
- overflow-y: auto;
- padding: 20px;
- padding-bottom: 110px;
- padding-top: 40px;
- }
-
- .message {
- display: flex;
- margin: 10px 0;
- }
-
- /* 确保消息内容向左或向右对齐 */
- .me {
- justify-content: flex-end;
- }
-
- .other {
- justify-content: flex-start;
- }
-
- /* 头像的样式 */
- .avatar {
- border-radius: 20%;
- margin-top: 18rpx;
- }
-
- .other-avatar {
- margin-right: 10rpx;
- /* 为非当前用户的消息增加右侧边距 */
- }
-
- .me-avatar {
- margin-left: 10rpx;
- /* 为当前用户的消息增加左侧边距 */
- }
-
- /* 限制头像的大小 */
- .avatar image {
- width: 80upx;
- height: 80upx;
- border-radius: 12rpx;
- border: 2upx solid #abb0b6;
- object-fit: cover;
- }
-
- .username-time {
- display: flex;
- flex-direction: column;
- align-items: flex-start;
- top: 15rpx;
- }
-
- .username-time-p {
- display: flex;
- flex-direction: row;
- align-items: flex-start;
- gap: 15rpx;
- margin-left: 10rpx;
- margin-bottom: 2rpx;
- }
-
- .me .username-time-p {
- margin-right: 10rpx;
- }
-
- .me .username-time {
- align-items: flex-end;
- }
-
- .username {
- font-size: 24rpx;
- font-weight: bold;
- color: #666;
- }
-
- .time {
- font-size: 20rpx;
- color: #999;
- }
-
- /* 消息内容的样式 */
- .message-content {
- background-color: #E0E0E0;
- padding: 10px;
- border-radius: 10px;
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
- margin: 0 10px;
- position: relative;
- max-width: 75%;
- word-wrap: break-word;
- }
-
- /* 自己发送消息的样式 */
- .me .message-content {
- background-color: #64B5F6;
- color: #fff;
- }
-
- /* 为气泡效果添加三角形 */
- .message-content::before {
- content: "";
- position: absolute;
- width: 0;
- height: 0;
- border-style: solid;
- }
-
- .me .message-content::before {
- left: 100%;
- margin-left: -1upx;
- border-width: 12upx 0 12upx 12upx;
- border-color: transparent transparent transparent #64B5F6;
- top: 15rpx;
- margin-bottom: -5px;
- }
-
- .other .message-content::before {
- right: 100%;
- margin-right: -1upx;
- border-width: 12upx 12upx 12upx 0;
- border-color: transparent #E0E0E0 transparent transparent;
- top: 15rpx;
- margin-bottom: -5px;
- }
-
- /* 底部工具栏样式 */
- .footer {
- display: flex;
- align-items: center;
- justify-content: space-between;
- /* 新增,使工具图标与输入框/发送按钮之间保持均匀间隔 */
- padding: 10px;
- background-color: #f8f8f8;
- position: fixed;
- bottom: 0;
- left: 0;
- right: 0;
- box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
- z-index: 2;
- }
-
- .input-wrap {
- flex: 1;
- }
-
- .send-button {
- margin-left: 10px;
- }
-
- /* 新增对工具图标的样式 */
- .tools-wrap {
- display: flex;
- align-items: center;
- /* 使图标上下居中 */
- }
-
- .tools-wrap image {
- width: 24px;
- /* 调整图标大小 */
- height: 24px;
- margin: 0 8px;
- /* 图标之间的间距 */
- }
- </style>
|