461 lines
17 KiB
Vue
461 lines
17 KiB
Vue
<template>
|
|
<div>
|
|
<!-- 页面标题 -->
|
|
<Banner
|
|
:titleKey="'contact.hero.title'"
|
|
:subtitleKey="'contact.hero.subtitle'"
|
|
bgImage="/images/bg/advantage.webp"
|
|
>
|
|
<!-- 按钮或其他内容 -->
|
|
</Banner>
|
|
|
|
<!-- 联系信息与表单 -->
|
|
<section class="py-20">
|
|
<div class="container">
|
|
<div class="grid md:grid-cols-3 gap-8">
|
|
<!-- 联系信息 -->
|
|
<div class="md:col-span-1">
|
|
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-lg p-8 h-full">
|
|
<h2 class="text-2xl font-bold mb-6 text-primary dark:text-[#4da6ff]">
|
|
{{ $t("contact.info.title") }}
|
|
</h2>
|
|
|
|
<div class="space-y-6">
|
|
<div class="flex items-start">
|
|
<div
|
|
class="bg-primary/10 dark:bg-primary/20 rounded-full mr-3 flex items-center justify-center w-10 h-10"
|
|
>
|
|
<i class="fas fa-map-marker-alt text-primary dark:text-[#4da6ff] text-lg"></i>
|
|
</div>
|
|
<div>
|
|
<h3 class="font-medium text-lg mb-1 dark:text-white">
|
|
{{ $t("contact.info.address.title") }}
|
|
</h3>
|
|
<p class="text-gray-600 dark:text-gray-300">
|
|
{{ $t("contact.info.address.content") }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex items-start">
|
|
<div
|
|
class="bg-primary/10 dark:bg-primary/20 rounded-full mr-3 flex items-center justify-center w-10 h-10"
|
|
>
|
|
<i class="fas fa-envelope text-primary dark:text-[#4da6ff] text-lg"></i>
|
|
</div>
|
|
<div>
|
|
<h3 class="font-medium text-lg mb-1 dark:text-white">
|
|
{{ $t("contact.info.email.title") }}
|
|
</h3>
|
|
<p class="text-gray-600 dark:text-gray-300">{{ contact.email }}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex items-start">
|
|
<div
|
|
class="bg-primary/10 dark:bg-primary/20 rounded-full mr-3 flex items-center justify-center w-10 h-10"
|
|
>
|
|
<i class="fas fa-phone-alt text-primary dark:text-[#4da6ff] text-lg"></i>
|
|
</div>
|
|
<div>
|
|
<h3 class="font-medium text-lg mb-1 dark:text-white">
|
|
{{ $t("contact.info.phone.title") }}
|
|
</h3>
|
|
<p class="text-gray-600 dark:text-gray-300">
|
|
{{ contact.phone }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex items-start">
|
|
<div
|
|
class="bg-primary/10 dark:bg-primary/20 rounded-full mr-3 flex items-center justify-center w-10 h-10"
|
|
>
|
|
<i class="fas fa-clock text-primary dark:text-[#4da6ff] text-lg"></i>
|
|
</div>
|
|
<div>
|
|
<h3 class="font-medium text-lg mb-1 dark:text-white">
|
|
{{ $t("contact.info.hours.title") }}
|
|
</h3>
|
|
<p class="text-gray-600 dark:text-gray-300">
|
|
{{ $t("contact.info.hours.content") }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-8">
|
|
<h3 class="font-medium text-lg mb-4 dark:text-white">
|
|
{{ $t("contact.info.social.title") }}
|
|
</h3>
|
|
<div class="flex space-x-4">
|
|
<!-- <a
|
|
:href="contact.instagram"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
class="bg-primary/10 dark:bg-primary/20 w-10 h-10 rounded-full flex items-center justify-center text-primary dark:text-[#4da6ff] hover:bg-primary hover:text-white transition-colors duration-300"
|
|
>
|
|
<i class="fab fa-instagram"></i>
|
|
</a> -->
|
|
<!-- <a
|
|
:href="contact.twitter"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
class="bg-primary/10 dark:bg-primary/20 w-10 h-10 rounded-full flex items-center justify-center text-primary dark:text-[#4da6ff] hover:bg-primary hover:text-white transition-colors duration-300"
|
|
>
|
|
<i class="fab fa-twitter"></i>
|
|
</a> -->
|
|
<a
|
|
:href="contact.telegram"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
class="bg-primary/10 dark:bg-primary/20 w-10 h-10 rounded-full flex items-center justify-center text-primary dark:text-[#4da6ff] hover:bg-primary hover:text-white transition-colors duration-300"
|
|
>
|
|
<i class="fab fa-telegram"></i>
|
|
</a>
|
|
<a
|
|
:href="contact.telegram"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
class="bg-primary/10 dark:bg-primary/20 w-10 h-10 rounded-full flex items-center justify-center text-primary dark:text-[#4da6ff] hover:bg-primary hover:text-white transition-colors duration-300"
|
|
>
|
|
<i class="fab fa-whatsapp"></i>
|
|
</a>
|
|
<!-- <a
|
|
:href="contact.facebook"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
class="bg-primary/10 dark:bg-primary/20 w-10 h-10 rounded-full flex items-center justify-center text-primary dark:text-[#4da6ff] hover:bg-primary hover:text-white transition-colors duration-300"
|
|
>
|
|
<i class="fab fa-facebook"></i>
|
|
</a> -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 联系表单 -->
|
|
<div class="md:col-span-2">
|
|
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-lg p-8">
|
|
<h2 class="text-2xl font-bold mb-2 text-primary dark:text-[#4da6ff]">
|
|
{{ $t("contact.form.title") }}
|
|
</h2>
|
|
<p class="text-gray-600 dark:text-gray-300 mb-6">
|
|
{{ $t("contact.form.subtitle") }}
|
|
</p>
|
|
|
|
<form @submit.prevent="submitForm" class="space-y-6">
|
|
<div class="grid md:grid-cols-2 gap-6">
|
|
<div>
|
|
<label
|
|
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2"
|
|
>{{ $t("contact.form.fields.name") }}</label
|
|
>
|
|
<input
|
|
type="text"
|
|
v-model="formData.name"
|
|
:placeholder="$t('contact.form.placeholders.name')"
|
|
class="w-full px-4 py-3 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent"
|
|
required
|
|
/>
|
|
</div>
|
|
|
|
<div>
|
|
<label
|
|
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2"
|
|
>{{ $t("contact.form.fields.email") }}</label
|
|
>
|
|
<input
|
|
type="email"
|
|
v-model="formData.email"
|
|
:placeholder="$t('contact.form.placeholders.email')"
|
|
class="w-full px-4 py-3 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent"
|
|
required
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">{{
|
|
$t("contact.form.fields.phone")
|
|
}}</label>
|
|
<input
|
|
type="tel"
|
|
v-model="formData.phone"
|
|
:placeholder="$t('contact.form.placeholders.phone')"
|
|
class="w-full px-4 py-3 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent"
|
|
/>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">{{
|
|
$t("contact.form.fields.company")
|
|
}}</label>
|
|
<input
|
|
type="text"
|
|
v-model="formData.company"
|
|
:placeholder="$t('contact.form.placeholders.company')"
|
|
class="w-full px-4 py-3 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent"
|
|
/>
|
|
</div>
|
|
<!-- //miguan -->
|
|
<input type="text" name="_gotcha" style="display: none" />
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">{{
|
|
$t("contact.form.fields.subject")
|
|
}}</label>
|
|
<select
|
|
v-model="formData.subject"
|
|
class="w-full px-4 py-3 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent"
|
|
required
|
|
>
|
|
<option value="" disabled>
|
|
{{ $t("contact.form.placeholders.subject") }}
|
|
</option>
|
|
<option
|
|
v-for="(option, index) in subjectOptions"
|
|
:key="index"
|
|
:value="option.value"
|
|
>
|
|
{{ option.label }}
|
|
</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">{{
|
|
$t("contact.form.fields.message")
|
|
}}</label>
|
|
<textarea
|
|
v-model="formData.message"
|
|
:placeholder="$t('contact.form.placeholders.message')"
|
|
class="w-full px-4 py-3 border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent resize-none"
|
|
rows="5"
|
|
required
|
|
></textarea>
|
|
</div>
|
|
|
|
<div class="flex items-start">
|
|
<input
|
|
type="checkbox"
|
|
id="privacy"
|
|
v-model="formData.privacy"
|
|
class="mt-1 mr-2"
|
|
required
|
|
/>
|
|
<label for="privacy" class="text-sm text-gray-600 dark:text-gray-300">
|
|
{{ $t("contact.form.privacy") }}
|
|
<a href="/terms" class="text-secondary dark:text-[#6db8ff]">{{
|
|
$t("contact.form.privacyLink")
|
|
}}</a>
|
|
</label>
|
|
</div>
|
|
|
|
<div>
|
|
<button
|
|
type="submit"
|
|
class="w-full px-6 py-3 bg-primary text-white rounded-lg transition-colors duration-300 font-medium flex items-center justify-center"
|
|
:disabled="formSubmitting"
|
|
>
|
|
<span v-if="!formSubmitting">{{
|
|
$t("contact.form.submit")
|
|
}}</span>
|
|
<span v-else class="flex items-center">
|
|
<i class="fas fa-spinner fa-spin mr-2"></i>
|
|
{{ $t("contact.form.sending") }}
|
|
</span>
|
|
</button>
|
|
</div>
|
|
</form>
|
|
|
|
<!-- 成功消息 -->
|
|
<div
|
|
v-if="formSubmitted"
|
|
class="mt-6 p-4 bg-green-50 dark:bg-green-900/20 text-green-700 dark:text-green-400 rounded-lg"
|
|
>
|
|
<div class="flex items-start">
|
|
<i
|
|
class="fas fa-check-circle text-green-500 dark:text-green-400 mt-1 mr-3 text-xl"
|
|
></i>
|
|
<div>
|
|
<p class="font-semibold">
|
|
{{ $t("contact.form.success.title") }}
|
|
</p>
|
|
<p class="text-sm mt-1">
|
|
{{ $t("contact.form.success.message") }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 错误消息 -->
|
|
<div
|
|
v-if="formError"
|
|
class="mt-6 p-4 bg-red-50 dark:bg-red-900/20 text-red-700 dark:text-red-400 rounded-lg"
|
|
>
|
|
<div class="flex items-start">
|
|
<i
|
|
class="fas fa-exclamation-circle text-red-500 dark:text-red-400 mt-1 mr-3 text-xl"
|
|
></i>
|
|
<div>
|
|
<p class="font-semibold">
|
|
{{ $t("contact.form.error.title") }}
|
|
</p>
|
|
<p class="text-sm mt-1">
|
|
{{ $t("contact.form.error.message") }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- 地图部分 -->
|
|
<section class="py-16 bg-gray-50 dark:bg-gray-900">
|
|
<div class="container">
|
|
<div class="text-center mb-12">
|
|
<h2 class="text-3xl font-bold text-gray-900 dark:text-white mb-4">
|
|
{{ $t("contact.map.title") }}
|
|
</h2>
|
|
<p class="text-xl text-gray-600 dark:text-gray-300 max-w-3xl mx-auto">
|
|
{{ $t("contact.map.subtitle") }}
|
|
</p>
|
|
</div>
|
|
|
|
<div class="shadow-xl rounded-lg overflow-hidden h-96">
|
|
<ClientOnly>
|
|
<Map />
|
|
</ClientOnly>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, reactive, computed, watch } from "vue";
|
|
import { useI18n } from "vue-i18n";
|
|
import Map from "~/components/Map.vue";
|
|
import SendForm from "~/public/js/SendForm";
|
|
const { t, locale } = useI18n();
|
|
import { contact } from "~/public/js/contact";
|
|
|
|
import { useHead } from "nuxt/app";
|
|
useHead({
|
|
title: () => t("meta.contact.title"),
|
|
meta: [
|
|
{ name: "description", content: () => t("meta.contact.description") },
|
|
{ name: "keywords", content: () => t("meta.contact.keywords") },
|
|
],
|
|
});
|
|
interface FormData {
|
|
name: string;
|
|
email: string;
|
|
phone: string;
|
|
company: string;
|
|
subject: string;
|
|
message: string;
|
|
privacy: boolean;
|
|
}
|
|
|
|
interface FaqItem {
|
|
question: string;
|
|
answer: string;
|
|
isOpen: boolean;
|
|
}
|
|
|
|
// 表单数据
|
|
const formData = reactive<FormData>({
|
|
name: "",
|
|
email: "",
|
|
phone: "",
|
|
company: "",
|
|
subject: "",
|
|
message: "",
|
|
privacy: false,
|
|
});
|
|
|
|
// 表单状态
|
|
const formSubmitting = ref(false);
|
|
const formSubmitted = ref(false);
|
|
const formError = ref(false);
|
|
|
|
// 主题选项
|
|
const subjectOptions = computed(() => [
|
|
{ value: "general", label: t("contact.form.subjects.general") },
|
|
{ value: "sales", label: t("contact.form.subjects.sales") },
|
|
{ value: "support", label: t("contact.form.subjects.support") },
|
|
{ value: "partnership", label: t("contact.form.subjects.partnership") },
|
|
]);
|
|
|
|
// 提交表单
|
|
const submitForm = async () => {
|
|
formSubmitting.value = true;
|
|
formError.value = false;
|
|
|
|
try {
|
|
// 准备邮件数据
|
|
const emailData = {
|
|
subject: `来自网站的联系表单: ${formData.subject}`,
|
|
body: `
|
|
姓名: ${formData.name}
|
|
邮箱: ${formData.email}
|
|
电话: ${formData.phone}
|
|
公司: ${formData.company}
|
|
主题: ${formData.subject}
|
|
消息内容:
|
|
${formData.message}
|
|
`,
|
|
};
|
|
|
|
// console.log('准备发送邮件数据:', emailData);
|
|
// 发送邮件请求
|
|
const response = await fetch(SendForm, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify(emailData),
|
|
});
|
|
|
|
// 解析响应
|
|
let responseData;
|
|
try {
|
|
responseData = await response.json();
|
|
} catch (e) {
|
|
console.error("解析响应失败:", e);
|
|
throw new Error("无法解析服务器响应");
|
|
}
|
|
|
|
// 检查响应状态
|
|
if (!response.ok) {
|
|
const errorMsg = responseData.error || "未知错误";
|
|
throw new Error(`邮件发送失败: ${errorMsg}`);
|
|
}
|
|
|
|
|
|
// 成功处理
|
|
formSubmitted.value = true;
|
|
|
|
// 重置表单
|
|
Object.keys(formData).forEach((key) => {
|
|
const k = key as keyof FormData;
|
|
if (k === "privacy") {
|
|
formData[k] = false;
|
|
} else {
|
|
formData[k] = "";
|
|
}
|
|
});
|
|
} catch (error) {
|
|
// 错误处理
|
|
console.error("发送邮件时出错:", error);
|
|
formError.value = true;
|
|
} finally {
|
|
formSubmitting.value = false;
|
|
}
|
|
};
|
|
</script>
|