| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- import { defineStore } from 'pinia'
- import { computed, ref } from 'vue'
- import { TOKEN_KEY } from '@/config/api'
- import { request } from '@/utils/request'
- function upsertCartItemLocal(list, incoming) {
- const next = [...list]
- const byId = next.findIndex((i) => i.id === incoming.id)
- if (byId >= 0) {
- next[byId] = incoming
- return next
- }
- const byProduct = next.findIndex((i) => i.productId === incoming.productId)
- if (byProduct >= 0) {
- next[byProduct] = incoming
- return next
- }
- next.unshift(incoming)
- return next
- }
- function summaryFromItems(list) {
- const lineCount = list.length
- const totalQuantity = list.reduce((sum, item) => sum + (Number(item.quantity) || 0), 0)
- const totalAmount = list.reduce((sum, item) => sum + (Number(item.amount) || 0), 0)
- return { lineCount, totalQuantity, totalAmount }
- }
- export const useCartStore = defineStore('cart', () => {
- const items = ref([])
- const summary = ref({ lineCount: 0, totalQuantity: 0, totalAmount: 0 })
- const isLoading = ref(false)
- const addingProductIds = ref(new Set())
- let summarySyncTimer = null
- const totalAmount = computed(() => summary.value.totalAmount)
- const totalCount = computed(() => summary.value.totalQuantity)
- const isEmpty = computed(() => summary.value.lineCount === 0)
- const itemsByCategory = computed(() => {
- const grouped = {}
- items.value.forEach((item) => {
- if (!grouped[item.categoryName]) grouped[item.categoryName] = []
- grouped[item.categoryName].push(item)
- })
- return grouped
- })
- async function fetchCartSummary() {
- const token = uni.getStorageSync(TOKEN_KEY)
- if (!token) return
- try {
- const res = await request({ url: '/mini/client/cart/summary', method: 'GET' })
- const result = res.data
- if (result.code === 200 && result.data) {
- const d = result.data
- summary.value = {
- lineCount: Number(d.lineCount) || 0,
- totalQuantity: Number(d.totalQuantity) || 0,
- totalAmount: Number(d.totalAmount) || 0
- }
- }
- } catch (error) {
- console.error('获取购物车汇总失败:', error)
- }
- }
- function scheduleSummarySync(delay = 500) {
- if (summarySyncTimer) clearTimeout(summarySyncTimer)
- summarySyncTimer = setTimeout(() => {
- void fetchCartSummary()
- summarySyncTimer = null
- }, delay)
- }
- async function fetchCart() {
- const token = uni.getStorageSync(TOKEN_KEY)
- if (!token) return
- isLoading.value = true
- try {
- const res = await request({ url: '/mini/client/cart', method: 'GET' })
- const result = res.data
- if (result.code === 200) {
- const list = (result.data && result.data.list) || []
- items.value = list
- summary.value = summaryFromItems(list)
- }
- } catch (error) {
- console.error('获取购物车失败:', error)
- } finally {
- isLoading.value = false
- }
- }
- async function addToCart(product, quantity = 1) {
- const token = uni.getStorageSync(TOKEN_KEY)
- if (!token) {
- uni.showToast({ title: '请先登录', icon: 'none' })
- return false
- }
- const productId = String((product && product.id) || '')
- if (!productId) {
- uni.showToast({ title: '商品信息无效', icon: 'none' })
- return false
- }
- if (addingProductIds.value.has(productId)) return false
- addingProductIds.value.add(productId)
- try {
- const res = await request({
- url: '/mini/client/cart',
- method: 'POST',
- data: { productId, quantity }
- })
- const result = res.data
- if (result.code === 200) {
- if (result.data) {
- items.value = upsertCartItemLocal(items.value, result.data)
- summary.value = summaryFromItems(items.value)
- }
- scheduleSummarySync()
- uni.showToast({ title: '已加入购物车', icon: 'success' })
- return true
- }
- uni.showToast({ title: result.message || '添加失败', icon: 'none' })
- return false
- } catch (error) {
- uni.showToast({ title: (error && error.message) || '添加失败', icon: 'none' })
- return false
- } finally {
- addingProductIds.value.delete(productId)
- }
- }
- async function updateQuantity(cartId, quantity) {
- const token = uni.getStorageSync(TOKEN_KEY)
- if (!token) return false
- try {
- const res = await request({
- url: `/mini/client/cart/${cartId}`,
- method: 'PUT',
- data: { quantity }
- })
- const result = res.data
- if (result.code === 200 && result.data) {
- const d = result.data
- if (Array.isArray(d.list)) {
- items.value = d.list
- summary.value = summaryFromItems(d.list)
- } else {
- items.value = upsertCartItemLocal(items.value, result.data)
- summary.value = summaryFromItems(items.value)
- }
- scheduleSummarySync()
- return true
- }
- return result.code === 200
- } catch {
- return false
- }
- }
- async function removeItem(cartId) {
- const token = uni.getStorageSync(TOKEN_KEY)
- if (!token) return false
- try {
- const res = await request({ url: `/mini/client/cart/${cartId}`, method: 'DELETE' })
- const result = res.data
- if (result.code === 200) {
- items.value = items.value.filter((i) => i.id !== cartId)
- summary.value = summaryFromItems(items.value)
- scheduleSummarySync()
- return true
- }
- return false
- } catch {
- return false
- }
- }
- async function clearCart() {
- const token = uni.getStorageSync(TOKEN_KEY)
- if (!token) return false
- try {
- const res = await request({ url: '/mini/client/cart', method: 'DELETE' })
- const result = res.data
- if (result.code === 200) {
- items.value = []
- summary.value = { lineCount: 0, totalQuantity: 0, totalAmount: 0 }
- scheduleSummarySync()
- return true
- }
- return false
- } catch {
- return false
- }
- }
- async function batchRemove(cartIds) {
- const token = uni.getStorageSync(TOKEN_KEY)
- if (!token) return false
- try {
- const res = await request({
- url: '/mini/client/cart/batch',
- method: 'DELETE',
- data: { cartIds }
- })
- const result = res.data
- if (result.code === 200) {
- items.value = items.value.filter((i) => !cartIds.includes(i.id))
- summary.value = summaryFromItems(items.value)
- scheduleSummarySync()
- return true
- }
- return false
- } catch {
- return false
- }
- }
- return {
- items,
- summary,
- isLoading,
- totalAmount,
- totalCount,
- isEmpty,
- itemsByCategory,
- fetchCart,
- fetchCartSummary,
- addToCart,
- updateQuantity,
- removeItem,
- clearCart,
- batchRemove
- }
- })
|