增加和平小店商品分类展示
This commit is contained in:
@@ -5,6 +5,7 @@ import { useActivity } from '@/composables/useActivity'
|
||||
import ProductSearch from '@/components/product/ProductSearch.vue'
|
||||
import ProductList from '@/components/product/ProductList.vue'
|
||||
import ProductCard from '@/components/product/ProductCard.vue'
|
||||
import XiaodianTabs from '@/components/product/XiaodianTabs.vue'
|
||||
|
||||
defineProps<{
|
||||
version: string
|
||||
@@ -67,6 +68,8 @@ const onSwitchActivity = async (e: Event) => {
|
||||
|
||||
<ProductSearch />
|
||||
|
||||
<XiaodianTabs v-if="isXiaodian" />
|
||||
|
||||
<ProductCard />
|
||||
|
||||
<div class="product-meta" :class="{ good: productInfo && !productInfo.stale, warn: productInfo?.stale }">
|
||||
|
||||
@@ -4,7 +4,7 @@ import { ref, computed, watch } from 'vue'
|
||||
import { useProducts } from '@/composables/useProducts'
|
||||
import { useActivity } from '@/composables/useActivity'
|
||||
|
||||
const { filteredProducts, selectedProductId, selectProduct, searchQuery } = useProducts()
|
||||
const { filteredProducts, selectedProductId, selectProduct, searchQuery, xiaodianTab } = useProducts()
|
||||
const { currentActivity } = useActivity()
|
||||
const isXiaodian = computed(() => currentActivity.value?.id === 'xiaodian')
|
||||
const priceLabel = computed(() => isXiaodian.value ? '点券' : '积分')
|
||||
@@ -25,6 +25,10 @@ const virtualizer = useVirtualizer(
|
||||
const handleSelect = (commodityId: string, commodityName: string) => {
|
||||
selectProduct(commodityId, commodityName)
|
||||
}
|
||||
|
||||
watch(xiaodianTab, () => {
|
||||
virtualizer.value.scrollToOffset(0)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
<script setup lang="ts">
|
||||
import { useProducts, type XiaodianTab } from '@/composables/useProducts'
|
||||
|
||||
const { xiaodianTab, setXiaodianTab } = useProducts()
|
||||
|
||||
const tabs: Array<{ id: XiaodianTab, label: string }> = [
|
||||
{ id: 'all', label: '全部商品' },
|
||||
{ id: 'discount', label: '特惠专区' },
|
||||
{ id: 'hot', label: '热门抢购' }
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="xiaodian-tabs" role="tablist" aria-label="和平小店商品分类">
|
||||
<button
|
||||
v-for="tab in tabs"
|
||||
:key="tab.id"
|
||||
class="xiaodian-tab"
|
||||
:class="{ active: xiaodianTab === tab.id }"
|
||||
type="button"
|
||||
role="tab"
|
||||
:aria-selected="xiaodianTab === tab.id"
|
||||
@click="setXiaodianTab(tab.id)"
|
||||
>{{ tab.label }}</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.xiaodian-tabs {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
padding: 3px;
|
||||
gap: 2px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--field);
|
||||
}
|
||||
|
||||
.xiaodian-tab {
|
||||
min-width: 0;
|
||||
height: 28px;
|
||||
border: 0;
|
||||
border-radius: 4px;
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
cursor: pointer;
|
||||
font-size: 11px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.xiaodian-tab:hover {
|
||||
color: var(--text-strong);
|
||||
background: var(--surface-2);
|
||||
}
|
||||
|
||||
.xiaodian-tab.active {
|
||||
color: var(--accent);
|
||||
background: var(--accent-soft);
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
@@ -1,10 +1,12 @@
|
||||
import { ref, computed } from 'vue'
|
||||
import { useToast } from './useToast'
|
||||
import { useActivity } from './useActivity'
|
||||
import { LoadProducts } from '@wails/go/app/App'
|
||||
|
||||
export interface Product {
|
||||
commodityId: string
|
||||
commodityName: string
|
||||
category: string
|
||||
score: number
|
||||
count: number
|
||||
pic: string
|
||||
@@ -32,18 +34,25 @@ const selectedProductId = ref<string | null>(null)
|
||||
const selectedProductName = ref('')
|
||||
const searchQuery = ref('')
|
||||
const loading = ref(false)
|
||||
export type XiaodianTab = 'all' | 'discount' | 'hot'
|
||||
const xiaodianTab = ref<XiaodianTab>('all')
|
||||
|
||||
export function useProducts() {
|
||||
const { showToast } = useToast()
|
||||
const { currentActivity } = useActivity()
|
||||
|
||||
const filteredProducts = computed(() => {
|
||||
const keyword = searchQuery.value.toLowerCase().trim()
|
||||
if (!keyword) return products.value
|
||||
return products.value.filter(p =>
|
||||
[p.commodityName, p.commodityId, p.score, p.count].some(
|
||||
return products.value.filter(p => {
|
||||
const matchesTab = currentActivity.value?.id !== 'xiaodian' || xiaodianTab.value === 'all'
|
||||
|| (xiaodianTab.value === 'discount' && p.category === '45')
|
||||
|| (xiaodianTab.value === 'hot' && p.category === '76')
|
||||
if (!matchesTab) return false
|
||||
if (!keyword) return true
|
||||
return [p.commodityName, p.commodityId, p.score, p.count].some(
|
||||
v => String(v ?? '').toLowerCase().includes(keyword)
|
||||
)
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
const selectedProduct = computed(() =>
|
||||
@@ -97,6 +106,10 @@ export function useProducts() {
|
||||
searchQuery.value = ''
|
||||
}
|
||||
|
||||
const setXiaodianTab = (tab: XiaodianTab) => {
|
||||
xiaodianTab.value = tab
|
||||
}
|
||||
|
||||
const restoreSelection = () => {
|
||||
const savedId = localStorage.getItem('selProd')
|
||||
const savedName = localStorage.getItem('selProdName')
|
||||
@@ -115,11 +128,13 @@ export function useProducts() {
|
||||
searchQuery,
|
||||
filteredProducts,
|
||||
loading,
|
||||
xiaodianTab,
|
||||
loadProducts,
|
||||
selectProduct,
|
||||
clearSelection,
|
||||
setSearch,
|
||||
clearSearch,
|
||||
setXiaodianTab,
|
||||
restoreSelection
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user