Files
TakeoutSaaS.C-Side-Mini-Pro…/src/pages/menu/composables/useMenuPage.ts

178 lines
5.0 KiB
TypeScript

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<MiniCategory[]>([])
const sections = ref<MiniMenuSection[]>([])
const detailVisible = ref(false)
const cartVisible = ref(false)
const activeDetail = ref<MiniProductDetail | null>(null)
const currentSkuId = ref('')
const detailQuantity = ref(1)
const specSelections = ref<Record<string, string[]>>({})
const addonSelections = ref<Record<string, string[]>>({})
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
}
}