列表支持商品加入购物车

master
gongfuxiang 2023-03-21 18:33:17 +08:00
parent bab4daff52
commit be15ac41d9
20 changed files with 515 additions and 151 deletions

21
App.vue
View File

@ -45,7 +45,7 @@
is_online_service_fixed: 1,
// 使0 , 1 icon
category_goods_model_icon_type: 0,
// 使logologo->logo->->
// 使logologo->logo->->
is_logo_use_text: 0,
// 0 , 1
user_center_nav_show_model_type: 0,
@ -57,7 +57,7 @@
"/pages/user/user"
],
//
request_url: 'https://d1.shopxo.vip/',
request_url: 'http://shopxo.com/',
// publicpublichttps://d1.shopxo.vip/public/
static_url: 'http://shopxo.com/',
// default
@ -1470,7 +1470,11 @@
// applogo
get_application_logo() {
return this.get_config('config.home_site_logo_wap', this.data.application_logo);
var logo = this.data.application_logo || null;
if(logo == null) {
logo = this.get_config('config.home_site_logo_wap');
}
return logo
},
//
@ -1510,6 +1514,17 @@
return false;
}
return true;
},
//
get_page_object(page) {
var pages = getCurrentPages();
for(var i=0; i<pages.length; i++) {
if(pages[i]['route'] == page) {
return pages[i];
}
}
return null;
},
//

View File

@ -1,3 +1,27 @@
## v2.3.32023-000
* 商品列表使用统一组件
* 商品参数新增弹窗展示
* 初始访问登录页面优化
* 公共url打开支持地图、电话、外部小程序协议方式
* 适配手机底部横线
* 轮播兼容iphone圆角失效问题
* 用户中心菜单支持列表展示样式
* 搜索页面支持九方格和列表展示样式
* 分类支持参数指定跳转
* icon导航图标支持纯图片
* 分类和门店详情适配规格起购数及限购数
* 起购数和限购数提升 到商品规格级别
* 地址新增编号快速搜索选择
* 订单售后页面新增客服展示
* 购买和加购分离统一组件
* 提现初始错误修复
* 立即购买支持多商品
* 积分使用兑换不足提示
* 博客新增评论、点赞
* 新增组合搭配
* 新增列表快捷加入购物车
## v2.3.22022-11-30
* 门店详情支持多规格直接加购
* 分类页面支持多规格直接加购+购物车操作

View File

@ -654,26 +654,6 @@ button[disabled].bg-gray {
color: #333;
}
/**
*
*/
.floor-list .goods-list .goods {
width: calc(50% - 10rpx);
float: left;
padding-bottom: 10rpx;
margin-bottom: 20rpx;
}
.floor-list .goods-list .goods:nth-of-type(2n + 1) {
margin-right: 10rpx;
}
.floor-list .goods-list .goods:nth-of-type(2n) {
margin-left: 10rpx;
}
.floor-list .goods-list .goods .goods-img {
width: 100%;
height: 380rpx !important;
}
/**
*
*/
@ -777,6 +757,17 @@ button[disabled].bg-gray {
width: calc(100% - 120rpx);
}
/**
*
*/
.goods-list .cart-badge-icon {
top: -18rpx;
right: 8rpx;
}
.goods-list .right-cart-icon {
bottom: 10rpx;
right: 20rpx;
}
/**
* -
*/
@ -787,6 +778,11 @@ button[disabled].bg-gray {
.goods-data-list .base {
width: calc(100% - 220rpx);
}
.goods-data-list .base .base-bottom {
bottom: 20rpx;
right: 20rpx;
width: calc(100% - 260rpx);
}
/*
* -
*/

View File

@ -3,7 +3,7 @@
<view v-if="(propConfig || null) != null && (propData || null) != null && propData.length > 0">
<block v-for="(floor, index) in propData" :key="index">
<block v-if="floor.goods_list.length > 0 && floor.home_data_location == propLocation">
<component-goods-list :propData="floor" propMoreUrlKey="url" :propLabel="propLabel" :propIsAutoPlay="(propConfig.is_home_auto_play || 0) == 1" :propCurrencySymbol="propCurrencySymbol"></component-goods-list>
<component-goods-list :propData="floor" propMoreUrlKey="url" :propLabel="propLabel" :propIsAutoPlay="(propConfig.is_home_auto_play || 0) == 1" :propCurrencySymbol="propCurrencySymbol" :propIsCartParaCurve="propIsCartParaCurve"></component-goods-list>
</block>
</block>
</view>
@ -11,8 +11,7 @@
</template>
<script>
const app = getApp();
import componentGoodsList from "../goods-list/goods-list";
import componentGoodsList from "../goods-list/goods-list";
export default {
data() {
return {};
@ -40,6 +39,10 @@
propLabel: {
type: [Array,Object,String],
default: null
},
propIsCartParaCurve: {
type: Boolean,
default: false
}
},
methods: {}

View File

@ -34,13 +34,13 @@
right: 0;
transform: translate(50%, -50%);
top: 0px;
min-width: 16px;
min-width: 14px;
padding: 0;
height: 16px;
line-height: 16px;
height: 14px;
line-height: 14px;
text-align: center;
background-color: #FF3B30;
border-radius: 16px;
border-radius: 20px;
color: #fff;
font-size: 10px;
padding: 1px 1px;

View File

@ -68,10 +68,10 @@
background: linear-gradient(to right, rgb(255 235 220), rgb(241 235 255));
}
.plugins-binding-list .left-content {
width: 60%;
width: 65%;
}
.plugins-binding-list .right-content {
width: 40%;
width: 35%;
padding-top: 100rpx;
}
.plugins-binding-list .estimate-discount-price .discount-icon {

View File

@ -0,0 +1,103 @@
<template>
<view>
<view v-if="cart_icon_data != null && (cart_icon_data.status || 0) == 1" class="cart-para-curve-container pf round" :style="cart_icon_data.style">
<image v-if="(cart_icon_data.icon || null) != null" class="cart-para-curve-icon round br" :src="cart_icon_data.icon"></image>
<view v-else class="cart-para-curve-icon bg-red padding dis-inline-block round br"></view>
</view>
</view>
</template>
<script>
const app = getApp();
export default {
data() {
return {
cart_icon_data: null
};
},
components: {},
props: {
propBtnHeight: {
type: Number,
default: 30
},
propBtnWidth: {
type: Number,
default: 30
},
propCart: {
type: String,
default: ''
},
},
methods: {
//
init(cart, pos, icon = '') {
if((pos || null) != null) {
var self = this;
var btn_size = this.propBtnHeight;
var btn_width = this.propBtnWidth;
// tabbar
if((cart || null) == null || (cart[0] || null) == null) {
var info = uni.getSystemInfoSync();
var tabbar = app.globalData.data.tabbar_pages;
//
var tabbar_cart_pos = tabbar.indexOf('/pages/cart/cart');
if(tabbar_cart_pos == -1) {
return false;
}
//
var tabbar_count = tabbar.length;
var cart_top = info.screenHeight;
var cart_width = info.screenWidth/tabbar_count;
var cart_left = cart_width*tabbar_cart_pos;
} else {
var temp = cart[0];
var cart_width = temp.width;
var cart_left = temp.left;
var cart_top = temp.top;
}
var left = pos.detail.x + btn_width/2 - btn_size/2;
var top = pos.detail.y - btn_size;
var x = cart_left + cart_width/2 - btn_size/2 - left;
var y = cart_top - btn_size - top;
if(self.cart_icon_data == null || (self.cart_icon_data.status || 0) == 0) {
self.setData({cart_icon_data: {
status: 1,
style: `--left:${left}px;--top:${top}px;--x:${x}px;--y:${y}px;`,
icon: icon,
}});
setTimeout(function(){
self.setData({ cart_icon_data: {status: 0}});
}, 495);
}
}
}
}
};
</script>
<style>
@keyframes moveY {
to {
transform: translateY(var(--y));
}
}
@keyframes moveX {
to {
transform: translateX(var(--x));
}
}
.cart-para-curve-container {
width: 60rpx;
height: 60rpx;
z-index: 10;
left: var(--left);
top: var(--top);
--duration: 0.5s;
animation: moveY var(--duration) cubic-bezier(0.5, -0.25, 1, 1);
}
.cart-para-curve-container .cart-para-curve-icon {
max-width: 100%;
max-height: 100%;
animation: moveX var(--duration) linear;
}
</style>

View File

@ -6,25 +6,27 @@
<uni-swipe-action>
<view v-for="(item, index) in data_list" :key="index" class="oh border-radius-main bg-white spacing-mb">
<uni-swipe-action-item :right-options="swipe_options" @click="swipe_opt_event" @change="swipe_change($event, index)">
<view :class="'cart-goods-item wh-auto padding-main pr ' + (common_site_type == 1 ? 'cart-exhibition-mode-data' : '')">
<view :class="'cart-goods-item padding-main pr ' + (common_site_type == 1 ? 'cart-exhibition-mode-data' : '')">
<!-- 选择 -->
<view v-if="common_site_type != 1" @tap="selected_event" data-type="node" :data-index="index" class="fl cart-selected">
<image v-if="(item.is_error || 0) != 1" class="icon" :src="common_static_url+'select' + ((item.is_error || 0) == 1 ? '-disabled' : ((item.selected || false) ? '-active' : '')) + '-icon.png'" mode="widthFix"></image>
<text v-if="(item.is_error || 0) == 1" class="cr-grey"></text>
</view>
<view class="items">
<navigator :url="item.goods_url" hover-class="none">
<!-- 图片 -->
<image :class="'cart-goods-image fl radius '+((item.is_error || 0) == 1 ? 'opacity' : '')" :src="item.images" mode="aspectFill"></image>
<!-- 错误 -->
<view v-if="(item.is_error || 0) == 1" class="error-msg pa tc text-size-xs">
<text class="cr-red tc bg-white round">{{item.error_msg}}</text>
</view>
</navigator>
<view class="items oh padding-left-sm">
<view class="fl">
<navigator :url="item.goods_url" hover-class="none">
<!-- 图片 -->
<image :class="'cart-goods-image fl radius '+((item.is_error || 0) == 1 ? 'opacity' : '')" :src="item.images" mode="aspectFill"></image>
<!-- 错误 -->
<view v-if="(item.is_error || 0) == 1" class="error-msg pa tc text-size-xs">
<text class="cr-red tc bg-white round">{{item.error_msg}}</text>
</view>
</navigator>
</view>
<!-- 基础 -->
<view class="cart-goods-base">
<view class="cart-goods-base fr">
<!-- 标题规格 -->
<navigator :url="item.goods_url" hover-class="none">
<view :class="'cart-goods-title multi-text margin-bottom-sm '+((item.is_error || 0) == 1 ? 'cr-grey' : '')">{{item.title}}</view>
@ -248,7 +250,7 @@
});
//
var cart_total = parseInt(data.buy_number || 0);
var cart_total = data.buy_number || 0;
if (cart_total <= 0) {
app.globalData.set_tab_bar_badge(2, 0);
} else {
@ -607,13 +609,9 @@
.cart-goods-image {
width: 155rpx;
height: 155rpx;
margin-right: 20rpx;
}
.cart-goods-base {
margin-left: 175rpx;
}
.cart-goods-item .items {
padding-left: 80rpx;
.cart-goods-base {
width: calc(100% - 170rpx);
}
.cart-goods-item .selected {
margin-top: 60rpx;
@ -623,7 +621,7 @@
* 错误提示
*/
.cart-goods-item .error-msg {
left: 96rpx;
left: 92rpx;
top: 78rpx;
width: 160rpx;
}

View File

@ -22,33 +22,38 @@
</view>
</view>
</view>
<view class="goods-spec-choice-content">
<!-- 商品规格 -->
<view v-if="goods_spec_choose.length > 0" class="goods-spec-choose">
<view v-for="(item, key) in goods_spec_choose" :key="key" class="item padding-top-xxl padding-bottom-xxl">
<view class="text-size-sm">{{item.name}}</view>
<view v-if="item.value.length > 0" class="spec margin-top-sm">
<block v-for="(items, keys) in item.value" :key="keys">
<button @tap.stop="goods_spec_choice_event" :data-key="key" :data-keys="keys" type="default" size="mini" hover-class="none" :class="'round '+items.is_active + ' ' + items.is_dont + ' ' + items.is_disabled">
<image v-if="(items.images || null) != null" :src="items.images" mode="scaleToFill" class="va-m dis-inline-block round margin-right-sm"></image>
<text class="va-m">{{items.name}}</text>
</button>
</block>
<block v-if="(goods.is_exist_many_spec || 0) == 1 && goods_spec_choose.length == 0">
<view class="padding-top-xxxl padding-bottom-xxxl tc cr-red">规格数据有误</view>
</block>
<block v-else>
<view class="goods-spec-choice-content">
<!-- 商品规格 -->
<view v-if="goods_spec_choose.length > 0" class="goods-spec-choose">
<view v-for="(item, key) in goods_spec_choose" :key="key" class="item padding-top-xxl padding-bottom-xxl">
<view class="text-size-sm">{{item.name}}</view>
<view v-if="item.value.length > 0" class="spec margin-top-sm">
<block v-for="(items, keys) in item.value" :key="keys">
<button @tap.stop="goods_spec_choice_event" :data-key="key" :data-keys="keys" type="default" size="mini" hover-class="none" :class="'round '+items.is_active + ' ' + items.is_dont + ' ' + items.is_disabled">
<image v-if="(items.images || null) != null" :src="items.images" mode="scaleToFill" class="va-m dis-inline-block round margin-right-sm"></image>
<text class="va-m">{{items.name}}</text>
</button>
</block>
</view>
</view>
</view>
<!-- 购买数量 -->
<view class="goods-buy-number oh pr margin-top-xl margin-bottom-xxl">
<view class="fl margin-top">购买数量</view>
<view class="number-content tc oh round">
<view @tap="goods_buy_number_event" class="number-submit tc cr-gray fl" data-type="0">-</view>
<input @blur="goods_buy_number_blur" class="tc cr-gray fl" type="number" :value="buy_number">
<view @tap="goods_buy_number_event" class="number-submit tc cr-gray fl" data-type="1">+</view>
</view>
</view>
</view>
<!-- 购买数量 -->
<view class="goods-buy-number oh pr margin-top-xl margin-bottom-xxl">
<view class="fl margin-top">购买数量</view>
<view class="number-content tc oh round">
<view @tap="goods_buy_number_event" class="number-submit tc cr-gray fl" data-type="0">-</view>
<input @blur="goods_buy_number_blur" class="tc cr-gray fl" type="number" :value="buy_number">
<view @tap="goods_buy_number_event" class="number-submit tc cr-gray fl" data-type="1">+</view>
</view>
</view>
</view>
<button class="bg-main br-main cr-white text-size-sm round" type="default" @tap.stop="spec_confirm_event" hover-class="none">确定</button>
<button class="bg-main br-main cr-white text-size-sm round" type="default" @tap.stop="spec_confirm_event" hover-class="none">确定</button>
</block>
</view>
</component-popup>
</view>
@ -74,6 +79,8 @@
goods_spec_choose: [],
buy_number: 1,
buy_event_type: 'cart',
is_direct_cart: 0,
is_success_tips: 1,
//
plugins_intellectstools_config: app.globalData.get_config('plugins_base.intellectstools.data'),
plugins_intellectstools_timer: null,
@ -93,25 +100,53 @@
if(!app.globalData.is_single_page_check()) {
return false;
}
params = params || {};
//
var status = true;
//
var goods_spec_choose = ((goods.specifications || null) != null) ? (goods.specifications.choose || []) : [];
//
var is_direct_cart = 0;
if((params.is_direct_cart || 0) == 1 && parseInt(goods.is_exist_many_spec || 0) == 0 && goods_spec_choose.length == 0) {
status = false;
is_direct_cart = 1;
}
//
var is_success_tips = (params.is_success_tips == undefined) ? 1 : params.is_success_tips || 0;
// +1
if(this.is_direct_cart == 1 && parseInt(this.goods.user_cart_count || 0) > 0) {
var buy_number = 1;
} else {
var buy_number = goods.buy_min_number || 1;
}
//
this.setData({
popup_status: true,
popup_status: status,
params: params || {},
back_data: back_data,
goods: goods || {},
goods_spec_choose: goods.specifications.choose || [],
goods_spec_choose: goods_spec_choose,
goods_spec_base_price: goods.price,
goods_spec_base_original_price: goods.original_price || 0,
goods_spec_base_inventory: goods.inventory,
goods_spec_base_images: goods.images,
buy_number: goods.buy_min_number || 1,
buy_event_type: params.buy_event_type || 'cart'
buy_number: buy_number,
buy_event_type: params.buy_event_type || 'cart',
is_direct_cart: is_direct_cart,
is_success_tips: is_success_tips,
});
//
this.spec_handle_dont(0, 1);
//
this.plugins_intellectstools_selected_spec_handle();
this.plugins_intellectstools_selected_spec_handle();
//
if(is_direct_cart) {
this.spec_confirm_event();
}
},
//
@ -603,7 +638,10 @@
success: res => {
uni.hideLoading();
if (res.data.code == 0) {
app.globalData.showToast(res.data.msg, 'success');
//
if(this.is_success_tips == 1) {
app.globalData.showToast(res.data.msg, 'success');
}
var cart_number = res.data.data.buy_number;
//

View File

@ -1,32 +1,40 @@
<template>
<view>
<view v-if="(propData || null) != null && (propData.goods_list || null) != null && propData.goods_list.length > 0">
<view v-if="(propData.title || null) != null || (propData.vice_title || null) != null" class="spacing-nav-title">
<text v-if="(propData.title || null) != null" class="text-wrapper" :style="'color:'+(propData.color || '#333')+';'">{{propData.title}}</text>
<text v-if="(propData.vice_title || null) != null" class="vice-name margin-left-lg cr-gray">{{propData.vice_title}}</text>
<navigator v-if="(propData[propMoreUrlKey] || null) != null" :url="propData[propMoreUrlKey]" hover-class="none" class="arrow-right padding-right-xxxl cr-gray fr"></navigator>
<view>
<view v-if="(data || null) != null && (data.goods_list || null) != null && data.goods_list.length > 0">
<view v-if="(data.title || null) != null || (data.vice_title || null) != null" class="spacing-nav-title">
<text v-if="(data.title || null) != null" class="text-wrapper" :style="'color:'+(data.color || '#333')+';'">{{data.title}}</text>
<text v-if="(data.vice_title || null) != null" class="vice-name margin-left-lg cr-gray">{{data.vice_title}}</text>
<navigator v-if="(data[propMoreUrlKey] || null) != null" :url="data[propMoreUrlKey]" hover-class="none" class="arrow-right padding-right-xxxl cr-gray fr"></navigator>
</view>
<view class="wh-auto oh pr">
<view v-if="(propData.keywords_arr || null) != null && propData.keywords_arr.length > 0" class="word-list scroll-view-horizontal margin-bottom-lg">
<view class="wh-auto oh pr goods-list">
<view v-if="(data.keywords_arr || null) != null && data.keywords_arr.length > 0" class="word-list scroll-view-horizontal margin-bottom-lg">
<scroll-view scroll-x>
<block v-for="(kv, ki) in propData.keywords_arr" :key="ki">
<block v-for="(kv, ki) in data.keywords_arr" :key="ki">
<navigator v-if="(kv || null) != null" :url="propKeywordsUrl + kv" hover-class="none" class="word-icon dis-inline-block bg-main-light text-size-xs cr-main round padding-top-xs padding-bottom-xs padding-left padding-right">{{kv}}</navigator>
</block>
</scroll-view>
</view>
<!-- 默认图文 -->
<block v-if="(propData.style_type || 0) == 0">
<block v-if="(data.style_type || 0) == 0">
<view class="goods-data-list">
<view v-for="(item, index) in propData.goods_list" :key="index" class="item oh padding-main border-radius-main bg-white oh pr spacing-mb">
<view v-for="(item, index) in data.goods_list" :key="index" class="item oh padding-main border-radius-main bg-white oh pr spacing-mb">
<!-- 商品主体内容 -->
<navigator :url="item.goods_url" hover-class="none">
<view :data-value="item.goods_url" @tap="url_event">
<image class="goods-img fl radius" :src="item.images" mode="aspectFit"></image>
<view class="base fr">
<view class="multi-text">{{item.title}}</view>
<view v-if="(item.simple_desc || null) != null" class="cr-grey single-text margin-top-sm">{{item.simple_desc}}</view>
<view class="sales-price margin-top-sm">{{propCurrencySymbol}}{{item.min_price}}</view>
<view class="base-bottom pa">
<view class="sales-price fl">{{propCurrencySymbol}}{{item.min_price}}</view>
<view v-if="(item.is_error || 0) == 0" class="fr pr" :data-index="index" @tap.stop="goods_cart_event">
<uni-icons type="plus" size="22" color="#1AAD19"></uni-icons>
<view class="cart-badge-icon pa">
<component-badge :propNumber="item.user_cart_count || 0"></component-badge>
</view>
</view>
</view>
</view>
</navigator>
</view>
<!-- 标签插件 -->
<view v-if="(propLabel || null) != null && propLabel.data.length > 0" :class="'plugins-label oh pa plugins-label-'+((propLabel.base.is_user_goods_label_icon || 0) == 0 ? 'text' : 'img')+' plugins-label-'+(propLabel.base.user_goods_show_style || 'top-left')">
<block v-for="(lv,li) in propLabel.data" :key="li">
@ -40,15 +48,23 @@
</view>
</block>
<!-- 九方格 -->
<block v-else-if="propData.style_type == 1">
<block v-else-if="data.style_type == 1">
<view class="goods-data-grid-list">
<view v-for="(item, index) in propData.goods_list" :key="index" class="item oh border-radius-main bg-white oh pr spacing-mb">
<view v-for="(item, index) in data.goods_list" :key="index" class="item oh border-radius-main bg-white oh pr spacing-mb">
<!-- 商品主体内容 -->
<navigator :url="item.goods_url" hover-class="none">
<image class="goods-img dis-block" :src="item.images" mode="aspectFit"></image>
<view class="base padding-horizontal-main margin-top-sm">
<view class="goods-title multi-text margin-bottom-sm">{{item.title}}</view>
<view class="sales-price">{{propCurrencySymbol}}{{item.min_price}}</view>
<view class="goods-title multi-text">{{item.title}}</view>
<view class="margin-top-sm">
<view class="sales-price fl">{{propCurrencySymbol}}{{item.min_price}}</view>
<view v-if="(item.is_error || 0) == 0" class="fr pa bg-white right-cart-icon" :data-index="index" @tap.stop="goods_cart_event">
<uni-icons type="plus" size="22" color="#1AAD19"></uni-icons>
<view class="cart-badge-icon pa">
<component-badge :propNumber="item.user_cart_count || 0"></component-badge>
</view>
</view>
</view>
</view>
</navigator>
<!-- 标签插件 -->
@ -64,18 +80,26 @@
</view>
</block>
<!-- 滚动 -->
<view v-else-if="propData.style_type == 2" class="rolling-horizontal border-radius-main oh spacing-mb">
<view v-else-if="data.style_type == 2" class="rolling-horizontal border-radius-main oh spacing-mb">
<view class="goods-data-rolling-list scroll-view-horizontal">
<swiper :vertical="false" :autoplay="propIsAutoPlay" :circular="false" :display-multiple-items="((propData.multiple_items || null) == null) ? (propData.goods_list.length < 3 ? propData.goods_list.length : 3) : (propData.goods_list.length < propData.multiple_items ? propData.goods_list.length : propData.multiple_items)" interval="3000">
<block v-for="(item, index) in propData.goods_list" :key="index">
<swiper :vertical="false" :autoplay="propIsAutoPlay" :circular="false" :display-multiple-items="((data.multiple_items || null) == null) ? (data.goods_list.length < 3 ? data.goods_list.length : 3) : (data.goods_list.length < data.multiple_items ? data.goods_list.length : data.multiple_items)" interval="3000">
<block v-for="(item, index) in data.goods_list" :key="index">
<swiper-item>
<view class="item bg-white border-radius-main margin-right-main oh pr ht-auto pr">
<!-- 商品主体内容 -->
<navigator :url="item.goods_url" hover-class="none">
<image class="goods-img dis-block wh-auto" :src="item.images" mode="aspectFit"></image>
<view class="padding-left-sm padding-right-sm margin-top-sm">
<view class="multi-text margin-bottom-sm">{{item.title}}</view>
<view class="sales-price">{{propCurrencySymbol}}{{item.min_price}}</view>
<view class="multi-text">{{item.title}}</view>
<view class="margin-top-sm">
<view class="sales-price fl">{{propCurrencySymbol}}{{item.min_price}}</view>
<view v-if="(item.is_error || 0) == 0" class="fr pa bg-white right-cart-icon" :data-index="index" @tap.stop="goods_cart_event">
<uni-icons type="plus" size="22" color="#1AAD19"></uni-icons>
<view class="cart-badge-icon pa">
<component-badge :propNumber="item.user_cart_count || 0"></component-badge>
</view>
</view>
</view>
</view>
</navigator>
<!-- 标签插件 -->
@ -93,25 +117,40 @@
</swiper>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<!-- 商品购买 -->
<component-goods-buy ref="goods_buy" v-on:CartSuccessEvent="goods_cart_back_event"></component-goods-buy>
<!-- 购物车抛物线 -->
<component-cart-para-curve ref="cart_para_curve"></component-cart-para-curve>
</view>
</template>
<script>
const app = getApp();
export default {
data() {
return {};
},
components: {},
const app = getApp();
import componentBadge from "../../components/badge/badge";
import componentGoodsBuy from "../../components/goods-buy/goods-buy";
import componentCartParaCurve from '../../components/cart-para-curve/cart-para-curve';
export default {
data() {
return {
data: null,
};
},
components: {
componentBadge,
componentGoodsBuy,
componentCartParaCurve
},
props: {
propCurrencySymbol: {
type: String,
default: app.globalData.data.currency_symbol
},
propData: {
type: [Array,Object],
default: []
type: [Array,Object],
default: []
},
propMoreUrlKey: {
type: String,
@ -128,15 +167,80 @@
propLabel: {
type: [Array,Object,String],
default: null
}
},
},
propIsCartParaCurve: {
type: Boolean,
default: false
}
},
//
watch: {
//
propData(value, old_value) {
this.data = value;
}
},
//
created: function() {
this.data = this.propData;
},
methods: {
//
goods_cart_event(e) {
if((this.$refs.goods_buy || null) != null) {
var index = e.currentTarget.dataset.index || 0;
var goods = this.propData.goods_list[index];
// 线
var is_success_tips = this.propIsCartParaCurve ? 0 : 1;
this.$refs.goods_buy.init(goods, {buy_event_type: 'cart', is_direct_cart: 1, is_success_tips: is_success_tips}, {index: index, pos: e});
}
},
//
goods_cart_back_event(e) {
//
var back = e.back_data;
var temp = this.data;
var goods = temp['goods_list'][back.index];
goods['user_cart_count'] = parseInt(goods['user_cart_count'] || 0)+parseInt(e.stock);
if(goods['user_cart_count'] > 99) {
goods['user_cart_count'] = '99+';
}
temp['goods_list'][back.index] = goods;
this.setData({data: temp});
// 线
if(this.propIsCartParaCurve && (this.$refs.cart_para_curve || null) != null) {
this.$refs.cart_para_curve.init(null, back.pos, goods.images);
}
//
var cart_total = e.cart_number || 0;
if (cart_total <= 0) {
app.globalData.set_tab_bar_badge(2, 0);
} else {
app.globalData.set_tab_bar_badge(2, 1, cart_total);
}
//
var page = app.globalData.current_page().split('?');
switch(page[0]) {
//
case 'pages/goods-detail/goods-detail' :
var obj = app.globalData.get_page_object(page[0]);
if(obj != null) {
obj.goods_cart_count_handle(cart_total);
}
break;
}
},
// url
url_event(e) {
app.globalData.url_event(e);
}
}
};
</script>
<style>
}
};
</script>
<style>
</style>

View File

@ -2,7 +2,7 @@
<view>
<view :class="'popup ' + (propClassname || '') + ' ' + ((propShow || false) ? 'popup-show' : '') + ' ' + ((propAnimation || true) ? 'animation': '' )" :disable-scroll="propDisablescroll">
<view class="popup-mask" v-if="propMask || true" @tap="onMaskTap"></view>
<view :class="'popup-content bottom-line-exclude popup-' + (propPosition || 'bottom')+ ' '+(propIsBar ? 'popup-bar' : '')">
<view :class="'popup-content bottom-line-exclude popup-' + (propPosition || 'bottom')+ ' '+(propIsBar ? 'popup-bar' : '')" :style="'left:'+popup_content_left_value+'px'">
<slot></slot>
</view>
</view>
@ -11,7 +11,9 @@
<script>
export default {
data() {
return {};
return {
popup_content_left_value: 'auto'
};
},
components: {},
props: {
@ -43,6 +45,19 @@
type: Boolean,
default: false
}
},
//
watch: {
//
propShow(value, old_value) {
//
var width = uni.getSystemInfoSync().windowWidth;
var left = 0;
if(width > 800) {
left = (width-800)/2;
}
this.popup_content_left_value = left;
}
},
methods: {
onMaskTap: function onMaskTap() {

View File

@ -37,7 +37,6 @@
const app = getApp();
import componentPopup from "../popup/popup";
import componentNoData from "../no-data/no-data";
var common_static_url = app.globalData.get_static_url('common');
export default {
data() {

View File

@ -12,7 +12,7 @@
</block>
</view>
<view class="padding-horizontal-main padding-top-main">
<view class="padding-horizontal-main padding-top-main bottom-line-exclude">
<!-- 地址 -->
<view v-if="common_site_type == 0 || common_site_type == 2 || common_site_type == 4" class="padding-horizontal-main padding-top-main border-radius-main bg-white spacing-mb">
<view class="address arrow-right cp" @tap="address_event">

View File

@ -82,7 +82,7 @@
<view class="margin-top-sm oh">
<view class="sales-price text-size-sm single-text pa">{{currency_symbol}}{{item.min_price}}</view>
<view v-if="common_site_type != 1" class="buy-opt tc pa">
<block v-if="(item.inventory || 0) > 0">
<block v-if="(item.is_error || 0) == 0">
<view v-if="(item.buy_number || 0) > 0" class="dis-inline-block va-m cp" :data-index="index" data-type="0" @tap.stop="buy_number_event">
<uni-icons type="minus" size="22" color="#f00"></uni-icons>
</view>
@ -92,7 +92,7 @@
</view>
</block>
<block v-else>
<text class="cr-grey text-size-xs">没货了</text>
<text class="cr-grey text-size-xs">{{item.error_msg}}</text>
</block>
</view>
</view>
@ -256,6 +256,9 @@
</view>
</block>
<!-- 购物车抛物线 -->
<component-cart-para-curve ref="cart_para_curve"></component-cart-para-curve>
<!-- 商品购买 -->
<component-goods-buy ref="goods_buy" v-on:CartSuccessEvent="goods_cart_back_event"></component-goods-buy>
@ -274,6 +277,7 @@
import componentNoData from "../../components/no-data/no-data";
import componentPopup from "../../components/popup/popup";
import componentBadge from "../../components/badge/badge";
import componentCartParaCurve from '../../components/cart-para-curve/cart-para-curve';
var common_static_url = app.globalData.get_static_url('common');
//
@ -318,7 +322,9 @@
//
is_single_page: app.globalData.is_current_single_page() || 0,
//
category_goods_model_icon_field: app.globalData.data.category_goods_model_icon_type == 0 ? 'big_images' : 'icon'
category_goods_model_icon_field: app.globalData.data.category_goods_model_icon_type == 0 ? 'big_images' : 'icon',
//
temp_opt_data: null,
};
},
@ -328,7 +334,8 @@
componentQuickNav,
componentNoData,
componentPopup,
componentBadge
componentBadge,
componentCartParaCurve
},
props: {},
@ -676,7 +683,7 @@
}
//
this.buy_number_event_handle(type, temp_goods);
this.buy_number_event_handle(e, type, temp_goods);
}
}
},
@ -688,7 +695,7 @@
},
//
buy_number_event_handle(type, goods, spec = '') {
buy_number_event_handle(e, type, goods, spec = '') {
var res = this.buy_number_handle(type, goods, 'buy_number');
if(res === false) {
return false;
@ -710,6 +717,15 @@
}
}
//
this.setData({
temp_opt_data: {
pos: e,
goods: goods,
type: type,
}
});
//
if(res == 0) {
if(cart_item == null) {
@ -726,6 +742,18 @@
return true;
},
// 线
cart_para_curve_handle() {
if((this.temp_opt_data || null) != null && (this.temp_opt_data.type || 0) == 1) {
if((this.$refs.cart_para_curve || null) != null) {
var self = this;
uni.createSelectorQuery().select('.botton-nav .cart').boundingClientRect().exec(function(res) {
self.$refs.cart_para_curve.init(res, self.temp_opt_data.pos, self.temp_opt_data.goods.images);
});
}
}
},
//
cart_buy_number_event(e) {
if(!app.globalData.is_single_page_check()) {
@ -842,6 +870,7 @@
success: res => {
uni.hideLoading();
if (res.data.code == 0) {
this.cart_para_curve_handle();
this.get_cart_data();
} else {
if (app.globalData.is_login_check(res.data)) {
@ -874,6 +903,7 @@
success: res => {
uni.hideLoading();
if (res.data.code == 0) {
this.cart_para_curve_handle();
this.get_cart_data();
} else {
if (app.globalData.is_login_check(res.data)) {

View File

@ -915,7 +915,7 @@
self.top_nav_title_scroll = false;
//
const query = uni.createSelectorQuery();
var query = uni.createSelectorQuery();
query.select(value).boundingClientRect();
query.selectViewport().scrollOffset();
query.exec(function(res) {
@ -993,8 +993,15 @@
//
goods_cart_back_event(e) {
this.setData({
goods_spec_selected_text: ((e.spec || null) == null) ? '' : e.spec.map(function(v){return v.value;}).join(' / '),
quick_nav_cart_count: e.cart_number
goods_spec_selected_text: ((e.spec || null) == null) ? '' : e.spec.map(function(v){return v.value;}).join(' / ')
});
this.goods_cart_count_handle(e.cart_number);
},
//
goods_cart_count_handle(cart_number) {
this.setData({
quick_nav_cart_count: cart_number
});
},

View File

@ -126,7 +126,7 @@
<!-- 活动配置-楼层顶部 - 插件 -->
<block v-if="pv.plugins == 'activity' && (plugins_activity_data || null) != null">
<component-activity-list :propConfig="plugins_activity_data.base" :propData="plugins_activity_data.data" propLocation="0" :propLabel="plugins_label_data" :propCurrencySymbol="currency_symbol"></component-activity-list>
<component-activity-list :propConfig="plugins_activity_data.base" :propData="plugins_activity_data.data" propLocation="0" :propLabel="plugins_label_data" :propCurrencySymbol="currency_symbol" :propIsCartParaCurve="true"></component-activity-list>
</block>
<!-- 门店 - 插件 -->
@ -178,7 +178,7 @@
</scroll-view>
</view>
<block v-if="floor.goods.length > 0">
<component-goods-list :propData="{style_type: 1, goods_list: floor.goods}" :propLabel="plugins_label_data" :propCurrencySymbol="currency_symbol"></component-goods-list>
<component-goods-list :propData="{style_type: 1, goods_list: floor.goods}" :propLabel="plugins_label_data" :propCurrencySymbol="currency_symbol" :propIsCartParaCurve="true"></component-goods-list>
</block>
</view>
</view>
@ -443,7 +443,7 @@
navigation: data.navigation || [],
article_list: data.article_list || [],
data_list: data.data_list,
cart_total: parseInt(data.cart_total.buy_number || 0),
cart_total: data.cart_total.buy_number || 0,
message_total: parseInt(data.message_total || 0),
right_icon_list: data.right_icon_list || [],
data_list_loding_status: data.data_list.length == 0 ? 0 : 3,

View File

@ -25,6 +25,10 @@
.data-list .item .spec-choice {
max-width: calc(100% - 220rpx);
}
.data-list .item .cart-badge-icon {
top: -16rpx;
right: 0;
}
/**
*

View File

@ -10,10 +10,10 @@
<view v-if="(data.goods || null) != null && data.goods.length > 0">
<!-- 商品 -->
<view class="data-list oh">
<view v-for="(item, index) in data.goods" :key="index" :class="'item padding-main border-radius-main bg-white oh spacing-mb '+(item.buy_data.is_cart == 0 ? 'br-red' : '')">
<view v-for="(item, index) in data.goods" :key="index" :class="'item padding-main border-radius-main bg-white oh spacing-mb '+(item.is_error == 0 ? '' : 'br-red')">
<image class="goods-img dis-block border-radius-main fl" :src="item.images" mode="aspectFit" :data-value="item.goods_url" @tap="url_event"></image>
<view class="right-base fr">
<label v-if="data.type == 1 && item.buy_data.is_cart == 1" class="fr" :data-index="index" @tap="goods_choice_event">
<label v-if="data.type == 1 && item.is_error == 0" class="fr" :data-index="index" @tap="goods_choice_event">
<radio :checked="(item.checked == undefined || item.checked == true)" style="transform:scale(0.7)" />
</label>
<view :class="'multi-text '+(data.type == 1 ? 'padding-right' : '')">{{item.title}}</view>
@ -22,14 +22,17 @@
<text v-if="item.original_price != 0" class="original-price margin-left-sm">{{currency_symbol}}{{item.original_price}}</text>
</view>
<view class="margin-top-xs">
<view v-if="item.buy_data.is_cart == 1">
<view class="va-m dis-inline-block margin-right-lg" :data-index="index" @tap="goods_cart_event">
<view v-if="item.is_error == 0">
<view class="va-m dis-inline-block margin-right-xl pr" :data-index="index" @tap="goods_cart_event">
<uni-icons type="cart" size="16" color="#999"></uni-icons>
<view class="cart-badge-icon pa">
<component-badge :propNumber="item.user_cart_count || 0"></component-badge>
</view>
</view>
<text class="cr-gray text-size-xs">{{item.inventory}}{{item.inventory_unit}}</text>
<view v-if="(item.is_exist_many_spec || 0) == 1" class="br-gray cr-gray radius fr padding-left padding-right single-text text-size-xs spec-choice" :data-index="index" @tap="spec_choice_event">{{item.spec_choice_text || ''}}</view>
</view>
<view v-else class="cr-yellow text-size-xs">{{item.buy_data.error}}</view>
<view v-else class="cr-yellow text-size-xs">{{item.error_msg}}</view>
</view>
</view>
</view>
@ -76,7 +79,8 @@
import componentNoData from "../../../../components/no-data/no-data";
import componentBottomLine from "../../../../components/bottom-line/bottom-line";
import componentGoodsSpecChoice from "../../../../components/goods-spec-choice/goods-spec-choice";
import componentGoodsBuy from "../../../../components/goods-buy/goods-buy";
import componentGoodsBuy from "../../../../components/goods-buy/goods-buy";
import componentBadge from "../../../../components/badge/badge";
export default {
data() {
@ -98,7 +102,8 @@
componentNoData,
componentBottomLine,
componentGoodsSpecChoice,
componentGoodsBuy
componentGoodsBuy,
componentBadge
},
onLoad(params) {
@ -275,7 +280,7 @@
var goods_data = [];
var temp_goods = this.data.goods;
for(var i in temp_goods) {
if(temp_goods[i]['buy_data']['is_cart'] == 1) {
if(temp_goods[i]['is_error'] == 0) {
var goods_id = null;
if(type == 1) {
if(temp_goods[i]['checked'] == undefined || temp_goods[i]['checked'] == true) {
@ -324,13 +329,22 @@
if((this.$refs.goods_buy || null) != null) {
var index = e.currentTarget.dataset.index || 0;
var goods = this.data['goods'][index];
this.$refs.goods_buy.init(goods, {buy_event_type: 'cart'}, index);
this.$refs.goods_buy.init(goods, {buy_event_type: 'cart', is_direct_cart: 1}, {index: index});
}
},
//
goods_cart_back_event(e) {
console.log(e);
//
var back = e.back_data;
var temp = this.data;
var goods = temp['goods'][back.index];
goods['user_cart_count'] = parseInt(goods['user_cart_count'] || 0)+parseInt(e.stock);
if(goods['user_cart_count'] > 99) {
goods['user_cart_count'] = '99+';
}
temp['goods'][back.index] = goods;
this.setData({data: temp});
}
}
};

View File

@ -101,4 +101,10 @@
margin-right: 50rpx;
margin-top: 2rpx;
width: calc(100% - 300rpx);
}
.service-nav .show-type-submit {
width: 50rpx;
height: 50rpx !important;
top: 18rpx;
right: 20rpx;
}

View File

@ -77,14 +77,17 @@
</view>
<!-- 聚合导航 -->
<view class="padding-main border-radius-main bg-white spacing-mb">
<view class="padding-main item-title fw-b text-size">我的服务</view>
<view class="service-nav padding-main border-radius-main bg-white spacing-mb">
<view class="padding-main pr">
<text class="fw-b text-size">我的服务</text>
<image class="show-type-submit pa cp" :src="common_static_url+'show-'+(nav_show_model_type == 0 ? 'grid' : 'list')+'-icon.png'" mode="aspectFill" @tap="nav_show_type_event"></image>
</view>
<!-- 列表模式 -->
<view v-if="nav_show_model_type == 1" class="nav-list">
<block v-for="(item, index) in navigation" :key="index">
<!-- 这里不展示订单导航 -->
<block v-if="item.event_value != '/pages/user-order/user-order'">
<view :data-value="item.event_value" :data-type="item.event_type" @tap="navigation_event" class="nav-item br-t cp padding-main">
<view :data-value="item.event_value" :data-type="item.event_type" @tap="navigation_event" class="nav-item br-t cp padding-main margin-top-sm">
<view class="arrow-right">
<image :src="item.images_url" class="item-icon va-m" mode="widthFix"></image>
<text class="item-name va-m cr-base margin-left-sm">{{item.name}}</text>
@ -359,7 +362,7 @@
this.setData(upd_data);
//
var cart_total = parseInt(data.cart_total.buy_number || 0);
var cart_total = data.cart_total.buy_number || 0;
if (cart_total <= 0) {
app.globalData.set_tab_bar_badge(2, 0);
} else {
@ -422,6 +425,11 @@
// url
url_event(e) {
app.globalData.url_event(e);
},
//
nav_show_type_event(e) {
this.setData({nav_show_model_type: this.nav_show_model_type == 0 ? 1 : 0});
}
}
};