359 lines
8.1 KiB
Vue
359 lines
8.1 KiB
Vue
<template>
|
|
<view>
|
|
<!-- 幻灯片 -->
|
|
<nut-swiper
|
|
:init-page="0"
|
|
:pagination-visible="true"
|
|
pagination-color="red"
|
|
auto-play="3000"
|
|
>
|
|
<nut-swiper-item v-for="(itm, idx) in swiperList" :key="idx">
|
|
<img
|
|
style="width: 100%; height: 100%"
|
|
:src="itm"
|
|
:alt="idx.toString()"
|
|
/>
|
|
</nut-swiper-item>
|
|
</nut-swiper>
|
|
<!-- 商家信息 -->
|
|
<view class="infoBox">
|
|
<view class="title">{{ mer_info.name }}</view>
|
|
<view class="bom">
|
|
<view class="left">
|
|
<view>{{ mer_info.address || "暂无商家地址" }}</view>
|
|
<view class="sub"
|
|
>距你{{
|
|
calculateDistance(
|
|
userLocalNum.t,
|
|
userLocalNum.l,
|
|
Number(mer_info.lat),
|
|
Number(mer_info.lon)
|
|
)
|
|
}}
|
|
</view>
|
|
</view>
|
|
<view class="right">
|
|
<view @click="clickMap">
|
|
<Locationg3 color="red" size="25" />
|
|
<view>导航</view>
|
|
</view>
|
|
<view @click="clickPhone">
|
|
<Find color="red" size="25" />
|
|
<view>电话</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<!-- 商品列表 -->
|
|
<view class="good-class" v-if="class_list.length > 0">
|
|
<nut-tabs
|
|
v-model="value"
|
|
title-scroll
|
|
direction="vertical"
|
|
title-gutter="5"
|
|
animated-time="0"
|
|
name="tabName"
|
|
>
|
|
<nut-tab-pane
|
|
v-for="(itm, index) in good_list"
|
|
:key="index"
|
|
:title="itm.name"
|
|
:pane-key="index"
|
|
>
|
|
<view v-if="itm.Goods.length > 0">
|
|
<view class="list" v-for="(item, index) in itm.Goods" :key="index">
|
|
<view class="item" @click.stop="toGoodDetails(item.gid, 1)">
|
|
<image :src="item.cover" lazy-load />
|
|
<view class="right">
|
|
<view class="name">{{ item.name }}</view>
|
|
<view class="stock">剩余:{{ item.stock }}</view>
|
|
<view class="bom">
|
|
<view>
|
|
<view class="price">
|
|
<text style="font-size: 15px">{{ item.number }}元</text>
|
|
</view>
|
|
<view class="price">
|
|
<text style="font-size: 15px"
|
|
>{{ item.exchange }}积分</text
|
|
>
|
|
</view>
|
|
</view>
|
|
<nut-button
|
|
size="mini"
|
|
type="primary"
|
|
@click.stop="add_cart(item)"
|
|
>
|
|
<template #icon>
|
|
<Cart2 />
|
|
</template>
|
|
</nut-button>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<nut-empty v-else description="该分类暂无商品"></nut-empty>
|
|
<view style="height: 180rpx"></view>
|
|
</nut-tab-pane>
|
|
</nut-tabs>
|
|
</view>
|
|
<nut-empty v-else description="该商家暂无商品"></nut-empty>
|
|
<!-- 购物车 -->
|
|
<cart ref="cartRef" :mer-info="mer_info" @update-cart="updateCartNum" />
|
|
</view>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import Taro from "@tarojs/taro";
|
|
import { Find, Locationg3 } from "@nutui/icons-vue-taro";
|
|
import { Ref, ref } from "vue";
|
|
import { calculateDistance } from "@/utils";
|
|
import { getGoodList, getMerCategory } from "@/api/goods";
|
|
import Cart from "@/components/Cart.vue";
|
|
import { Cart2 } from "@nutui/icons-vue-taro";
|
|
|
|
const swiperList = ref([]);
|
|
|
|
const mer_info = ref<any>({});
|
|
|
|
const value = ref("0");
|
|
|
|
const userLocalNum = ref({
|
|
l: 0,
|
|
t: 0,
|
|
});
|
|
|
|
Taro.useLoad(async () => {
|
|
Taro.getLocation({
|
|
type: "wgs84",
|
|
success: (res) => {
|
|
userLocalNum.value.l = res.longitude;
|
|
userLocalNum.value.t = res.latitude;
|
|
},
|
|
});
|
|
mer_info.value = Taro.getStorageSync("mer_info");
|
|
Taro.setNavigationBarTitle({
|
|
title: mer_info.value.name,
|
|
});
|
|
swiperList.value = mer_info.value.img.split(",");
|
|
await get_class_list();
|
|
await cartRef.value.get_cart_list();
|
|
});
|
|
|
|
const clickPhone = () => {
|
|
Taro.makePhoneCall({
|
|
phoneNumber: mer_info.value.mobile,
|
|
});
|
|
};
|
|
|
|
const clickMap = () => {
|
|
Taro.openLocation({
|
|
name: mer_info.value.name,
|
|
address: mer_info.value.address,
|
|
latitude: Number(mer_info.value.lat),
|
|
longitude: Number(mer_info.value.lon),
|
|
scale: 18,
|
|
});
|
|
};
|
|
|
|
const class_list = ref<
|
|
Array<{
|
|
ID?: number;
|
|
name?: string;
|
|
}>
|
|
>([]);
|
|
const get_class_list = async () => {
|
|
const res = await getMerCategory({
|
|
Bid: mer_info.value.bid,
|
|
});
|
|
class_list.value = res.data.data || [];
|
|
await get_good_list(class_list.value[0].ID as number);
|
|
};
|
|
|
|
// const clickTab = (val: any) => {
|
|
// get_good_list(class_list.value[val.paneKey].ID as number);
|
|
// };
|
|
|
|
interface goodList {
|
|
ID: number;
|
|
name: string;
|
|
bid: string;
|
|
Goods: GoodsType[];
|
|
}
|
|
|
|
interface GoodsType {
|
|
gid: string;
|
|
cover: string;
|
|
name: string;
|
|
number: number;
|
|
stock: number;
|
|
cartNum: number;
|
|
exchange: number;
|
|
}
|
|
|
|
interface CartItems {
|
|
bid: string;
|
|
gid: string;
|
|
number: number;
|
|
price: number;
|
|
cover: string;
|
|
name: string;
|
|
exchange: number;
|
|
}
|
|
|
|
const good_list = ref<goodList[]>([]);
|
|
const get_good_list = async (id: number) => {
|
|
Taro.showLoading({
|
|
title: "加载中",
|
|
mask: true,
|
|
});
|
|
const res = await getGoodList({
|
|
bid: mer_info.value.bid,
|
|
goods_class_id: id,
|
|
status: 1,
|
|
state: 1,
|
|
});
|
|
good_list.value = res.data.data || [];
|
|
Taro.hideLoading();
|
|
};
|
|
|
|
const toGoodDetails = (id: string, type: number) => {
|
|
Taro.navigateTo({
|
|
url: `/pages/goods/goods_detail/index?gid=${id}&type=${type}`,
|
|
});
|
|
};
|
|
|
|
const cartRef = ref(null) as Ref;
|
|
|
|
const add_cart = (item: GoodsType) => {
|
|
const num = item.cartNum ? Number(item.cartNum) + 1 : 1;
|
|
cartRef.value.add_cart(item, num);
|
|
};
|
|
|
|
const updateCartNum = (cartItems: CartItems[]) => {
|
|
if (cartItems.length > 0) {
|
|
good_list.value.forEach((category: goodList) => {
|
|
category.Goods.forEach((good: GoodsType) => {
|
|
cartItems.forEach((cartItem: CartItems) => {
|
|
if (good.gid === cartItem.gid) {
|
|
good.cartNum = cartItem.number;
|
|
}
|
|
});
|
|
});
|
|
});
|
|
} else {
|
|
good_list.value.forEach((category: goodList) => {
|
|
category.Goods.forEach((good: GoodsType) => {
|
|
Reflect.deleteProperty(good, "cartNum");
|
|
});
|
|
});
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
page {
|
|
// IOS安全区域
|
|
padding-bottom: constant(safe-area-inset-bottom);
|
|
padding-bottom: env(safe-area-inset-bottom);
|
|
}
|
|
|
|
.nut-swiper {
|
|
height: 350px;
|
|
}
|
|
|
|
.infoBox {
|
|
background-color: #fff;
|
|
padding: 20px;
|
|
|
|
.title {
|
|
font-size: large;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.bom {
|
|
display: flex;
|
|
align-items: flex-end;
|
|
margin-top: 10px;
|
|
|
|
.left {
|
|
width: 80%;
|
|
|
|
.sub {
|
|
color: #999;
|
|
}
|
|
}
|
|
|
|
.right {
|
|
flex: 1;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
color: #999;
|
|
text-align: center;
|
|
}
|
|
}
|
|
}
|
|
|
|
.good-class {
|
|
margin-top: 10px;
|
|
|
|
.nut-tabs {
|
|
height: 100vh;
|
|
border-top: #fff 10px solid;
|
|
}
|
|
}
|
|
|
|
.list {
|
|
.item {
|
|
display: flex;
|
|
margin-bottom: 10px;
|
|
|
|
image {
|
|
width: 180px;
|
|
height: 180px;
|
|
border-radius: 10px;
|
|
}
|
|
|
|
.right {
|
|
flex: 1;
|
|
margin-left: 5px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
// text-align: right;
|
|
|
|
.stock {
|
|
margin-top: 10px;
|
|
color: #8f8f8f;
|
|
}
|
|
|
|
.name {
|
|
// height: 20px;
|
|
font-size: 28px;
|
|
display: -webkit-box;
|
|
-webkit-box-orient: vertical;
|
|
-webkit-line-clamp: 2;
|
|
overflow: hidden;
|
|
word-break: break-word;
|
|
}
|
|
|
|
.bom {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: flex-end;
|
|
//margin-top: 10px;
|
|
|
|
.price {
|
|
font-size: 20px;
|
|
font-weight: bold;
|
|
color: #ff0000;
|
|
-webkit-box-orient: vertical;
|
|
-webkit-line-clamp: 1;
|
|
overflow: hidden;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|