feat(结账): 重构结账页面,添加个人信息录入组件
将原有的表单输入替换为iframe嵌入的外部表单组件 添加个人信息录入状态管理,支持本地缓存已填写数据 清理页面加载时的历史个人信息录入标记
Showing
3 changed files
with
416 additions
and
75 deletions
src/components/infoEntry/formPage.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <van-popup | ||
| 3 | + v-model:show="visible" | ||
| 4 | + position="right" | ||
| 5 | + :style="{ width: '100%', height: '100%' }" | ||
| 6 | + :close-on-click-overlay="false" | ||
| 7 | + :lock-scroll="true" | ||
| 8 | + @close="handleClose" | ||
| 9 | + > | ||
| 10 | + <div class="info-entry-container"> | ||
| 11 | + <!-- 头部导航栏 --> | ||
| 12 | + <!-- <div class="header"> | ||
| 13 | + <h2 class="title">个人信息录入</h2> | ||
| 14 | + </div> --> | ||
| 15 | + | ||
| 16 | + <!-- iframe容器 --> | ||
| 17 | + <div class="iframe-container" ref="iframeContainer"> | ||
| 18 | + <iframe | ||
| 19 | + ref="iframeRef" | ||
| 20 | + :src="iframeSrc" | ||
| 21 | + frameborder="0" | ||
| 22 | + class="form-iframe" | ||
| 23 | + @load="handleIframeLoad" | ||
| 24 | + ></iframe> | ||
| 25 | + </div> | ||
| 26 | + </div> | ||
| 27 | + </van-popup> | ||
| 28 | +</template> | ||
| 29 | + | ||
| 30 | +<script setup> | ||
| 31 | +import { ref, watch, nextTick, onMounted, onUnmounted } from 'vue' | ||
| 32 | + | ||
| 33 | +/** | ||
| 34 | + * 组件属性定义 | ||
| 35 | + */ | ||
| 36 | +const props = defineProps({ | ||
| 37 | + // 控制弹窗显示状态 | ||
| 38 | + show: { | ||
| 39 | + type: Boolean, | ||
| 40 | + default: false | ||
| 41 | + }, | ||
| 42 | + // iframe的src地址 | ||
| 43 | + iframeSrc: { | ||
| 44 | + type: String, | ||
| 45 | + required: true | ||
| 46 | + } | ||
| 47 | +}) | ||
| 48 | + | ||
| 49 | +/** | ||
| 50 | + * 组件事件定义 | ||
| 51 | + */ | ||
| 52 | +const emit = defineEmits(['update:show', 'data-received', 'close']) | ||
| 53 | + | ||
| 54 | +// 响应式数据 | ||
| 55 | +const visible = ref(false) | ||
| 56 | +const iframeRef = ref(null) | ||
| 57 | +const iframeContainer = ref(null) | ||
| 58 | + | ||
| 59 | +/** | ||
| 60 | + * 监听show属性变化,同步更新visible状态 | ||
| 61 | + */ | ||
| 62 | +watch(() => props.show, (newVal) => { | ||
| 63 | + visible.value = newVal | ||
| 64 | +}, { immediate: true }) | ||
| 65 | + | ||
| 66 | +/** | ||
| 67 | + * 监听visible变化,同步更新父组件的show状态 | ||
| 68 | + */ | ||
| 69 | +watch(visible, (newVal) => { | ||
| 70 | + emit('update:show', newVal) | ||
| 71 | +}) | ||
| 72 | + | ||
| 73 | +/** | ||
| 74 | + * 处理iframe加载完成事件 | ||
| 75 | + */ | ||
| 76 | +const handleIframeLoad = () => { | ||
| 77 | + nextTick(() => { | ||
| 78 | + setupMessageListener() | ||
| 79 | + }) | ||
| 80 | +} | ||
| 81 | + | ||
| 82 | +/** | ||
| 83 | + * 调整iframe高度以适应内容 | ||
| 84 | + */ | ||
| 85 | +const adjustIframeHeight = () => { | ||
| 86 | + // 移除高度限制,让iframe自然滚动 | ||
| 87 | + console.log('iframe高度调整已禁用,允许自然滚动') | ||
| 88 | +} | ||
| 89 | + | ||
| 90 | +/** | ||
| 91 | + * 设置消息监听器,用于接收iframe内表单的数据 | ||
| 92 | + */ | ||
| 93 | +const setupMessageListener = () => { | ||
| 94 | + window.addEventListener('message', handleMessage) | ||
| 95 | +} | ||
| 96 | + | ||
| 97 | +/** | ||
| 98 | + * 处理来自iframe的消息 | ||
| 99 | + * @param {MessageEvent} event - 消息事件 | ||
| 100 | + */ | ||
| 101 | +const handleMessage = (event) => { | ||
| 102 | + try { | ||
| 103 | + // // 验证消息来源(可根据实际情况调整) | ||
| 104 | + // const allowedOrigins = [ | ||
| 105 | + // 'https://oa-dev.onwall.cn', | ||
| 106 | + // 'https://oa.onwall.cn', | ||
| 107 | + // 'http://localhost', | ||
| 108 | + // 'http://127.0.0.1' | ||
| 109 | + // ] | ||
| 110 | + | ||
| 111 | + // const isAllowedOrigin = allowedOrigins.some(origin => | ||
| 112 | + // event.origin.startsWith(origin) | ||
| 113 | + // ) | ||
| 114 | + | ||
| 115 | + // if (!isAllowedOrigin) { | ||
| 116 | + // console.warn('收到来自未授权源的消息:', event.origin) | ||
| 117 | + // return | ||
| 118 | + // } | ||
| 119 | + | ||
| 120 | + // 解析消息数据 | ||
| 121 | + let messageData = event.data | ||
| 122 | + if (typeof messageData === 'string') { | ||
| 123 | + try { | ||
| 124 | + messageData = JSON.parse(messageData) | ||
| 125 | + } catch (e) { | ||
| 126 | + // 如果不是JSON格式,直接使用原始数据 | ||
| 127 | + } | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + console.log('收到iframe消息:', messageData) | ||
| 131 | + | ||
| 132 | + // 检查是否是表单提交的数据 | ||
| 133 | + if (messageData && (messageData.type === 'formSubmit')) { | ||
| 134 | + // 发送数据给父组件 | ||
| 135 | + emit('data-received', messageData) | ||
| 136 | + | ||
| 137 | + // 关闭弹窗 | ||
| 138 | + handleClose() | ||
| 139 | + } | ||
| 140 | + } catch (error) { | ||
| 141 | + console.error('处理iframe消息时出错:', error) | ||
| 142 | + } | ||
| 143 | +} | ||
| 144 | + | ||
| 145 | +/** | ||
| 146 | + * 处理弹窗关闭 | ||
| 147 | + */ | ||
| 148 | +const handleClose = () => { | ||
| 149 | + visible.value = false | ||
| 150 | + emit('close') | ||
| 151 | +} | ||
| 152 | + | ||
| 153 | +/** | ||
| 154 | + * 组件挂载时的初始化 | ||
| 155 | + */ | ||
| 156 | +onMounted(() => { | ||
| 157 | + // 如果需要在挂载时就设置监听器 | ||
| 158 | + setupMessageListener() | ||
| 159 | +}) | ||
| 160 | + | ||
| 161 | +/** | ||
| 162 | + * 组件卸载时清理 | ||
| 163 | + */ | ||
| 164 | +onUnmounted(() => { | ||
| 165 | + window.removeEventListener('message', handleMessage) | ||
| 166 | +}) | ||
| 167 | + | ||
| 168 | +/** | ||
| 169 | + * 暴露给父组件的方法 | ||
| 170 | + */ | ||
| 171 | +defineExpose({ | ||
| 172 | + close: handleClose, | ||
| 173 | + adjustHeight: adjustIframeHeight | ||
| 174 | +}) | ||
| 175 | +</script> | ||
| 176 | + | ||
| 177 | +<style lang="less" scoped> | ||
| 178 | +.info-entry-container { | ||
| 179 | + width: 100%; | ||
| 180 | + height: 100%; | ||
| 181 | + display: flex; | ||
| 182 | + flex-direction: column; | ||
| 183 | + background-color: #f5f5f5; | ||
| 184 | +} | ||
| 185 | + | ||
| 186 | +.header { | ||
| 187 | + display: flex; | ||
| 188 | + align-items: center; | ||
| 189 | + padding: 12px 16px; | ||
| 190 | + background-color: #fff; | ||
| 191 | + border-bottom: 1px solid #eee; | ||
| 192 | + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); | ||
| 193 | + position: relative; | ||
| 194 | + z-index: 10; | ||
| 195 | +} | ||
| 196 | + | ||
| 197 | +.close-btn { | ||
| 198 | + background: none; | ||
| 199 | + border: none; | ||
| 200 | + padding: 8px; | ||
| 201 | + cursor: pointer; | ||
| 202 | + display: flex; | ||
| 203 | + align-items: center; | ||
| 204 | + justify-content: center; | ||
| 205 | + border-radius: 4px; | ||
| 206 | + transition: background-color 0.2s; | ||
| 207 | + | ||
| 208 | + &:hover { | ||
| 209 | + background-color: #f0f0f0; | ||
| 210 | + } | ||
| 211 | + | ||
| 212 | + &:active { | ||
| 213 | + background-color: #e0e0e0; | ||
| 214 | + } | ||
| 215 | +} | ||
| 216 | + | ||
| 217 | +.title { | ||
| 218 | + flex: 1; | ||
| 219 | + text-align: center; | ||
| 220 | + font-size: 16px; | ||
| 221 | + font-weight: 500; | ||
| 222 | + color: #333; | ||
| 223 | + margin: 0; | ||
| 224 | +} | ||
| 225 | + | ||
| 226 | +.iframe-container { | ||
| 227 | + flex: 1; | ||
| 228 | + overflow: auto; | ||
| 229 | + background-color: #fff; | ||
| 230 | +} | ||
| 231 | + | ||
| 232 | +.form-iframe { | ||
| 233 | + width: 100%; | ||
| 234 | + height: 100%; | ||
| 235 | + border: none; | ||
| 236 | + display: block; | ||
| 237 | +} | ||
| 238 | + | ||
| 239 | +// 响应式设计 | ||
| 240 | +@media (max-width: 768px) { | ||
| 241 | + .header { | ||
| 242 | + padding: 10px 12px; | ||
| 243 | + } | ||
| 244 | + | ||
| 245 | + .title { | ||
| 246 | + font-size: 14px; | ||
| 247 | + } | ||
| 248 | + | ||
| 249 | + .close-btn { | ||
| 250 | + padding: 6px; | ||
| 251 | + } | ||
| 252 | +} | ||
| 253 | +</style> |
| ... | @@ -80,61 +80,15 @@ | ... | @@ -80,61 +80,15 @@ |
| 80 | <div class="px-4 pt-4"> | 80 | <div class="px-4 pt-4"> |
| 81 | <form @submit.prevent="handleSubmit"> | 81 | <form @submit.prevent="handleSubmit"> |
| 82 | <FrostedGlass class="rounded-xl p-4 mb-4"> | 82 | <FrostedGlass class="rounded-xl p-4 mb-4"> |
| 83 | - <h3 class="font-medium mb-3">个人信息</h3> | 83 | + <!-- 预览个人信息iframe --> |
| 84 | - | 84 | + <iframe |
| 85 | - <div class="space-y-3"> | 85 | + v-if="!showInfoEntry" |
| 86 | - <div> | 86 | + :src="iframeInfoSrc" |
| 87 | - <label class="block text-sm text-gray-600 mb-1">姓名 <span class="text-red-500">*</span></label> | 87 | + class="w-full border-0" |
| 88 | - <input | 88 | + ref="infoEntryIframe" |
| 89 | - v-model="formData.receive_name" | 89 | + style="width: 100%; min-height: 600px; height: auto; border: none;" |
| 90 | - type="text" | 90 | + frameborder="0" |
| 91 | - class="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm" | 91 | + ></iframe> |
| 92 | - placeholder="请输入您的姓名" | ||
| 93 | - required | ||
| 94 | - /> | ||
| 95 | - </div> | ||
| 96 | - | ||
| 97 | - <div> | ||
| 98 | - <label class="block text-sm text-gray-600 mb-1">手机号码 <span class="text-red-500">*</span></label> | ||
| 99 | - <input | ||
| 100 | - v-model="formData.receive_phone" | ||
| 101 | - type="tel" | ||
| 102 | - class="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm" | ||
| 103 | - placeholder="请输入您的手机号码" | ||
| 104 | - required | ||
| 105 | - /> | ||
| 106 | - </div> | ||
| 107 | - | ||
| 108 | - <!-- <div> | ||
| 109 | - <label class="block text-sm text-gray-600 mb-1">电子邮箱</label> | ||
| 110 | - <input | ||
| 111 | - v-model="formData.receive_email" | ||
| 112 | - type="email" | ||
| 113 | - class="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm" | ||
| 114 | - placeholder="请输入您的邮箱(选填)" | ||
| 115 | - /> | ||
| 116 | - </div> --> | ||
| 117 | - | ||
| 118 | - <div> | ||
| 119 | - <!-- <label class="block text-sm text-gray-600 mb-1">联系地址 <span class="text-red-500">*</span></label> --> | ||
| 120 | - <label class="block text-sm text-gray-600 mb-1">联系地址</label> | ||
| 121 | - <input | ||
| 122 | - v-model="formData.receive_address" | ||
| 123 | - type="text" | ||
| 124 | - class="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm" | ||
| 125 | - placeholder="请输入您的详细地址" | ||
| 126 | - /> | ||
| 127 | - </div> | ||
| 128 | - | ||
| 129 | - <div> | ||
| 130 | - <label class="block text-sm text-gray-600 mb-1">备注</label> | ||
| 131 | - <textarea | ||
| 132 | - v-model="formData.notes" | ||
| 133 | - class="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm resize-none h-20" | ||
| 134 | - placeholder="有什么需要我们注意的事项?(选填)" | ||
| 135 | - /> | ||
| 136 | - </div> | ||
| 137 | - </div> | ||
| 138 | </FrostedGlass> | 92 | </FrostedGlass> |
| 139 | 93 | ||
| 140 | <FrostedGlass class="rounded-xl p-4 mb-6"> | 94 | <FrostedGlass class="rounded-xl p-4 mb-6"> |
| ... | @@ -276,43 +230,89 @@ | ... | @@ -276,43 +230,89 @@ |
| 276 | </WechatPayment> | 230 | </WechatPayment> |
| 277 | </div> | 231 | </div> |
| 278 | </van-popup> | 232 | </van-popup> |
| 233 | + | ||
| 234 | + <!-- 个人信息录入弹窗 --> | ||
| 235 | + <FormPage | ||
| 236 | + v-model:show="showInfoEntry" | ||
| 237 | + :iframe-src="iframeSrc" | ||
| 238 | + @data-received="handleInfoEntryComplete" | ||
| 239 | + @close="handleInfoEntryClose" | ||
| 240 | + /> | ||
| 279 | </AppLayout> | 241 | </AppLayout> |
| 280 | </template> | 242 | </template> |
| 281 | 243 | ||
| 282 | <script setup> | 244 | <script setup> |
| 283 | -import { ref } from 'vue' | 245 | +import { ref, onMounted, onUnmounted, watch } from 'vue' |
| 284 | import { useRoute, useRouter } from 'vue-router' | 246 | import { useRoute, useRouter } from 'vue-router' |
| 285 | import AppLayout from '@/components/layout/AppLayout.vue' | 247 | import AppLayout from '@/components/layout/AppLayout.vue' |
| 286 | import FrostedGlass from '@/components/ui/FrostedGlass.vue' | 248 | import FrostedGlass from '@/components/ui/FrostedGlass.vue' |
| 287 | import ConfirmDialog from '@/components/ui/ConfirmDialog.vue' | 249 | import ConfirmDialog from '@/components/ui/ConfirmDialog.vue' |
| 288 | import WechatPayment from '@/components/payment/WechatPayment.vue' | 250 | import WechatPayment from '@/components/payment/WechatPayment.vue' |
| 251 | +import FormPage from '@/components/infoEntry/formPage.vue' | ||
| 289 | import { useCart } from '@/contexts/cart' | 252 | import { useCart } from '@/contexts/cart' |
| 290 | import { useTitle } from '@vueuse/core' | 253 | import { useTitle } from '@vueuse/core' |
| 291 | import { getUserInfoAPI } from "@/api/users"; | 254 | import { getUserInfoAPI } from "@/api/users"; |
| 292 | 255 | ||
| 293 | const $route = useRoute() | 256 | const $route = useRoute() |
| 294 | const $router = useRouter() | 257 | const $router = useRouter() |
| 295 | -useTitle($route.meta.title) | 258 | +// useTitle($route.meta.title) |
| 296 | const router = useRouter() | 259 | const router = useRouter() |
| 297 | const { items: cartItems, mode, getTotalPrice, handleCheckout, clearCart, removeFromCart } = useCart() | 260 | const { items: cartItems, mode, getTotalPrice, handleCheckout, clearCart, removeFromCart } = useCart() |
| 298 | 261 | ||
| 299 | // Form state | 262 | // Form state |
| 300 | const formData = ref({ | 263 | const formData = ref({ |
| 301 | - receive_name: '', | ||
| 302 | - receive_phone: '', | ||
| 303 | - receive_email: '', | ||
| 304 | - receive_address: '', | ||
| 305 | - notes: '', | ||
| 306 | pay_type: 'WeChat' | 264 | pay_type: 'WeChat' |
| 307 | }) | 265 | }) |
| 308 | 266 | ||
| 267 | +// 存储当前课程的localStorage键名,用于页面离开时清理 | ||
| 268 | +let currentInfoEntryKey = null | ||
| 309 | 269 | ||
| 310 | onMounted(async () => { | 270 | onMounted(async () => { |
| 311 | const { code, data } = await getUserInfoAPI(); | 271 | const { code, data } = await getUserInfoAPI(); |
| 312 | - if (code) { | 272 | + |
| 313 | - // 获取默认用户信息 | 273 | + // 页面加载时立即检查cartItems中是否有form_url |
| 314 | - formData.value.receive_name = data.user.name ? data.user.name : ''; | 274 | + if (cartItems.value && cartItems.value.length > 0) { |
| 315 | - formData.value.receive_phone = data.user.mobile ? data.user.mobile : ''; | 275 | + const itemWithForm = cartItems.value.find(item => item.form_url) |
| 276 | + | ||
| 277 | + if (itemWithForm && itemWithForm.form_url) { | ||
| 278 | + // 检查用户是否已经录入过个人信息 | ||
| 279 | + const infoEntryKey = `info_entry_completed_${itemWithForm.id}` | ||
| 280 | + currentInfoEntryKey = infoEntryKey // 保存键名用于清理 | ||
| 281 | + const savedInfoData = localStorage.getItem(infoEntryKey) | ||
| 282 | + | ||
| 283 | + console.log('检查个人信息录入状态:', { | ||
| 284 | + courseId: itemWithForm.id, | ||
| 285 | + hasSavedData: !!savedInfoData | ||
| 286 | + }) | ||
| 287 | + | ||
| 288 | + if (!savedInfoData) { | ||
| 289 | + // 只有未录入过信息时才弹出弹窗 | ||
| 290 | + showInfoEntry.value = true | ||
| 291 | + iframeSrc.value = itemWithForm.form_url | ||
| 292 | + console.log('首次录入,显示个人信息录入弹窗') | ||
| 293 | + } else { | ||
| 294 | + // 已录入过信息,从缓存中恢复数据并显示预览 | ||
| 295 | + try { | ||
| 296 | + const infoData = JSON.parse(savedInfoData) | ||
| 297 | + formData.value.customize_id = infoData.customize_id | ||
| 298 | + iframeInfoSrc.value = infoData.form_url + '&page_type=info' + '&data_id=' + infoData.customize_id | ||
| 299 | + console.log('从缓存恢复个人信息数据:', infoData) | ||
| 300 | + } catch (error) { | ||
| 301 | + console.error('解析缓存数据失败:', error) | ||
| 302 | + // 如果解析失败,重新录入 | ||
| 303 | + showInfoEntry.value = true | ||
| 304 | + iframeSrc.value = itemWithForm.form_url | ||
| 305 | + } | ||
| 306 | + } | ||
| 307 | + } | ||
| 308 | + } | ||
| 309 | +}) | ||
| 310 | + | ||
| 311 | +// 页面离开时清理localStorage中的录入状态标记 | ||
| 312 | +onUnmounted(() => { | ||
| 313 | + if (currentInfoEntryKey) { | ||
| 314 | + localStorage.removeItem(currentInfoEntryKey) | ||
| 315 | + console.log('页面离开,清理个人信息录入状态:', currentInfoEntryKey) | ||
| 316 | } | 316 | } |
| 317 | }) | 317 | }) |
| 318 | 318 | ||
| ... | @@ -323,6 +323,27 @@ const orderStatus = ref('') | ... | @@ -323,6 +323,27 @@ const orderStatus = ref('') |
| 323 | const isProcessing = ref(false) | 323 | const isProcessing = ref(false) |
| 324 | const orderComplete = ref(false) | 324 | const orderComplete = ref(false) |
| 325 | 325 | ||
| 326 | +// 个人信息录入相关状态 | ||
| 327 | +const showInfoEntry = ref(false) | ||
| 328 | +// 个人信息录入弹窗的iframe地址 | ||
| 329 | +const iframeSrc = ref(null) | ||
| 330 | +// 个人信息录入弹窗的iframe地址 | ||
| 331 | +const iframeInfoSrc = ref(null) | ||
| 332 | + | ||
| 333 | +/** | ||
| 334 | + * 监听个人信息录入弹窗状态,动态修改页面标题 | ||
| 335 | + */ | ||
| 336 | +watch(showInfoEntry, (newVal) => { | ||
| 337 | + if (newVal) { | ||
| 338 | + // 弹窗打开时,修改标题为"个人信息录入" | ||
| 339 | + // document.title = '个人信息录入' | ||
| 340 | + useTitle('个人信息录入') | ||
| 341 | + } else { | ||
| 342 | + // 弹窗关闭时,修改标题为"结账" | ||
| 343 | + useTitle($route.meta.title) | ||
| 344 | + } | ||
| 345 | +}) | ||
| 346 | + | ||
| 326 | // 确认对话框状态 | 347 | // 确认对话框状态 |
| 327 | const showConfirmDialog = ref(false) | 348 | const showConfirmDialog = ref(false) |
| 328 | const itemToDelete = ref(null) | 349 | const itemToDelete = ref(null) |
| ... | @@ -342,12 +363,6 @@ const handleImageError = (e) => { | ... | @@ -342,12 +363,6 @@ const handleImageError = (e) => { |
| 342 | const handleSubmit = async (e) => { | 363 | const handleSubmit = async (e) => { |
| 343 | try { | 364 | try { |
| 344 | // 表单验证 | 365 | // 表单验证 |
| 345 | - if (!formData.value.receive_name?.trim()) { | ||
| 346 | - throw new Error('请输入姓名') | ||
| 347 | - } | ||
| 348 | - if (!formData.value.receive_phone?.trim()) { | ||
| 349 | - throw new Error('请输入手机号码') | ||
| 350 | - } | ||
| 351 | if (!formData.value.pay_type) { | 366 | if (!formData.value.pay_type) { |
| 352 | throw new Error('请选择支付方式') | 367 | throw new Error('请选择支付方式') |
| 353 | } | 368 | } |
| ... | @@ -378,6 +393,53 @@ const handleSubmit = async (e) => { | ... | @@ -378,6 +393,53 @@ const handleSubmit = async (e) => { |
| 378 | } | 393 | } |
| 379 | } | 394 | } |
| 380 | 395 | ||
| 396 | +// 处理个人信息录入完成 | ||
| 397 | +const handleInfoEntryComplete = async (data) => { | ||
| 398 | + try { | ||
| 399 | + console.log('收到个人信息录入数据:', data) | ||
| 400 | + | ||
| 401 | + // cartItems是数组,需要找到包含form的项目 | ||
| 402 | + const itemWithForm = cartItems.value.find(item => item.form) | ||
| 403 | + const formValue = itemWithForm ? itemWithForm.form : null | ||
| 404 | + | ||
| 405 | + // 把个人信息录入数据赋值给formData | ||
| 406 | + formData.value = { ...formData.value, form: formValue, customize_id: data.id } | ||
| 407 | + | ||
| 408 | + // 标记该课程的个人信息已录入完成,并保存相关数据 | ||
| 409 | + if (itemWithForm && itemWithForm.id) { | ||
| 410 | + const infoEntryKey = `info_entry_completed_${itemWithForm.id}` | ||
| 411 | + const infoData = { | ||
| 412 | + completed: true, | ||
| 413 | + customize_id: data.id, | ||
| 414 | + form_url: itemWithForm.form_url, | ||
| 415 | + timestamp: Date.now() | ||
| 416 | + } | ||
| 417 | + localStorage.setItem(infoEntryKey, JSON.stringify(infoData)) | ||
| 418 | + console.log('个人信息录入完成,已保存状态和数据:', infoEntryKey, infoData) | ||
| 419 | + } | ||
| 420 | + | ||
| 421 | + isProcessing.value = true | ||
| 422 | + } catch (error) { | ||
| 423 | + } finally { | ||
| 424 | + isProcessing.value = false | ||
| 425 | + } | ||
| 426 | +} | ||
| 427 | + | ||
| 428 | +// 处理个人信息录入关闭 | ||
| 429 | +const handleInfoEntryClose = () => { | ||
| 430 | + showInfoEntry.value = false | ||
| 431 | + | ||
| 432 | + // cartItems是数组,需要找到包含form_url的项目 | ||
| 433 | + const itemWithForm = cartItems.value.find(item => item.form_url) | ||
| 434 | + if (itemWithForm && itemWithForm.form_url) { | ||
| 435 | + // 写入地址查询详情 | ||
| 436 | + iframeInfoSrc.value = itemWithForm.form_url + '&page_type=info' + '&data_id=' + formData.value.customize_id | ||
| 437 | + console.log('个人信息录入弹窗关闭,iframe地址:', iframeInfoSrc.value) | ||
| 438 | + } else { | ||
| 439 | + console.log('未找到包含form_url的购物车项目') | ||
| 440 | + } | ||
| 441 | +} | ||
| 442 | + | ||
| 381 | // 处理支付成功 | 443 | // 处理支付成功 |
| 382 | const handlePaymentSuccess = () => { | 444 | const handlePaymentSuccess = () => { |
| 383 | orderComplete.value = true | 445 | orderComplete.value = true | ... | ... |
| ... | @@ -449,13 +449,25 @@ const handlePurchase = () => { | ... | @@ -449,13 +449,25 @@ const handlePurchase = () => { |
| 449 | } | 449 | } |
| 450 | 450 | ||
| 451 | if (course.value) { | 451 | if (course.value) { |
| 452 | - addToCart({ | 452 | + // 调试日志:检查course.value.form_url的值 |
| 453 | + console.log('CourseDetailPage - course.value.form_url:', course.value.form_url) | ||
| 454 | + console.log('CourseDetailPage - 完整course数据:', course.value) | ||
| 455 | + | ||
| 456 | + const cartItem = { | ||
| 453 | id: course.value.id, | 457 | id: course.value.id, |
| 454 | type: 'course', | 458 | type: 'course', |
| 455 | title: course.value.title, | 459 | title: course.value.title, |
| 456 | price: course.value.price, | 460 | price: course.value.price, |
| 457 | - imageUrl: course.value.imageUrl | 461 | + imageUrl: course.value.imageUrl, |
| 458 | - }) | 462 | + form: course.value.form, // 报名关联的表单 |
| 463 | + // 需要把当前页面域名拼写进去 | ||
| 464 | + form_url: window.location.origin + course.value.form_url, // 课程关联的表单的 URL | ||
| 465 | + } | ||
| 466 | + | ||
| 467 | + // 调试日志:检查传递给addToCart的数据 | ||
| 468 | + console.log('CourseDetailPage - 传递给addToCart的数据:', cartItem) | ||
| 469 | + | ||
| 470 | + addToCart(cartItem) | ||
| 459 | proceedToCheckout() | 471 | proceedToCheckout() |
| 460 | } | 472 | } |
| 461 | } | 473 | } |
| ... | @@ -520,6 +532,20 @@ onMounted(async () => { | ... | @@ -520,6 +532,20 @@ onMounted(async () => { |
| 520 | router.push('/courses') | 532 | router.push('/courses') |
| 521 | } | 533 | } |
| 522 | } | 534 | } |
| 535 | + | ||
| 536 | + | ||
| 537 | + // 进入页面时清理所有info_entry_completed_开头的localStorage标记 | ||
| 538 | + const keysToRemove = [] | ||
| 539 | + for (let i = 0; i < localStorage.length; i++) { | ||
| 540 | + const key = localStorage.key(i) | ||
| 541 | + if (key && key.startsWith('info_entry_completed_')) { | ||
| 542 | + keysToRemove.push(key) | ||
| 543 | + } | ||
| 544 | + } | ||
| 545 | + keysToRemove.forEach(key => { | ||
| 546 | + localStorage.removeItem(key) | ||
| 547 | + console.log('清理历史个人信息录入标记:', key) | ||
| 548 | + }) | ||
| 523 | }) | 549 | }) |
| 524 | 550 | ||
| 525 | 551 | ... | ... |
-
Please register or login to post a comment