hookehuyr

refactor(plan): 提取计划书提交回调逻辑为 composable

- 创建 usePlanSubmit composable 统一处理弹窗关闭、状态清空、导航跳转
- 重构 index、search、product-detail、product-center 页面使用 composable
- 移除重复的 handlePlanSubmit 函数实现(~100 行)

🤖 Generated with assistance from Claude Code
/**
* 计划书提交后处理 Composable
*
* @description 统一处理计划书提交后的弹窗关闭、状态清空、导航跳转逻辑
* @author Claude Code
* @example
* const { handlePlanSubmit } = usePlanSubmit({
* getPopupState: () => showPlanPopup.value,
* setPopupState: (state) => { showPlanPopup.value = state }
* })
*
* // 使用
* await handlePlanSubmit(result, {
* beforeNav: async () => { console.log('导航前') },
* afterNav: async () => { console.log('导航后') }
* })
*/
import { nextTick } from 'vue'
import Taro from '@tarojs/taro'
import { useGo } from '@/hooks/useGo'
/**
* 计划书提交后处理 Hook
*
* @param {Object} options - 配置选项
* @param {Function} options.getPopupState - 获取弹窗状态(必需)
* @param {Function} options.setPopupState - 设置弹窗状态(必需)
* @param {Function} options.clearSelectedProduct - 清空选中产品(可选)
* @param {boolean} options.useGoUtil - 是否使用 go() 工具(默认 true)
* @param {string} options.pageName - 页面名称(用于日志,默认 'Page')
* @returns {Object} 包含 handlePlanSubmit 方法的对象
*/
export function usePlanSubmit(options = {}) {
const {
getPopupState,
setPopupState,
clearSelectedProduct,
useGoUtil = true,
pageName = 'Page'
} = options
/**
* 处理计划书提交结果
*
* @param {Object} result - 提交结果
* @param {boolean} result.success - 是否成功
* @param {string} result.message - 错误信息(失败时)
* @param {number} result.order_id - 订单 ID(成功时)
* @param {number} result.product_id - 产品 ID(成功时)
* @param {string} result.form_sn - 表单标识(成功时)
* @param {Object} callbacks - 回调函数
* @param {Function} callbacks.beforeNav - 导航前回调
* @param {Function} callbacks.afterNav - 导航后回调
*/
const handlePlanSubmit = async (result, callbacks = {}) => {
console.log(`[${pageName}] 计划书提交结果:`, result)
// 1. 关闭弹窗
setPopupState(false)
// 2. 等待 DOM 更新
await nextTick()
// 3. 清空选中产品(如果提供)
if (clearSelectedProduct) {
clearSelectedProduct()
}
// 4. 构建结果页面参数
const params = {
success: result.success ? 'true' : 'false'
}
// 失败时传递错误信息
if (!result.success && result.message) {
params.message = result.message
}
console.log(`[${pageName}] 跳转到结果页面,参数:`, params)
// 5. 执行导航前回调
if (callbacks.beforeNav) {
await callbacks.beforeNav(result)
}
// 6. 跳转到结果页面
if (useGoUtil) {
// 使用 go() 工具函数
const go = useGo()
go('/pages/plan-submit-result/index', params)
} else {
// 直接使用 Taro API
Taro.navigateTo({
url: `/pages/plan-submit-result/index?${new URLSearchParams(params).toString()}`
})
}
// 7. 执行导航后回调
if (callbacks.afterNav) {
await callbacks.afterNav()
}
}
return {
handlePlanSubmit
}
}
......@@ -172,6 +172,7 @@ import MaterialCard from '@/components/cards/MaterialCard.vue';
import { listAPI } from '@/api/get_product';
import { weekHotAPI } from '@/api/file';
import { homeIconAPI } from '@/api/home';
import { usePlanSubmit } from '@/composables/usePlanSubmit';
// User Store
......@@ -220,40 +221,14 @@ const openPlanPopup = (productId) => {
showPlanPopup.value = true;
};
/**
* 处理计划书提交
*
* @description 接收 PlanFormContainer 的提交结果事件
* PlanFormContainer 已经调用过 API 并处理了 toast 提示
* 这里根据成功/失败状态跳转到结果页面
* @param {Object} result - 提交结果
* @param {boolean} result.success - 是否成功
* @param {number} result.order_id - 订单 ID
* @param {number} result.product_id - 产品 ID
* @param {string} result.form_sn - 表单标识
*/
const handlePlanSubmit = async (result) => {
console.log('[Home Page] 计划书提交结果:', result);
// 关闭弹窗
showPlanPopup.value = false;
await nextTick();
selectedProduct.value = null;
// 构建结果页面参数
const params = {
success: result.success ? 'true' : 'false'
};
// 失败时传递后端返回的错误信息
if (!result.success && result.message) {
params.message = result.message;
}
go('/pages/plan-submit-result/index', params);
};
// 使用 composable 统一处理计划书提交后逻辑
const { handlePlanSubmit } = usePlanSubmit({
getPopupState: () => showPlanPopup.value,
setPopupState: (state) => { showPlanPopup.value = state },
clearSelectedProduct: () => { selectedProduct.value = null },
useGoUtil: true,
pageName: 'Home Page'
})
const handlePlanClose = async () => {
showPlanPopup.value = false;
......
......@@ -139,7 +139,7 @@
</template>
<script setup>
import { ref, computed, nextTick } from 'vue'
import { ref, computed } from 'vue'
import Taro, { useLoad } from '@tarojs/taro'
import { useGo } from '@/hooks/useGo'
import { useListItemClick, ListType } from '@/composables/useListItemClick'
......@@ -149,6 +149,7 @@ import SearchBar from '@/components/forms/SearchBar.vue'
import PlanFormContainer from '@/components/plan/PlanFormContainer.vue'
import { listAPI } from '@/api/get_product'
import { mockProductListAPI } from '@/utils/mockData'
import { usePlanSubmit } from '@/composables/usePlanSubmit'
// ⚠️ MOCK 数据开关 - 开发环境使用 mock 数据,生产环境使用真实 API
// const USE_MOCK_DATA = process.env.NODE_ENV === 'development'
......@@ -498,42 +499,13 @@ const openPlanPopup = (product) => {
showPlanPopup.value = true
}
/**
* 处理计划书提交
*
* @description 接收 PlanFormContainer 的提交结果事件
* PlanFormContainer 已经调用过 API 并处理了 toast 提示
* 这里根据成功/失败状态跳转到结果页面
* @param {Object} result - 提交结果
* @param {boolean} result.success - 是否成功
* @param {number} result.order_id - 订单 ID
* @param {number} result.product_id - 产品 ID
* @param {string} result.form_sn - 表单标识
*/
const handlePlanSubmit = async (result) => {
console.log('[Product Center] 计划书提交结果:', result)
// 关闭弹窗
showPlanPopup.value = false
await nextTick()
// 构建结果页面参数
const params = {
success: result.success ? 'true' : 'false'
}
// 失败时传递后端返回的错误信息
if (!result.success && result.message) {
params.message = result.message
}
console.log('[Product Center] 跳转到结果页面,参数:', params)
Taro.navigateTo({
url: `/pages/plan-submit-result/index?${new URLSearchParams(params).toString()}`
})
}
// 使用 composable 统一处理计划书提交后逻辑
const { handlePlanSubmit } = usePlanSubmit({
getPopupState: () => showPlanPopup.value,
setPopupState: (state) => { showPlanPopup.value = state },
useGoUtil: false,
pageName: 'Product Center'
})
</script>
<style lang="less">
......
......@@ -125,7 +125,7 @@
</template>
<script setup>
import { ref, nextTick } from 'vue'
import { ref } from 'vue'
import NavHeader from '@/components/navigation/NavHeader.vue'
import IconFont from '@/components/icons/IconFont.vue'
import PlanFormContainer from '@/components/plan/PlanFormContainer.vue'
......@@ -133,6 +133,7 @@ import { useFileOperation } from '@/composables/useFileOperation'
import Taro, { useLoad } from '@tarojs/taro'
import { getDocumentIcon, getDocumentLabel } from '@/utils/documentIcons'
import { detailAPI } from '@/api/get_product'
import { usePlanSubmit } from '@/composables/usePlanSubmit'
const { viewFile } = useFileOperation()
......@@ -216,42 +217,13 @@ const openPlanPopup = () => {
showPlanPopup.value = true
}
/**
* 处理计划书提交
*
* @description 接收 PlanFormContainer 的提交结果事件
* PlanFormContainer 已经调用过 API 并处理了 toast 提示
* 这里根据成功/失败状态跳转到结果页面
* @param {Object} result - 提交结果
* @param {boolean} result.success - 是否成功
* @param {number} result.order_id - 订单 ID(成功时)
* @param {number} result.product_id - 产品 ID
* @param {string} result.form_sn - 表单标识
*/
const handlePlanSubmit = async (result) => {
console.log('[Product Detail] 计划书提交结果:', result)
// 关闭弹窗
showPlanPopup.value = false
await nextTick()
// 构建结果页面参数
const params = {
success: result.success ? 'true' : 'false'
}
// 失败时传递后端返回的错误信息
if (!result.success && result.message) {
params.message = result.message
}
console.log('[Product Detail] 跳转到结果页面,参数:', params)
Taro.navigateTo({
url: `/pages/plan-submit-result/index?${new URLSearchParams(params).toString()}`
})
}
// 使用 composable 统一处理计划书提交后逻辑
const { handlePlanSubmit } = usePlanSubmit({
getPopupState: () => showPlanPopup.value,
setPopupState: (state) => { showPlanPopup.value = state },
useGoUtil: false,
pageName: 'Product Detail'
})
useLoad((options) => {
console.log('产品详情页参数:', options)
......
......@@ -125,7 +125,7 @@
</template>
<script setup>
import { ref, computed, nextTick } from 'vue'
import { ref, computed } from 'vue'
import Taro from '@tarojs/taro'
import { useGo } from '@/hooks/useGo'
import LoadMoreList from '@/components/list/LoadMoreList'
......@@ -137,6 +137,7 @@ import MaterialCard from '@/components/cards/MaterialCard.vue'
import PlanFormContainer from '@/components/plan/PlanFormContainer.vue'
import { searchAPI } from '@/api/search'
import { mockSearchAPI } from '@/utils/mockData'
import { usePlanSubmit } from '@/composables/usePlanSubmit'
// ⚠️ MOCK 数据开关 - 开发环境使用 mock 数据,生产环境使用真实 API
const USE_MOCK_DATA = process.env.NODE_ENV === 'development'
......@@ -457,50 +458,14 @@ const openPlanPopup = (productId) => {
showPlanPopup.value = true
}
/**
* 处理计划书提交
*
* @description 接收 PlanFormContainer 的提交结果事件
* PlanFormContainer 已经调用过 API 并处理了 toast 提示
* 这里根据成功/失败状态跳转到结果页面
* @param {Object} result - 提交结果
* @param {boolean} result.success - 是否成功
* @param {number} result.order_id - 订单 ID
* @param {number} result.product_id - 产品 ID
* @param {string} result.form_sn - 表单标识
*/
const handlePlanSubmit = async (result) => {
console.log('[Search Page] 计划书提交结果:', result)
// 关闭弹窗
showPlanPopup.value = false
await nextTick()
selectedProduct.value = null
// 构建结果页面参数
const params = {
success: result.success ? 'true' : 'false'
}
// 失败时传递后端返回的错误信息
if (!result.success && result.message) {
params.message = result.message
}
console.log('[Search Page] 跳转到结果页面,参数:', params)
go('/pages/plan-submit-result/index', params)
}
const handlePlanClose = async () => {
showPlanPopup.value = false
await nextTick()
selectedProduct.value = null
}
// 使用 composable 统一处理计划书提交后逻辑
const { handlePlanSubmit } = usePlanSubmit({
getPopupState: () => showPlanPopup.value,
setPopupState: (state) => { showPlanPopup.value = state },
clearSelectedProduct: () => { selectedProduct.value = null },
useGoUtil: true,
pageName: 'Search Page'
})
/**
* 处理收藏状态改变
......