refactor: 拆分小程序 vue 结构
This commit is contained in:
177
src/pages/menu/composables/useMenuPage.ts
Normal file
177
src/pages/menu/composables/useMenuPage.ts
Normal file
@@ -0,0 +1,177 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user