Commit ce4ef458 authored by six.nonacosa's avatar six.nonacosa
Browse files

litemall client power for vue -- init

litemall client power for vue  -- init

thanks litemall
parent 94107e65
<template>
<div class="user_module">
<van-cell-group>
<van-cell icon="shoucang" title="我的收藏" to="/user/collect" isLink/>
<!-- <van-cell icon="team" title="我的团队" to="/user/team" isLink /> -->
<!-- <van-cell icon="gold-bean" title="我的金豆" isLink /> -->
<van-cell icon="dingwei" title="收货地址" to="/user/address" isLink/>
<!-- <van-cell icon="id-card" title="实名认证" to="/user/autonym" isLink /> -->
<!-- <van-cell icon="kefu" title="服务中心" to="/user/server" isLink/> -->
</van-cell-group>
</div>
</template>
<script>
export default {
name: 'user-module'
};
</script>
<style scoped lang="scss">
.user_module {
background-color: #fff;
}
</style>
<template>
<div>
<van-cell-group>
<van-cell title="我的订单" isLink>
<router-link to="/user/order/list/0" class="text-desc">全部订单</router-link>
</van-cell>
</van-cell-group>
<van-row class="order_status">
<van-col span="6">
<div class="order_status_icon" @click="$router.push({path: '/user/order/list/1'})">
<van-icon name="daifukuan" :info="order.unpaid > 0 ? order.unpaid : ''"/>
</div>
<div>待付款</div>
</van-col>
<van-col span="6">
<div class="order_status_icon" @click="$router.push({path: '/user/order/list/2'})">
<van-icon name="daifahuo" :info="order.unship > 0 ? order.unship : ''"/>
</div>
<div>待发货</div>
</van-col>
<van-col span="6">
<div class="order_status_icon" @click="$router.push({path: '/user/order/list/3'})">
<van-icon name="wuliu" :info="order.unrecv > 0 ? order.unrecv : ''"/>
</div>
<div>待收货</div>
</van-col>
<van-col span="6">
<div class="order_status_icon" @click="$router.push({path: '/user/order/list/4'})">
<van-icon name="shouhouguanli" :info="order.uncomment > 0 ? order.uncomment : ''"/>
</div>
<div>已完成</div>
</van-col>
</van-row>
</div>
</template>
<script>
import { Row, Col } from 'vant';
export default {
name: 'order-group',
data() {
return {
order: []
};
},
created() {
this.init();
},
methods: {
async init() {
let { data } = await this.$reqGet('/wx/user/index');
this.order = data.data.order;
}
},
components: {
[Row.name]: Row,
[Col.name]: Col
}
};
</script>
<style scoped lang="scss">
@import '../../assets/scss/mixin';
.order_status {
background-color: #fff;
text-align: center;
padding: 10px 0;
font-size: 12px;
> div {
@include one-border;
&::after {
top: 50%;
left: 50%;
border-bottom: 0;
border-right: 1px solid $border-color;
height: 150%;
transform: scale(0.5) translate3d(-50%, -50%, 0);
transform-origin: 0 0;
}
&:last-child::after {
border: 0;
}
}
.order_status_icon {
position: relative;
width: 36px;
height: 36px;
border-radius: 50%;
display: inline-block;
i {
position: absolute;
top: 50%;
left: 50%;
transform: translate3d(-50%, -50%, 0);
font-size: 24px;
color: #000;
}
}
}
</style>
<template>
<div class="tabbar-user">
<user-header :isLogin="isLogin"/>
<order-group/>
<ecoupon-group/>
<user-module/>
<van-button size="large" class="tabbar-user__quit" v-if="isLogin" @click="quit">退出当前账户</van-button>
</div>
</template>
<script>
import userHeader from './tabbar-user-header';
import orderGroup from './tabbar-user-order';
// import ecouponGroup from './tabbar-user-ecoupon';
import userModule from './tabbar-user-module';
import { removeLocalStorage } from 'core/utils/local-storage';
export default {
data() {
return {
isLogin: false
};
},
activated() {
this.getLoginStatus();
},
methods: {
quit() {
removeLocalStorage(
'Authorization',
'user_id',
'avatar',
'background_image',
'nickName'
);
this.$router.push({ name: 'login' });
},
getLoginStatus() {
this.isLogin =
!!localStorage.getItem('Authorization') &&
!!localStorage.getItem('user_id');
}
},
components: {
[userHeader.name]: userHeader,
[orderGroup.name]: orderGroup,
// [ecouponGroup.name]: ecouponGroup,
[userModule.name]: userModule
}
};
</script>
<style scoped lang="scss">
.tabbar-user {
> div {
margin-bottom: 10px;
}
&__quit {
border: 0;
border-radius: 0;
}
}
</style>
<template>
<div class="user_information">
<van-cell-group>
<van-cell title="头像" class="cell_middle">
<van-uploader :afterRead="avatarAfterRead">
<div class="user_avatar_upload">
<img
:src="avatar + '?x-oss-process=image/resize,m_fill,h_50,w_50'"
alt="你的头像"
v-if="avatar"
>
<van-icon name="camera_full" v-else></van-icon>
</div>
</van-uploader>
</van-cell>
<!-- <van-cell title="背景图" to="/user/information/setbg" isLink></van-cell> -->
<!-- <van-cell title="昵称" to="/user/information/setNickname" :value="nickName" isLink/> -->
<!-- <van-cell title="性别" :value="genderText" @click="showSex = true" isLink/> -->
<!-- <van-cell title="密码设置" to="/user/information/setPassword" isLink/> -->
<!-- <van-cell title="手机号" to="/user/information/setMobile" :value="mobile" isLink></van-cell> -->
<van-cell title="背景图" isLink></van-cell>
<van-cell title="昵称" :value="nickName" isLink/>
<van-cell title="性别" isLink/>
<!-- <van-cell title="密码设置" to="/user/information/setPassword" isLink/> -->
<van-cell title="手机号" :value="mobile" isLink></van-cell>
</van-cell-group>
<van-button class="bottom_btn" @click="loginOut" type="primary" bottomAction>退出登录</van-button>
<van-popup v-model="showSex" position="bottom">
<van-picker
showToolbar
:columns="sexColumns"
title="选择性别"
@cancel="showSex = false"
@confirm="onSexConfirm"
/>
</van-popup>
</div>
</template>
<script>
import { Uploader, Picker, Popup, Button } from 'vant';
import { USER_PROFILE } from '@/api/user';
import { removeLocalStorage } from 'core/utils/local-storage';
import { getLocalStorage } from 'core/utils/local-storage';
export default {
data() {
return {
sexColumns: [
{
values: ['保密', '', ''],
defaultIndex: 0
}
],
showSex: false,
avatar: '',
nickName: '',
gender: -1,
mobile: ''
};
},
computed: {
genderText() {
const text = ['保密', '', ''];
return text[this.gender] || '';
}
},
created() {
this.getUserInfo();
},
methods: {
avatarAfterRead(file) {
console.log(file);
},
onSexConfirm(value, index) {
this.$reqPut(USER_PROFILE, {
gender: index[0]
}).then(res => {
this.gender = res.data.data.gender;
this.showSex = false;
});
},
getUserInfo() {
const infoData = getLocalStorage(
'nickName',
'background_image',
'avatar'
);
debugger;
this.avatar = infoData.avatar;
this.nickName = infoData.nickName;
// this.gender = infoData.gender;
// this.mobile = infoData.mobile;
},
loginOut() {
removeLocalStorage(
'Authorization',
// 'user_id',
'avatar',
// 'background_image',
'nickName'
);
this.$router.push({ name: 'home' });
}
},
components: {
[Button.name]: Button,
[Uploader.name]: Uploader,
[Picker.name]: Picker,
[Popup.name]: Popup
}
};
</script>
<style lang="scss" scoped>
.user_information {
.user_avatar_upload {
position: relative;
width: 50px;
height: 50px;
border: 1px solid $border-color;
img {
max-width: 100%;
max-height: 100%;
}
i {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 20px;
color: $border-color;
}
}
}
</style>
<template>
<div>set mobile</div>
</template>
<script>
export default {};
</script>
<template>
<div>
<van-cell-group>
<van-field
label="登录密码"
v-model="password"
type="password"
placeholder="请输入登录密码"
:error="!!$vuelidation.error('password')" />
<van-field
label="新手机号"
v-model="new_mobile"
placeholder="请输入新手机号"
:error="!!$vuelidation.error('new_mobile')" />
<van-field
label="验证码"
v-model="code"
@click-icon="getCode"
placeholder="请输入验证码">
<span slot="icon"
class="verifi_code red"
:class="{verifi_code_counting: counting}"
@click="getCode">
<countdown v-if="counting" :time="60000" @countdownend="countdownend">
<template slot-scope="props">{{ +props.seconds || 60 }}秒后获取</template>
</countdown>
<span v-else>获取验证码</span>
</span>
</van-field>
</van-cell-group>
<div class="bottom_btn">
<van-button size="large" type="danger" @click="saveMobile">保存</van-button>
</div>
</div>
</template>
<script>
import { USER_SENDCODE } from '@/api/user';
import { Field } from 'vant';
export default {
data: () => ({
password: '',
new_mobile: '',
code: '',
counting: false
}),
vuelidation: {
data: {
password: {
required: true
},
new_mobile: {
required: true,
mobile: true
}
}
},
methods: {
getCode() {
if (!this.counting && this.vuelidat()) {
this.$reqPost(USER_SENDCODE, {
mobile: this.new_mobile,
operation: 'changeMobile'
}).then(() => {
this.$toast.success('发送成功');
this.counting = true;
});
}
},
countdownend() {
this.counting = false;
},
vuelidat() {
this.$vuelidation.valid();
if (this.$vuelidation.error('new_mobile')) {
const msg = this.$vuelidation.error('new_mobile');
this.$toast(msg == 'Required' ? '请输入手机号' : msg);
return false;
}
return true;
},
saveMobile() {
console.log('保存手机号');
}
},
components: {
[Field.name]: Field
}
};
</script>
<style lang="scss" scoped>
@import '../../../../assets/scss/var';
@import '../../../../assets/scss/mixin';
.bottom_btn {
padding: 30px 15px 0 15px;
}
.verifi_code {
@include one-border;
padding-left: 10px;
&::after {
border-bottom: 0;
border-left: 1px solid $border-color;
}
&_counting {
color: $font-color-gray;
}
}
</style>
<template>
<div class="set_nickname">
<van-cell-group>
<van-field v-model="nickName" label="昵称" :error="!!$vuelidation.error('nickName')"/>
</van-cell-group>
<div class="bottom_btn">
<van-button size="large" type="danger" @click="saveNick">保存</van-button>
</div>
</div>
</template>
<script>
import { USER_PROFILE } from '@/api/user';
import { Field } from 'vant';
export default {
data() {
return {
nickName: ''
};
},
created() {
this.getNick();
},
methods: {
getNick() {
this.nickName = localStorage.getItem('nickName') || '';
},
saveNick() {
if (true) {
this.$reqPut(USER_PROFILE, { nickName: this.nickName })
.then(res => {
localStorage.setItem('nickName', res.data.data.nickName);
return this.$dialog.alert({ message: '保存成功' });
})
.then(() => {
this.$router.go(-1);
});
}
}
},
components: {
[Field.name]: Field
}
};
</script>
<style scoped>
.bottom_btn {
padding: 30px 15px 0 15px;
}
</style>
<template>
<div>
<van-cell-group>
<van-field
label="原密码"
v-model="password"
type="password"
placeholder="请输入原密码"
:error="!!$vuelidation.error('password')"
/>
<van-field
label="新密码"
v-model="new_password"
type="password"
placeholder="请输入新密码"
:error="!!$vuelidation.error('new_password')"
/>
<van-field
label="确认密码"
v-model="repeat_password"
type="password"
placeholder="请再次输入密码"
:error="!!$vuelidation.error('repeat_password')"
/>
</van-cell-group>
<div class="bottom_btn">
<van-button size="large" type="danger" @click="modifypassword">保存</van-button>
</div>
</div>
</template>
<script>
import { USER_MODIFY_PASSWORD, USER_LOGOUT } from '@/api/user';
import { removeLocalStorage } from 'core/utils/local-storage';
import { Field } from 'vant';
export default {
data: () => ({
password: '',
new_password: '',
repeat_password: ''
}),
methods: {
modifypassword() {
if (this.passwordValid()) {
this.$reqPut(USER_MODIFY_PASSWORD, {
old_password: this.password,
new_password: this.new_password
})
.then(() => this.$dialog.alert({ message: '保存成功, 请重新登录.' }))
.then(() => this.$reqGet(USER_LOGOUT))
.then(() => {
removeLocalStorage(
'Authorization',
'user_id',
'avatar',
'background_image',
'nickName'
);
this.$router.replace({ name: 'login' });
});
}
},
passwordValid() {
if (this.new_password != this.repeat_password) {
this.$toast('密码不一致, 请再次确认密码');
return false;
}
return true;
}
},
components: {
[Field.name]: Field
}
};
</script>
<style scoped>
.bottom_btn {
padding: 30px 15px 0 15px;
}
</style>
<template>
<van-tabbar v-model="active" style="z-index: 1999">
<van-tabbar-item
v-for="(tab, index) in tabbar"
:icon="tab.icon"
:to="tab.path"
:dot="tab.dot"
:info="tab.info"
:key="index">
{{tab.name}}
</van-tabbar-item>
</van-tabbar>
</template>
<script>
import { Tabbar, TabbarItem } from 'vant';
export default {
data() {
return {
active: 0,
tabbar: [
{
name: '精选',
path: '/',
pathName: 'home',
icon: 'compass-full',
dot: false,
info: ''
},
{
name: '分类',
path: '/items',
pathName: 'class',
icon: 'class-full',
dot: false,
info: ''
},
{
name: '购物车',
path: '/order',
pathName: 'cart',
icon: 'cart-full',
dot: false,
info: ''
},
{
name: '我的',
path: '/user',
pathName: 'user',
icon: 'wode',
dot: false,
info: ''
}
]
};
},
watch: {
$route: 'changeActive'
},
created() {
const toName = this.$route.name;
this.setActive(toName);
},
methods: {
changeActive({ name }) {
this.setActive(name);
},
setActive(name) {
this.tabbar.forEach((tab, i) => {
if (tab.pathName == name) {
this.active = i;
return false;
}
});
}
},
components: {
[Tabbar.name]: Tabbar,
[TabbarItem.name]: TabbarItem
}
};
</script>
import { debounce } from 'lodash';
import scroll from 'core/utils/scroll';
const CONTEXT = '$scrollArrow';
const OFFSET = 30;
// 绑定事件
function startBind(el) {
const context = el[CONTEXT];
context.vm.$nextTick(() => {
if (scroll.isAttached(el)) {
doBindEvent.call(el[CONTEXT]);
}
});
}
// 绑定事件到元素上
// 读取基本的控制变量
function doBindEvent() {
if (this.el[CONTEXT].binded) {
return;
}
this.el[CONTEXT].binded = true;
this.scrollEventListener = debounce(handleScrollEvent.bind(this), 100);
// this.scrollEventTarget = this.el;
// var disabledExpr = this.el.getAttribute('waterfall-disabled');
// var disabled = false;
// if (disabledExpr) {
// this.vm.$watch(disabledExpr, (value) => {
// this.disabled = value;
// this.scrollEventListener();
// });
// disabled = Boolean(this.vm[disabledExpr]);
// }
// this.disabled = disabled;
const offset = this.el.getAttribute('scroll-offset');
this.offset = Number(offset) || OFFSET;
this.el.addEventListener('scroll', this.scrollEventListener);
// this.scrollEventListener();
}
// 处理滚动函数
function handleScrollEvent() {
const element = this.el;
// 已被禁止的滚动处理
// if (this.disabled) return;
const targetScrollLeft = scroll.getScrollLeft(element);
const targetVisibleWidth = scroll.getVisibleWidth(element);
// 滚动元素可视区域下边沿到滚动元素元素最顶上 距离
const targetRight = targetScrollLeft + targetVisibleWidth;
// 如果无元素高度,考虑为元素隐藏,直接返回
if (!targetVisibleWidth) return;
// 判断是否到了最右边
const isRightOver = element.scrollWidth - targetRight < this.offset;
// 判断是否到了最左边
const isLeftOver = targetScrollLeft < this.offset;
this.cb &&
this.cb({
target: element,
isRightOver,
isLeftOver
});
// // 判断是否到了顶
// let needLoadMoreToUpper = targetScrollTop < this.offset;
// if (needLoadMoreToUpper) {
// this.cb.upper && this.cb.upper({
// target: scrollEventTarget,
// top: targetScrollTop
// });
// }
}
// 确认何时绑事件监听函数
function doCheckStartBind(el) {
const context = el[CONTEXT];
if (context.vm._isMounted) {
startBind(el);
} else {
context.vm.$on('hook:mounted', () => {
startBind(el);
});
}
}
export default {
bind(el, binding, vnode) {
if (!el[CONTEXT]) {
el[CONTEXT] = {
el,
vm: vnode.context,
cb: {}
};
}
el[CONTEXT].cb = binding.value;
doCheckStartBind(el);
},
update(el) {
const context = el[CONTEXT];
context.scrollEventListener && context.scrollEventListener();
}
};
<template>
<div class="field_group">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'md-field-group'
};
</script>
<style lang="scss" scoped>
.field_group {
padding-left: 15px;
padding-right: 15px;
> div {
margin-bottom: 15px;
&:last-child {
margin-bottom: 0;
}
}
}
</style>
<template>
<div class="md_field" :class="{md_field_hasIcon: !!icon, md_field_isError: isError}">
<van-icon v-if="icon" :name="icon" class="md_feld_icon"/>
<div class="md_field_control">
<input
:type="type"
v-on="listeners"
v-bind="$attrs"
:value="value">
</div>
<div>
<slot name="rightIcon">
<van-icon :name="rightIcon" @click="rightClick" v-show="value" />
</slot>
</div>
</div>
</template>
<script>
export default {
name: 'md-field',
props: {
value: {},
type: {
type: String,
default: 'text'
},
rightIcon: String,
icon: String,
isError: Boolean
},
computed: {
listeners() {
return {
...this.$listeners,
input: this.onInput
};
}
},
methods: {
onInput(event) {
this.$emit('input', event.target.value);
},
rightClick(event) {
this.$emit('right-click', event);
}
}
};
</script>
<style lang="scss" scoped>
.md_field {
position: relative;
border: 1px solid $border-color;
border-radius: 5px;
padding-top: 10px;
padding-bottom: 10px;
padding-left: 10px;
display: table;
width: 100%;
box-sizing: border-box;
background-color: #fff;
> div {
display: table-cell;
}
> .md_field_control {
padding-right: 10px;
box-sizing: border-box;
input {
border: 0;
line-height: 14px;
font-size: 14px;
width: 100%;
}
}
.md_feld_icon {
position: absolute;
top: 50%;
left: 10px;
transform: translate(0, -50%);
}
}
.md_field_hasIcon {
padding-left: 40px;
}
.md_field_isError {
color: $red;
background-color: #fcf5f5;
border: 1px solid $red;
input {
color: $red;
background-color: #fcf5f5;
}
input:-webkit-autofill {
-webkit-box-shadow: 0 0 0 1000px #fcf5f5 inset !important;
}
}
</style>
<template>
<van-list
v-model="loading"
:finished="finished"
:offset="100"
@load="loadMore"
v-bind="$attrs"
v-on="$listeners"
:immediate-check="false"
>
<is-empty v-if="isEmpty">{{ emptyText }}</is-empty>
<slot v-else></slot>
<div v-if="finished" class="text-center nomore">{{ onMoreText }}</div>
</van-list>
</template>
<script>
import { List } from 'vant';
import { get } from 'lodash';
import IsEmpty from '@/vue/components/is-empty';
import loadMore from '@/vue/mixin/load-more';
const DEFAULT_CONFIG = {
params: {},
headers: {}
};
export default {
name: 'infinity-scroll',
mixins: [loadMore],
props: {
apiUrl: {
type: String,
required: true
},
resKey: {
type: String,
default: 'data.goodsList'
},
pageKey: {
type: String,
default: 'data.page'
},
emptyText: {
type: String,
default: '抱歉,找不到结果~'
},
onMoreText: {
type: String,
default: '没有更多了~'
},
perPage: Number,
beforeRequest: Function
},
created() {
this.resetInit();
},
methods: {
beforeInitData() {
return this.beforeRequest ? this.beforeRequest() : DEFAULT_CONFIG;
},
async initData() {
const { params = {}, headers = {} } = this.beforeInitData();
const prePage = this.perPage || this.pages.perPage;
console.log(params);
console.log(headers);
const res = await this.$reqGet(
'/wx/goods/list',
{
// 'per-page': prePage,
page: this.pages.currPage,
size: 100,
categoryId: params.cid
// ...params
},
headers
);
await this.sleep(1000);
const items = get(res.data, this.resKey, []);
const page = get(res.data, this.pageKey, null);
this.$emit('onLoad', items);
return page;
},
sleep(time) {
return new Promise(resolve => {
setTimeout(resolve, time);
});
}
},
components: {
IsEmpty,
[List.name]: List
}
};
</script>
<style lang="scss" scoped>
.nomore {
padding: 10px 0;
color: $font-color-gray;
}
</style>
<template>
<div class="is_empty">
<div>
<img src="../../../assets/images/is_empty.png" alt="无商品" width="20%">
</div>
<div>
<slot></slot>
</div>
</div>
</template>
<script>
export default {
name: 'is-empty'
};
</script>
<style lang="scss" scoped>
.is_empty {
text-align: center;
color: $font-color-gray;
padding-top: 100px;
> div {
margin-bottom: 20px;
}
}
</style>
<template>
<div class="item_card_H_wrap one_border" @click="OnClick">
<div class="clearfix">
<div class="item_card_image float-l">
<div v-if="$slots.leftTopIcon" class="leftTopIcon">
<slot name="leftTopIcon"></slot>
</div>
<div v-if="$slots.mask" class="item_img_mask">
<slot name="mask"></slot>
</div>
<img v-lazy="goods.picUrl">
<div class="item_image_desc">{{goodsStatusToMe}}</div>
</div>
<!-- {{goods}} -->
<div class="item_card_info">
<div class="item_card_name">
<van-tag plain type="danger" v-if="goods.is_haitao">海淘</van-tag>
<span v-if="$slots.icon" class="item_card_icon">
<slot name="icon"></slot>
</span>
{{goods.name}}
</div>
<div class="item_card_info_desc">{{goods.brief}}</div>
<div class="item_card_footer">
<div class="footer_price">
<span>{{goods.retailPrice * 100 | yuan}}</span>
<span class="marketPrice" v-if="goods.counterPrice">{{goods.counterPrice * 100 | yuan}}</span>
</div>
<div class="footer_desc" v-if="$slots.footer">
<slot name="footer"></slot>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import item_mix from '@/vue/mixin/item-card';
export default {
name: 'item-card-hori',
mixins: [item_mix]
};
</script>
<style lang="scss" scoped>
.item_card_H_wrap {
padding: 15px 10px;
}
.item_card_image {
position: relative;
padding-top: 5px;
width: 90px;
height: 90px;
text-align: center;
img {
display: inline-block;
max-height: 100%;
max-width: 100%;
}
.leftTopIcon {
position: absolute;
left: 0;
top: 0;
max-width: 50%;
text-align: left;
}
.item_image_desc {
position: absolute;
bottom: 0;
background-color: rgba(244, 133, 145, 0.8);
width: 100%;
color: #fff;
font-size: 12px;
}
.item_img_mask {
position: absolute;
top: 50%;
left: 50%;
z-index: 2;
transform: translate(-50%, -50%);
width: 70px;
height: 70px;
overflow: hidden;
}
}
.item_card_info {
position: relative;
margin-left: 110px;
height: 100px;
.item_card_name {
font-size: 12px;
margin-bottom: 10px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.item_card_name .item_card_icon {
width: 25px;
height: 14px;
vertical-align: middle;
display: inline-block;
background-repeat: no-repeat;
}
.isHaiTao {
background-image: url(http://mamaqunaer.oss-cn-shanghai.aliyuncs.com/20171121/xMACDPN2Bz.png);
}
.item_card_info_desc {
font-size: 12px;
color: $font-color-gray;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
}
.item_card_icon img {
max-height: 100%;
max-width: 100%;
}
.item_card_footer {
position: absolute;
bottom: 0;
left: 0;
right: 0;
display: flex;
.footer_price {
color: $red;
margin-right: 5px;
}
.footer_price .marketPrice {
color: $font-color-gray;
font-size: 12px;
text-decoration: line-through;
margin-left: 5px;
}
.footer_desc {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
</style>
<template>
<div class="item_card_V_wrap" @click="OnClick">
<div class="item_card_image">
<div v-if="$slots.leftTopIcon" class="leftTopIcon">
<slot name="leftTopIcon"></slot>
</div>
<div v-if="$slots.mask" class="item_img_mask">
<slot name="mask"></slot>
</div>
<img v-lazy="goods.pic_url">
<div class="item_image_desc">{{goodsStatusToMe}}</div>
</div>
<div class="item_card_name">
<van-tag plain type="danger" v-if="goods.is_haitao">海淘</van-tag>
<span v-if="$slots.icon" class="item_card_icon">
<slot name="icon"></slot>
</span>
{{goods.name}}
</div>
<div class="item_card_price">{{goods.retailPrice | yuan}}</div>
</div>
</template>
<script>
import item_mix from '@/vue/mixin/item-card';
export default {
name: 'item-card-vert',
mixins: [item_mix]
};
</script>
<style lang="scss" scoped>
.item_card_V_wrap {
display: inline-block;
flex: 1;
width: 90px;
margin: 0 10px;
}
.item_card_image {
position: relative;
width: 100%;
height: 90px;
margin-bottom: 5px;
text-align: center;
.leftTopIcon {
position: absolute;
left: 0;
top: 0;
z-index: 3;
max-width: 50%;
text-align: left;
}
img {
display: inline-block;
max-height: 100%;
max-width: 100%;
}
.item_image_desc {
position: absolute;
bottom: 0;
background-color: rgba(244, 133, 145, 0.8);
width: 100%;
color: #fff;
font-size: 12px;
}
.item_img_mask {
position: absolute;
top: 50%;
left: 50%;
z-index: 2;
transform: translate(-50%, -50%);
width: 70px;
height: 70px;
overflow: hidden;
}
}
.item_card_name {
line-height: 16px;
font-size: 12px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
text-align: center;
}
.item_card_icon {
width: 30px;
height: 14px;
vertical-align: middle;
display: inline-block;
background-repeat: no-repeat;
background-size: 100% 100%;
}
.item_card_icon img {
max-height: 100%;
max-width: 100%;
}
.isHaiTao {
background-image: url(http://www-dev.mamaqunaer.com/images/common/icon_menu_bdt.png);
}
.item_card_price {
text-align: center;
color: $red;
}
</style>
<template>
<div class="items_group">
<van-cell-group v-if="setting && !!setting.title">
<van-cell>
<slot v-if="$slots.title_right" name="title_right"></slot>
<template slot="icon">
<van-icon class="van-cell__left-icon" v-if="setting.icon" :style="{color: setting.title_color}" :name="setting.icon"/>
</template>
<template slot="title">
<span class="group_title" :style="{color: setting.title_color}">{{setting.title}}</span>
<slot name="title-desc">
<span class="group_title_desc">{{setting.title_desc}}</span>
</slot>
</template>
</van-cell>
</van-cell-group>
<div class="group_banner" v-if="setting && setting.banner">
<img v-lazy="setting.banner" alt="海报" width="100%">
</div>
<div class="item_scroll_box" v-if="setting.style">
<div class="item_scroll" v-scrollArrow="scrollMore">
<div class="item_scroll_wrap" :style="{width: scrollWidth}">
<slot></slot>
</div>
</div>
<transition name="fade">
<van-icon name="arrow" v-show="leftOver && isShowArrow" class="items_arrow right_arrow" />
</transition>
<transition name="fade">
<van-icon name="arrow-left" v-show="rightOver && isShowArrow" class="items_arrow left_arrow" />
</transition>
</div>
<div v-else>
<slot></slot>
</div>
</div>
</template>
<script>
import ItemCardVert from '../item-card-vert/';
import ItemCardHori from '../item-card-hori/';
import { Cell, CellGroup, Icon } from 'vant';
import scrollArrow from '../_directive/scrollMore';
export default {
name: 'item-group',
props: {
setting: {
type: Object,
default: () => ({})
},
col: {
type: Number,
default: 3
}
},
data() {
const clientW =
document.body.clientWidth || document.documentElement.clientWidth,
col = this.col,
itemW = Math.floor(clientW / col),
itemsLen = this.setting.item_len;
return {
itemW,
scrollWidth: `${itemW * itemsLen}px`,
rightOver: false,
leftOver: true,
isShowArrow: itemsLen > col
};
},
methods: {
scrollMore(obj) {
this.rightOver = !obj.isLeftOver;
this.leftOver = !obj.isRightOver;
}
},
directives: {
scrollArrow
},
components: {
[Cell.name]: Cell,
[CellGroup.name]: CellGroup,
[Icon.name]: Icon,
[ItemCardVert.name]: ItemCardVert,
[ItemCardHori.name]: ItemCardHori
}
};
</script>
<style lang="scss" scoped>
.items_group {
background-color: #fff;
}
.group_title {
font-weight: 700;
}
.group_title_desc {
font-size: 12px;
color: $font-color-gray;
}
.group_banner img {
max-height: 200px;
display: block;
}
.item_scroll_box {
position: relative;
width: 100%;
padding: 10px 0;
}
.item_scroll {
width: 100%;
overflow-y: hidden;
overflow-x: scroll;
}
.item_scroll_wrap {
display: flex;
}
.items_arrow {
position: absolute;
top: 50%;
transform: translate(0, -50%);
font-size: 18px;
}
.left_arrow {
left: 0;
}
.right_arrow {
right: 0;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.fade-enter-active,
.fade-leave-active {
transition: all 0.3s;
}
.fade-enter-to,
.fade-leave {
opacity: 1;
}
</style>
<template>
<div class="contact_popup">
<div class="contact_box contact_top">
<div>微信长按识别店主二维码</div>
<div><img src="../../../assets/images/qc_code.png" alt="店主二维码"></div>
</div>
<div class="contact_box">
<div><van-icon name="phone" /> {{mobile}}</div>
<div class="contact_btn"><a :href="'tel:' + mobile">联系店家</a></div>
</div>
</div>
</template>
<script>
export default {
name: 'md-kefu',
props: {
qcCode: String,
mobile: String
}
};
</script>
<style lang="scss" scoped>
.contact_popup {
white-space: nowrap;
background-color: $bg-color;
text-align: center;
border-radius: 5px;
.contact_box {
padding: 20px 30px;
> div:first-child {
margin-bottom: 20px;
}
}
.contact_top {
@include one-border;
&::after {
border-bottom-color: #999;
}
}
.contact_btn {
border: 1px solid $red;
width: 80%;
margin: 0 auto;
color: #fff;
background-color: $red;
padding: 5px 0;
border-radius: 3px;
a {
color: #fff;
display: block;
}
}
img {
max-width: 100%;
max-height: 100%;
}
}
</style>
import spinner from './spinner';
export default spinner;
<template>
<div>
<div class="lds-ball">
<div></div>
</div>
</div>
</template>
<script>
export default {};
</script>
Supports Markdown
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