|
@@ -1,54 +1,38 @@
|
|
|
<template>
|
|
|
- <div
|
|
|
- class="container"
|
|
|
- :style="{ height: `calc(100% - ${currentBottomHeight}px)` }"
|
|
|
- >
|
|
|
+ <div class="container" :style="{ height: `calc(100% - ${currentBottomHeight}px)` }">
|
|
|
<div class="chat-bg"></div>
|
|
|
+ <!-- 顶部导航 -->
|
|
|
<div class="header-chat">
|
|
|
<svg-icon class="page-icon" name="lf-arrow" @click="goBack" />
|
|
|
- <div class="header-title">群聊2(8)</div>
|
|
|
+ <div class="header-title">群聊2({{ wsStore.messages.length }})</div>
|
|
|
<svg-icon class="page-icon" name="more" @click="goDetail" />
|
|
|
</div>
|
|
|
+
|
|
|
+ <!-- 聊天消息区域 -->
|
|
|
<div class="chat-list">
|
|
|
<div v-for="(item, index) in wsStore.messages" :key="index">
|
|
|
- <div class="chat-time">23:{{ 20 + index }}</div>
|
|
|
+ <div class="chat-time">{{ formatTime(item.timestamp || Date.now()) }}</div>
|
|
|
<div class="box">
|
|
|
<div class="list-item" :class="walletStore.account == item.toUsername ?'' : 'flex-reverse'">
|
|
|
+ <!-- 头像 -->
|
|
|
<van-image
|
|
|
class="list-img"
|
|
|
- :class="index % 2 === 0 ? 'mr12' : 'ml12'"
|
|
|
+ :class="item.from === walletStore.account ? 'ml12' : 'mr12'"
|
|
|
round
|
|
|
src="https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg"
|
|
|
@click="router.push('personal')"
|
|
|
/>
|
|
|
+ <!-- 内容 -->
|
|
|
<div class="list-cont">
|
|
|
- <div>{{ item.fromUsername }}</div>
|
|
|
- <!-- 名片 -->
|
|
|
- <!-- <div class="business-card" v-if="i % 2 === 0">
|
|
|
- <div class="business-card-cont">
|
|
|
- <van-image
|
|
|
- class="list-img mr12"
|
|
|
- round
|
|
|
- src="https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg"
|
|
|
- />
|
|
|
- <div>名字名字</div>
|
|
|
- </div>
|
|
|
- <div class="line"></div>
|
|
|
- <div class="business-card-text">个人名片</div>
|
|
|
- </div> -->
|
|
|
- <!-- 文本信息 -->
|
|
|
- <div class="content" v-if="item.contentType === 1">
|
|
|
- {{ item.content }}
|
|
|
- </div>
|
|
|
+ <div>{{ item.fromUsername || '匿名用户' }}</div>
|
|
|
+ <div class="content" v-if="item.contentType === 1">{{ item.content }}</div>
|
|
|
+ <!-- 可扩展 contentType === 2 图片,3 名片等 -->
|
|
|
</div>
|
|
|
</div>
|
|
|
- <!--消息撤回 -->
|
|
|
- <!-- <div class="withdrawal">
|
|
|
- <div class="withdrawal-text">哈哈哈撤回了一条消息</div>
|
|
|
- </div> -->
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
+
|
|
|
<!-- 输入框 -->
|
|
|
<div class="page-foot">
|
|
|
<div class="flex-box">
|
|
@@ -64,130 +48,115 @@
|
|
|
placeholder="输入文本"
|
|
|
@keyup.enter="sendMessage"
|
|
|
/>
|
|
|
- <svg-icon
|
|
|
- class="page-icon mr12"
|
|
|
- name="emoji"
|
|
|
- @click="toggleAppBox(1)"
|
|
|
- />
|
|
|
+ <svg-icon class="page-icon mr12" name="emoji" @click="toggleAppBox(1)" />
|
|
|
<svg-icon class="page-icon" name="add2" @click="toggleAppBox(2)" />
|
|
|
</div>
|
|
|
|
|
|
<!-- 表情面板 -->
|
|
|
- <div
|
|
|
- class="app-box"
|
|
|
- v-show="showEmoji"
|
|
|
- :style="{ height: `${appBoxHeight}px` }"
|
|
|
- >
|
|
|
+ <div class="app-box" v-show="showEmoji" :style="{ height: `${appBoxHeight}px` }">
|
|
|
😀 😃 😄 😁 😆 😅 😂 🤣 😊 😇 🙂 🙃 😉 😌 😍
|
|
|
</div>
|
|
|
|
|
|
<!-- 工具栏面板 -->
|
|
|
- <div
|
|
|
- class="app-box"
|
|
|
- v-show="showTools"
|
|
|
- :style="{ height: `${appBoxHeight}px` }"
|
|
|
- >
|
|
|
- <!-- 工具栏内容:可放按钮、图标等 -->
|
|
|
- <div class="tool-btn">照片</div>
|
|
|
- <div class="tool-btn">视频</div>
|
|
|
- <div class="tool-btn">语音通话</div>
|
|
|
- <div class="tool-btn">名片</div>
|
|
|
+ <div class="app-box" v-show="showTools" :style="{ height: `${appBoxHeight}px` }">
|
|
|
+ <div class="tool-btn">
|
|
|
+ <svg-icon class="tool-icon" name="tp" />
|
|
|
+ <div>图片</div>
|
|
|
+ </div>
|
|
|
+ <div class="tool-btn"><svg-icon class="tool-icon" name="ps" /><div>拍摄</div></div>
|
|
|
+ <div class="tool-btn"><svg-icon class="tool-icon" name="yyth" /><div>语音通话</div></div>
|
|
|
+ <div class="tool-btn"><svg-icon class="tool-icon" name="spth" /><div>视频通话</div></div>
|
|
|
+ <div class="tool-btn"><svg-icon class="tool-icon" name="mp" /><div>名片</div></div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
-<script setup>
|
|
|
-import { Keyboard } from "@capacitor/keyboard";
|
|
|
+<script setup>
|
|
|
+import { ref, computed, onMounted, onUnmounted } from "vue";
|
|
|
+import { useRouter, useRoute } from "vue-router";
|
|
|
import { useWebSocketStore } from "@/stores/modules/webSocketStore.js";
|
|
|
import { useWalletStore } from "@/stores/modules/walletStore.js";
|
|
|
+import { Keyboard } from "@capacitor/keyboard";
|
|
|
+import { Capacitor } from "@capacitor/core";
|
|
|
|
|
|
+// 路由 & store
|
|
|
const router = useRouter();
|
|
|
-const route = useRoute()
|
|
|
-const text = ref("");
|
|
|
-
|
|
|
+const route = useRoute();
|
|
|
const wsStore = useWebSocketStore();
|
|
|
const walletStore = useWalletStore();
|
|
|
|
|
|
+// 输入框文本
|
|
|
+const text = ref("");
|
|
|
+
|
|
|
// 状态管理
|
|
|
const keyboardHeight = ref(0);
|
|
|
const showEmoji = ref(false);
|
|
|
const showTools = ref(false);
|
|
|
-const appBoxHeight = ref(260); // 面板高度,可根据需要调整
|
|
|
+const appBoxHeight = ref(210);
|
|
|
+
|
|
|
+// 平台判断
|
|
|
+const isMobile = Capacitor.getPlatform() !== "web";
|
|
|
|
|
|
-// 计算当前底部总高度
|
|
|
+// 底部高度动态计算
|
|
|
const currentBottomHeight = computed(() => {
|
|
|
- // 优先级:键盘 > 表情面板 > 工具面板 > 默认高度
|
|
|
- if (keyboardHeight.value > 0) {
|
|
|
- return keyboardHeight.value; // 只计算键盘高度
|
|
|
- }
|
|
|
- if (showEmoji.value || showTools.value) {
|
|
|
- return appBoxHeight.value; // 只计算面板高度
|
|
|
- }
|
|
|
- return 0; // 默认底部间距
|
|
|
+ if (keyboardHeight.value > 0) return keyboardHeight.value;
|
|
|
+ if (showEmoji.value || showTools.value) return appBoxHeight.value;
|
|
|
+ return 0;
|
|
|
});
|
|
|
|
|
|
-// 切换面板显示
|
|
|
-const toggleAppBox = async (type) => {
|
|
|
- // 先隐藏键盘(如果正在显示)
|
|
|
- await Keyboard.hide();
|
|
|
- keyboardHeight.value = 0; // 立即重置键盘高度
|
|
|
-
|
|
|
- // 切换面板状态
|
|
|
- if (type === 1) {
|
|
|
- showEmoji.value = !showEmoji.value;
|
|
|
- showTools.value = false;
|
|
|
- } else {
|
|
|
- showTools.value = !showTools.value;
|
|
|
- showEmoji.value = false;
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
+// 输入框聚焦
|
|
|
const onFocus = () => {
|
|
|
- // 隐藏所有面板
|
|
|
showEmoji.value = false;
|
|
|
showTools.value = false;
|
|
|
- // 判断是不是web
|
|
|
- if (Capacitor.getPlatform() != "web") {
|
|
|
- setupKeyboardListeners();
|
|
|
- }
|
|
|
+ if (isMobile) setupKeyboardListeners();
|
|
|
};
|
|
|
|
|
|
-// 键盘监听
|
|
|
-const setupKeyboardListeners = async () => {
|
|
|
+// 监听键盘高度
|
|
|
+const setupKeyboardListeners = () => {
|
|
|
Keyboard.addListener("keyboardWillShow", (info) => {
|
|
|
keyboardHeight.value = info.keyboardHeight;
|
|
|
});
|
|
|
-
|
|
|
Keyboard.addListener("keyboardWillHide", () => {
|
|
|
keyboardHeight.value = 0;
|
|
|
});
|
|
|
};
|
|
|
|
|
|
-const goBack = () => {
|
|
|
- router.push("im");
|
|
|
-};
|
|
|
-const goDetail = () => {
|
|
|
- router.push("detail");
|
|
|
+// 切换表情/工具面板
|
|
|
+const toggleAppBox = async (type) => {
|
|
|
+ if (isMobile) await Keyboard.hide();
|
|
|
+ keyboardHeight.value = 0;
|
|
|
+ if (type === 1) {
|
|
|
+ showEmoji.value = !showEmoji.value;
|
|
|
+ showTools.value = false;
|
|
|
+ } else {
|
|
|
+ showTools.value = !showTools.value;
|
|
|
+ showEmoji.value = false;
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
// 发送消息
|
|
|
const sendMessage = () => {
|
|
|
- if (!text.value.trim()) {
|
|
|
- return; // 空消息不发送
|
|
|
- }
|
|
|
-
|
|
|
- let message = {
|
|
|
+ if (!text.value.trim()) return;
|
|
|
+ const message = {
|
|
|
content: text.value,
|
|
|
- contentType: 1, // 1: 文本消息
|
|
|
- messageType: 1, // 1: 单聊天
|
|
|
- to:route.query.uuid,
|
|
|
+ contentType: 1,
|
|
|
+ messageType: 1,
|
|
|
+ to: route.query.uuid,
|
|
|
};
|
|
|
wsStore.sendMessage(message);
|
|
|
- // 清空输入框
|
|
|
text.value = "";
|
|
|
};
|
|
|
|
|
|
+// 时间格式化
|
|
|
+const formatTime = (timestamp) => {
|
|
|
+ const date = new Date(timestamp);
|
|
|
+ const h = date.getHours().toString().padStart(2, "0");
|
|
|
+ const m = date.getMinutes().toString().padStart(2, "0");
|
|
|
+ return `${h}:${m}`;
|
|
|
+};
|
|
|
+
|
|
|
+// 页面生命周期
|
|
|
onMounted(() => {
|
|
|
wsStore.getMessages({
|
|
|
uuid: walletStore.account,
|
|
@@ -197,10 +166,12 @@ onMounted(() => {
|
|
|
});
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
- if (Capacitor.getPlatform() !== "web") {
|
|
|
- Keyboard.removeAllListeners();
|
|
|
- }
|
|
|
+ if (isMobile) Keyboard.removeAllListeners();
|
|
|
});
|
|
|
+
|
|
|
+// 页面跳转
|
|
|
+const goBack = () => router.push("im");
|
|
|
+const goDetail = () => router.push("detail");
|
|
|
</script>
|
|
|
|
|
|
<style lang="less" scoped>
|
|
@@ -378,18 +349,34 @@ onUnmounted(() => {
|
|
|
}
|
|
|
.app-box {
|
|
|
position: fixed;
|
|
|
- bottom: 260px;
|
|
|
+ bottom: 210px;
|
|
|
left: 0;
|
|
|
right: 0;
|
|
|
- height: 260px;
|
|
|
background: white;
|
|
|
transition: transform 0.3s ease;
|
|
|
transform: translateY(100%);
|
|
|
- background-color: yellow;
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ padding: 10px 0 0 32px;
|
|
|
|
|
|
&.visible {
|
|
|
transform: translateY(0);
|
|
|
}
|
|
|
+ .tool-btn{
|
|
|
+ margin-right: 32px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ font-family: PingFang SC, PingFang SC;
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #000000;
|
|
|
+ .tool-icon{
|
|
|
+ width: 56px;
|
|
|
+ height: 56px;
|
|
|
+ margin-bottom: 4px;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
.page-foot {
|