修正项目
This commit is contained in:
132
xlcs-user/components/AddToCart/AddToCart.vue
Normal file
132
xlcs-user/components/AddToCart/AddToCart.vue
Normal file
@@ -0,0 +1,132 @@
|
||||
<template>
|
||||
<view>
|
||||
<!-- 如果商品没有加入购物车 -->
|
||||
<block v-if="getCheckProductExists">
|
||||
<u-button size="mini" type="warning" @click="addShopCart">加入购物车</u-button>
|
||||
</block>
|
||||
<block v-else>
|
||||
<u-number-box
|
||||
ref="uNumber"
|
||||
v-model="skuNumValue"
|
||||
:disabled-input="true"
|
||||
:input-height="40"
|
||||
:input-width="60"
|
||||
:max="getMax"
|
||||
:min="0"
|
||||
:size="20"
|
||||
@minus="changeSkuNumMinus"
|
||||
@plus="changeSkuNumPlus"
|
||||
></u-number-box>
|
||||
</block>
|
||||
|
||||
<u-modal ref="confirmModal" v-model="showConfirmModal" :async-close="true" :show-cancel-button="true"
|
||||
@cancel="modalCancel" @confirm="modalConfirm">
|
||||
<view class="u-flex u-row-center u-m-20">确认删除该商品?</view>
|
||||
</u-modal>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapGetters, mapActions} from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'AddToCart',
|
||||
data() {
|
||||
return {
|
||||
id: 0,
|
||||
isCart: false,
|
||||
showConfirmModal: false
|
||||
};
|
||||
},
|
||||
props: {
|
||||
shopDetail: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
// 在购物车页面的时候,使用带活动的购物车将传递的不再是商品的id
|
||||
// 商品详情信息中没有id,而是skuId
|
||||
skuId: {
|
||||
type: Number,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('cartModule', ['checkProductExists', 'getProductSkuNum']),
|
||||
// 检查是否存在商品于购物车
|
||||
getCheckProductExists() {
|
||||
return !this.checkProductExists(this.id);
|
||||
},
|
||||
// 商品加入购物车的数量
|
||||
skuNumValue: {
|
||||
get() {
|
||||
return this.getProductSkuNum(this.id);
|
||||
},
|
||||
set(value) {
|
||||
}
|
||||
},
|
||||
// 最大可加入购物车的数量
|
||||
getMax() {
|
||||
let perLimit = this.shopDetail.perLimit;
|
||||
// 秒杀商品与普通商品购买上限判断字段不同
|
||||
if (this.shopDetail.skuType === 1) {
|
||||
perLimit = this.shopDetail.seckillSkuVo && this.shopDetail.seckillSkuVo.seckillLimit
|
||||
}
|
||||
return perLimit;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions('cartModule', ['addShopAction', 'changeSkuNumAction']),
|
||||
// 添加到购物车
|
||||
addShopCart() {
|
||||
if (this.skuId) {
|
||||
this.shopDetail.id = this.skuId;
|
||||
}
|
||||
this.addShopAction(this.shopDetail);
|
||||
},
|
||||
// 购物车数量递减
|
||||
changeSkuNumMinus(e) {
|
||||
// 如果是购物车中进行递减操作,并且购物车数量为0,那么需要弹出确认框
|
||||
if (e.value < 1 && this.isCart) {
|
||||
this.showConfirmModal = true;
|
||||
} else {
|
||||
this.changeSkuNumAction({skuId: this.id, value: -1, currentBuyNum: e.value, isCart: this.isCart});
|
||||
}
|
||||
|
||||
},
|
||||
// 购物车数量递增
|
||||
changeSkuNumPlus(e) {
|
||||
this.changeSkuNumAction({skuId: this.id, value: 1, currentBuyNum: e.value, isCart: this.isCart});
|
||||
},
|
||||
// 确认删除商品模态框
|
||||
modalConfirm() {
|
||||
this.showConfirmModal = false;
|
||||
this.changeSkuNumAction({skuId: this.id, value: -1, currentBuyNum: 0, isCart: this.isCart});
|
||||
},
|
||||
// 取消删除商品模态框,只需要将商品购买数修改回初始值
|
||||
modalCancel() {
|
||||
this.showConfirmModal = false;
|
||||
// 重新设置u-number-box的初始值
|
||||
this.$refs.uNumber.$data.inputVal = 1;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
// skuId是在购物车频道使用,如果是商品列表,是id
|
||||
skuId: {
|
||||
handler(newVal, oldVal) {
|
||||
if (newVal) {
|
||||
this.id = newVal;
|
||||
this.isCart = true;
|
||||
} else {
|
||||
this.id = this.shopDetail.id;
|
||||
this.isCart = false;
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss"></style>
|
130
xlcs-user/components/CouponInfoList/CouponInfoList.vue
Normal file
130
xlcs-user/components/CouponInfoList/CouponInfoList.vue
Normal file
@@ -0,0 +1,130 @@
|
||||
<template>
|
||||
<u-popup v-model="showCouponInfoListModal" :closeable="true" border-radius="14" mode="bottom" @close="closeModal">
|
||||
<view class="coupon">
|
||||
<view v-for="couponInfoItem in couponInfoList" :key="couponInfoItem.id" class="content u-m-b-20">
|
||||
<view class="left">
|
||||
<view class="sum">
|
||||
¥
|
||||
<text class="num">{{ couponInfoItem.amount }}</text>
|
||||
</view>
|
||||
<view class="type">{{ couponInfoItem.couponType === 'FULL_REDUCTION' ? '满减券' : '现金券' }}</view>
|
||||
<view class="type">{{ getRangeType(couponInfoItem.rangeType) }}</view>
|
||||
</view>
|
||||
<view class="centre">
|
||||
<view class="title">{{ couponInfoItem.couponName }}</view>
|
||||
<view class="u-type-info">{{ couponInfoItem.rangeDesc }}</view>
|
||||
<view class="valid-date">过期时间:{{ dayjs(couponInfoItem.expireTime).format('YYYY-MM-DD') }}</view>
|
||||
</view>
|
||||
<view class="right">
|
||||
<block v-if="couponInfoItem.couponStatus === 1">
|
||||
<u-tag text="已领取" type="success"/>
|
||||
</block>
|
||||
<block v-else-if="couponInfoItem.couponStatus === 2">
|
||||
<u-tag text="已使用" type="info"/>
|
||||
</block>
|
||||
<block v-else>
|
||||
<view :round="true" class="immediate-use" size="mini" @click="receiveCoupon(couponInfoItem.id)">领取</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
export default {
|
||||
props: ['showCouponInfoList', 'couponInfoList'],
|
||||
name: 'CouponInfoList',
|
||||
computed: {
|
||||
getRangeType() {
|
||||
return function (rangeType) {
|
||||
switch (rangeType) {
|
||||
case 'ALL':
|
||||
return '全场通用';
|
||||
case 'SKU':
|
||||
return '指定商品';
|
||||
case 'CATEGORY':
|
||||
return '指定分类';
|
||||
}
|
||||
};
|
||||
},
|
||||
showCouponInfoListModal: {
|
||||
get() {
|
||||
return this.showCouponInfoList;
|
||||
},
|
||||
set(value) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
dayjs,
|
||||
closeModal() {
|
||||
this.$emit('update:showCouponInfoList', false);
|
||||
},
|
||||
// 领取优惠券
|
||||
receiveCoupon(id) {
|
||||
this.$emit('getCouponInfo', id)
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.coupon {
|
||||
margin: 80rpx auto;
|
||||
margin-bottom: 30rpx;
|
||||
background-color: #ffffff;
|
||||
width: 700rpx;
|
||||
color: $u-type-warning;
|
||||
font-size: 28rpx;
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
padding: 40rpx 20rpx;
|
||||
border: 10rpx;
|
||||
background-color: #fff5f4;
|
||||
|
||||
.left {
|
||||
.sum {
|
||||
font-size: 32rpx;
|
||||
|
||||
.num {
|
||||
font-size: 60rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.centre {
|
||||
margin-left: 40rpx;
|
||||
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: $u-main-color;
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
margin-left: 30rpx;
|
||||
|
||||
.immediate-use {
|
||||
padding: 0 20rpx;
|
||||
height: 50rpx;
|
||||
border-radius: 25rpx;
|
||||
line-height: 50rpx;
|
||||
background-color: $u-type-warning !important;
|
||||
color: #ffffff !important;
|
||||
font-size: 24rpx;
|
||||
border: none;
|
||||
word-break: keep-all;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
99
xlcs-user/components/ListImgItem/ListImgItem.vue
Normal file
99
xlcs-user/components/ListImgItem/ListImgItem.vue
Normal file
@@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<view :style="[{ width: width, height: height }]" class="gg">
|
||||
<view class="gg-left u-font-xs u-p-l-10 u-p-r-10">
|
||||
<block v-if="showLeft">
|
||||
<slot name="left">秒杀</slot>
|
||||
</block>
|
||||
</view>
|
||||
<view class="gg-right u-font-xs u-p-l-10 u-p-r-10">
|
||||
<block v-if="showRight">
|
||||
<slot name="right">推荐</slot>
|
||||
</block>
|
||||
</view>
|
||||
<u-image :border-radius="borderRadius" :height="height" :lazy-load="lazyLoad" :src="src" :width="width"/>
|
||||
<view class="gg-bottom u-font-xs u-p-l-10 u-p-r-10">
|
||||
<block v-if="showBottom">
|
||||
<slot name="bottom">新人专享</slot>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ListImgItem',
|
||||
props: {
|
||||
lazyLoad: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
borderRadius: {
|
||||
type: String,
|
||||
default: '10rpx'
|
||||
},
|
||||
src: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: true
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
default: '100%'
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: '200rpx'
|
||||
},
|
||||
showLeft: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showRight: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showBottom: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.gg {
|
||||
position: relative;
|
||||
|
||||
&-left {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
background-color: $u-type-primary;
|
||||
color: $u-type-info-light;
|
||||
border-top-left-radius: 10rpx;
|
||||
}
|
||||
|
||||
&-right {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
background-color: $u-type-error;
|
||||
color: $u-type-info-light;
|
||||
border-top-right-radius: 10rpx;
|
||||
}
|
||||
|
||||
&-bottom {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
background-color: $u-type-success;
|
||||
color: $u-type-info-light;
|
||||
border-bottom-left-radius: 10rpx;
|
||||
border-bottom-right-radius: 10rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
@@ -0,0 +1,130 @@
|
||||
<template>
|
||||
<view class="gg-header">
|
||||
<view class="gg-header-location u-p-r-50" @click="show = true">
|
||||
<text class="u-p-r-10">{{ currentPickUpArea }}</text>
|
||||
<u-icon color="gray" name="arrow-down-fill" size="20"></u-icon>
|
||||
</view>
|
||||
<!-- 如果利用v-model操作,会造成searchKeyword对于父组件的二次重渲染问题,所以将value与blur拆分,
|
||||
并且利用update:searchKeyword的方式将数据传递到父组件,并进行本组件的数据搜索操作 -->
|
||||
<u-search
|
||||
:clearabled="false"
|
||||
:show-action="true"
|
||||
:value="searchKeyword"
|
||||
class="gg-header-search"
|
||||
height="70"
|
||||
input-align="left"
|
||||
@blur="onBlurSearch"
|
||||
@custom="searchLocation"
|
||||
@search="searchLocation"
|
||||
></u-search>
|
||||
<u-picker v-model="show" :default-selector="[0]" :range="findAllList" mode="selector" range-key="regionName"
|
||||
@confirm="findAllListConfirm"></u-picker>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState, mapMutations, mapActions} from 'vuex';
|
||||
import {BAIDU_MAP_AK} from '../../common/const.js';
|
||||
// 百度地址资料:https://lbsyun.baidu.com/index.php?title=wxjsapi/guide/geocoding
|
||||
const bmap = require('../../common/bmap-wx.min.js');
|
||||
const BMap = new bmap.BMapWX({
|
||||
ak: BAIDU_MAP_AK
|
||||
});
|
||||
|
||||
export default {
|
||||
name: 'PickUpLocationHeader',
|
||||
props: ['searchKeyword'],
|
||||
data() {
|
||||
return {
|
||||
show: false,
|
||||
latitude: '',
|
||||
longitude: ''
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState('pickUpLocationModule', ['findAllList', 'currentPickUpArea'])
|
||||
},
|
||||
methods: {
|
||||
...mapMutations('pickUpLocationModule', ['setCurrentPickUpAreaMutation']),
|
||||
...mapActions('pickUpLocationModule', ['getSysRegionFindAllListAction']),
|
||||
findAllListConfirm(index) {
|
||||
// 通过百度地图进行地址解析,返回经纬度,并通知父组件进行列表显示处理
|
||||
// 发起geocoding检索请求
|
||||
BMap.geocoding({
|
||||
address: this.findAllList[index],
|
||||
fail: e => {
|
||||
console.log(e);
|
||||
},
|
||||
success: data => {
|
||||
let wxMarkerData = data.wxMarkerData;
|
||||
this.latitude = wxMarkerData[0].latitude;
|
||||
this.longitude = wxMarkerData[0].longitude;
|
||||
// 通过父组件查询数据
|
||||
this.$emit('getSearchLeader', {
|
||||
latitude: this.latitude,
|
||||
longitude: this.longitude
|
||||
});
|
||||
|
||||
this.setCurrentPickUpAreaMutation(this.findAllList[index])
|
||||
}
|
||||
});
|
||||
},
|
||||
searchLocation(value) {
|
||||
if (value && value.trim().length > 0) {
|
||||
BMap.geocoding({
|
||||
address: value,
|
||||
fail: e => {
|
||||
console.log(e);
|
||||
},
|
||||
success: data => {
|
||||
let wxMarkerData = data.wxMarkerData;
|
||||
this.latitude = wxMarkerData[0].latitude;
|
||||
this.longitude = wxMarkerData[0].longitude;
|
||||
|
||||
// 通过父组件查询数据
|
||||
this.$emit('getSearchLeader', {
|
||||
latitude: this.latitude,
|
||||
longitude: this.longitude
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
onBlurSearch(value) {
|
||||
this.$emit('update:searchKeyword', value);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
searchKeyword: {
|
||||
handler(newVal, oldVal) {
|
||||
console.log(newVal, oldVal)
|
||||
this.searchLocation(newVal);
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getSysRegionFindAllListAction();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.gg {
|
||||
&-header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&-location {
|
||||
text {
|
||||
color: gray;
|
||||
}
|
||||
}
|
||||
|
||||
&-search {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<block>
|
||||
<u-tag v-if="isCurrent" class="gg-current-location-tag u-m-l-20" mode="dark" size="mini" text="当前提货点"
|
||||
type="error"/>
|
||||
|
||||
<view :class="{ selected }" class="gg-current-location u-p-20" @click="changePickUpLocation(location.id)">
|
||||
<u-image :src="location.storePath" border-radius="10rpx" class="gg-current-location-img" height="150rpx"
|
||||
width="150rpx"></u-image>
|
||||
<view class="gg-current-location-msg u-m-l-20 u-m-r-20">
|
||||
<view class="gg-current-location-msg-title u-m-b-5">{{ location.takeName }}</view>
|
||||
<view class="gg-current-location-msg-distance-address u-m-t-5">
|
||||
<text v-if="location.distance" class="gg-current-location-msg-distance u-font-xs u-m-r-20">
|
||||
距离最近*距离{{ location.distance }}km
|
||||
</text>
|
||||
<text class="gg-current-location-msg-address u-font-xs">{{ location.detailAddress }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<block v-if="showRadio">
|
||||
<view v-if="isCurrent" class="gg-current-location-btn">
|
||||
<u-icon color="#fa3534" name="checkmark-circle-fill" size="40"/>
|
||||
</view>
|
||||
<view v-else class="gg-current-location-btn">
|
||||
<u-icon name="checkmark-circle-fill" size="40"/>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</block>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'PickUpLocationItem',
|
||||
props: {
|
||||
selected: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isCurrent: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showRadio: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
location: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changePickUpLocation(id) {
|
||||
this.$emit('selectPickUpLocation', id);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.selected {
|
||||
background-color: $u-type-info !important;
|
||||
}
|
||||
|
||||
.gg-current-location {
|
||||
display: flex;
|
||||
background-color: $u-type-info-light;
|
||||
border-radius: 20rpx;
|
||||
|
||||
&-tag {
|
||||
position: absolute;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
&-msg {
|
||||
flex: 1;
|
||||
|
||||
&-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&-distance {
|
||||
color: $u-type-error;
|
||||
}
|
||||
|
||||
&-address {
|
||||
color: $u-type-info;
|
||||
}
|
||||
}
|
||||
|
||||
&-btn {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user