|
|
|
@ -3,8 +3,15 @@ import { onShow } from "@dcloudio/uni-app"; |
|
|
|
import { nextTick, ref } from "vue"; |
|
|
|
import customTabBar from "@/components/custom-tab-bar/my-tab-bar.vue"; |
|
|
|
import navigation from "@/components/navigation/navigation.vue"; |
|
|
|
import { getProductTypesApi } from "@/libs/api"; |
|
|
|
import { getCartInfoApi, getProductsApi, getProductTypesApi } from "@/libs/api"; |
|
|
|
import { getHeight, useHeight } from "@/libs/utils"; |
|
|
|
import useStore from "@/store"; |
|
|
|
|
|
|
|
// const app = getApp(); |
|
|
|
const store = useStore(); |
|
|
|
|
|
|
|
// const plugin = requirePlugin("WechatSI") |
|
|
|
// const manager = plugin.getRecordRecognitionManager() |
|
|
|
|
|
|
|
/** |
|
|
|
* 搜索关键字 |
|
|
|
@ -34,7 +41,14 @@ const currentTab = ref(0); |
|
|
|
* 当前子类标签 |
|
|
|
*/ |
|
|
|
const currentType = ref(0); |
|
|
|
|
|
|
|
/** |
|
|
|
* 右侧商品列表的高度 |
|
|
|
*/ |
|
|
|
const bottomHeight = ref(0); |
|
|
|
/** |
|
|
|
* 右侧商品列表的滚动高度 |
|
|
|
*/ |
|
|
|
const scrollTop = ref(0); |
|
|
|
/** |
|
|
|
* 顶部展开栏左右偏移量 |
|
|
|
*/ |
|
|
|
@ -51,6 +65,56 @@ const isShowAll = ref(false); |
|
|
|
* 子类型数据 |
|
|
|
*/ |
|
|
|
const typeData = ref([]); |
|
|
|
/** |
|
|
|
* 商品数据 |
|
|
|
*/ |
|
|
|
const products = ref([]); |
|
|
|
/** |
|
|
|
* 判断商品列表滚动到底部是否还有数据 |
|
|
|
*/ |
|
|
|
const unLoading = ref(false); |
|
|
|
/** |
|
|
|
* 判断商品列表有无数据 |
|
|
|
*/ |
|
|
|
const showList = ref(true); |
|
|
|
/** |
|
|
|
* 当前页码 |
|
|
|
*/ |
|
|
|
const pageIndex = ref(1); |
|
|
|
/** |
|
|
|
* 每页显示数量 |
|
|
|
*/ |
|
|
|
const pageSize = ref(20); |
|
|
|
/** |
|
|
|
* 总页数 |
|
|
|
*/ |
|
|
|
const pageCount = ref(0); |
|
|
|
/** |
|
|
|
* 判断是否滚动到了底部 |
|
|
|
*/ |
|
|
|
const isBottom = ref(false); |
|
|
|
/** |
|
|
|
* 下拉刷新状态 |
|
|
|
*/ |
|
|
|
const triggered = ref(false); |
|
|
|
|
|
|
|
/** |
|
|
|
* 触摸开始时的X坐标 |
|
|
|
*/ |
|
|
|
const touchDotX = ref(0); |
|
|
|
/** |
|
|
|
* 触摸开始时的Y坐标 |
|
|
|
*/ |
|
|
|
const touchDotY = ref(0); |
|
|
|
/** |
|
|
|
* 是否触摸开始 |
|
|
|
*/ |
|
|
|
const touchStar = ref(false); |
|
|
|
|
|
|
|
/** |
|
|
|
* 右侧商品列表的高度 |
|
|
|
*/ |
|
|
|
const rightHeight = ref(0); |
|
|
|
/** |
|
|
|
* 滚动加载数据时当前商品类型id |
|
|
|
*/ |
|
|
|
@ -81,21 +145,19 @@ function onShowAllTypes() { |
|
|
|
*/ |
|
|
|
function onSwitchNav(item, index) { |
|
|
|
navScrollLeft.value = (index - 2) * 50; |
|
|
|
if (currentTab.value === index) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
else { |
|
|
|
currentTab.value = index; |
|
|
|
currentType.value = 0; |
|
|
|
// products.value = []; |
|
|
|
// unLoading.value = false; |
|
|
|
// showList.value = true; |
|
|
|
// pageIndex.value = 1; |
|
|
|
isShowAll.value = false; |
|
|
|
keyword.value = ""; |
|
|
|
isSearching.value = false; |
|
|
|
getLeftTypes(item.id); |
|
|
|
} |
|
|
|
if (currentTab.value === index) |
|
|
|
return; |
|
|
|
|
|
|
|
currentTab.value = index; |
|
|
|
currentType.value = 0; |
|
|
|
products.value = []; |
|
|
|
unLoading.value = false; |
|
|
|
showList.value = true; |
|
|
|
pageIndex.value = 1; |
|
|
|
isShowAll.value = false; |
|
|
|
keyword.value = ""; |
|
|
|
isSearching.value = false; |
|
|
|
getLeftTypes(item.id); |
|
|
|
} |
|
|
|
function onOpenRecord() {} |
|
|
|
/** |
|
|
|
@ -146,15 +208,8 @@ async function getLeftTypes(parentId, isSearch) { |
|
|
|
typeData.value = resp.data; |
|
|
|
|
|
|
|
if (resp.total > 0) { |
|
|
|
console.log(currentType.value, typeData.value, 333); |
|
|
|
|
|
|
|
scrollId.value = typeData.value[currentType.value].id; |
|
|
|
if (isSearch) { |
|
|
|
getProducts(""); |
|
|
|
} |
|
|
|
else { |
|
|
|
getProducts(scrollId.value); |
|
|
|
} |
|
|
|
getProducts(isSearch ? "" : scrollId.value); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -162,32 +217,189 @@ async function getLeftTypes(parentId, isSearch) { |
|
|
|
/** |
|
|
|
* 获取商品信息 |
|
|
|
*/ |
|
|
|
function getProducts(parentId, tips) { |
|
|
|
if (hasFetchedCart.value) { |
|
|
|
loadProductList(parentId, tips); |
|
|
|
async function getProducts(parentId, tips) { |
|
|
|
if (!hasFetchedCart.value) { |
|
|
|
const params = { |
|
|
|
warehouseId: uni.getStorageSync("warehousId"), |
|
|
|
addrId: uni.getStorageSync("addressId"), |
|
|
|
}; |
|
|
|
const resp = await getCartInfoApi(params); |
|
|
|
store.changeCartList(resp.code === "0" ? resp.data : []); |
|
|
|
// app.globalData.cartList = resp.code === "0" ? resp.data : []; |
|
|
|
hasFetchedCart.value = resp.code === "0"; |
|
|
|
} |
|
|
|
|
|
|
|
loadProductList(parentId, tips); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 菜品列表 全局只加载一次 |
|
|
|
*/ |
|
|
|
async function loadProductList(parentId, tips) { |
|
|
|
showList.value = true; |
|
|
|
// const params = { |
|
|
|
// warehouseId: wx.getStorageSync("warehousId"), |
|
|
|
// addrId: wx.getStorageSync("addressId"), |
|
|
|
// }; |
|
|
|
|
|
|
|
const cartList = store.cartList; |
|
|
|
const total = cartList.reduce((cur, acc) => acc + cur.quantity, 0); |
|
|
|
store.increment(total); |
|
|
|
|
|
|
|
const params = { |
|
|
|
typeId: parentId, |
|
|
|
promotion: false, |
|
|
|
orderByField: "name", |
|
|
|
ase: true, |
|
|
|
search: keyword.value, |
|
|
|
pageNum: pageIndex.value, |
|
|
|
pageSize: pageSize.value, |
|
|
|
warehouseid: uni.getStorageSync("warehousId"), |
|
|
|
}; |
|
|
|
|
|
|
|
const resp = await getProductsApi(params); |
|
|
|
if (resp.code !== "0") |
|
|
|
return; |
|
|
|
|
|
|
|
pageCount.value = resp.pageCount; |
|
|
|
|
|
|
|
if (!(resp.total > 0)) { |
|
|
|
showList.value = false; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
resp.data.forEach((item) => { |
|
|
|
// 初始化购物车映射表(格式:specId_price -> quantity) |
|
|
|
const cartMap = cartList.reduce((acc, cur) => { |
|
|
|
return { ...acc, [`${cur.specId}_${cur.price}`]: cur.quantity }; |
|
|
|
}, {}); |
|
|
|
|
|
|
|
item.specs.forEach((specsItem) => { |
|
|
|
// 为每个规格项生成相同的组合键 |
|
|
|
const specKey = `${specsItem.id}_${specsItem.price}`; |
|
|
|
// 从映射表中获取数量(不存在则设为0) |
|
|
|
specsItem.sum = cartMap[specKey] || 0; |
|
|
|
}); |
|
|
|
|
|
|
|
// 判断是否显示“选规格”按钮 |
|
|
|
item.showChoose = item.specs.length > 1 ? 1 : 0; |
|
|
|
item.showChild = item.specs.length > 1 ? false : item.showChild; |
|
|
|
}); |
|
|
|
|
|
|
|
products.value = pageIndex.value === 1 |
|
|
|
? resp.data |
|
|
|
: [...products.value, ...(resp.data || [])]; |
|
|
|
|
|
|
|
rightHeight.value = (await getHeight("#scroll-page")) + 1; |
|
|
|
if (tips === 1) { |
|
|
|
currentType.value -= 1; |
|
|
|
} |
|
|
|
else if (tips === 2) { |
|
|
|
currentType.value += 1; |
|
|
|
scrollTop.value = 0; |
|
|
|
bottomHeight.value = 0; |
|
|
|
} |
|
|
|
uni.hideNavigationBarLoading(); // 停止下拉刷新 |
|
|
|
uni.stopPullDownRefresh(); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 滚动事件 |
|
|
|
* @param {Event} e - 滚动事件参数 |
|
|
|
*/ |
|
|
|
function onScroll(e) { |
|
|
|
isBottom.value = (e.detail.scrollHeight - e.detail.scrollTop) <= rightHeight.value; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 翻页数据 |
|
|
|
*/ |
|
|
|
function onLoadList() { |
|
|
|
const pageIdx = pageIndex.value + 1; |
|
|
|
if (pageIdx <= pageCount.value) { |
|
|
|
pageIndex.value = pageIdx; |
|
|
|
unLoading.value = false; |
|
|
|
getProducts(scrollId.value); |
|
|
|
} |
|
|
|
else { |
|
|
|
unLoading.value = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 下拉刷新 |
|
|
|
*/ |
|
|
|
function onRefresherrefresh() { |
|
|
|
triggered.value = false; |
|
|
|
if (currentType.value !== 0) { |
|
|
|
getProducts(typeData[currentType.value - 1].id, 1); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function loadProductList(parentId, tips) { |
|
|
|
// showList.value = true; |
|
|
|
// uni.showLoading({ |
|
|
|
// title: "加载中", |
|
|
|
// mask: true, |
|
|
|
// }); |
|
|
|
// uni.hideLoading(); |
|
|
|
// let cartList = app.globalData.cartList; |
|
|
|
// @touchstart="onTouchStart" |
|
|
|
// @touchmove="onTouchMove" |
|
|
|
// @touchend="onTouchend" |
|
|
|
|
|
|
|
function onTouchStart(e) { |
|
|
|
touchDotX.value = e.touches[0].pageX; |
|
|
|
touchDotY.value = e.touches[0].pageY; |
|
|
|
touchStar.value = false; |
|
|
|
} |
|
|
|
|
|
|
|
function onTouchMove(e) { |
|
|
|
const pageX = e.touches[0].pageX; |
|
|
|
const pageY = e.touches[0].pageY; |
|
|
|
if (!touchStar.value) { |
|
|
|
return; |
|
|
|
} |
|
|
|
const moveY = Math.abs(pageY - touchDotY.value); |
|
|
|
/** |
|
|
|
* 左滑手势:横向滑动距离 ≥ 40 且纵向偏移 < 10,且当前不是最后一个一级分类时,切换到下一个一级分类 |
|
|
|
*/ |
|
|
|
const isLeft = pageX - touchDotX.value <= -40 |
|
|
|
&& moveY < 10 |
|
|
|
&& (currentTab.value < navData.value.length - 1); |
|
|
|
|
|
|
|
/** |
|
|
|
* 右滑手势:横向滑动距离 ≥ 40 且纵向偏移 < 10,且当前不是第一个一级分类时,切换到上一个一级分类 |
|
|
|
*/ |
|
|
|
const isRight = pageX - touchDotX.value >= 40 |
|
|
|
&& moveY < 10 |
|
|
|
&& (currentTab.value !== 0); |
|
|
|
|
|
|
|
// 左右滑动切换一级分类时,重置当前二级分类为第一个 |
|
|
|
if (isLeft || isRight) { |
|
|
|
currentType.value = 0; |
|
|
|
products.value = []; |
|
|
|
unLoading.value = false; |
|
|
|
showList.value = true; |
|
|
|
pageIndex.value = 1; |
|
|
|
touchStar.value = false; |
|
|
|
|
|
|
|
currentTab.value = isLeft ? currentTab.value + 1 : currentTab.value - 1; |
|
|
|
const navId = navData.value[currentTab.value]?.id; |
|
|
|
navScrollLeft.value = (currentTab.value - 2) * 50; |
|
|
|
getLeftTypes(navId); |
|
|
|
} |
|
|
|
|
|
|
|
bottomHeight.value = touchDotY.value > pageY |
|
|
|
? bottomHeight.value + 0.2 // 向上 |
|
|
|
: bottomHeight.value - 0.2; // 往下 |
|
|
|
} |
|
|
|
|
|
|
|
function onTouchEnd() { |
|
|
|
bottomHeight.value = 0; |
|
|
|
} |
|
|
|
|
|
|
|
onShow(() => { |
|
|
|
getProductTypes(); |
|
|
|
safeHeight.value = useHeight(); |
|
|
|
|
|
|
|
nextTick(async () => { |
|
|
|
const boxHeight = await getHeight(".first-box"); |
|
|
|
const { screen, status, menu, bottom } = safeHeight.value; |
|
|
|
pageContainerHeight.value = screen - status - menu - bottom - boxHeight - 60; |
|
|
|
// searchHeight.value = await getHeight(".header-box"); |
|
|
|
}); |
|
|
|
}); |
|
|
|
</script> |
|
|
|
@ -196,9 +408,14 @@ onShow(() => { |
|
|
|
<view class="w-full h-full"> |
|
|
|
<!-- 微信的胶囊以及搜索框 --> |
|
|
|
<navigation background="#fff" class="header-box"> |
|
|
|
<!-- <image class="icon-left" src="../../images/all/search.png" mode="" /> --> |
|
|
|
<div class="box" :style="{ height: `${safeHeight.menu || 45}px` }"> |
|
|
|
<text class="iconfont icon-search" /> |
|
|
|
<div |
|
|
|
class="box" |
|
|
|
:style="{ |
|
|
|
height: `${safeHeight.menu || 45}px`, |
|
|
|
width: safeHeight.menu ? '70%' : '100%', |
|
|
|
}" |
|
|
|
> |
|
|
|
<text class="iconfont icon-search1" /> |
|
|
|
<input |
|
|
|
class="input" |
|
|
|
type="text" |
|
|
|
@ -238,6 +455,8 @@ onShow(() => { |
|
|
|
</view> |
|
|
|
</scroll-view> |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 展开 --> |
|
|
|
<view class="right" @click="onShowAllTypes"> |
|
|
|
<text class="text"> |
|
|
|
展 |
|
|
|
@ -256,7 +475,9 @@ onShow(() => { |
|
|
|
<view |
|
|
|
class="first-big-type" |
|
|
|
:style="{ |
|
|
|
top: isShowAll ? `${safeHeight.status + (safeHeight.menu || 45) + 5}px` : '-1600rpx', |
|
|
|
top: isShowAll |
|
|
|
? `${safeHeight.status + (safeHeight.menu || 45) + 5}px` |
|
|
|
: '-1600rpx', |
|
|
|
}" |
|
|
|
> |
|
|
|
<view class="title"> |
|
|
|
@ -314,6 +535,39 @@ onShow(() => { |
|
|
|
</text> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
<scroll-view |
|
|
|
id="scroll-page" |
|
|
|
class="right" |
|
|
|
:scroll-top="scrollTop" |
|
|
|
scroll-y |
|
|
|
:throttle="false" |
|
|
|
:style="{ |
|
|
|
width: isSearch ? '100%' : '80%', |
|
|
|
height: '100%', |
|
|
|
marginTop: `${-(bottomHeight)}%`, |
|
|
|
transition: '.01s all', |
|
|
|
}" |
|
|
|
refresher-enabled |
|
|
|
refresher-threshold="20" |
|
|
|
enhanced |
|
|
|
enable-passive |
|
|
|
:refresher-triggered="triggered" |
|
|
|
refresher-default-style="white" |
|
|
|
scroll-with-animation |
|
|
|
show-scrollbar |
|
|
|
@scrolltolower="onLoadList" |
|
|
|
@scroll="onScroll" |
|
|
|
@refresherrefresh="onRefresherrefresh" |
|
|
|
> |
|
|
|
<view |
|
|
|
v-if="showList" |
|
|
|
class="content-right" |
|
|
|
@touchstart="onTouchStart" |
|
|
|
@touchmove="onTouchMove" |
|
|
|
@touchend="onTouchEnd" |
|
|
|
/> |
|
|
|
</scroll-view> |
|
|
|
<!-- @refresherrestore="onTriggered" --> |
|
|
|
</view> |
|
|
|
|
|
|
|
<customTabBar tab-index="1" /> |
|
|
|
@ -325,7 +579,8 @@ onShow(() => { |
|
|
|
width: 100%; |
|
|
|
.box { |
|
|
|
margin-left: 14rpx; |
|
|
|
width: 70%; |
|
|
|
margin-right: 14rpx; |
|
|
|
// width: 70%; |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
border-radius: 50rpx; |
|
|
|
@ -337,7 +592,7 @@ onShow(() => { |
|
|
|
color: #333; |
|
|
|
flex: 1; |
|
|
|
} |
|
|
|
.icon-search { |
|
|
|
.icon-search1 { |
|
|
|
margin-left: 38rpx; |
|
|
|
} |
|
|
|
.icon-yuyin { |
|
|
|
@ -725,7 +980,7 @@ page { |
|
|
|
} |
|
|
|
|
|
|
|
.name { |
|
|
|
font-size: 24rpx; |
|
|
|
font-size: $text-base; |
|
|
|
margin-top: 12rpx; |
|
|
|
text-align: center; |
|
|
|
padding: 10rpx 8rpx; |
|
|
|
@ -747,7 +1002,8 @@ page { |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
color: #666666; |
|
|
|
font-size: 24rpx; |
|
|
|
// font-size: 24rpx; |
|
|
|
font-size: $text-base; |
|
|
|
margin-top: 30rpx; |
|
|
|
|
|
|
|
.left { |
|
|
|
@ -1039,7 +1295,7 @@ page { |
|
|
|
transform: translateY(-50%); |
|
|
|
color: #3aa24b; |
|
|
|
font-weight: bold; |
|
|
|
font-size: 44rpx; |
|
|
|
font-size: 80rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.title { |
|
|
|
@ -1097,7 +1353,8 @@ page { |
|
|
|
|
|
|
|
.name { |
|
|
|
font-weight: 400; |
|
|
|
font-size: 25rpx; |
|
|
|
font-size: $text-sm; |
|
|
|
// font-size: 25rpx; |
|
|
|
color: #333333; |
|
|
|
margin-top: 8rpx; |
|
|
|
transition: .3s all; |
|
|
|
@ -1166,7 +1423,8 @@ page { |
|
|
|
border-radius: 0 0 20rpx 20rpx; |
|
|
|
|
|
|
|
.title { |
|
|
|
font-size: 28rpx; |
|
|
|
// font-size: 28rpx; |
|
|
|
font-size: $text-lg; |
|
|
|
font-weight: bold; |
|
|
|
} |
|
|
|
|
|
|
|
@ -1189,7 +1447,8 @@ page { |
|
|
|
|
|
|
|
.name { |
|
|
|
font-weight: 400; |
|
|
|
font-size: 25rpx; |
|
|
|
font-size: $text-base; |
|
|
|
// font-size: 25rpx; |
|
|
|
color: #333333; |
|
|
|
margin-top: 8rpx; |
|
|
|
|
|
|
|
@ -1222,7 +1481,8 @@ page { |
|
|
|
height: 100%; |
|
|
|
overflow-y: scroll; |
|
|
|
font-weight: 400; |
|
|
|
font-size: 26rpx; |
|
|
|
font-size: $text-base; |
|
|
|
// font-size: 26rpx; |
|
|
|
color: #333333; |
|
|
|
background: #F8FAF7; |
|
|
|
padding-top: 14rpx; |
|
|
|
|