Hanye官网
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

contact.vue 8.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. <template>
  2. <div class="py-8">
  3. <div class="container-custom">
  4. <h1 class="text-3xl font-bold mb-8">{{ $t('contact.title') }}</h1>
  5. <div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
  6. <!-- 联系表单 -->
  7. <div class="bg-white border border-gray-200 rounded-lg overflow-hidden">
  8. <div class="p-8">
  9. <h2 class="text-2xl font-semibold mb-6">给我们留言</h2>
  10. <ErrorBoundary :error="error">
  11. <form @submit.prevent="submitForm">
  12. <div class="mb-4">
  13. <label for="name" class="block text-gray-700 font-medium mb-2">{{ $t('contact.name') }}</label>
  14. <input
  15. type="text"
  16. id="name"
  17. v-model="formData.name"
  18. class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
  19. :class="{ 'border-red-500': formErrors.name }"
  20. required
  21. >
  22. <p v-if="formErrors.name" class="mt-1 text-sm text-red-600">{{ formErrors.name }}</p>
  23. </div>
  24. <div class="mb-4">
  25. <label for="email" class="block text-gray-700 font-medium mb-2">{{ $t('contact.email') }}</label>
  26. <input
  27. type="email"
  28. id="email"
  29. v-model="formData.email"
  30. class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
  31. :class="{ 'border-red-500': formErrors.email }"
  32. required
  33. >
  34. <p v-if="formErrors.email" class="mt-1 text-sm text-red-600">{{ formErrors.email }}</p>
  35. </div>
  36. <div class="mb-6">
  37. <label for="message" class="block text-gray-700 font-medium mb-2">{{ $t('contact.message') }}</label>
  38. <textarea
  39. id="message"
  40. v-model="formData.message"
  41. class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 h-32"
  42. :class="{ 'border-red-500': formErrors.message }"
  43. required
  44. ></textarea>
  45. <p v-if="formErrors.message" class="mt-1 text-sm text-red-600">{{ formErrors.message }}</p>
  46. </div>
  47. <div>
  48. <button
  49. type="submit"
  50. class="btn btn-primary w-full"
  51. :disabled="isLoading"
  52. >
  53. <span v-if="isLoading" class="flex items-center justify-center">
  54. <span class="animate-spin h-4 w-4 border-2 border-white rounded-full border-t-transparent mr-2"></span>
  55. 提交中...
  56. </span>
  57. <span v-else>{{ $t('contact.submit') }}</span>
  58. </button>
  59. </div>
  60. <div v-if="submitSuccess" class="mt-4 p-3 bg-green-50 text-green-800 rounded-md">
  61. 消息已成功发送,我们会尽快与您联系。
  62. </div>
  63. </form>
  64. </ErrorBoundary>
  65. </div>
  66. </div>
  67. <!-- 联系信息 -->
  68. <div class="bg-white border border-gray-200 rounded-lg overflow-hidden">
  69. <div class="p-8">
  70. <h2 class="text-2xl font-semibold mb-6">联系方式</h2>
  71. <div class="space-y-6">
  72. <div class="flex items-start">
  73. <div class="flex-shrink-0 h-10 w-10 flex items-center justify-center bg-blue-100 text-blue-600 rounded-full">
  74. <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
  75. <path fill-rule="evenodd" d="M5.05 4.05a7 7 0 119.9 9.9L10 18.9l-4.95-4.95a7 7 0 010-9.9zM10 11a2 2 0 100-4 2 2 0 000 4z" clip-rule="evenodd" />
  76. </svg>
  77. </div>
  78. <div class="ml-4">
  79. <h3 class="text-lg font-medium text-gray-900">地址</h3>
  80. <p class="mt-1 text-gray-600">
  81. 中国上海市浦东新区张江高科技园区<br>
  82. 科技大道123号
  83. </p>
  84. </div>
  85. </div>
  86. <div class="flex items-start">
  87. <div class="flex-shrink-0 h-10 w-10 flex items-center justify-center bg-blue-100 text-blue-600 rounded-full">
  88. <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
  89. <path d="M2 3a1 1 0 011-1h2.153a1 1 0 01.986.836l.74 4.435a1 1 0 01-.54 1.06l-1.548.773a11.037 11.037 0 006.105 6.105l.774-1.548a1 1 0 011.059-.54l4.435.74a1 1 0 01.836.986V17a1 1 0 01-1 1h-2C7.82 18 2 12.18 2 5V3z" />
  90. </svg>
  91. </div>
  92. <div class="ml-4">
  93. <h3 class="text-lg font-medium text-gray-900">电话</h3>
  94. <p class="mt-1 text-gray-600">+86 123 456 7890</p>
  95. </div>
  96. </div>
  97. <div class="flex items-start">
  98. <div class="flex-shrink-0 h-10 w-10 flex items-center justify-center bg-blue-100 text-blue-600 rounded-full">
  99. <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
  100. <path d="M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884z" />
  101. <path d="M18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z" />
  102. </svg>
  103. </div>
  104. <div class="ml-4">
  105. <h3 class="text-lg font-medium text-gray-900">邮箱</h3>
  106. <p class="mt-1 text-gray-600">contact@example.com</p>
  107. </div>
  108. </div>
  109. <div class="flex items-start">
  110. <div class="flex-shrink-0 h-10 w-10 flex items-center justify-center bg-blue-100 text-blue-600 rounded-full">
  111. <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
  112. <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z" clip-rule="evenodd" />
  113. </svg>
  114. </div>
  115. <div class="ml-4">
  116. <h3 class="text-lg font-medium text-gray-900">工作时间</h3>
  117. <p class="mt-1 text-gray-600">
  118. 周一至周五: 9:00 - 18:00<br>
  119. 周六、周日: 休息
  120. </p>
  121. </div>
  122. </div>
  123. </div>
  124. </div>
  125. </div>
  126. </div>
  127. </div>
  128. </div>
  129. </template>
  130. <script setup lang="ts">
  131. /**
  132. * 联系我们页面
  133. * 提供联系表单和联系信息
  134. */
  135. import { ref, reactive } from 'vue';
  136. import { useErrorHandler } from '~/composables/useErrorHandler';
  137. const { error, isLoading, wrapAsync } = useErrorHandler();
  138. const submitSuccess = ref(false);
  139. // 表单数据
  140. const formData = reactive({
  141. name: '',
  142. email: '',
  143. message: ''
  144. });
  145. // 表单错误
  146. const formErrors = reactive({
  147. name: '',
  148. email: '',
  149. message: ''
  150. });
  151. /**
  152. * 验证表单输入
  153. * @returns 表单是否有效
  154. */
  155. function validateForm(): boolean {
  156. let isValid = true;
  157. // 重置错误
  158. formErrors.name = '';
  159. formErrors.email = '';
  160. formErrors.message = '';
  161. // 验证姓名
  162. if (!formData.name.trim()) {
  163. formErrors.name = '请输入您的姓名';
  164. isValid = false;
  165. }
  166. // 验证邮箱
  167. if (!formData.email.trim()) {
  168. formErrors.email = '请输入您的邮箱';
  169. isValid = false;
  170. } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
  171. formErrors.email = '请输入有效的邮箱地址';
  172. isValid = false;
  173. }
  174. // 验证消息
  175. if (!formData.message.trim()) {
  176. formErrors.message = '请输入您的消息';
  177. isValid = false;
  178. }
  179. return isValid;
  180. }
  181. /**
  182. * 提交表单
  183. */
  184. async function submitForm() {
  185. // 重置成功状态
  186. submitSuccess.value = false;
  187. // 验证表单
  188. if (!validateForm()) {
  189. return;
  190. }
  191. // 提交表单数据
  192. await wrapAsync(async () => {
  193. // 模拟API请求
  194. await new Promise(resolve => setTimeout(resolve, 1000));
  195. // 模拟成功响应
  196. submitSuccess.value = true;
  197. // 清空表单
  198. formData.name = '';
  199. formData.email = '';
  200. formData.message = '';
  201. return true;
  202. });
  203. }
  204. // SEO优化
  205. useHead({
  206. title: '联系我们 - Hanye',
  207. meta: [
  208. { name: 'description', content: '联系我们获取更多信息或咨询服务。我们期待收到您的留言。' }
  209. ]
  210. });
  211. </script>