fix: show customer chat before connection completes
Deploy olons-server production / deploy (push) Successful in 4m30s
Deploy olons-server production / deploy (push) Successful in 4m30s
This commit is contained in:
@@ -38,22 +38,11 @@
|
||||
<section v-else class="m-chat">
|
||||
<PageHeader :title="current?.name || '在线客服'" />
|
||||
<div class="m-chat-time">会话内容已安全加密,请勿发送密码或验证码</div>
|
||||
<div v-if="!chatLoading && connectionState !== 'online'" :class="['m-chat-connection', `is-${connectionState}`]">
|
||||
<span>{{ connectionStatusText }}</span>
|
||||
<div v-if="connectionState !== 'online' || chatError" :class="['m-chat-connection', `is-${connectionState}`]" role="status" aria-live="polite">
|
||||
<span>{{ chatError || connectionStatusText }}</span>
|
||||
<button v-if="connectionState === 'offline'" type="button" @click="connectChat">重新连接</button>
|
||||
</div>
|
||||
<div v-if="chatLoading" class="m-chat-empty">
|
||||
<n-icon :component="ChatbubbleEllipsesOutline" />
|
||||
<h2>正在连接客服</h2>
|
||||
<p>首次连接会自动建立好友关系</p>
|
||||
</div>
|
||||
<div v-else-if="chatError" class="m-chat-empty">
|
||||
<n-icon :component="ChatbubbleEllipsesOutline" />
|
||||
<h2>连接失败</h2>
|
||||
<p class="m-form-error">{{ chatError }}</p>
|
||||
<button class="m-primary-btn" @click="connectChat">重新连接</button>
|
||||
</div>
|
||||
<div v-else ref="messageList" class="m-chat-messages">
|
||||
<div ref="messageList" class="m-chat-messages">
|
||||
<div v-for="message in historicalMessages" :key="`history-${message.seq}-${message.from}`" :class="['m-chat-row', { 'is-mine': message.mine }]">
|
||||
<div class="m-chat-avatar" aria-hidden="true">
|
||||
<img v-if="!message.mine && safeImage(current?.avatar_url)" :src="safeImage(current?.avatar_url)" alt="" />
|
||||
@@ -77,7 +66,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="historicalMessages.length" class="m-chat-history-divider"><span>以上是历史会话</span></div>
|
||||
<div class="m-chat-session-tip">[ {{ current?.name || '在线客服' }} ] 与您建立了会话</div>
|
||||
<div class="m-chat-session-tip">[ {{ current?.name || '在线客服' }} ] 客服会话已打开</div>
|
||||
<div class="m-chat-system-row">
|
||||
<div class="m-chat-avatar m-chat-avatar--agent" aria-hidden="true">
|
||||
<img v-if="safeImage(current?.avatar_url)" :src="safeImage(current?.avatar_url)" alt="" />
|
||||
@@ -85,7 +74,7 @@
|
||||
</div>
|
||||
<div class="m-chat-system-message">
|
||||
<small>{{ current?.name || '在线客服' }} · {{ messageDateTime(sessionStartedAt) }}</small>
|
||||
<p><b>【系统消息】</b>尊敬的用户您好,我是{{ current?.name || '在线客服' }},当前已为您接通在线客服,请问有什么可以帮您?</p>
|
||||
<p><b>【系统消息】</b>您好,我是{{ current?.name || '在线客服' }}。您可以先输入要咨询的问题,正在为您连接客服。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-for="message in liveMessages" :key="`live-${message.seq}-${message.from}`" :class="['m-chat-row', { 'is-mine': message.mine }]">
|
||||
@@ -113,12 +102,12 @@
|
||||
</div>
|
||||
<div class="m-chat-composer" :class="{ 'is-expanded': toolsOpen }">
|
||||
<form class="m-chat-input" @submit.prevent="sendMessage">
|
||||
<input v-model="draft" :disabled="chatLoading || Boolean(chatError) || connectionState !== 'online' || sending || mediaSending" maxlength="1000" placeholder="请输入消息" />
|
||||
<input v-model="draft" :disabled="sending || mediaSending" maxlength="1000" placeholder="请输入消息" />
|
||||
<button
|
||||
v-if="draft.trim()"
|
||||
class="m-chat-send"
|
||||
type="submit"
|
||||
:disabled="chatLoading || Boolean(chatError) || connectionState !== 'online' || sending || mediaSending"
|
||||
:disabled="!chat || connectionState !== 'online' || sending || mediaSending"
|
||||
>{{ sending ? '发送中' : '发送' }}</button>
|
||||
<button v-else class="m-chat-tool" type="button" aria-label="更多" @click="toggleTools">
|
||||
<img :src="mobileAssets.chatMore" alt="" />
|
||||
@@ -127,8 +116,8 @@
|
||||
<div v-if="mediaSending" class="m-chat-uploading"><progress max="100" :value="uploadProgress"></progress><b>正在上传 {{ uploadProgress }}%</b></div>
|
||||
<div v-if="toolsOpen && !emojiOpen" class="m-chat-tools">
|
||||
<button type="button" @click="emojiOpen = true"><n-icon :component="HappyOutline" /><span>表情</span></button>
|
||||
<button type="button" :disabled="mediaSending" @click="photoInput?.click()"><n-icon :component="ImageOutline" /><span>照片</span></button>
|
||||
<button type="button" :disabled="mediaSending" @click="videoInput?.click()"><n-icon :component="VideocamOutline" /><span>视频</span></button>
|
||||
<button type="button" :disabled="!chat || connectionState !== 'online' || mediaSending" @click="photoInput?.click()"><n-icon :component="ImageOutline" /><span>照片</span></button>
|
||||
<button type="button" :disabled="!chat || connectionState !== 'online' || mediaSending" @click="videoInput?.click()"><n-icon :component="VideocamOutline" /><span>视频</span></button>
|
||||
<input ref="photoInput" class="m-chat-file-input" type="file" accept="image/jpeg,image/png,image/webp,image/gif" @change="sendMedia('image', $event)" />
|
||||
<input ref="videoInput" class="m-chat-file-input" type="file" accept="video/mp4,video/webm,video/quicktime" @change="sendMedia('video', $event)" />
|
||||
</div>
|
||||
@@ -157,7 +146,6 @@
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import {
|
||||
ChatbubbleEllipsesOutline,
|
||||
HappyOutline,
|
||||
HeadsetOutline,
|
||||
ImageOutline,
|
||||
@@ -184,7 +172,6 @@
|
||||
services.value.find((item) => String(item.id) === String(route.params.id)) ||
|
||||
services.value[0]
|
||||
);
|
||||
const chatLoading = ref(false);
|
||||
const chatError = ref('');
|
||||
const connectionState = ref<CustomerServiceConnectionState>('offline');
|
||||
const connectionStatusText = computed(() => {
|
||||
@@ -268,7 +255,6 @@
|
||||
chat = null;
|
||||
messages.value = [];
|
||||
historyBoundarySeq.value = 0;
|
||||
chatLoading.value = false;
|
||||
chatError.value = '';
|
||||
connectionState.value = 'offline';
|
||||
draft.value = '';
|
||||
@@ -283,7 +269,9 @@
|
||||
disconnectChat();
|
||||
if (!serviceID) return;
|
||||
const version = connectionVersion;
|
||||
chatLoading.value = true;
|
||||
connectionState.value = 'connecting';
|
||||
chatError.value = '';
|
||||
sessionStartedAt.value = new Date().toISOString();
|
||||
try {
|
||||
const session = await request<CustomerServiceSession>({
|
||||
url: `/v1/customer-services/${serviceID}/session`,
|
||||
@@ -321,8 +309,7 @@
|
||||
chat?.disconnect();
|
||||
chat = null;
|
||||
chatError.value = errorText(err);
|
||||
} finally {
|
||||
if (version === connectionVersion) chatLoading.value = false;
|
||||
connectionState.value = 'offline';
|
||||
}
|
||||
}
|
||||
async function sendMessage() {
|
||||
|
||||
Reference in New Issue
Block a user