You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
979 lines
25 KiB
979 lines
25 KiB
<script setup>
|
|
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 {
|
|
addCartApi,
|
|
getCartInfoApi,
|
|
getProductsApi,
|
|
getProductTypesApi,
|
|
previewApi,
|
|
} from "@/libs/api";
|
|
import { getHeight, useHeight, validates } from "@/libs/utils";
|
|
import useStore from "@/store";
|
|
|
|
const store = useStore();
|
|
/**
|
|
* 购物车商品id列表
|
|
*/
|
|
const keys = [];
|
|
|
|
// const plugin = requirePlugin("WechatSI")
|
|
// const manager = plugin.getRecordRecognitionManager()
|
|
|
|
/**
|
|
* 搜索关键字
|
|
*/
|
|
const keyword = ref("");
|
|
/**
|
|
* 搜索框的高度
|
|
*/
|
|
// const searchHeight = ref(0);
|
|
/**
|
|
* 状态栏高度
|
|
*/
|
|
// const statusBarHeight = ref(0);
|
|
/**
|
|
* 屏幕的高度
|
|
*/
|
|
// const screenHeight = ref(0);
|
|
/**
|
|
* 各种距离
|
|
*/
|
|
const safeHeight = ref({});
|
|
/**
|
|
* 当前标签
|
|
*/
|
|
const currentTab = ref(0);
|
|
/**
|
|
* 当前子类标签
|
|
*/
|
|
const currentType = ref(0);
|
|
/**
|
|
* 右侧商品列表的高度
|
|
*/
|
|
const bottomHeight = ref(0);
|
|
/**
|
|
* 右侧商品列表的滚动高度
|
|
*/
|
|
const scrollTop = ref(0);
|
|
/**
|
|
* 顶部展开栏左右偏移量
|
|
*/
|
|
const navScrollLeft = ref(0);
|
|
/**
|
|
* 顶部类型数据
|
|
*/
|
|
const navData = ref([]);
|
|
/**
|
|
* 展开顶部类型数据
|
|
*/
|
|
const isShowAll = ref(false);
|
|
/**
|
|
* 子类型数据
|
|
*/
|
|
const typeData = ref([]);
|
|
/**
|
|
* 商品数据
|
|
*/
|
|
const products = ref([]);
|
|
/**
|
|
* 购物车商品数量
|
|
*/
|
|
const cartCount = ref(0);
|
|
/**
|
|
* 购物车商品列表
|
|
*/
|
|
const cartList = ref([]);
|
|
/**
|
|
* 购物车商品总价
|
|
*/
|
|
const totalPrice = ref(0);
|
|
/**
|
|
* 服务费用
|
|
*/
|
|
const serviceFee = ref(0);
|
|
/**
|
|
* 配送费
|
|
*/
|
|
const shippingFee = ref(0);
|
|
/**
|
|
* 是否显示购物车
|
|
*/
|
|
const showCart = ref(false);
|
|
/**
|
|
* 判断商品列表滚动到底部是否还有数据
|
|
*/
|
|
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
|
|
*/
|
|
const scrollId = ref("");
|
|
/**
|
|
* 是否在搜索中
|
|
*/
|
|
const isSearching = ref(false);
|
|
/**
|
|
* 滚动页面的高度
|
|
*/
|
|
const pageContainerHeight = ref(0);
|
|
/**
|
|
* 标记是否已获取过购物车(首次加载后设为true)
|
|
*/
|
|
const hasFetchedCart = ref(true);
|
|
/**
|
|
* 上次点击加入购物车的时间
|
|
*/
|
|
// const actionTime = ref(true);
|
|
/**
|
|
* 输入购买数量弹框的值
|
|
*/
|
|
const inputValue = ref("");
|
|
/**
|
|
* 隐藏购买数量弹框
|
|
*/
|
|
// const hiddenModal = ref(true);
|
|
|
|
function onSearch() {}
|
|
|
|
function onChangeKeyword() {}
|
|
/**
|
|
* 展开顶部类型数据
|
|
*/
|
|
function onShowAllTypes() {
|
|
isShowAll.value = !isShowAll.value;
|
|
}
|
|
/**
|
|
* 点击一级分类,并修改二级分类数据
|
|
*/
|
|
function onSwitchNav(item, index) {
|
|
navScrollLeft.value = (index - 2) * 50;
|
|
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() {}
|
|
/**
|
|
* 点击了二级分类,并修改列表
|
|
*/
|
|
function onSwitchType(item, index) {
|
|
if (currentType.value === index)
|
|
return;
|
|
currentType.value = index;
|
|
products.value = [];
|
|
unLoading.value = false;
|
|
showList.value = true;
|
|
pageIndex.value = 1;
|
|
scrollId.value = item.id;
|
|
getProducts(scrollId.value);
|
|
}
|
|
/**
|
|
* 获取顶部tab标签列表,对应左侧类别
|
|
*/
|
|
async function getProductTypes(id, isSearch) {
|
|
const res = await getProductTypesApi();
|
|
if (res.code === "0") {
|
|
navData.value = res.data;
|
|
if (id) {
|
|
getLeftTypes(id);
|
|
res.data.forEach((item, index) => {
|
|
if (item.id === id) {
|
|
currentTab.value = index;
|
|
navScrollLeft.value = (index - 2) * 50;
|
|
}
|
|
});
|
|
}
|
|
else {
|
|
const idx = isSearch ? 0 : currentTab.value;
|
|
getLeftTypes(navData.value[idx].id, isSearch ? true : undefined);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* 获取左侧子类别
|
|
* @param parentId
|
|
* @param isSearch
|
|
*/
|
|
async function getLeftTypes(parentId, isSearch) {
|
|
const res = await getProductTypesApi({ parentId });
|
|
if (res.code === "0") {
|
|
typeData.value = res.data;
|
|
|
|
if (res.total > 0) {
|
|
scrollId.value = typeData.value[currentType.value].id;
|
|
getProducts(isSearch ? "" : scrollId.value);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* 获取商品信息
|
|
*/
|
|
async function getProducts(parentId, tips) {
|
|
if (!hasFetchedCart.value) {
|
|
const params = {
|
|
warehouseId: uni.getStorageSync("warehousId"),
|
|
addrId: uni.getStorageSync("addressId"),
|
|
};
|
|
const res = await getCartInfoApi(params);
|
|
store.changeCartList(res.code === "0" ? res.data : []);
|
|
// app.globalData.cartList = res.code === "0" ? res.data : [];
|
|
hasFetchedCart.value = res.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 res = await getProductsApi(params);
|
|
if (res.code !== "0")
|
|
return;
|
|
|
|
pageCount.value = res.pageCount;
|
|
|
|
if (!(res.total > 0)) {
|
|
showList.value = false;
|
|
return;
|
|
}
|
|
|
|
res.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
|
|
? res.data
|
|
: [...products.value, ...(res.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);
|
|
}
|
|
}
|
|
/**
|
|
* 触摸开始事件
|
|
* @param e 触摸事件参数
|
|
*/
|
|
function onTouchStart(e) {
|
|
touchDotX.value = e.touches[0].pageX;
|
|
touchDotY.value = e.touches[0].pageY;
|
|
touchStar.value = false;
|
|
}
|
|
/**
|
|
* 触摸移动事件
|
|
* @param e 触摸事件参数
|
|
*/
|
|
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() {
|
|
if (
|
|
// 当底部手势滑动距离 ≥ 4 且当前二级分类索引未越界时,触发加载下一二级分类
|
|
bottomHeight.value >= 4
|
|
&& currentType.value <= typeData.value.length - 1
|
|
) {
|
|
bottomHeight.value = 0;
|
|
if (!isSearching.value) {
|
|
getProducts(typeData.value[currentType.value + 1].id, 2);
|
|
}
|
|
}
|
|
if (
|
|
// 当底部手势滑动距离大于 0 且已滚动到底部时,重置手势滑动距离
|
|
bottomHeight.value > 0
|
|
&& bottomHeight.value >= 0
|
|
&& isBottom.value
|
|
) {
|
|
bottomHeight.value = 0;
|
|
}
|
|
}
|
|
|
|
function onGotoNext() {
|
|
if (currentType.value === typeData.value.length - 1) {
|
|
return;
|
|
}
|
|
currentType.value += 1;
|
|
scrollTop.value = 0;
|
|
bottomHeight.value = 0;
|
|
}
|
|
|
|
function onGotoDetail(item) {
|
|
uni.navigateTo({
|
|
url: `/pages/detail/detail?id=${item.id}`,
|
|
});
|
|
}
|
|
/**
|
|
* 初始化购物车信息
|
|
*/
|
|
async function initCartInfo() {
|
|
const data = {
|
|
warehouseId: uni.getStorageSync("warehousId"),
|
|
addrId: uni.getStorageSync("addressId"),
|
|
};
|
|
const res = await getCartInfoApi(data);
|
|
if (res.code !== 0)
|
|
return;
|
|
cartCount.value = res.total;
|
|
cartList.value = res.data || [];
|
|
|
|
store.goodsCheckedItems = res.data.map(item => item.id); ;
|
|
totalPrice.value = res.data.reduce((acc, item) => acc + item.amount, 0).toFixed(2);
|
|
if (store.goodsCheckedItems > 0) {
|
|
preview(store.goodsCheckedItems);
|
|
}
|
|
else if (showCart.value) {
|
|
showList.value = false;
|
|
}
|
|
}
|
|
/**
|
|
* 订单预览
|
|
* @param itemIds 商品id列表
|
|
*/
|
|
async function preview(itemIds) {
|
|
const data = {
|
|
itemIds: itemIds.join(","),
|
|
addrId: uni.getStorageSync("addressId"),
|
|
};
|
|
const res = await previewApi(data);
|
|
serviceFee.value = res.data.serviceFee;
|
|
shippingFee.value = res.data.shippingFee;
|
|
totalPrice.value = res.data.itemAmount;
|
|
}
|
|
/**
|
|
* 加入购物车
|
|
* @param item 商品项
|
|
*/
|
|
async function onAdd(item) {
|
|
// item.specs[0].sum = 9;
|
|
// if (item.sum === "") {
|
|
// item.sum = inputValue.value;
|
|
// }
|
|
const isPass = validates([
|
|
() => item.stock == item.sum && "采购数量不能大于库存数量",
|
|
() => item.stock == 0 && "库存数量为0无法添加",
|
|
]);
|
|
|
|
if (!isPass) {
|
|
return;
|
|
}
|
|
|
|
// 判空为 0, 否则转换为数字
|
|
item.sum = Number(item.sum) || 0;
|
|
// 起订量(item.minNum), 否则每次+1
|
|
item.sum += item.sum === 0 ? (item.minNum || 1) : 1;
|
|
// 保持输入框与购物车数量同步
|
|
inputValue.value = item.sum;
|
|
|
|
toCart(item);
|
|
}
|
|
|
|
/**
|
|
* 更新购物车
|
|
* @param item 商品项
|
|
*/
|
|
async function toCart(item) {
|
|
const data = {
|
|
quantity: item.sum,
|
|
specId: item.id,
|
|
Chuxiao: item.chuxiao,
|
|
warehouseId: uni.getStorageSync("warehousId"),
|
|
addrId: uni.getStorageSync("addressId"),
|
|
};
|
|
|
|
if (!data.specId) {
|
|
uni.showModal({
|
|
title: "提示",
|
|
content: "当前商品规格错误,请稍候再试",
|
|
showCancel: false,
|
|
confirmText: "确定",
|
|
});
|
|
}
|
|
|
|
if (data.Chuxiao === "" || data.Chuxiao === undefined) {
|
|
data.Chuxiao = false;
|
|
}
|
|
|
|
if (!data.warehouseId || !data.addrId) {
|
|
uni.showModal({
|
|
title: "提示",
|
|
content: "请先选择收货地址,再添加商品",
|
|
showCancel: false,
|
|
confirmText: "确定",
|
|
});
|
|
}
|
|
|
|
keys.push(item.id);
|
|
const res = await addCartApi(data);
|
|
keys.splice(item.id, 1);
|
|
if (res.code === "0") {
|
|
initCartInfo();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 减少购买数量
|
|
* @param item 商品项
|
|
*/
|
|
function onMinus(item) {
|
|
// if (item.sum === "") {
|
|
// item.sum = inputValue.value;
|
|
// }
|
|
const isPass = validates([
|
|
() => item.stock == item.sum && "采购数量不能大于库存数量",
|
|
() => item.stock == 0 && "库存数量为0无法添加",
|
|
() => item.sum < 0 && "显示错误,采购数量不能小于0",
|
|
]);
|
|
|
|
if (!isPass) {
|
|
return;
|
|
}
|
|
|
|
// 判空为 0, 否则转换为数字
|
|
item.sum = Number(item.sum) || 0;
|
|
// 达到起订量(item.minNum)直接清空, 否则每次-1
|
|
item.sum -= item.sum === (item.minNum || 1) ? (item.minNum || 1) : 1;
|
|
// 保持输入框与购物车数量同步
|
|
inputValue.value = item.sum;
|
|
|
|
toCart(item);
|
|
}
|
|
|
|
function onChooseNorm(item) {
|
|
item.showChild = !item.showChild;
|
|
}
|
|
|
|
// function onModelConfirm() { }
|
|
|
|
// function onModelCancel() { }
|
|
|
|
function onShowKeyboard() { }
|
|
|
|
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>
|
|
|
|
<template>
|
|
<!-- 微信的胶囊以及搜索框 -->
|
|
<navigation background="#fff" class="header-box">
|
|
<div
|
|
class="box"
|
|
:style="{
|
|
height: `${safeHeight.menu || 45}px`,
|
|
width: safeHeight.menu ? '70%' : '100%',
|
|
}"
|
|
>
|
|
<text class="iconfont icon-search1" />
|
|
<input
|
|
class="input"
|
|
type="text"
|
|
placeholder="请输入商品名称"
|
|
placeholder-style="color: #999999"
|
|
:value="keyword"
|
|
@onConfirm="onSearch"
|
|
@input="onChangeKeyword"
|
|
>
|
|
<text class="iconfont icon-yuyin" @click="onOpenRecord" />
|
|
</div>
|
|
</navigation>
|
|
|
|
<!-- 横向的分类 一级分类 -->
|
|
<view class="first-box">
|
|
<view class="left">
|
|
<scroll-view
|
|
class="scroll-view"
|
|
scroll-x
|
|
scroll-with-animation
|
|
:scroll-left="navScrollLeft"
|
|
>
|
|
<view
|
|
v-for="(navItem, idx) in navData"
|
|
:key="idx"
|
|
class="list-box"
|
|
@click="() => onSwitchNav(navItem, idx)"
|
|
>
|
|
<view class="type-list">
|
|
<image class="image" :src="navItem.imageUrl" mode="" />
|
|
<text
|
|
class="name" :class="[currentTab === idx ? 'name-active' : ''] "
|
|
>
|
|
{{ navItem.name }}
|
|
</text>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
|
|
<!-- 展开 -->
|
|
<view class="right" @click="onShowAllTypes">
|
|
<text class="text">
|
|
展
|
|
</text>
|
|
<text class="text">
|
|
开
|
|
</text>
|
|
<text class="iconfont icon-down" />
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 遮罩层 -->
|
|
<view v-show="isShowAll" class="first-type-mask" @click="onShowAllTypes" />
|
|
|
|
<!-- 展开全部分类 -->
|
|
<view
|
|
class="first-big-type"
|
|
:style="{
|
|
top: isShowAll
|
|
? `${safeHeight.status + (safeHeight.menu || 45) + 5}px`
|
|
: '-1600rpx',
|
|
}"
|
|
>
|
|
<view class="title">
|
|
全部分类
|
|
</view>
|
|
<view class="list-box">
|
|
<view
|
|
v-for="(navItem, idx) in navData"
|
|
:key="idx"
|
|
class="listx"
|
|
@click="() => onSwitchNav(navItem, idx)"
|
|
>
|
|
<image
|
|
class="img"
|
|
:class="[currentTab == idx ? 'nav-item-img-active' : '']"
|
|
:src="navItem.imageUrl"
|
|
/>
|
|
<view
|
|
class="name"
|
|
:class="[currentTab == idx ? 'active' : '']"
|
|
>
|
|
{{ navItem.name }}
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view
|
|
class="retract"
|
|
@click="onShowAllTypes"
|
|
>
|
|
<view class="left">
|
|
点击收起
|
|
</view>
|
|
<text class="iconfont icon-up1" />
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 内容 可滚动 -->
|
|
<view
|
|
class="page-container"
|
|
:style="{ height: `${pageContainerHeight}px` }"
|
|
>
|
|
<view v-if="!isSearching" class="left">
|
|
<view
|
|
v-for="(typeItem, typex) in typeData"
|
|
:key="typex"
|
|
class="text"
|
|
@click="() => onSwitchType(typeItem, typex)"
|
|
>
|
|
<text
|
|
class="name"
|
|
:class="[currentType == typex ? 'text-active' : '']"
|
|
>
|
|
{{ typeItem.name }}
|
|
</text>
|
|
</view>
|
|
</view>
|
|
<!--
|
|
:scroll-top="scrollTop" 设置滚动条位置
|
|
scroll-y 允许纵向滚动
|
|
scroll-with-animation 滚动时带动画
|
|
show-scrollbar 显示滚动条
|
|
enhanced 启用增强特性
|
|
enable-passive 启用 passive 滚动,提升性能
|
|
refresher-enabled 启用下拉刷新
|
|
refresher-default-style="white" 下拉刷新默认样式为白色
|
|
:refresher-threshold="20" 下拉刷新触发阈值 20px
|
|
:refresher-triggered="triggered" 控制下拉刷新状态
|
|
:throttle="false" 关闭滚动节流
|
|
@scrolltolower="onLoadList" 滚动到底部时触发加载下一页
|
|
@scroll="onScroll" 滚动过程中实时监听滚动位置
|
|
@refresherrefresh="onRefresherrefresh" 下拉刷新时触发重新加载当前分类数据
|
|
-->
|
|
<scroll-view
|
|
id="scroll-page"
|
|
class="right"
|
|
:scroll-top="scrollTop"
|
|
scroll-y
|
|
scroll-with-animation
|
|
show-scrollbar
|
|
enhanced
|
|
enable-passive
|
|
refresher-enabled
|
|
refresher-default-style="white"
|
|
:refresher-threshold="20"
|
|
:refresher-triggered="triggered"
|
|
:throttle="false"
|
|
:style="{
|
|
width: isSearching ? '100%' : '80%',
|
|
height: '100%',
|
|
marginTop: `${-(bottomHeight)}%`,
|
|
transition: '.01s all',
|
|
}"
|
|
@scrolltolower="onLoadList"
|
|
@scroll="onScroll"
|
|
@refresherrefresh="onRefresherrefresh"
|
|
>
|
|
<view
|
|
v-if="showList"
|
|
class="content-right"
|
|
@touchstart="onTouchStart"
|
|
@touchmove="onTouchMove"
|
|
@touchend="onTouchEnd"
|
|
>
|
|
<view
|
|
v-for="(item, idx) in products"
|
|
:key="idx"
|
|
class="right-list"
|
|
>
|
|
<view v-if="!item.showChoose && item.specs[0].stock == 0" class="of-stock" />
|
|
<view class="right-list-top">
|
|
<view
|
|
class="right-list-left"
|
|
@click="() => onGotoDetail(item)"
|
|
>
|
|
<image class="image" :src="item.imageUrl" mode="" />
|
|
<view
|
|
v-if="!item.showChoose && item.specs[0].stock == 0"
|
|
class="of-stock-text"
|
|
>
|
|
补货中
|
|
</view>
|
|
</view>
|
|
<view class="right-list-right">
|
|
<view class="top" @click="() => onGotoDetail(item)">
|
|
<view class="name">
|
|
{{ item.name }}
|
|
</view>
|
|
<view class="inventory">
|
|
{{
|
|
// 仅当商品只有1个规格且库存不为“无限库存”(-1)时才显示库存数量
|
|
item.specs.length == 1 && !(item.specs[0].stock == -1)
|
|
? `库存:${item.specs[0].stock}`
|
|
: ''
|
|
}}
|
|
</view>
|
|
</view>
|
|
<view class="under">
|
|
<view class="price-box" @click="() => onGotoDetail(item)">
|
|
<view class="price">
|
|
<text>¥{{ item.specs[0].price }}</text>
|
|
</view>
|
|
<text v-if="item.specs[0].chuxiao" class="original">
|
|
正价:¥{{ item.specs[0].oldPrice }}/{{ item.specs[0].unit }}
|
|
</text>
|
|
<text v-else class="no-original">
|
|
/{{ item.specs[0].unit }}
|
|
</text>
|
|
</view>
|
|
<view v-if="!item.showChoose && item.specs[0].stock != 0" class="choose-box">
|
|
<block v-if="item.specs[0].sum !== 0">
|
|
<view class="line-one" />
|
|
<view class="line-two" />
|
|
<view class="minus" @click.stop="() => onMinus(item)">
|
|
<image class="icon" src="/static/home/minus.png" mode="" />
|
|
</view>
|
|
<text class="input" @click="() => onShowKeyboard(item)">
|
|
{{ item.specs[0].sum }}
|
|
</text>
|
|
</block>
|
|
<view class="add" @click.stop="() => onAdd(item)">
|
|
<image class="icon" src="/static/home/add.png" mode="" />
|
|
</view>
|
|
</view>
|
|
<view
|
|
v-if="item.showChoose"
|
|
class="specifications"
|
|
@click.stop="() => onChooseNorm(item)"
|
|
>
|
|
{{ item.showChild ? '收起' : '选规格' }}
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view v-if="item.showChild" class="right-list-under">
|
|
<view
|
|
v-for="(childs) in item.specs"
|
|
:key="childs.id"
|
|
class="goods-under-list"
|
|
>
|
|
<view class="price-box">
|
|
<view class="price">
|
|
<text>¥{{ childs.price }}</text>
|
|
</view>
|
|
<text v-if="item.specs[0].chuxiao" class="original">
|
|
/{{ childs.unit }}
|
|
</text>
|
|
<text v-else class="no-original">
|
|
/{{ childs.unit }}
|
|
</text>
|
|
<view class="no-original">
|
|
{{ childs.stock == -1 ? '' : `库存:${childs.stock}` }}
|
|
</view>
|
|
</view>
|
|
<view class="choose-box">
|
|
<block v-if="childs.sum !== 0 || childs.sum != ''">
|
|
<view class="line-one" />
|
|
<view class="line-two" />
|
|
<view
|
|
class="minus"
|
|
data-quantity="-1"
|
|
data-exa="sum"
|
|
@click="onSetSum"
|
|
>
|
|
<image class="icon" src="/static/home/minus.png" mode="" />
|
|
</view>
|
|
<text
|
|
class="input"
|
|
@click="() => showKeyboard()"
|
|
>
|
|
{{ childs.sum }}
|
|
</text>
|
|
</block>
|
|
<view
|
|
v-if="childs.stock != 0"
|
|
class="add"
|
|
data-quantity="1"
|
|
data-id="{{childs.id}}"
|
|
data-chuxiao="{{childs.chuxiao}}"
|
|
data-exa="sum"
|
|
@click="() => setSum(childs)"
|
|
>
|
|
<image class="icon" src="/static/home/add.png" mode="" />
|
|
</view>
|
|
<text v-if="childs.stock == 0" class="no-stock">
|
|
补货中
|
|
</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view
|
|
v-if="!isSearching
|
|
&& products.length !== 0
|
|
&& currentType != typeData.length - 1"
|
|
class="next"
|
|
@click="onGotoNext"
|
|
>
|
|
<text>上划或点击进入</text>
|
|
<text style="color: #3aa24b;">
|
|
{{ typeData[currentType + 1].name }}
|
|
</text>
|
|
</view>
|
|
</view>
|
|
<view
|
|
v-if="products.length === 0"
|
|
:style="{
|
|
fontSize: '29rpx',
|
|
color: '#666666',
|
|
textAlign: 'center',
|
|
marginTop: '30rpx',
|
|
}"
|
|
>
|
|
暂无商品~
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
|
|
<!-- 输入购买数量弹框 -->
|
|
<!-- <modal
|
|
v-show="!hiddenModal"
|
|
title="修改购买数量"
|
|
confirm-text="确定"
|
|
cancel-text="取消"
|
|
@confirm="onModelConfirm"
|
|
@cancel="onModelCancel"
|
|
>
|
|
<input
|
|
placeholder="输入所需数量"
|
|
focus="{{focus}}"
|
|
:value="inputValue"
|
|
type="number"
|
|
@input="input"
|
|
>
|
|
</modal> -->
|
|
|
|
<customTabBar tab-index="1" />
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
@import './classification.scss';
|
|
</style>
|