hookehuyr

feat(消息发送): 添加发送状态控制和自动回复提示

- 添加 isSending 状态防止重复发送
- 发送中禁用按钮并显示加载状态
- 立即清空输入框提升用户体验
- 添加自动回复提示消息
- 优化发送失败时的输入框恢复逻辑
...@@ -58,11 +58,11 @@ ...@@ -58,11 +58,11 @@
58 <!-- 输入框区域 --> 58 <!-- 输入框区域 -->
59 <view class="chat-input-area"> 59 <view class="chat-input-area">
60 <view class="input-container"> 60 <view class="input-container">
61 - <nut-textarea v-model="inputMessage" placeholder="请输入回复内容..." :rows="2" :max-length="500" 61 + <textarea v-model="inputMessage" placeholder="请输入回复内容..." :rows="2" :max-length="500"
62 :cursorSpacing="100" class="message-input" @focus="handleInputFocus" /> 62 :cursorSpacing="100" class="message-input" @focus="handleInputFocus" />
63 <nut-button type="primary" size="small" color="orange" @click="sendMessage" 63 <nut-button type="primary" size="small" color="orange" @click="sendMessage"
64 - :disabled="!inputMessage.trim()" class="send-button"> 64 + :disabled="!inputMessage.trim() || isSending" class="send-button">
65 - 发送 65 + {{ isSending ? '发送中...' : '发送' }}
66 </nut-button> 66 </nut-button>
67 </view> 67 </view>
68 </view> 68 </view>
...@@ -114,6 +114,8 @@ const visible = computed({ ...@@ -114,6 +114,8 @@ const visible = computed({
114 114
115 // 输入消息内容 115 // 输入消息内容
116 const inputMessage = ref('') 116 const inputMessage = ref('')
117 +// 发送状态标记
118 +const isSending = ref(false)
117 119
118 // 滚动相关 120 // 滚动相关
119 const scrollTop = ref(0) 121 const scrollTop = ref(0)
...@@ -229,6 +231,11 @@ const sendMessage = async () => { ...@@ -229,6 +231,11 @@ const sendMessage = async () => {
229 return 231 return
230 } 232 }
231 233
234 + // 防止重复发送
235 + if (isSending.value) {
236 + return
237 + }
238 +
232 // 只有聊天类型才能发送消息 239 // 只有聊天类型才能发送消息
233 if (props.conversation?.type !== 'chat') { 240 if (props.conversation?.type !== 'chat') {
234 Taro.showToast({ 241 Taro.showToast({
...@@ -240,6 +247,11 @@ const sendMessage = async () => { ...@@ -240,6 +247,11 @@ const sendMessage = async () => {
240 247
241 const messageContent = inputMessage.value.trim() 248 const messageContent = inputMessage.value.trim()
242 249
250 + // 设置发送状态并立即清空输入框
251 + isSending.value = true
252 + inputMessage.value = ''
253 + await nextTick() // 确保输入框立即清空
254 +
243 try { 255 try {
244 // 先添加到本地显示(新消息添加到末尾) 256 // 先添加到本地显示(新消息添加到末尾)
245 const newMessage = { 257 const newMessage = {
...@@ -252,9 +264,6 @@ const sendMessage = async () => { ...@@ -252,9 +264,6 @@ const sendMessage = async () => {
252 } 264 }
253 messages.value.push(newMessage) 265 messages.value.push(newMessage)
254 266
255 - // 清空输入框
256 - inputMessage.value = ''
257 -
258 // 滚动到底部 267 // 滚动到底部
259 await nextTick() 268 await nextTick()
260 scrollToBottom() 269 scrollToBottom()
...@@ -271,6 +280,25 @@ const sendMessage = async () => { ...@@ -271,6 +280,25 @@ const sendMessage = async () => {
271 newMessage.id = response.data.id 280 newMessage.id = response.data.id
272 } 281 }
273 282
283 + // 添加自动回复提示消息
284 + setTimeout(() => {
285 + const autoReplyMessage = {
286 + type: 'received',
287 + content: '您的消息已发送,我们会尽快回复您,请耐心等待。',
288 + time: new Date().toLocaleTimeString('zh-CN', {
289 + hour: '2-digit',
290 + minute: '2-digit'
291 + }),
292 + isAutoReply: true // 标记为自动回复消息
293 + }
294 + messages.value.push(autoReplyMessage)
295 +
296 + // 滚动到底部显示新消息
297 + nextTick(() => {
298 + scrollToBottom()
299 + })
300 + }, 1000) // 延迟1秒显示自动回复
301 +
274 // 触发发送消息事件,通知父组件更新列表 302 // 触发发送消息事件,通知父组件更新列表
275 emit('sendMessage', { 303 emit('sendMessage', {
276 conversation: props.conversation, 304 conversation: props.conversation,
...@@ -284,6 +312,9 @@ const sendMessage = async () => { ...@@ -284,6 +312,9 @@ const sendMessage = async () => {
284 } else { 312 } else {
285 // 发送失败,移除本地消息 313 // 发送失败,移除本地消息
286 messages.value.pop() 314 messages.value.pop()
315 + // 只在真正失败时才恢复输入框内容,避免闪烁
316 + await nextTick()
317 + inputMessage.value = messageContent
287 Taro.showToast({ 318 Taro.showToast({
288 title: response.msg || '发送失败', 319 title: response.msg || '发送失败',
289 icon: 'error' 320 icon: 'error'
...@@ -293,10 +324,16 @@ const sendMessage = async () => { ...@@ -293,10 +324,16 @@ const sendMessage = async () => {
293 console.error('发送消息失败:', error) 324 console.error('发送消息失败:', error)
294 // 发送失败,移除本地消息 325 // 发送失败,移除本地消息
295 messages.value.pop() 326 messages.value.pop()
327 + // 只在真正失败时才恢复输入框内容,避免闪烁
328 + await nextTick()
329 + inputMessage.value = messageContent
296 Taro.showToast({ 330 Taro.showToast({
297 title: '发送失败', 331 title: '发送失败',
298 icon: 'error' 332 icon: 'error'
299 }) 333 })
334 + } finally {
335 + // 重置发送状态
336 + isSending.value = false
300 } 337 }
301 } 338 }
302 339
......