2b69686795
- 新增404页面,优化未找到页面体验,避免被搜索引擎索引 - 增加文件代理接口,隐藏真实文件服务器地址,支持文件请求代理 - 实现/article、/case、/product及/page动态路由兼容列表与详情展示 - 添加动态CMS页面兼容入口处理旧式路径,统一路由与SEO设置 - 新增模板1、模板7、模板2、模板3关于我们页面,实现多模板支持 - 模板增强支持CMS单页内容加载及SEO信息动态设置 - 配置环境变量及Git忽略文件规则辅助开发和构建环境管理
154 lines
4.7 KiB
Vue
154 lines
4.7 KiB
Vue
<template>
|
||
<ClientOnly>
|
||
<Teleport to="body">
|
||
<Transition name="consult-fade">
|
||
<div
|
||
v-if="isOpen"
|
||
class="fixed inset-0 z-[100] flex items-center justify-center p-4"
|
||
@click.self="closeConsult"
|
||
>
|
||
<!-- 遮罩 -->
|
||
<div class="absolute inset-0 bg-black/50 backdrop-blur-sm" />
|
||
|
||
<!-- 弹窗卡片 -->
|
||
<Transition name="consult-pop" appear>
|
||
<div
|
||
v-if="isOpen"
|
||
class="relative bg-white rounded-2xl shadow-2xl w-full max-w-md p-6 sm:p-8 max-h-[90vh] overflow-y-auto"
|
||
role="dialog"
|
||
aria-modal="true"
|
||
aria-label="立即咨询"
|
||
>
|
||
<!-- 关闭按钮 -->
|
||
<button
|
||
type="button"
|
||
class="absolute top-4 right-4 w-8 h-8 flex items-center justify-center rounded-full text-gray-400 hover:text-gray-600 hover:bg-gray-100 transition-colors"
|
||
aria-label="关闭"
|
||
@click="closeConsult"
|
||
>
|
||
<svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||
</svg>
|
||
</button>
|
||
|
||
<!-- 成功态 -->
|
||
<div v-if="submitted" class="text-center py-6">
|
||
<div class="w-14 h-14 mx-auto mb-4 rounded-full bg-green-100 flex items-center justify-center">
|
||
<svg class="w-7 h-7 text-green-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
||
</svg>
|
||
</div>
|
||
<h3 class="text-lg font-bold text-gray-900 mb-2">提交成功</h3>
|
||
<p class="text-gray-600 text-sm">我们会尽快与您联系,请保持电话畅通。</p>
|
||
</div>
|
||
|
||
<!-- 表单态 -->
|
||
<div v-else>
|
||
<div class="mb-6 pr-8">
|
||
<h2 class="text-xl font-bold text-gray-900 mb-1">立即咨询</h2>
|
||
<p class="text-sm text-gray-500">留下您的联系方式,我们将尽快与您联系</p>
|
||
</div>
|
||
|
||
<ContactForm
|
||
type="consult"
|
||
content-label="需求"
|
||
submit-text="立即提交"
|
||
:content-required="false"
|
||
:preset-content="presetNeed"
|
||
:source="source"
|
||
accent="#1a6dff"
|
||
@success="onSuccess"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</Transition>
|
||
</div>
|
||
</Transition>
|
||
</Teleport>
|
||
</ClientOnly>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
/**
|
||
* 全站咨询弹窗
|
||
* 通过 useConsult() 控制开关,内部复用共享 ContactForm(与 /contact 功能对齐:
|
||
* 手机号段校验、蜜罐、滑块验证码(按后台配置)、频率限制、去重、提交)。
|
||
* 挂载在 layouts/default.vue,全站可用。
|
||
*/
|
||
import ContactForm from './ContactForm.vue'
|
||
|
||
const { isOpen, presetNeed, source, closeConsult } = useConsult()
|
||
|
||
const submitted = ref(false)
|
||
|
||
let successTimer: ReturnType<typeof setTimeout> | null = null
|
||
|
||
// 打开时锁定背景滚动;关闭时复位成功态
|
||
watch(isOpen, (open) => {
|
||
if (open) {
|
||
submitted.value = false
|
||
if (import.meta.client) {
|
||
document.body.style.overflow = 'hidden'
|
||
}
|
||
} else {
|
||
if (import.meta.client) {
|
||
document.body.style.overflow = ''
|
||
}
|
||
}
|
||
})
|
||
|
||
// ESC 关闭
|
||
function onKeydown(e: KeyboardEvent) {
|
||
if (e.key === 'Escape' && isOpen.value) closeConsult()
|
||
}
|
||
|
||
// 提交成功后显示成功态,2.5s 自动关闭
|
||
function onSuccess() {
|
||
submitted.value = true
|
||
successTimer = setTimeout(() => {
|
||
if (submitted.value) {
|
||
submitted.value = false
|
||
closeConsult()
|
||
}
|
||
}, 2500)
|
||
}
|
||
|
||
onMounted(() => {
|
||
window.addEventListener('keydown', onKeydown)
|
||
})
|
||
|
||
onBeforeUnmount(() => {
|
||
window.removeEventListener('keydown', onKeydown)
|
||
if (successTimer) clearTimeout(successTimer)
|
||
if (import.meta.client) {
|
||
document.body.style.overflow = ''
|
||
}
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
.consult-fade-enter-active,
|
||
.consult-fade-leave-active {
|
||
transition: opacity 0.2s ease;
|
||
}
|
||
.consult-fade-enter-from,
|
||
.consult-fade-leave-to {
|
||
opacity: 0;
|
||
}
|
||
|
||
.consult-pop-enter-active {
|
||
transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.25s ease;
|
||
}
|
||
.consult-pop-leave-active {
|
||
transition: transform 0.2s ease, opacity 0.2s ease;
|
||
}
|
||
.consult-pop-enter-from {
|
||
transform: scale(0.95) translateY(10px);
|
||
opacity: 0;
|
||
}
|
||
.consult-pop-leave-to {
|
||
transform: scale(0.95);
|
||
opacity: 0;
|
||
}
|
||
</style>
|