修正项目

This commit is contained in:
2024-01-07 01:10:08 +08:00
parent 2f29241806
commit b22014e976
943 changed files with 27699 additions and 28227 deletions

View File

@@ -0,0 +1,19 @@
{
// launch.json 配置了启动调试时相关设置configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
// launchtype项可配置值为local或remote, local代表前端连本地云函数remote代表前端连云端云函数
"version": "0.0",
"configurations": [
{
"default": {
"launchtype": "local"
},
"h5": {
"launchtype": "local"
},
"mp-weixin": {
"launchtype": "local"
},
"type": "uniCloud"
}
]
}

23
xlcs-user/App.vue Normal file
View File

@@ -0,0 +1,23 @@
<script>
export default {
onLaunch: function () {
console.log('App Launch')
},
onShow: function () {
console.log('App Show')
},
onHide: function () {
console.log('App Hide')
}
}
</script>
<style lang="scss">
/* 注意要写在第一行同时给style标签加入lang="scss"属性 */
@import "./common/css/iconfont.css";
@import "uview-ui/index.scss";
page {
height: 100%;
}
</style>

1
xlcs-user/common/bmap-wx.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
export const BAIDU_MAP_AK = 'jU4Ww0DiPzXUZmCshR6XjcH5Y3AG6GCE'
export const BAIDU_MAP_WEB_AK = '1FRohQ2W2TH9XGvEHmuckB6G'

View File

@@ -0,0 +1,123 @@
@font-face {
font-family: "iconfont"; /* Project id 2738663 */
src: url('./common/css/iconfont.woff2?t=1629617005518') format('woff2'),
url('./common/css/iconfont.woff?t=1629617005518') format('woff'),
url('./common/css/iconfont.ttf?t=1629617005518') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-pinglun2:before {
content: "\e629";
}
.icon-tihuoguanli:before {
content: "\e6a9";
}
.icon-daifahuo1:before {
content: "\e612";
}
.icon-daifukuan:before {
content: "\e621";
}
.icon-tuikuanshouhou:before {
content: "\e6bb";
}
.icon-truck-full:before {
content: "\e9d9";
}
.icon-daifahuo:before {
content: "\e708";
}
.icon-dianpu:before {
content: "\e650";
}
.icon-miaosha:before {
content: "\e60e";
}
.icon-tubiaolunkuo-:before {
content: "\e605";
}
.icon-kefu:before {
content: "\e601";
}
.icon-shezhi:before {
content: "\e61c";
}
.icon-yonghu:before {
content: "\e616";
}
.icon-yaoqing:before {
content: "\e687";
}
.icon-ico:before {
content: "\e646";
}
.icon-yonghu1:before {
content: "\e615";
}
.icon-zhekou-:before {
content: "\e607";
}
.icon-tousu:before {
content: "\e638";
}
.icon-jiameng:before {
content: "\e624";
}
.icon-shanghupiliangruzhu:before {
content: "\e62b";
}
.icon-biaoqiankuozhan_tuijian-394:before {
content: "\ebfb";
}
.icon-tubiaozhizuomoban:before {
content: "\e647";
}
.icon-shuiguo:before {
content: "\f342";
}
.icon-cart:before {
content: "\e60c";
}
.icon-aui-icon-my:before {
content: "\e61f";
}
.icon-categories:before {
content: "\e60f";
}
.icon-home:before {
content: "\e61b";
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,167 @@
import {BAIDU_MAP_WEB_AK} from './const.js';
const get_baidu_map_address =
`https://api.map.baidu.com/reverse_geocoding/v3/?output=json&ak=${BAIDU_MAP_WEB_AK}&coordtype=wgs84ll&location=` // 通过经纬度获取地址信息
const get_home_index = 'home/index' // 获取首页数据
const get_sys_region_find_all_list = '/sys/region/findAllList' // 查询所有提供点的区域
const get_search_leader = '/search/leader' // 根据经纬度搜索提货点
const get_select_leader = 'user/leader/auth/selectLeader' // 选择提货点
const get_categories = '/home/category' // 获取分类
const get_search_sku = '/search/sku' // 搜索商品
const get_home_item = '/home/item' // 商品详情
const get_add_to_cart = '/cart/addToCart' // 加入购物车
const get_cart_list = '/cart/cartList' // 购物车列表
const get_check_cart = '/cart/checkCart' // 切换购物车商品的选中状态
const delete_cart = '/cart/deleteCart' // 删除购物车
const get_activity_cart_list = '/cart/activityCartList' // 带活动的购物车列表
const get_check_all_cart = '/cart/checkAllCart' // 对所有购物车商品进行全选/反选
const post_batch_check_cart = '/cart/batchCheckCart' // 对指定的多个商品进行选择/反选
const get_find_all_sec_kill_time_list = '/activity/seckill/findAllSeckillTimeList' // 从缓存中查询时间段列表
const get_find_sec_kill_sku_list = '/activity/seckill/findSeckillSkuList/' // 从缓存中读取秒杀sku
const get_coupon_info = '/activity/auth/getCouponInfo/' // 领取优惠券
const get_confirm_order = '/order/auth/confirmOrder' // 确认订单
const post_submit_order = '/order/auth/submitOrder' // 生成订单
const get_order_info = '/order/auth/getOrderInfoById' // 订单详情
const get_wx_login = '/user/weixin/wxLogin' // 微信用户登陆
const post_update_user = '/user/weixin/auth/updateUser' // 更新用户信息
const get_weixin_payment = '/payment/weixin/createJsapi' // 获取微信支付信息
const get_find_user_order = '/order/auth/findUserOrderPage' // 获取用户订单信息
const get_order_status = '/payment/weixin/queryPayStatus' // 获取订单状态
const install = (Vue, vm) => {
const limit = 10;
const page = 1
// 获取首页数据
const getHomeIndex = () => vm.$u.get(get_home_index);
/*---------------------------------------------------------
提货点模块
---------------------------------------------------------*/
// 根据经纬度获取地址信息
const getBaiduMapAddress = (o) => vm.$u.get(get_baidu_map_address + `${o.latitude},${o.longitude}`)
// 查询所有提供点的区域
const getSysRegionFindAllList = () => vm.$u.get(get_sys_region_find_all_list, {
showLoading: false
});
// 根据经纬度搜索提货点
const getSearchLeader = (o) => vm.$u.get(get_search_leader + `/${o.page}/${o.limit}`, {
...o,
showLoading: false
})
// 选择提货点
const getSelectLeader = (o) => vm.$u.get(get_select_leader + `/${o.leaderId}`, {
showLoading: false
})
/*---------------------------------------------------------
商品模块
---------------------------------------------------------*/
// 获取分类
const getCategories = () => vm.$u.get(get_categories, {
showLoading: false
});
// 搜索商品
const getSearchSku = (o) => vm.$u.get(get_search_sku +
`/${o.page || page}/${o.limit || limit}`, {
...o,
limit: o.limit || limit
});
// 商品详情
const getHomeItem = (o) => vm.$u.get(get_home_item + `/${o.skuId}`);
/*---------------------------------------------------------
秒杀模块
---------------------------------------------------------*/
// 从缓存中查询时间段列表
const getFindAllSeckillTimeList = () => vm.$u.get(get_find_all_sec_kill_time_list);
// 从缓存中读取秒杀sku
const getFindSeckillSkuList = (o) => vm.$u.get(get_find_sec_kill_sku_list + `/${o.timeName}`);
/*---------------------------------------------------------
购物车模块
---------------------------------------------------------*/
// 加入购物车
const getAddToCart = (o) => vm.$u.get(get_add_to_cart + `/${o.skuId}/${o.skuNum}`, {
showLoading: false
});
// 购物车列表
const getCartList = () => vm.$u.get(get_cart_list);
// 切换购物车商品的选中状态
const getCheckCart = (o) => vm.$u.get(get_check_cart + `/${o.skuId}/${o.isChecked}`, {
showLoading: false
});
// 删除购物车
const deleteCart = (skuId) => vm.$u.delete(delete_cart + `/${skuId}`, {
showLoading: false
});
// 带活动的购物车列表
const getActivityCartList = (o) => vm.$u.get(get_activity_cart_list, {
showLoading: o.showLoading ? o.showLoading : false
});
// 对所有购物车商品进行全选/反选
const getCheckAllCart = (o) => vm.$u.get(get_check_all_cart + `/${o.isChecked}`, {
showLoading: o.showLoading ? o.showLoading : false
});
// 对指定的多个商品进行选择/反选
const postBatchCheckCart = (o) => vm.$u.post(post_batch_check_cart + `/${o.isChecked}`, o.skuIdList);
// 领取优惠券
const getCouponInfo = (o) => vm.$u.get(get_coupon_info + `/${o.id}`)
// 确认订单
const getConfirmOrder = () => vm.$u.get(get_confirm_order)
// 生成订单
const postSubmitOrder = (o) => vm.$u.post(post_submit_order, o)
// 订单详情
const getOrderInfo = (o) => vm.$u.get(get_order_info + `/${o.orderId}`)
// 获取微信支付信息
const getWxPayment = (o) => vm.$u.get(get_weixin_payment + `/${o.orderNo}`)
// 获取订单状态信息
const getOrderStatus = (o) => vm.$u.get(get_order_status + `/${o.orderNo}`)
/*---------------------------------------------------------
用户登陆
---------------------------------------------------------*/
// 微信用户登陆
const getWxLogin = (o) => vm.$u.get(get_wx_login + `/${o.code}`, {
showLoading: false
})
// 更新用户信息
const postUpdateUser = (o) => vm.$u.post(post_update_user, {
...o,
showLoading: false
})
// 获取用户订单信息
const getFindUserOrder = (o) => vm.$u.get(get_find_user_order + `/${o.page}/${o.limit}`, {
...o
})
vm.$u.api = {
getHomeIndex,
getSysRegionFindAllList,
getSearchLeader,
getSelectLeader,
getCategories,
getSearchSku,
getHomeItem,
getAddToCart,
getCartList,
getCheckCart,
deleteCart,
getActivityCartList,
getCheckAllCart,
postBatchCheckCart,
getBaiduMapAddress,
getFindAllSeckillTimeList,
getFindSeckillSkuList,
getCouponInfo,
getConfirmOrder,
postSubmitOrder,
getOrderInfo,
getWxPayment,
getWxLogin,
postUpdateUser,
getFindUserOrder,
getOrderStatus
};
}
export default {
install
}

View File

@@ -0,0 +1,37 @@
const install = (Vue, vm) => {
Vue.prototype.$u.http.setConfig({
baseUrl: 'http://127.0.0.1:8200/api',
loadingText: '请求中...', // 请求loading中的文字提示
loadingTime: 800, // 在此时间内请求还没回来的话就显示加载中动画单位ms
loadingMask: true, // 展示loading的时候是否给一个透明的蒙层防止触摸穿透
});
// 请求拦截配置Token等参数
Vue.prototype.$u.http.interceptor.request = (config) => {
config.header.token = uni.getStorageSync('token')
return config;
}
// 响应拦截,判断状态码是否通过
Vue.prototype.$u.http.interceptor.response = (res) => {
if (res.code == 200) {
return res.data;
} else if (res.code == 208) {
// 未登陆token过期
uni.reLaunch({
url: '/pages/login/login'
})
return false;
} else {
uni.showToast({
title: res.message,
icon: 'none'
})
return false;
}
}
}
export default {
install
}

File diff suppressed because one or more lines are too long

View 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>

View 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>

View 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>

View File

@@ -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>

View File

@@ -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>

15
xlcs-user/index.html Normal file
View File

@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
name="viewport"/>
<title></title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script src="/main.js" type="module"></script>
</body>
</html>

26
xlcs-user/main.js Normal file
View File

@@ -0,0 +1,26 @@
import App from './App'
import Vue from 'vue'
import uView from "uview-ui";
import store from './store'
import dayjs from 'dayjs';
Vue.prototype.$dayjs = dayjs;
Vue.use(uView);
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
...App,
store
})
// http拦截器将此部分放在new Vue()和app.$mount()之间才能App.vue中正常使用
import httpInterceptor from '@/common/http.interceptor.js'
Vue.use(httpInterceptor, app)
// http接口API集中管理引入部分
import httpApi from '@/common/http.api.js'
Vue.use(httpApi, app)
app.$mount()

80
xlcs-user/manifest.json Normal file
View File

@@ -0,0 +1,80 @@
{
"name" : "xlcs-user",
"appid" : "__UNI__719160A",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",
"transformPx" : false,
/* 5+App */
"app-plus" : {
"usingComponents" : true,
"nvueStyleCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
/* */
"modules" : {},
/* */
"distribute" : {
/* android */
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
/* ios */
"ios" : {},
/* SDK */
"sdkConfigs" : {}
}
},
/* */
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "wx2edefe049c6a37b9",
"setting" : {
"urlCheck" : false,
"es6" : true,
"postcss" : true,
"minified" : true
},
"usingComponents" : true,
"permission" : {
"scope.userLocation" : {
"desc" : "获取地理位置"
}
}
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
},
"vueVersion" : "2"
}

7
xlcs-user/package.json Normal file
View File

@@ -0,0 +1,7 @@
{
"dependencies": {
"dayjs": "^1.10.7",
"uview-ui": "^1.8.4",
"vuex": "^3.6.2"
}
}

164
xlcs-user/pages.json Normal file
View File

@@ -0,0 +1,164 @@
{
"easycom": {
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
},
"pages": [
//pages数组中第一项表示应用启动页参考https://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",
"style": {
"navigationStyle": "custom",
// 隐藏系统导航栏
"navigationBarTextStyle": "white",
// 状态栏字体为白色,只能为 white-白色black-黑色 二选一
"navigationBarTitleText": "uni-app"
}
},
{
"path": "pages/categories/categories",
"style": {
"navigationStyle": "custom",
// 隐藏系统导航栏
"navigationBarTitleText": "分类",
"enablePullDownRefresh": false
}
},
{
"path": "pages/cart/cart",
"style": {
"navigationStyle": "custom",
// 隐藏系统导航栏
"navigationBarTitleText": "购物车",
"enablePullDownRefresh": false
}
},
{
"path": "pages/my/my",
"style": {
"navigationStyle": "custom",
// 隐藏系统导航栏
"navigationBarTitleText": "我的",
"enablePullDownRefresh": false
}
},
{
"path": "pages/login/login",
"style": {
"navigationBarTitleText": "登陆页",
"enablePullDownRefresh": false
}
},
{
"path": "pages/homeItem/homeItem",
"style": {
"navigationStyle": "custom",
// 隐藏系统导航栏
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"tabBar": {
"color": "#2c2c2c",
"selectedColor": "#d81e06",
"borderStyle": "white",
"backgroundColor": "#ffffff",
"list": [
{
"pagePath": "pages/index/index",
"iconPath": "static/images/tabbar/home.png",
"selectedIconPath": "static/images/tabbar/home-selected.png",
"text": "首页"
},
{
"pagePath": "pages/categories/categories",
"iconPath": "static/images/tabbar/categories.png",
"selectedIconPath": "static/images/tabbar/categories-selected.png",
"text": "分类"
},
{
"pagePath": "pages/cart/cart",
"iconPath": "static/images/tabbar/cart.png",
"selectedIconPath": "static/images/tabbar/cart-selected.png",
"text": "购物车"
},
{
"pagePath": "pages/my/my",
"iconPath": "static/images/tabbar/my.png",
"selectedIconPath": "static/images/tabbar/my-selected.png",
"text": "我的"
}
]
},
"subPackages": [
{
"root": "pagesLocation",
"pages": [
{
"path": "myPickUpLocation/myPickUpLocation",
"style": {
"navigationBarTitleText": "我的提货点",
"enablePullDownRefresh": false
}
},
{
"path": "choosePickUpLocation/choosePickUpLocation",
"style": {
"navigationBarTitleText": "选择其它提货点",
"enablePullDownRefresh": false
}
}
]
},
{
"root": "pagesOrder",
"pages": [
{
"path": "confirmOrder/confirmOrder",
"style": {
"navigationBarTitleText": "确认订单",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
// 隐藏系统导航栏
}
},
{
"path": "getOrderInfo/getOrderInfo",
"style": {
"navigationBarTitleText": "确认支付",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
// 隐藏系统导航栏
}
},
{
"path": "orderList/orderList",
"style": {
"navigationBarTitleText": "订单列表",
"enablePullDownRefresh": false
}
}
]
},
{
"root": "pagesSeckill",
"pages": [
{
"path": "seckill/seckill",
"style": {
"navigationBarTitleText": "限时秒杀",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
// 隐藏系统导航栏
}
}
]
}
]
}

View File

@@ -0,0 +1,228 @@
<template>
<view class="gg">
<u-navbar :border-bottom="false" :is-back="false">
<view class="u-flex u-m-l-20 u-m-r-20">
<view class="u-font-xl u-m-r-20">购物车</view>
<view class="u-font-xs u-light-color u-p-t-10">{{ getSelectedCount }}件商品</view>
</view>
</u-navbar>
<view class="gg-content">
<scroll-view v-if="getCartInfoList" class="gg-cart-sv-container" scroll-y="true">
<u-checkbox-group>
<view v-for="(cartInfoListItem, index) in getCartInfoList" :key="index">
<u-card :border="false" :padding="10" :show-head="showMultiCheckbox(index)">
<view slot="head" class="u-m-10">
<u-checkbox
:name="getMultiCheckedIds(index)"
:value="getMultiCheckCart(index)"
active-color="red"
shape="circle"
@change="changeMultiChecked"
></u-checkbox>
<text>{{ cartInfoListItem.activityRule.ruleDesc }}</text>
</view>
<view slot="body">
<view v-for="(cartInfoItem, idx) in cartInfoListItem.cartInfoList" :key="idx">
<!-- 动态class绑定是为了确保最后一条底部线条不显示 -->
<view :class="{ 'u-border-bottom': idx !== cartInfoListItem.cartInfoList.length - 1 }"
class="u-body-item u-flex u-col-between u-p-10">
<u-checkbox
v-model="cartInfoItem.isChecked"
:name="cartInfoItem.skuId"
active-color="red"
shape="circle"
@change="changeChecked"
></u-checkbox>
<ListImgItem
:lazyLoad="false"
:showBottom="cartInfoItem.skuType === 0 && cartInfoItem.isNewPerson === 1"
:showLeft="cartInfoItem.skuType === 1"
:showRight="false"
:src="cartInfoItem.imgUrl"
height="200rpx"
width="200rpx"
></ListImgItem>
<view class="u-p-b-20 u-m-l-20" style="flex:1">
<view class="u-font-lg">{{ cartInfoItem.skuName }}</view>
<view class="u-flex u-row-between">
<view class="u-type-error">
<text></text>
<text>{{ cartInfoItem.cartPrice }}</text>
</view>
<AddToCart :shopDetail="cartInfoItem" :skuId="cartInfoItem.skuId"></AddToCart>
</view>
</view>
</view>
</view>
</view>
</u-card>
</view>
</u-checkbox-group>
</scroll-view>
<u-empty v-else :margin-top="300" mode="car">
<u-button slot="bottom" type="error" @click="gotoCategory">点击购买商品</u-button>
</u-empty>
<view class="gg-navigation">
<view class="navigation">
<view class="left">
<view class="item u-m-t-20">
<u-checkbox :value="isAllSelected" active-color="red" shape="circle"
@change="changeAllSelected"></u-checkbox>
</view>
<view class="item">
<view class="u-font-sm u-line-1">
<view class="u-type-error">现价:{{ getCartPriceInfo.totalAmount }}</view>
<view class="u-font-xs u-type-info">
优惠券优惠:{{ getCartPriceInfo.couponReduceAmount }}
<text class="u-font-xs u-m-l-20 u-type-info">原价:</text>
<text class="u-font-xs u-type-info">{{ getCartPriceInfo.originalTotalAmount }}</text>
</view>
</view>
</view>
<!-- <view class="item car u-type-info" v-if="getCartCouponInfoList.length > 0" @click="showCouponInfoList = true">
<u-icon name="gift-fill" :size="40" :color="$u.color['contentColor']"></u-icon>
<view class="text u-line-1">优惠券</view>
</view> -->
</view>
<view class="right">
<view class="buy btn u-line-1" @click="gotoConfirmOrder">立即购买</view>
</view>
</view>
</view>
</view>
<CouponInfoList :couponInfoList="getCartCouponInfoList"
:showCouponInfoList.sync="showCouponInfoList"></CouponInfoList>
</view>
</template>
<script>
import {mapActions, mapGetters} from 'vuex';
export default {
data() {
return {
showCouponInfoList: false
};
},
computed: {
...mapGetters('cartModule', [
'getCartInfoList',
'showMultiCheckbox',
'getMultiCheckCart',
'getMultiCheckedIds',
'isAllSelected',
'getCartPriceInfo',
'getSelectedCount',
'getCartCouponInfoList'
])
},
methods: {
...mapActions('cartModule', ['getActivityCartListAction', 'changeCheckCartAction', 'changeMultiCheckedCartAction', 'changeAllCheckCartAction']),
...mapActions('cartModule', ['getCartListAction']),
// 到分类页购买商品
gotoCategory() {
uni.switchTab({
url: '/pages/categories/categories'
});
},
// 修改单个商品选中状态
changeChecked(detail) {
let isChecked = 1;
const {name: skuId, value} = detail;
if (!value) isChecked = 0;
this.changeCheckCartAction({skuId, isChecked});
},
// 修改多个商品的选中状态
changeMultiChecked(detail) {
let skuIdList = [];
skuIdList = detail.name.split(',');
const isChecked = detail.value === true ? 1 : 0;
this.changeMultiCheckedCartAction({skuIdList, isChecked});
},
// 全部选中/返选
changeAllSelected(detail) {
this.changeAllCheckCartAction({isChecked: detail.value === true ? 1 : 0});
},
// 跳转至确认订单
gotoConfirmOrder() {
this.$u.route('/pagesOrder/confirmOrder/confirmOrder')
}
},
// 思考为什么需要将请求放置于onShow钩子函数中
// 主要考虑tabs切换后需要进行实时数据的获取
onShow() {
this.getActivityCartListAction({showLoading: true});
},
mounted() {
// 需要获取购物车数据列表,将最新获取的数据渲染到页面
this.getCartListAction();
}
};
</script>
<style lang="scss">
.gg {
height: 100%;
background-color: $u-bg-color;
// scrollView的固定高度设置
// 底部导航与顶部自定义导航高度需要减去
&-cart-sv-container {
height: calc(100vh - 90rpx - 136rpx);
}
// 底部导航
&-navigation {
width: 100%;
height: 90rpx;
position: fixed;
bottom: 0;
.navigation {
height: 100%;
display: flex;
border: solid 2rpx #f2f2f2;
background-color: #ffffff;
padding: 12rpx 0;
.left {
display: flex;
flex: 1;
font-size: 20rpx;
.item {
margin: 0 10rpx;
&.car {
text-align: center;
position: relative;
}
}
}
.right {
display: flex;
font-size: 28rpx;
align-items: center;
.btn {
line-height: 66rpx;
padding: 0 30rpx;
border-radius: 36rpx;
color: #ffffff;
}
.buy {
background-color: #ff7900;
margin: 0 30rpx;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,295 @@
<template>
<view class="gg">
<u-navbar :border-bottom="false" :is-back="false">
<view class="u-flex u-m-l-20 u-m-r-20 gg-search-navbar">
<view class="u-font-xl u-m-r-20">分类</view>
<view class="gg-notice-search-bar">
<u-icon class="gg-notice-search-bar-left-icon" name="search"></u-icon>
<u-notice-bar
:border-radius="30"
:is-circular="false"
:list="list"
:more-icon="false"
:volume-icon="false"
class="gg-notice-search-bar-u-notice-bar"
mode="vertical"
type="none"
></u-notice-bar>
</view>
</view>
</u-navbar>
<view class="gg-menu-wrap">
<scroll-view :scroll-top="scrollTop" class="gg-tab-view menu-scroll-view" scroll-with-animation scroll-y>
<view
v-for="(item, index) in categories"
:key="item.id"
:class="[current === index ? 'gg-tab-item-active' : '']"
:data-current="index"
class="gg-tab-item"
@tap.stop="swichCategory(item.id, index)"
>
<text class="u-line-1">{{ item.name }}</text>
</view>
</scroll-view>
<scroll-view class="gg-right-box" scroll-y @scrolltolower="loadMore">
<view v-for="(item, index) in searchResult.content" :key="item.id" @click="gotoProductItem(item.id)">
<view class="u-m-b-10 u-m-l-20 u-m-r-20 u-flex gg-product-item">
<ListImgItem
:showBottom="item.skuType === 0 && item.isNewPerson === 1"
:showLeft="item.skuType === 1"
:showRight="false"
:src="item.imgUrl"
height="200rpx"
width="200rpx"
>
<template #left>秒杀商品</template>
</ListImgItem>
<view class="gg-product-item-msg u-border-bottom u-p-b-20 u-m-l-20">
<view>
<view class="u-font-lg">{{ item.title }}</view>
<view class="u-type-info u-font-sm">已售{{ item.sale }}/剩余{{ item.stock }}</view>
<block v-if="item.ruleList">
<view v-for="(rule, ruleIndex) in item.ruleList" :key="ruleIndex" class="u-font-xs u-type-error-dark">
{{ rule }}
</view>
</block>
</view>
<view class="u-flex u-row-between">
<view class="u-type-error gg-product-item-msg-price-container">
<text></text>
<text class="gg-product-item-msg-price-container-value">{{ item.price }}</text>
</view>
<AddToCart :shopDetail="item"></AddToCart>
</view>
</view>
</view>
<u-gap height="20"></u-gap>
</view>
<!-- 如果列表没有更多数据则显示分隔线 -->
<u-divider v-if="!(searchResult.first && searchResult.empty) && searchResult.last" :height="60"
bg-color="transparent">我是有底线的
</u-divider>
<!-- 如果列表没有数据则显示空内容 -->
<u-empty :show="searchResult.first && searchResult.empty" mode="list"></u-empty>
</scroll-view>
</view>
</view>
</template>
<script>
import {mapState, mapActions} from 'vuex';
export default {
data() {
return {
list: ['最见搜索关键字', '暂时未处理搜索页', '可以考虑最见关键字'],
current: 0, // 预设当前项的值
categoryId: 0, // 当前选中的分类Id
scrollTop: 0, //tab标题的滚动条位置
menuHeight: 0, // 左边菜单的高度
menuItemHeight: 0, // 左边菜单item的高度
filter: {
page: 1, // 当前页码
limit: 5, // 每页记录数
keyword: '', // 关键字
wareId: ''
},
searchResult: {
content: [],
last: false
} // 搜索商品结果对象
};
},
computed: {
...mapState('categoriesModule', ['categories'])
},
methods: {
...mapActions('categoriesModule', ['getCategoriesAction']),
...mapActions('cartModule', ['getCartListAction']),
/*
为什么不使用scroll-into-view而使用手动计算的方式
这是因为scroll-into-view不会进行居中菜单位置的定位处理
为了更好的用户操作体验,可以让当前选中菜单定位于整体滚动的居中位置
*/
// 点击左边的栏目切换
async swichCategory(categoryId, index) {
Object.assign(this.$data.searchResult, this.$options.data().searchResult); // 这里重置 searchResult 下的所有数据
Object.assign(this.$data.filter, this.$options.data().filter); // 这里重置 filter 下的所有数据
this.categoryId = categoryId;
if (index == this.current) return; // 防止选中分类的再次点击
this.current = index;
// 如果为0意味着尚未初始化
if (this.menuHeight == 0 || this.menuItemHeight == 0) {
await this.getElRect('menu-scroll-view', 'menuHeight');
await this.getElRect('gg-tab-item', 'menuItemHeight');
}
// 将菜单菜单活动item垂直居中
this.scrollTop = index * this.menuItemHeight + this.menuItemHeight / 2 - this.menuHeight / 2;
// 获取右侧商品搜索结果数据
this.getCategoryProductList();
},
// 获取一个目标元素的高度
getElRect(elClass, dataVal) {
new Promise((resolve, reject) => {
const query = uni.createSelectorQuery().in(this);
query
.select('.' + elClass)
.fields({size: true}, res => {
// 如果节点尚未生成res值为null循环调用执行
if (!res) {
setTimeout(() => {
this.getElRect(elClass);
}, 10);
return;
}
this[dataVal] = res.height;
})
.exec();
});
},
// 获取分类商品列表
async getCategoryProductList() {
const o = {
categoryId: this.categoryId,
page: this.filter.page,
keyword: this.filter.keyword,
limit: this.filter.limit,
wareId: this.filter.wareId
};
let result = await this.$u.api.getSearchSku(o);
this.searchResult = {...result, content: [...this.searchResult.content, ...result.content]};
},
// 加载更多数据
loadMore() {
if (!this.searchResult.last) {
this.filter.page = this.filter.page + 1;
this.getCategoryProductList();
}
},
// 跳转到商品详情页
gotoProductItem(skuId) {
this.$u.route('/pages/homeItem/homeItem', {
skuId
});
}
},
async mounted() {
await this.getCategoriesAction(); // 从仓库中获取分类列表
this.categoryId = this.categories[0].id; // 获取第一个分类的id
await this.getCategoryProductList(); // 商品数据搜索请求
// 需要获取购物车数据列表,将最新获取的数据渲染到页面
this.getCartListAction();
}
};
</script>
<style lang="scss" scoped>
.gg {
height: calc(100vh);
display: flex;
flex-direction: column;
&-search-navbar {
margin-top: -20rpx;
width: 100%;
}
/* 滚动信息搜索框 */
&-notice-search-bar {
flex: 1;
display: flex;
align-items: center;
background-color: #ededed;
border-radius: 30rpx;
/* 滚动信息搜索框左侧图标 */
&-left-icon {
position: relative;
left: 20rpx;
color: $u-light-color;
}
/* 滚动信息搜索框中的字体设置 */
&-u-notice-bar {
flex: 1;
/* 深层穿透修改子组件字体颜色样式 */
::v-deep .u-news-item {
color: $u-light-color !important;
}
}
}
/* 菜单包装器 */
&-menu-wrap {
flex: 1;
display: flex;
overflow: hidden;
}
/* 左侧sv选项卡模式菜单 */
&-tab-view {
width: 200rpx;
height: 100%;
}
/* 左侧菜单选项卡项 */
&-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;
/* 激活状态 */
&-active {
position: relative;
color: $u-type-warning;
font-size: 30rpx;
font-weight: 600;
background: #fff;
/* 伪类处理 */
&::before {
content: '';
position: absolute;
border-left: 4px solid $u-type-warning;
height: 32rpx;
left: 0;
top: 39rpx;
}
}
}
/* 产品列表项 */
&-product-item {
height: 210rpx;
&-msg {
height: 100%;
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
&-price-container {
&-value {
font-size: 40rpx;
}
}
}
}
&-right-box {
background-color: rgb(250, 250, 250);
}
}
</style>

View File

@@ -0,0 +1,336 @@
<template>
<view v-if="!detail.skuInfoVo" class="gg">
<u-empty mode="data"></u-empty>
</view>
<view v-else class="gg">
<u-navbar :border-bottom="false" :is-back="true" class="navbar"></u-navbar>
<scroll-view class="gg-sv" scroll-y>
<view class="gg-content">
<!-- 商品轮播图 -->
<block v-if="swiperList.length > 0">
<u-swiper :height="500" :list="swiperList" indicator-pos="bottomRight" mode="number"></u-swiper>
</block>
<!-- 商品缩略图及属性还有价格购买数量的显示 -->
<view class="u-flex u-type-info-light u-p-20 gg-content-price">
<view class="u-p-r-20">
<ListImgItem
:showBottom="detail.skuInfoVo.skuType === 0 && detail.skuInfoVo.isNewPerson === 1"
:showLeft="detail.skuInfoVo.skuType === 1"
:showRight="false"
:src="detail.skuInfoVo.imgUrl"
height="120rpx"
width="120rpx"
></ListImgItem>
</view>
<!-- 区别秒杀商品与一般商品的价格体系 -->
<!-- 秒杀商品显示 -->
<block v-if="detail.skuInfoVo.skuType === 1">
<view>
<view class="gg-content-price-current u-flex">
<view>秒杀价格{{ detail.seckillSkuVo.seckillSale }}</view>
<view class="u-p-l-20">市场价格{{ detail.skuInfoVo.marketPrice }}</view>
</view>
<view class="gg-content-price-limit">
<view>
限购{{ detail.seckillSkuVo.seckillLimit }} 销售{{ detail.seckillSkuVo.seckillSale }}
库存{{ detail.seckillSkuVo.seckillStock }}
</view>
<view>
秒杀场次{{ detail.seckillSkuVo.timeName }} 倒计时
<u-count-down ref="seckillCountDown" :timestamp="seckillSeconds" @end="seckillEnd"></u-count-down>
</view>
</view>
</view>
</block>
<!-- 普通商品显示 -->
<block v-else>
<view>
<view class="gg-content-price-current u-flex">
<view>当前价格{{ detail.skuInfoVo.price }}</view>
<view class="u-p-l-20">市场价格{{ detail.skuInfoVo.marketPrice }}</view>
</view>
<view class="gg-content-price-limit">
<view>限购数量{{ detail.skuInfoVo.perLimit }}</view>
</view>
</view>
</block>
</view>
<!-- 商品名称 -->
<view class="u-m-20 u-p-20 gg-content-container">
<view class="u-flex">{{ detail.skuInfoVo.skuName }}</view>
</view>
<!-- 属性列表 -->
<view v-if="detail.skuInfoVo.skuAttrValueList.length > 0" class="u-m-20 u-p-20 gg-content-container">
<view v-for="skuAttrValueItem in detail.skuInfoVo.skuAttrValueList" :key="skuAttrValueItem.id"
class="u-p-t-5">
{{ skuAttrValueItem.attrName }}{{ skuAttrValueItem.attrValue }}
</view>
</view>
<!-- 活动规则 -->
<view v-if="detail.activityRuleList.length > 0" class="u-m-20 u-p-20 gg-content-container">
<view v-for="activityRuleItem in detail.activityRuleList" :key="activityRuleItem.id" class="u-p-t-5">
{{ activityRuleItem.ruleDesc }}
</view>
</view>
<!-- 售后与提货地址 -->
<view class="u-m-20 u-p-20 gg-content-container">
<view class="u-flex">
<view class="u-font-sm u-m-r-20 u-type-info">售后无忧</view>
<view class="u-font-sm u-m-r-20 u-flex-1">
支持保价
<text class="u-type-error"></text>
极速退款
<text class="u-type-error"></text>
7天无理由退货
</view>
<u-icon class="u-m-r-20 u-type-info" name="arrow-right" size="24"></u-icon>
</view>
<view class="u-flex u-m-t-20">
<view class="u-font-sm u-m-r-20 u-type-info">提货信息</view>
<view class="u-font-sm u-m-r-20 u-flex-1">
<view>
现在下单
<text class="u-type-error">明天16:00可提货</text>
</view>
<view>提货点{{ leaderAddressVo.takeName ? leaderAddressVo.takeName : '请设置提货点' }}</view>
</view>
<u-icon class="u-m-r-20 u-type-info" name="arrow-right" size="24"></u-icon>
</view>
</view>
<!-- 商品详情图片清单 -->
<view v-if="skuPosterList.length > 0" class="u-m-20 u-p-20 gg-content-container">
<image v-for="skuPoster in skuPosterList" :key="skuPoster.id" :src="skuPoster.image"></image>
</view>
<u-gap height="30"></u-gap>
</view>
</scroll-view>
<view class="gg-navigation">
<view class="navigation">
<view class="left">
<view class="item" @click="gotoHome">
<u-icon :color="$u.color['contentColor']" :size="40" name="home-fill"></u-icon>
<view class="text u-line-1">首页</view>
</view>
<view class="item car">
<u-badge v-if="skuId !== 0" :count="getProductSkuNum(skuId)" :offset="[-3, -6]" class="car-num"
type="error"></u-badge>
<u-icon :color="$u.color['contentColor']" :size="40" name="shopping-cart-fill"></u-icon>
<view class="text u-line-1">购物车</view>
</view>
<view v-if="detail.couponInfoList.length > 0" class="item car" @click="showCouponInfoList = true">
<u-badge :count="detail.couponInfoList.length" :offset="[-3, -6]" class="car-num" type="error"></u-badge>
<u-icon :color="$u.color['contentColor']" :size="40" name="gift-fill"></u-icon>
<view class="text u-line-1">优惠券</view>
</view>
</view>
<!-- 即将秒杀与加入购物车的显示 -->
<view v-if="!seckillEnded" class="right u-p-r-10 u-flex">
<!-- 即将开抢 -->
<block v-if="getDetail.seckillSkuVo.timeStaus === 3">
<view class="u-m-r-20 u-line-1 u-flex-1 u-text-center">场次:{{ getDetail.seckillSkuVo.timeName }}</view>
<view class="buy-disabled btn u-line-1">即将开抢</view>
</block>
<!-- 加入购物车 -->
<block v-else>
<view class="u-m-r-20 u-line-1 u-flex-1">
<AddToCart v-if="detail.skuInfoVo.id" :shopDetail="getDetail" :skuId="detail.skuInfoVo.id"></AddToCart>
</view>
<view class="buy btn u-line-1">立即购买</view>
</block>
</view>
<!-- 秒杀结束显示 -->
<view v-else class="right u-p-r-10 u-flex">
<view class="u-m-r-20 u-line-1 u-flex-1"></view>
<view class="buy-disabled btn u-line-1">秒杀结束</view>
</view>
</view>
</view>
<CouponInfoList :couponInfoList="detail.couponInfoList" :showCouponInfoList.sync="showCouponInfoList"
@getCouponInfo="getCouponInfo"></CouponInfoList>
</view>
</template>
<script>
import {mapState, mapGetters} from 'vuex';
export default {
data() {
return {
detail: {},
skuId: 0,
seckillSeconds: 0,
seckillEnded: false,
showCouponInfoList: false
};
},
computed: {
...mapState('pickUpLocationModule', ['leaderAddressVo']),
...mapGetters('cartModule', ['getProductSkuNum']),
// 轮播图的获取
swiperList() {
let lst = [];
this.detail &&
this.detail.skuInfoVo &&
this.detail.skuInfoVo.skuImagesList.length > 0 &&
this.detail.skuInfoVo.skuImagesList.forEach(item => {
lst.push({
image: item.imgUrl,
title: item.imgName
});
});
return lst;
},
// 商品详情海报图片列表
skuPosterList() {
let lst = [];
this.detail &&
this.detail.skuInfoVo &&
this.detail.skuInfoVo.skuPosterList.length > 0 &&
this.detail.skuInfoVo.skuPosterList.forEach(item => {
lst.push({
image: item.imgUrl,
title: item.imgName
});
});
return lst;
},
getDetail() {
return {...this.detail.skuInfoVo, seckillSkuVo: this.detail.seckillSkuVo};
}
},
methods: {
async getHomeItemData(skuId) {
let result = await this.$u.api.getHomeItem({skuId});
this.detail = result;
// skuInfoVo 商品信息
// couponInfoList 优惠券信息
// activityRuleList 活动信息
// 如果是秒杀商品,需要计算倒计时秒数
if (this.detail.skuInfoVo.skuType === 1) {
const now = this.$dayjs();
const endTime = this.$dayjs(this.$dayjs().format('YYYY-MM-DD') + ' ' + this.detail.seckillSkuVo.endTime);
const seconds = endTime.diff(now, 'second');
this.seckillSeconds = seconds;
}
},
// 切换首页
gotoHome() {
uni.switchTab({
url: '/pages/index/index'
});
return false;
},
// 秒杀倒计时结束
seckillEnd() {
this.seckillEnded = true;
},
// 领取优惠券
async getCouponInfo(id) {
try {
const result = await this.$u.api.getCouponInfo({id});
const pos = this.detail.couponInfoList.findIndex(item => item.id === id);
this.$set(this.detail.couponInfoList[pos], 'couponStatus', 1);
} catch (e) {
console.error(e);
}
}
},
onLoad(options) {
let skuId = +options.skuId;
this.skuId = skuId;
this.getHomeItemData(skuId);
}
};
</script>
<style lang="scss">
.gg {
height: 100%;
&-sv {
height: calc(100vh - 116rpx - 102rpx);
}
&-content {
background-color: $u-bg-color;
&-price {
background: linear-gradient(to right, rgb(255, 180, 61), rgb(255, 101, 0));
}
&-container {
z-index: 9999;
background-color: #fff;
border-radius: 25rpx;
}
}
&-navigation {
position: fixed;
bottom: 0;
width: 100%;
.navigation {
display: flex;
border: solid 2rpx #f2f2f2;
background-color: #ffffff;
padding: 16rpx 0;
justify-content: space-around;
.left {
display: flex;
font-size: 20rpx;
.item {
margin: 0 30rpx;
&.car {
text-align: center;
position: relative;
.car-num {
position: absolute;
top: -10rpx;
right: -10rpx;
}
}
}
}
.right {
width: 375rpx;
display: flex;
font-size: 28rpx;
align-items: center;
.btn {
line-height: 50rpx;
padding: 0 30rpx;
border-radius: 36rpx;
color: #ffffff;
}
.buy {
background-color: #ff7900;
}
.buy-disabled {
background-color: $u-type-info;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,487 @@
<template>
<view v-if="token" class="gg">
<!-- 利用background-image设置导航的线形渐变色彩 -->
<u-navbar :background="{ 'background-image': 'linear-gradient(to right, rgb(255,180,61), rgb(255, 101, 0))' }" :border-bottom="false"
:is-back="false">
<view class="gg-map-slot-wrap u-font-xs u-m-l-20 u-p-l-10 u-p-r-10 u-p-t-5 u-p-b-5" @click="pickUpLocation">
<u-icon name="map" size="24"></u-icon>
<text class="u-p-l-10 u-p-r-10">{{
leaderAddressVo.takeName ? leaderAddressVo.takeName : '请设置提货点'
}}
</text>
<u-icon name="arrow-right" size="20"></u-icon>
</view>
</u-navbar>
<!-- 主内容区域-Begin -->
<view class="gg-content">
<!-- 头部区域 -->
<view class="gg-header u-p-l-20 u-p-r-20">
<!--
头部滚动提示搜索区
1.搜索图标
2.滚动提示条
3.搜索按钮自定义样式
-->
<view class="gg-notice-search-bar">
<u-icon class="gg-notice-search-bar-left-icon" name="search"></u-icon>
<u-notice-bar
:border-radius="30"
:is-circular="false"
:list="list"
:more-icon="false"
:volume-icon="false"
class="gg-notice-search-bar-u-notice-bar"
mode="vertical"
type="none"
></u-notice-bar>
<u-button :custom-style="ggNoticeSearchBarRightBtnCustomStyle" class="u-m-r-20" shape="square" size="mini"
type="error">搜索
</u-button>
</view>
<!-- 新人专享低价好物sv滚动区 -->
<view class="gg-new-vip u-p-20 u-m-t-20">
<view class="u-font-lg u-content-color">新人专享低价好物</view>
<scroll-view class="gg-new-vip-sv" enable-flex scroll-x>
<view class="u-flex u-m-t-10">
<view v-for="(item, index) in newPersonSkuInfoList" :key="item.id" class="gg-new-vip-sv-item u-p-r-20"
@click="gotoProductItem(item.id)">
<ListImgItem
:showBottom="item.skuType === 0 && item.isNewPerson === 1"
:showLeft="item.skuType === 1"
:showRight="false"
:src="item.imgUrl"
height="200rpx"
width="200rpx"
></ListImgItem>
<text class="u-type-error"> {{ item.price }}</text>
<AddToCart :shopDetail="item" :skuId="item.id"></AddToCart>
</view>
</view>
</scroll-view>
</view>
</view>
<!-- 头部区域底部左右圆角区 -->
<view class="gg-header-bottom"></view>
<!-- 小鹿超市规则 -->
<view class="u-flex u-row-between u-p-20 u-m-20 gg-border" @click="showRulePopup = true">
<u-image height="30rpx" src="/static/logo.png" width="30rpx"></u-image>
<view>平台资质法律条款规则及投诉入口</view>
</view>
<!-- 商品分类 -->
<view class="u-m-20 u-p-20 gg-border">
<scroll-view enable-flex scroll-x @scroll="scrollMove">
<view class="u-flex u-p-r-20 u-p-t-20">
<!-- 循环滚动内容 -->
<view v-for="item in categoryList" :key="item.id" class="u-p-l-20 u-p-r-20">
<u-image :src="item.imgUrl" border-radius="30rpx" height="100rpx" width="100rpx"></u-image>
<text class="u-font-xs">{{ item.name }}</text>
</view>
</view>
</scroll-view>
<view class="gg-category">
<u-line-progress :percent="categorySVPercent" :show-percent="false" class="gg-category-progress"
height="5"></u-line-progress>
</view>
</view>
<!-- 限时秒杀 -->
<block v-if="seckillSkuVoList.length > 0">
<!-- 秒杀 -->
<view class="u-m-l-20 u-m-r-20 u-flex">
<view class="u-flex u-flex-1">
<view class="u-font-lg u-type-error">
秒杀抢购
<text class="u-font-sm">{{ seckillTime.name }} {{ seckillTime.startTime }}-{{
seckillTime.endTime
}}
</text>
</view>
</view>
<u-button :plain="true" size="mini" @click="gotoSeckill">查看全部 ></u-button>
</view>
<view class="u-m-20 u-p-20 gg-border">
<scroll-view enable-flex scroll-x>
<view class="u-flex u-p-r-20 u-p-t-20">
<!-- 循环滚动内容 -->
<view v-for="item in seckillSkuVoList" :key="item.skuId" class="u-p-l-20 u-p-r-20 u-text-center"
@click="gotoProductItem(item.skuId)">
<text class="u-font-sm u-m-b-5">{{ item.timeName }}</text>
<u-image :src="item.imgUrl" border-radius="30rpx" height="200rpx" width="200rpx"></u-image>
<text class="u-font-sm u-m-t-5">{{ item.skuName }}</text>
<AddToCart :shopDetail="item" :skuId="item.skuId"></AddToCart>
</view>
</view>
</scroll-view>
</view>
</block>
<!-- 如何购买商品 -->
<view class="u-p-20 u-m-20 gg-border u-font-xs">
<view class="u-m-b-20">如何在[小鹿超市]购买商品</view>
<view class="u-flex">
<view class="gg-number u-m-r-10">1</view>
挑商品
<u-icon name="arrow-right-double u-m-l-10 u-tips-color"></u-icon>
<u-icon class="u-content-color" name="arrow-right-double"></u-icon>
<view class="gg-number gg-number-gray u-m-r-10 u-m-l-10">2</view>
选提货点
<u-icon name="arrow-right-double u-m-l-10 u-tips-color"></u-icon>
<u-icon class="u-content-color" name="arrow-right-double"></u-icon>
<view class="gg-number gg-number-gray u-m-r-10 u-m-l-10">3</view>
次日16点提货点取货
</view>
</view>
<!-- 热销好货 -->
<view class="u-font-xl u-type-error u-m-20">热销好货</view>
<view v-for="(item, index) in hotSkuList" :key="item.id" class="u-p-20 u-m-20 gg-border"
@click="gotoProductItem(item.id)">
<view class="u-m-b-10 u-m-l-20 u-m-r-20 u-flex gg-product-item">
<ListImgItem
:showBottom="item.skuType === 0 && item.isNewPerson === 1"
:showLeft="item.skuType === 1"
:showRight="false"
:src="item.imgUrl"
height="250rpx"
width="250rpx"
></ListImgItem>
<view class="gg-product-item-msg u-border-bottom u-p-b-20 u-m-l-20">
<view class="gg-product-item-msg-title">
<view class="u-font-lg">{{ item.title }}</view>
<view class="u-type-info u-font-sm">已售{{ item.sale }}/剩余{{ item.stock }}</view>
<block v-if="item.ruleList">
<view v-for="(rule, ruleIndex) in item.ruleList" :key="ruleIndex" class="u-font-xs u-type-error-dark">
{{ rule }}
</view>
</block>
</view>
<view class="u-flex u-row-between">
<view class="u-type-error gg-product-item-msg-price">
<text></text>
<text class="gg-product-item-msg-price-value">{{ item.price }}</text>
</view>
<AddToCart :shopDetail="item"></AddToCart>
</view>
</view>
</view>
</view>
<u-gap height="20"></u-gap>
</view>
<!-- 主内容区域-End -->
<!-- 平台资质法律条款规则及投诉入口弹出框 -->
<u-popup v-model="showRulePopup" :closeable="true" border-radius="20" mode="bottom">
<view class="u-p-t-20 u-p-b-20">
<view class="u-m-20">
<view class="u-font-xl u-m-b-10">
<u-icon class="u-m-r-10" color="#dd6161" name="checkmark-circle" size="28"></u-icon>
品质保障
</view>
<view class="u-light-color u-font-xs">
全场商品均经过品质检验若收货时发现商品有变质腐烂损坏等情况可申请退款
</view>
</view>
<view class="u-m-20">
<view class="u-font-xl u-m-b-10">
<u-icon class="u-m-r-10" color="#dd6161" name="kefu-ermai" size="28"></u-icon>
极速退款
</view>
<view class="u-light-color u-font-xs">根据平台的规则在一定条件下可享受极速退款到账服务</view>
</view>
<view class="u-m-20">
<view class="u-font-xl u-m-b-10">
<u-icon class="u-m-r-10" color="#dd6161" name="bag" size="28"></u-icon>
次日自提
</view>
<view class="u-light-color u-font-xs">每日23点前下单次日16点可到下单门店自提</view>
</view>
<view class="u-m-20">
<view class="u-font-xl u-m-b-10">
<u-icon class="u-m-r-10" color="#dd6161" name="integral" size="28"></u-icon>
资质规则
</view>
<view class="u-light-color u-font-xs">平台资质法律条款规则及投诉入口点击查看详情</view>
</view>
</view>
</u-popup>
</view>
<view v-else class="emptyPage">
<u-empty mode="page"></u-empty>
</view>
</template>
<script>
import {mapState, mapGetters, mapActions} from 'vuex';
let watchTimes = 0;
export default {
data() {
return {
list: ['寒雨连江夜入吴', '平明送客楚山孤', '洛阳亲友如相问', '一片冰心在玉壶'],
// 滚动提示搜索区右侧按钮自定义样式
ggNoticeSearchBarRightBtnCustomStyle: {
borderRadius: '30rpx'
},
showRulePopup: false,
windowWidth: 0, // 设备宽度
categorySVPercent: 0, // 精选进度百分比
token: null
};
},
onLoad() {
uni.getSystemInfo({
success: res => {
this.windowWidth = res.windowWidth;
}
});
},
computed: {
...mapState('indexModule', ['home']),
...mapGetters('indexModule', ['categoryList', 'hotSkuList', 'newPersonSkuInfoList', 'seckillTime', 'seckillSkuVoList', 'leaderAddressVo'])
},
methods: {
...mapActions('indexModule', ['getHomeIndexAction']),
scrollMove(e) {
// 计算滚动的进度百分比
let scrollLeft = e.detail.scrollLeft;
let scrollWidth = e.detail.scrollWidth - this.windowWidth;
let percent = parseInt((scrollLeft / scrollWidth) * 100);
// 利用防抖进行性能的优化
this.$u.debounce(() => {
this.categorySVPercent = percent;
}, 100);
},
// 跳转至设置提货点
pickUpLocation() {
this.$u.route('/pagesLocation/myPickUpLocation/myPickUpLocation');
},
// 跳转至商品详情页
gotoProductItem(skuId) {
this.$u.route('/pages/homeItem/homeItem', {skuId});
},
// 跳转至秒杀页
gotoSeckill() {
this.$u.route('/pagesSeckill/seckill/seckill');
}
},
watch: {
/* ------------------------------------------------------------
watch监控第一部分函数式监控
1.只能监控单层数据,不能立即监控,只有数据变化的时候才可以
2.深度监控无法实现
3.函数不可以使用箭头函数否则this对象无法找到
------------------------------------------------------------ */
// leaderAddressVo: function() {
// console.log('normal watch', this.leaderAddressVo);
// }
/* ------------------------------------------------------------
watch监控第二部分对象式监控
1.immediate立即监控的触发次数无论如何先会触发一次监控数据变化
2.深度监控的作用,直接监控对象属性值的变化
3.监控次数的判断
1)因为立即监控,所以页面初始会触发一次
2)可以设置全局变量进行判断条件依据
3)利用监控次数确认路由的跳转
------------------------------------------------------------ */
// 'leaderAddressVo.userId': {
// handler(newVal) {
// watchTimes++;
// if (watchTimes > 1) {
// watchTimes = 0;
// if (!newVal) {
// console.log('immediate deep watch');
// }
// }
// },
// immediate: true,
// deep: true
// }
/* ------------------------------------------------------------
watch监控第三部分对象式监控
1.immediate的去除
2.等mounted请求结束数据设置完毕以后再进行数据变化的监控
3.不需要进行监控次数的判断
------------------------------------------------------------ */
'leaderAddressVo.userId': {
handler(newVal) {
if (!newVal) {
uni.redirectTo({
url: '/pagesLocation/myPickUpLocation/myPickUpLocation'
});
}
},
deep: true
}
},
onShow() {
/*
onShow比mounted先执行
mounted中有获取数据的异步请求本身是异步还需要再进行数据设置获取
onShow已经执行完毕是否能确认leaderAddressVo对象的内容变化不能
是否能在onShow中利用leaderAddressVo进行条件判断不能
*/
console.log('leaderAddressVo:', this.leaderAddressVo);
},
async mounted() {
console.log('mounted');
const token = await uni.getStorageSync('token');
if (this.$u.test.isEmpty(token)) {
uni.reLaunch({
url: '/pages/login/login'
});
return;
}
this.token = token;
await this.getHomeIndexAction();
}
};
</script>
<style lang="scss" scoped>
/*
利用scss中&-的方式实现层级样式的拼接
*/
.gg {
/* navbar 导航中进行地图位置的获取设置 */
&-map-slot-wrap {
display: flex;
align-items: center;
background-color: rgba(240, 240, 240, 0.35);
color: #fff;
border-radius: 100rpx;
}
/* 内容区域 */
&-content {
background-color: $u-bg-color;
}
/*
notice-bar头部滚动信息搜索区域
利用background-image的linear-gradient保持与导航一致的线形渐变色彩
*/
&-header {
background-image: linear-gradient(to right, rgb(255, 180, 61), rgb(255, 101, 0));
height: 500rpx;
}
/* 滚动信息搜索框 */
&-notice-search-bar {
display: flex;
align-items: center;
background-color: white;
border-radius: 30rpx;
/* 滚动信息搜索框左侧图标 */
&-left-icon {
position: relative;
left: 20rpx;
color: $u-light-color;
}
/* 滚动信息搜索框中的字体设置 */
&-u-notice-bar {
flex: 1;
/* 深层穿透修改子组件字体颜色样式 */
::v-deep .u-news-item {
color: $u-light-color !important;
}
}
}
/* 头部区域底部左右圆角区域 */
&-header-bottom {
background-image: linear-gradient(to right, rgb(255, 180, 61), rgb(255, 101, 0));
height: 25rpx;
border-bottom-left-radius: 25rpx;
border-bottom-right-radius: 25rpx;
}
/* 新人专享 */
&-new-vip {
background-color: white;
border-radius: 20rpx;
&-sv {
height: 320rpx;
&-item {
display: flex;
flex-direction: column;
}
}
}
/* 小鹿超市规则 */
&-border {
border-radius: 20rpx;
border-bottom: 1rpx solid #f5f5f5;
box-shadow: 0px 1px 20px 0px rgba(0, 0, 0, 0.1); /*下边阴影 */
}
/* 商品分类 */
&-category {
display: flex;
justify-content: center;
align-items: center;
height: 5rpx;
&-progress {
width: 10vw;
}
}
/* 如何购买商品 */
&-number {
border-radius: 50%;
background-color: $u-type-warning;
width: 30rpx;
height: 30rpx;
text-align: center;
font-size: 20rpx;
color: white;
&-gray {
background-color: gray;
}
}
/* 热销好货 */
&-product-item {
height: 250rpx;
&-msg {
height: 100%;
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
&-price {
&-value {
font-size: 50rpx;
}
}
}
}
}
.emptyPage {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
height: 100vh;
}
</style>

View File

@@ -0,0 +1,139 @@
<template>
<view class="wrap">
<view class="content">
<view class="title">欢迎登陆小鹿超市</view>
</view>
<view class="buttom">
<view class="loginType">
<!-- 对于按钮需要进行禁用判断以防止多次点击 -->
<button :disabled="isLogin" class="loginBtn" @click="getUserMsg">
<view class="wechat item">
<view class="icon">
<u-icon color="rgb(83,194,64)" name="weixin-fill" size="200"></u-icon>
</view>
微信登陆
</view>
</button>
</view>
<view class="hint">
登录代表同意
<text class="link">小鹿超市用户协议隐私政策</text>
并授权使用您的小鹿超市账号信息如昵称头像收获地址以便您统一管理
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
// 防止按钮多次点击的布尔值
isLogin: false,
};
},
methods: {
// 获取用户信息
getUserMsg() {
// 不允许按钮点击
this.isLogin = true;
// 获取用户信息
uni.getUserProfile({
desc: '获取用户信息',
success: res => {
// 获取到用户头像、昵称、性别等内容,并将它们进行本地缓存的存储
const photoUrl = res.userInfo.avatarUrl;
const nickName = res.userInfo.nickName;
const sex = res.userInfo.gender;
uni.setStorageSync('userInfo', {photoUrl, nickName, sex});
// 进行微信登陆操作具体查看小程序登陆wx.login流程图
// https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html
uni.login({
success: async res => {
// 利用小程序登陆配合code码进行用户登陆操作并返回用户的token值
const result = await this.$u.api.getWxLogin({code: res.code});
console.log(result, result.token, "<<<")
// 将token值进行本地缓存存储
uni.setStorage({
key: 'token',
data: result.token,
success: async () => {
// 更新用户信息
// await this.$u.api.postUpdateUser({
// sex,
// photoUrl,
// nickName
// });
// 路由跳转至首页
uni.reLaunch({
url: '/pages/index/index',
});
}
});
}
});
},
fail: err => {
console.log(err);
},
complete: () => {
// 恢复按钮可用性
this.isLogin = false;
}
});
}
}
};
</script>
<style lang="scss" scoped>
.wrap {
font-size: 28rpx;
.content {
width: 600rpx;
margin: 80rpx auto 0;
.title {
text-align: left;
font-size: 60rpx;
font-weight: 500;
margin-bottom: 100rpx;
}
}
.buttom {
.loginType {
display: flex;
justify-content: center;
padding: 100rpx;
.loginBtn {
background: transparent;
}
.loginBtn::after {
border: none;
}
.item {
display: flex;
flex-direction: column;
align-items: center;
color: $u-content-color;
font-size: 28rpx;
}
}
.hint {
padding: 20rpx 40rpx;
font-size: 24rpx;
color: $u-tips-color;
.link {
color: $u-type-warning;
}
}
}
}
</style>

275
xlcs-user/pages/my/my.vue Normal file
View File

@@ -0,0 +1,275 @@
<template>
<view class="gg">
<u-navbar :background="{ 'background-image': 'linear-gradient(to right, rgb(255,180,61), rgb(255, 101, 0))' }" :border-bottom="false"
:is-back="false"></u-navbar>
<view class="gg-content">
<view class="gg-header u-p-l-20 u-p-r-20">
<view class="u-flex u-m-l-20">
<u-image :src="userInfo.photoUrl" height="100rpx" shape="circle" width="100rpx"/>
<view class="u-font-lg u-type-info-light u-m-l-20">Hi {{ userInfo.nickName }}</view>
</view>
<view class="wrap u-p-t-20" justify="between">
<u-row gutter="16">
<u-col span="4">
<view class="gg-order-item">
<view class="u-font-lg u-type-info-light">0</view>
<view class="u-font-xs u-type-info-light">资产</view>
</view>
</u-col>
<u-col span="4">
<view class="gg-order-item">
<view class="u-font-lg u-type-info-light">0.00</view>
<view class="u-font-xs u-type-info-light">红包</view>
</view>
</u-col>
<u-col span="4">
<view class="gg-order-item">
<view class="u-font-lg u-type-info-light">0</view>
<view class="u-font-xs u-type-info-light">优惠券</view>
</view>
</u-col>
</u-row>
</view>
</view>
<view class="gg-header-bottom"></view>
<view class="gg-content-container">
<view class="gg-content-container-box">
<view class="u-flex u-row-between">
<view class="u-m-20">我的订单</view>
<view class="u-m-20 u-font-xs u-type-info" @click="gotoOrderList(-1)">查看全部 ></view>
</view>
<view class="u-flex u-row-around">
<view class="gg-order-item" @click="gotoOrderList(0)">
<view class="iconfont icon-daifukuan u-type-warning"></view>
<view class="u-font-xs">待付款</view>
</view>
<view class="gg-order-item" @click="gotoOrderList(1)">
<view class="iconfont icon-daifahuo1 u-type-warning"></view>
<view class="u-font-xs u-p-l-5">待发货</view>
</view>
<view class="gg-order-item" @click="gotoOrderList(2)">
<view class="iconfont icon-tihuoguanli u-type-warning"></view>
<view class="u-font-xs u-p-l-5">待提货</view>
</view>
<view class="gg-order-item" @click="gotoOrderList(3)">
<view class="iconfont icon-pinglun2 u-type-warning"></view>
<view class="u-font-xs u-p-l-10">待评价</view>
</view>
<view class="gg-order-item" @click="gotoOrderList(4)">
<view class="iconfont icon-tuikuanshouhou u-type-warning"></view>
<view class="u-font-xs">已完结</view>
</view>
</view>
<view class="u-p-20"></view>
</view>
<view class="gg-content-container-box u-m-t-20">
<view class="u-flex u-row-around u-p-t-20">
<view class="gg-order-item">
<image :src="recommend" class="gg-svg-icon"></image>
<view class="u-font-xs">有奖推荐</view>
</view>
<view class="gg-order-item">
<image :src="invite" class="gg-svg-icon"></image>
<view class="u-font-xs u-p-l-5">邀新团长有奖</view>
</view>
<view class="gg-order-item">
<image :src="fruit" class="gg-svg-icon"></image>
<view class="u-font-xs u-p-l-5">7天种水果</view>
</view>
<view class="gg-order-item">
<image :src="discount" class="gg-svg-icon"></image>
<view class="u-font-xs u-p-l-10">天天低价</view>
</view>
</view>
<view class="u-p-20"></view>
</view>
<view class="gg-content-container-box u-m-t-20">
<u-swiper :list="list"></u-swiper>
</view>
<view class="gg-content-container-box u-m-t-20">
<view class="wrap u-p-t-20" justify="between">
<u-row gutter="16">
<u-col span="3">
<view class="gg-order-item">
<view class="iconfont icon-ico"></view>
<view class="u-font-xs">提货码</view>
</view>
</u-col>
<u-col span="3">
<view class="gg-order-item" @click="gotoMyPickUpLocation">
<view class="iconfont icon-dianpu"></view>
<view class="u-font-xs">提货点管理</view>
</view>
</u-col>
<u-col span="3">
<view class="gg-order-item">
<view class="iconfont icon-miaosha"></view>
<view class="u-font-xs">秒杀提醒</view>
</view>
</u-col>
<u-col span="3">
<view class="gg-order-item">
<view class="iconfont icon-yonghu"></view>
<view class="u-font-xs">成为团长</view>
</view>
</u-col>
</u-row>
<u-gap height="30"></u-gap>
<u-row gutter="16">
<u-col span="3">
<view class="gg-order-item">
<view class="iconfont icon-kefu"></view>
<view class="u-font-xs">联系客服</view>
</view>
</u-col>
<u-col span="3">
<view class="gg-order-item">
<view class="iconfont icon-shanghupiliangruzhu"></view>
<view class="u-font-xs">商户入驻</view>
</view>
</u-col>
<u-col span="3">
<view class="gg-order-item">
<view class="iconfont icon-jiameng"></view>
<view class="u-font-xs">代理商加盟</view>
</view>
</u-col>
<u-col span="3">
<view class="gg-order-item">
<view class="iconfont icon-tousu"></view>
<view class="u-font-xs">投诉与建议</view>
</view>
</u-col>
</u-row>
<u-gap height="30"></u-gap>
<u-row gutter="16">
<u-col span="3">
<view class="gg-order-item">
<view class="iconfont icon-shezhi"></view>
<view class="u-font-xs">设置</view>
</view>
</u-col>
</u-row>
<u-gap height="30"></u-gap>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
// https://www.zhangxinxu.com/sp/svgo/ 利用在线svg转base64功能
// 将svg图形转成base64然后再设置成js变量的形式引入使用
// 需要注意将变量设置到data中
// 强调为什么不用iconfont呢和上面的iconfont一样。因为彩色图标变黑了色彩没起作用。
import {fruit, recommend, invite, discount} from '@/common/svgIcon.js';
export default {
data() {
return {
userInfo: {},
fruit,
recommend,
invite,
discount,
list: [
{
image: 'https://cdn.uviewui.com/uview/swiper/1.jpg',
title: '昨夜星辰昨夜风,画楼西畔桂堂东'
},
{
image: 'https://cdn.uviewui.com/uview/swiper/2.jpg',
title: '身无彩凤双飞翼,心有灵犀一点通'
},
{
image: 'https://cdn.uviewui.com/uview/swiper/3.jpg',
title: '谁念西风独自凉,萧萧黄叶闭疏窗,沉思往事立残阳'
}
]
};
},
methods: {
gotoOrderList(index) {
this.$u.route('/pagesOrder/orderList/orderList?current=' + index);
},
gotoMyPickUpLocation() {
uni.navigateTo({
url: '/pagesLocation/myPickUpLocation/myPickUpLocation'
});
}
},
async mounted() {
this.userInfo = uni.getStorageSync('userInfo');
}
};
</script>
<style lang="scss" scoped>
.gg {
height: 100%;
&-content {
height: 100%;
background-color: $u-bg-color;
}
&-header {
background-image: linear-gradient(to right, rgb(255, 180, 61), rgb(255, 101, 0));
height: 300rpx;
}
// 头部区域底部左右圆角区域
&-header-bottom {
background-image: linear-gradient(to right, rgb(255, 180, 61), rgb(255, 101, 0));
height: 100rpx;
border-bottom-left-radius: 100rpx;
border-bottom-right-radius: 100rpx;
}
&-content-container {
margin-left: 20rpx;
width: 710rpx;
position: absolute;
top: 370rpx;
&-box {
display: flex;
flex-direction: column;
background-color: #fff;
border-radius: 25rpx;
.iconfont {
font-size: 50rpx;
width: 80rpx;
height: 60rpx;
text-align: center;
}
}
}
&-order-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
&-svg-icon {
width: 80rpx;
height: 80rpx;
}
}
</style>

View File

@@ -0,0 +1,174 @@
<template>
<view class="gg u-p-20">
<!-- 利用.sync修饰符将searchKeyword传递到子组件 -->
<PickUpLocationHeader :searchKeyword.sync="searchKeyword" @getSearchLeader="getSearchLeader"/>
<u-gap height="20"/>
<map id="pickUpLocationMap" :latitude="latitude" :longitude="longitude" :markers="covers" :scale="scale"
class="gg-location-map" show-location @markertap="mapMarkertap"></map>
<view class="gg-location">
<!-- 利用scroll-into-view进行选中提货点的定位操作 -->
<scroll-view :scroll-into-view="`map-${markerId}`" class="gg-location-scroll" scroll-with-animation scroll-y
@scrolltolower="loadMore">
<block v-if="searchResult.content.length > 0">
<view v-for="(item, index) in searchResult.content" :id="`map-${item.id}`" :key="item.id" class="u-m-b-20">
<PickUpLocationItem
:isCurrent="checkIsCurrent(item.id)"
:location="item"
:selected="markerId === item.id"
@selectPickUpLocation="selectPickUpLocation"
></PickUpLocationItem>
</view>
</block>
<u-empty v-else mode="list"></u-empty>
</scroll-view>
</view>
<view class="gg-confirm-pick-up-location">
<u-button type="warning">确认提货点</u-button>
</view>
</view>
</template>
<script>
import {mapState, mapGetters, mapMutations, mapActions} from 'vuex';
export default {
data() {
return {
searchKeyword: '',
filter: {
page: 1, // 当前页码
limit: 5, // 每页记录数
latitude: '', // 经度
longitude: '' // 纬度
},
searchResult: {
content: [],
last: false
},
scale: 12, // 缩放尺寸
markerId: 0, // 当前选中标记
covers: [
{
latitude: 39.909,
longitude: 116.39742,
iconPath: '/static/images/location.png',
width: 30,
height: 30
}
]
};
},
computed: {
...mapState('pickUpLocationModule', ['leaderAddressVo']),
...mapGetters('pickUpLocationModule', ['checkIsCurrent'])
},
methods: {
...mapActions('pickUpLocationModule', ['selectLeaderAddressVoAction']),
async getSearchLeader(data) {
// 查询数据
if (data) {
Object.assign(this.$data.searchResult, this.$options.data().searchResult); // 这里重置 searchResult 下的所有数据
Object.assign(this.$data.filter, this.$options.data().filter); // 这里重置 filter 下的所有数据
}
this.filter.latitude = data ? data.latitude : this.filter.latitude;
this.filter.longitude = data ? data.longitude : this.filter.longitude;
const o = {
limit: this.filter.limit,
page: this.filter.page,
longitude: this.filter.longitude,
latitude: this.filter.latitude
};
let result = await this.$u.api.getSearchLeader(o);
this.searchResult = {...result, content: [...this.searchResult.content, ...result.content]};
// marker标记点的设置
if (this.searchResult.content.length > 0) {
let covers = [];
this.searchResult.content.map(item => {
covers.push({
id: item.id,
latitude: item.location.lat,
longitude: item.location.lon,
iconPath: '/static/images/location.png',
width: 30,
height: 30
});
});
// 需要将查询结果地图上标识
this.covers = covers;
// 先将位置移动到第一个位置
let latitude = this.searchResult.content[0].location.lat;
let longitude = this.searchResult.content[0].location.lon;
this.pickUpLocationMapCtx.moveToLocation({latitude, longitude}); // 移动到该位置
this.scale = 12;
}
},
// 加载更多数据
loadMore() {
if (!this.searchResult.last) {
this.filter.page = this.filter.page + 1;
this.getSearchLeader();
}
},
// 标记点点击操作
mapMarkertap({detail: {markerId}}) {
this.markerId = markerId
},
// 选择提货点
selectPickUpLocation(leaderId) {
this.selectLeaderAddressVoAction({leaderId});
},
},
onReady: function (e) {
this.pickUpLocationMapCtx = uni.createMapContext('pickUpLocationMap');
},
mounted() {
uni.getLocation({
type: 'gcj02',
success: async res => {
this.covers[0]['latitude'] = res.latitude;
this.covers[0]['longitude'] = res.longitude;
// 通过网页接口从经纬度获取地址信息
// 会报Unhandled promise rejection的错误可以利用trycatch在error阶段获取数据
try {
const result = await this.$u.api.getBaiduMapAddress({latitude: res.latitude, longitude: res.longitude});
} catch (error) {
this.searchKeyword = error.result.addressComponent.district + error.result.addressComponent.street;
}
this.pickUpLocationMapCtx.moveToLocation();
}
});
}
};
</script>
<style lang="scss" scoped>
.gg {
display: flex;
flex-direction: column;
/* 地图设置 */
&-location-map {
width: 100%;
height: calc(100vh - 120rpx - 400rpx - 140rpx);
}
/* 滚动区域 */
&-location {
padding: 20rpx 20rpx 20rpx 20rpx;
&-scroll {
height: 400rpx;
}
}
}
</style>

View File

@@ -0,0 +1,110 @@
<template>
<view class="gg u-p-20">
<PickUpLocationHeader @getSearchLeader="getSearchLeader" />
<view v-if="leaderAddressVo" class="gg-current-location-container u-m-t-20">
<PickUpLocationItem :isCurrent="checkIsCurrent(leaderAddressVo.leaderId)" :location="leaderAddressVo">
</PickUpLocationItem>
</view>
<scroll-view class="gg-location-sv-container" scroll-y @scrolltolower="loadMore">
<block v-if="searchResult.content.length > 0">
<view v-for="(item, index) in searchResult.content" :key="item.id" class="u-m-b-20">
<PickUpLocationItem :isCurrent="checkIsCurrent(item.id)" :location="item"
@selectPickUpLocation="selectPickUpLocation"></PickUpLocationItem>
</view>
</block>
<u-empty v-else mode="list"></u-empty>
</scroll-view>
<u-button type="warning" @click="choosePickUpLocation">搜索并选择其它提货点</u-button>
</view>
</template>
<script>
import {
mapState,
mapGetters,
mapActions
} from 'vuex';
export default {
data() {
return {
filter: {
page: 1, // 当前页码
limit: 5, // 每页记录数
latitude: '', // 经度
longitude: '' // 纬度
},
searchResult: {
content: [], // 搜索的结果
last: false // 是否已经最后
}
};
},
computed: {
...mapState('pickUpLocationModule', ['leaderAddressVo']),
...mapGetters('pickUpLocationModule', ['checkIsCurrent'])
},
methods: {
...mapActions('pickUpLocationModule', ['selectLeaderAddressVoAction']),
async getSearchLeader(data) {
if (data) {
Object.assign(this.$data.searchResult, this.$options.data()
.searchResult); // 这里重置 searchResult 下的所有数据
Object.assign(this.$data.filter, this.$options.data().filter); // 这里重置 filter 下的所有数据
}
this.filter.latitude = data ? data.latitude : this.filter.latitude;
this.filter.longitude = data ? data.longitude : this.filter.longitude;
const o = {
limit: this.filter.limit,
page: this.filter.page,
longitude: this.filter.longitude,
latitude: this.filter.latitude
};
let result = await this.$u.api.getSearchLeader(o);
this.searchResult = {
...result,
content: [...this.searchResult.content, ...result.content]
};
},
// 加载更多数据
loadMore() {
if (!this.searchResult.last) {
this.filter.page = this.filter.page + 1;
this.getSearchLeader();
}
},
// 选择提货点
selectPickUpLocation(leaderId) {
if (leaderId) this.selectLeaderAddressVoAction({
leaderId
});
},
// 选择其它提货点
choosePickUpLocation() {
this.$u.route('/pagesLocation/choosePickUpLocation/choosePickUpLocation');
},
}
};
</script>
<style lang="scss" scoped>
.gg {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
&-current-location-container {
flex: 1;
}
&-location-sv-container {
height: calc(100vh - 450rpx);
}
}
</style>

View File

@@ -0,0 +1,345 @@
<template>
<view class="gg">
<u-navbar :border-bottom="false" :is-back="true">
<view class="u-flex u-m-l-20 u-m-r-20">
<view class="u-font-xl u-m-r-20">生成订单</view>
<view class="u-font-xs u-light-color u-p-t-10">{{ getSelectedCount }}件商品</view>
</view>
</u-navbar>
<view class="gg-content">
<scroll-view v-if="getCartInfoList" class="gg-cart-sv-container" scroll-y="true">
<!-- 提货点 -->
<u-card :padding="10" :show-head="false">
<view slot="body" class="u-m-10">提货点{{ getLeaderAddressVo.takeName }}</view>
</u-card>
<u-card :padding="10" :show-head="true">
<view slot="head" class="u-m-10">提货人联系方式</view>
<view slot="body" class="u-m-10">
<u-input v-model="sumbitOrderForm.receiverName" class="u-p-b-20" placeholder="请输入提货人姓名"/>
<u-input v-model="sumbitOrderForm.receiverPhone" placeholder="请输入提货人电话" type="number"/>
</view>
</u-card>
<!-- 商品 -->
<view v-for="(cartInfoListItem, index) in getCartInfoList" :key="index">
<u-card :border="false" :padding="10" :show-head="showMultiCheckbox(index)">
<view slot="head" class="u-m-10">
<text>{{ cartInfoListItem.activityRule.ruleDesc }}</text>
</view>
<view slot="body">
<view v-for="(cartInfoItem, idx) in cartInfoListItem.cartInfoList" :key="idx">
<!-- 动态class绑定是为了确保最后一条底部线条不显示 -->
<view :class="{ 'u-border-bottom': idx !== cartInfoListItem.cartInfoList.length - 1 }"
class="u-body-item u-flex u-col-between u-p-10">
<ListImgItem
:lazyLoad="false"
:showBottom="cartInfoItem.skuType === 0 && cartInfoItem.isNewPerson === 1"
:showLeft="cartInfoItem.skuType === 1"
:showRight="false"
:src="cartInfoItem.imgUrl"
height="200rpx"
width="200rpx"
></ListImgItem>
<view class="u-p-b-20 u-m-l-20" style="flex:1">
<view>{{ cartInfoItem.skuName }}</view>
<view>购买数量{{ cartInfoItem.skuNum }}</view>
<view class="u-flex u-row-between">
<view class="u-type-error">
<text></text>
<text class="u-font-xl">{{ cartInfoItem.cartPrice }}</text>
</view>
</view>
</view>
</view>
</view>
</view>
</u-card>
</view>
<!-- 优惠券 -->
<u-card v-if="getCartCouponInfoList.length > 0" :padding="10" :show-head="false">
<view slot="body">
<view class="coupon">
<view
v-for="couponInfoItem in getCartCouponInfoList"
:key="couponInfoItem.id"
:class="{ selected: couponInfoItem.selected }"
class="content u-m-b-20"
@click="switchCouponInfoItem(couponInfoItem)"
>
<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.isSelect === 1">
<u-tag text="可以使用" type="error"/>
</block>
<block v-else>
<u-tag text="不能使用" type="info"/>
</block>
<block v-if="couponInfoItem.isOptimal === 1">
<u-tag text="最优推荐" type="error"/>
</block>
<block v-else>
<u-tag text="非优使用" type="info"/>
</block>
</view>
</view>
</view>
</view>
</u-card>
</scroll-view>
<view class="gg-navigation">
<view class="navigation">
<view class="left">
<view class="item u-p-l-20">
<view class="u-font-sm u-line-1">
<view class="u-type-error">现价:{{ getCartPriceInfo.totalAmount }}</view>
<view class="u-font-xs u-type-info">
优惠券优惠:{{ getCartPriceInfo.couponReduceAmount }}
<text class="u-font-xs u-m-l-20 u-type-info">原价:</text>
<text class="u-font-xs u-type-info">{{ getCartPriceInfo.originalTotalAmount }}</text>
</view>
</view>
</view>
</view>
<view class="right">
<view class="buy btn u-line-1" @click="createSubmitOrder">生成订单</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import {mapState, mapGetters, mapActions} from 'vuex';
import dayjs from 'dayjs';
export default {
data() {
return {
couponId: 0,
sumbitOrderForm: {
couponId: 0,
leaderId: 0,
orderNo: '',
receiverName: '',
receiverPhone: ''
}
};
},
computed: {
...mapState('orderModule', ['order']),
...mapGetters('orderModule', ['getCartInfoList', 'getSelectedCount', 'getCartPriceInfo', 'getLeaderAddressVo', 'showMultiCheckbox', 'getCartCouponInfoList']),
getRangeType() {
return function (rangeType) {
switch (rangeType) {
case 'ALL':
return '全场通用';
case 'SKU':
return '指定商品';
case 'CATEGORY':
return '指定分类';
}
};
}
},
methods: {
dayjs,
...mapActions('orderModule', ['getConfirmOrderAction']),
switchCouponInfoItem(couponInfoItem) {
if (couponInfoItem.isSelect) {
this.getCartCouponInfoList.forEach(item => (item.selected = false));
couponInfoItem.selected = true;
const couponReduceAmount = couponInfoItem.amount; // 优惠价格
const totalAmount = this.getCartPriceInfo.originalTotalAmount - couponReduceAmount; // 总价
this.getCartPriceInfo.totalAmount = totalAmount;
this.getCartPriceInfo.couponReduceAmount = couponReduceAmount;
this.couponId = couponInfoItem.id;
} else {
uni.showToast({
title: '优惠券无法使用'
});
}
},
async createSubmitOrder() {
this.sumbitOrderForm.orderNo = this.order.orderNo;
this.sumbitOrderForm.couponId = this.couponId;
this.sumbitOrderForm.leaderId = this.getLeaderAddressVo.leaderId;
if (this.$u.test.isEmpty(this.sumbitOrderForm.receiverName)) {
uni.showToast({
title: '请输入提货者姓名',
icon: 'none'
});
this.sumbitOrderForm.receiverName = '';
return;
}
if (!this.$u.test.mobile(this.sumbitOrderForm.receiverPhone)) {
uni.showToast({
title: '请输入提货者手机号码',
icon: 'none'
});
this.sumbitOrderForm.receiverPhone = '';
return;
}
const result = await this.$u.api.postSubmitOrder(this.sumbitOrderForm);
this.$u.route(`/pagesOrder/getOrderInfo/getOrderInfo?orderId=${result}`);
}
},
mounted() {
this.getConfirmOrderAction();
this.getCartCouponInfoList.map(item => {
if (item.selected) {
this.couponId = item.id;
}
});
}
};
</script>
<style lang="scss">
.gg {
height: 100%;
background-color: $u-bg-color;
// scrollView的固定高度设置
// 底部导航与顶部自定义导航高度需要减去
&-cart-sv-container {
height: calc(100vh - 90rpx - 136rpx);
}
// 底部导航
&-navigation {
width: 100%;
height: 90rpx;
position: fixed;
bottom: 0;
.navigation {
height: 100%;
display: flex;
border: solid 2rpx #f2f2f2;
background-color: #ffffff;
padding: 12rpx 0;
.left {
display: flex;
flex: 1;
font-size: 20rpx;
.item {
margin: 0 10rpx;
&.car {
text-align: center;
position: relative;
}
}
}
.right {
display: flex;
font-size: 28rpx;
align-items: center;
.btn {
line-height: 66rpx;
padding: 0 30rpx;
border-radius: 36rpx;
color: #ffffff;
}
.buy {
background-color: #ff7900;
margin: 0 30rpx;
}
}
}
}
}
.coupon {
background-color: #ffffff;
width: 100%;
// border: 10rpx;
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: 10rpx;
display: flex;
flex-direction: column;
align-items: center;
u-tag {
padding: 5rpx;
}
.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;
}
}
}
}
.selected {
background-color: $u-type-error !important;
}
</style>

View File

@@ -0,0 +1,187 @@
<template>
<view class="gg">
<u-navbar :border-bottom="false" :is-back="true">
<view class="u-flex u-m-l-20 u-m-r-20">
<view class="u-font-xl u-m-r-20">订单详情</view>
</view>
</u-navbar>
<view class="gg-content">
<scroll-view class="gg-cart-sv-container" scroll-y="true">
<!-- 提货点 -->
<u-card :padding="10" :show-head="true">
<view slot="head" class="u-m-10">提货人联系方式</view>
<view slot="body" class="u-m-10">
<view class="u-p-20">收货人员{{ order.receiverName }}</view>
<view class="u-p-20">联系方式{{ order.receiverPhone }}</view>
<view class="u-p-20">提货地点{{ order.receiverAddress }}</view>
</view>
</u-card>
<!-- 商品 -->
<u-card :padding="10" :show-head="true">
<view slot="head" class="u-m-10">选购商品</view>
<view slot="body" class="u-m-10">
<view v-for="(orderItem, index) in order.orderItemList" :key="orderItem.id">
<view class="u-body-item u-flex u-col-between u-p-10">
<u-image :height="200" :lazy-load="true" :src="orderItem.imgUrl" :width="200"></u-image>
<view class="orderItemPrices u-p-20">
<view class="u-font-xl">{{ orderItem.skuName }}</view>
<view>单价{{ orderItem.skuPrice }}</view>
<view>数量{{ orderItem.skuNum }}</view>
<view v-if="orderItem.splitActivityAmount > 0">活动金额:{{ orderItem.splitActivityAmount }}</view>
<view v-if="orderItem.splitCouponAmount > 0">优惠券额:{{ orderItem.splitCouponAmount }}</view>
<view>
小计
<text class="u-type-error">{{ orderItem.splitTotalAmount }}</text>
</view>
</view>
</view>
</view>
<view>
<view class="u-flex u-row-between u-p-20">
<view>商品总额</view>
<view>{{ order.originalTotalAmount }}</view>
</view>
<view class="u-flex u-row-between u-p-20">
<view>实际付款</view>
<view>{{ order.totalAmount }}</view>
</view>
</view>
</view>
</u-card>
<u-card :padding="10" :show-head="false">
<view slot="body" class="u-m-10">
<view class="u-flex u-row-between u-p-20">
<view class="u-flex-1">订单编号</view>
<view class="u-flex">
<view>{{ order.orderNo }}</view>
<view class="u-type-primary u-p-l-10" @click="copyOrderNo">复制</view>
</view>
</view>
<view class="u-flex u-row-between u-p-20">
<view class="u-flex-1">下单时间</view>
<view>{{ order.createTime }}</view>
</view>
</view>
</u-card>
</scroll-view>
<view class="gg-navigation">
<view class="navigation">
<view class="buy btn u-line-1" @click="payOrder">支付订单</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
timer: null,
resul: {},
orderId: 0,
order: {}
};
},
onLoad(options) {
this.orderId = +options.orderId;
},
methods: {
async getOrderInfoById(orderId) {
const result = await this.$u.api.getOrderInfo({orderId});
this.order = result;
},
copyOrderNo() {
uni.setClipboardData({
data: this.order.orderNo, //要被复制的内容
success: () => {
//复制成功的回调函数
uni.showToast({
title: '复制成功',
icon: 'none'
});
}
});
},
async payOrder() {
const result = await this.$u.api.getWxPayment({orderNo: this.order.orderNo});
wx.requestPayment({
timeStamp: result.timeStamp,
nonceStr: result.nonceStr,
package: result.package,
signType: 'MD5',
paySign: result.paySign,
success: res => {
this.$u.api.getOrderStatus({orderNo: this.order.orderNo});
uni.showToast({
title: '支付成功',
icon: 'none'
});
uni.switchTab({
url: '/pages/index/index'
});
},
fail: err => {
uni.showToast({
icon: 'none',
title: err
});
}
});
}
},
mounted() {
this.getOrderInfoById(this.orderId);
}
};
</script>
<style lang="scss">
.gg {
height: 100%;
background-color: $u-bg-color;
// scrollView的固定高度设置
// 底部导航与顶部自定义导航高度需要减去
&-cart-sv-container {
height: calc(100vh - 90rpx - 136rpx);
}
.orderItemPrices {
display: flex;
flex-direction: column;
}
// 底部导航
&-navigation {
width: 100%;
height: 90rpx;
position: fixed;
bottom: 0;
.navigation {
height: 100%;
display: flex;
justify-content: flex-end;
border: solid 2rpx #f2f2f2;
background-color: #ffffff;
padding: 12rpx 0;
.btn {
line-height: 66rpx;
padding: 0 30rpx;
border-radius: 36rpx;
color: #ffffff;
}
.buy {
background-color: #ff7900;
margin: 0 30rpx;
}
}
}
}
</style>

View File

@@ -0,0 +1,341 @@
<template>
<view>
<view class="wrap">
<view class="u-tabs-box">
<u-tabs-swiper ref="tabs" :current="current" :is-scroll="false" :list="list" activeColor="#f29100"
swiperWidth="750" @change="change"></u-tabs-swiper>
</view>
<swiper :current="swiperCurrent" class="swiper-box">
<swiper-item v-for="idx in 5" :key="idx" class="swiper-item">
<scroll-view scroll-y style="height: 100%;width: 100%;" @scrolltolower="reachBottom">
<view class="page-box">
<view v-for="(res, index) in orderList[idx]" :key="res.id" class="order">
<view class="top">
<view class="left">
[{{ index + 1 }}]
<u-icon :size="30" color="rgb(94,94,94)" name="clock"></u-icon>
<u-icon :size="26" color="rgb(203,203,203)" name="arrow-right"></u-icon>
<view class="store">{{ res.createTime }}</view>
</view>
<view class="right">{{ res.param.orderStatusName }}</view>
</view>
<view v-for="(item, index) in res.orderItemList" :key="index" class="item">
<view class="left">
<image :src="item.imgUrl" mode="aspectFill"></image>
</view>
<view class="content">
<view class="title u-line-2">{{ item.skuName }}</view>
<view class="type">活动金额{{ item.splitActivityAmount }}</view>
<view class="type">优惠券金额{{ item.splitCouponAmount }}</view>
</view>
<view class="right">
<view class="price">{{ item.skuPrice }}</view>
<view class="number">x{{ item.skuNum }}</view>
<view class="u-type-error">{{ item.splitTotalAmount }}</view>
</view>
</view>
<view class="total">
<text class="total-price">
<text class="decimal">现价{{ res.totalAmount }} 原价{{ res.originalTotalAmount }}</text>
</text>
</view>
<view class="bottom">
<view class="more">
<u-icon color="rgb(203,203,203)" name="more-dot-fill"></u-icon>
</view>
<view class="logistics btn">查看物流</view>
<view class="exchange btn">卖了换钱</view>
<view class="evaluate btn">评价</view>
</view>
</view>
<u-gap height="30"></u-gap>
<u-loadmore :status="loadStatus[idx]" bgColor="#f2f2f2"></u-loadmore>
</view>
</scroll-view>
</swiper-item>
</swiper>
</view>
</view>
</template>
<script>
export default {
data() {
return {
// 订单列表
orderList: [[], [], [], [], []],
// 订单类型、状态与数量
list: [
{
name: '待付款',
orderStatus: 'UNPAID',
count: 0
},
{
name: '待发货',
orderStatus: 'WAITING_DELEVER',
count: 0
},
{
name: '待收货',
orderStatus: 'WAITING_TAKE',
count: 0
},
{
name: '待评价',
orderStatus: 'WAITING_COMMON',
count: 0
},
{
name: '已完结',
orderStatus: 'FINISHED',
count: 0
}
],
// 当前选中的选项卡
current: 0,
// 当前的swiper
swiperCurrent: 0,
// 每个选项卡数据加载的状态
loadStatus: ['loadmore', 'loadmore', 'loadmore', 'loadmore', 'loadmore'],
// 每个选项卡初始页面
page: [1, 1, 1, 1, 1],
// 每个选项卡总页数
pages: [0, 0, 0, 0, 0],
// 每次列表请求的记录条数
limit: 5
};
},
async onLoad(options) {
// 请求不同状态的初始列表数据
await this.getOrderList(0, 'UNPAID');
await this.getOrderList(1, 'WAITING_DELEVER');
await this.getOrderList(2, 'WAITING_TAKE');
await this.getOrderList(3, 'WAITING_COMMON');
await this.getOrderList(4, 'FINISHED');
let current = +options.current;
if (current !== -1) {
this.change(current);
}
},
methods: {
// 触底加载
reachBottom() {
const orderStatus = this.list[this.current].orderStatus;
if (this.loadStatus[this.current] !== 'nomore') this.getOrderList(this.current, orderStatus);
},
// 页面数据
// idx是数组下标orderStatus是订单状态的常量值请求接口的时候需要使用
async getOrderList(idx, orderStatus) {
const result = await this.$u.api.getFindUserOrder({
page: this.page[idx],
limit: this.limit,
orderStatus
});
// 给每个选项卡存储总页数以及总记录数
this.pages[idx] = result.pages; // 设置总页数
this.list[idx].count = result.total; // 总记录数
// 对于每个选项卡
// 其中每一个如果总页数为0则没有记录loadmore组件状态为nomore
// 并且不需要执行后续操作内容
if (this.pages[idx] === 0) {
this.loadStatus.splice(idx, 1, 'nomore');
return;
}
// 如果每个选项卡的当前页值小于总页数值,
// 那么需要将请求后的数据与之前数据进行数据合并,
// 并且确认loadmore组件的状态为loadmore可加载更多
// 还需要将页码数进行+1操作
if (this.page[idx] <= this.pages[idx]) {
this.orderList[idx] = [...this.orderList[idx], ...result.records];
this.loadStatus.splice(idx, 1, 'loadmore');
this.page[idx] = this.page[idx] + 1;
} else {
this.loadStatus.splice(idx, 1, 'nomore');
}
},
// tab栏切换
change(index) {
this.swiperCurrent = index;
this.current = index;
const orderStatus = this.list[index].orderStatus;
this.getOrderList(index, orderStatus);
}
}
};
</script>
<style>
/* #ifndef H5 */
page {
height: 100%;
background-color: #f2f2f2;
}
/* #endif */
</style>
<style lang="scss" scoped>
.order {
width: 710rpx;
background-color: #ffffff;
margin: 20rpx auto;
border-radius: 20rpx;
box-sizing: border-box;
padding: 20rpx;
font-size: 28rpx;
.top {
display: flex;
justify-content: space-between;
.left {
display: flex;
align-items: center;
.store {
margin: 0 10rpx;
font-size: 32rpx;
font-weight: bold;
}
}
.right {
color: $u-type-warning-dark;
}
}
.item {
display: flex;
margin: 20rpx 0 0;
.left {
margin-right: 20rpx;
image {
width: 200rpx;
height: 200rpx;
border-radius: 10rpx;
}
}
.content {
flex: 1;
.title {
font-size: 28rpx;
line-height: 50rpx;
}
.type {
margin: 10rpx 0;
font-size: 24rpx;
color: $u-tips-color;
}
.delivery-time {
color: #e5d001;
font-size: 24rpx;
}
}
.right {
margin-left: 10rpx;
padding-top: 20rpx;
text-align: right;
.decimal {
font-size: 24rpx;
margin-top: 4rpx;
}
.number {
color: $u-tips-color;
font-size: 24rpx;
}
}
}
.total {
margin-top: 20rpx;
text-align: right;
font-size: 24rpx;
.total-price {
font-size: 32rpx;
}
}
.bottom {
display: flex;
margin-top: 40rpx;
padding: 0 10rpx;
justify-content: space-between;
align-items: center;
.btn {
line-height: 52rpx;
width: 160rpx;
border-radius: 26rpx;
border: 2rpx solid $u-border-color;
font-size: 26rpx;
text-align: center;
color: $u-type-info-dark;
}
.evaluate {
color: $u-type-warning-dark;
border-color: $u-type-warning-dark;
}
}
}
.centre {
text-align: center;
margin: 200rpx auto;
font-size: 32rpx;
image {
width: 164rpx;
height: 164rpx;
border-radius: 50%;
margin-bottom: 20rpx;
}
.tips {
font-size: 24rpx;
color: #999999;
margin-top: 20rpx;
}
.btn {
margin: 80rpx auto;
width: 200rpx;
border-radius: 32rpx;
line-height: 64rpx;
color: #ffffff;
font-size: 26rpx;
background: linear-gradient(270deg, rgba(249, 116, 90, 1) 0%, rgba(255, 158, 1, 1) 100%);
}
}
.wrap {
display: flex;
flex-direction: column;
height: calc(100vh - var(--window-top));
width: 100%;
}
.swiper-box {
flex: 1;
}
.swiper-item {
height: 100%;
}
</style>

View File

@@ -0,0 +1,188 @@
<template>
<block v-if="empty">
<u-navbar :background="{ background: 'rgb(255, 101, 0)' }" :border-bottom="false" :is-back="true"
back-icon-color="#fff">
<view class="u-font-xl u-flex u-row-center u-type-info-light u-flex-1">
<view>限时秒杀</view>
</view>
</u-navbar>
<u-empty mode="data"></u-empty>
</block>
<block v-else>
<view class="gg">
<!-- 利用background-image设置导航的线形渐变色彩 -->
<u-navbar :background="{ background: 'rgb(255, 101, 0)' }" :border-bottom="false" :is-back="true"
back-icon-color="#fff">
<view class="u-font-xl u-flex u-row-center u-type-info-light u-flex-1">
<view>限时秒杀</view>
</view>
</u-navbar>
<view class="gg-content">
<view class="gg-content-header">
<scroll-view :scroll-into-view="`scroll-${navId}`" enable-flex scroll-x>
<view class="u-flex u-flex-nowrap u-p-r-20 u-p-t-20">
<!-- 循环滚动内容 -->
<view
v-for="seckillTime in seckillTimeList"
:id="`scroll-${seckillTime.id}`"
:key="seckillTime.id"
class="u-p-l-20 u-p-r-20"
@click="changeNav(seckillTime.id, seckillTime.name)"
>
<view class="u-text-center" style="width: 140rpx;">
<view class="u-font-xl u-type-info-light">{{ seckillTime.name }}</view>
<!-- 1已开抢 2抢购中 3即将开抢 -->
<block v-if="seckillTime.timeStaus === 1">
<u-tag
:bg-color="seckillTime.id === navId ? '#ff0000' : '#fff'"
:color="seckillTime.id === navId ? '#fff' : '#555'"
mode="dark"
shape="circle"
text="已开抢"
/>
</block>
<block v-if="seckillTime.timeStaus === 2">
<u-tag
:bg-color="seckillTime.id === navId ? '#19be6b' : '#fff'"
:color="seckillTime.id === navId ? '#fff' : '#555'"
mode="dark"
shape="circle"
text="抢购中"
/>
</block>
<block v-if="seckillTime.timeStaus === 3">
<u-tag
:bg-color="seckillTime.id === navId ? '#fc0' : '#fff'"
:color="seckillTime.id === navId ? '#fff' : '#555'"
mode="dark"
shape="circle"
text="即将开抢"
/>
</block>
</view>
</view>
</view>
</scroll-view>
<view class="gg-sv-seckill-container">
<view class="u-m-20 u-flex u-flex-1 gg-sv-list-container">
<scroll-view class="gg-sv-list" scroll-y="true">
<view v-for="seckillSku in seckillSkuList" :key="seckillSku.id" class="gg-sv-item">
<u-image :src="seckillSku.imgUrl" border-radius="10rpx" height="400rpx" width="100%"/>
<view class="u-font-xl u-p-t-10 u-p-b-10">{{ seckillSku.skuName }}</view>
<view>限购数量{{ seckillSku.seckillLimit }} 销售量{{ seckillSku.seckillSale }}
库存{{ seckillSku.seckillStock }}
</view>
<view class="u-flex u-flex-1 u-row-between u-p-t-10 ">
<view>
价格
<text class="u-font-xl u-type-error">{{ seckillSku.seckillPrice }}</text>
</view>
<view>
<u-button shape="circle" size="medium" type="error" @click="gotoProductItem(seckillSku.skuId)">
立即抢购
</u-button>
</view>
</view>
</view>
</scroll-view>
</view>
</view>
</view>
</view>
</view>
</block>
</template>
<script>
export default {
data() {
return {
seckillTimeList: [],
timeName: '',
navId: 0,
seckillSkuList: [],
empty: false
};
},
methods: {
// 秒杀时间段获取
async getSeckillTimeList() {
const result = await this.$u.api.getFindAllSeckillTimeList();
this.seckillTimeList = result;
},
// 秒杀商品列表
async geSeckillSkuList(timeName) {
const result = await this.$u.api.getFindSeckillSkuList({timeName});
this.seckillSkuList = result;
},
// 跳转至商品详情
gotoProductItem(id) {
this.$u.route('/pages/homeItem/homeItem?skuId=' + id);
},
// 秒杀时间段进行导航切换
changeNav(navId, timeName) {
this.navId = navId;
this.geSeckillSkuList(timeName);
},
},
async mounted() {
// 获取秒杀时间段与第一个时间段的商品列表
await this.getSeckillTimeList();
if (this.seckillTimeList.length > 0) {
this.navId = this.seckillTimeList[0].id;
this.timeName = this.seckillTimeList[0].name;
this.geSeckillSkuList(this.timeName);
} else {
this.empty = true;
}
}
};
</script>
<style lang="scss">
body {
background-color: $u-bg-color;
}
.gg {
&-content {
&-header {
background-color: rgb(255, 101, 0);
height: 300rpx;
border-bottom-left-radius: 80rpx;
border-bottom-right-radius: 80rpx;
}
}
&-sv-seckill-container {
position: absolute;
z-index: 1;
top: 280rpx;
width: 100%;
}
&-sv-list-container {
background-color: $u-bg-color;
border-radius: 20rpx;
}
&-sv-list {
height: calc(100vh - 380rpx);
padding: 20rpx;
}
&-sv-item {
padding: 20rpx;
border-bottom: 10rpx solid white;
border-radius: 20rpx;
background-color: white;
margin-bottom: 20rpx;
}
.active {
background-color: red !important;
}
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
xlcs-user/static/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

19
xlcs-user/store/index.js Normal file
View File

@@ -0,0 +1,19 @@
import Vue from 'vue'
import Vuex from 'vuex'
import indexModule from './modules/index'
import pickUpLocationModule from './modules/pickUpLocation'
import categoriesModule from './modules/categories'
import cartModule from './modules/cart'
import orderModule from './modules/order'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
indexModule,
pickUpLocationModule,
categoriesModule,
cartModule,
orderModule
},
})

View File

@@ -0,0 +1,246 @@
import Vue from "vue"
const state = {
cartList: [],
activityCartList: {}
};
const getters = {
// 检查商品是否存在于购物车中
checkProductExists(state) {
return function (skuId) {
const pos = state.cartList.findIndex(item => item.skuId === skuId)
return pos === -1 ? false : true;
}
},
// 获取单个商品的购买数量
getProductSkuNum(state) {
return function (skuId) {
const index = state.cartList.findIndex(item => item.skuId === skuId);
return index !== -1 ? state.cartList[index].skuNum : 0;
}
},
// 获取购物车商品信息列表
getCartInfoList(state) {
return state.activityCartList.carInfoVoList
},
// 是否显示包含多个商品的内容
showMultiCheckbox(state) {
return function (index) {
return state.activityCartList.carInfoVoList[index].cartInfoList.length > 1
}
},
// 确认多个商品项是否为选中
getMultiCheckCart(state) {
return function (index) {
return state.activityCartList.carInfoVoList[index].cartInfoList.every(item => item.isChecked === 1);
}
},
// 获取多个商品项的ids
getMultiCheckedIds(state) {
return function (index) {
let ids = []
state.activityCartList.carInfoVoList[index].cartInfoList.forEach(item => ids.push(item.skuId));
return ids.toString();
}
},
// 判断是否全选
isAllSelected(state) {
let isAllSelected = true;
state.activityCartList.carInfoVoList && state.activityCartList.carInfoVoList
.forEach(carInfoItem => {
carInfoItem.cartInfoList.forEach(cartInfoItem => {
if (cartInfoItem.isChecked === 0) {
isAllSelected = false;
return false;
}
})
})
return isAllSelected;
},
// 获取购物车价格信息
getCartPriceInfo(state) {
if (!state.activityCartList.totalAmount) {
return {
couponReduceAmount: 0,
originalTotalAmount: 0,
totalAmount: 0
}
}
return {
couponReduceAmount: state.activityCartList.couponReduceAmount,
originalTotalAmount: state.activityCartList.originalTotalAmount,
totalAmount: state.activityCartList.totalAmount
}
},
// 确认选中购物车的数量
getSelectedCount(state) {
let count = 0;
state.activityCartList.carInfoVoList && state.activityCartList.carInfoVoList
.forEach(carInfoItem => {
carInfoItem.cartInfoList.forEach(cartInfoItem => {
if (cartInfoItem.isChecked === 1) {
count += cartInfoItem.skuNum;
}
})
})
return count;
},
// 获取购物车优惠券信息列表
getCartCouponInfoList(state) {
return state.activityCartList.couponInfoList
},
}
const mutations = {
// 添加到购物车
addShopMutation(state, payload) {
state.cartList.push(payload);
},
// 获取不带活动的购物车列表
getCartListMutation(state, payload) {
state.cartList = payload;
},
// 修改购物车数量
changeSkuNumMutation(state, payload) {
// skuId为商品id
// value为+1或者-1操作的递增值
// currentBuyNum为number-box组件当前商品购物车的操作值
const {
skuId,
value,
currentBuyNum
} = payload
const index = state.cartList.findIndex(item => item.skuId === skuId);
// 如果当前购买数量小于1则删除该商品
if (currentBuyNum < 1) {
state.cartList.splice(index, 1)
} else {
state.cartList[index].skuNum += value
}
},
// 删除购物车
deleteShopMutation(state, payload) {
// 删除cartList中的数据
const cartListIndex = state.cartList.findIndex(item => item.skuId === payload);
state.cartList.splice(cartListIndex, 1)
},
// 获取带活动的购物车列表
getActivityCartListMutation(state, payload) {
state.activityCartList = payload
},
}
const actions = {
// 添加到购物车
async addShopAction({
commit,
state
}, payload) {
// 给对象添加响应式数据属性
Vue.set(payload, 'skuNum', 1)
Vue.set(payload, 'skuId', payload.id)
Vue.set(payload, 'isChecked', 1)
await this._vm.$u.api.getAddToCart({
skuId: payload.id,
skuNum: payload.skuNum,
})
commit('addShopMutation', payload)
},
// 获取不带活动的购物车列表
async getCartListAction({
commit
}) {
let result = await this._vm.$u.api.getCartList()
commit('getCartListMutation', result)
},
// 修改购物车数量
async changeSkuNumAction({
commit,
dispatch
}, payload) {
const {
skuId,
value,
currentBuyNum,
isCart
} = payload;
// 如果当前购买的数量小于1则需要将该商品从购物车中删除否则进行购物车数量的修改
if (currentBuyNum < 1) {
dispatch('deleteShopAction', payload)
} else {
await this._vm.$u.api.getAddToCart({
skuId: skuId,
skuNum: value,
})
commit('changeSkuNumMutation', payload)
}
// 通过isCart判断是否是在购物车里进行购物车数量的改变
// 如果是在购物车里进行数量变化,则还需要获取带活动的购物车列表
if (isCart) dispatch('getActivityCartListAction')
},
// 删除购物车
async deleteShopAction({
commit,
dispatch
}, payload) {
const {
skuId,
value,
currentBuyNum,
isCart
} = payload;
await this._vm.$u.api.deleteCart(skuId);
// 删除时如果是在购物车列表操作,则需要重新获取数据
if (isCart) await dispatch('getActivityCartListAction')
await commit('deleteShopMutation', skuId)
},
// 获取带活动的购物车列表
async getActivityCartListAction({
commit
}, payload) {
let showLoading = false;
if (payload) showLoading = true
let result = await this._vm.$u.api.getActivityCartList({
showLoading
})
commit('getActivityCartListMutation', result)
},
// 切换购物车商品的选中状态
async changeCheckCartAction({
commit,
dispatch
}, payload) {
let result = await this._vm.$u.api.getCheckCart(payload)
dispatch('getActivityCartListAction')
},
// 对指定的多个商品进行选择/反选
async changeMultiCheckedCartAction({
commit,
dispatch
}, payload) {
let result = await this._vm.$u.api.postBatchCheckCart(payload)
dispatch('getActivityCartListAction')
},
// 对所有购物车商品进行全选/反选
async changeAllCheckCartAction({
commit,
dispatch
}, payload) {
let result = await this._vm.$u.api.getCheckAllCart(payload)
dispatch('getActivityCartListAction')
},
};
export default {
namespaced: true,
state,
mutations,
actions,
getters,
};

View File

@@ -0,0 +1,27 @@
const state = {
categories: []
};
const getters = {};
const mutations = {
updateCategoriesMutation(state, payload) {
state.categories = payload;
}
};
const actions = {
async getCategoriesAction({
commit
}) {
return new Promise(async reslove => {
let result = await this._vm.$u.api.getCategories()
commit('updateCategoriesMutation', result)
reslove();
})
}
};
export default {
namespaced: true,
state,
mutations,
actions,
getters,
};

View File

@@ -0,0 +1,59 @@
const state = {
home: {}
};
const getters = {
// 商品分类
categoryList(state) {
return state.home.categoryList || [];
},
// 热销商品
hotSkuList(state) {
return state.home.hotSkuList || [];
},
// 新人专享
newPersonSkuInfoList(state) {
return state.home.newPersonSkuInfoList || [];
},
// 提货点信息
leaderAddressVo(state) {
return state.home.leaderAddressVo || {}
},
// 秒杀时间
seckillTime(state) {
return state.home.seckillTime || {}
},
// 秒杀商品
seckillSkuVoList(state) {
return state.home.seckillSkuVoList || []
}
};
const mutations = {
// 获取首页数据
getHomeIndexMutation(state, payload) {
state.home = payload
}
};
const actions = {
async getHomeIndexAction({
commit,
dispatch
}) {
// 直接用this.$u.api在仓库中是无法调用到对应的接口的因为this对象指向不同
// 仓库中的this指向的是Store所以需要通过this._vm来找到对应的Vue实例
let result = await this._vm.$u.api.getHomeIndex()
await commit('getHomeIndexMutation', result)
// 利用root属性将派发pickUpLocation模块中的action动作
dispatch('pickUpLocationModule/changeLeaderAddressVoAction', result.leaderAddressVo, {
root: true
})
dispatch('cartModule/getCartListAction', {}, {root: true})
}
};
export default {
namespaced: true,
state,
mutations,
actions,
getters,
};

View File

@@ -0,0 +1,90 @@
import Vue from 'vue'
const state = {
order: {}
};
const getters = {
// 获取订单商品信息列表
getCartInfoList(state) {
return state.order.carInfoVoList
},
// 获取提货点信息
getLeaderAddressVo(state) {
return state.order.leaderAddressVo
},
// 确认选中购物车的数量
getSelectedCount(state) {
let count = 0;
state.order.carInfoVoList && state.order.carInfoVoList
.forEach(carInfoItem => {
carInfoItem.cartInfoList.forEach(cartInfoItem => {
if (cartInfoItem.isChecked === 1) {
count += cartInfoItem.skuNum;
}
})
})
return count;
},
// 获取购物车价格信息
getCartPriceInfo(state) {
if (!state.order.totalAmount) {
return {
couponReduceAmount: 0,
originalTotalAmount: 0,
totalAmount: 0,
activityReduceAmount: 0
}
}
return {
couponReduceAmount: state.order.couponReduceAmount,
originalTotalAmount: state.order.originalTotalAmount,
totalAmount: state.order.totalAmount,
activityReduceAmount: state.order.activityReduceAmount
}
},
// 是否显示包含多个商品的内容
showMultiCheckbox(state) {
return function (index) {
return state.order.carInfoVoList[index].cartInfoList.length > 1
}
},
// 获取订单优惠券信息列表
getCartCouponInfoList(state) {
const couponInfoList = state.order.couponInfoList || []
if (couponInfoList) {
couponInfoList.forEach((
item) => {
Vue.set(item, 'selected', item.isOptimal === 1 && item.isSelect === 1)
})
}
return couponInfoList
},
}
const mutations = {
// 获取确认订单
getConfirmOrderMutation(state, payload) {
state.order = payload
}
}
const actions = {
// 获取确认订单
async getConfirmOrderAction({
commit
}) {
let result = await this._vm.$u.api.getConfirmOrder()
commit('getConfirmOrderMutation', result)
}
}
export default {
namespaced: true,
state,
mutations,
actions,
getters,
};

View File

@@ -0,0 +1,63 @@
const state = {
leaderAddressVo: {}, // 当前提货点
currentPickUpArea: '', // 当前提货点区域
findAllList: [], // 指定区域的提货点列表
};
const getters = {
checkIsCurrent(state, payload) {
return function (id) {
if (state.leaderAddressVo) {
return state.leaderAddressVo.leaderId === id;
} else {
return false
}
}
},
};
const mutations = {
getSysRegionFindAllListMutation(state, payload) {
state.findAllList = payload
},
setCurrentPickUpAreaMutation(state, payload) {
state.currentPickUpArea = payload.regionName
},
changeCurrentPickUpAreaMutation(state, payload) {
state.currentPickUpArea = payload[0].regionName
},
changeLeaderAddressVoMutation(state, payload) {
state.leaderAddressVo = payload;
}
};
const actions = {
async getSysRegionFindAllListAction({
commit
}) {
let result = await this._vm.$u.api.getSysRegionFindAllList();
await commit('getSysRegionFindAllListMutation', result)
await commit('changeCurrentPickUpAreaMutation', result)
},
changeLeaderAddressVoAction({
commit,
dispatch
}, payload) {
commit('changeLeaderAddressVoMutation', payload)
},
async selectLeaderAddressVoAction({
commit,
dispatch
}, payload) {
let result = await this._vm.$u.api.getSelectLeader(payload);
// 从首页设置当前提货点
dispatch('indexModule/getHomeIndexAction', {}, {
root: true
})
}
};
export default {
namespaced: true,
state,
mutations,
actions,
getters,
};

78
xlcs-user/uni.scss Normal file
View File

@@ -0,0 +1,78 @@
/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场https://ext.dcloud.net.cn上很多三方插件均使用了这些样式变量
* 如果你是插件开发者建议你使用scss预处理并在插件代码中直接使用这些变量无需 import 这个文件方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者插件使用者你可以通过修改这些变量来定制自己的插件主题实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
*/
@import 'uview-ui/theme.scss';
/* 颜色变量 */
/* 行为相关颜色 */
$uni-color-primary: #007aff;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;
/* 文字基本颜色 */
$uni-text-color: #333; //基本色
$uni-text-color-inverse: #fff; //反色
$uni-text-color-grey: #999; //辅助灰色,如加载更多的提示信息
$uni-text-color-placeholder: #808080;
$uni-text-color-disable: #c0c0c0;
/* 背景颜色 */
$uni-bg-color: #ffffff;
$uni-bg-color-grey: #f8f8f8;
$uni-bg-color-hover: #f1f1f1; //点击状态颜色
$uni-bg-color-mask: rgba(0, 0, 0, 0.4); //遮罩颜色
/* 边框颜色 */
$uni-border-color: #c8c7cc;
/* 尺寸变量 */
/* 文字尺寸 */
$uni-font-size-sm: 12px;
$uni-font-size-base: 14px;
$uni-font-size-lg: 16;
/* 图片尺寸 */
$uni-img-size-sm: 20px;
$uni-img-size-base: 26px;
$uni-img-size-lg: 40px;
/* Border Radius */
$uni-border-radius-sm: 2px;
$uni-border-radius-base: 3px;
$uni-border-radius-lg: 6px;
$uni-border-radius-circle: 50%;
/* 水平间距 */
$uni-spacing-row-sm: 5px;
$uni-spacing-row-base: 10px;
$uni-spacing-row-lg: 15px;
/* 垂直间距 */
$uni-spacing-col-sm: 4px;
$uni-spacing-col-base: 8px;
$uni-spacing-col-lg: 12px;
/* 透明度 */
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
/* 文章场景相关 */
$uni-color-title: #2C405A; // 文章标题颜色
$uni-font-size-title: 20px;
$uni-color-subtitle: #555555; // 二级标题颜色
$uni-font-size-subtitle: 26px;
$uni-color-paragraph: #3F536E; // 文章段落颜色
$uni-font-size-paragraph: 15px;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More