Files
pj_h5_cloud/src/pages/tabbar/onlineShop.vue
T
2025-07-17 14:54:18 +08:00

282 lines
8.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<crud-layout bg="/static/page/blue-bg.png">
<z-paging
ref="pageRef"
height="100%"
:fixed="false"
v-model="pageHook.list"
:default-page-size="10"
safe-area-inset-bottom
:loading-more-enabled="true"
:show-scrollbar="false"
@query="query"
:auto-clean-list-when-reload="false"
:auto-scroll-to-top-when-reload="false"
@scroll="pageHook.scroll"
:auto="false"
>
<template #top>
<view class="flex justify-between items-center my-1 z-1000">
<tm-text font-size="40" color="#0779FD" class="font-bold">欢迎选购</tm-text>
<view class="flex justify-center items-center" @tap="changeShop">
<image class="size-40rpx" src="@/static/page/address-blue.svg" />
<tm-text font-size="32" color="#0779FD">{{ state.curMerchant.name }}</tm-text>
<image class="size-30rpx ml-1" src="@/static/page/arrow-down-s-fill.svg" />
</view>
</view>
<view class="w-full flex items-center">
<tm-input
class="flex-1"
v-model="state.params.keyword"
type="text"
:height="66"
:minHeight="66"
:fontSize="28"
:showClear="true"
:focus="false"
placeholder="请输入商品名称"
style="border: 2rpx solid #0779fd; border-radius: 14rpx"
:focus-highlight="false"
color="#ECF4F9"
>
<template v-slot:rightIcon>
<tm-button class="mr-1 py-3" size="xs" @click="searchProduct">搜索</tm-button>
</template>
</tm-input>
<tm-badge bg-color="red" :offset="[8, 4]" :label="cartStore.totCount">
<view class="flex-col-center size-80rpx" @tap="doCart">
<view class="color-#0094ff! iconfont icon-biaoqianlanicon_gouwuche-xuanzhong" />
<view class="c-#0094ff text-20rpx">购物车</view>
</view>
</tm-badge>
</view>
<scroll-view scroll-x class="whitespace-nowrap my-2">
<tm-tag
class="mr-2"
size="s"
:skin="state.params.categoryId == v.id ? 'normal' : 'outlined'"
v-for="(v, i) in state.classifyList"
:key="i"
@tap="doClassify(v.id)"
>
{{ v.name }}
</tm-tag>
</scroll-view>
</template>
<Waterfall
:list="pageHook.list"
:gutter="10"
:breakpoints="{
1800: { rowPerView: 4 },
1400: { rowPerView: 3 },
975: { rowPerView: 2 },
}"
:hasAroundGutter="false"
backgroundColor="#ffffff00"
:crossOrigin="false"
:animationCancel="true"
>
<template #default="{ item, url, index }">
<view class="card" @click="toDetail(item)">
<LazyImg class="rounded-2" :url="filePath(item.picUrl)" />
<view class="p-16rpx flex-col">
<view class="sub-text-32 show-line">{{ item.productName }}</view>
<view class="flex-row justify-between items-center">
<view class="flex items-center">
<view class="second-text-32 c-red!">¥ {{ storePrice(item.minPrice).toFixed(2) }}</view>
<!-- <view v-if="parseFloat(item.promotionPrice) != 0" class="ml-10rpx second-text-30 line-through">
¥{{ hooks.useMoney(item.retailPrice) || 0 }}
</view> -->
</view>
<view class="second-text-26">已售:{{ item.salesCount || 0 }}</view>
</view>
</view>
</view>
</template>
</Waterfall>
<tm-drawer
title="切换超市"
:showClose="false"
:showFooter="true"
size="70%"
placement="bottom"
v-model:show="state.showDrawer"
:duration="100"
zIndex="1200"
>
<tm-radio-group v-model="state.curMerchantRadioId" direction="column">
<view
v-for="(item, index) in state.merchantList"
:key="index"
class="w-full flex items-center p-2 rounded-3"
:class="[state.curMerchantRadioId == item.id ? 'bg-#e8e8e8' : '']"
>
<tm-radio class="w-full h-full px-2" :value="item.id">
<template v-slot:label="checked">
<view class="flex items-center">
<image class="w-130rpx h-130rpx rounded-2" :src="filePath(item.logoPic)" mode="aspectFill" />
<view class="ml-2 flex-1 flex-col">
<tm-text font-size="30">{{ item.name }}</tm-text>
<view class="second-text-26">地址:{{ item.addressDes }}</view>
<view class="second-text-26">手机:{{ item.phone }}</view>
</view>
</view>
</template>
</tm-radio>
</view>
</tm-radio-group>
<template #footer>
<view class="px-20rpx pt-2 flex justify-between">
<tm-button skin="thin" block @click="state.showDrawer = false">取消</tm-button>
&nbsp;&nbsp;
<tm-button block @click="confirmRadioMerchant">确定</tm-button>
</view>
</template>
</tm-drawer>
</z-paging>
</crud-layout>
</template>
<script setup lang="ts">
import { onLoad, onShow } from "@dcloudio/uni-app"
import { ref, reactive } from "vue"
import { LazyImg, Waterfall } from "vue-waterfall-plugin-next"
import "vue-waterfall-plugin-next/dist/style.css"
import { isEmpty } from "radash"
import { filePath } from "@@/utils/file"
import { merchantApi, onlineShopApi } from "@@/api"
import { hooks, router } from "@@/index"
import { useCartStore } from "@/sheep/stores/cart"
import { storePrice } from "@/sheep/utils/formatMoney"
const cartStore = useCartStore()
const state = reactive<any>({
params: {
merchantId: "",
categoryId: "",
size: 10,
keyword: "",
},
merchantList: [],
curMerchant: {},
classifyList: [],
showDrawer: false,
curMerchantRadioId: "",
})
const pageRef = ref<any>(null)
onLoad(async () => {
const app = getApp()
app._initTabbar()
await getAllMerchant()
await getClassify()
await cartStore.getShopCart()
})
onShow(() => {
// pageRef.value && pageRef.value.reload(false)
})
// 获取所有商户
const getAllMerchant = async () => {
uni.showLoading({ title: "加载中...", mask: true })
try {
const { code, data }: any = await merchantApi.page({ current: 1, pagesize: 9999999, type: "3" })
if (code == 0) {
state.merchantList = data.records
if (!isEmpty(state.merchantList)) {
state.curMerchant = state.merchantList[0]
state.params.merchantId = state.curMerchant.id
cartStore.saveShopMerchantId(state.curMerchant.id)
return
}
state.curMerchant = {}
}
} catch (error) {
state.merchantList = []
} finally {
uni.hideLoading()
}
}
const treeToList = <T extends { children?: T[] }>(tree: T[], result: T[] = []): T[] => {
for (const node of tree) {
result.push(node)
if (node?.children?.length) {
treeToList(node.children, result)
}
}
return result
}
// 获取分类
const getClassify = async () => {
if (state.curMerchant.id) {
const { data } = await onlineShopApi.getSpuCategory()
state.classifyList = treeToList(data) ?? []
state.classifyList.unshift({ id: "", name: "全部分类" })
if (!isEmpty(state.classifyList)) {
state.params.categoryId = state.classifyList[0].id
pageRef.value && pageRef.value.reload(true)
}
}
}
// 切换超市
const changeShop = () => {
state.curMerchantRadioId = state.curMerchant.id || ""
state.showDrawer = true
}
// 确定切换超市
const confirmRadioMerchant = async () => {
state.curMerchant = state.merchantList.find((item: any) => item.id == state.curMerchantRadioId)
state.showDrawer = false
state.params.merchantId = state.curMerchant.id
cartStore.saveShopMerchantId(state.curMerchant.id)
await cartStore.getShopCart()
pageRef.value && pageRef.value.reload(true)
}
// 点击搜索
const searchProduct = () => {
state.params.categoryId = ""
pageRef.value && pageRef.value.reload(true)
}
// 切换分类
const doClassify = async (categoryId: string) => {
if (state.params.categoryId == categoryId) return
state.params.categoryId = categoryId
pageRef.value && pageRef.value.reload(true)
}
const pageHook = hooks.usePage(pageRef, onlineShopApi.getSpuList, null, "data.records")
const query = (page: number, pagesize: number) => {
pageHook.startPage(page, pagesize, false, state.params)
}
const toDetail = async (v: any) => {
const isLogin = await hooks.useCheckLogin()
if (isLogin) {
router.jump("/pages/shop/product-detail", { id: v.id })
}
}
const doCart = async () => {
const isLogin = await hooks.useCheckLogin()
if (isLogin) {
router.jump("/pages/shop/cart")
}
}
</script>