Commit fdd31016 authored by liumiss's avatar liumiss

店铺页面功能完成

parent efab2145
<template>
<span class="support-ico" :class="iconCls"></span>
</template>
<script>
export default {
name: 'support-ico',
props: {
size: {
type: Number
},
type: {
type: Number
}
},
computed: {
iconCls() {
const classMap = ['decrease', 'discount', 'special', 'invoice', 'guarantee']
return `icon-${this.size} ${classMap[this.type]}`
}
}
}
</script>
<style lang="stylus" scoped>
@import "~common/stylus/mixin"
.support-ico
display: inline-block
background-repeat: no-repeat
.icon-1
width: 12px
height: 12px
background-size: 12px 12px
&.decrease
bg-image('decrease_1')
&.discount
bg-image('discount_1')
&.guarantee
bg-image('guarantee_1')
&.invoice
bg-image('invoice_1')
&.special
bg-image('special_1')
.icon-2
width: 16px
height: 16px
background-size: 16px 16px
&.decrease
bg-image('decrease_2')
&.discount
bg-image('discount_2')
&.guarantee
bg-image('guarantee_2')
&.invoice
bg-image('invoice_2')
&.special
bg-image('special_2')
.icon-3
width: 12px
height: 12px
background-size: 12px 12px
&.decrease
bg-image('decrease_3')
&.discount
bg-image('discount_3')
&.guarantee
bg-image('guarantee_3')
&.invoice
bg-image('invoice_3')
&.special
bg-image('special_3')
.icon-4
width: 16px
height: 16px
background-size: 16px 16px
&.decrease
bg-image('decrease_4')
&.discount
bg-image('discount_4')
&.guarantee
bg-image('guarantee_4')
&.invoice
bg-image('invoice_4')
&.special
bg-image('special_4')
</style>
const EVENT_SHOW = 'show'
const EVENT_HIDE = 'hide'
export default {
data() {
return {
visible: false
}
},
methods: {
show() {
this.visible = true
this.$emit(EVENT_SHOW)
},
hide() {
this.visible = false
this.$emit(EVENT_HIDE)
}
}
}
const ALL = 2
export default {
data() {
return {
selectType: ALL,
onlyContent: true
}
},
computed: {
computedRatings() {
let ret = [];
if (this.ratings && this.ratings.length > 0) {
this.ratings.forEach((rating) => {
if (this.onlyContent && !rating.text) {
return
}
if (this.selectType === ALL || rating.rateType === this.selectType) {
ret.push(rating)
}
})
}
return ret
}
},
methods: {
onSelect(type) {
this.selectType = type
},
onToggle() {
this.onlyContent = !this.onlyContent
}
}
}
......@@ -33,6 +33,9 @@
font-size: $fontsize-large-xx
}
.bg-white{
background: #fff;
}
.line::after {
position: absolute;
......
......@@ -8,6 +8,13 @@ $color-dark-green = #06ae57
$color-light-blue = #3ca0e6
$color-blue = #1296fa
$color-red = rgb(240, 20, 20)
// $color-blue = rgb(0, 160, 220)
// $color-light-blue = rgba(0, 160, 220, 0.2)
$color-green = #00b43c
$color-col-line = #d9dde1
$color-row-line = rgba(7, 17, 27, 0.1)
$margin-top-10 = 10px
$margin-top-20 = 20px
......
import CubePage from "../../components/cube-page.vue";
import addressList from "../../components/address-list.vue";
import CubeBuyCart from "../../components/cube-buy-cart.vue";
import CubeBuyCart from "../../components/cube-cart-control.vue";
function plugin (Vue){
if(plugin.installed)return;
Vue.component('cube-page',CubePage)
Vue.component('cube-address-list',addressList)
Vue.component('cube-buy-cart',CubeBuyCart)
Vue.component('cube-cart-control',CubeBuyCart)
}
export default plugin;
\ No newline at end of file
......@@ -12,12 +12,6 @@
<span class="cart_num" v-if="foodNum">{{foodNum}}</span>
</transition>
<i class="cubeic-add icon" @click="addToCart"></i>
<!-- <svg
class="add_icon"
@click="addToCart(foods.category_id, foods.item_id, foods.specfoods[0].food_id, foods.specfoods[0].name, foods.specfoods[0].price, '', foods.specfoods[0].packing_fee, foods.specfoods[0].sku_id, foods.specfoods[0].stock, $event)"
>
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#cart-add" />
</svg>-->
</section>
</template>
......@@ -29,7 +23,9 @@ export default {
showMoveDot: [] //控制下落的小圆点显示隐藏
};
},
mounted() {},
mounted() {
},
computed: {
...mapState(["cartList"]),
/**
......@@ -40,26 +36,23 @@ export default {
},
//shopCart变化的时候重新计算当前商品的数量
foodNum: function() {
let category_id = this.categoryId;
let item_id = this.food.id;
let category_id = this.food.goods_category_id;
let food_id = this.food.id;
if (
this.shopCart &&
this.shopCart[category_id] &&
this.shopCart[category_id][item_id]
this.shopCart[category_id][food_id]
) {
// let num = 0;
// Object.values(this.shopCart[category_id][item_id]).forEach(
// (item, index) => {
// num += item.num;
// }
// );
return this.shopCart[category_id][item_id].num;
console.log(this.shopCart[category_id][food_id].num)
return this.shopCart[category_id][food_id].num;
} else {
return 0;
}
}
},
props: ["food", "shopId", "categoryId"],
props: ["food", "shopId"],
methods: {
...mapMutations(["ADD_CART", "REDUCE_CART"]),
//移出购物车
......@@ -68,7 +61,7 @@ export default {
const food = this.food;
const addInfo = {
shopid: this.shopId,
category_id: this.categoryId,
category_id: food.goods_category_id,
food_id: food.id,
name: food.name,
favorable_price: food.favorable_price,
......@@ -78,31 +71,19 @@ export default {
}
},
//加入购物车,计算按钮位置。
addToCart() {
addToCart(event) {
const food = this.food;
const addInfo = {
shopid: this.shopId,
category_id: this.categoryId,
category_id: food.goods_category_id,
food_id: food.id,
name: food.name,
favorable_price: food.favorable_price,
price: food.price
};
this.$store.commit("ADD_CART", addInfo);
let elLeft = event.target.getBoundingClientRect().left;
let elBottom = event.target.getBoundingClientRect().bottom;
this.showMoveDot.push(true);
this.$emit("showMoveDot", this.showMoveDot, elLeft, elBottom);
},
//显示规格列表
showChooseList(foodScroll) {
this.$emit("showChooseList", foodScroll);
this.$emit("showMoveDots", event.target);
},
//点击多规格商品的减按钮,弹出提示
showReduceTip() {
this.$emit("showReduceTip");
}
}
};
</script>
......
<template>
<transition name="fade" appear>
<cube-popup
:mask-closable="true"
v-show="visible"
@mask-click="maskClick"
position="bottom"
type="shop-cart-list"
:z-index="90"
>
<transition name="move" appear @after-leave="afterLeave">
<div v-if="visible">
<div class="list-header">
<h1 class="title">购物车</h1>
<span class="empty" @click="empty">清空</span>
</div>
<cube-scroll class="list-content" ref="listContent">
<ul>
<li class="food" v-for="(food,index) in selectFoods" :key="index">
<span class="name word-one">{{food.name}}</span>
<div class="price">
<span>¥{{food.price*food.num}}</span>
</div>
<div class="cart-control-wrapper">
<cube-cart-control
ref="buyCart"
:shopId="shopId"
:food="food"
@showMoveDots="showMoveDotFun"
></cube-cart-control>
</div>
</li>
</ul>
</cube-scroll>
</div>
</transition>
</cube-popup>
</transition>
</template>
<script>
import CartControl from "components/cube-cart-control";
import popupMixin from "common/mixins/popup";
const EVENT_SHOW = "show";
const EVENT_ADD = "add";
const EVENT_LEAVE = "leave";
export default {
name: "shop-cart-list",
mixins: [popupMixin],
props: {
selectFoods: {
type: Array,
default() {
return [];
}
},
},
data(){
return{
shopId:this.$route.params.id
}
},
created() {
this.$on(EVENT_SHOW, () => {
this.$nextTick(() => {
this.$refs.listContent.refresh();
});
});
},
methods: {
showMoveDotFun(target) {
this.$emit(EVENT_ADD, target);
},
afterLeave() {
this.$emit(EVENT_LEAVE);
},
maskClick() {
this.hide();
},
empty() {
this.$createDialog({
type: "confirm",
content: "清空购物车?",
confirmBtn: {
text: "确定",
active: true
},
cancelBtn: {
text: "取消"
},
onConfirm: () => {
this.selectFoods.forEach(food => {
food.num = 0;
});
this.hide();
}
}).show();
}
},
components: {
CartControl
},
};
</script>
<style lang="stylus" scoped>
@import '~common/stylus/variable';
.cube-shop-cart-list {
bottom: 48px;
&.fade-enter, &.fade-leave-active {
opacity: 0;
}
&.fade-enter-active, &.fade-leave-active {
transition: all 0.3s ease-in-out;
}
.move-enter, .move-leave-active {
transform: translate3d(0, 100%, 0);
}
.move-enter-active, .move-leave-active {
transition: all 0.3s ease-in-out;
}
.list-header {
height: 40px;
line-height: 40px;
padding: 0 14px;
background: #f3f5f7;
.title {
float: left;
font-size: $fontsize-medium;
color: $color-dark-grey;
}
.empty {
float: right;
font-size: $fontsize-small;
color: $color-blue;
}
}
.list-content {
padding: 0 14px;
max-height: 217px;
overflow: hidden;
background: $color-white;
.food {
position: relative;
padding: 12px 0;
box-sizing: border-box;
.name {
display: inline-block;
width: 63%;
// line-height: 24px;
font-size: $fontsize-medium;
color: $color-dark-grey;
}
.price {
position: absolute;
right: 80px;
bottom: 12px;
line-height: 24px;
font-weight: 700;
font-size: $fontsize-medium;
color: $color-red;
}
.cart-control-wrapper {
position: absolute;
right: 0;
bottom: 14px;
}
}
}
}
</style>
<template>
<div class="shop-cart-sticky" v-show="visible">
<shop-cart
ref="shopCart"
:shopId="shopId"
:selectFoods="selectFoods"
:deliveryPrice="deliveryPrice"
:minPrice="minPrice"
:fold="fold"
:sticky="true"
></shop-cart>
</div>
</template>
<script>
import ShopCart from "components/shopCart/shop-cart";
import popupMixin from "common/mixins/popup";
export default {
name: "shop-cart-sticky",
mixins: [popupMixin],
data() {
return {
visible: true
};
},
created() {
},
props: {
selectFoods: {
type: Array,
default() {
return [];
}
},
deliveryPrice: {
type: Number,
default: 0
},
minPrice: {
type: Number,
default: 0
},
fold: {
type: Boolean,
default: true
},
list: {
type: Object,
default() {
return {};
}
},
shopId: {
type: String
},
},
methods: {
drop(el) {
this.$refs.shopCart.drop(el);
}
},
components: {
ShopCart
}
};
</script>
<style lang="stylus" scoped>
.shop-cart-sticky {
position: absolute;
left: 0;
bottom: 0;
z-index: 999;
width: 100%;
height: 48px;
}
</style>
<template>
<div>
<section class="buy_cart_container">
<section @click="toggleList" class="cart_icon_num">
<div
class="cart_icon_container"
:class="{cart_icon_activity: totalPrice > 0}"
ref="cartContainer"
>
<i class="cubeic-alert cart_icon"></i>
<div class="num">
<van-tag v-show="totalCount>0" round type="danger">{{totalCount}}</van-tag>
</div>
</div>
<div class="cart_num">
<div class="price">¥ {{totalPrice}}</div>
<div>另需配送费¥{{deliveryPrice}}元</div>
</div>
</section>
<div class="gotopay" :class="payClass" @click="pay">
<div>{{payDesc}}</div>
</div>
</section>
<div class="ball-container">
<div v-for="(ball,index) in balls" :key="index">
<transition @before-enter="beforeDrop" @enter="dropping" @after-enter="afterDrop">
<div class="ball" v-show="ball.show" style="position: fixed;">
<div class="inner inner-hook"></div>
</div>
</transition>
</div>
</div>
<!-- <div class="shopcart">
<div class="ball-container">
<div v-for="(ball,index) in balls" :key="index">
<transition @before-enter="beforeDrop" @enter="dropping" @after-enter="afterDrop">
<div class="ball" v-show="ball.show">
<div class="inner inner-hook"></div>
</div>
</transition>
</div>
</div>
</div> -->
</div>
</template>
<script>
// import Bubble from 'components/bubble/bubble'
const BALL_LEN = 10;
const innerClsHook = "inner-hook";
function createBalls() {
let balls = [];
for (let i = 0; i < BALL_LEN; i++) {
balls.push({ show: false });
}
return balls;
}
export default {
name: "shop-cart",
props: {
selectFoods: {
type: Array,
default() {
return [];
}
},
deliveryPrice: {
type: Number,
default: 0
},
minPrice: {
type: Number,
default: 0
},
sticky: {
type: Boolean,
default: false
},
fold: {
type: Boolean,
default: true
},
shopId: {
type: String
},
},
data() {
return {
balls: createBalls(),
listFold: this.fold
};
},
created() {
this.dropBalls = [];
},
computed: {
totalPrice() {
let total = 0;
this.selectFoods.forEach(food => {
total += food.price * food.num;
});
return total;
},
totalCount() {
let count = 0;
this.selectFoods.forEach(food => {
count += food.num;
});
return count;
},
payDesc() {
if (this.totalPrice === 0) {
return `¥${this.minPrice}元起送`;
} else if (this.totalPrice < this.minPrice) {
let diff = this.minPrice - this.totalPrice;
return `还差¥${diff}元起送`;
} else {
return "去结算";
}
},
payClass() {
if (!this.totalCount || this.totalPrice < this.minPrice) {
return "not-enough";
} else {
return "enough";
}
}
},
methods: {
toggleList() {
if (this.listFold) {
if (!this.totalCount) {
return;
}
this.listFold = false;
this._showShopCartList();
this._showShopCartSticky();
} else {
this.listFold = true;
this._hideShopCartList();
}
},
pay(e) {
if (this.totalPrice < this.minPrice) {
return;
}
this.$createDialog({
title: "支付",
content: `您需要支付${this.totalPrice}元`
}).show();
e.stopPropagation();
},
drop(el) {
for (let i = 0; i < this.balls.length; i++) {
const ball = this.balls[i];
if (!ball.show) {
ball.show = true;
ball.el = el;
this.dropBalls.push(ball);
return;
}
}
},
beforeDrop(el) {
const ball = this.dropBalls[this.dropBalls.length - 1];
const rect = ball.el.getBoundingClientRect();
const x = rect.left - 32;
const y = -(window.innerHeight - rect.top - 22);
el.style.display = "";
el.style.transform = el.style.webkitTransform = `translate3d(0,${y}px,0)`;
const inner = el.getElementsByClassName(innerClsHook)[0];
inner.style.transform = inner.style.webkitTransform = `translate3d(${x}px,0,0)`;
},
dropping(el, done) {
this._reflow = document.body.offsetHeight;
el.style.transform = el.style.webkitTransform = `translate3d(0,0,0)`;
const inner = el.getElementsByClassName(innerClsHook)[0];
inner.style.transform = inner.style.webkitTransform = `translate3d(0,0,0)`;
el.addEventListener("transitionend", done);
},
afterDrop(el) {
const ball = this.dropBalls.shift();
if (ball) {
ball.show = false;
el.style.display = "none";
}
},
_showShopCartList() {
this.shopCartListComp =
this.shopCartListComp ||
this.$createShopCartList({
$props: {
selectFoods: "selectFoods"
},
$events: {
leave: () => {
this._hideShopCartSticky();
},
hide: () => {
this.listFold = true;
},
add: el => {
this.shopCartStickyComp.drop(el);
}
}
});
this.shopCartListComp.show();
},
_showShopCartSticky() {
this.shopCartStickyComp =
this.shopCartStickyComp ||
this.$createShopCartSticky({
$props: {
selectFoods: "selectFoods",
deliveryPrice: "deliveryPrice",
minPrice: "minPrice",
fold: "listFold",
list: this.shopCartListComp
}
});
this.shopCartStickyComp.show();
},
_hideShopCartList() {
const list = this.sticky ? this.$parent.list : this.shopCartListComp;
list.hide && list.hide();
},
_hideShopCartSticky() {
this.shopCartStickyComp.hide();
}
},
watch: {
fold(newVal) {
this.listFold = newVal;
},
totalCount(count) {
if (!this.fold && count === 0) {
this._hideShopCartList();
}
}
}
};
</script>
<style lang="stylus" scoped>
@import '~common/stylus/mixin';
@import '~common/stylus/variable';
.buy_cart_container {
// position();
// top: 68%;
height: 50px;
background-color: #3d3d3f;
z-index: 99;
wh(100%, 50px);
flex();
.cart_icon_num {
width: 74%;
.cart_icon_container {
position: absolute;
top: -20px;
wh(60px, 60px);
font-size: 60px;
.num {
position: absolute;
top: 0;
right: 0;
text-align: right;
span {
vertical-align: top;
}
}
}
.cart_icon_activity {
color: #1296fa;
}
.cart_num {
padding-left: 60px;
.price {
scw(18px, #fff);
}
scw(12px, #7d7e80, 600);
}
}
.gotopay {
text-align: center;
background-color: #535356;
scw(14px, #fff, 600);
wh(100px, 100%);
flex();
&.no-enough {
scw(12px, #fff);
}
&.enough {
background-color: #4cd964;
}
}
}
.ball-container {
.ball {
left: 32px;
bottom: 22px;
wh(14px,14px);
z-index: 200;
transition: all 0.4s cubic-bezier(0.49, -0.29, 0.75, 0.41);
.inner {
width: 16px;
height: 16px;
border-radius: 50%;
background: $color-blue;
transition: all 0.4s linear;
}
}
}
</style>
......@@ -6,6 +6,7 @@ import 'amfe-flexible'
import store from './store'
import './cube-ui'
import './vant';
import './register'
import VueAMap from 'vue-amap';
......
import { createAPI } from 'cube-ui'
import Vue from 'vue'
import ShopCartList from 'components/shop-cart-list'
import ShopCartStikcy from 'components/shopCart/shop-cart-sticky'
import Food from "./views/shopItem/children/food-detail"
createAPI(Vue, ShopCartList)
createAPI(Vue, ShopCartStikcy)
createAPI(Vue, Food)
\ No newline at end of file
......@@ -16,6 +16,7 @@ const state = {
Q: 0
}
},
shopInfo:{},
edit_address: {}, // 待编辑的地址信息
cartList: {}, // 加入购物车的商品列表
}
......
import {sessionstorage} from '../common/utils/mUtils'
import { sessionstorage } from '../common/utils/mUtils'
export default {
// 记录当前地理位置
......@@ -27,6 +27,12 @@ export default {
}
}
},
// 记录当前地理位置
CURRENT_SHOPINFO(state, info) {
state.shopInfo = info;
},
// 记录待 编辑地址信息
RECORD_ADDRESSINFO(state, info) {
state.edit_address = info
......@@ -50,19 +56,20 @@ export default {
let shop = cart[shopid] = (cart[shopid] || {});
let category = shop[category_id] = (shop[category_id] || {});
// let item = category[item_id] = (category[item_id] || {});
if (category[food_id]) {
category[food_id]['num']++;
} else {
category[food_id] = {
"goods_category_id":category_id,
"num": 1,
"id": food_id,
"name": name,
"price": price,
/* "specs": specs,
"packing_fee": packing_fee,
"sku_id": sku_id,
"stock": stock */
/* "specs": specs,
"packing_fee": packing_fee,
"sku_id": sku_id,
"stock": stock */
};
}
state.cartList = { ...cart };
......@@ -71,29 +78,28 @@ export default {
},
// 移出购物车
REDUCE_CART(state, {
shopid,
category_id,
item_id,
food_id,
name,
price,
specs,
}) {
let cart = state.cartList;
let shop = (cart[shopid] || {});
let category = (shop[category_id] || {});
// let item = (category[item_id] || {});
if (category && category[food_id]) {
if (category[food_id]['num'] > 0) {
category[food_id]['num']--;
state.cartList = {...cart};
//存入localStorage
sessionstorage.save('buyCart', state.cartList);
} else {
//商品数量为0,则清空当前商品的信息
category[food_id] = null;
}
}
},
REDUCE_CART(state, {
shopid,
category_id,
item_id,
food_id,
name,
price,
specs,
}) {
let cart = state.cartList;
let shop = (cart[shopid] || {});
let category = (shop[category_id] || {});
if (category && category[food_id]) {
if (category[food_id]['num'] > 0) {
category[food_id]['num']--;
state.cartList = { ...cart };
//存入localStorage
sessionstorage.save('buyCart', state.cartList);
} else {
//商品数量为0,则清空当前商品的信息
category[food_id] = null;
}
}
},
}
\ No newline at end of file
......@@ -6,14 +6,14 @@ import {
Image,
Grid,
GridItem,
// AddressList,
Row, Col,
Cell, CellGroup ,
Field,
Button,
Tag,
Card,
Tab, Tabs
Tab, Tabs ,
Rate
} from 'vant'
Vue.use(Search)
Vue.use(Image)
......@@ -26,3 +26,5 @@ Vue.use(Field)
Vue.use(Tag)
Vue.use(Button)
Vue.use(Tab).use(Tabs);
Vue.use(Rate)
......@@ -34,10 +34,8 @@
<div v-if="poisData==null" class="no-data text-base">
<cube-loading :size="24"></cube-loading>正在定位
</div>
<div v-else-if="poisData.length==0" class="no-data text-base">
地址查询失败
</div>
<div v-else-if="poisData.length==0" class="no-data text-base">地址查询失败</div>
</cube-scroll>
</div>
</div>
......@@ -88,50 +86,51 @@ export default {
],
events: {
init(map) {
AMapUI.loadUI(["misc/PositionPicker"], function(PositionPicker) {
var positionPicker = new PositionPicker({
mode: "dragMap", //设定为拖拽地图模式,可选'dragMap'、'dragMarker',默认为'dragMap'
map: map, //依赖地图对象
iconStyle: {
//自定义外观
url: "//webapi.amap.com/ui/1.0/assets/position-picker2.png", //图片地址
size: [48, 48], //要显示的点大小,将缩放图片
ancher: [24, 40] //锚点的位置,即被size缩放之后,图片的什么位置作为选中的位置
setTimeout(function() {
AMapUI.loadUI(["misc/PositionPicker"], function(PositionPicker) {
var positionPicker = new PositionPicker({
mode: "dragMap", //设定为拖拽地图模式,可选'dragMap'、'dragMarker',默认为'dragMap'
map: map, //依赖地图对象
iconStyle: {
//自定义外观
url: "//webapi.amap.com/ui/1.0/assets/position-picker2.png", //图片地址
size: [48, 48], //要显示的点大小,将缩放图片
ancher: [24, 40] //锚点的位置,即被size缩放之后,图片的什么位置作为选中的位置
}
});
positionPicker.on("success", function(positionResult) {
self.nowLocation = positionResult.regeocode.pois[0];
self.center2 = [
positionResult.position.lng,
positionResult.position.lat
];
self.poisData = positionResult.regeocode.pois;
console.log(positionResult);
});
positionPicker.on("fail", function(positionResult) {
console.log(positionResult);
self.poisData = [];
});
if (self.hasPosition) {
let position = self.$route.query.geohash.split(",");
positionPicker.start([31.19, 121.7]);
} else {
positionPicker.start();
}
positionPicker.start([31.19, 121.7]);
//TODO:事件绑定、结果处理等
});
positionPicker.on("success", function(positionResult) {
self.nowLocation = positionResult.regeocode.pois[0];
self.center2 = [
positionResult.position.lng,
positionResult.position.lat
];
self.poisData = positionResult.regeocode.pois;
console.log(positionResult);
});
positionPicker.on("fail", function(positionResult) {
console.log(positionResult);
self.poisData = [];
AMapUI.loadUI(["control/BasicControl"], function(BasicControl) {
//缩放控件
map.addControl(
new BasicControl.Zoom({
position: "rb", //left top,左上角
showZoomNum: false //显示zoom值
})
);
});
if (self.hasPosition) {
let position = self.$route.query.geohash.split(",");
positionPicker.start(position);
} else {
positionPicker.start();
}
//TODO:事件绑定、结果处理等
});
AMapUI.loadUI(["control/BasicControl"], function(BasicControl) {
//缩放控件
map.addControl(
new BasicControl.Zoom({
position: "rb", //left top,左上角
showZoomNum: false //显示zoom值
})
);
});
}, 200);
}
}
};
......@@ -143,8 +142,11 @@ export default {
this.$store.commit("CHOISE_POSITION", curChoise);
this.$router.go(-1);
},
onSearch(){
this.$router.replace({name:'searchLocation',query:{geohash:this.$route.query.geohash}})
onSearch() {
this.$router.replace({
name: "searchLocation",
query: { geohash: this.$route.query.geohash }
});
}
}
};
......
<template>
<div style="height:600px;background:pink">
</div>
</template>
\ No newline at end of file
<template>
<div class="scroll-list-wrap">
<div @click="onClosePopup">132</div>
</div>
<transition name="move" @after-leave="afterLeave">
{{food}}
<div class="food" v-show="visible">
<cube-scroll ref="scroll">
<div class="food-content">
<div class="image-header">
<img :src="$globalUrlFile+food.icon" />
<div class="back" @click="hide">
<i class="cubeic-back"></i>
</div>
</div>
<div class="content">
<h1 class="title">{{food.name}}</h1>
<div class="detail">
<span class="sell-count">月售366份</span>
<span class="rating">好评率50%</span>
</div>
<div class="price">
<span class="now">¥{{food.price}}</span>
<span class="old" v-show="food.favorable_price">¥{{food.favorable_price}}</span>
</div>
<div class="cart-control-wrapper" style="position: absolute;">
<cube-cart-control
v-show="foodNum"
ref="buyCart"
:shopId="shopId"
:food="food"
@showMoveDots="showMoveDotFun"
></cube-cart-control>
</div>
<transition name="fade">
<div @click="addFirst" class="buy" v-show="!foodNum" style="position: absolute;">加入购物车</div>
</transition>
</div>
<!-- <split v-show="food.info"></split> -->
<div class="info" v-show="food.info">
<h1 class="title">商品信息</h1>
<p class="text">{{food.info}}</p>
</div>
<!-- <split></split> -->
<div class="rating">
<h1 class="title">商品评价</h1>
<rating-select
@select="onSelect"
@toggle="onToggle"
:selectType="selectType"
:onlyContent="onlyContent"
:desc="desc"
:ratings="ratings"
></rating-select>
<div class="rating-wrapper">
<!-- <ul v-show="computedRatings && computedRatings.length">
<li
v-for="(rating,index) in computedRatings"
class="rating-item border-bottom-1px"
:key="index"
>
<div class="user">
<span class="name">{{rating.username}}</span>
<img class="avatar" width="12" height="12" :src="rating.avatar" />
</div>
<div class="time">{{format(rating.rateTime)}}</div>
<p class="text">
<span
:class="{'icon-thumb_up':rating.rateType===0,'icon-thumb_down':rating.rateType===1}"
></span>
{{rating.text}}
</p>
</li>
</ul>-->
<div class="no-rating" v-show="!computedRatings || !computedRatings.length">暂无评价</div>
</div>
</div>
</div>
</cube-scroll>
</div>
</transition>
</template>
<script>
<script type="text/ecmascript-6">
// import moment from "moment";
// import CartControl from "components/cube-cart-control";
import RatingSelect from "./rating/rating-select";
// import Split from "components/split/split";
import ratingMixin from "common/mixins/rating";
import popupMixin from "common/mixins/popup";
import { mapState } from "vuex";
const EVENT_SHOW = "show";
const EVENT_ADD = "add";
const EVENT_LEAVE = "leave";
export default {
name: "food",
mixins: [ratingMixin, popupMixin],
props: ["food", "shopId"],
data() {
return {
desc: {
all: "全部",
positive: "推荐",
negative: "吐槽"
}
};
},
computed: {
...mapState(["cartList"]),
ratings() {
return this.food.ratings;
},
/**
* 监听cartList变化,更新当前商铺的购物车信息shopCart,同时返回一个新的对象
*/
shopCart: function() {
return Object.assign({}, this.cartList[this.shopId]);
},
//shopCart变化的时候重新计算当前商品的数量
foodNum: function() {
let category_id = this.food.goods_category_id;
let food_id = this.food.id;
if (
this.shopCart &&
this.shopCart[category_id] &&
this.shopCart[category_id][food_id]
) {
return this.shopCart[category_id][food_id].num;
} else {
return 0;
}
}
},
created() {
this.$on(EVENT_SHOW, () => {
this.$nextTick(() => {
this.$refs.scroll.refresh();
});
});
},
methods: {
onClosePopup() {
this.$emit("close");
afterLeave() {
this.$emit(EVENT_LEAVE);
},
addFirst(event) {
//加入购物车
const food = this.food;
const addInfo = {
shopid: this.shopId,
category_id: this.categoryId,
food_id: food.id,
name: food.name,
favorable_price: food.favorable_price,
price: food.price
};
this.$store.commit("ADD_CART", addInfo);
this.$emit(EVENT_ADD, event.target);
},
showMoveDotFun(target) {
this.$emit(EVENT_ADD, target);
},
format(time) {
// return moment(time).format("YYYY-MM-DD hh:mm");
return time;
}
},
components: {
// CartControl,
RatingSelect
// Split
}
};
</script>
<style lang="stylus" scoped>
.scroll-list-wrap {
z-index: 10;
@import '~common/stylus/variable';
@import '~common/stylus/mixin.styl';
.food {
position: fixed;
left: 0;
top: 0;
bottom: 48px;
z-index: 30;
width: 100%;
background: $color-white;
&.move-enter-active, &.move-leave-active {
transition: all 0.3s linear;
}
&.move-enter, &.move-leave-active {
transform: translate3d(100%, 0, 0);
}
.image-header {
position: relative;
width: 100%;
height: 0;
padding-top: 100%;
img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.back {
position: absolute;
top: 10px;
left: 0;
.cubeic-back {
display: block;
padding: 10px;
font-size: $fontsize-large-xxx;
color: $color-white;
}
}
}
.content {
position: relative;
padding: 18px;
.title {
line-height: 14px;
margin-bottom: 8px;
font-size: $fontsize-medium;
font-weight: 700;
color: $color-dark-grey;
}
.detail {
margin-bottom: 18px;
line-height: 10px;
height: 10px;
.sell-count, .rating {
font-size: $fontsize-small-s;
color: $color-light-grey;
}
.sell-count {
margin-right: 12px;
}
}
.price {
line-height: 24px;
font-weight: 700;
.now {
margin-right: 8px;
font-size: 14px;
color: $color-red;
}
.old {
text-decoration: line-through;
font-size: $fontsize-small-s;
color: $color-light-grey;
}
}
.cart-control-wrapper {
// position: absolute;
right: 18px;
bottom: 18px;
}
.buy {
// position: absolute;
right: 18px;
bottom: 18px;
z-index: 10;
height: 24px;
line-height: 24px;
padding: 0 12px;
box-sizing: border-box;
border-radius: 12px;
font-size: $fontsize-small-s;
color: $color-white;
background: $color-blue;
opacity: 1;
&.fade-enter-active, &.fade-leave-active {
transition: all 0.3s;
}
&.fade-enter, &.fade-leave-active {
opacity: 0;
z-index: -1;
}
}
}
.info {
padding: 18px;
.title {
line-height: 14px;
margin-bottom: 6px;
font-size: $fontsize-medium;
color: $color-dark-grey;
}
.text {
line-height: 24px;
padding: 0 8px;
font-size: $fontsize-small;
color: $color-grey;
}
}
.rating {
padding-top: 18px;
.title {
line-height: 14px;
margin-left: 18px;
font-size: $fontsize-medium;
color: $color-dark-grey;
}
.rating-wrapper {
padding: 0 18px;
.rating-item {
position: relative;
padding: 16px 0;
&:last-child {
border-none();
}
.user {
position: absolute;
right: 0;
top: 16px;
display: flex;
align-items: center;
line-height: 12px;
.name {
margin-right: 6px;
font-size: $fontsize-small-s;
color: $color-light-grey;
}
.avatar {
border-radius: 50%;
}
}
.time {
margin-bottom: 6px;
line-height: 12px;
font-size: $fontsize-small-s;
color: $color-light-grey;
}
.text {
line-height: 16px;
font-size: $fontsize-small;
color: $color-dark-grey;
.icon-thumb_up, .icon-thumb_down {
margin-right: 4px;
line-height: 16px;
font-size: $fontsize-small;
}
.icon-thumb_up {
color: $color-blue;
}
.icon-thumb_down {
color: $color-light-grey;
}
}
}
.no-rating {
padding: 16px 0;
font-size: $fontsize-small;
color: $color-light-grey;
}
}
}
}
</style>
\ No newline at end of file
</style>
<template>
<div class="rating-select">
<div class="rating-type border-bottom-1px">
<span @click="select(2)" class="block positive" :class="{'active':selectType===2}">{{desc.all}}<span
class="count">{{ratings.length}}</span></span>
<span @click="select(0)" class="block positive" :class="{'active':selectType===0}">{{desc.positive}}<span
class="count">{{positives.length}}</span></span>
<span @click="select(1)" class="block negative" :class="{'active':selectType===1}">{{desc.negative}}<span
class="count">{{negatives.length}}</span></span>
</div>
<div @click="toggleContent" class="switch" :class="{'on':onlyContent}">
<span class="icon-check_circle"></span>
<span class="text">只看有内容的评价</span>
</div>
</div>
</template>
<script>
const POSITIVE = 0
const NEGATIVE = 1
const ALL = 2
const EVENT_TOGGLE = 'toggle'
const EVENT_SELECT = 'select'
export default {
props: {
ratings: {
type: Array,
default() {
return []
}
},
selectType: {
type: Number,
default: ALL
},
onlyContent: {
type: Boolean,
default: false
},
desc: {
type: Object,
default() {
return {
all: '全部',
positive: '满意',
negative: '不满意'
}
}
}
},
computed: {
positives() {
return this.ratings.filter((rating) => {
return rating.rateType === POSITIVE
})
},
negatives() {
return this.ratings.filter((rating) => {
return rating.rateType === NEGATIVE
})
}
},
methods: {
select(type) {
this.$emit(EVENT_SELECT, type)
},
toggleContent() {
this.$emit(EVENT_TOGGLE)
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import "~common/stylus/variable"
.rating-select
.rating-type
padding: 18px 0
margin: 0 18px
.block
display: inline-block
padding: 8px 12px
margin-right: 8px
line-height: 16px
border-radius: 1px
font-size: $fontsize-small
color: $color-grey
&.active
color: $color-white
.count
margin-left: 2px
&.positive
background: $color-light-blue
&.active
background: $color-blue
&.negative
background: $color-light-grey-s
&.active
background: $color-grey
.switch
display: flex
align-items: center
padding: 12px 18px
line-height: 24px
border-bottom: 1px solid $color-row-line
color: $color-light-grey
&.on
.icon-check_circle
color: $color-green
.icon-check_circle
margin-right: 4px
font-size: $fontsize-large-xxx
.text
font-size: $fontsize-small
</style>
This diff is collapsed.
<template>
<div>
111111111111
<cube-scroll class="seller" :options="sellerScrollOptions">
<div class="seller-content">
<div class="overview bg-white">
<h1 class="title">{{seller.name}}</h1>
<div class="desc border-bottom-1px">
<van-rate
v-model="seller.score"
allow-half
:size="16"
color="#ff9900"
void-icon="star"
void-color="#eee"
/>
<span class="text">({{seller.ratingCount}})</span>
<span class="text">月售{{seller.sellCount}}单</span>
</div>
<ul class="remark">
<li class="block">
<h2>起送价</h2>
<div class="content">
<span class="stress">{{seller.minPrice}}</span>元
</div>
</li>
<li class="block">
<h2>商家配送</h2>
<div class="content">
<span class="stress">{{seller.deliveryPrice}}</span>元
</div>
</li>
<li class="block">
<h2>平均配送时间</h2>
<div class="content">
<span class="stress">{{seller.deliveryTime}}</span>分钟
</div>
</li>
</ul>
<div class="favorite" @click="toggleFavorite" style="position: absolute;">
<span class="cubeic-like" :class="{'active':favorite}"></span>
<span class="text">{{favoriteText}}</span>
</div>
</div>
<div class="bulletin section">
<h1 class="title">公告与活动</h1>
<div class="content-wrapper border-bottom-1px">
<p class="content">{{seller.bulletin}}</p>
</div>
<ul v-if="seller.supports" class="supports">
<li
class="support-item border-bottom-1px"
v-for="(item,index) in seller.supports"
:key="index"
>
<support-ico :size="4" :type="seller.supports[index].type"></support-ico>
<span class="text">{{seller.supports[index].description}}</span>
</li>
</ul>
</div>
<div class="pics section">
<h1 class="title">商家实景</h1>
<cube-scroll class="pic-wrapper" :options="picScrollOptions">
<ul class="pic-list">
<li class="pic-item" v-for="(pic,index) in seller.pics" :key="index">
<img :src="pic" width="120" height="90" />
</li>
</ul>
</cube-scroll>
</div>
<div class="info section">
<h1 class="title border-bottom-1px">商家信息</h1>
<ul>
<li
class="info-item border-bottom-1px"
v-for="(info,index) in seller.infos"
:key="index"
>{{info}}</li>
</ul>
</div>
</div>
</template>
\ No newline at end of file
</cube-scroll>
</template>
<script>
// import { saveToLocal, loadFromLocal } from "common/js/storage";
import { mapState } from "vuex";
import SupportIco from "../../../assets/support-ico/support-ico";
export default {
// props: {
// data: {
// type: Object,
// default() {
// return {};
// }
// }
// },
data() {
return {
favorite: false,
sellerScrollOptions: {
directionLockThreshold: 0,
click: false
},
picScrollOptions: {
scrollX: true,
stopPropagation: true,
directionLockThreshold: 0
}
};
},
computed: {
...mapState(["shopInfo"]),
seller() {
Object.assign(this.shopInfo, {
score: 3.5,
ratingCount: 0,
sellCount: 30,
minPrice: 20,
deliveryPrice: 5,
deliveryTime: 38
});
return this.shopInfo || {};
},
favoriteText() {
return this.favorite ? "已收藏" : "收藏";
}
},
created() {
// this.favorite = loadFromLocal(this.seller.id, "favorite", false);
},
methods: {
toggleFavorite() {
this.favorite = !this.favorite;
// saveToLocal(this.seller.id, "favorite", this.favorite);
}
},
components: {
SupportIco
}
};
</script>
<style lang="stylus" scoped>
@import '~common/stylus/variable';
@import '~common/stylus/mixin';
.seller {
height: 100%;
text-align: left;
.overview {
position: relative;
padding: 18px;
.title {
margin-bottom: 8px;
line-height: 14px;
font-size: $fontsize-medium;
color: $color-dark-grey;
}
.desc {
display: flex;
align-items: center;
padding-bottom: 18px;
.star {
margin-right: 8px;
}
.text {
margin-left: 12px;
line-height: 18px;
font-size: $fontsize-small-s;
color: $color-grey;
}
}
.remark {
display: flex;
padding-top: 18px;
.block {
flex: 1;
width: 33.33%;
flex-direction: column;
text-align: center;
border-right: 1px solid $color-col-line;
&:last-child {
border: none;
}
h2 {
margin-bottom: 4px;
line-height: 10px;
font-size: $fontsize-small-s;
color: $color-light-grey;
}
.content {
line-height: 24px;
font-size: $fontsize-small-s;
color: $color-dark-grey;
.stress {
font-size: $fontsize-large-xxx;
}
}
}
}
.favorite {
width: 50px;
right: 11px;
top: 18px;
text-align: center;
.cubeic-like {
display: block;
margin-bottom: 4px;
line-height: 24px;
font-size: $fontsize-large-xxx;
color: $color-light-grey-s;
&.active {
color: $color-red;
}
}
.text {
line-height: 10px;
font-size: $fontsize-small-s;
color: $color-grey;
}
}
}
.bulletin {
padding: 18px 18px 0 18px;
white-space: normal;
.title {
margin-bottom: 8px;
line-height: 14px;
color: $color-dark-grey;
font-size: $fontsize-medium;
}
.content-wrapper {
padding: 0 12px 16px 12px;
.content {
line-height: 24px;
font-size: $fontsize-small;
color: $color-red;
}
}
.supports {
.support-item {
display: flex;
align-items: center;
padding: 16px 12px;
&:last-child {
border-none();
}
}
.support-ico {
margin-right: 6px;
}
.text {
line-height: 16px;
font-size: $fontsize-small;
color: $color-dark-grey;
}
}
}
.pics {
padding: 18px;
.title {
margin-bottom: 12px;
line-height: 14px;
color: $color-dark-grey;
font-size: $fontsize-medium;
}
.pic-wrapper {
display: flex;
align-items: center;
.pic-list {
.pic-item {
display: inline-block;
margin-right: 6px;
width: 120px;
height: 90px;
&:last-child {
margin: 0;
}
}
}
}
}
.info {
padding: 18px 18px 0 18px;
color: $color-dark-grey;
.title {
padding-bottom: 12px;
line-height: 14px;
font-size: $fontsize-medium;
}
.info-item {
padding: 16px 12px;
line-height: 16px;
font-size: $fontsize-small;
&:last-child {
border-none();
}
}
}
}
</style>
......@@ -37,7 +37,7 @@
<script>
import { allCategoryAndGoods, getShopInfo } from "../../common/serve";
import shopTab from "./children/shop";
import evaluate from "./children/evaluate";
import evaluate from "./children/rating/rating-select";
import shopInfo from "./children/shopInfo";
import goodsData from "../../data";
......@@ -88,30 +88,27 @@ export default {
console.log("changed to:", label);
},
async initData() {
let res = await allCategoryAndGoods(this.shopId);
if (res.code == 0) {
this.data = res.data;
this.current = res.data[0].category_name;
}
let msg = await getShopInfo(this.shopId);
if (msg.code == 0) {
this.shopInfo = msg.data;
}
},
let p1 = allCategoryAndGoods(this.shopId); // 获取分类和商品数据
let p2 = getShopInfo(this.shopId); // 获取店铺信息
Promise.all([p1, p2])
.then(result => {
let goodsMsg = result[0];
if (goodsMsg.code == 0) {
this.data = goodsMsg.data;
this.current = goodsMsg.data[0].category_name;
}
stickyChangeHandler(current) {
console.log("sticky-change", current);
},
//显示下落圆球
showMoveDotFun(showMoveDot, elLeft, elBottom) {
this.showMoveDot = [...this.showMoveDot, ...showMoveDot];
this.elLeft = elLeft;
this.elBottom = elBottom;
},
listenInCart() {},
showChooseList() {},
showReduceTip() {},
showMoveDotFun() {}
let shopMsg = result[1];
if (shopMsg.code == 0) {
this.shopInfo = shopMsg.data;
this.$store.commit('CURRENT_SHOPINFO',shopMsg.data)
}
})
.catch(error => {
});
}
}
};
</script>
......@@ -133,7 +130,8 @@ export default {
.cube-tab-bar {
background-color: #fff;
.cube-tab-bar-slider{
.cube-tab-bar-slider {
}
}
</style>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment