import { computed, ref } from 'vue' import { showToast, useDidShow } from '@tarojs/taro' import { pinia, useAppStore, useCartStore } from '@/stores' import type { MiniCategory, MiniMenuSection, MiniProductDetail } from '@/shared' import { openRoute } from '@/utils/router' import { createMenuDataActions } from './menu-page/data-actions' import { createMenuDetailActions } from './menu-page/detail-actions' import { getSelectedIds, resolveSelectionError } from './menu-page/selection-helpers' export function useMenuPage () { const appStore = useAppStore(pinia) const cartStore = useCartStore(pinia) const loading = ref(true) const errorMessage = ref('') const categories = ref([]) const sections = ref([]) const detailVisible = ref(false) const cartVisible = ref(false) const activeDetail = ref(null) const currentSkuId = ref('') const detailQuantity = ref(1) const specSelections = ref>({}) const addonSelections = ref>({}) const currentStore = computed(() => appStore.currentStore) const cartCount = computed(() => cartStore.itemCount) const totalAmountText = computed(() => cartStore.totalAmountText) const lineList = computed(() => cartStore.lineList) const currentSku = computed(() => activeDetail.value?.skus.find((sku) => sku.id === currentSkuId.value) || null ) const currentDetailPrice = computed(() => { if (!activeDetail.value) return 0 const basePrice = currentSku.value?.price ?? activeDetail.value.basePrice const addonPrice = activeDetail.value.optionGroups .filter((group) => group.groupType === 'addon') .flatMap((group) => group.options.filter((option) => (addonSelections.value[group.id] || []).includes(option.id)) ) .reduce((amount, option) => amount + option.extraPrice, 0) return (basePrice + addonPrice) * detailQuantity.value }) const displayUnitPrice = computed(() => detailQuantity.value > 0 ? currentDetailPrice.value / detailQuantity.value : 0 ) const currentDetailPriceText = computed(() => currentDetailPrice.value.toFixed(2)) const canAddCurrentDetail = computed(() => { if (!activeDetail.value) return false if (activeDetail.value.skus.length && !currentSkuId.value) return false return !resolveSelectionError({ activeDetail: activeDetail.value, addonSelections: addonSelections.value, currentSkuId: currentSkuId.value, specSelections: specSelections.value }) }) const summaryText = computed(() => { if (!activeDetail.value) return '' const parts: string[] = [] activeDetail.value.optionGroups.forEach((group) => { const selected = getSelectedIds(addonSelections.value, specSelections.value, group.id) group.options .filter((option) => selected.includes(option.id)) .forEach((option) => parts.push(option.name)) }) return parts.join(' · ') || '请选择规格' }) const disabledButtonText = computed(() => resolveSelectionError({ activeDetail: activeDetail.value, addonSelections: addonSelections.value, currentSkuId: currentSkuId.value, specSelections: specSelections.value }) || '请选择规格' ) function isOptionSelected (groupId: string, optionId: string) { return getSelectedIds(addonSelections.value, specSelections.value, groupId).includes(optionId) } function closeDetail () { detailVisible.value = false activeDetail.value = null currentSkuId.value = '' detailQuantity.value = 1 specSelections.value = {} addonSelections.value = {} } const { handleSceneChange, loadMenu } = createMenuDataActions({ appStore, categories, errorMessage, loading, sections }) const { changeDetailQuantity, confirmAddCurrentDetail, handleProductAction, toggleOption } = createMenuDetailActions({ activeDetail, addonSelections, appStore, canAddCurrentDetail, cartStore, closeDetail, currentDetailPrice, currentSkuId, detailQuantity, detailVisible, specSelections }) function goStoreSelect () { void openRoute('/pages/store/select/index') } async function goCheckout () { if (!cartStore.itemCount) { await showToast({ title: '请先加购商品', icon: 'none' }) return } void openRoute('/pages/trade/checkout/index') } useDidShow(() => { void loadMenu() }) return { activeDetail, appStore, canAddCurrentDetail, cartCount, cartStore, cartVisible, categories, changeDetailQuantity, closeDetail, confirmAddCurrentDetail, currentDetailPriceText, currentStore, detailQuantity, detailVisible, disabledButtonText, displayUnitPrice, errorMessage, goCheckout, goStoreSelect, handleProductAction, handleSceneChange, isOptionSelected, lineList, loadMenu, loading, sections, summaryText, toggleOption, totalAmountText } }