调整小程序

This commit is contained in:
yovinchen 2023-09-22 15:41:37 +08:00
parent b0ce6e2ad1
commit e06438f776
52 changed files with 4958 additions and 0 deletions

View File

@ -2,5 +2,6 @@
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
<mapping directory="$PROJECT_DIR$/atguigu-tuan" vcs="Git" />
</component>
</project>

View File

@ -0,0 +1,19 @@
{
// launch.json configurations app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
// launchtypelocalremote, localremote
"version": "0.0",
"configurations": [
{
"default": {
"launchtype": "local"
},
"h5": {
"launchtype": "local"
},
"mp-weixin": {
"launchtype": "local"
},
"type": "uniCloud"
}
]
}

23
atguigu-tuan/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
atguigu-tuan/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,38 @@
const install = (Vue, vm) => {
Vue.prototype.$u.http.setConfig({
//baseUrl: 'https://gmall-prod.atguigu.cn/api',
baseUrl: 'http://ggkt2.vipgz1.91tunnel.com/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
// idskuId
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
atguigu-tuan/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
atguigu-tuan/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()

View File

@ -0,0 +1,80 @@
{
"name": "atguigu-tuan",
"appid": "__UNI__3804DB8",
"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"
}

View File

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

164
atguigu-tuan/pages.json Normal file
View File

@ -0,0 +1,164 @@
{
"easycom": {
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
},
"pages": [
//pageshttps://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 => {
// resnull
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>
/*
gg为硅谷guigu前缀利用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 => {
// codetoken
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>

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/ 线svgbase64
// svgbase64js使
// data
// iconfonticonfont
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 rejectiontrycatcherror
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,100 @@
<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);
},
//
// idxorderStatus使
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; //
//
// 0loadmorenomore
//
if (this.pages[idx] === 0) {
this.loadStatus.splice(idx, 1, 'nomore');
return;
}
//
//
// loadmoreloadmore
// +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

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

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
atguigu-tuan/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;

18
atguigu-tuan/yarn.lock Normal file
View File

@ -0,0 +1,18 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
dayjs@^1.10.7:
version "1.10.7"
resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz#2cf5f91add28116748440866a0a1d26f3a6ce468"
integrity sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==
uview-ui@^1.8.4:
version "1.8.4"
resolved "https://r.cnpmjs.org/uview-ui/download/uview-ui-1.8.4.tgz#e32bbf2379421d319022e324e1cb7b5387d3bd44"
integrity sha1-4yu/I3lCHTGQIuMk4ct7U4fTvUQ=
vuex@^3.6.2:
version "3.6.2"
resolved "https://registry.npmjs.org/vuex/-/vuex-3.6.2.tgz#236bc086a870c3ae79946f107f16de59d5895e71"
integrity sha512-ETW44IqCgBpVomy520DT5jf8n0zoCac+sxWnn+hMe/CzaSejb/eVw2YToiXYX+Ex/AuHHia28vWTq4goAexFbw==