feat(chat): 访客与客服聊天界面、历史拉取与断线重连
聊天页支持发送确认、历史补拉和重连;刷新后不重复展示已确认消息。
This commit is contained in:
1 parent
db48cac9e0
commit
4388e1d203
19 files changed
+6252
No files matched your search
@@ -0,0 +1,96 @@
|
||||
<!--
|
||||
Copyright 2024-2026 ChatterMate
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { toast } from 'vue-sonner'
|
||||
import channelsService, { type WhatsAppTemplate } from '@/services/channels'
|
||||
import { DEFAULT_LANGUAGE } from '@/utils/whatsappLanguages'
|
||||
import BaseModal from '@/components/common/BaseModal.vue'
|
||||
import WhatsAppTemplateSelect, {
|
||||
type TemplateSelection,
|
||||
} from '@/components/conversations/WhatsAppTemplateSelect.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
accountId: string
|
||||
sessionId: string
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'close'): void
|
||||
(e: 'sent', template: WhatsAppTemplate): void
|
||||
}>()
|
||||
|
||||
const selection = ref<TemplateSelection | null>(null)
|
||||
const sending = ref(false)
|
||||
|
||||
const canSend = computed(() => !!selection.value?.complete && !sending.value)
|
||||
|
||||
const send = async () => {
|
||||
if (!selection.value || !canSend.value) return
|
||||
const { template, components } = selection.value
|
||||
try {
|
||||
sending.value = true
|
||||
await channelsService.sendWhatsAppTemplate(props.accountId, {
|
||||
session_id: props.sessionId,
|
||||
template_name: template.name,
|
||||
language: template.language || DEFAULT_LANGUAGE,
|
||||
components,
|
||||
})
|
||||
toast.success('模板已发送', { description: '客户可在接下来 24 小时内回复。' })
|
||||
emit('sent', template)
|
||||
} catch (error: any) {
|
||||
toast.error('模板发送失败', {
|
||||
description: error?.response?.data?.detail || '请重试',
|
||||
closeButton: true,
|
||||
})
|
||||
} finally {
|
||||
sending.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BaseModal title="发送模板" @close="emit('close')">
|
||||
<p class="tpl-intro">
|
||||
该会话已超出 WhatsApp 的 24 小时窗口,发送已审核的模板可重新开启会话。
|
||||
</p>
|
||||
|
||||
<WhatsAppTemplateSelect v-model:selection="selection" :account-id="accountId" />
|
||||
|
||||
<template #actions>
|
||||
<button class="modal-btn" @click="emit('close')">取消</button>
|
||||
<button
|
||||
class="modal-btn modal-btn-primary"
|
||||
:disabled="!canSend"
|
||||
:aria-busy="sending"
|
||||
@click="send"
|
||||
>
|
||||
<font-awesome-icon v-if="sending" icon="fa-solid fa-spinner" spin />
|
||||
{{ sending ? '发送中…' : '发送模板' }}
|
||||
</button>
|
||||
</template>
|
||||
</BaseModal>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.tpl-intro {
|
||||
margin: 0 0 16px;
|
||||
color: var(--muted);
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user