diff --git a/api/request.js b/api/request.js
index 6a216d9..bbcdfe5 100644
--- a/api/request.js
+++ b/api/request.js
@@ -78,7 +78,12 @@ export const request = (options = {}) => {
if (response.statusCode >= 200 && response.statusCode < 300) {
resolve(result.data)
} else {
- reject(new Error(`HTTP ${response.statusCode}: ${response.errMsg || '请求失败'}`))
+ // 创建包含状态码和响应数据的错误对象
+ const error = new Error(`HTTP ${response.statusCode}: ${response.errMsg || '请求失败'}`)
+ error.statusCode = response.statusCode
+ error.response = response
+ error.data = result.data || response.data
+ reject(error)
}
},
fail: (error) => {
diff --git a/api/user.js b/api/user.js
new file mode 100644
index 0000000..9403da4
--- /dev/null
+++ b/api/user.js
@@ -0,0 +1,22 @@
+/**
+ * 用户信息相关 API
+ */
+import { post } from './request.js'
+
+/**
+ * 保存用户信息
+ * @param {Object} data - 用户数据
+ * @param {string} data.name - 用户姓名
+ * @param {string} data.phone - 用户手机号码
+ * @param {string} data.address - 用户地址
+ * @param {string} data.msg - 用户留言
+ * @param {string} data.page_visit_uuid - 页面访问UUID
+ * @returns {Promise}
+ */
+export const saveUserInfo = (data) => {
+ return post('/api/user-info', data)
+}
+
+export default {
+ saveUserInfo
+}
diff --git a/components/EndPage.vue b/components/EndPage.vue
index 0a9e20c..f7e61dd 100644
--- a/components/EndPage.vue
+++ b/components/EndPage.vue
@@ -122,12 +122,25 @@ const props = defineProps({
longfusi: false,
dongzhimen: false
})
+ },
+ hasSubmitted: {
+ type: Boolean,
+ default: false
}
})
const emit = defineEmits(['lottery', 'couplet', 'restart'])
const handleLottery = () => {
+ // 如果已经提交过,直接提示
+ if (props.hasSubmitted) {
+ uni.showToast({
+ title: '您已经提交过信息了,请勿重复提交',
+ icon: 'none',
+ duration: 2000
+ })
+ return
+ }
emit('lottery')
}
diff --git a/components/LotteryFormModal.vue b/components/LotteryFormModal.vue
index 264c70f..b75dd35 100644
--- a/components/LotteryFormModal.vue
+++ b/components/LotteryFormModal.vue
@@ -5,6 +5,10 @@ const props = defineProps({
visible: {
type: Boolean,
default: false
+ },
+ hasSubmitted: {
+ type: Boolean,
+ default: false
}
})
@@ -48,9 +52,16 @@ const showToast = (title) => {
// 提交表单
const handleSubmit = () => {
+ // 如果已经提交过,直接提示
+ if (props.hasSubmitted) {
+ showToast('您已经提交过信息了,请勿重复提交')
+ return
+ }
+
console.log('提交表单', formData.value)
// 验证表单
+ console.log('表单数据:', formData.value)
if (!formData.value.name || !formData.value.phone || !formData.value.address || !formData.value.msg) {
showToast('请填写完整信息')
return
@@ -58,7 +69,9 @@ const handleSubmit = () => {
// 验证手机号
const phoneRegex = /^1[3-9]\d{9}$/
- if (!phoneRegex.test(formData.value.phone)) {
+ const phone = formData.value.phone.trim()
+ console.log('手机号验证:', phone, '长度:', phone.length, '匹配结果:', phoneRegex.test(phone))
+ if (!phoneRegex.test(phone)) {
showToast('请输入正确的手机号')
return
}
@@ -76,7 +89,15 @@ const handleSubmit = () => {
return
}
- emit('submit', { ...formData.value })
+ // 提交前清理数据
+ const submitData = {
+ name: formData.value.name.trim(),
+ phone: formData.value.phone.trim(),
+ address: formData.value.address.trim(),
+ msg: formData.value.msg.trim()
+ }
+
+ emit('submit', submitData)
}
@@ -110,6 +131,8 @@ const handleSubmit = () => {
type="text"
placeholder="请输入您的姓名"
class="form-input"
+ maxlength="30"
+ required
/>
@@ -119,6 +142,8 @@ const handleSubmit = () => {
type="tel"
placeholder="请输入您的联系电话"
class="form-input"
+ maxlength="11"
+ required
/>
@@ -129,6 +154,7 @@ const handleSubmit = () => {
placeholder="请输入您的邮寄地址"
class="form-input"
maxlength="100"
+ required
/>
@@ -138,6 +164,7 @@ const handleSubmit = () => {
placeholder="请输入您的留言"
class="form-textarea"
maxlength="200"
+ required
>
{{ formData.msg.length }}/200
diff --git a/components/SinglePageContainer.vue b/components/SinglePageContainer.vue
index f6fe375..7cabcbf 100644
--- a/components/SinglePageContainer.vue
+++ b/components/SinglePageContainer.vue
@@ -3,6 +3,7 @@ import { ref, onMounted, onUnmounted, computed, watch, nextTick } from 'vue'
import { useSceneStore } from '../store/scene'
import { useCollectionStore } from '../store/collection'
import { recordPageVisit } from '../api/visit.js'
+import { saveUserInfo } from '../api/user.js'
import LongImageViewer from './LongImageViewer.vue'
import MediaPlayer from './MediaPlayer.vue'
import QianmenScene from './QianmenScene.vue'
@@ -42,6 +43,10 @@ const showCoupletDisplay = ref(false)
const coupletKeyword = ref('')
// 生成的春联
const generatedCouplet = ref(null)
+// 页面访问UUID
+const pageVisitUuid = ref('')
+// 是否已提交用户信息
+const hasSubmittedUserInfo = ref(false)
// 推荐关键词
@@ -141,6 +146,13 @@ onMounted(() => {
recordPageVisit({
user_agent: navigator.userAgent,
page_name: 'home'
+ }).then(res => {
+ if (res && res.uuid) {
+ pageVisitUuid.value = res.uuid
+ console.log('页面访问UUID:', res.uuid)
+ }
+ }).catch(err => {
+ console.log('页面访问记录失败:', err)
})
// 检查并初始化场景交互状态
@@ -340,21 +352,74 @@ const closeLotteryForm = () => {
}
// 提交抽奖表单
-const submitLotteryForm = (formData) => {
- // 模拟提交
+const submitLotteryForm = async (formData) => {
+ // 检查是否已经提交过
+ if (hasSubmittedUserInfo.value) {
+ uni.showToast({
+ title: '您已经提交过信息了,请勿重复提交',
+ icon: 'none',
+ duration: 2000
+ })
+ return
+ }
+
+ // 检查是否有UUID
+ if (!pageVisitUuid.value) {
+ uni.showToast({
+ title: '系统错误,请刷新页面重试',
+ icon: 'none',
+ duration: 2000
+ })
+ return
+ }
+
uni.showLoading({
title: '提交中...',
mask: true
})
- setTimeout(() => {
+ try {
+ // 调用用户信息保存接口
+ await saveUserInfo({
+ name: formData.name,
+ phone: formData.phone,
+ address: formData.address,
+ msg: formData.msg,
+ page_visit_uuid: pageVisitUuid.value
+ })
+
+ // 标记为已提交
+ hasSubmittedUserInfo.value = true
+
uni.hideLoading()
uni.showToast({
- title: '报名成功!我们将在活动结束后通知您抽奖结果',
+ title: '提交成功!我们将在活动结束后通知您抽奖结果',
duration: 2000
})
showLotteryForm.value = false
- }, 1500)
+ } catch (error) {
+ uni.hideLoading()
+ console.error('提交用户信息失败:', error)
+
+ // 直接展示后端返回的错误信息
+ let errorMessage = '提交失败,请稍后重试'
+
+ // 检查是否有后端返回的错误信息
+ if (error.data && error.data.error) {
+ errorMessage = error.data.error
+ } else if (error.response && error.response.data && error.response.data.error) {
+ errorMessage = error.response.data.error
+ } else if (error.message) {
+ // 如果是网络错误或其他错误,显示通用提示
+ errorMessage = '提交失败,请稍后重试'
+ }
+
+ uni.showToast({
+ title: errorMessage,
+ icon: 'none',
+ duration: 2000
+ })
+ }
}
// 打开AI春联生成弹窗
@@ -471,6 +536,7 @@ onUnmounted(() => {
:collected-count="collectedItems.length"
:total-count="scenes.length - 1"
:collected-seals="collectedSeals"
+ :has-submitted="hasSubmittedUserInfo"
@lottery="openLotteryForm"
@couplet="openAICoupletForm"
@restart="scrollToTop"
@@ -552,6 +618,7 @@ onUnmounted(() => {