6
0
Fork 0
hui.zhou
ihzero 2023-02-09 15:18:56 +08:00
parent 9740568620
commit 61fddda672
10 changed files with 2213 additions and 288 deletions

View File

@ -9,6 +9,9 @@
<block v-if="showShrough">
<view v-if="goods['market_price']!=undefined && goods.market_price" class="fontFam line-through text-txGray text-20rpx">{{goods.market_price}}</view>
</block>
<view v-if="cart" @click.stop="onCart">
<u-icon size="46" color="#f0ad4e" name="shopping-cart"></u-icon>
</view>
</view>
<view class="flex items-center justify-between">
<view class="flex items-center">
@ -19,6 +22,7 @@
<view v-if="isCollection">
<u-icon size="36" color="#f0ad4e" name="star-fill"></u-icon>
</view>
</view>
</view>
</view>
@ -42,12 +46,20 @@ export default {
showShrough:{
type:Boolean,
default:false
},
cart:{
type:Boolean,
default:false
}
},
data() {
return {};
},
methods: {},
methods: {
onCart(){
this.$emit('cartClick',this.goods)
}
},
};
</script>
<style lang="scss" scoped>
@ -56,7 +68,7 @@ export default {
}
.fontFam{
/* #ifdef APP-PLUS */
font-family: "宋体";
/* #endif */
font-family: "宋体";
/* #endif */
}
</style>

View File

@ -0,0 +1,263 @@
<template>
<view>
<cu-navbar class="cu-navbar" :background="{ background: '#f5f5f5' }" :border-bottom="false" :isBack="false" :title="`购物车(${cartList.length})`">
<view slot="left" class="flex items-center pl-base text-xl font-medium text-txBase font-extrabold">
<!-- 左边返回箭头 -->
<view class="w-20rpx flex items-center mr-10rpx" @tap="back" v-if="isBack">
<image class="w-20rpx" src="/static/images/user/left_arrow.png" mode="widthFix"></image>
</view>
<!-- <view>购物车<text class="text-md">({{ cartList.length }})</text></view> -->
</view>
<!-- <view slot="right" class="mx-base relative" @tap="$u.route('/pageA/news/index')">
<u-icon name="chat" size="48"></u-icon>
<u-badge :is-dot="true" size="16" :offset="[0, 2]" type="warning"></u-badge>
</view> -->
<block v-if="isLogin">
<view class="pl-base text-xl font-medium text-txBase" @tap="changeEdit">
{{ navBarLeftText }}
</view>
</block>
</cu-navbar>
<!-- 已登录 -->
<block v-if="cartList.length > 0">
<view class="bg-white rounded-xs card mx-base">
<block v-for="(item, index) in cartList" :key="item.id">
<cart-goods-item
:data="item"
:goods="item.sku"
:selected="isSelect(item)"
@select="onSelect"
@tap="onGoodsClick"
@num-change="onNumChange"
:isEdit="isEdit"
></cart-goods-item>
<u-line color="#E5E5E5" v-if="index != cartList.length - 1" />
</block>
</view>
<view class="fixed inset-x-0 bg-white px-18rpx py-20rpx bottom-card z-99">
<view class="flex w-full items-end">
<view class="flex items-end">
<view class="flex items-center" @tap="selectAll = !selectAll">
<image v-if="selectAll" class="w-32rpx h-32rpx flex-none mr-17rpx" src="/static/images/cart/check-round-fill.png" mode="scaleToFill" />
<image v-else class="w-32rpx h-32rpx flex-none mr-17rpx" src="/static/images/cart/check-round.png" mode="scaleToFill" />
<text class="text-lg">全选</text>
</view>
<view class="ml-30rpx">
<text> {{ cartList.length }} </text>
</view>
</view>
<block v-if="isEdit">
<view class="flex-1"></view>
<view>
<view :disabled="selectedCart.length == 0" class="btn btn-primary rounded-full text-lg px-30rpx py-10rpx" @tap="delShow = true">
移除
</view>
</view>
</block>
<block v-else>
<view class="flex-1 text-right text-xl mr-20rpx">
<text>合计:</text>
<text class="text-txSvip">{{ calculate.amount }}</text>
</view>
<view>
<view @tap="onSubmit" class="btn btn-primary rounded-full text-lg px-30rpx py-10rpx"> 确认下单 </view>
</view>
</block>
</view>
</view>
<view class="box-shdow inset-x-0 h-2rpx fixed bottom-card z-99"></view>
<view class="h-148rpx"></view>
</block>
<!-- 未登录 -->
<block v-else>
<view class="flex items-center justify-center flex-col bg-white py-100rpx">
<image src="/static/images/cart/empty-cart.png" class="w-300rpx h-254rpx" mode="scaleToFill" />
<view class="text-txGray text-md">购物车是空的</view>
<view class="w-full px-150rpx flex items-center mt-50rpx text-txBase text-md mx-100rpx justify-between">
<view @tap="jumpIndex" class="w-180rpx h-55rpx border border-txBase leading-55rpx text-center rounded-full"> 去逛逛</view>
<view @tap="$u.routeAuth('/pageA/collection/index')" class="w-180rpx h-55rpx border border-txBase leading-55rpx text-center rounded-full"
>看看关注</view
>
</view>
</view>
</block>
<!-- 删除提示 -->
<cu-modal
v-model="delShow"
:content="`确定要删除${selectedCart.length}种商品吗?`"
show-cancel-button
async-close
@confirm="delConfirm"
></cu-modal>
</view>
</template>
<script>
import CartGoodsItem from '@/pages/shop_cart/components/cart-goods-item.vue';
import { mapActions, mapGetters } from 'vuex';
import { add, mcl } from '@/utils';
import CartMixin from '@/pages/shop_cart/mixin';
export default {
mixins: [CartMixin],
components: {
CartGoodsItem,
},
props: {
isBack: {
type: Boolean,
default: false,
},
},
data() {
return {
delShow: false,
isEdit: false,
calculate: {
amount: 0,
},
};
},
onShow() {
this.getCartList();
},
computed: {
...mapGetters(['cartList', 'selectedCart']),
navBarLeftText() {
return this.isEdit ? '完成' : '管理';
},
selectAll: {
set(val) {
this.setSelectedCart(val ? this.cartList.map((e) => e.id) : []);
},
get() {
return this.cartList.length == this.selectedCart.length && this.cartList.length > 0;
},
},
selectedCorrect() {
return this.selectedCart?.filter((id) => this.cartList.findIndex((e) => e.id == id && e.sku.is_online) >= 0) ?? [];
},
height() {
const { windowHeight, statusBarHeight } = this.$u.sys();
return windowHeight - statusBarHeight - 44 + 'px';
},
},
methods: {
...mapActions({
getCartList: 'goods/getCartList',
setSelectedCart: 'goods/setSelectedCart',
}),
//
onSubmit() {
if (this.selectedCorrect.length == 0) return this.$u.toast('请选择需要结算的商品');
const params = {
cards: this.selectedCorrect,
type: 'cart',
};
this.$u.route('/pages/confirm_order/confirm_order?data=' + encodeURIComponent(JSON.stringify(params)));
},
//
async onNumChange(value, id) {
await this.$api.put(
`/v1/shopping-cart-items/${id}`,
{
quantity: value,
},
{
custom: {
loading: true,
},
},
);
this.getCartList();
},
//
async delConfirm() {
if (this.selectedCart.length == 0) return this.$u.toast('您还未选择商品哦');
await this.$api.delete(
'/v1/shopping-cart-items',
{ ids: this.selectedCart },
{
custom: {
loading: true,
},
},
);
this.delShow = false;
this.getCartList();
},
//
changeEdit() {
this.isEdit = !this.isEdit;
},
//
onSelect(id, selected) {
if (selected) {
this.setSelectedCart([...this.selectedCart, id]);
} else {
this.setSelectedCart(this.selectedCart.filter((e) => id != e));
}
},
//
onGoodsClick(e) {
if (this.isEdit) return false;
this.$u.route('/pages/product_details/index', {
skuId: e.id,
});
},
//
getCalculateAmount() {
const { is_vip } = this.$store.getters?.user ?? false;
const amount = this.cartList.reduce((pr, cu) => {
if (this.selectedCart.findIndex((e) => e == cu.id) >= 0) pr = add(mcl(is_vip ? cu.sku.vip_price : cu.sku.sell_price, cu.quantity), pr);
return pr;
}, 0);
this.calculate.amount = amount;
},
//
isSelect({ id }) {
return this.selectedCart.some((item) => item == id);
},
back() {
uni.navigateBack({
delta: 1,
});
},
jumpIndex() {
uni.switchTab({
url: '/pages/index/index',
});
},
},
watch: {
selectedCart: {
immediate: true,
handler(e) {
this.getCalculateAmount();
// console.log(e);
},
},
},
};
</script>
<style lang="scss" scoped>
.card {
box-shadow: 0px 2px 6px rgba(0, 0, 0, 0.08);
}
.bottom-card {
box-shadow: 0px -4rpx 8rpx rgba(0, 0, 0, 0.25);
bottom: var(--window-bottom);
}
.bottom-h {
padding: var(--window-bottom);
}
.box-shdow {
box-shadow: 0px 2px 6px rgba(0, 0, 0, 0.25);
background: #ffffff;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,249 @@
<template>
<view class="">
<view class="flex items-center px-40rpx text-32rpx bg-white py-30rpx sticky top-0 z-99">
<view class="mr-15rpx">商品信息</view>
<u-search @search="searchGoods" class="flex-1" placeholder="货号或名称" v-model="keyword" :show-action="false">
</u-search>
<u-icon @tap="onQR" class="ml-20rpx" name="scan" color="#333333" size="48"></u-icon>
</view>
<!-- 有商品时 -->
<block v-if="!isShow">
<!-- 搜索的商品列表 -->
<view class="px-30rpx bg-white" v-if="goodsList.length">
<block v-for="(item,index) in goodsList" :key="index">
<GoodsItem :isAdd="true" :goods="item" @addGood="addGood" />
</block>
</view>
<view v-if="chooseList.length>0" class="py-20rpx text-40rpx font-extrabold text-center"></view>
<!-- 提货数量 -->
<view class=" bg-white">
<u-swipe-action v-for="(item, index) in chooseList" :key="item.id" :show="item.show" :index="index" @click="click" @open="open" :options="options"
>
<view class="py-20rpx flex w-full items-start px-30rpx" >
<view
class="w-38rpx mt-8rpx h-38rpx rounded-full border border-hex-ef4444 border-solid text-center leading-38rpx text-hex-ef4444">
{{index+1}}
</view>
<view class="flex-1 ml-15rpx">
<view class="flex items-center">
<view class="flex flex-1 items-center justify-between">
<view>默认已提货量</view>
<view>
<u-number-box :min="0" v-model="item.defaultNum" :max="item.num">
</u-number-box>
</view>
</view>
</view>
<GoodsItem class="px-0" :goods="item" @numChange="numChange" />
</view>
</view>
<u-line v-if="chooseList.length-1!=index" :hair-line="false" color="#c8c9cc"></u-line>
</u-swipe-action>
</view>
<view class="h-180rpx"></view>
<!-- 底部按钮 -->
<view class="flex items-center justify-end bg-white bottom-card z-99 fixed inset-x-0">
<view class="flex items-center">
<view>
合计
<text class="ml-10rpx price-text text-hex-ef4444">{{totalPrice}}</text>
</view>
<view class="ml-10rpx">
vip
<text class="ml-10rpx price-text text-hex-ef4444">{{vipPrice}}</text>
</view>
</view>
<view @click="qrCode" class="bg-hex-ef4444 h-100rpx w-210rpx text-white text-center leading-100rpx ml-30rpx">
生成二维码</view>
</view>
</block>
<!-- 无商品时 -->
<block v-else>
<view class="flex items-center justify-center flex-col mt-80rpx">
<image src="http://cdn.uviewui.com/uview/empty/car.png" mode="aspectFill"></image>
<view class="text-hex-909399 -mt-20rpx">请搜索您需要的商品</view>
</view>
</block>
<cu-modal v-model="modeShow" @confirm="confirm" confirm-color="#378264" show-cancel-button content="是否生成二维码?"
confirmText="确认" cancelText="再想想">
</cu-modal>
</view>
</template>
<script>
import GoodsItem from './components/goods-item.vue'
export default {
components: {
GoodsItem
},
data() {
return {
modeShow: false,
isShow: true,
id: '',
keyword: '',
list: [], //
chooseList: [], //
goodItem: {},
options: [
{
text: '删除',
style: {
backgroundColor: '#ef4444'
}
}
]
};
},
onLoad({
id
}) {
this.id = id
},
computed: {
//
totalPrice() {
const total = this.chooseList.reduce((pr, cu) => {
return pr + cu.sell_price * cu.num
}, 0)
return total.toFixed(2)
},
//
vipPrice() {
const total = this.chooseList.reduce((pr, cu) => {
return pr + cu.vip_price * cu.num
}, 0)
return total.toFixed(2)
},
goodsList(){
return this.list?.map(e=>{
return {
...e,
defaultNum:1,
num:1
}
})
}
},
methods: {
click(index,index1) {
if(index1==0){
this.$nextTick(()=>{
this.chooseList.splice(index, 1)
this.chooseList[index].show = false;
})
}
},
open(index) {
this.chooseList[index].show = true;
this.chooseList.forEach((val, idx) => {
if(index != idx) this.chooseList[idx].show = false;
})
},
//
onQR(){
uni.scanCode({
onlyFromCamera: true,
success: ({result})=>{
this.keyword=result
this.searchGoods()
},
fail:err=>{
this.$u.toast('扫码失败,请重新扫描')
}
});
},
async searchGoods() {
const resDate = await this.$api.get(`/v1/store/${this.id}/products`, {
params: {
keyword: this.keyword
}
})
this.list = resDate.data
if (this.list.length == 0) {
return this.$u.toast('暂未搜索到该商品')
}
this.isShow = false
// this.goodList=
// let goodsObj = resDate.data.length > 0 ? resDate.data[0] : {}
// goodsObj.defaultNum = 1
// goodsObj.num = 1
// this.goodItem = goodsObj
},
//
addGood(e) {
const result = this.chooseList.findIndex(item => item.id == e)
if (result == -1) {
const goodsItem=this.goodsList?.find(el=>el.id==e)
this.chooseList.push(Object.assign(goodsItem,{show:false}))
} else {
const num = this.chooseList[result].num + 1
this.getUpdate(result, num)
}
},
//
numChange(id, value) {
const Index = this.chooseList.findIndex(item => item.id == id)
this.getUpdate(Index, value)
},
//
getUpdate(Index, val) {
this.chooseList[Index].num = val
this.chooseList[Index].defaultNum = val
this.chooseList = [...this.chooseList]
},
qrCode() {
if (this.chooseList.length == 0) {
return this.$u.toast('至少选选择一件商品')
}
this.modeShow = true
},
//
async confirm() {
uni.showLoading({
title: '二维码生成中',
mask: true
});
try {
const arrList = this.chooseList.map(item => {
return {
sku_id: item.id,
quantity: item.num,
send: item.defaultNum
}
})
const obj = {
store_id: this.id,
products: arrList,
note: ''
}
const {
image
} = await this.$api.post(`/v1/order-pre`, obj);
this.$u.route('/pageB/code/index', {
image
})
this.keyword = ''
this.list = []
this.chooseList = []
this.goodItem = {}
this.isShow = true
uni.hideLoading()
} catch (err) {}finally{
}
}
}
}
</script>
<style>
</style>
<style lang="scss">
.bottom-card {
box-shadow: 0px -4rpx 8rpx rgba(0, 0, 0, 0.25);
bottom: var(--window-bottom);
}
</style>

View File

@ -1,249 +1,305 @@
<template>
<view class="">
<view class="flex items-center px-40rpx text-32rpx bg-white py-30rpx sticky top-0 z-99">
<view class="mr-15rpx">商品信息</view>
<u-search @search="searchGoods" class="flex-1" placeholder="货号或名称" v-model="keyword" :show-action="false">
</u-search>
<u-icon @tap="onQR" class="ml-20rpx" name="scan" color="#333333" size="48"></u-icon>
</view>
<!-- 有商品时 -->
<block v-if="!isShow">
<!-- 搜索的商品列表 -->
<view class="px-30rpx bg-white" v-if="goodsList.length">
<block v-for="(item,index) in goodsList" :key="index">
<GoodsItem :isAdd="true" :goods="item" @addGood="addGood" />
</block>
<view class="u-wrap">
<view class="u-search-box bg-white">
<view class="flex items-center">
<view class="mr-15rpx">商品信息</view>
<u-search class="flex-1" placeholder="货号或名称" :show-action="false"> </u-search>
<u-icon class="ml-20rpx" name="scan" color="#333333" size="48"></u-icon>
</view>
<view v-if="chooseList.length>0" class="py-20rpx text-40rpx font-extrabold text-center"></view>
<!-- 提货数量 -->
<view class=" bg-white">
<u-swipe-action v-for="(item, index) in chooseList" :key="item.id" :show="item.show" :index="index" @click="click" @open="open" :options="options"
>
<view class="py-20rpx flex w-full items-start px-30rpx" >
<view
class="w-38rpx mt-8rpx h-38rpx rounded-full border border-hex-ef4444 border-solid text-center leading-38rpx text-hex-ef4444">
{{index+1}}
</view>
<view class="flex-1 ml-15rpx">
<view class="flex items-center">
<view class="flex flex-1 items-center justify-between">
<view>默认已提货量</view>
<view>
<u-number-box :min="0" v-model="item.defaultNum" :max="item.num">
</u-number-box>
</view>
</view>
<view class="u-menu-wrap">
<scroll-view scroll-y scroll-with-animation class="u-tab-view menu-scroll-view" :scroll-top="scrollTop" :scroll-into-view="itemId">
<view
v-for="(item, index) in tabbar"
:key="index"
class="u-tab-item"
:class="[current == index ? 'u-tab-item-active' : '']"
@tap.stop="swichMenu(index)"
>
<text class="u-line-1">{{ item.name }}</text>
</view>
</scroll-view>
<scroll-view :scroll-top="scrollRightTop" scroll-y scroll-with-animation class="right-box" @scroll="rightScroll">
<view class="page-view">
<view class="class-item" :id="'item' + index" v-for="(item, index) in tabbar" :key="index">
<view class="item-title">
<text>{{ item.name }}</text>
</view>
<view class="item-container">
<view class="thumb-box" v-for="(item1, index1) in item.foods" :key="index1" @tap="$u.route('/pageB/select_product/search?category=20')">
<image class="item-menu-image" :src="item1.icon" mode=""></image>
<view class="item-menu-name">{{ item1.name }}</view>
</view>
</view>
<GoodsItem class="px-0" :goods="item" @numChange="numChange" />
</view>
</view>
<u-line v-if="chooseList.length-1!=index" :hair-line="false" color="#c8c9cc"></u-line>
</u-swipe-action>
</view>
<view class="h-180rpx"></view>
<!-- 底部按钮 -->
<view class="flex items-center justify-end bg-white bottom-card z-99 fixed inset-x-0">
<view class="flex items-center">
<view>
合计
<text class="ml-10rpx price-text text-hex-ef4444">{{totalPrice}}</text>
</view>
<view class="ml-10rpx">
vip
<text class="ml-10rpx price-text text-hex-ef4444">{{vipPrice}}</text>
</view>
</view>
<view @click="qrCode" class="bg-hex-ef4444 h-100rpx w-210rpx text-white text-center leading-100rpx ml-30rpx">
生成二维码</view>
</view>
</block>
<!-- 无商品时 -->
<block v-else>
<view class="flex items-center justify-center flex-col mt-80rpx">
<image src="http://cdn.uviewui.com/uview/empty/car.png" mode="aspectFill"></image>
<view class="text-hex-909399 -mt-20rpx">请搜索您需要的商品</view>
</view>
</block>
<cu-modal v-model="modeShow" @confirm="confirm" confirm-color="#378264" show-cancel-button content="是否生成二维码?"
confirmText="确认" cancelText="再想想">
</cu-modal>
</scroll-view>
</view>
</view>
</template>
<script>
import GoodsItem from './components/goods-item.vue'
export default {
components: {
GoodsItem
},
data() {
return {
modeShow: false,
isShow: true,
id: '',
keyword: '',
list: [], //
chooseList: [], //
goodItem: {},
options: [
{
text: '删除',
style: {
backgroundColor: '#ef4444'
}
}
]
};
},
onLoad({
id
}) {
this.id = id
},
computed: {
//
totalPrice() {
const total = this.chooseList.reduce((pr, cu) => {
return pr + cu.sell_price * cu.num
}, 0)
return total.toFixed(2)
},
//
vipPrice() {
const total = this.chooseList.reduce((pr, cu) => {
return pr + cu.vip_price * cu.num
}, 0)
return total.toFixed(2)
},
goodsList(){
return this.list?.map(e=>{
return {
...e,
defaultNum:1,
num:1
}
})
import classifyData from './classify.data.js';
export default {
data() {
return {
scrollTop: 0, //tab
oldScrollTop: 0,
current: 0, //
menuHeight: 0, //
menuItemHeight: 0, // item
itemId: '', // scroll-viewid
tabbar: classifyData,
menuItemPos: [],
arr: [],
scrollRightTop: 0, // scroll-view
timer: null, //
};
},
onLoad() {},
onReady() {
this.getMenuItemTop();
},
methods: {
//
async swichMenu(index) {
if (this.arr.length == 0) {
await this.getMenuItemTop();
}
if (index == this.current) return;
this.scrollRightTop = this.oldScrollTop;
this.$nextTick(function () {
this.scrollRightTop = this.arr[index];
this.current = index;
this.leftMenuStatus(index);
});
},
methods: {
click(index,index1) {
if(index1==0){
this.$nextTick(()=>{
this.chooseList.splice(index, 1)
this.chooseList[index].show = false;
//
getElRect(elClass, dataVal) {
new Promise((resolve, reject) => {
const query = uni.createSelectorQuery().in(this);
query
.select('.' + elClass)
.fields(
{
size: true,
},
(res) => {
// resnull
if (!res) {
setTimeout(() => {
this.getElRect(elClass);
}, 10);
return;
}
this[dataVal] = res.height;
resolve();
},
)
.exec();
});
},
//
async observer() {
this.tabbar.map((val, index) => {
let observer = uni.createIntersectionObserver(this);
// scroll-viewiditemxxright-box
// .right-box
observer
.relativeTo('.right-box', {
top: 0,
})
}
},
open(index) {
this.chooseList[index].show = true;
this.chooseList.forEach((val, idx) => {
if(index != idx) this.chooseList[idx].show = false;
})
},
//
onQR(){
uni.scanCode({
onlyFromCamera: true,
success: ({result})=>{
this.keyword=result
this.searchGoods()
},
fail:err=>{
this.$u.toast('扫码失败,请重新扫描')
}
});
},
async searchGoods() {
const resDate = await this.$api.get(`/v1/store/${this.id}/products`, {
params: {
keyword: this.keyword
}
})
this.list = resDate.data
if (this.list.length == 0) {
return this.$u.toast('暂未搜索到该商品')
}
this.isShow = false
// this.goodList=
// let goodsObj = resDate.data.length > 0 ? resDate.data[0] : {}
// goodsObj.defaultNum = 1
// goodsObj.num = 1
// this.goodItem = goodsObj
},
//
addGood(e) {
const result = this.chooseList.findIndex(item => item.id == e)
if (result == -1) {
const goodsItem=this.goodsList?.find(el=>el.id==e)
this.chooseList.push(Object.assign(goodsItem,{show:false}))
} else {
const num = this.chooseList[result].num + 1
this.getUpdate(result, num)
}
},
//
numChange(id, value) {
const Index = this.chooseList.findIndex(item => item.id == id)
this.getUpdate(Index, value)
},
//
getUpdate(Index, val) {
this.chooseList[Index].num = val
this.chooseList[Index].defaultNum = val
this.chooseList = [...this.chooseList]
},
qrCode() {
if (this.chooseList.length == 0) {
return this.$u.toast('至少选选择一件商品')
}
this.modeShow = true
},
//
async confirm() {
uni.showLoading({
title: '二维码生成中',
mask: true
});
try {
const arrList = this.chooseList.map(item => {
return {
sku_id: item.id,
quantity: item.num,
send: item.defaultNum
.observe('#item' + index, (res) => {
if (res.intersectionRatio > 0) {
let id = res.id.substring(4);
this.leftMenuStatus(id);
}
})
const obj = {
store_id: this.id,
products: arrList,
note: ''
}
const {
image
} = await this.$api.post(`/v1/order-pre`, obj);
this.$u.route('/pageB/code/index', {
image
})
this.keyword = ''
this.list = []
this.chooseList = []
this.goodItem = {}
this.isShow = true
uni.hideLoading()
} catch (err) {}finally{
}
});
});
},
//
async leftMenuStatus(index) {
this.current = index;
// 0
if (this.menuHeight == 0 || this.menuItemHeight == 0) {
await this.getElRect('menu-scroll-view', 'menuHeight');
await this.getElRect('u-tab-item', 'menuItemHeight');
}
}
}
// item
this.scrollTop = index * this.menuItemHeight + this.menuItemHeight / 2 - this.menuHeight / 2;
},
// item
getMenuItemTop() {
new Promise((resolve) => {
let selectorQuery = uni.createSelectorQuery();
selectorQuery
.selectAll('.class-item')
.boundingClientRect((rects) => {
// rects[](selectAll)
if (!rects.length) {
setTimeout(() => {
this.getMenuItemTop();
}, 10);
return;
}
rects.forEach((rect) => {
// rects[0].top()
this.arr.push(rect.top - rects[0].top);
resolve();
});
})
.exec();
});
},
//
async rightScroll(e) {
this.oldScrollTop = e.detail.scrollTop;
if (this.arr.length == 0) {
await this.getMenuItemTop();
}
if (this.timer) return;
if (!this.menuHeight) {
await this.getElRect('menu-scroll-view', 'menuHeight');
}
setTimeout(() => {
//
this.timer = null;
// scrollHeight
let scrollHeight = e.detail.scrollTop + this.menuHeight / 2;
for (let i = 0; i < this.arr.length; i++) {
let height1 = this.arr[i];
let height2 = this.arr[i + 1];
// height2
if (!height2 || (scrollHeight >= height1 && scrollHeight < height2)) {
this.leftMenuStatus(i);
return;
}
}
}, 10);
},
},
};
</script>
<style>
</style>
<style lang="scss">
.bottom-card {
box-shadow: 0px -4rpx 8rpx rgba(0, 0, 0, 0.25);
bottom: var(--window-bottom);
}
<style lang="scss" scoped>
.u-wrap {
height: calc(100vh);
/* #ifdef H5 */
height: calc(100vh - var(--window-top));
/* #endif */
display: flex;
flex-direction: column;
}
.u-search-box {
padding: 18rpx 30rpx;
}
.u-menu-wrap {
flex: 1;
display: flex;
overflow: hidden;
}
.u-search-inner {
background-color: rgb(234, 234, 234);
border-radius: 100rpx;
display: flex;
align-items: center;
padding: 10rpx 16rpx;
}
.u-search-text {
font-size: 26rpx;
color: $u-tips-color;
margin-left: 10rpx;
}
.u-tab-view {
width: 200rpx;
height: 100%;
}
.u-tab-item {
height: 110rpx;
background: #f6f6f6;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
font-size: 26rpx;
color: #444;
font-weight: 400;
line-height: 1;
}
.u-tab-item-active {
position: relative;
color: #000;
font-size: 30rpx;
font-weight: 600;
background: #fff;
}
.u-tab-item-active::before {
content: '';
position: absolute;
border-left: 4px solid $u-type-primary;
height: 32rpx;
left: 0;
top: 39rpx;
}
.u-tab-view {
height: 100%;
}
.right-box {
background-color: rgb(250, 250, 250);
}
.page-view {
padding: 16rpx;
}
.class-item {
margin-bottom: 30rpx;
background-color: #fff;
padding: 16rpx;
border-radius: 8rpx;
}
.class-item:last-child {
min-height: 100vh;
}
.item-title {
font-size: 26rpx;
color: $u-main-color;
font-weight: bold;
}
.item-menu-name {
font-weight: normal;
font-size: 24rpx;
color: $u-main-color;
}
.item-container {
display: flex;
flex-wrap: wrap;
}
.thumb-box {
width: 33.333333%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
margin-top: 20rpx;
}
.item-menu-image {
width: 120rpx;
height: 120rpx;
}
</style>

View File

@ -0,0 +1,222 @@
<template>
<view>
<u-navbar :border-bottom="false" back-icon-color="#000000" :background="{ background: '#ffffff' }">
<view class="w-full">
<u-search placeholder="搜索商品" @change="Change" @search="Search" v-model="searchText" :show-action="false"></u-search>
</view>
<view slot="right" class="pr-26rpx pl-14rpx flex items-center" @tap="$u.route('/pageB/select_product/cart')">
<image class="w-48rpx h-48rpx" src="/static/images/cart/short-cart.png" mode="scaleToFill" />
</view>
</u-navbar>
<!-- tabs -->
<view class="fixed left-0 right-0 z-8 text-txGray text-lg w-full bg-white h-90rpx shadow-down flex items-center justify-around">
<view @tap.stop="handType('')" :class="!sort ? 'text-primary' : ''">综合</view>
<view @tap.stop="onPriceSort" class="flex items-center" :class="sort == 'price' || sort == '-price' ? 'text-primary' : ''">
<view>价格</view>
<view>
<trigonometry :key="'a' + key" direction="up" :color="sort == 'price' ? '#378264' : '#808080'"></trigonometry>
<trigonometry :key="'b' + key" direction="down" :color="sort == '-price' ? '#378264' : '#808080'"></trigonometry>
</view>
</view>
<view @tap.stop="onSaleSort" :class="sort == 'sales' || sort == '-sales' ? 'text-primary' : ''" class="flex items-center">
<view>销量</view>
<view class="flex items-center justify-center flex-col ml-5rpx">
<trigonometry :key="'c' + key" direction="up" :color="sort == 'sales' ? '#378264' : '#808080'"></trigonometry>
<trigonometry :key="'d' + key" direction="down" :color="sort == '-sales' ? '#378264' : '#808080'"></trigonometry>
</view>
</view>
<view @tap.stop="handType('release_at')" :class="sort == 'release_at' ? 'text-primary' : ''">上新</view>
</view>
<mescroll-body
top="90"
:height="height"
ref="mescrollRef"
@init="mescrollInit"
@down="downCallback"
@up="upCallback"
:down="downOption"
:up="upOption"
>
<view class="px-rowSm mt-20rpx">
<u-waterfall v-model="dataList" ref="uWaterfall">
<template v-slot:left="{ leftList }">
<view v-for="(item, index) in leftList" :key="index" class="px-rowSm mb-base">
<goods-item :goods="item" cart @cartClick="cartClick"></goods-item>
</view>
</template>
<template v-slot:right="{ rightList }">
<view v-for="(item, index) in rightList" :key="index" class="px-rowSm mb-base">
<goods-item :goods="item" cart @cartClick="cartClick"></goods-item>
</view>
</template>
</u-waterfall>
</view>
</mescroll-body>
<!-- 规格弹窗 -->
<spec-popup
:key="productId"
:loading="loading"
:specs="specs"
:sku="detail"
v-model="show"
:quota-used="number"
:show-cart="popupType == 1 || popupType == 0"
:show-buy="popupType == 2 || popupType == 0"
:show-confirm="popupType == 3"
@add-cart="onAddCart"
@stepper-change="onChangeNumber"
>
</spec-popup>
<u-mask :show="loading">
<view style="display: flex; justify-content: center; align-items: center; height: 100%">
<text style="color: white">加载中</text>
<u-loading mode="flower" size="60" />
</view>
</u-mask>
</view>
</template>
<script>
import MescrollMixin from '@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js';
export default {
mixins: [MescrollMixin],
data() {
return {
key: 0,
sort: '', //price sales release_at price -price
searchText: '',
category: '',
loading: false,
popupType: 1,
number: 1,
products: {},
productId: '',
skuId: '',
downOption: {
auto: false,
},
upOption: {
page: {
size: 20,
},
noMoreSize: 1,
},
show: false,
dataList: [], //
};
},
computed: {
specs() {
return this.products?.spu_specs ?? [];
},
detail() {
return this.products?.sku ?? {};
},
height() {
const { windowHeight, statusBarHeight } = this.$u.sys();
return windowHeight - statusBarHeight - 44 + 'px';
},
},
onLoad({ searchText, category }) {
this.searchText = searchText;
this.category = category;
},
methods: {
Change(e) {
if (e == '') uni.navigateBack();
},
Search() {
this.category = '';
this.downCallback();
},
onChangeNumber(e) {
this.number = e;
console.log(e);
},
//
async cartClick(e) {
this.productId = e.id;
this.number = 1;
await this.getProducts();
this.show = true;
console.log(e);
},
onAddCart(e) {
console.log('添加到购物车数量:' + this.number);
console.log(e);
},
//
async getProducts() {
try {
this.loading = true;
const resData = await this.$api.get(`/v1/product/products/${this.productId}`);
this.products = resData;
this.skuId = this.products?.sku.id;
} catch (error) {
console.log(error);
} finally {
this.loading = false;
}
},
downCallback() {
this.dataList = [];
this.$refs.uWaterfall.clear();
this.mescroll.resetUpScroll();
},
async upCallback(page) {
this.loadData(page);
},
loadData(page) {
let obj = {
page: page.num,
per_page: page.size,
category: this.category,
keyword: this.searchText,
sort: this.sort,
};
this.$api
.get(`/v1/product/products`, {
params: obj,
})
.then((res) => {
this.mescroll.endSuccess(res.data.length);
if (page.num == 1) this.dataList = [];
this.dataList = this.dataList.concat(res.data);
})
.catch((err) => {
this.mescroll.endErr();
});
},
//
handType(val) {
if (this.sort == val) return;
this.$u.throttle(() => {
this.sort = val;
this.downCallback();
});
},
//
onPriceSort() {
this.Refresh();
this.sort = this.sort == 'price' ? '-price' : 'price';
this.downCallback();
},
//
onSaleSort() {
this.Refresh();
this.sort = this.sort == 'sales' ? '-sales' : 'sales';
this.downCallback();
},
//
Refresh() {
this.$nextTick(() => {
this.key++;
});
},
},
};
</script>
<style lang="scss"></style>

View File

@ -1,14 +1,28 @@
<template>
<view class=" text-30rpx font-extrabold">
<loading-view v-if="isFirstLoading"></loading-view>
<mescroll-body ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="upCallback"
:down="downOption" :up="upOption">
<view class="grid grid-cols-2 gap-x-80rpx pt-20rpx px-80rpx">
<view @click="$u.route('/pageB/select_product/index',{id:item.id})" class="flex items-center justify-center flex-col mt-40rpx"
v-for="(item,index) in dataList" :key="index">
<u-image class="flex-none" width="240" height="240" :src="item.image" :lazy-load="true">
</u-image>
<view class="mt-15rpx">{{item.title}}</view>
<view class="">
<loading-view v-if="isFirstLoading"></loading-view>
<view class="text-center text-42rpx pt-30rpx">
线上预约店
</view>
<view class="my-20rpx px-20rpx">
<image @click="$u.route('/pageB/select_product/index', { id: 0 })" mode="widtFix" class="w-full h-250rpx rounded-15rpx" src="/static/images/user/u=2313295534,3451005153&fm=253&fmt=auto&app=138&f=JPEG.webp"></image>
</view>
<view class="my-20rpx px-20rpx">
<u-line></u-line>
</view>
<view class="text-center text-42rpx">
线下预约店
</view>
<mescroll-body ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="upCallback" :down="downOption" :up="upOption">
<view class="grid grid-cols-2 gap-x-80rpx pt-20rpx px-80rpx">
<view
@click="$u.route('/pageB/select_product/index', { id: item.id })"
class="flex items-center justify-center flex-col mt-40rpx text-30rpx font-extrabold"
v-for="(item, index) in dataList"
:key="index"
>
<u-image class="flex-none" width="240" height="240" :src="item.image" :lazy-load="true"> </u-image>
<view class="mt-15rpx leading-40rpx">{{ item.title }}</view>
</view>
</view>
</mescroll-body>
@ -16,52 +30,54 @@
</template>
<script>
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
export default {
mixins: [MescrollMixin], // 使mixin
data() {
return {
isFirstLoading:true,
downOption: {},
upOption: {
page: {
size: 20
},
noMoreSize: 1
import MescrollMixin from '@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js';
export default {
mixins: [MescrollMixin], // 使mixin
data() {
return {
isFirstLoading: true,
downOption: {},
upOption: {
page: {
size: 20,
},
dataList: [], //
};
},
onLoad() {
setTimeout(()=>{
this.isFirstLoading=false
},300)
},
methods: {
downCallback() {
this.mescroll.resetUpScroll();
this.dataList = []
noMoreSize: 1,
},
async upCallback(page) {
this.loadData(page);
},
loadData(page) {
this.$api.get(`/v1/store`, {
dataList: [], //
};
},
onLoad() {
setTimeout(() => {
this.isFirstLoading = false;
}, 300);
},
methods: {
downCallback() {
this.mescroll.resetUpScroll();
this.dataList = [];
},
async upCallback(page) {
this.loadData(page);
},
loadData(page) {
this.$api
.get(`/v1/store`, {
params: {
page: page.num,
per_page: page.size
}
}).then(res => {
this.mescroll.endSuccess(res.data.length)
per_page: page.size,
},
})
.then((res) => {
this.mescroll.endSuccess(res.data.length);
if (page.num == 1) this.dataList = [];
this.dataList = this.dataList.concat(res.data);
}).catch(err => {
this.mescroll.endErr()
})
},
}
};
.catch((err) => {
this.mescroll.endErr();
});
},
},
};
</script>
<style lang="scss" scoped>
</style>
<style lang="scss" scoped></style>

View File

@ -538,6 +538,22 @@
"navigationStyle": "default"
}
},
{
"path": "select_product/search",
"style": {
"navigationBarTitleText": "搜索商品",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
}
},
{
"path": "select_product/cart",
"style": {
"navigationBarTitleText": "搜索商品",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
}
},
{
"path": "select_product/com_order",
"style": {

View File

@ -186,10 +186,14 @@
</view>
</view>
</view>
<view class="w-710rpx bg-hex-f08003 text-white px-base m-auto rounded-xs mt-base text-center py-26rpx text-46rpx" v-if="is_company" @tap="$u.routeAuth('/pageB/select_store/index')">
帮用户下单
</view>
<!-- -->
<view class="w-710rpx bg-white px-base m-auto rounded-xs mt-base">
<!-- 销售端 -->
<view @tap="$u.routeAuth('/pageB/index/index')"
<!-- <view @tap="$u.routeAuth('/pageB/index/index')"
class="flex justify-between items-center py-base border-b border-txBorder" v-if="is_company">
<view class="flex items-center">
<image class="w-32rpx h-32rpx" src="/static/images/user/my_account.png" mode=""></image>
@ -198,7 +202,7 @@
<view>
<u-icon color="#383838" name="arrow-right" size="32"></u-icon>
</view>
</view>
</view> -->
<!-- #ifndef MP-WEIXIN -->
<view class="flex justify-between items-center py-base " @tap="$u.route(`/pages/web_view/index?url=${service}`)">
<view class="flex items-center">

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB