refactor(plan): 提取计划书提交回调逻辑为 composable
- 创建 usePlanSubmit composable 统一处理弹窗关闭、状态清空、导航跳转 - 重构 index、search、product-detail、product-center 页面使用 composable - 移除重复的 handlePlanSubmit 函数实现(~100 行) 🤖 Generated with assistance from Claude Code
Showing
5 changed files
with
144 additions
and
153 deletions
src/composables/usePlanSubmit.js
0 → 100644
| 1 | +/** | ||
| 2 | + * 计划书提交后处理 Composable | ||
| 3 | + * | ||
| 4 | + * @description 统一处理计划书提交后的弹窗关闭、状态清空、导航跳转逻辑 | ||
| 5 | + * @author Claude Code | ||
| 6 | + * @example | ||
| 7 | + * const { handlePlanSubmit } = usePlanSubmit({ | ||
| 8 | + * getPopupState: () => showPlanPopup.value, | ||
| 9 | + * setPopupState: (state) => { showPlanPopup.value = state } | ||
| 10 | + * }) | ||
| 11 | + * | ||
| 12 | + * // 使用 | ||
| 13 | + * await handlePlanSubmit(result, { | ||
| 14 | + * beforeNav: async () => { console.log('导航前') }, | ||
| 15 | + * afterNav: async () => { console.log('导航后') } | ||
| 16 | + * }) | ||
| 17 | + */ | ||
| 18 | +import { nextTick } from 'vue' | ||
| 19 | +import Taro from '@tarojs/taro' | ||
| 20 | +import { useGo } from '@/hooks/useGo' | ||
| 21 | + | ||
| 22 | +/** | ||
| 23 | + * 计划书提交后处理 Hook | ||
| 24 | + * | ||
| 25 | + * @param {Object} options - 配置选项 | ||
| 26 | + * @param {Function} options.getPopupState - 获取弹窗状态(必需) | ||
| 27 | + * @param {Function} options.setPopupState - 设置弹窗状态(必需) | ||
| 28 | + * @param {Function} options.clearSelectedProduct - 清空选中产品(可选) | ||
| 29 | + * @param {boolean} options.useGoUtil - 是否使用 go() 工具(默认 true) | ||
| 30 | + * @param {string} options.pageName - 页面名称(用于日志,默认 'Page') | ||
| 31 | + * @returns {Object} 包含 handlePlanSubmit 方法的对象 | ||
| 32 | + */ | ||
| 33 | +export function usePlanSubmit(options = {}) { | ||
| 34 | + const { | ||
| 35 | + getPopupState, | ||
| 36 | + setPopupState, | ||
| 37 | + clearSelectedProduct, | ||
| 38 | + useGoUtil = true, | ||
| 39 | + pageName = 'Page' | ||
| 40 | + } = options | ||
| 41 | + | ||
| 42 | + /** | ||
| 43 | + * 处理计划书提交结果 | ||
| 44 | + * | ||
| 45 | + * @param {Object} result - 提交结果 | ||
| 46 | + * @param {boolean} result.success - 是否成功 | ||
| 47 | + * @param {string} result.message - 错误信息(失败时) | ||
| 48 | + * @param {number} result.order_id - 订单 ID(成功时) | ||
| 49 | + * @param {number} result.product_id - 产品 ID(成功时) | ||
| 50 | + * @param {string} result.form_sn - 表单标识(成功时) | ||
| 51 | + * @param {Object} callbacks - 回调函数 | ||
| 52 | + * @param {Function} callbacks.beforeNav - 导航前回调 | ||
| 53 | + * @param {Function} callbacks.afterNav - 导航后回调 | ||
| 54 | + */ | ||
| 55 | + const handlePlanSubmit = async (result, callbacks = {}) => { | ||
| 56 | + console.log(`[${pageName}] 计划书提交结果:`, result) | ||
| 57 | + | ||
| 58 | + // 1. 关闭弹窗 | ||
| 59 | + setPopupState(false) | ||
| 60 | + | ||
| 61 | + // 2. 等待 DOM 更新 | ||
| 62 | + await nextTick() | ||
| 63 | + | ||
| 64 | + // 3. 清空选中产品(如果提供) | ||
| 65 | + if (clearSelectedProduct) { | ||
| 66 | + clearSelectedProduct() | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + // 4. 构建结果页面参数 | ||
| 70 | + const params = { | ||
| 71 | + success: result.success ? 'true' : 'false' | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + // 失败时传递错误信息 | ||
| 75 | + if (!result.success && result.message) { | ||
| 76 | + params.message = result.message | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + console.log(`[${pageName}] 跳转到结果页面,参数:`, params) | ||
| 80 | + | ||
| 81 | + // 5. 执行导航前回调 | ||
| 82 | + if (callbacks.beforeNav) { | ||
| 83 | + await callbacks.beforeNav(result) | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + // 6. 跳转到结果页面 | ||
| 87 | + if (useGoUtil) { | ||
| 88 | + // 使用 go() 工具函数 | ||
| 89 | + const go = useGo() | ||
| 90 | + go('/pages/plan-submit-result/index', params) | ||
| 91 | + } else { | ||
| 92 | + // 直接使用 Taro API | ||
| 93 | + Taro.navigateTo({ | ||
| 94 | + url: `/pages/plan-submit-result/index?${new URLSearchParams(params).toString()}` | ||
| 95 | + }) | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + // 7. 执行导航后回调 | ||
| 99 | + if (callbacks.afterNav) { | ||
| 100 | + await callbacks.afterNav() | ||
| 101 | + } | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + return { | ||
| 105 | + handlePlanSubmit | ||
| 106 | + } | ||
| 107 | +} |
| ... | @@ -172,6 +172,7 @@ import MaterialCard from '@/components/cards/MaterialCard.vue'; | ... | @@ -172,6 +172,7 @@ import MaterialCard from '@/components/cards/MaterialCard.vue'; |
| 172 | import { listAPI } from '@/api/get_product'; | 172 | import { listAPI } from '@/api/get_product'; |
| 173 | import { weekHotAPI } from '@/api/file'; | 173 | import { weekHotAPI } from '@/api/file'; |
| 174 | import { homeIconAPI } from '@/api/home'; | 174 | import { homeIconAPI } from '@/api/home'; |
| 175 | +import { usePlanSubmit } from '@/composables/usePlanSubmit'; | ||
| 175 | 176 | ||
| 176 | 177 | ||
| 177 | // User Store | 178 | // User Store |
| ... | @@ -220,40 +221,14 @@ const openPlanPopup = (productId) => { | ... | @@ -220,40 +221,14 @@ const openPlanPopup = (productId) => { |
| 220 | showPlanPopup.value = true; | 221 | showPlanPopup.value = true; |
| 221 | }; | 222 | }; |
| 222 | 223 | ||
| 223 | -/** | 224 | +// 使用 composable 统一处理计划书提交后逻辑 |
| 224 | - * 处理计划书提交 | 225 | +const { handlePlanSubmit } = usePlanSubmit({ |
| 225 | - * | 226 | + getPopupState: () => showPlanPopup.value, |
| 226 | - * @description 接收 PlanFormContainer 的提交结果事件 | 227 | + setPopupState: (state) => { showPlanPopup.value = state }, |
| 227 | - * PlanFormContainer 已经调用过 API 并处理了 toast 提示 | 228 | + clearSelectedProduct: () => { selectedProduct.value = null }, |
| 228 | - * 这里根据成功/失败状态跳转到结果页面 | 229 | + useGoUtil: true, |
| 229 | - * @param {Object} result - 提交结果 | 230 | + pageName: 'Home Page' |
| 230 | - * @param {boolean} result.success - 是否成功 | 231 | +}) |
| 231 | - * @param {number} result.order_id - 订单 ID | ||
| 232 | - * @param {number} result.product_id - 产品 ID | ||
| 233 | - * @param {string} result.form_sn - 表单标识 | ||
| 234 | - */ | ||
| 235 | -const handlePlanSubmit = async (result) => { | ||
| 236 | - console.log('[Home Page] 计划书提交结果:', result); | ||
| 237 | - | ||
| 238 | - // 关闭弹窗 | ||
| 239 | - showPlanPopup.value = false; | ||
| 240 | - | ||
| 241 | - await nextTick(); | ||
| 242 | - | ||
| 243 | - selectedProduct.value = null; | ||
| 244 | - | ||
| 245 | - // 构建结果页面参数 | ||
| 246 | - const params = { | ||
| 247 | - success: result.success ? 'true' : 'false' | ||
| 248 | - }; | ||
| 249 | - | ||
| 250 | - // 失败时传递后端返回的错误信息 | ||
| 251 | - if (!result.success && result.message) { | ||
| 252 | - params.message = result.message; | ||
| 253 | - } | ||
| 254 | - | ||
| 255 | - go('/pages/plan-submit-result/index', params); | ||
| 256 | -}; | ||
| 257 | 232 | ||
| 258 | const handlePlanClose = async () => { | 233 | const handlePlanClose = async () => { |
| 259 | showPlanPopup.value = false; | 234 | showPlanPopup.value = false; | ... | ... |
| ... | @@ -139,7 +139,7 @@ | ... | @@ -139,7 +139,7 @@ |
| 139 | </template> | 139 | </template> |
| 140 | 140 | ||
| 141 | <script setup> | 141 | <script setup> |
| 142 | -import { ref, computed, nextTick } from 'vue' | 142 | +import { ref, computed } from 'vue' |
| 143 | import Taro, { useLoad } from '@tarojs/taro' | 143 | import Taro, { useLoad } from '@tarojs/taro' |
| 144 | import { useGo } from '@/hooks/useGo' | 144 | import { useGo } from '@/hooks/useGo' |
| 145 | import { useListItemClick, ListType } from '@/composables/useListItemClick' | 145 | import { useListItemClick, ListType } from '@/composables/useListItemClick' |
| ... | @@ -149,6 +149,7 @@ import SearchBar from '@/components/forms/SearchBar.vue' | ... | @@ -149,6 +149,7 @@ import SearchBar from '@/components/forms/SearchBar.vue' |
| 149 | import PlanFormContainer from '@/components/plan/PlanFormContainer.vue' | 149 | import PlanFormContainer from '@/components/plan/PlanFormContainer.vue' |
| 150 | import { listAPI } from '@/api/get_product' | 150 | import { listAPI } from '@/api/get_product' |
| 151 | import { mockProductListAPI } from '@/utils/mockData' | 151 | import { mockProductListAPI } from '@/utils/mockData' |
| 152 | +import { usePlanSubmit } from '@/composables/usePlanSubmit' | ||
| 152 | 153 | ||
| 153 | // ⚠️ MOCK 数据开关 - 开发环境使用 mock 数据,生产环境使用真实 API | 154 | // ⚠️ MOCK 数据开关 - 开发环境使用 mock 数据,生产环境使用真实 API |
| 154 | // const USE_MOCK_DATA = process.env.NODE_ENV === 'development' | 155 | // const USE_MOCK_DATA = process.env.NODE_ENV === 'development' |
| ... | @@ -498,42 +499,13 @@ const openPlanPopup = (product) => { | ... | @@ -498,42 +499,13 @@ const openPlanPopup = (product) => { |
| 498 | showPlanPopup.value = true | 499 | showPlanPopup.value = true |
| 499 | } | 500 | } |
| 500 | 501 | ||
| 501 | -/** | 502 | +// 使用 composable 统一处理计划书提交后逻辑 |
| 502 | - * 处理计划书提交 | 503 | +const { handlePlanSubmit } = usePlanSubmit({ |
| 503 | - * | 504 | + getPopupState: () => showPlanPopup.value, |
| 504 | - * @description 接收 PlanFormContainer 的提交结果事件 | 505 | + setPopupState: (state) => { showPlanPopup.value = state }, |
| 505 | - * PlanFormContainer 已经调用过 API 并处理了 toast 提示 | 506 | + useGoUtil: false, |
| 506 | - * 这里根据成功/失败状态跳转到结果页面 | 507 | + pageName: 'Product Center' |
| 507 | - * @param {Object} result - 提交结果 | 508 | +}) |
| 508 | - * @param {boolean} result.success - 是否成功 | ||
| 509 | - * @param {number} result.order_id - 订单 ID | ||
| 510 | - * @param {number} result.product_id - 产品 ID | ||
| 511 | - * @param {string} result.form_sn - 表单标识 | ||
| 512 | - */ | ||
| 513 | -const handlePlanSubmit = async (result) => { | ||
| 514 | - console.log('[Product Center] 计划书提交结果:', result) | ||
| 515 | - | ||
| 516 | - // 关闭弹窗 | ||
| 517 | - showPlanPopup.value = false | ||
| 518 | - | ||
| 519 | - await nextTick() | ||
| 520 | - | ||
| 521 | - // 构建结果页面参数 | ||
| 522 | - const params = { | ||
| 523 | - success: result.success ? 'true' : 'false' | ||
| 524 | - } | ||
| 525 | - | ||
| 526 | - // 失败时传递后端返回的错误信息 | ||
| 527 | - if (!result.success && result.message) { | ||
| 528 | - params.message = result.message | ||
| 529 | - } | ||
| 530 | - | ||
| 531 | - console.log('[Product Center] 跳转到结果页面,参数:', params) | ||
| 532 | - | ||
| 533 | - Taro.navigateTo({ | ||
| 534 | - url: `/pages/plan-submit-result/index?${new URLSearchParams(params).toString()}` | ||
| 535 | - }) | ||
| 536 | -} | ||
| 537 | </script> | 509 | </script> |
| 538 | 510 | ||
| 539 | <style lang="less"> | 511 | <style lang="less"> | ... | ... |
| ... | @@ -125,7 +125,7 @@ | ... | @@ -125,7 +125,7 @@ |
| 125 | </template> | 125 | </template> |
| 126 | 126 | ||
| 127 | <script setup> | 127 | <script setup> |
| 128 | -import { ref, nextTick } from 'vue' | 128 | +import { ref } from 'vue' |
| 129 | import NavHeader from '@/components/navigation/NavHeader.vue' | 129 | import NavHeader from '@/components/navigation/NavHeader.vue' |
| 130 | import IconFont from '@/components/icons/IconFont.vue' | 130 | import IconFont from '@/components/icons/IconFont.vue' |
| 131 | import PlanFormContainer from '@/components/plan/PlanFormContainer.vue' | 131 | import PlanFormContainer from '@/components/plan/PlanFormContainer.vue' |
| ... | @@ -133,6 +133,7 @@ import { useFileOperation } from '@/composables/useFileOperation' | ... | @@ -133,6 +133,7 @@ import { useFileOperation } from '@/composables/useFileOperation' |
| 133 | import Taro, { useLoad } from '@tarojs/taro' | 133 | import Taro, { useLoad } from '@tarojs/taro' |
| 134 | import { getDocumentIcon, getDocumentLabel } from '@/utils/documentIcons' | 134 | import { getDocumentIcon, getDocumentLabel } from '@/utils/documentIcons' |
| 135 | import { detailAPI } from '@/api/get_product' | 135 | import { detailAPI } from '@/api/get_product' |
| 136 | +import { usePlanSubmit } from '@/composables/usePlanSubmit' | ||
| 136 | 137 | ||
| 137 | const { viewFile } = useFileOperation() | 138 | const { viewFile } = useFileOperation() |
| 138 | 139 | ||
| ... | @@ -216,42 +217,13 @@ const openPlanPopup = () => { | ... | @@ -216,42 +217,13 @@ const openPlanPopup = () => { |
| 216 | showPlanPopup.value = true | 217 | showPlanPopup.value = true |
| 217 | } | 218 | } |
| 218 | 219 | ||
| 219 | -/** | 220 | +// 使用 composable 统一处理计划书提交后逻辑 |
| 220 | - * 处理计划书提交 | 221 | +const { handlePlanSubmit } = usePlanSubmit({ |
| 221 | - * | 222 | + getPopupState: () => showPlanPopup.value, |
| 222 | - * @description 接收 PlanFormContainer 的提交结果事件 | 223 | + setPopupState: (state) => { showPlanPopup.value = state }, |
| 223 | - * PlanFormContainer 已经调用过 API 并处理了 toast 提示 | 224 | + useGoUtil: false, |
| 224 | - * 这里根据成功/失败状态跳转到结果页面 | 225 | + pageName: 'Product Detail' |
| 225 | - * @param {Object} result - 提交结果 | 226 | +}) |
| 226 | - * @param {boolean} result.success - 是否成功 | ||
| 227 | - * @param {number} result.order_id - 订单 ID(成功时) | ||
| 228 | - * @param {number} result.product_id - 产品 ID | ||
| 229 | - * @param {string} result.form_sn - 表单标识 | ||
| 230 | - */ | ||
| 231 | -const handlePlanSubmit = async (result) => { | ||
| 232 | - console.log('[Product Detail] 计划书提交结果:', result) | ||
| 233 | - | ||
| 234 | - // 关闭弹窗 | ||
| 235 | - showPlanPopup.value = false | ||
| 236 | - | ||
| 237 | - await nextTick() | ||
| 238 | - | ||
| 239 | - // 构建结果页面参数 | ||
| 240 | - const params = { | ||
| 241 | - success: result.success ? 'true' : 'false' | ||
| 242 | - } | ||
| 243 | - | ||
| 244 | - // 失败时传递后端返回的错误信息 | ||
| 245 | - if (!result.success && result.message) { | ||
| 246 | - params.message = result.message | ||
| 247 | - } | ||
| 248 | - | ||
| 249 | - console.log('[Product Detail] 跳转到结果页面,参数:', params) | ||
| 250 | - | ||
| 251 | - Taro.navigateTo({ | ||
| 252 | - url: `/pages/plan-submit-result/index?${new URLSearchParams(params).toString()}` | ||
| 253 | - }) | ||
| 254 | -} | ||
| 255 | 227 | ||
| 256 | useLoad((options) => { | 228 | useLoad((options) => { |
| 257 | console.log('产品详情页参数:', options) | 229 | console.log('产品详情页参数:', options) | ... | ... |
| ... | @@ -125,7 +125,7 @@ | ... | @@ -125,7 +125,7 @@ |
| 125 | </template> | 125 | </template> |
| 126 | 126 | ||
| 127 | <script setup> | 127 | <script setup> |
| 128 | -import { ref, computed, nextTick } from 'vue' | 128 | +import { ref, computed } from 'vue' |
| 129 | import Taro from '@tarojs/taro' | 129 | import Taro from '@tarojs/taro' |
| 130 | import { useGo } from '@/hooks/useGo' | 130 | import { useGo } from '@/hooks/useGo' |
| 131 | import LoadMoreList from '@/components/list/LoadMoreList' | 131 | import LoadMoreList from '@/components/list/LoadMoreList' |
| ... | @@ -137,6 +137,7 @@ import MaterialCard from '@/components/cards/MaterialCard.vue' | ... | @@ -137,6 +137,7 @@ import MaterialCard from '@/components/cards/MaterialCard.vue' |
| 137 | import PlanFormContainer from '@/components/plan/PlanFormContainer.vue' | 137 | import PlanFormContainer from '@/components/plan/PlanFormContainer.vue' |
| 138 | import { searchAPI } from '@/api/search' | 138 | import { searchAPI } from '@/api/search' |
| 139 | import { mockSearchAPI } from '@/utils/mockData' | 139 | import { mockSearchAPI } from '@/utils/mockData' |
| 140 | +import { usePlanSubmit } from '@/composables/usePlanSubmit' | ||
| 140 | 141 | ||
| 141 | // ⚠️ MOCK 数据开关 - 开发环境使用 mock 数据,生产环境使用真实 API | 142 | // ⚠️ MOCK 数据开关 - 开发环境使用 mock 数据,生产环境使用真实 API |
| 142 | const USE_MOCK_DATA = process.env.NODE_ENV === 'development' | 143 | const USE_MOCK_DATA = process.env.NODE_ENV === 'development' |
| ... | @@ -457,50 +458,14 @@ const openPlanPopup = (productId) => { | ... | @@ -457,50 +458,14 @@ const openPlanPopup = (productId) => { |
| 457 | showPlanPopup.value = true | 458 | showPlanPopup.value = true |
| 458 | } | 459 | } |
| 459 | 460 | ||
| 460 | -/** | 461 | +// 使用 composable 统一处理计划书提交后逻辑 |
| 461 | - * 处理计划书提交 | 462 | +const { handlePlanSubmit } = usePlanSubmit({ |
| 462 | - * | 463 | + getPopupState: () => showPlanPopup.value, |
| 463 | - * @description 接收 PlanFormContainer 的提交结果事件 | 464 | + setPopupState: (state) => { showPlanPopup.value = state }, |
| 464 | - * PlanFormContainer 已经调用过 API 并处理了 toast 提示 | 465 | + clearSelectedProduct: () => { selectedProduct.value = null }, |
| 465 | - * 这里根据成功/失败状态跳转到结果页面 | 466 | + useGoUtil: true, |
| 466 | - * @param {Object} result - 提交结果 | 467 | + pageName: 'Search Page' |
| 467 | - * @param {boolean} result.success - 是否成功 | 468 | +}) |
| 468 | - * @param {number} result.order_id - 订单 ID | ||
| 469 | - * @param {number} result.product_id - 产品 ID | ||
| 470 | - * @param {string} result.form_sn - 表单标识 | ||
| 471 | - */ | ||
| 472 | -const handlePlanSubmit = async (result) => { | ||
| 473 | - console.log('[Search Page] 计划书提交结果:', result) | ||
| 474 | - | ||
| 475 | - // 关闭弹窗 | ||
| 476 | - showPlanPopup.value = false | ||
| 477 | - | ||
| 478 | - await nextTick() | ||
| 479 | - | ||
| 480 | - selectedProduct.value = null | ||
| 481 | - | ||
| 482 | - // 构建结果页面参数 | ||
| 483 | - const params = { | ||
| 484 | - success: result.success ? 'true' : 'false' | ||
| 485 | - } | ||
| 486 | - | ||
| 487 | - // 失败时传递后端返回的错误信息 | ||
| 488 | - if (!result.success && result.message) { | ||
| 489 | - params.message = result.message | ||
| 490 | - } | ||
| 491 | - | ||
| 492 | - console.log('[Search Page] 跳转到结果页面,参数:', params) | ||
| 493 | - | ||
| 494 | - go('/pages/plan-submit-result/index', params) | ||
| 495 | -} | ||
| 496 | - | ||
| 497 | -const handlePlanClose = async () => { | ||
| 498 | - showPlanPopup.value = false | ||
| 499 | - | ||
| 500 | - await nextTick() | ||
| 501 | - | ||
| 502 | - selectedProduct.value = null | ||
| 503 | -} | ||
| 504 | 469 | ||
| 505 | /** | 470 | /** |
| 506 | * 处理收藏状态改变 | 471 | * 处理收藏状态改变 | ... | ... |
-
Please register or login to post a comment