|
@@ -82,6 +82,27 @@
|
|
|
<!-- 语音消息 -->
|
|
|
<div class="content" v-if="item.contentType === Constant.REJECT_AUDIO_ONLINE || item.contentType === Constant.REJECT_VIDEO_ONLINE">[对方拒绝]</div>
|
|
|
<div class="content" v-if="item.contentType === Constant.CANCELL_AUDIO_ONLINE || item.contentType === Constant.CANCELL_VIDEO_ONLINE">[通话结束]</div>
|
|
|
+ <div class="quotation">引用消息</div>
|
|
|
+ <!-- 阅后即焚消息 -->
|
|
|
+ <div
|
|
|
+ class="burn-message"
|
|
|
+ @click="openBurnMessage(item)"
|
|
|
+ >
|
|
|
+ <!-- 未查看 -->
|
|
|
+ <div v-if="!item.viewed && !item.destroyed" class="burn-mask">
|
|
|
+ 🔒 阅后即焚,点击查看
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 已查看但未销毁 -->
|
|
|
+ <div v-else-if="item.viewed && !item.destroyed" class="burn-content">
|
|
|
+ {{ item.content }}
|
|
|
+ <span class="burn-countdown">{{ item.countdown }}s</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 已焚毁 -->
|
|
|
+ <div v-else class="burn-destroyed">🔥 该消息已焚毁</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
@@ -101,7 +122,11 @@
|
|
|
cancel-text="取消"
|
|
|
@select="onActionSelect"
|
|
|
/>
|
|
|
-
|
|
|
+ <!-- 引用消息展示 -->
|
|
|
+ <div v-if="quoteMsg" class="quote-box">
|
|
|
+ <div class="quote-content">{{ quoteMsg.fromUsername}}:{{ renderQuoteContent(quoteMsg) }}</div>
|
|
|
+ <span class="quote-close" @click="cancelQuote">✕</span>
|
|
|
+ </div>
|
|
|
<!-- 输入框 -->
|
|
|
<div class="page-foot">
|
|
|
<div class="flex-box">
|
|
@@ -114,32 +139,34 @@
|
|
|
/>
|
|
|
|
|
|
<!-- 文字输入框 或 按住说话按钮 -->
|
|
|
- <template v-if="!voiceMode">
|
|
|
- <van-field
|
|
|
- rows="1"
|
|
|
- type="textarea"
|
|
|
- :border="false"
|
|
|
- autosize
|
|
|
- class="input"
|
|
|
- v-model="text"
|
|
|
- @focus="onFocus"
|
|
|
- placeholder="输入文本"
|
|
|
- @keypress="handleKeyPress"
|
|
|
- @keyup.enter="sendMessage"
|
|
|
- />
|
|
|
- <!-- :disabled="deletefriend.includes(wsStore.toUserInfo.uuid)" -->
|
|
|
- </template>
|
|
|
+ <div class="box-input">
|
|
|
+ <template v-if="!voiceMode">
|
|
|
+ <van-field
|
|
|
+ rows="1"
|
|
|
+ type="textarea"
|
|
|
+ :border="false"
|
|
|
+ autosize
|
|
|
+ class="input"
|
|
|
+ v-model="text"
|
|
|
+ @focus="onFocus"
|
|
|
+ placeholder="输入文本"
|
|
|
+ @keypress="handleKeyPress"
|
|
|
+ @keyup.enter="sendMessage"
|
|
|
+ />
|
|
|
+ <!-- :disabled="deletefriend.includes(wsStore.toUserInfo.uuid)" -->
|
|
|
+ </template>
|
|
|
|
|
|
- <template v-else>
|
|
|
- <div
|
|
|
- class="hold-talk-btn"
|
|
|
- @touchstart.prevent.stop="handleTouchStart"
|
|
|
- @touchmove.prevent.stop="handleTouchMove"
|
|
|
- @touchend.prevent.stop="handleTouchEnd"
|
|
|
- >
|
|
|
- {{ cancelRecording ? "松开手指,取消发送" : "按住说话" }}
|
|
|
- </div>
|
|
|
- </template>
|
|
|
+ <template v-else>
|
|
|
+ <div
|
|
|
+ class="hold-talk-btn"
|
|
|
+ @touchstart.prevent.stop="handleTouchStart"
|
|
|
+ @touchmove.prevent.stop="handleTouchMove"
|
|
|
+ @touchend.prevent.stop="handleTouchEnd"
|
|
|
+ >
|
|
|
+ 按住说话
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
<svg-icon
|
|
|
class="page-icon mr12 emoji-toggle"
|
|
|
name="emoji"
|
|
@@ -151,18 +178,12 @@
|
|
|
@click="toggleAppBox(2)"
|
|
|
/>
|
|
|
</div>
|
|
|
-
|
|
|
<!-- 录音状态浮层 -->
|
|
|
- <!-- <div v-if="recording" class="recording-toast">
|
|
|
- <div v-if="cancelRecording" class="cancel-msg">松开手指,取消发送</div>
|
|
|
- <div v-else class="send-msg">松开发送,上滑取消</div>
|
|
|
- </div> -->
|
|
|
<div v-if="recording" class="recording-toast">
|
|
|
<div class="mic-icon"></div>
|
|
|
<div v-if="cancelRecording" class="cancel-msg">松开手指,取消发送</div>
|
|
|
<div v-else class="send-msg">手指上滑,取消发送</div>
|
|
|
</div>
|
|
|
-
|
|
|
<!-- 表情面板 -->
|
|
|
<div
|
|
|
class="app-box"
|
|
@@ -219,6 +240,10 @@
|
|
|
<svg-icon class="tool-icon" name="mp" />
|
|
|
<div>名片</div>
|
|
|
</div> -->
|
|
|
+ <div class="tool-btn">
|
|
|
+ <svg-icon class="tool-icon" name="mp" />
|
|
|
+ <div>阅后即焚</div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
@@ -258,7 +283,8 @@ const appBoxHeight = ref(210);
|
|
|
const chatListRef = ref(null);
|
|
|
const emojiRef = ref(null);
|
|
|
const toolsRef = ref(null);
|
|
|
-const deletefriend = ref([])
|
|
|
+const deletefriend = ref([]);
|
|
|
+const quoteMsg = ref(null);// 当前引用的消息
|
|
|
// 表情数组
|
|
|
const emojis = [
|
|
|
"😀", "😃", "😄", "😁", "😆", "😅", "😂", "🤣",
|
|
@@ -320,6 +346,7 @@ const toggleAppBox = async (type) => {
|
|
|
showToast(`${wsStore.toUserInfo.type == 'user' ? '对方已删除' : '您已不在群聊里面'}`);
|
|
|
return;
|
|
|
}
|
|
|
+ voiceMode.value = false;
|
|
|
if (isMobile) await Keyboard.hide();
|
|
|
keyboardHeight.value = 0;
|
|
|
if (type === 1) {
|
|
@@ -478,6 +505,7 @@ const showActionSheet = ref(false)
|
|
|
const actions = [
|
|
|
{ name: "复制", key: "copy" },
|
|
|
{ name: "撤回", key: "revoke" },
|
|
|
+ { name: "引用", key: "quote" }
|
|
|
];
|
|
|
const onLongPress = (msg) => {
|
|
|
currentMsg.value = msg;
|
|
@@ -500,9 +528,29 @@ const onActionSelect = (action) => {
|
|
|
};
|
|
|
wsStore.sendMessage(message);
|
|
|
currentMsg.value.revoked = true;
|
|
|
+ }else if(action.key === "quote"){
|
|
|
+ // 引用
|
|
|
+ quoteMsg.value = currentMsg.value; // 设置引用
|
|
|
+ console.log(quoteMsg.value)
|
|
|
}
|
|
|
showActionSheet.value = false;
|
|
|
};
|
|
|
+// 取消引用
|
|
|
+const cancelQuote = () => {
|
|
|
+ quoteMsg.value = null;
|
|
|
+};
|
|
|
+// 渲染引用的内容(文字/图片等)
|
|
|
+const renderQuoteContent = (msg) => {
|
|
|
+ if (msg.contentType === MSG_TYPE.TEXT) {
|
|
|
+ return msg.content;
|
|
|
+ } else if (msg.contentType === MSG_TYPE.IMAGE) {
|
|
|
+ return "[图片]";
|
|
|
+ } else if (msg.contentType === MSG_TYPE.AUDIO) {
|
|
|
+ return "[语音]";
|
|
|
+ } else {
|
|
|
+ return "[消息]";
|
|
|
+ }
|
|
|
+};
|
|
|
|
|
|
// 发送消息
|
|
|
const sendMessage = () => {
|
|
@@ -857,10 +905,14 @@ const goNoticePage = () => {
|
|
|
position: relative;
|
|
|
background-color: #fff;
|
|
|
.flex-box {
|
|
|
- padding: 8px 16px 20px;
|
|
|
+ padding: 8px 16px 16px;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
box-sizing: border-box;
|
|
|
+ .box-input{
|
|
|
+ flex: 1;
|
|
|
+ margin: 0 12px;
|
|
|
+ }
|
|
|
.input {
|
|
|
flex: 1;
|
|
|
background: #f2f2f2;
|
|
@@ -869,7 +921,7 @@ const goNoticePage = () => {
|
|
|
padding: 6px 16px;
|
|
|
font-weight: 500;
|
|
|
font-size: 15px;
|
|
|
- margin: 0 12px;
|
|
|
+ // margin: 0 12px;
|
|
|
overflow-y: auto;
|
|
|
}
|
|
|
}
|
|
@@ -952,7 +1004,7 @@ const goNoticePage = () => {
|
|
|
user-select: none;
|
|
|
-webkit-user-select: none;
|
|
|
-webkit-touch-callout: none;
|
|
|
- margin: 0 12px;
|
|
|
+ // margin: 0 12px;
|
|
|
line-height: 24px;
|
|
|
border: 1px solid #f5f5f5;
|
|
|
}
|
|
@@ -1031,4 +1083,92 @@ const goNoticePage = () => {
|
|
|
color: red;
|
|
|
margin-left: 6px;
|
|
|
}
|
|
|
+// 引用样式
|
|
|
+.quote-box {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ background: #f2f2f2;
|
|
|
+ border-radius: 6px;
|
|
|
+ padding: 4px 16px;
|
|
|
+ // margin-bottom: 6px;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #969696;
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+.quote-content {
|
|
|
+ margin-bottom: 2px;
|
|
|
+}
|
|
|
+.quotation{
|
|
|
+ background: #f2f2f2;
|
|
|
+ border-radius: 5px;
|
|
|
+ padding: 5px 10px;
|
|
|
+ margin-top: 5px;
|
|
|
+}
|
|
|
+// 阅后即焚样式
|
|
|
+.burn-message {
|
|
|
+ background: #fff;
|
|
|
+ color: #000;
|
|
|
+ border-radius: 10px;
|
|
|
+ margin-top: 8px;
|
|
|
+ padding: 8px 14px;
|
|
|
+ max-width: 100%;
|
|
|
+ font-size: 15px;
|
|
|
+ position: relative;
|
|
|
+ cursor: pointer;
|
|
|
+ word-break: break-word;
|
|
|
+ white-space: pre-wrap;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+
|
|
|
+ &.self {
|
|
|
+ background: #4d71ff;
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+
|
|
|
+ .burn-mask {
|
|
|
+ text-align: center;
|
|
|
+ color: #999;
|
|
|
+ font-size: 14px;
|
|
|
+ filter: blur(0px);
|
|
|
+ }
|
|
|
+
|
|
|
+ .burn-content {
|
|
|
+ animation: fadeIn 0.3s ease-in;
|
|
|
+ position: relative;
|
|
|
+
|
|
|
+ .burn-countdown {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #ff5b5b;
|
|
|
+ margin-left: 6px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .burn-destroyed {
|
|
|
+ color: #999;
|
|
|
+ font-size: 13px;
|
|
|
+ text-align: center;
|
|
|
+ animation: fadeOut 1s forwards;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+@keyframes fadeIn {
|
|
|
+ from {
|
|
|
+ opacity: 0;
|
|
|
+ transform: scale(0.95);
|
|
|
+ }
|
|
|
+ to {
|
|
|
+ opacity: 1;
|
|
|
+ transform: scale(1);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+@keyframes fadeOut {
|
|
|
+ from {
|
|
|
+ opacity: 1;
|
|
|
+ }
|
|
|
+ to {
|
|
|
+ opacity: 0;
|
|
|
+ height: 0;
|
|
|
+ }
|
|
|
+}
|
|
|
</style>
|