线上商城改版

This commit is contained in:
weiwei committed 2025-06-18 11:57:00 +08:00
1 parent b94b5bf911
commit 4a19ae2856
4 files changed
+307 -65

No files matched your search

+1 -1
View File
@@ -102,7 +102,7 @@ const tabbar: TabbarItem[] = [
},
]
// 设置tabbar项目
// 设置tabbar
const setTabbarItem = (index: number, item: TabbarItem, visible: boolean) => {
uni.setTabBarItem({
index,
+4 -3
View File
@@ -145,10 +145,11 @@ const doProduct = (v: any) => {
:hasAroundGutter="false"
backgroundColor="#ffffff00"
:crossOrigin="false"
:animationDuration="100"
:animationDuration="0"
:posDuration="0"
>
<template #default="{ item, url, index }">
<div class="card">
<view class="card">
<LazyImg class="rounded-2" :url="item.picUrl" />
<view class="p-x-15rpx p-y-25rpx flex items-center justify-between">
<view class="sub-text-28 show-line">{{ item.name }}</view>
@@ -162,7 +163,7 @@ const doProduct = (v: any) => {
<!-- <view class="second-text-24">{{ hooks.useFormatNum("销量", "", item.salesCount) }}</view> -->
<!-- </view> -->
</view>
</div>
</view>
</template>
</Waterfall>
+82
View File
@@ -0,0 +1,82 @@
<script setup lang="ts">
import { ref, reactive } from "vue"
import { onLoad, onShow } from "@dcloudio/uni-app"
import { merchantApi } from "@@/api"
import { hooks, router } from "@@/index"
import { filePath } from "@@/utils/file"
const pageRef = ref<any>(null)
const state = reactive<any>({
pa: {
pagesize: 10,
type: "3",
},
})
const pageHook = hooks.usePage(pageRef, merchantApi.page, null, "data.records")
const query = (page: number, pagesize: number) => {
pageHook.startPage(page, pagesize, false, state.pa)
}
onLoad(() => {
const app = getApp()
app._initTabbar()
})
onShow(() => {
pageRef.value && pageRef.value.reload(false)
})
const toDetail = async (v: any) => {
const isLogin = await hooks.useCheckLogin()
if (isLogin) {
router.jump("/pages/shop/detail", { id: v.id })
}
}
</script>
<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"
>
<view class="h-20rpx" />
<view class="flex-row card p-20rpx m-b-20rpx" v-for="(v, i) in pageHook.list" :key="i" @tap="toDetail(v)">
<image class="w-180rpx h-180rpx rounded-12rpx" :src="filePath(v.logoPic)" mode="aspectFill" />
<view class="flex-1 flex-col m-l-20rpx">
<view class="flex-row items-center justify-between">
<view class="flex-row-center sub-text-34">{{ v.name }}</view>
<tm-tag size="s">{{ v.deptName }}</tm-tag>
</view>
<view class="m-t-10rpx">
<view v-if="v.phone" class="flex items-center">
<image class="w-24rpx h-24rpx" src="@/static/page/phone.svg" />
<view class="second-text-28 ml-1">{{ v.phone }}</view>
</view>
<view class="second-text-24">
<view class="second-text-28">{{ v.jobTime == ",," ? "" : "营业时间:" }}</view>
<view>{{ v.jobTime?.split(",")[0] ? "早:" + v.jobTime?.split(",")[0] : "" }}</view>
<view>{{ v.jobTime?.split(",")[1] ? "中:" + v.jobTime?.split(",")[1] : "" }}</view>
<view>{{ v.jobTime?.split(",")[2] ? "晚:" + v.jobTime?.split(",")[2] : "" }}</view>
</view>
<view v-if="v.addressDes" class="second-text-28">
<image class="w-24rpx h-24rpx" src="@/static/page/address.svg" />
<text class="ml-1">地址:</text>
<text class="m-l-10rpx">{{ v.addressDes }}</text>
</view>
</view>
</view>
</view>
</z-paging>
</crud-layout>
</template>
+220 -61
View File
@@ -1,39 +1,3 @@
<script setup lang="ts">
import { ref, reactive } from "vue"
import { onLoad, onShow } from "@dcloudio/uni-app"
import { merchantApi } from "@@/api"
import { hooks, router } from "@@/index"
import { filePath } from "@@/utils/file"
const pageRef = ref<any>(null)
const state = reactive<any>({
pa: {
pagesize: 10,
type: "3",
},
})
const pageHook = hooks.usePage(pageRef, merchantApi.page, null, "data.records")
const query = (page: number, pagesize: number) => {
pageHook.startPage(page, pagesize, false, state.pa)
}
onLoad(() => {
const app = getApp()
app._initTabbar()
})
onShow(() => {
pageRef.value && pageRef.value.reload(false)
})
const toDetail = async (v: any) => {
const isLogin = await hooks.useCheckLogin()
if (isLogin) {
router.jump("/pages/shop/detail", { id: v.id })
}
}
</script>
<template>
<crud-layout bg="/static/page/blue-bg.png">
<z-paging
@@ -49,34 +13,229 @@ const toDetail = async (v: any) => {
:auto-clean-list-when-reload="false"
:auto-scroll-to-top-when-reload="false"
@scroll="pageHook.scroll"
:auto="false"
>
<view class="h-20rpx" />
<view class="flex-row card p-20rpx m-b-20rpx" v-for="(v, i) in pageHook.list" :key="i" @tap="toDetail(v)">
<image class="w-180rpx h-180rpx rounded-12rpx" :src="filePath(v.logoPic)" mode="aspectFill" />
<view class="flex-1 flex-col m-l-20rpx">
<view class="flex-row items-center justify-between">
<view class="flex-row-center sub-text-34">{{ v.name }}</view>
<tm-tag size="s">{{ v.deptName }}</tm-tag>
</view>
<view class="m-t-10rpx">
<view v-if="v.phone" class="flex items-center">
<image class="w-24rpx h-24rpx" src="@/static/page/phone.svg" />
<view class="second-text-28 ml-1">{{ v.phone }}</view>
</view>
<view class="second-text-24">
<view class="second-text-28">{{ v.jobTime == ",," ? "" : "营业时间:" }}</view>
<view>{{ v.jobTime?.split(",")[0] ? "早:" + v.jobTime?.split(",")[0] : "" }}</view>
<view>{{ v.jobTime?.split(",")[1] ? "中:" + v.jobTime?.split(",")[1] : "" }}</view>
<view>{{ v.jobTime?.split(",")[2] ? "晚:" + v.jobTime?.split(",")[2] : "" }}</view>
</view>
<view v-if="v.addressDes" class="second-text-28">
<image class="w-24rpx h-24rpx" src="@/static/page/address.svg" />
<text class="ml-1">地址:</text>
<text class="m-l-10rpx">{{ v.addressDes }}</text>
</view>
<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-baseline" @tap="changeShop">
<tm-icon name="map-pin-2-line" color="#0779FD" />
<tm-text font-size="32" color="#0779FD">{{ state.curMerchant.name }}</tm-text>
<tm-icon name="arrow-down-s-fill" color="#0779FD" size="40" />
</view>
</view>
</view>
<tm-input
v-model="state.params.productName"
type="text"
:height="66"
:minHeight="66"
:fontSize="28"
:showClear="true"
:focus="true"
placeholder="请输入商品名称"
style="border: 2px solid #0779fd; border-radius: 14rpx"
:focus-highlight="false"
>
<template v-slot:rightIcon>
<tm-button class="mr-1 py-3" size="xs" @click="searchProduct">搜索</tm-button>
</template>
</tm-input>
<scroll-view scroll-x class="whitespace-nowrap my-2">
<tm-tag
class="mx-1"
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!">
¥{{ parseFloat(item.promotionPrice) != 0 ? hooks.useMoney(item.promotionPrice) : hooks.useMoney(item.retailPrice) }}
</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 }}</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"
: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" :src="filePath(item.logoPic)" />
<view class="ml-2 flex-1 flex-col">
<tm-text font-size="30">{{ item.name }}</tm-text>
<tm-text font-size="28">地址:{{ item.addressDes }}</tm-text>
<tm-text font-size="28">手机:{{ item.phone }}</tm-text>
</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, shopApi } from "@@/api"
import { hooks, router } from "@@/index"
const state = reactive<any>({
params: {
merchantId: "",
categoryId: "",
size: 10,
productName: "",
},
merchantList: [],
curMerchant: {},
classifyList: [],
curMerchantRadioId: "",
showDrawer: false,
})
const pageRef = ref<any>(null)
onLoad(async () => {
const app = getApp()
app._initTabbar()
await getAllMerchant()
await getClassify()
})
onShow(() => {
// pageRef.value && pageRef.value.reload(false)
})
// 获取所有商户
const getAllMerchant = async () => {
uni.showLoading({ title: "加载中...", mask: true })
try {
const res: any = await merchantApi.page({ current: 1, pagesize: 9999999, type: "3" })
if (res.code == 0) {
state.merchantList = res.data.records
if (!isEmpty(state.merchantList)) {
state.curMerchant = state.merchantList[0]
return
}
state.curMerchant = {}
}
} catch (error) {
state.merchantList = []
} finally {
uni.hideLoading()
}
}
// 获取分类
const getClassify = async () => {
if (state.curMerchant.id) {
const { data } = await shopApi.getSupermarketSpuCategory({ merchantId: state.curMerchant.id })
state.classifyList = data ?? []
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
await getClassify()
}
// 切换分类
const doClassify = async (id: string) => {
if (state.params.categoryId == id) return
state.params.categoryId = id
pageRef.value && pageRef.value.reload(true)
}
// 点击搜索
const searchProduct = () => {
pageRef.value && pageRef.value.reload(true)
}
const pageHook = hooks.usePage(pageRef, shopApi.getSupermarketSpuList, null, "data.records")
const query = (page: number, pagesize: number) => {
pageHook.startPage(page, pagesize, false, { ...state.params, merchantId: state.curMerchant.id })
}
const toDetail = async (v: any) => {
const isLogin = await hooks.useCheckLogin()
if (isLogin) {
router.jump("/pages/shop/product-detail", { id: v.id })
}
}
</script>