178 lines
5.0 KiB
TypeScript
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
|
|
}
|
|
}
|