|
|
@ -77,6 +77,7 @@ |
|
|
<text>{{ item.mediaDuration || 1 }}''</text> |
|
|
<text>{{ item.mediaDuration || 1 }}''</text> |
|
|
</view> |
|
|
</view> |
|
|
<view class="bubble" v-else :class="{ muted: item.pending, blocked: item.blocked }">{{ item.content }}</view> |
|
|
<view class="bubble" v-else :class="{ muted: item.pending, blocked: item.blocked }">{{ item.content }}</view> |
|
|
|
|
|
<view class="message-time" v-if="item.displayTime">{{ item.displayTime }}</view> |
|
|
<view class="message-status" v-if="item.mine && messageStatusText(item)" :class="{ blocked: item.blocked }"> |
|
|
<view class="message-status" v-if="item.mine && messageStatusText(item)" :class="{ blocked: item.blocked }"> |
|
|
{{ messageStatusText(item) }} |
|
|
{{ messageStatusText(item) }} |
|
|
</view> |
|
|
</view> |
|
|
@ -511,8 +512,44 @@ |
|
|
} |
|
|
} |
|
|
return item.localOnly |
|
|
return item.localOnly |
|
|
}) |
|
|
}) |
|
|
|
|
|
locals.forEach(item => { |
|
|
|
|
|
if (!item.messageTime) item.messageTime = this.pickMessageTime(item) |
|
|
|
|
|
if (!item.displayTime) item.displayTime = this.formatMessageTime(item.messageTime) |
|
|
|
|
|
}) |
|
|
return remote.concat(locals) |
|
|
return remote.concat(locals) |
|
|
}, |
|
|
}, |
|
|
|
|
|
pickMessageTime(item) { |
|
|
|
|
|
if (!item) return '' |
|
|
|
|
|
return item.createTime || item.createdTime || item.sendTime || item.sentTime || item.messageTime || |
|
|
|
|
|
item.createdAt || item.createAt || item.updateTime || '' |
|
|
|
|
|
}, |
|
|
|
|
|
parseMessageTime(value) { |
|
|
|
|
|
if (!value) return 0 |
|
|
|
|
|
if (typeof value === 'number') { |
|
|
|
|
|
const time = value < 10000000000 ? value * 1000 : value |
|
|
|
|
|
return Number.isNaN(time) ? 0 : time |
|
|
|
|
|
} |
|
|
|
|
|
const text = String(value) |
|
|
|
|
|
let time = new Date(text).getTime() |
|
|
|
|
|
if (Number.isNaN(time)) { |
|
|
|
|
|
time = new Date(text.replace(/-/g, '/')).getTime() |
|
|
|
|
|
} |
|
|
|
|
|
return Number.isNaN(time) ? 0 : time |
|
|
|
|
|
}, |
|
|
|
|
|
formatMessageTime(value) { |
|
|
|
|
|
const time = this.parseMessageTime(value) |
|
|
|
|
|
if (!time) return '' |
|
|
|
|
|
const date = new Date(time) |
|
|
|
|
|
const now = new Date() |
|
|
|
|
|
const timeText = `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}` |
|
|
|
|
|
const dayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime() |
|
|
|
|
|
const msgDayStart = new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() |
|
|
|
|
|
if (msgDayStart === dayStart) return timeText |
|
|
|
|
|
if (msgDayStart === dayStart - 24 * 60 * 60 * 1000) return `昨天 ${timeText}` |
|
|
|
|
|
const dateText = `${date.getMonth() + 1}/${date.getDate()}` |
|
|
|
|
|
if (date.getFullYear() === now.getFullYear()) return `${dateText} ${timeText}` |
|
|
|
|
|
return `${date.getFullYear()}/${dateText} ${timeText}` |
|
|
|
|
|
}, |
|
|
messageStatusText(item) { |
|
|
messageStatusText(item) { |
|
|
if (!item || !item.mine) return '' |
|
|
if (!item || !item.mine) return '' |
|
|
if (item.blocked) return item.blockTip || '内容未通过审核,请换一个更合适的内容' |
|
|
if (item.blocked) return item.blockTip || '内容未通过审核,请换一个更合适的内容' |
|
|
@ -541,6 +578,7 @@ |
|
|
const messageId = item.id || item.messageId |
|
|
const messageId = item.id || item.messageId |
|
|
const clientMsgId = item.clientMsgId || '' |
|
|
const clientMsgId = item.clientMsgId || '' |
|
|
const mine = item.mine !== undefined && item.mine !== null ? item.mine : (currentUserId && String(item.senderId) === currentUserId) |
|
|
const mine = item.mine !== undefined && item.mine !== null ? item.mine : (currentUserId && String(item.senderId) === currentUserId) |
|
|
|
|
|
const messageTime = this.pickMessageTime(item) |
|
|
return { |
|
|
return { |
|
|
domId: 'msg-' + (messageId || clientMsgId || Date.now() + '-' + Math.random().toString(16).slice(2)), |
|
|
domId: 'msg-' + (messageId || clientMsgId || Date.now() + '-' + Math.random().toString(16).slice(2)), |
|
|
messageId, |
|
|
messageId, |
|
|
@ -557,6 +595,9 @@ |
|
|
blockTip: item.auditTip || (item.isBlocked === 1 ? '内容未通过审核,请换一个更合适的内容' : ''), |
|
|
blockTip: item.auditTip || (item.isBlocked === 1 ? '内容未通过审核,请换一个更合适的内容' : ''), |
|
|
localState: '', |
|
|
localState: '', |
|
|
localOnly: false, |
|
|
localOnly: false, |
|
|
|
|
|
createAt: item.createAt, |
|
|
|
|
|
messageTime, |
|
|
|
|
|
displayTime: this.formatMessageTime(messageTime), |
|
|
mediaAuditStatus: item.mediaAuditStatus || 0 |
|
|
mediaAuditStatus: item.mediaAuditStatus || 0 |
|
|
} |
|
|
} |
|
|
}, |
|
|
}, |
|
|
@ -701,6 +742,8 @@ |
|
|
local.poster = remote.poster || local.poster || '' |
|
|
local.poster = remote.poster || local.poster || '' |
|
|
local.localOnly = false |
|
|
local.localOnly = false |
|
|
local.localState = '' |
|
|
local.localState = '' |
|
|
|
|
|
local.messageTime = remote.messageTime || local.messageTime |
|
|
|
|
|
local.displayTime = remote.displayTime || local.displayTime |
|
|
if (local.messageType === 1 || local.messageType === 3) local.content = remote.content || local.content |
|
|
if (local.messageType === 1 || local.messageType === 3) local.content = remote.content || local.content |
|
|
this.saveLocalMessages() |
|
|
this.saveLocalMessages() |
|
|
if (!wasBlocked && local.blocked && local.mine) { |
|
|
if (!wasBlocked && local.blocked && local.mine) { |
|
|
@ -711,7 +754,7 @@ |
|
|
normalizePage(page) { |
|
|
normalizePage(page) { |
|
|
if (!page) return [] |
|
|
if (!page) return [] |
|
|
const records = Array.isArray(page) ? page : (page.records || []) |
|
|
const records = Array.isArray(page) ? page : (page.records || []) |
|
|
return records.map(this.normalizeMessage).reverse() |
|
|
return records.map(item => this.normalizeMessage(item)).reverse() |
|
|
}, |
|
|
}, |
|
|
async loadLatestMessages() { |
|
|
async loadLatestMessages() { |
|
|
if (!this.roomId) return |
|
|
if (!this.roomId) return |
|
|
@ -885,6 +928,7 @@ |
|
|
// 同一毫秒内连续发送(如连点表情)必须保证 clientMsgId 唯一,否则 ACK 会串消息 |
|
|
// 同一毫秒内连续发送(如连点表情)必须保证 clientMsgId 唯一,否则 ACK 会串消息 |
|
|
this.msgSeq = (this.msgSeq || 0) + 1 |
|
|
this.msgSeq = (this.msgSeq || 0) + 1 |
|
|
const clientMsgId = 'm-' + Date.now() + '-' + this.msgSeq |
|
|
const clientMsgId = 'm-' + Date.now() + '-' + this.msgSeq |
|
|
|
|
|
const createAt = Date.now() |
|
|
this.messages.push({ |
|
|
this.messages.push({ |
|
|
domId: 'msg-' + clientMsgId, |
|
|
domId: 'msg-' + clientMsgId, |
|
|
clientMsgId, |
|
|
clientMsgId, |
|
|
@ -900,7 +944,9 @@ |
|
|
blockTip: '', |
|
|
blockTip: '', |
|
|
localState: media.localState || 'sending', |
|
|
localState: media.localState || 'sending', |
|
|
localOnly: true, |
|
|
localOnly: true, |
|
|
createAt: Date.now(), |
|
|
createAt, |
|
|
|
|
|
messageTime: createAt, |
|
|
|
|
|
displayTime: this.formatMessageTime(createAt), |
|
|
mediaAuditStatus: media.mediaAuditStatus || 0 |
|
|
mediaAuditStatus: media.mediaAuditStatus || 0 |
|
|
}) |
|
|
}) |
|
|
this.saveLocalMessages() |
|
|
this.saveLocalMessages() |
|
|
@ -962,6 +1008,11 @@ |
|
|
msg.blocked = ack.isBlocked === 1 |
|
|
msg.blocked = ack.isBlocked === 1 |
|
|
msg.localOnly = false |
|
|
msg.localOnly = false |
|
|
msg.localState = '' |
|
|
msg.localState = '' |
|
|
|
|
|
const messageTime = this.pickMessageTime(ack) |
|
|
|
|
|
if (messageTime) { |
|
|
|
|
|
msg.messageTime = messageTime |
|
|
|
|
|
msg.displayTime = this.formatMessageTime(messageTime) |
|
|
|
|
|
} |
|
|
if (msg.blocked) { |
|
|
if (msg.blocked) { |
|
|
if (msg.messageType === 1) msg.content = '这句话没有送出,请换一种更温柔的说法。' |
|
|
if (msg.messageType === 1) msg.content = '这句话没有送出,请换一种更温柔的说法。' |
|
|
msg.blockTip = ack.auditTip || '内容未通过审核,请换一个更合适的内容' |
|
|
msg.blockTip = ack.auditTip || '内容未通过审核,请换一个更合适的内容' |
|
|
@ -1577,19 +1628,7 @@ |
|
|
this.applyAck(msg) |
|
|
this.applyAck(msg) |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
this.messages.push({ |
|
|
this.messages.push(this.normalizeMessage(msg)) |
|
|
domId: 'msg-' + (msg.messageId || Date.now()), |
|
|
|
|
|
messageId: msg.messageId, |
|
|
|
|
|
clientMsgId: msg.clientMsgId, |
|
|
|
|
|
messageType: msg.messageType || 1, |
|
|
|
|
|
mediaDuration: msg.mediaDuration, |
|
|
|
|
|
mediaSize: msg.mediaSize, |
|
|
|
|
|
mediaFormat: msg.mediaFormat, |
|
|
|
|
|
poster: msg.poster || '', |
|
|
|
|
|
mediaAuditStatus: msg.mediaAuditStatus || 0, |
|
|
|
|
|
content: msg.content, |
|
|
|
|
|
mine: String(msg.senderId || '') === String(uni.getStorageSync('id') || '') |
|
|
|
|
|
}) |
|
|
|
|
|
this.scrollToBottom() |
|
|
this.scrollToBottom() |
|
|
}) |
|
|
}) |
|
|
ieSocket.onPresence((event) => { |
|
|
ieSocket.onPresence((event) => { |
|
|
@ -2074,6 +2113,13 @@ |
|
|
background: rgba(255, 228, 236, .82); |
|
|
background: rgba(255, 228, 236, .82); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.message-time { |
|
|
|
|
|
margin-top: 8rpx; |
|
|
|
|
|
color: rgba(22, 27, 46, 0.34); |
|
|
|
|
|
font-size: 19rpx; |
|
|
|
|
|
line-height: 28rpx; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
.image-bubble { |
|
|
.image-bubble { |
|
|
padding: 8rpx; |
|
|
padding: 8rpx; |
|
|
background: rgba(255, 255, 255, 0.72); |
|
|
background: rgba(255, 255, 255, 0.72); |
|
|
|