282 lines
8.0 KiB
Vue
282 lines
8.0 KiB
Vue
<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>
|
||
|
||
<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>
|