commit message

This commit is contained in:
Chopper
2021-05-13 10:56:04 +08:00
commit ec3e958037
728 changed files with 132685 additions and 0 deletions

View File

@@ -0,0 +1,149 @@
<template>
<div>
<div class="container">
<img
:src="logoImg"
v-if="showLogo"
class="logo-img"
alt=""
@click="$router.push('/')"
/>
<i-input
v-model="searchData"
size="large"
class="search"
placeholder="输入你想查找的商品"
@keyup.enter.native="search"
>
<Button v-if="!store" slot="append" @click="search">搜索</Button>
</i-input>
<div v-if="store" class="btn-div">
<Button class="store-search" type="warning" @click="searchStore">搜本店</Button>
<Button class="store-search" type="primary" @click="search">搜全站</Button>
</div>
<template v-if="showTag">
<div style="height:12px" v-if="promotionTags.length === 0"></div>
<div v-else>
<Tag
v-for="(item, index) in promotionTags"
:key="index"
>
<span class="hover-color" @click="selectTags(item)">{{ item }}</span>
</Tag>
</div>
</template>
</div>
</div>
</template>
<script>
import {getLogo} from '@/api/common.js'
import {hotWords} from '@/api/goods.js'
export default {
name: 'search',
props: {
showTag: { // 是否展示搜索栏下方热门搜索
type: Boolean,
default: true
},
showLogo: { // 是否展示左侧logo
type: Boolean,
default: true
},
store: { // 是否为店铺页面
type: Boolean,
default: false
}
},
data () {
return {
searchData: '', // 搜索内容
logoImg: '', // pc端展示logo
promotionTags: [] // 热门搜索列表
};
},
methods: {
selectTags (item) {
this.searchData = item;
this.search();
},
search () {
this.$router.push({
path: '/goodsList',
query: { keyword: this.searchData }
});
},
searchStore () {
this.$emit('search', this.searchData)
}
},
mounted () {
if (!this.Cookies.getItem('logo')) {
getLogo().then(res => {
if (res.success) {
let logoObj = JSON.parse(res.result.settingValue)
this.Cookies.setItem('logo', logoObj.buyerSideLogo)
this.logoImg = logoObj.buyerSideLogo
}
})
} else {
this.logoImg = this.Cookies.getItem('logo')
}
this.searchData = this.$route.query.keyword
hotWords({start: 1, end: 5}).then(res => {
if (res.success) this.promotionTags = res.result
})
}
};
</script>
<style scoped lang="scss">
.container {
margin: 30px auto;
width: 460px;
position: relative;
}
.search {
margin: 10px 0px 5px 0;
/deep/ .ivu-input.ivu-input-large {
border: 2px solid $theme_color;
font-size: 12px;
height: 34px;
&:focus {
box-shadow: none;
}
}
/deep/ .ivu-input-group-append {
border: 1px solid $theme_color;
border-left: none;
height: 30px;
background-color: $theme_color;
color: #ffffff;
button {
font-size: 14px;
font-weight: 600;
line-height: 1;
}
}
}
.logo-img {
position: absolute;
left: -360px;
top: -9px;
width: 150px;
cursor: pointer;
}
.store-search{
padding: 0 9px;
border-radius: 0;
&:nth-child(2){
margin-left: -5px;
}
}
.btn-div{
position: relative;
height: 0px;
top: -38px;
left: 336px;
}
</style>

View File

@@ -0,0 +1,173 @@
<template>
<div>
<Modal v-model="showAddr" width="800" title="收件人地址">
<Form
:model="formData"
ref="form"
label-position="left"
:label-width="100"
:rules="ruleInline"
>
<FormItem label="收件人" prop="name">
<i-input v-model="formData.name" style="width: 600px"></i-input>
</FormItem>
<FormItem label="收件地区" prop="address">
<i-input
v-model="formData.address"
disabled
style="width: 600px"
></i-input>
<Button type="primary" size="small" @click="$refs.map.showMap = true">选择</Button>
</FormItem>
<FormItem label="详细地址" prop="detail">
<i-input v-model="formData.detail" style="width: 600px"></i-input>
</FormItem>
<FormItem label="手机号码" prop="mobile">
<i-input v-model="formData.mobile" style="width: 600px"></i-input>
</FormItem>
<FormItem label="地址别名">
<i-input
v-model="formData.alias"
length
:maxlength="4"
placeholder="请输入地址别名,例如公司"
style="width: 600px"
></i-input>
</FormItem>
<FormItem label="默认地址">
<i-switch v-model="formData.isDefault" />
</FormItem>
</Form>
<div class="mt_20" slot="footer">
<Button @click="hide">取消</Button>
<Button type="primary" class="mr_10" :loading="loading" @click="save">保存收货地址</Button>
</div>
</Modal>
<lili-map ref="map" @getAddress="getAddress"></lili-map>
</div>
</template>
<script>
import liliMap from '@/components/map';
import {
newMemberAddress,
editMemberAddress,
getAddrDetail
} from '@/api/address';
export default {
name: 'addressManage',
props: {
id: {
defalut: '',
type: String
}
},
data () {
return {
showAddr: false, // 控制模态框显隐
formData: { // 表单数据
isDefault: false
},
ruleInline: { // 验证规则
name: [{ required: true, message: '请输入收件人姓名', trigger: 'blur' }],
address: [{ required: true, message: '请输入地址', trigger: 'change' }],
detail: [
{ required: true, message: '请输入详细地址', trigger: 'blur' }
],
mobile: [
{ required: true, message: '手机号不能为空', trigger: 'blur' },
{
type: 'string',
pattern: /^1[3|4|5|6|7|8][0-9]{9}$/,
message: '手机号格式出错',
trigger: 'blur'
}
]
},
loading: false, // 提交的加载状态
mapMsg: {} // 地图信息
};
},
methods: {
save () {
this.$refs.form.validate((valid) => {
if (valid) {
const params = JSON.parse(JSON.stringify(this.formData));
params.consigneeAddressPath = params.address.replace(/\s/g, ',');
delete params.address;
this.loading = true;
if (this.id) {
editMemberAddress(params).then((res) => {
this.loading = false;
if (res.code === 200) {
this.$Message.success('编辑地址成功');
this.$emit('change', true);
this.hide();
}
}).catch(() => { this.loading = false; });
} else {
newMemberAddress(params).then((res) => {
this.loading = false;
if (res.code === 200) {
this.$Message.success('新增地址成功');
this.$emit('change', true);
this.hide();
}
}).catch(() => { this.loading = false; });
}
}
});
},
getAddrById (id) {
// 获取地址详情
getAddrDetail(id).then((res) => {
if (res.code === 200) {
console.log(res);
const data = res.result;
data.address = res.result.consigneeAddressPath.replace(/,/g, ' ');
this.formData = data;
}
});
},
getAddress (item) {
// 获取地图选择信息
console.log(item);
this.mapMsg = item;
this.$set(this.formData, 'address', item.addr);
this.$set(this.formData, 'consigneeAddressIdPath', item.addrId);
this.$set(this.formData, 'detail', item.detail);
this.formData.lat = item.position.lat;
this.formData.lon = item.position.lng;
},
show () {
this.showAddr = true;
},
hide () {
this.showAddr = false;
}
},
watch: {
id: {
immediate: true,
handler: function (v) {
console.log(v);
if (v) {
this.getAddrById(v);
} else {
this.formData = {}
this.$refs.form.resetFields();
}
}
}
},
components: {
liliMap
}
};
</script>
<style scoped lang="scss">
.add-box {
margin: 40px 0;
}
</style>

View File

@@ -0,0 +1,42 @@
<template>
<!-- 头部广告 -->
<div class="advertising" v-if="show" :style="{'background-color': data.bgColor}">
<img :src="data.img" class="hover-pointer" @click="linkTo(data.url)"/>
<Icon type="md-close-circle" size="20" @click="show = false" />
</div>
</template>
<script>
export default {
props: {
data: { // 传入的广告信息
type: Object,
default: null
}
},
data () {
return {
show: true // 是否显示头部广告
}
}
};
</script>
<style scoped lang="scss">
.advertising {
height: 80px;
width: 100%;
background-color: $theme_color;
text-align: center;
overflow: hidden;
position: relative;
> img {
width: 1200px;
height: 100%;
}
*:nth-child(2){
position: relative;
right: 36px;
top: -57px;
cursor: pointer;
}
}
</style>

View File

@@ -0,0 +1,2 @@
# 广告
## FixedTop 顶部广告

View File

@@ -0,0 +1,12 @@
## 自定义card -
### 参数
>_Title 卡片头部
>_More 右侧栏显示内容 -- 默认不显示
>_Src 右侧内容显示之后的src路径
>_Tabs 传入数组 -- 默认无
>_Change 点击数组返回的index

View File

@@ -0,0 +1,149 @@
<template>
<Card class="_Card" :bordered="false" :dis-hover="true">
<div slot="title" class="cardTitle">
<span :style="{fontSize:`${_Size}px`}">{{_Title}}</span>
<div v-if="_Tabs" class="cardTabs">
<div @click="tabsChange(index)" :class="{active:(isActive==index)}" class="cardTabsItem" :style="{fontSize:`${_Size-2}px`}" v-for="(item,index) in _Tabs"
:key="index">
{{item}}
</div>
</div>
</div>
<div slot="extra" class="cardExtra" v-if="_More" @click="callBack()">
{{_More}}
</div>
<div>
</div>
</Card>
</template>
<script>
export default {
name: 'index',
props:
{
_Tabs: { // 可点击的tab栏
type: null,
default: ''
},
// 头部
_Title: { // 标题
type: null,
default: '卡片头部'
},
// 右侧更多
_More: {
type: null,
default: false
},
_Size: { // 文字大小
type: Number,
default: 16
},
// 点击更多触发跳转
_Src: {
type: null,
default: function (val) {
if (this._More) {
return val;
} else {
return false;
}
}
}
},
data () {
return {
isActive: 0 // 已激活tab栏下标
};
},
mounted () {},
methods: {
// 点击右侧的回调
callBack () {
let _this = this;
if (this._Src !== '' || this._Src != null) {
this.$router.push({
path: _this._Src
});
}
},
// 点击tab的回调
tabsChange (index) {
// 处理并返回index
this.isActive = index;
this.$emit('_Change', index);
}
}
};
</script>
<style scoped lang="scss">
.cardTitle {
display: flex;
cursor: pointer;
}
.active{
color: $theme_color;
position: relative;
&::before{
content: '';
position: absolute;
width: 100%;
height: 3px;
bottom: 0;
left: 0;
background: $theme_color;
}
}
.cardTabs {
display: flex;
padding: 0 12px;
> .cardTabsItem {
padding: 0 12px;
}
> .cardTabsItem:hover {
color: $theme_color;
}
}
/deep/ .ivu-card, .ivu-card-head, ._Card {
margin-bottom: 20px;
@include white_background_color();
}
/deep/ .ivu-card-head {
position: relative;
padding: 0 14px;
height: 50px;
line-height: 50px;
&::before {
content: '';
width: 3px;
height: 50%;
top: 25%;
background: $theme_color;
position: absolute;
left: 0;
}
}
.cardExtra {
color: $theme_color;
cursor: pointer;
}
/deep/ .ivu-card-body {
padding: 0 !important;
display: none;
}
</style>

View File

@@ -0,0 +1,110 @@
<template>
<div class="wrapper">
<empty v-if="list.length==0" />
<ul class="coupon-list" v-else>
<li v-for="(item, index) in list" class="coupon-item" :key="index">
<div class="c-left">
<div>
<span v-if="item.couponType === 'PRICE'" class="fontsize_12 global_color">¥<span class="price">{{item.price | unitPrice}}</span></span>
<span v-if="item.couponType === 'DISCOUNT'" class="fontsize_12 global_color"><span class="price">{{item.discount}}</span></span>
<span class="describe">{{item.consumeThreshold}}元可用</span>
</div>
<p>使用范围{{useScope(item.scopeType, item.storeName)}}</p>
<p>有效期{{item.endTime}}</p>
</div>
<b></b>
<a class="c-right" @click="go(item)">立即使用</a>
<i class="circle-top"></i>
<i class="circle-bottom"></i>
</li>
</ul>
<Page :total="total" @on-change="changePageNum"
v-if="list.length && total > params.pageNumber"
class="pageration"
@on-page-size-change="changePageSize"
:page-size="params.pageSize"
show-sizer>
</Page>
<Spin v-if="loading" fix></Spin>
</div>
</template>
<script>
import { memberCouponList } from '@/api/member.js';
export default {
data () {
return {
loading: false, // 列表加载状态
params: { // 请求参数
pageNumber: 1,
pageSize: 10
},
total: 0, // 优惠券总数
list: [] // 优惠券列表
};
},
methods: {
getList () {
this.loading = true
memberCouponList(this.params).then(res => {
this.loading = false
if (res.success) {
this.list = res.result.records
this.total = res.result.total
}
})
},
go (item) { // 根据使用条件跳转商品列表页面
if (item.storeId !== 'platform') {
this.$router.push({path: '/merchant', query: {id: item.storeId}})
} else {
if (item.scopeType === 'PORTION_GOODS_CATEGORY') {
this.$router.push({path: '/goodsList', query: {categoryId: item.scopeId}})
} else {
this.$router.push({path: '/goodsList'})
}
}
},
changePageNum (val) {
this.params.pageNumber = val;
this.getList()
},
changePageSize (val) {
this.pageNumber = 1;
this.params.pageSize = val;
this.getList()
},
useScope (type, storeName) {
let shop = '平台';
let goods = '全部商品'
if (storeName !== 'platform') shop = storeName
switch (type) {
case 'ALL':
goods = '全部商品'
break;
case 'PORTION_GOODS':
goods = '部分商品'
break;
case 'PORTION_GOODS_CATEGORY':
goods = '部分分类商品'
break;
}
return `${shop}${goods}可用`
}
},
mounted () {
this.getList()
}
};
</script>
<style scoped lang="scss">
@import '../../assets/styles/coupon.scss';
.pageration{
text-align: right;
}
</style>

View File

@@ -0,0 +1,323 @@
<template>
<div class="content-drawer">
<div v-if="title === '购物车'" class="cart-con">
<ul>
<li v-for="(goods,goodsIndex) in cartList" :key="goodsIndex">
<div>
<img :src="goods.goodsSku.thumbnail" width="90" height="90" alt="">
</div>
<div>
<p class="hover-color" @click="linkTo(`/goodsDetail?skuId=${goods.goodsSku.id}&goodsId=${goods.goodsSku.goodsId}`)">{{goods.goodsSku.goodsName}}</p>
<p class="price">{{goods.goodsSku.price | unitPrice('¥')}}<span>&nbsp; x{{goods.num}}</span></p>
</div>
<span class="del hover-color" @click="delGoods(goods.goodsSku.id)">删除</span>
</li>
</ul>
<Button size="large" class="mt_10" type="primary" @click="linkTo('/cart')" long>去购物车结算</Button>
</div>
<div v-else-if="title === '我的订单'" class="order-con">
<ul>
<li v-for="(order,orderIndex) in orderList" :key="orderIndex">
<div class="order-status"><span>{{filterOrderStatus(order.orderStatus)}}</span><span>{{order.createTime}}</span></div>
<div class="goods-img">
<img :src="img.image"
@click="linkTo(`/goodsDetail?skuId=${img.skuId}&goodsId=${img.goodsId}`)"
v-for="(img,imgIndex) in order.orderItems"
:key="imgIndex" width="40" height="40" alt="">
</div>
<div class="order-handle"><span>{{ order.flowPrice | unitPrice("¥") }}</span><span class="hover-color" @click="linkTo(`home/OrderDetail?sn=${order.sn}`)">查看订单</span></div>
</li>
</ul>
<Button type="primary" @click="linkTo('/home/MyOrder')" long>查看全部订单</Button>
</div>
<div v-else-if="title === '优惠券'" class="coupon-con">
<ul class="coupon-list">
<li v-for="(coupon, index) in couponList" class="coupon-item" :key="index">
<div class="c-left">
<div>
<span v-if="coupon.couponType === 'PRICE'" class="fontsize_12 global_color">¥<span class="price">{{coupon.price | unitPrice}}</span></span>
<span v-if="coupon.couponType === 'DISCOUNT'" class="fontsize_12 global_color"><span class="price">{{coupon.discount}}</span></span>
<span class="describe">{{coupon.consumeThreshold}}元可用</span>
</div>
<p>使用范围{{useScope(coupon.scopeType, coupon.storeName)}}</p>
<p>有效期{{coupon.endTime}}</p>
</div>
<b></b>
<a class="c-right" @click="receive(coupon)">立即领取</a>
<i class="circle-top"></i>
<i class="circle-bottom"></i>
</li>
</ul>
</div>
<div v-else-if="title === '我的足迹'" class="tracks-con">
<ul>
<li v-for="(track,trackIndex) in tracksList" :key="trackIndex">
<img :src="track.thumbnail" :alt="track.thumbnail" @click="linkTo(`/goodsDetail?skuId=${track.id}&goodsId=${track.goodsId}`)" width="100" height="100">
<div @click="addToCart(track.id)">加入购物车</div>
<p class="global_color">{{track.price | unitPrice('¥')}}</p>
</li>
</ul>
<div class="hover-color" style="text-align:center;" @click="linkTo('/home/MyTracks')">查看更多>></div>
</div>
<div v-else-if="title === '我的收藏'" class="collect-con">
<ul>
<li v-for="(collect,collectIndex) in collectList" :key="collectIndex">
<img :src="collect.image" :alt="collect.image" @click="linkTo(`/goodsDetail?skuId=${collect.skuId}&goodsId=${collect.goodsId}`)" width="100" height="100">
<div @click="addToCart(collect.skuId)">加入购物车</div>
<span class="del-icon" @click.stop="cancelCollect(collect.skuId)">
<Icon type="md-trash" />
</span>
<p class="global_color">{{collect.price | unitPrice('¥')}}</p>
</li>
</ul>
<div class="hover-color" style="text-align:center;" @click="linkTo('/home/Favorites')">查看更多>></div>
</div>
<Spin v-if="loading" fix></Spin>
</div>
</template>
<script>
import {cartGoodsAll, delCartGoods, addCartGoods, cartCount} from '@/api/cart.js'
import { getOrderList } from '@/api/order';
import {couponList, receiveCoupon, tracksList, collectList, cancelCollect} from '@/api/member.js'
export default {
name: 'Drawer',
props: {
title: {
default: '',
type: String
}
},
watch: {
title (val) {
switch (val) {
case '购物车':
this.getCartList()
break;
case '我的订单':
this.getOrderList()
break;
case '我的足迹':
this.getTracksList()
break;
case '优惠券':
this.getCouponList()
break;
case '我的收藏':
this.getCollectList()
break;
}
}
},
data () {
return {
loading: false, // 控制spin显隐
cartList: [], // 购物车列表
couponList: [], // 优惠券列表
orderList: [], // 订单列表
collectList: [], // 收藏列表
tracksList: [], // 足迹列表
orderStatusList: [ // 订单状态
{
name: '未付款',
status: 'UNPAID'
},
{
name: '已付款',
status: 'PAID'
},
{
name: '待发货',
status: 'UNDELIVERED'
},
{
name: '已发货',
status: 'DELIVERED'
},
{
name: '已完成',
status: 'COMPLETED'
},
{
name: '待核验',
status: 'TAKE'
},
{
name: '已取消',
status: 'CANCELLED'
}
]
};
},
components: {},
mounted () {},
methods: {
getCartList () { // 获取购物车列表
this.loading = true
cartGoodsAll().then(res => {
this.loading = false
this.cartList = res.result.skuList
})
},
// 删除商品
delGoods (id) {
delCartGoods({ skuIds: id }).then((res) => {
if (res.code === 200) {
this.$Message.success('删除成功');
this.getCartList();
cartCount().then(res => {
this.$store.commit('SET_CARTNUM', res.result)
this.Cookies.setItem('cartNum', res.result)
})
} else {
this.$Message.error(res.message);
}
});
},
filterOrderStatus (status) { // 获取订单状态中文
const ob = this.orderStatusList.filter(e => { return e.status === status });
return ob[0].name
},
receive (item) { // 领取优惠券
receiveCoupon(item.id).then(res => {
if (res.success) {
this.$Modal.confirm({
title: '领取优惠券',
content: '<p>优惠券领取成功,可到我的优惠券页面查看</p>',
okText: '我的优惠券',
cancelText: '立即使用',
onOk: () => {
this.$router.push('/home/Coupons')
},
onCancel: () => {
if (item.storeId !== 'platform') {
this.$router.push({path: '/merchant', query: {id: item.storeId}})
} else {
if (item.scopeType === 'PORTION_GOODS_CATEGORY') {
this.$router.push({path: '/goodsList', query: {categoryId: item.scopeId}})
} else {
this.$router.push({path: '/goodsList'})
}
}
}
});
}
})
},
useScope (type, storeName) { // 判断优惠券使用范围
let shop = '平台';
let goods = '全部商品'
if (storeName !== 'platform') shop = storeName
switch (type) {
case 'ALL':
goods = '全部商品'
break;
case 'PORTION_GOODS':
goods = '部分商品'
break;
case 'PORTION_GOODS_CATEGORY':
goods = '部分分类商品'
break;
}
return `${shop}${goods}可用`
},
addToCart (id) { // 添加商品到购物车
const params = {
num: 1,
skuId: id
}
this.loading = true;
addCartGoods(params).then(res => {
this.loading = false;
if (res.code === 200) {
this.$Message.success('商品已成功添加到购物车')
} else {
this.$Message.warning(res.message);
}
}).catch(() => { this.loading = false });
},
getCouponList () { // 获取优惠券列表
// this.loading = true;
const params = {
pageNumber: 1,
pageSize: 10
}
couponList(params).then(res => {
this.loading = false
if (res.success) {
this.couponList = res.result.records
}
}).catch(() => { this.loading = false })
},
getOrderList () { // 获取订单列表
this.loading = true
const params = {
pageNumber: 1,
pageSize: 10,
tag: 'ALL'
}
getOrderList(params).then(res => {
this.loading = false
if (res.success) {
this.orderList = res.result.records;
}
});
},
getCollectList () { // 获取收藏列表
const params = {
pageNumber: 1,
pageSize: 10,
type: 'GOODS'
}
this.loading = true
collectList(params).then(res => {
this.loading = false
this.collectList = res.result.records
})
},
cancelCollect (id) { // 取消商品收藏
cancelCollect('GOODS', id).then(res => {
if (res.success) {
this.$Message.success('取消收藏成功')
this.getCollectList();
}
})
},
getTracksList () { // 获取足迹列表
const params = {
pageNumber: 1,
pageSize: 20
}
this.loading = true
tracksList(params).then(res => {
this.tracksList = res.result
this.loading = false
}).catch(() => { this.loading = false })
}
}
};
</script>
<style scoped lang="scss">
@import '../../assets/styles/coupon.scss';
@import './drawer.scss';
.coupon-item{
overflow: hidden;
background-color: #fff;
height: 120px;
.c-left{
padding: 15px;
}
.c-right{
width: 38px;
padding: 13px;
font-size: 14px;
}
i{
right: 30px;
background-color: #eee;
}
}
</style>

View File

@@ -0,0 +1,155 @@
<template>
<div>
<div class="wrapper" :style="{right:handleDrawer ? '300px' : '0px'}">
<div class="barItem" @mouseenter="showCartNum(item)" @click="clickBar(item)" v-for="(item,index) in resetConfig.menuList" :key="index">
<Tooltip placement="left" :content="item.title">
<Icon size="20" :type="item.icon"/>
<p class="barTitle" v-if="item.titleShow"> {{item.title}}</p>
<div class="circle" v-if="item.title === '购物车'">
{{cartNum < 100 ? cartNum : 99}}
</div>
</Tooltip>
</div>
</div>
<Drawer width="300" class="popup" :title="drawerData.title" :mask="resetConfig.mask" :closable="resetConfig.closable"
v-model="handleDrawer">
<drawerPage :title="drawerData.title" />
</Drawer>
</div>
</template>
<script>
import Storage from '@/plugins/storage.js';
import Configuration from './config';
import drawerPage from './Drawer'
import {cartCount} from '@/api/cart.js'
export default {
name: 'Main',
data () {
return {
resetConfig: Configuration, // 菜单项
handleDrawer: false, // 是否可展开
drawerData: '' // 菜单基础数据
}
},
components: {drawerPage},
computed: {
userInfo () {
return Storage.getItem('userInfo');
},
cartNum () {
return this.$store.state.cartNum
}
},
methods: {
showCartNum (item) {
if (this.userInfo && item.title === '购物车') {
this.getCartList()
}
},
clickBar (val) {
if (!this.userInfo) {
this.$Modal.confirm({
title: '请登录',
content: '<p>请登录后执行此操作</p>',
okText: '立即登录',
cancelText: '继续浏览',
onOk: () => {
this.$router.push({
path: '/login',
query: {
rePath: this.$router.history.current.path,
query: JSON.stringify(this.$router.history.current.query)
}
});
}
});
} else {
if (val.display) {
this.handleDrawer = true
this.drawerData = val
} else {
this.handleDrawer = false
switch (val.title) {
case '会员中心':
this.openBlank('/home')
break;
case '我的资产':
this.openBlank('/home/MoneyManagement')
break;
}
}
}
},
openBlank (path) {
let routerUrl = this.$router.resolve({
path: path
})
window.open(routerUrl.href, '_blank')
},
getCartList () { // 获取购物车列表
cartCount().then(res => {
this.$store.commit('SET_CARTNUM', res.result)
this.Cookies.setItem('cartNum', res.result)
})
}
}
}
</script>
<style scoped lang="scss">
.wrapper {
background-color: #000!important;
}
.barItem {
text-align: center;
padding: 13px 0;
cursor: pointer;
color: #fff;
&:hover{
background-color: $theme_color;
.circle{
color: $theme_color;
background-color: #fff;
}
}
}
.barTitle {
writing-mode: vertical-lr;
letter-spacing: 2px;
padding: 4px 0;
}
.circle {
width: 20px;
height: 20px;
border-radius: 50%;
color: #fff;
background: $theme_color;
}
.wrapper {
width: 40px;
position: fixed;
transition: .35s;
height: 100%;
z-index: 9999;
background: $dark_background_color;
top: 0;
display: flex;
justify-content: center;
flex-direction: column;
}
/deep/.popup .ivu-drawer-body{
padding: 0!important;
background-color: #eee;
}
/deep/.popup .ivu-drawer-wrap{
z-index: 3001;
}
</style>

View File

@@ -0,0 +1,42 @@
# 右侧侧边栏组件
> 本组件依赖于iview的组件基础上进行封装
>项目结构
>* Main -- 组件用于挂在右侧的横栏
>* drawer -- 右侧横栏的内容
>* config -- 用于设置大小
#### config设置
```
/**
menuList // 组件的menu
display //是否显示此menu
badge //显示徽标数
titleShow //是否显示title
*/
//实例代码
width : 50, //bar的大小
menuList:[
{
icon
}
]
```
> 账户信息
> 购物车
> 我的订单
> 优惠券
> 我的资产
> 我的足迹
> 我的收藏
> 邮箱订阅
## 如何使用
1.

View File

@@ -0,0 +1,63 @@
const config = {
closable: true, // 是否显示右上角关闭按钮
mask: true, // 是否显示遮罩层
menuList: [{
icon: 'md-person', // menu的icon
title: '会员中心', // menu的标题
titleShow: false,
path: '', // menu点击的路径
display: false // 是否显示此menu
},
{
icon: 'ios-cart', // menu的icon
title: '购物车', // menu的标题
path: '', // menu点击的路径
display: true, // 是否显示此menu
badge: 12,
titleShow: true
},
{
icon: 'md-clipboard', // menu的icon
title: '我的订单', // menu的标题
path: '', // menu点击的路径
display: true, // 是否显示此menu
badge: '',
titleShow: false
},
{
icon: 'md-pricetag', // menu的icon
title: '优惠券', // menu的标题
path: '', // menu点击的路径
display: true, // 是否显示此menu
badge: '',
titleShow: false
},
{
icon: 'logo-usd', // menu的icon
title: '我的资产', // menu的标题
path: '', // menu点击的路径
display: false, // 是否显示此menu
badge: '',
titleShow: false
},
{
icon: 'ios-eye', // menu的icon
title: '我的足迹', // menu的标题
path: '', // menu点击的路径
display: true, // 是否显示此menu
badge: '',
titleShow: false
},
{
icon: 'md-star', // menu的icon
title: '我的收藏', // menu的标题
path: '', // menu点击的路径
display: true, // 是否显示此menu
badge: '',
titleShow: false
}
]
}
export default config

View File

@@ -0,0 +1,130 @@
.content-drawer {
height: 100%;
font-size: 12px;
}
// 购物车样式
.cart-con{
position: relative;
background: #fff;
height: 100%;
ul>li{
font-size: 12px;
border-bottom: 1px dashed #999;
margin: 0 10px;
display: flex;
padding: 10px 0;
align-items: center;
position: relative;
p{margin-bottom: 10px;}
.del{
position: absolute;
right: 10px;
bottom: 30px;
}
.price {
color: $theme_color;
span{color: #999;}
}
&:last-child{border: none;}
}
}
// 订单样式
.order-con{
ul>li {
margin: 10px;
background-color: #fff;
.order-status {
display: flex;
background-color: #666;
border-radius: 3px 3px 0 0;
color: #fff;
justify-content: space-between;
padding: 0 10px;
}
.goods-img {
padding-left: 10px;
padding-top: 10px;
img{
border: 1px solid #eee;
margin-right: 10px;
&:hover{
cursor: pointer;
}
}
}
.order-handle{
display: flex;
justify-content: space-between;
padding:5px 10px;
border-top: 1px solid #eee;
span:nth-child(1){
color: $theme_color;
}
}
}
}
// 优惠券样式
.coupon-con{
margin-top: 10px;
}
// 足迹样式
.tracks-con,.collect-con{
ul{
display: flex;
flex-wrap: wrap;
padding: 10px;
}
li {
background-color: #fff;
margin: 10px;
width: 120px;
position: relative;
text-align: center;
&:hover{
div,.del-icon{
display: block;
}
}
img{
cursor: pointer;
}
div{
display: none;
position: absolute;
bottom: 18px;
width: 100%;
background-color: #666;
color: #fff;
&:hover{
background-color: $theme_color;
cursor: pointer;
}
}
.del-icon{
display: none;
font-size: 20px;
position: absolute;
width: 30px;
height: 30px;
line-height: 30px;
text-align: center;
right: 0;
top: 0;
cursor: pointer;
color: $theme_color;
}
}
}
// 我的收藏样式
.collect-con{
}

View File

@@ -0,0 +1,45 @@
<template>
<div class="empty">
<img
class="empty-img"
:style="{ width: _Size + 'px' }"
src="../../assets/images/empty.png"
alt=""
/>
<p v-if="_Title">{{ _Title }}</p>
</div>
</template>
<script>
export default {
name: 'Main',
data () {
return {
};
},
props: {
_Title: { // 描述内容
type: null,
default: '暂无更多'
},
_Size: { // 图片大小
type: Number,
default: 150
}
}
};
</script>
<style scoped lang="scss">
.empty {
margin: 30px 0;
text-align: center;
width: 100%;
}
p {
cursor: pointer;
@include sub_color($light_sub_color);
}
</style>

View File

@@ -0,0 +1,10 @@
# 空状态封装
```
// _Title
<empty></empty> //默认显示
q
<empty _Title='暂无更多了' ></empty> //自定义返回标题
```

View File

@@ -0,0 +1,189 @@
<template>
<div>
<footer class="footer">
<div class="clearfix"></div>
<div class="icon-row">
<div class="footer-icon">
<h5 class="footer-icon-child"></h5>
<span class="footer-icon-text">品类齐全轻松购物</span>
</div>
<div class="footer-icon">
<h5 class="footer-icon-child footer-icon-child-2"></h5>
<span class="footer-icon-text">多仓直发极速配送</span>
</div>
<div class="footer-icon">
<h5 class="footer-icon-child footer-icon-child-3"></h5>
<span class="footer-icon-text">正品行货精致服务</span>
</div>
<div class="footer-icon">
<h5 class="footer-icon-child footer-icon-child-4"></h5>
<span class="footer-icon-text">天天低价畅选无忧</span>
</div>
</div>
<div class="service-intro">
<div class="servece-type">
<div class="servece-type-info" v-for="(guide, index) in guideArr" :key="index">
<ul>
<li v-for="(item, index) in guide" :key="index" @click="goArticle">{{item}}</li>
</ul>
</div>
</div>
<div class="clearfix"></div>
<div class="friend-link">
<div class="friend-link-item">
<ul>
<li v-for="(link, index) in moreLink" :key="index" @click="goArticle">
<span class="link-item" :class="{'link-last-item': index === 4}">{{link}}</span>
</li>
</ul>
</div>
</div>
<div class="clearfix"></div>
<div class="copyright">
<p>Copyright © LILI</p>
</div>
</div>
</footer>
</div>
</template>
<script>
export default {
name: 'Footer',
data () {
return {
guideArr: [ // 导航链接
[ '购物指南', '购物流程', '会员介绍', '生活旅行', '常见问题', '大家电', '联系客服' ],
[ '配送方式', '上门自提', '211限时达', '配送服务查询', '收取标准', '海外配送' ],
[ '支付方式', '货到付款', '在线支付', '分期付款', '邮局汇款', '公司转账' ],
[ '售后服务', '售后政策', '价格保护', '退款说明', '返修/退换货', '取消订单' ]
],
moreLink: ['关于我们', '联系我们', '联系客服', '商家帮助', '隐私政策'] // 更多链接
};
},
methods: {
goArticle () { // 跳转
let routeUrl = this.$router.resolve({
path: '/article'
})
window.open(routeUrl.href, '_blank')
}
}
};
</script>
<style scoped lang="scss">
/*****************************底 部 开 始*****************************/
.footer {
width: 100%;
height: 450px;
padding-top: 30px;
@include background_color($light_background_color);
}
.icon-row {
margin: 15px auto;
padding-top: 8px;
width: 1000px;
height: 64px;
}
.footer-icon {
margin-left: 17px;
margin-right: 17px;
float: left;
}
.footer-icon-child {
margin-top: 10px;
overflow: hidden;
position: absolute;
width: 36px;
height: 42px;
background-image: url("../../assets/images/footer/ico_service.png");
text-indent: -999px;
}
.footer-icon-child-2 {
background-position: 0 -43px;
}
.footer-icon-child-3 {
background-position: 0 -86px;
}
.footer-icon-child-4 {
background-position: 0 -129px;
}
.footer-icon-text{
margin-left: 45px;
font-size: 18px;
font-weight: bold;
line-height: 64px;
}
.service-intro {
width: 100%;
border-top: 1px solid $border_color;
}
.servece-type {
margin: 15px auto;
height: 200px;
width: 800px;
display: flex;
flex-direction: row;
justify-content: space-between;
}
.servece-type-info ul {
list-style: none;
}
.servece-type-info li {
font-size: 14px;
cursor: pointer;
line-height: 26px;
}
.servece-type-info li:first-child {
font-size: 16px;
line-height: 28px;
font-weight: bold;
}
.friend-link {
display: flex;
align-items: center;
width: 908px;
height: 30px;
margin: 0px auto;
border-top: 1px solid $border_color;
}
.friend-link-item {
margin: 0px auto;
}
.friend-link-item ul {
list-style: none;
}
.friend-link-item li {
padding: 5px 0px;
float: left;
}
.link-item {
padding: 0px 8px;
cursor: pointer;
border-right: 1px solid $border_color;
}
.link-last-item {
border: none;
}
.copyright {
width: 100%;
line-height: 30px;
text-align: center;
}
.copyright a{
color: #232323;
font-size: 20px;
}
.footer-icon-text{
@include title_color($light_title_color)
}
.copyright,.friend-link,.servece-type-info {
@include sub_color($light_sub_color)
}
/*****************************底 部 结 束*****************************/
</style>

View File

@@ -0,0 +1,54 @@
// 全局组件配置
import empty from './empty/Main' // 空状态组件
import drawer from './drawer/Main' // 右侧bar
import Header from '@/components/header/Header'; // 头部组件
import FixedTopPage from '@/components/advertising/FixedTop'; // 顶部广告
import Footer from '@/components/footer/Footer'; // 底部栏
import Search from '@/components/Search' // 搜索框
import card from '@/components/card' // 个人中心 卡片
import cateNav from '@/components/nav/cateNav' // 个人中心 卡片
empty.install = function (Vue) {
Vue.component('empty', empty);
};
drawer.install = function (Vue) {
Vue.component('drawer', drawer);
};
Header.install = function (Vue) {
Vue.component('BaseHeader', Header);
};
FixedTopPage.install = function (Vue) {
Vue.component('FixedTopPage', FixedTopPage);
};
Footer.install = function (Vue) {
Vue.component('BaseFooter', Footer);
};
Search.install = function (Vue) {
Vue.component('Search', Search);
};
card.install = function (Vue) {
Vue.component('card', card)
}
cateNav.install = function (Vue) {
Vue.component('cateNav', cateNav)
}
// 引用本js中所有的组件
export function InstallAll (Vue) {
Vue.use(empty)
Vue.use(drawer)
Vue.use(Header)
Vue.use(FixedTopPage)
Vue.use(Footer)
Vue.use(Search)
Vue.use(card)
Vue.use(cateNav)
}

View File

@@ -0,0 +1,123 @@
<template>
<div>
<div class="wrapper" v-if="type === 'goodsDetail'">
<div class="wr-l"><Icon size="23" type="ios-alarm-outline" /> 秒杀活动</div>
<div class="count-down" v-if="end === ''">
<p>倒计时</p><span>{{ hours }}</span><span>{{ minutes }}</span><span>{{ seconds }}</span>
</div>
<div v-else>{{end}}</div>
</div>
<span v-else class="cart-promotion">
<span v-if="end === ''">据活动结束<span>{{ hours }}</span> : <span>{{ minutes }}</span> : <span>{{ seconds }}</span></span>
<span v-else>活动已结束</span>
</span>
</div>
</template>
<script>
export default {
props: {
time: { // 传入的初始时间
default: 1718977559428
},
type: {
default: 'goodsDetail', // 设置两个值goodsDetail和cart样式不同
type: String
}
},
data () {
return {
end: '', // 结束状态
hours: '', // 小时
minutes: '', // 分钟
seconds: '', // 秒
interval: '' // 定时器
};
},
mounted () {
this.init()
},
methods: {
countDown (val) {
function addZero (i) {
return i < 10 ? '0' + i : i + '';
}
var nowtime = new Date();
var endtime = new Date(val);
var lefttime = parseInt((endtime.getTime() - nowtime.getTime()) / 1000);
var h = parseInt((lefttime / (60 * 60)) % 24);
var m = parseInt((lefttime / 60) % 60);
var s = parseInt(lefttime % 60);
h = addZero(h);
m = addZero(m);
s = addZero(s);
this.hours = h;
this.minutes = m
this.seconds = s;
if (lefttime <= 0) {
this.end = `活动已结束`;
clearInterval(this.interval)
}
},
init () {
this.interval = setInterval((item) => {
this.countDown(this.time);
}, 1000);
}
}
};
</script>
<style scoped lang="scss">
.cart-promotion{
font-size: 13px;
color: #999;
margin-left: 10px;
}
.wrapper {
background-image: linear-gradient(266deg, #ff0b33, #ff4257, #ff5f7c, #fa78a2);
height: 32px;
color: #fff;
line-height: 32px;
font-size: 16px;
padding: 0 10px;
display: flex;
align-items: center;
justify-content: space-between;
}
.wr-r{
font-size: 13px;
}
.count-down {
margin-right: -20px;
p{
float: left;
line-height: 20px;
}
> span {
position: relative;
float: left;
width: 20px;
height: 20px;
text-align: center;
background-color: #2f3430;
margin-right: 20px;
color: white;
font-size: 14px;
line-height: 20px;
&::after {
content: ":";
display: block;
position: absolute;
right: -20px;
font-weight: bolder;
font-size: 14px;
width: 20px;
height: 100%;
top: 0;
}
}
> span:last-child::after {
content: "";
}
}
</style>

View File

@@ -0,0 +1,658 @@
<template>
<div class="wrapper">
<div class="item-detail-show">
<!-- 详情左侧展示数据图片收藏举报 -->
<div class="item-detail-left">
<!-- 大图放大镜 -->
<div class="item-detail-big-img">
<pic-zoom :url="imgList[imgIndex].url" :scale="2"></pic-zoom>
</div>
<div class="item-detail-img-row">
<div
class="item-detail-img-small"
@mouseover="imgIndex = index"
v-for="(item, index) in imgList"
:key="index"
>
<img :src="item.url" />
</div>
</div>
<div class="goodsConfig mt_10">
<span @click="collect" ><Icon type="ios-heart" :color="isCollected ? '#ed3f14' : '#666'" />{{isCollected?'已收藏':'收藏'}}</span>
<!-- <span>举报</span> -->
</div>
</div>
<!-- 右侧商品信息活动信息操作展示 -->
<div class="item-detail-right">
<div class="item-detail-title">
<p>
{{ skuDetail.goodsName }}
</p>
</div>
<!-- 限时秒杀 -->
<Promotion v-if="promotionMap['SECKILL']" :time="promotionMap['SECKILL'].endTime"></Promotion>
<!-- 商品详细 价格优惠券促销 -->
<div class="item-detail-price-row">
<div class="item-price-left">
<!-- 商品原价 -->
<div class="item-price-row" v-if="!skuDetail.promotionPrice">
<p>
<span class="item-price-title"> &nbsp;&nbsp;&nbsp;&nbsp;</span>
<span class="item-price">{{skuDetail.price | unitPrice("¥")}}</span>
</p>
</div>
<!-- 秒杀价格 -->
<div class="item-price-row" v-if="skuDetail.promotionPrice">
<p>
<span class="item-price-title" v-if="promotionMap['SECKILL']"> &nbsp;&nbsp;</span>
<span class="item-price">{{skuDetail.promotionPrice | unitPrice("¥")}}</span>
<span class="item-price-old">{{skuDetail.price | unitPrice("¥")}}</span>
</p>
</div>
<!-- 优惠券展示 -->
<div class="item-price-row" v-if="promotionMap['COUPON'].length">
<p>
<span class="item-price-title"> </span>
<span
class="item-coupon"
v-for="(item, index) in promotionMap['COUPON']"
:key="index"
@click="receiveCoupon(item.id)"
>
<span v-if="item.couponType == 'PRICE'">{{ item.consumeThreshold }}{{item.price}}</span>
<span v-if="item.couponType == 'DISCOUNT'">{{ item.consumeThreshold }}{{item.couponDiscount}}</span>
</span>
</p>
</div>
<!-- 满减展示 -->
<div class="item-price-row" v-if="promotionMap['FULL_DISCOUNT']">
<p>
<span class="item-price-title">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span class="item-promotion">满减</span>
<span class="item-desc-pintuan" v-if="promotionMap['FULL_DISCOUNT'].fullMinus">{{ promotionMap['FULL_DISCOUNT'].fullMoney }}立减现金{{ promotionMap['FULL_DISCOUNT'].fullMinus}}</span>
<span class="item-desc-pintuan" v-if="promotionMap['FULL_DISCOUNT'].fullRate">{{ promotionMap['FULL_DISCOUNT'].fullMoney }}立享{{ promotionMap['FULL_DISCOUNT'].fullRate}}</span>
</p>
</div>
</div>
<div class="item-price-right">
<div class="item-remarks-sum">
<p>累计评价</p>
<p>
<span class="item-remarks-num">{{ skuDetail.commentNum || 0 }} </span>
</p>
</div>
</div>
</div>
<!-- 选择颜色 -->
<div class="item-select" v-for="(sku, index) in formatList" :key="sku.id">
<div class="item-select-title">
<p>{{ sku.name }}</p>
</div>
<div class="item-select-column">
<div class="item-select-row" v-for="(item) in sku.values" :key="item.id">
<div class="item-select-box" @click="select(index, sku.id, item.id)"
:class="{ 'item-select-box-active': item.id === currentSelceted[index] }"
>
<div class="item-select-intro">
<p>{{ item.value }}</p>
</div>
</div>
</div>
</div>
</div>
<br />
<div class="add-buy-car-box">
<div class="item-select">
<div class="item-select-title">
<p>数量</p>
</div>
<div class="item-select-row">
<InputNumber :min="1" :disabled="skuDetail.quantity === 0" v-model="count"></InputNumber>
<span class="inventory"> 库存{{skuDetail.quantity}}</span>
</div>
</div>
<div class="item-select">
<div class="item-select-title">
<p>重量</p>
</div>
<div class="item-select-row">
<span class="inventory"> {{skuDetail.weight}}kg</span>
</div>
</div>
<div class="add-buy-car">
<Button type="error" :loading="loading" :disabled="skuDetail.quantity === 0" @click="addShoppingCartBtn">加入购物车</Button>
<Button type="warning" :loading="loading1" :disabled="skuDetail.quantity === 0" @click="buyNow">立即购买</Button>
</div>
</div>
</div>
<!-- <div class="item-detail-see">
<Divider>更多推荐</Divider>
<Row>
<Col :span="24" class="see-Item">
<img class="see-Img" src="https://demo.dscmall.cn/storage/images/201703/thumb_img/0_thumb_G_1489099128797.jpg" alt="" />
<p>
名龙堂i7 6700升7700 GTX1060 6G台式电脑主机DIY游戏组装整机
升6GB独显 送正版WIN10 一年上门
</p>
<p class="global_color">2500.00</p>
</Col>
<Col :span="24" class="see-Item">
<img
class="see-Img"
src="https://demo.dscmall.cn/storage/images/201703/thumb_img/0_thumb_G_1489099128797.jpg"
alt=""
/>
<p>
名龙堂i7 6700升7700 GTX1060 6G台式电脑主机DIY游戏组装整机
升6GB独显 送正版WIN10 一年上门
</p>
<p class="global_color">2500.00</p>
</Col>
</Row>
</div> -->
</div>
</div>
</template>
<script>
import Promotion from './Promotion.vue';
import PicZoom from 'vue-piczoom'; // 图片放大 https://github.com/826327700/vue-piczoom
import { collectGoods, isCollection, receiveCoupon, cancelCollect } from '@/api/member.js';
import { addCartGoods } from '@/api/cart.js';
export default {
name: 'ShowGoods',
props: {
detail: {
type: Object,
default: null
}
},
data () {
return {
count: 1, // 商品数量
imgIndex: 0, // 展示图片下标
currentSelceted: [], // 当前商品sku
imgList: this.detail.data.specList[0].specImage, // 商品图片列表
skuDetail: this.detail.data, // sku详情
goodsSpecList: this.detail.specs, // 商品spec
promotionMap: { // 活动状态
SECKILL: null,
FULL_DISCOUNT: null,
COUPON: []
}, // 促销活动
formatList: [], // 选择商品品类的数组
loading: false, // 立即购买loading
loading1: false, // 加入购物车loading
isCollected: false // 是否收藏
};
},
components: {
PicZoom,
Promotion
},
methods: {
select (index, id, valueId) { // 选择规格
this.$set(this.currentSelceted, index, valueId);
let selectedSkuId = this.goodsSpecList.find((i) => {
let matched = true;
let specValues = i.specValues.filter((j) => j.specName !== 'images');
for (let n = 0; n < specValues.length; n++) {
if (specValues[n].specValueId !== this.currentSelceted[n]) {
matched = false;
return;
}
}
if (matched) {
return i;
}
});
console.log(selectedSkuId);
this.$router.push({
path: '/goodsDetail',
query: { skuId: selectedSkuId.skuId, goodsId: this.skuDetail.goodsId }
});
},
addShoppingCartBtn () { // 添加购物车
const params = {
num: this.count,
skuId: this.skuDetail.id
};
this.loading = true;
addCartGoods(params).then(res => {
this.loading = false;
if (res.code === 200) {
this.$router.push({path: '/shoppingCart', query: {detail: this.skuDetail, count: this.count}});
} else {
this.$Message.warning(res.message);
}
});
},
buyNow () { // 立即购买
const params = {
num: this.count,
skuId: this.skuDetail.id,
cartType: 'BUY_NOW'
};
this.loading1 = true;
addCartGoods(params).then(res => {
this.loading1 = false;
if (res.code === 200) {
this.$router.push({path: '/pay', query: {way: 'BUY_NOW'}});
} else {
this.$Message.warning(res.message);
}
});
},
async collect () { // 收藏商品
if (this.isCollected) {
let cancel = await cancelCollect('GOODS', this.skuDetail.id)
if (cancel.success) {
this.$Message.success('取消收藏成功')
this.isCollected = false
}
} else {
let collect = await collectGoods('GOODS', this.skuDetail.id);
if (collect.code === 200) {
this.isCollected = true;
this.$Message.success('收藏商品成功,可以前往个人中心我的收藏查看');
}
}
},
formatSku (list) {
// 格式化数据
let arr = [{}];
list.forEach((item, index) => {
item.specValues.forEach((spec, specIndex) => {
let id = spec.specNameId;
let name = spec.specName;
let values = {
id: spec.specValueId,
value: spec.specValue,
quantity: item.quantity
};
if (name === 'images') {
return;
}
arr.forEach((arrItem, arrIndex) => {
if (
arrItem.name === name &&
arrItem.values &&
!arrItem.values.find((i) => i.id === values.id)
) {
arrItem.values.push(values);
}
let keys = arr.map((key) => {
return key.name;
});
if (!keys.includes(name)) {
arr.push({
id: id,
name: name,
values: [values]
});
}
});
});
});
arr.shift();
this.formatList = arr;
let cur = list.filter((i) => i.skuId === this.$route.query.skuId)[0];
if (cur) {
cur.specValues.filter((i) => i.specName !== 'images')
.forEach((value, _index) => {
this.currentSelceted[_index] = value.specValueId;
});
}
this.skuList = list;
},
receiveCoupon (id) { // 领取优惠券
receiveCoupon(id).then(res => {
if (res.success) {
this.$Message.success('优惠券领取成功')
} else {
this.$Message.warning(res.message)
}
})
},
promotion () { // 格式化促销活动,返回当前促销的对象
let keysArr = Object.keys(this.detail.promotionMap);
if (keysArr.length === 0) return false;
for (let i = 0; i < keysArr.length; i++) {
let key = keysArr[i].split('-')[0]
if (key === 'COUPON') {
this.promotionMap[key].push(this.detail.promotionMap[keysArr[i]])
} else {
this.promotionMap[key] = this.detail.promotionMap[keysArr[i]]
}
}
}
},
mounted () {
if (this.Cookies.getItem('userInfo')) {
isCollection('GOODS', this.skuDetail.id).then(res => {
if (res.success && res.result) {
this.isCollected = true;
}
})
}
this.formatSku(this.goodsSpecList);
this.promotion()
document.title = this.skuDetail.goodsName
}
};
</script>
<style scoped lang="scss">
/******************商品图片及购买详情开始******************/
.item-detail-see {
width: 175px;
margin-left: 30px;
}
.inventory {
padding-left: 4px;
@include sub_color($light_sub_color);
}
.global_color {
text-align: center;
}
.see-Img {
width: 100%;
height: 175px;
}
.see-Item {
> p {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.Report {
color: $theme_color !important;
}
.wrapper {
@include white_background_color();
}
.item-sale-flex {
width: 29%;
padding: 0 3%;
}
.item-sale {
margin: 10px 0;
> h3 {
width: 13%;
text-align: center;
font-size: 20px;
line-height: 60px;
box-sizing: border-box;
border-right: 1px solid $border_color;
}
height: 60px;
justify-content: center;
align-items: center;
display: flex;
width: 1200px;
margin: 0 auto;
margin-bottom: 10px;
border: 1px solid $border_color;
background: #f7f7f7;
}
.item-detail-show {
width: 1200px;
margin: 0 auto;
padding: 30px;
display: flex;
flex-direction: row;
}
.item-detail-left {
width: 350px;
margin-right: 30px;
}
.item-detail-big-img {
width: 350px;
height: 350px;
box-shadow: 0px 0px 8px $border_color;
cursor: pointer;
}
.item-detail-big-img img {
width: 100%;
}
.item-detail-img-row {
margin-top: 15px;
display: flex;
}
.item-detail-img-small {
width: 68px;
height: 68px;
box-shadow: 0px 0px 8px #ccc;
cursor: pointer;
margin-left: 5px;
}
.item-detail-img-small img {
height: 100%;
width: 100%;
}
/*商品选购详情*/
.item-detail-right {
flex: 1;
display: flex;
flex-direction: column;
}
.item-detail-title p {
@include content_color($light_content_color);
font-weight: bold;
font-size: 20px;
padding: 8px 0;
}
.item-detail-express {
font-size: 14px;
padding: 2px 3px;
border-radius: 3px;
background-color: $theme_color;
color: #fff;
}
/*商品标签*/
.item-detail-tag {
padding: 8px 0;
font-size: 12px;
color: $theme_color;
}
/*价格详情等*/
.item-detail-price-row {
padding: 10px;
display: flex;
// width: 555px;
flex-direction: row;
justify-content: space-between;
// @include background_color($light_background_color);
background: url("../../assets/images/goodsDetail/price-bg.png");
}
.item-price-left {
display: flex;
flex-direction: column;
}
.item-price-title {
color: #999999;
font-size: 14px;
margin-right: 15px;
}
.item-price-row {
margin: 5px 0px;
}
.item-price {
color: $theme_color;
font-size: 20px;
cursor: pointer;
}
.item-price-old {
color: gray;
text-decoration: line-through;
font-size: 14px;
margin-left: 5px;
}
.item-coupon {
margin-right: 5px;
padding: 3px;
color: $theme_color;
font-size: 12px;
background-color: #ffdedf;
border: 1px dotted $theme_color;
cursor: pointer;
}
.item-promotion {
margin-right: 5px;
padding: 3px;
color: $theme_color;
font-size: 12px;
border: 1px solid $theme_color;
}
.item-remarks-sum {
padding-left: 8px;
border-left: 1px solid $border_color;
}
.item-remarks-sum p {
color: #999999;
font-size: 12px;
line-height: 10px;
text-align: center;
}
.item-remarks-num {
line-height: 18px;
color: #005eb7;
}
.item-select {
display: flex;
flex-direction: row;
margin-top: 15px;
}
.item-select-title {
@include content_color($light_content_color);
font-size: 14px;
margin-right: 15px;
width: 60px;
}
.item-select-column {
display: flex;
flex-wrap: wrap;
flex: 1;
}
.item-select-row {
// display: flex;
// flex-direction: row;
// flex-wrap: wrap;
margin-bottom: 8px;
}
.item-select-box {
display: flex;
flex-direction: row;
align-items: center;
}
.item-select-img {
width: 36px;
}
.item-select-box {
padding: 5px;
margin-right: 8px;
@include background_color($light_background_color);
border: 0.5px solid $border_color;
cursor: pointer;
@include content_color($light_content_color);
}
.item-select-box:hover {
border: 0.5px solid $theme_color;
}
.item-select-box-active {
border: 0.5px solid $theme_color;
}
.item-select-box-disabled {
background-color: gray;
}
.item-select-img img {
width: 100%;
}
.item-select-intro p {
margin: 0px;
padding: 5px;
}
.item-select-class {
padding: 5px;
margin-right: 8px;
@include sub_background_color($light_background_color);
border: 0.5px solid #ccc;
cursor: pointer;
}
.item-select-class:hover {
border: 0.5px solid $theme_color;
}
.add-buy-car-box {
width: 100%;
margin-top: 15px;
border-top: 1px dotted $border_color;
}
.add-buy-car {
margin-top: 15px;
}
.goodsConfig {
display: flex;
justify-content: space-between;
> span {
padding-right: 10px;
&:hover{
cursor: pointer;
color: $theme_color;
}
}
}
/******************商品图片及购买详情结束******************/
</style>

View File

@@ -0,0 +1,489 @@
<template>
<div>
<div class="item-intro-show">
<!-- <div class="item-intro-recommend">
<div class="item-recommend-title">
<p>店铺热销</p>
</div>
<div class="item-intro-recommend-column">
<div class="item-recommend-column" v-for="(item, index) in hotList" :key="index">
<div class="item-recommend-img">
<img :src="item.img" alt="">
</div>
<div class="item-recommend-intro">
<span>
<span class="item-recommend-top-num">{{index + 1}}</span> 热销{{item.sale}}</span>
<span class="item-recommend-price">{{item.price | unitPrice}}</span>
</div>
</div>
</div>
</div> -->
<div class="item-intro-detail" ref="itemIntroDetail">
<div class="item-intro-nav item-tabs">
<Tabs :animated="false" @on-click="tabClick">
<TabPane label="商品介绍">
<div class="item-intro-img" ref="itemIntroGoods">
<div v-html="skuDetail.intro" v-if="skuDetail.intro"></div>
<div v-else style="margin:20px;">暂无商品介绍</div>
</div>
</TabPane>
<TabPane label="商品评价">
<div class="remarks-container" ref="itemGoodsComment">
<div class="remarks-analyse-box">
<div class="remarks-analyse-goods">
<i-circle :percent="skuDetail.grade || 100" stroke-color="#5cb85c">
<span class="remarks-analyse-num">{{skuDetail.grade || 100}}%</span>
<p class="remarks-analyse-title">好评率</p>
</i-circle>
</div>
</div>
<div class="remarks-bar">
<span @click="searchByGrade('')" :class="{selectedBar: commentParams.grade === ''}">全部({{commentTypeNum.all}})</span>
<span @click="searchByGrade('GOOD')" :class="{selectedBar: commentParams.grade === 'GOOD'}">好评({{commentTypeNum.good}})</span>
<span @click="searchByGrade('MODERATE')" :class="{selectedBar: commentParams.grade === 'MODERATE'}">中评({{commentTypeNum.moderate}})</span>
<span @click="searchByGrade('WORSE')" :class="{selectedBar: commentParams.grade === 'WORSE'}">差评({{commentTypeNum.worse}})</span>
</div>
<div style="text-align: center;margin-top: 20px;" v-if="commentList.length === 0">
暂无评价数据
</div>
<div class="remarks-box" v-for="(item,index) in commentList" :key="index" v-else>
<div class="remarks-user">
<Avatar :src="item.memberProfile" />
<span class="remarks-user-name">{{item.memberName | secrecyMobile}}</span>
</div>
<div class="remarks-content-box">
<p>
<Rate disabled :value="Number(item.descriptionScore)" allow-half class="remarks-star"></Rate>
</p>
<p class="remarks-content">{{item.content}}</p>
<div class="comment-img" v-if="item.haveImage">
<div v-for="(img, imgIndex) in item.image.split(',')"
@click="previewImg(img, item)"
:class="{borderColor:img === item.previewImg}"
:key="imgIndex">
<img :src="img" alt="">
</div>
</div>
<div class="preview-img" v-if="item.previewImg" @click.prevent="hidePreviewImg(item)">
<div>
<span @click.stop="rotatePreviewImg(0, item)"><Icon type="md-refresh" />左转</span>
<span @click.stop="rotatePreviewImg(1, item)"><Icon type="md-refresh" />右转</span>
</div>
<img :src="item.previewImg" :style="{transform:`rotate(${item.deg}deg)`}" width="198" alt="">
</div>
<p class="remarks-sub">
<span class="remarks-item">{{item.goodsName}}</span>
<span class="remarks-time">{{item.createTime}}</span>
</p>
</div>
</div>
<div class="remarks-page">
<Page :total="commentTotal" size="small"
@on-change="changePageNum"
@on-page-size-change="changePageSize"
:page-size="commentParams.pageSize"
></Page>
</div>
</div>
</TabPane>
<!-- <TabPane label="商品问答">
<ShowGoodsQuestion/>
</TabPane> -->
</Tabs>
</div>
</div>
</div>
</div>
</template>
<script>
import ShowGoodsQuestion from '@/components/goodsDetail/ShowGoodsQuestion';
import { goodsComment, goodsCommentNum } from '@/api/member.js';
export default {
name: 'ShowGoodsDetail',
props: {
detail: { // 商品详情
type: Object,
default: null
}
},
data () {
return {
commentList: [], // 评论列表
commentParams: { // 评论传参
pageNumber: 1,
pageSize: 10,
grade: '',
goodsId: ''
},
commentTypeNum: {}, // 评论数量,包括好中差分别的数量
commentTotal: 0, // 评论总数
onceFlag: true // 只调用一次
};
},
computed: {
skuDetail () {
return this.detail.data;
}
},
methods: {
changeHeight (name) {
let heightCss = window.getComputedStyle(this.$refs[name]).height;
heightCss = parseInt(heightCss.substr(0, heightCss.length - 2)) + 89;
this.$refs.itemIntroDetail.style.height = heightCss + 'px';
},
changePageNum (val) {
this.commentParams.pageNumber = val;
this.getList();
},
changePageSize (val) {
this.commentParams.pageNumber = 1;
this.commentParams.pageSize = val;
this.getList();
},
getList () { // 获取评论列表
this.commentParams.goodsId = this.skuDetail.goodsId;
goodsComment(this.commentParams).then(res => {
if (res.code === 200) {
this.commentList = res.result.records;
this.commentTotal = res.result.total;
}
});
goodsCommentNum(this.skuDetail.goodsId).then(res => {
if (res.code === 200) {
this.commentTypeNum = res.result;
}
});
},
searchByGrade (grade) {
this.$set(this.commentParams, 'grade', grade);
this.commentParams.pageNumber = 1;
this.getList();
},
tabClick (name) {
if (name === 0) {
this.$nextTick(() => {
this.changeHeight('itemIntroGoods')
});
} else {
this.$nextTick(() => {
this.changeHeight('itemGoodsComment')
});
}
},
previewImg (img, item) { // 预览图片
this.$set(item, 'previewImg', img);
this.$nextTick(() => {
this.changeHeight('itemGoodsComment')
});
},
hidePreviewImg (item) { // 隐藏预览图片
this.$set(item, 'previewImg', '');
this.$nextTick(() => {
this.changeHeight('itemGoodsComment')
});
},
rotatePreviewImg (type, item) { // 图片旋转
if (type) {
if (item.deg) {
this.$set(item, 'deg', item.deg + 90);
} else {
this.$set(item, 'deg', 90);
}
} else {
if (item.deg) {
this.$set(item, 'deg', item.deg - 90);
} else {
this.$set(item, 'deg', -90);
}
}
},
handleScroll () {
if (this.onceFlag) {
this.$nextTick(() => {
this.changeHeight('itemIntroGoods')
});
this.onceFlag = false
}
}
},
mounted () {
this.$nextTick(() => {
setTimeout(this.changeHeight('itemIntroGoods'), 2000);
});
window.addEventListener('scroll', this.handleScroll)
this.getList();
},
components: {
ShowGoodsQuestion
}
};
</script>
<style scoped lang="scss">
/***************商品详情介绍和推荐侧边栏开始***************/
.item-intro-show{
width: 1200px;
margin: 15px auto;
display: flex;
flex-direction: row;
}
.item-intro-recommend{
width: 200px;
display: flex;
flex-direction: column;
}
.item-intro-recommend-column{
display: flex;
flex-direction: column;
box-shadow: 0px 0px 5px #999;
}
.item-recommend-title{
width: 100%;
height: 38px;
font-size: 16px;
line-height: 38px;
color: #fff;
background-color: $theme_color;
box-shadow: 0px 0px 5px $theme_color;
text-align: center;
}
.item-recommend-column{
margin-top: 15px;
}
.item-recommend-intro{
padding: 5px 15px;
display: flex;
flex-direction: row;
justify-content: space-between;
font-size: 12px;
color: #999;
cursor: pointer;
}
.item-recommend-img{
width: 80%;
margin: 0px auto;
cursor: pointer;
}
.item-recommend-img img{
width: 100%;
}
.item-recommend-top-num{
color: #fff;
margin: 0px 2px;
padding: 1px 5px;
border-radius: 12px;
background-color: $theme_color;
}
.item-recommend-price{
color: $theme_color;
font-weight: bolder;
}
.item-intro-detail{
margin: 0 30px;
// min-height: 1500px;
width: 100%;
}
.item-intro-nav{
width: 100%;
height: 38px;
background-color: #F7F7F7;
// border-bottom: 1px solid $theme_color;
}
.item-intro-nav ul{
margin: 0px;
padding: 0px;
list-style: none;
}
.item-intro-nav li{
float: left;
height: 100%;
width: 120px;
line-height: 38px;
text-align: center;
color: $theme_color;
}
.item-intro-nav li:first-child{
background-color: $theme_color;
color: #fff;
}
.item-intro-img {
width: 100%;
min-height: 300px;
}
.item-intro-img img{
max-width: 1000px;
}
/************* 商品参数 *************/
.item-param-container {
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: space-between;
}
.item-param-box {
padding: 5px;
padding-left: 30px;
width: 240px;
height: 36px;
font-size: 14px;
/* text-align: center; */
/* background-color: #ccc; */
}
.item-param-title {
color: #232323;
}
.item-param-content {
color: #999;
}
.remarks-title {
padding-left: 15px;
height: 36px;
font-size: 16px;
font-weight: bolder;
line-height: 36px;
color: #666666;
background-color: #F7F7F7;
}
.remarks-analyse-box {
padding: 15px;
display: flex;
align-items: center;
}
.remarks-analyse-goods {
margin-left: 15px;
margin-right: 15px;
}
.remarks-analyse-num {
font-size: 26px;
}
.remarks-analyse-title {
font-size: 12px;
line-height: 20px;
}
.remarks-bar {
padding-left: 15px;
height: 36px;
line-height: 36px;
color: #666666;
background-color: #F7F7F7;
.selectedBar{
color: $theme_color;
}
}
.remarks-bar span {
margin-right: 15px;
&:hover{
color: $theme_color;
cursor: pointer;
}
}
.remarks-box {
padding: 15px;
display: flex;
flex-direction: row;
border-bottom: 1px #ccc dotted;
}
.remarks-user {
width: 180px;
}
.remarks-user-name {
padding-left: 15px;
}
.remarks-content-box {
width: calc(100% - 180px);
.comment-img{
display: flex;
.borderColor{
border-color: $theme_color;
}
div{
border: 1px solid #999;
margin-right: 5px;
width: 50px;
height: 50px;
img{width: 100%;}
}
}
.preview-img{
position: relative;
border: 1px solid #eee;
margin: 10px 0;
width: 200px;
div{
position: absolute;
top: 3px;
left: 3px;
z-index: 3;
span{
display: inline-block;
background-color: rgba(0,0,0,.5);
padding:3px 5px;
color: #fff;
border-radius: 4px;
cursor: pointer;
}
span:nth-child(1) .ivu-icon {
transform: rotateY(180deg);
}
}
img:hover{
cursor: url(require('../../../static/small.cur')),auto;
}
}
}
.remarks-content {
font-size: 14px;
color: #232323;
line-height: 28px;
}
.remarks-sub {
margin-top: 5px;
color: #ccc;
}
.remarks-time {
margin-left: 15px;
}
.remarks-page {
margin: 15px;
display: flex;
justify-content:flex-end;
}
/***************商品详情介绍和推荐侧边栏结束***************/
/* 改变便签页样式 */
.ivu-tabs-ink-bar {
background-color: $theme_color !important;
}
/deep/.ivu-tabs-bar{
border: none;
}
.item-tabs > .ivu-tabs > .ivu-tabs-bar .ivu-tabs-tab{
border-radius: 0px;
color: #999;
height: 38px;
// background: #F7F7F7;
}
.item-tabs > .ivu-tabs > .ivu-tabs-bar .ivu-tabs-tab-active{
color: #fff;
background-color: $theme_color;
}
.item-tabs > .ivu-tabs > .ivu-tabs-bar .ivu-tabs-tab-active:before{
content: '';
display: block;
width: 100%;
height: 1px;
color: #fff;
background: #F7F7F7;
position: absolute;
top: 0;
left: 0;
}
.ivu-rate-star-full:before, .ivu-rate-star-half .ivu-rate-star-content:before {
color: $theme_color;
}
</style>

View File

@@ -0,0 +1,53 @@
<template>
<div class="wrapper">
<div v-if="true" class="question-list">
<div class="-item" v-for="index in 6" :key="index">
<!-- 提问 -->
<div class="-item-put -item-div">
<div class="-item-div-l blod">
<Tag color="warning"></Tag>
有屏幕调节亮度吗
</div>
<div class="-item-div-r">2020年10月21日17:03:35</div>
</div>
<!-- 解答 -->
<div class="-item-reply -item-div">
<div class="-item-div-l">
<Tag color="success"></Tag>
能调节点屏幕上方有一条调整带可正负2调整
</div>
<div class="-item-div-r">2020年10月21日17:03:35</div>
</div>
</div>
</div>
<div v-else class="question-empty">
<empty></empty>
</div>
</div>
</template>
<script>
export default {};
</script>
<style scoped lang="scss">
.-item-div {
padding: 10px 0;
display: flex;
align-items: center;
justify-content: space-between;
margin: 10px 0;
}
.-item-div-l {
display: flex;
@include content_color($light_content_color);
}
.-item-div-r {
@include sub_color($light_content_color);
}
.blod {
font-weight: bold;
}
.-item {
margin: 10px 0;
border-bottom: 1px solid $border_color;
}
</style>

View File

@@ -0,0 +1,85 @@
<template>
<div>
<div class="remarks-title">
<span>售后保障</span>
</div>
<div class="item-protect-container">
<div class="item-protect-box">
<p class="item-protect-title-box">
<Avatar style="background-color: #e4393c" icon="ribbon-a" />
<span class="item-protect-title">卖家服务</span>
</p>
<p class="item-protect-detail">
高品质敢承诺7天无理由退货30天免费换新质量问题商家承担来回运费换新如需发票请在确认收货无误后联系商家开出*发票不随货品一同发出
</p>
</div>
<div class="item-protect-box">
<p class="item-protect-title-box">
<Avatar style="background-color: #e4393c" icon="cash" />
<span class="item-protect-title">平台承诺</span>
</p>
<p class="item-protect-detail">
平台卖家销售并发货的商品由平台卖家提供发票和相应的售后服务请您放心购买<br> 因厂家会在没有任何提前通知的情况下更改产品包装产地或者一些附件本司不能确保客户收到的货物与商城图片产地附件说明完全一致只能确保为原厂正货并且保证与当时市场上同样主流新品一致若本商城没有及时更新请大家谅解
</p>
</div>
<div class="item-protect-box">
<p class="item-protect-title-box">
<Avatar style="background-color: #e4393c" icon="locked" />
<span class="item-protect-title">正品行货</span>
</p>
<p class="item-protect-detail">
BIT商城向您保证所售商品均为正品行货BIT自营商品开具机打发票或电子发票
</p>
</div>
<div class="item-protect-box">
<p class="item-protect-title-box">
<Avatar style="background-color: #e4393c" icon="settings" />
<span class="item-protect-title">全国联保</span>
</p>
<p class="item-protect-detail">
凭质保证书及BIT商城发票可享受全国联保服务奢侈品钟表除外奢侈品钟表由BIT联系保修享受法定三包售后服务与您亲临商场选购的商品享受相同的质量保证BIT商城还为您提供具有竞争力的商品价格和运费政策请您放心购买<br><br> 因厂家会在没有任何提前通知的情况下更改产品包装产地或者一些附件本司不能确保客户收到的货物与商城图片产地附件说明完全一致只能确保为原厂正货并且保证与当时市场上同样主流新品一致若本商城没有及时更新请大家谅解
</p>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'ShowProductWarranty'
};
</script>
<style scoped lang="scss">
.remarks-title {
padding-left: 15px;
height: 36px;
font-size: 16px;
font-weight: bolder;
line-height: 36px;
color: #666666;
background-color: #F7F7F7;
}
.item-protect-container {
padding: 15px;
}
.item-protect-box {
margin-bottom: 30px;
}
.item-protect-title-box {
display: flex;
align-items: center;
}
.item-protect-title {
padding-left: 15px;
font-size: 20px;
font-weight: bolder;
color: $theme_color;
}
.item-protect-detail {
padding-top: 5px;
padding-left: 46px;
font-size: 14px;
color: #999;
}
</style>

View File

@@ -0,0 +1,426 @@
<template>
<div class="box">
<div class="nav">
<ul class="location">
<li><router-link to="/" v-if="$route.path !== '/'" class="home-page" ><Icon type="md-home" />首页</router-link></li>
<li>
<Dropdown placement="bottom-start">
<a href="javascript:void(0)">
<Icon type="ios-pin" class="icon"></Icon>
{{ city }}
</a>
<DropdownMenu slot="list">
<div class="city">
<p v-for="(items, index) in cityArr" :key="index">
<span
v-for="(item, index) in items"
class="city-item"
:key="index"
@click="changeCity(item)"
>{{ item }}</span>
</p>
</div>
</DropdownMenu>
</Dropdown>
</li>
</ul>
<ul class="detail">
<!-- <li class="first hover-pointer" @click="handleClickTheme()">切换主题</li> -->
<li class="first" v-show="!userInfo.username">
<router-link :to="`/login?rePath=${$route.path}&query=${JSON.stringify($route.query)}`">
<span style="border:none" class="tipsLogin">请登录</span>
</router-link>
</li>
<li v-show="!!userInfo.username">
<Dropdown>
<p class="username-p">
<Avatar class="person-icon" :src="userInfo.face" icon="person" size="small" />
<span class="username">{{ userInfo.nickName? userInfo.nickName : userInfo.username | secrecyMobile }}</span>
</p>
<DropdownMenu slot="list">
<div class="my-page">
<div class="my-info" @click="myInfo">
<Icon type="md-home"></Icon>
<p>我的主页</p>
</div>
<div class="sign-out" @click="signOutFun">
<Icon type="md-exit"></Icon>
<p>退出登陆</p>
</div>
</div>
</DropdownMenu>
</Dropdown>
</li>
<li class="hover-color" @click="goUserCenter('home/MyOrder')"><span class="nav-item">我的订单</span></li>
<li class="hover-color" @click="goUserCenter('home/MyTracks')"><span class="nav-item">我的足迹</span></li>
<li v-if="$route.name !== 'Cart'" style="position:relative;" @mouseenter="getCartList">
<i class="cart-badge" v-show="cartNum">{{cartNum < 100 ? cartNum : '99'}}</i>
<Dropdown placement="bottom-start">
<router-link to="cart" target="_blank">
<Icon
size="18"
class="cart-icon"
type="ios-cart-outline"
></Icon>
购物车
</router-link>
<DropdownMenu slot="list">
<div class="shopping-cart-null" style="width:200px" v-show="shoppingCart.length <= 0">
<Icon type="ios-cart-outline" class="cart-null-icon"></Icon>
<span>你的购物车没有宝贝哦</span>
<span>赶快去添加商品吧~</span>
</div>
<div class="shopping-cart-list" v-show="shoppingCart.length > 0">
<div
class="shopping-cart-box"
v-for="(item, index) in shoppingCart"
@click="goToPay"
:key="index"
>
<div class="shopping-cart-img">
<img :src="item.goodsSku.thumbnail" class="hover-pointer" />
</div>
<div class="shopping-cart-info">
<div class="shopping-cart-title ">
<p class="hover-pointer goods-title">{{ item.goodsSku.goodsName }}</p>
</div>
<div class="shopping-cart-detail">
<p>
数量:
<span class="shopping-cart-text">{{ item.num }}</span>
价钱:
<span class="shopping-cart-text">{{ item.purchasePrice | unitPrice('¥') }}</span>
</p>
</div>
</div>
</div>
<div class="go-to-buy">
<Button type="error" size="small" @click="goToPay">去结账</Button>
</div>
</div>
</DropdownMenu>
</Dropdown>
</li>
<li>
<span class="nav-item" @click="shopEntry">店铺入驻</span>
</li>
<!-- <li>
<router-link to="/feedback">意见反馈</router-link>
</li>-->
</ul>
</div>
</div>
</template>
<script>
import storage from '@/plugins/storage.js';
import {cartGoodsAll, cartCount} from '@/api/cart.js'
export default {
name: 'M-Header',
created () {
if (storage.getItem('userInfo')) {
this.userInfo = JSON.parse(storage.getItem('userInfo'));
}
},
data () {
return {
// 主题颜色切换
themeType: 'light',
city: '珠海', // 展示城市
cityArr: [
['北京', '上海', '天津', '重庆', '广州'],
['深圳', '河南', '辽宁', '吉林', '江苏'],
['江西', '四川', '海南', '贵州', '云南'],
['西藏', '陕西', '甘肃', '青海', '珠海']
],
userInfo: {}, // 用户信息
shoppingCart: [] // 购物车
};
},
computed: {
cartNum () {
return this.$store.state.cartNum
}
},
methods: {
handleClickTheme () {
this.themeType === 'light'
? (this.themeType = 'dark')
: (this.themeType = 'light');
window.document.documentElement.setAttribute(
'data-theme',
this.themeType
);
},
changeCity (city) {
this.city = city;
},
goToPay () {
let url = this.$router.resolve({
path: '/cart'
})
window.open(url.href, '_blank')
},
myInfo () {
let url = this.$router.resolve({
path: '/home'
})
window.open(url.href, '_blank')
},
signOutFun () {
storage.removeItem('accessToken');
storage.removeItem('refreshToken');
storage.removeItem('userInfo');
this.$router.push('/login');
},
goUserCenter (path) { // 跳转我的订单,我的足迹
if (this.userInfo.username) {
this.$router.push({path: path})
} else {
this.$Modal.confirm({
title: '请登录',
content: '<p>请登录后执行此操作</p>',
okText: '立即登录',
cancelText: '继续浏览',
onOk: () => {
this.$router.push({
path: '/login',
query: {
rePath: this.$router.history.current.path,
query: JSON.stringify(this.$router.history.current.query)
}
});
}
});
}
},
shopEntry () { // 店铺入驻
if (storage.getItem('accessToken')) {
let routeUrl = this.$router.resolve({
path: '/shopEntry',
query: {id: 1}
});
window.open(routeUrl.href, '_blank');
} else {
this.$router.push('login');
}
},
getCartList () { // 获取购物车列表
if (this.userInfo.username) {
cartCount().then(res => {
this.$store.commit('SET_CARTNUM', res.result)
this.Cookies.setItem('cartNum', res.result)
})
cartGoodsAll().then(res => {
this.shoppingCart = res.result.skuList
})
}
}
}
};
</script>
<style scoped lang="scss">
.shopping-cart-detail,
.shopping-cart-text,
.shopping-cart-info,
.nav a,
.location,
.first,
.username,
.shopping-cart-null span {
@include sub_color($light_sub_color);
}
.tipsLogin {
color: $theme_color;
}
.box {
width: 100%;
// height: 35px;
@include background_color($light_white_background_color);
}
.nav {
margin: 0 auto;
width: 1200px;
display: flex;
flex-direction: row;
justify-content: space-between;
}
.nav ul {
list-style: none;
}
.nav li {
float: left;
font-size: 14px;
line-height: 35px;
margin-right: 15px;
font-weight: bold;
}
.nav a,.nav-item {
text-decoration: none;
padding-left: 15px;
border-left: 1px solid #ccc;
color: #999;
cursor: pointer;
}
.location a {
border-left: none;
}
.nav a:hover {
color: $theme_color;
}
.icon {
color: gray;
vertical-align: middle;
}
.first a:first-child {
padding-left: 3px;
border-left: none;
}
.city {
padding: 10px 15px;
}
.city-item {
font-weight: bold;
cursor: pointer;
padding: 5px;
}
.city-item:hover {
color: $theme_color;
}
.person-icon {
color: $theme_color;
background-color: #f0cdb2;
}
.shopping-cart-list {
padding: 10px 15px;
box-sizing: border-box;
height: 300px;
overflow: scroll;
}
.shopping-cart-box {
margin: 8px 0px;
margin-top: 15px;
padding-bottom: 15px;
height: 40px;
display: flex;
align-items: center;
border-bottom: 1px #ccc dotted;
}
.shopping-cart-box:first-child {
margin-top: 8px;
}
.shopping-cart-img {
margin-right: 15px;
width: 40px;
height: 40px;
}
.shopping-cart-img img {
width: 100%;
}
.shopping-cart-info {
display: flex;
flex-direction: column;
justify-content: space-between;
align-content: space-between;
width: 200px;
overflow: hidden;
font-size: 12px;
line-height: 20px;
}
.go-to-buy {
display: flex;
justify-content: flex-end;
}
.shopping-cart-null {
padding: 15px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.cart-null-icon {
font-size: 38px;
margin-bottom: 15px;
}
.shopping-cart-null span {
font-size: 12px;
line-height: 16px;
}
.username-p {
cursor: pointer;
}
.my-page {
padding: 3px 5px;
width: 180px;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.my-page a {
margin: 0px;
padding: 0px;
border: none;
}
.my-info {
padding: 5px;
width: 50%;
height: 100%;
text-align: center;
cursor: pointer;
}
.my-info:hover {
box-shadow: 0px 0px 5px #ccc;
}
.my-info i {
font-size: 28px;
}
.my-info p {
font-size: 12px;
}
.sign-out {
padding: 5px;
width: 50%;
height: 100%;
text-align: center;
cursor: pointer;
}
.sign-out:hover {
box-shadow: 0px 0px 5px $border_color;
}
.sign-out i {
font-size: 28px;
}
.sign-out p {
font-size: 12px;
}
.cart-icon{
padding: 0 6px;
}
.goods-title:hover {
color: $theme_color;
}
.cart-badge {
position: absolute;
right: -8px;
font-style: normal;
background-color: $theme_color;
color: #fff;
font-size: 12px;
width: 17px;
height: 17px;
border-radius: 10px;
line-height: 17px;
text-align: center;
z-index: 3;
top: 3px;
}
</style>

View File

@@ -0,0 +1,102 @@
<template>
<div class="shop-box">
<div class="shop-container">
<div class="shop-title">
<div class="shop-title-content">
<p><router-link :to="`/merchant?id=${skuDetail.storeId}`">{{ skuDetail.storeName }}</router-link></p>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'ShopHeader',
props: {
detail: {
type: Object,
default: null
}
},
computed: {
skuDetail () {
return this.detail;
}
}
};
</script>
<style scoped>
/* 店铺介绍 */
.shop-box {
width: 100%;
height: 50px;
background-color: #484848;
}
.shop-container {
width: 1200px;
height: 100%;
margin: 0px auto;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
color: #fff;
}
.shop-title {
display: flex;
flex-direction: row;
}
.shop-title-icon {
font-size: 46px;
}
.shop-title-content {
padding-top: 8px;
margin-left: 15px;
display: flex;
}
.shop-title-content p {
line-height: 26px;
font-size: 20px;
}
.shop-title-content p:nth-child(2) {
font-size: 16px;
margin-left: 20px;
}
.shop-title-content a {
color: #fff;
}
.shop-another-item {
display: flex;
flex-direction: row;
}
.shop-another-item-detail {
display: flex;
flex-direction: row;
align-items: center;
margin-left: 15px;
}
.shop-another-item-img {
height: 80px;
border-radius: 40px;
overflow: hidden;
}
.shop-another-item-img img {
width: 80px;
}
.shop-anoter-item-intro {
margin-left: 15px;
}
</style>

View File

@@ -0,0 +1,93 @@
<template>
<div class="scroll-show">
<div class="content clearfix">
<cateNav class="cate" :showNavBar="false"></cateNav>
<Search class="search-con" :showLogo="false" :showTag="false"></Search>
<Icon type="ios-cart-outline" @click="goCartList" class="cart-icon" @mouseenter.native="getCartList" />
<i class="cart-badge">{{cartNum < 100 ? cartNum : '99'}}</i>
</div>
</div>
</template>
<script>
import {cartCount} from '@/api/cart.js'
import storage from '@/plugins/storage.js';
export default {
data () {
return {
userInfo: {} // 用户信息
}
},
computed: {
cartNum () { // 购物车数量
return this.$store.state.cartNum
}
},
methods: {
goCartList () {
let routerUrl = this.$router.resolve({
path: '/cart'
})
window.open(routerUrl.href, '_blank')
},
getCartList () { // 获取购物车列表
if (storage.getItem('userInfo')) {
cartCount().then(res => {
this.$store.commit('SET_CARTNUM', res.result)
this.Cookies.setItem('cartNum', res.result)
})
}
}
},
mounted () {
if (storage.getItem('userInfo')) {
this.userInfo = JSON.parse(storage.getItem('userInfo'));
}
}
}
</script>
<style lang="scss" scoped>
.content{
width: 1200px;
height: 40px;
margin: 10px auto;
position: relative;
}
.cate {
float: left;
width: 200px!important;
}
.search-con{
float: left;
width: 800px;
overflow: hidden;
margin-top: -27px;
}
.cart-icon {
width: 30px;
float: left;
font-size: 25px;
margin-top: 8px;
color: $theme_color;
z-index: 1;
position: relative;
&:hover{
cursor: pointer;
}
}
.cart-badge {
position: absolute;
font-style: normal;
right: 165px;
display: block;
background-color: $theme_color;
color: #fff;
font-size: 12px;
width: 17px;
height: 17px;
border-radius: 10px;
line-height: 17px;
text-align: center;
z-index: 5;
top: 3px;
}
</style>

View File

@@ -0,0 +1,33 @@
<template>
<div class="model-form">
<div class="model-content">
<template v-for="(element, index) in data.list">
<model-form-item
v-if="element && element.key"
:key="element.key"
:element="element"
:index="index"
:data="data"
></model-form-item>
</template>
</div>
</div>
</template>
<script>
import ModelFormItem from './modelFormItem.vue';
export default {
name: 'modelForm',
components: {
ModelFormItem
},
props: ['data']
};
</script>
<style lang="scss" scoped>
.model-content {
width: 1200px;
margin: 0 auto;
background: #fff;
min-height: 1200px;
}
</style>

View File

@@ -0,0 +1,302 @@
<template>
<div class="model-item" v-if="element && element.key">
<!-- 轮播图模块包括个人信息快捷导航模块 -->
<template v-if="element.type == 'carousel'">
<model-carousel :data="element"></model-carousel>
</template>
<!-- 热门广告 -->
<template v-if="element.type == 'hotAdvert'">
<div>
<img
style="display: block"
class="hover-pointer"
:src="element.options.list[0].img"
@click="linkTo(element.options.list[0].url)"
width="1200"
alt=""
/>
</div>
<ul class="advert-list">
<template v-for="(item, index) in element.options.list">
<li
v-if="index !== 0"
@click="linkTo(item.url)"
class="hover-pointer"
:key="index"
>
<img :src="item.img" width="230" height="190" alt="" />
</li>
</template>
</ul>
</template>
<!-- 限时秒杀 待完善 -->
<!-- <template v-if="element.type == 'seckill'">
<seckill :data="element"></seckill>
</template> -->
<!-- 折扣广告 -->
<template v-if="element.type == 'discountAdvert'">
<div
class="discountAdvert"
:style="{
'background-image': 'url(' + element.options.bgImg.img + ')',
}"
>
<img
@click="linkTo(item.url)"
class="hover-pointer"
v-for="(item, index) in element.options.classification"
:key="index"
:src="item.img"
width="190"
height="210"
alt=""
/>
<img
@click="linkTo(item.url)"
class="hover-pointer"
v-for="(item, index) in element.options.brandList"
:key="'discount' + index"
:src="item.img"
width="240"
height="105"
alt=""
/>
</div>
</template>
<!-- 好货推荐 -->
<template v-if="element.type == 'recommend'">
<recommend :data="element"></recommend>
</template>
<!-- 新品排行 -->
<template v-if="element.type == 'newGoodsSort'">
<new-goods-sort :data="element"></new-goods-sort>
</template>
<!-- 首页广告 -->
<template v-if="element.type == 'firstAdvert'">
<first-page-advert :data="element"></first-page-advert>
</template>
<!-- 横幅广告 -->
<template v-if="element.type == 'bannerAdvert'">
<img
width="1200"
class="hover-pointer"
@click="linkTo(element.options.url)"
:src="element.options.img"
alt=""
/>
</template>
<template v-if="element.type == 'notEnough'">
<not-enough :data="element"></not-enough>
</template>
</div>
</template>
<script>
import ModelCarousel from './modelList/carousel.vue';
import FirstPageAdvert from './modelList/firstPageAdvert.vue';
import NewGoodsSort from './modelList/newGoodsSort.vue';
import Recommend from './modelList/recommend.vue';
import NotEnough from './modelList/notEnough.vue';
import Seckill from './modelList/seckill.vue';
export default {
name: 'modelFormItem',
props: ['element', 'select', 'index', 'data'],
components: {
ModelCarousel,
Recommend,
NewGoodsSort,
FirstPageAdvert,
NotEnough,
Seckill
},
data () {
return {
showModal: false, // 控制模态框显隐
selected: {} // 已选数据
};
}
};
</script>
<style lang="scss" scoped>
.model-item {
position: relative;
margin-bottom: 20px;
&:hover {
.del-btn {
display: block;
}
}
}
.del-btn {
width: 100px;
height: 100px;
display: none;
position: absolute;
right: -100px;
top: 0;
&:hover {
display: block;
}
}
/** 热门广告 */
.advert-list {
background: $theme_color;
height: 200px;
display: flex;
justify-content: space-around;
padding: 3px 10px;
> li {
img {
cursor: pointer;
border-radius: 10px;
transition: all 150ms ease-in-out;
&:hover {
transform: translateY(-3px);
box-shadow: rgba(0, 0, 0, 0.4) 0px 5px 20px 0px;
}
}
}
}
/** 限时秒杀 */
.limit-img {
display: flex;
flex-direction: row;
img {
width: 300px;
height: 100px;
}
}
/** 折扣广告 */
.discountAdvert {
height: 566px;
background-repeat: no-repeat;
margin-left: -97px;
position: relative;
padding-left: 295px;
display: flex;
flex-wrap: wrap;
align-items: start;
img {
margin-top: 10px;
margin-right: 10px;
transition: all 150ms ease-in-out;
&:hover {
box-shadow: 0 5px 12px 0 rgba(0, 0, 0, 0.4);
transform: translateY(-2px);
}
}
}
/** 首页品牌 */
.brand {
.brand-view {
display: flex;
margin-top: 10px;
.brand-view-content {
width: 470px;
margin-left: 10px;
img {
width: 100%;
height: 316px;
}
.brand-view-title {
height: 50px;
padding: 0 5px;
display: flex;
align-items: center;
justify-content: space-between;
}
}
.brand-view-content:first-child {
width: 240px;
margin-left: 0;
}
}
.brand-list {
margin-top: 10px;
display: flex;
align-items: center;
flex-wrap: wrap;
li {
width: 121px;
height: 112px;
position: relative;
overflow: hidden;
border: 1px solid #f5f5f5;
margin: -1px -1px 0 0;
&:hover {
.brand-mash {
display: flex;
}
}
.brand-img {
text-align: center;
margin-top: 30px;
img {
width: 100px;
height: auto;
}
}
.brand-mash {
display: none;
position: absolute;
top: 0;
left: 0;
background: rgba(0, 0, 0, 0.5);
width: inherit;
height: inherit;
font-size: 12px;
font-weight: bold;
.ivu-icon {
position: absolute;
right: 10px;
top: 10px;
font-size: 15px;
}
align-items: center;
justify-content: center;
flex-direction: column;
color: #fff;
cursor: pointer;
div:last-child {
background-color: $theme_color;
border-radius: 9px;
padding: 0 10px;
margin-top: 5px;
}
}
}
.refresh {
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
.ivu-icon {
font-size: 18px;
transition: all 0.3s ease-out;
}
&:hover {
background-color: $theme_color;
color: #fff;
.ivu-icon {
transform: rotateZ(360deg);
}
}
}
}
}
/** 装修模态框 内部样式start */
.modal-top-advert {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
> * {
margin-bottom: 10px;
}
}
</style>

View File

@@ -0,0 +1,180 @@
<template>
<div class="model-carousel">
<div class="nav-body clearfix">
<!-- 侧边导航占位 -->
<div class="nav-side"></div>
<div class="nav-content">
<!-- 轮播图 -->
<Carousel autoplay>
<CarouselItem v-for="(item, index) in data.options.list" :key="index">
<div style="overflow: hidden">
<img
:src="item.img"
width="790"
@click="linkTo(item.url)"
height="340"
class="hover-pointer"
/>
</div>
</CarouselItem>
</Carousel>
</div>
<div class="nav-right">
<div class="person-msg">
<img :src="userInfo.face" v-if="userInfo.face" alt />
<Avatar icon="ios-person" class="mb_10" v-else size="80" />
<div>Hi{{ userInfo.nickName || "欢迎来到LiLi Shop" | secrecyMobile }}</div>
<div v-if="userInfo.id">
<Button type="error" shape="circle" @click="$router.push('home')">会员中心</Button>
</div>
<div v-else>
<Button type="error" @click="$router.push('login')" shape="circle"
>请登录</Button
>
</div>
</div>
<div class="shop-msg">
<div>
<span>常见问题</span>
<ul class="article-list">
<li class="ellipsis" :alt="article.title" v-for="(article, index) in articleList" :key="index" @click="goArticle(article.id)">
{{article.title}}
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import {articleList} from '@/api/common.js'
import storage from '@/plugins/storage';
export default {
name: 'modelCarousel',
props: ['data'],
data () {
return {
userInfo: {}, // 用户信息
articleList: [], // 常见问题
params: { // 请求常见问题参数
pageNumber: 1,
pageSize: 5,
type: 'ANNOUNCEMENT',
sort: 'sort'
}
};
},
methods: {
getArticleList () {
articleList(this.params).then(res => {
if (res.success) {
this.articleList = res.result.records
}
})
},
goArticle (id) {
let routeUrl = this.$router.resolve({
path: '/article',
query: {id}
});
window.open(routeUrl.href, '_blank');
}
},
mounted () {
if (storage.getItem('userInfo')) this.userInfo = JSON.parse(storage.getItem('userInfo'));
this.getArticleList()
}
};
</script>
<style scoped lang="scss">
.model-carousel {
width: 1200px;
height: 340px;
overflow: hidden;
}
/* 导航主体 */
.nav-body {
width: 1200px;
height: 340px;
margin: 0px auto;
}
.nav-side {
height: 100%;
width: 200px;
float: left;
padding: 0px;
color: #fff;
background-color: #6e6568;
}
/*导航内容*/
.nav-content {
width: 790px;
overflow: hidden;
float: left;
position: relative;
}
.nav-right {
float: left;
width: 210px;
.person-msg {
display: flex;
align-items: center;
flex-direction: column;
margin: 20px auto;
button {
height: 25px !important;
margin-top: 10px;
}
.ivu-btn-default {
color: $theme_color;
border-color: $theme_color;
}
img {
margin-bottom: 10px;
width: 80px;
height: 80px;
border-radius: 50%;
}
}
.shop-msg {
div {
width: 100%;
margin: 10px 27px;
span {
cursor: pointer;
text-align: center;
font-weight: bold;
margin-left: 5px;
}
span:nth-child(1) {
@include content_color($theme_color);
margin-left: 0;
}
span:nth-child(2) {
font-weight: normal;
}
span:nth-child(3):hover {
color: $theme_color;
}
}
ul {
li {
cursor: pointer;
margin: 5px 0;
color: #999395;
width: 150px;
font-size: 12px;
&:hover {
color: $theme_color;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,99 @@
<template>
<div class="first-page-advert">
<div
class="item hover-pointer"
@click="linkTo(item.url)"
:style="{
backgroundImage: `linear-gradient(to right, ${item.fromColor}, ${item.toColor})`,
}"
v-for="(item, index) in options.list"
:key="index"
>
<div>
<span class="line top-line"></span>
<p>{{ item.name }}</p>
<span class="line btm-line"></span>
<p>{{ item.describe }}</p>
</div>
<img :src="item.img" width="170" height="170" alt="" />
</div>
</div>
</template>
<script>
export default {
props: {
data: {
type: Object,
default: null
}
},
data () {
return {
options: this.data.options // 装修数据
};
},
methods: {}
};
</script>
<style lang="scss" scoped>
.first-page-advert {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
// margin-top: -10px;
.item {
width: 393px;
height: 170px;
margin-top: 10px;
display: flex;
align-items: center;
justify-content: center;
img {
margin-left: 20px;
transition: transform 0.5s, -webkit-transform 0.5s, -moz-transform 0.5s;
&:hover {
transform: translateX(-5px);
}
}
&:nth-of-type(1),
&:nth-of-type(2),
&:nth-of-type(3) {
margin-top: 0;
}
p:nth-of-type(1) {
margin: 3px 0;
font-size: 18px;
color: #fff;
}
p:nth-of-type(2) {
margin-top: 3px;
color: #fff;
}
}
.line {
position: relative;
display: block;
height: 2px;
background: url(../../../assets/images/festival_icon.png);
z-index: 1;
}
.top-line {
width: 78px;
background-position: -1px -3px;
}
.btm-line {
background-position: 0 -11px;
width: 154px;
}
}
.modal-top-advert {
align-items: start;
padding: 0 30px;
.exhibition {
width: 300px;
height: 50px;
}
}
</style>

View File

@@ -0,0 +1,234 @@
<template>
<div class="new-goods">
<div class="left">
<div class="top-header" :style="{ background: options.left.bgColor }">
<span>{{ options.left.title }}</span>
<span @click="linkTo(options.left.url)" class="hover-pointer"
>{{ options.left.secondTitle }} &gt;</span
>
</div>
<div class="content">
<div
class="con-item hover-pointer"
v-for="(item, index) in options.left.list"
:key="index"
@click="linkTo(item.url)"
>
<div>
<p>{{ item.name }}</p>
<p class="describe">{{ item.describe }}</p>
</div>
<img :src="item.img" alt="" />
</div>
</div>
</div>
<div class="middle">
<div class="top-header" :style="{ background: options.middle.bgColor }">
<span>{{ options.middle.title }}</span>
<span class="hover-pointer" @click="linkTo(options.middle.url)"
>{{ options.middle.secondTitle }} &gt;</span
>
</div>
<div class="content">
<div
class="con-item hover-pointer"
v-for="(item, index) in options.middle.list"
:key="index"
@click="linkTo(item.url)"
>
<div>
<p>{{ item.name }}</p>
<p class="describe">{{ item.describe }}</p>
</div>
<img :src="item.img" alt="" />
</div>
</div>
</div>
<div class="right">
<div class="top-header" :style="{ background: options.right.bgColor }">
<span>{{ options.right.title }}</span>
<span @click="linkTo(options.right.url)" class="hover-pointer"
>{{ options.right.secondTitle }} &gt;</span
>
</div>
<div class="content">
<div
v-for="(item, index) in options.right.list"
:key="index"
class="hover-pointer"
@click="linkTo(item.url)"
>
<img :src="item.img" alt="" />
<p>{{ item.name }}</p>
<p>{{ item.price | unitPrice("¥") }}</p>
<div class="jiaobiao" :class="'jiaobiao' + (index + 1)">
{{ index + 1 }}
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
data: {
type: Object,
default: null
}
},
data () {
return {
options: this.data.options // 装修数据
};
},
methods: {}
};
</script>
<style lang="scss" scoped>
.new-goods {
display: flex;
justify-content: space-between;
> div {
width: 393px;
height: 440px;
}
.left > .content {
> div:nth-child(1) {
height: 240px;
flex-direction: column;
border: 1px solid #eee;
border-top: none;
border-left: none;
justify-content: space-between;
img {
width: 160px;
height: 160px;
}
.describe {
margin-top: 10px;
}
}
> div:nth-child(2) {
border-right: 1px solid #eee;
}
> div:nth-child(3),
> div:nth-child(4) {
border-bottom: 1px solid #eee;
}
}
.middle > .content {
> div {
border-style: solid;
border-color: #eee;
border-width: 0;
border-bottom-width: 1px;
}
> div:nth-child(1),
> div:nth-child(2),
> div:nth-child(3) {
border-right-width: 1px;
}
> div:nth-child(6),
> div:nth-child(3) {
border-bottom-width: 0;
}
}
.right > .content {
display: flex;
flex-wrap: wrap;
flex-direction: row;
font-size: 12px;
> div {
position: relative;
width: 120px;
padding: 5px 10px 0 10px;
img {
width: 100px;
height: 100px;
}
border-bottom: 1px solid #eee;
:nth-child(2) {
height: 38px;
overflow: hidden;
}
:nth-child(3) {
color: $theme_color;
margin-top: 5px;
}
.jiaobiao {
position: absolute;
width: 23px;
height: 23px;
top: 10px;
right: 16px;
background: url(../../../assets/images/festival_icon.png);
color: #fff;
text-align: center;
}
.jiaobiao1,
.jiaobiao4 {
background-position: -2px -30px;
}
.jiaobiao2,
.jiaobiao5 {
background-position: -31px -30px;
}
.jiaobiao3,
.jiaobiao6 {
background-position: -60px -30px;
}
}
> div:nth-child(4),
> div:nth-child(5),
> div:nth-child(6) {
border: none;
}
}
.top-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 50px;
padding: 0 10px;
background: #c43d7e;
color: #fff;
span:nth-child(1) {
font-size: 20px;
}
span:nth-child(2) {
font-size: 12px;
}
}
.content {
padding: 10px 12px 0;
display: flex;
flex-wrap: wrap;
flex-direction: column;
height: 370px;
}
.con-item {
width: 185px;
height: 120px;
display: flex;
padding-left: 10px;
padding-top: 10px;
img {
width: 90px;
height: 90px;
margin-top: 10px;
}
}
.describe {
color: #999;
font-size: 12px;
margin-top: 15px;
}
}
</style>

View File

@@ -0,0 +1,145 @@
<template>
<div class="not-enough">
<ul class="nav-bar">
<li
v-for="(item, index) in conData.options.navList"
:class="currentIndex === index ? 'curr' : ''"
@click="changeCurr(index)"
:key="index"
>
<p>{{ item.title }}</p>
<p>{{ item.desc }}</p>
</li>
</ul>
<div class="content" v-if="showContent">
<div
v-for="(item, index) in conData.options.list[currentIndex]"
:key="index"
class="hover-pointer"
@click="linkTo(item.url)"
>
<img :src="item.img" width="210" height="210" :alt="item.name" />
<p>{{ item.name }}</p>
<p>
<span>{{ Number(item.price) | unitPrice("¥") }}</span>
</p>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
data: {
type: Object,
default: null
}
},
data () {
return {
currentIndex: 0, // 当前分类下标
conData: this.data, // 装修数据
showContent: true // 是否展示内容
};
},
watch: {
data: function (val) {
this.conData = val;
},
conData: function (val) {
this.$emit('content', val);
}
},
mounted () {},
methods: {
changeCurr (index) {
this.currentIndex = index;
}
}
};
</script>
<style lang="scss" scoped>
.nav-bar {
display: flex;
justify-content: center;
width: 100%;
margin-bottom: 10px;
background-color: rgb(218, 217, 217);
height: 60px;
align-items: center;
position: relative;
li {
padding: 0 30px;
text-align: center;
p:nth-child(1) {
font-size: 16px;
border-radius: 50px;
padding: 0 7px;
}
p:nth-child(2) {
font-size: 14px;
color: #999;
}
&:hover {
p {
color: $theme_color;
}
cursor: pointer;
}
border-right: 1px solid #eee;
}
li:last-of-type {
border: none;
}
.curr {
p:nth-child(1) {
background-color: $theme_color;
color: #fff;
}
p:nth-child(2) {
color: $theme_color;
}
}
}
.content {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
> div {
padding: 10px;
box-sizing: border-box;
border: 1px solid #eee;
margin-bottom: 10px;
&:hover {
border-color: $theme_color;
color: $theme_color;
}
p:nth-of-type(1) {
overflow: hidden;
width: 210px;
white-space: nowrap;
text-overflow: ellipsis;
margin: 10px 0 5px 0;
}
p:nth-of-type(2) {
color: $theme_color;
font-size: 16px;
display: flex;
justify-content: space-between;
align-items: center;
span:nth-child(2) {
text-decoration: line-through;
font-size: 12px;
color: #999;
}
}
}
}
</style>

View File

@@ -0,0 +1,217 @@
<template>
<div class="recommend">
<div class="recommend-left">
<div class="head-recommend" :style="{ background: msgLeft.bgColor }">
<span>{{ msgLeft.title }}</span>
<span class="hover-pointer" @click="linkTo(msgLeft.url)">{{ msgLeft.secondTitle }}&gt;</span>
</div>
<div class="content-left">
<div>
<img class="hover-pointer" @click="linkTo(msgLeft.list[0].url)" :src="msgLeft.list[0].img" width="160" height="160" alt="" />
<div class="margin-left">{{ msgLeft.list[0].name }}</div>
<div class="margin-left">{{ msgLeft.list[0].describe }}</div>
<Button
size="small"
:style="{ background: msgLeft.bgColor }"
@click="linkTo(msgLeft.list[0].url)"
class="fz_12 view-btn"
>点击查看</Button
>
</div>
<div>
<template v-for="(item, index) in msgLeft.list">
<div v-if="index != 0" :key="index" @click="linkTo(item.url)" class="hover-pointer">
<img :src="item.img" width="80" height="80" alt="" />
<div>
<div>{{ item.name }}</div>
<div>{{ item.describe }}</div>
</div>
</div>
</template>
</div>
</div>
</div>
<div class="recommend-right">
<div class="head-recommend" :style="{ background: msgRight.bgColor }">
<span>{{ msgRight.title }}</span>
<span @click="linkTo(msgRight.url)" class="hover-pointer"
>{{ msgRight.secondTitle }}&gt;</span
>
</div>
<div class="content-right">
<div
v-for="(item, index) in msgRight.list"
:key="index"
@click="linkTo(item.url)" class="hover-pointer"
>
<div class="right-item" :style="{'border': index===2 || index===3 ?'none': ''}">
<div>
<span :style="{ background: msgRight.bgColor }">{{item.name}}</span>
<span>{{ item.describe }}</span>
</div>
<div class="right-img">
<img :src="item.img" alt="" />
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
data: {
type: Object,
default: {}
}
},
data () {
return {
msgLeft: this.data.options.contentLeft, // 左侧数据
msgRight: this.data.options.contentRight // 右侧数据
};
},
methods: {}
};
</script>
<style lang="scss" scoped>
.recommend {
display: flex;
justify-content: space-between;
.recommend-left {
width: 595px;
.content-left {
display: flex;
padding-top: 10px;
font-size: 12px;
> div:nth-child(1) {
width: 189px;
border-right: 1px solid #eee;
height: 360px;
img {
margin: 40px 0 0 15px;
}
.margin-left {
margin-left: 15px;
width: 145px;
}
div:nth-of-type(1) {
font-weight: bold;
border-top: 1px solid #eee;
padding-top: 10px;
padding-bottom: 10px;
}
div:nth-of-type(2) {
color: #999;
}
.view-btn {
margin-left: 15px;
margin-top: 10px;
color: #fff;
}
}
> div:nth-child(2) {
width: 405px;
display: flex;
flex-wrap: wrap;
> div {
display: flex;
align-items: center;
width: 200px;
height: 120px;
img {
margin: 0 10px;
}
> div:nth-child(2) {
:nth-child(2) {
color: #449dae;
}
}
}
}
}
}
.recommend-right {
width: 595px;
height: 360px;
.head-recommend {
background: #a25684;
}
.content-right {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
padding-top: 10px;
> div {
width: 50%;
text-align: center;
height: 180px;
padding-top: 10px;
.right-item {
border-bottom: 1px solid #eee;
display: flex;
margin-top: 30px;
margin-left: 5px;
margin-right: 5px;
height: 150px;
padding: 0 10px;
font-size: 12px;
>div:nth-child(1) {
width: 130px;
margin-top: 30px;
span:nth-child(1){
color: #fff;
border-radius: 10px;
padding: 0 5px;
background-color: #a25684;
display: block;
width: 120px;
overflow: hidden;
white-space: nowrap;
margin: 0 10px 10px 0;
}
span:nth-child(2) {
font-size: 12px;
color: #666;
display: block;
}
}
.right-img {
width: 100;
height: 100px;
text-align: center;
margin: 0 auto;
img{
max-height: 100px;
max-width: 100px;
}
}
}
}
> div:nth-child(n + 1) {
border-right: 1px solid #eee;
}
}
}
.head-recommend {
display: flex;
align-items: center;
justify-content: space-between;
height: 50px;
padding: 0 10px;
background: #449dae;
color: #fff;
span:nth-child(1) {
font-size: 20px;
}
span:nth-child(2) {
font-size: 12px;
}
}
}
</style>

View File

@@ -0,0 +1,289 @@
<template>
<div class="seckill">
<div class="aside hover-pointer" @click="goPromotion">
<div class="title">{{ actName }}</div>
<div class="hour">
<span>{{ currHour }}:00</span>点场 倒计时
</div>
<div class="count-down" v-if="actStatus === 1">
<span>{{ hours }}</span
><span>{{ minutes }}</span
><span>{{ seconds }}</span>
</div>
<div class="act-status" v-else>
{{ actStatus == 0 ? "未开始" : "已结束" }}
</div>
</div>
<div class="section">
<swiper ref="mySwiper" :options="swiperOptions">
<swiper-slide
v-for="(item, index) in options.list[0].goodsList"
:key="index"
class="swiper-slide"
>
<div class="content hover-pointer" @click="goPromotion">
<img :src="item.img" width="140" height="140" :alt="item.name" />
<div class="ellipsis">{{ item.name }}</div>
<div>
<span>{{ item.price | unitPrice("¥") }}</span>
<span>{{ item.originalPrice | unitPrice("¥") }}</span>
</div>
</div>
</swiper-slide>
</swiper>
</div>
</div>
</template>
<script>
import { Swiper, SwiperSlide, directive } from 'vue-awesome-swiper';
import 'swiper/swiper-bundle.css';
export default {
components: {
Swiper,
SwiperSlide
},
directives: {
swiper: directive
},
props: {
data: {
type: Object,
default: null
}
},
data () {
return {
options: this.data.options, // 装修数据
actStatus: 0, // 0 未开始 1 进行中 2 已结束
actName: '限时秒杀', // 活动名称
currHour: '00', // 当前秒杀场
diffSeconds: 0, // 倒计时秒数
days: 0, // 天
hours: 0, // 小时
minutes: 0, // 分钟
seconds: 0, // 秒
interval: undefined, // 定时器
swiperOptions: { // 轮播图参数
slidesPerView: 5,
autoplay: true,
loop: true
}
};
},
watch: {
diffSeconds (val) {
const hours = Math.floor(val / 3600);
// 当前秒数 / 60向下取整
// 获取到所有分钟数 3600 / 60 = 60分钟
// 对60取模超过小时数的分钟数
const minutes = Math.floor(val / 60) % 60;
// 当前的秒数 % 60获取到 超过小时数、分钟数的秒数(秒数)
const seconds = val % 60;
this.hours = hours < 10 ? '0' + hours : hours;
this.minutes = minutes < 10 ? '0' + minutes : minutes;
this.seconds = seconds < 10 ? '0' + seconds : seconds;
if (val === 0) {
clearInterval(this.interval);
this.hours = 0;
this.minutes = 0;
this.seconds = 0;
this.countDown(this.options.list);
}
}
},
mounted () {
this.countDown(this.options.list);
},
beforeDestroy () {
clearInterval(this.interval);
},
methods: {
// 倒计时
countDown (list) {
/**
* 默认倒计时两小时
* 如果没有开始,则显示未开始
* 进行中显示倒计时 + 时间
* 今天的秒杀结束则显示已结束
*/
let nowHour = new Date().getHours();
if (nowHour < Number(list[0].time)) {
// 活动未开始
this.currHour = list[0].time;
this.actStatus = 0;
} else if (nowHour >= Number(list[list.length - 1].time + 2)) {
// 活动已结束
this.actStatus = 2;
this.currHour = list[list.length - 1].time;
} else {
// 活动进行中
this.actStatus = 1;
for (let i = 0; i < list.length; i++) {
if (nowHour === Number(list[i].time)) {
this.currHour = list[i].time;
}
if (
nowHour > Number(list[i].time) &&
nowHour < Number(list[i].time + 2)
) {
this.currHour = list[i].time;
}
}
// 当前0点时间戳
let zeroTime = new Date(new Date().toLocaleDateString()).getTime();
// 活动倒计时
this.diffSeconds = Math.floor((zeroTime + 3600 * 1000 * (this.currHour + 2) - new Date().getTime()) / 1000);
this.interval = setInterval(() => {
this.diffSeconds--;
}, 1000);
}
},
goPromotion () {
let routeUrl = this.$router.resolve({
path: '/seckill'
});
window.open(routeUrl.href, '_blank');
}
}
};
</script>
<style lang="scss" scoped>
.seckill {
width: 100%;
height: 260px;
display: flex;
.aside {
overflow: hidden;
width: 190px;
height: 100%;
color: #fff;
background-image: url("../../../assets/images/seckillBg.png");
.title {
width: 100%;
text-align: center;
font-size: 28px;
margin-top: 31px;
}
.hour {
margin-top: 90px;
text-align: center;
span {
font-size: 18px;
}
}
.count-down {
margin: 10px 0 0 30px;
> span {
position: relative;
float: left;
width: 30px;
height: 30px;
text-align: center;
background-color: #2f3430;
margin-right: 20px;
color: white;
font-size: 20px;
&::after {
content: ":";
display: block;
position: absolute;
right: -20px;
font-weight: bolder;
font-size: 18px;
width: 20px;
height: 100%;
top: 0;
}
}
> span:last-child::after {
content: "";
}
}
.act-status {
margin: 10px 0 0 65px;
font-size: 20px;
}
}
.section {
width: 1000px;
// background: #efefef;
.swiper-slide {
height: 260px;
.content {
width: 200px;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
position: relative;
&::after {
content: "";
display: block;
position: absolute;
top: 50%;
right: 0;
width: 1px;
height: 200px;
transform: translateY(-50%);
background: linear-gradient(180deg, white, #eeeeee, white);
}
img {
margin-top: 30px;
}
> div {
width: 160px;
margin-top: 10px;
font-size: 12px;
position: relative;
}
> div:nth-of-type(1):hover {
color: $theme_color;
cursor: pointer;
}
> div:nth-of-type(2) {
border: 1px solid $theme_color;
line-height: 24px;
display: flex;
text-align: center;
span:nth-child(1) {
color: #fff;
font-size: 16px;
width: 92px;
background-color: $theme_color;
position: relative;
&::before {
content: " ";
width: 0;
height: 0;
border-color: transparent white transparent transparent;
border-style: solid;
border-width: 24px 8px 0 0;
position: absolute;
top: 0;
left: 84px;
}
}
span:nth-child(2) {
color: #999;
width: 66px;
text-decoration: line-through;
}
}
}
}
}
}
.ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>

View File

@@ -0,0 +1,3 @@
## 此组件为结算页面修改发票信息使用 后续可以复用到个人信息添加发票页面
### 目前没有参数,之后会设置一个参数接收历史的单位发票数据

View File

@@ -0,0 +1,171 @@
<template>
<div class="invoice-modal">
<Modal v-model="invoiceAvailable" width="600" footer-hide>
<p slot="header">
<span>发票信息</span>
</p>
<!-- <div>
<div>为响应环保自营全面启用电子普通发票非自营发票由第三方商家实际开具</div>
<div>电子普通发票是税务机关认可的有效收付款凭证与纸质普通发票具有同等法律效力可用于报销入账售后维权等</div>
<div>如商品由第三方卖家销售发票类型及内容将由该卖家决定</div>
</div> -->
<!-- 普通发票 -->
<div class="nav-content">
<Form
:model="invoiceForm"
ref="form"
label-position="left"
:rules="ruleInline"
:label-width="110"
>
<FormItem label="发票类型">
<RadioGroup v-model="invoiceForm.type">
<Radio :label="1">个人</Radio>
<Radio :label="2">单位</Radio>
</RadioGroup>
</FormItem>
<FormItem
label="发票抬头"
v-if="invoiceForm.type == 2"
prop="receiptTitle"
>
<i-input v-model="invoiceForm.receiptTitle"></i-input>
</FormItem>
<FormItem
label="纳税人识别号"
v-if="invoiceForm.type == 2"
prop="taxpayerId"
>
<i-input v-model="invoiceForm.taxpayerId"></i-input>
</FormItem>
<FormItem label="发票内容">
<RadioGroup v-model="invoiceForm.receiptContent">
<Radio label="不开发票">不开发票</Radio>
<Radio label="商品明细">商品明细</Radio>
</RadioGroup>
</FormItem>
</Form>
<div style="text-align: center">
<Button type="primary" :loading="loading" @click="save">保存发票信息</Button>
<Button type="default" @click="invoiceAvailable = false">取消</Button>
</div>
</div>
</Modal>
</div>
</template>
<script>
import { saveReceipt } from '@/api/member.js';
import { TINumber } from '@/plugins/RegExp.js';
export default {
name: 'invoiceModal',
data () {
return {
invoiceAvailable: false, // 模态框显隐
loading: false, // 提交状态
invoiceForm: { // 发票表单
// 普票表单
receiptTitle: '', // 发票抬头
taxpayerId: '', // 纳税人识别号
receiptContent: '不开发票', // 发票内容
type: 1 // 1 个人 2 单位
},
ruleInline: {
receiptTitle: [{ required: true, message: '请填写公司名称' }],
taxpayerId: [
{ required: true, message: '请填写纳税人识别号' },
{ pattern: TINumber, message: '请填写正确的纳税人识别号' }
]
}
};
},
methods: {
save () {
if (this.invoiceForm.type === 1) {
// 个人
let flag = true;
this.receiptItems.forEach((e) => {
if (
e.receiptTitle === '个人' &&
e.receiptContent === this.invoiceForm.receiptContent
) {
this.$emit('change', e);
flag = false;
this.invoiceAvailable = false;
}
});
if (flag) {
let params = {
receiptTitle: '个人',
receiptContent: this.invoiceForm.receiptContent
};
this.loading = true;
saveReceipt(params)
.then((res) => {
this.loading = false;
if (res.success) {
this.$emit('change', res.result);
this.invoiceAvailable = false;
}
})
.catch(() => {
this.loading = false;
});
}
} else {
// 单位
this.$refs.form.validate((valid) => {
if (valid) {
this.loading = true;
let params = {
receiptTitle: this.invoiceForm.receiptTitle,
taxpayerId: this.invoiceForm.taxpayerId,
receiptContent: this.invoiceForm.receiptContent
};
let flag = true;
this.receiptItems.forEach((e) => {
if (e.taxpayerId === params.taxpayerId) {
flag = false;
}
});
if (!flag) {
this.$Message.error('已有当前税号的发票信息,请直接选择已有发票');
} else {
saveReceipt(params)
.then((res) => {
this.loading = false;
if (res.success) {
this.$emit('change', res.result);
this.invoiceAvailable = false;
}
})
.catch(() => {
this.loading = false;
});
}
}
});
}
}
}
};
</script>
<style lang="scss" scoped>
/** 普票 */
.inv-type {
text-align: center;
}
.add-inv {
font-size: 12px;
color: #438cde;
cursor: pointer;
&:hover {
color: $theme_color;
}
}
.nav-content {
width: 500px;
margin: 10px auto;
}
</style>

View File

@@ -0,0 +1,65 @@
<template>
<div class="wrapper">
<card _Title="猜你喜欢" :_Size="16"> </card>
<Row :gutter="12" class="likeList">
<Col
:span="4"
class="likeItem"
v-for="(item, index) in goodsData"
:key="index"
>
<img :src="item.img" alt="" />
<div class="likeTitle">{{ item.title }}</div>
<div class="likePrice">{{ item.price }}</div>
</Col>
</Row>
</div>
</template>
<script>
export default {
name: 'like',
data () {
}
};
</script>
<style scoped lang="scss">
.wrapper {
@include white_background_color();
}
.likeList {
padding: 0 12px;
display: flex;
flex-wrap: wrap;
> .likeItem {
/*width: 210px;*/
/*margin: 10px 5px;*/
> img {
display: block;
width: 100%;
height: auto;
}
> .likeTitle,
.likePrice {
margin: 6px 0;
text-align: center;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
> .likePrice {
color: $theme_color;
}
}
}
</style>

View File

@@ -0,0 +1,201 @@
<template>
<div class="lili-map">
<Modal v-model="showMap" title="选择地址" width="800">
<div class="address">{{ addrContent.address }}</div>
<div id="map-container"></div>
<div class="search-con">
<Input
placeholder="输入关键字搜索"
id="input-map"
v-model="mapSearch"
/>
<ul>
<li
v-for="(tip, index) in tips"
:key="index"
@click="selectAddr(tip.location)"
>
<p>{{ tip.name }}</p>
<p>{{ tip.district + tip.address }}</p>
</li>
</ul>
</div>
<div slot="footer">
<Button type="default" @click="showMap = false">取消</Button>
<Button type="primary" :loading="loading" @click="ok">确定</Button>
</div>
</Modal>
</div>
</template>
<script>
import AMapLoader from '@amap/amap-jsapi-loader';
import { handleRegion } from '@/api/address.js';
export default {
name: 'map',
props: {
useApi: {
default: true,
type: Boolean
}
},
data () {
return {
showMap: false, // 展示地图
mapSearch: '', // 地图搜索
map: null, // 初始化地图
autoComplete: null, // 初始化搜索方法
geocoder: null, // 初始化地理、坐标转化
positionPicker: null, // 地图拖拽选点
tips: [], // 搜索关键字列表
addrContent: {}, // 回显地址信息
loading: false // 加载状态
};
},
watch: {
mapSearch: function (val) {
this.searchOfMap(val);
}
},
methods: {
ok () {
// 确定选择
this.loading = true;
const address = this.addrContent.address;
const township = this.addrContent.regeocode.addressComponent.township;
const index = address.indexOf(township) + township.length;
this.addrContent.detail = address.substring(index);
const params = {
cityCode: this.addrContent.regeocode.addressComponent.citycode,
townName: this.addrContent.regeocode.addressComponent.township
};
if (this.useApi) {
handleRegion(params).then((res) => {
this.loading = false;
if (res.code === 200) {
this.showMap = false;
this.addrContent.addr = res.result.name.replace(/,/g, ' ');
this.addrContent.addrId = res.result.id;
this.$emit('getAddress', this.addrContent);
}
});
} else {
this.loading = false;
this.showMap = false;
this.$emit('getAddress', this.addrContent);
}
},
init () {
AMapLoader.load({
key: 'b440952723253aa9fe483e698057bf7d', // 申请好的Web端开发者Key首次调用 load 时必填
version: '', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
plugins: [
'AMap.ToolBar',
'AMap.Autocomplete',
'AMap.PlaceSearch',
'AMap.Geolocation',
'AMap.Geocoder'
], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
AMapUI: {
// 是否加载 AMapUI缺省不加载
version: '1.1', // AMapUI 缺省 1.1
plugins: ['misc/PositionPicker'] // 需要加载的 AMapUI ui插件
}
})
.then((AMap) => {
let that = this;
this.map = new AMap.Map('map-container', {
zoom: 12
});
that.map.addControl(new AMap.ToolBar());
that.map.addControl(new AMap.Autocomplete());
that.map.addControl(new AMap.PlaceSearch());
that.map.addControl(new AMap.Geocoder());
// 实例化Autocomplete
let autoOptions = {
city: '全国'
};
that.autoComplete = new AMap.Autocomplete(autoOptions); // 搜索
that.geocoder = new AMap.Geocoder(autoOptions);
that.positionPicker = new AMapUI.PositionPicker({
// 拖拽选点
mode: 'dragMap',
map: that.map
});
that.positionPicker.start();
/**
*
* 所有回显数据都在positionResult里面
* 需要字段可以查找
*
*/
that.positionPicker.on('success', function (positionResult) {
// console.log(positionResult);
that.addrContent = positionResult;
});
})
.catch((e) => {});
},
searchOfMap (val) {
// 地图搜索
let that = this;
this.autoComplete.search(val, function (status, result) {
// 搜索成功时result即是对应的匹配数据
if (status === 'complete' && result.info === 'OK') {
that.tips = result.tips;
} else {
that.tips = [];
}
});
},
selectAddr (location) {
// 选择坐标
if (!location) {
this.$Message.warning('请选择正确点位');
return false;
}
const lnglat = [location.lng, location.lat];
this.positionPicker.start(lnglat);
}
},
mounted () {
this.init();
}
};
</script>
<style lang="scss" scoped>
#map-container {
width: 500px;
height: 400px;
}
.search-con {
position: absolute;
right: 20px;
top: 64px;
width: 260px;
ul {
width: 260px;
height: 400px;
overflow: scroll;
li {
padding: 5px;
p:nth-child(2) {
color: #999;
font-size: 12px;
}
&:hover {
background-color: #eee;
cursor: pointer;
}
}
}
}
.address {
margin-bottom: 10px;
font-weight: bold;
}
</style>

View File

@@ -0,0 +1,186 @@
<template>
<div>
<Cascader
:data="data"
:load-data="loadData"
v-model="addr"
@on-change="change"
style="width: 300px"
></Cascader>
</div>
</template>
<script>
import {getRegion} from '@/api/common.js';
export default {
data () {
return {
data: [], // 地区数据
addr: [] // 已选数据
};
},
props: ['addressId'],
mounted () {},
methods: {
change (val, selectedData) {
/**
* @returns [regionId,region]
*/
this.$emit('selected', [
val,
selectedData[selectedData.length - 1].__label.split('/')
]);
},
loadData (item, callback) {
item.loading = true;
getRegion(item.value).then((res) => {
if (res.result.length <= 0) {
item.loading = false;
} else {
res.result.forEach((child) => {
item.loading = false;
let data = {
value: child.id,
label: child.name,
loading: false,
children: []
};
if (child.level === 'street' || item.label === '香港特别行政区') {
item.children.push({
value: child.id,
label: child.name
});
} else {
item.children.push(data);
}
});
callback();
}
});
},
async init () {
let data = await getRegion(0);
let arr = [];
data.result.forEach((item) => {
let obj;
// 台湾省做处理
if (item.name === '台湾省') {
obj = {
value: item.id,
label: item.name
};
} else {
obj = {
value: item.id,
label: item.name,
loading: false,
children: []
};
}
arr.push(obj);
});
this.data = arr;
console.warn('init');
},
async reviewData () {
// 数据回显
let addr = JSON.parse(JSON.stringify(this.addressId.split(',')));
let length = addr.length;
let data = await getRegion(0);
let arr0 = [];
let arr1 = [];
let arr2 = [];
// 第一级数据
data.result.forEach((item) => {
let obj;
// 台湾省做处理
if (item.name === '台湾省') {
obj = {
value: item.id,
label: item.name
};
} else {
obj = {
value: item.id,
label: item.name,
loading: false,
children: []
};
}
arr0.push(obj);
});
// 根据选择的数据来加载数据列表
if (length > 0) {
let children = await getRegion(addr[0]);
children = this.handleData(children.result);
arr0.forEach((e) => {
if (e.value === addr[0]) {
e.children = arr1 = children;
}
});
}
if (length > 1) {
let children = await getRegion(addr[1]);
children = this.handleData(children.result);
arr1.forEach((e) => {
if (e.value === addr[1]) {
e.children = arr2 = children;
}
});
}
if (length > 2) {
let children = await getRegion(addr[2]);
children = this.handleData(children.result);
arr2.forEach((e) => {
if (e.value === addr[2]) {
e.children = children;
}
});
}
this.data = arr0;
this.addr = addr;
},
handleData (data) {
// 处理接口数据
let item = [];
data.forEach((child) => {
let obj = {
value: child.id,
label: child.name,
loading: false,
children: []
};
if (child.level === 'street' || item.label === '香港特别行政区') {
item.push({
value: child.id,
label: child.name
});
} else {
item.push(obj);
}
});
return item;
}
},
watch: {
addressId: {
handler: function (v) {
console.log(v);
if (v) {
this.reviewData();
} else {
this.init();
}
},
immediate: true
},
addr (v) {
console.log(v);
}
}
};
</script>
<style scoped lang="scss">
</style>

View File

@@ -0,0 +1,708 @@
<template>
<div class="item-class-show">
<div class="head-bar">
<!-- 有商品分类展示商品分类 -->
<template v-if="$route.query.categoryId">
<!-- 头部展示筛选信息 -->
<div @click="cateClick(tabBar,1)">{{ tabBar.name }}</div>
<Icon type="ios-arrow-forward" />
<div class="bar" v-if="tabBar.first">
{{ tabBar.first.name }} <Icon type="ios-arrow-down" />
<ul>
<li v-for="item in tabBar.children" :key="item.id" @click="cateClick(item,2)">
{{ item.name }}
</li>
</ul>
</div>
<Icon type="ios-arrow-forward" v-if="tabBar.first" />
<div class="bar" v-if="tabBar.second">
{{ tabBar.second.name }} <Icon type="ios-arrow-down" />
<ul>
<li v-for="item in tabBar.first.children" :key="item.id" @click="cateClick(item,3)">
{{ item.name }}
</li>
</ul>
</div>
<Icon type="ios-arrow-forward" v-if="tabBar.second" />
</template>
<!-- 无商品分类展示搜索结果 -->
<template v-else>
<div style="font-size:14px">全部结果</div>
<Icon type="ios-arrow-forward" />
<div>{{params.keyword}}</div>
</template>
<!-- 所选分类 -->
<a
class="selected-item"
@click="cancelSelected(item, index)"
v-for="(item, index) in selectedItem"
:key="index"
:title="item.name"
>
<span>{{ item.type }}</span><span>{{ item.name }}</span
><Icon type="md-close" />
</a>
</div>
<!-- 筛选主体 -->
<div class="content">
<!-- 品牌 有图片独立出来 -->
<div class="brand" v-show="tagsContent[0].show && tagsContent[0].values.length">
<div>
<strong>{{ tagsContent[0].key }}</strong>
</div>
<div>
<ul :class="{ 'show-more': tagsContent[0].more }">
<li
@click="selectBrand(item.name, 0)"
:class="{ 'border-color': multSelected.includes(item) }"
v-for="(item, index) in tagsContent[0].values"
:key="index"
>
<img :src="item.url" alt="" /><span>{{ item.name }}</span>
<div
class="corner-icon"
v-show="multSelected.includes(item.name)"
>
<div></div>
<Icon type="md-checkmark" />
</div>
</li>
</ul>
<div class="btn" v-show="multiple !== 0">
<span @click="moreBrand(0)"
>{{ tagsContent[0].more ? "收起" : "更多"
}}<Icon
:type="tagsContent[0].more ? 'ios-arrow-up' : 'ios-arrow-down'"
/></span>
<span @click="multSelectBrand(0)"><Icon type="md-add" />多选</span>
</div>
<div class="multBtn" v-show="multiple === 0">
<Button
type="primary"
size="small"
:disabled="!multSelected.length"
@click="sure(0)"
>确定</Button
>
<Button size="small" @click="cancel">取消</Button>
</div>
</div>
</div>
<!-- 其他筛选项 -->
<template v-for="(tag, tagIndex) in tagsContent">
<div class="other" v-if="tag.show && tagIndex !== 0" :key="tagIndex">
<div>
<strong>{{ tag.key }}</strong>
</div>
<div>
<ul
:class="{ 'show-more': tag.more }"
class="list"
v-show="multiple !== tagIndex"
>
<li
@click="selectBrand(item, tagIndex)"
class="item"
v-for="(item, index) in tag.values"
:key="index"
>
{{ item }}
</li>
</ul>
<CheckboxGroup
:class="{ 'show-more': tag.more }"
class="list"
v-model="multSelected"
v-show="multiple === tagIndex"
>
<Checkbox
class="item"
:label="item"
v-for="(item, index) in tag.values"
:key="index"
>{{ item }}</Checkbox
>
</CheckboxGroup>
<div class="btn" v-show="multiple !== tagIndex">
<span @click="moreBrand(tagIndex)" v-show="tag.values.length > 9"
>{{ tag.more ? "收起" : "更多"
}}<Icon :type="tag.more ? 'ios-arrow-up' : 'ios-arrow-down'"
/></span>
<span @click="multSelectBrand(tagIndex)"
><Icon type="md-add" />多选</span
>
</div>
<div class="multBtn" v-show="multiple === tagIndex">
<Button
type="primary"
size="small"
:disabled="!multSelected.length"
@click="sure(tagIndex)"
>确定</Button
>
<Button size="small" @click="cancel">取消</Button>
</div>
</div>
</div>
</template>
</div>
</div>
</template>
<script>
import * as APIGoods from '@/api/goods';
export default {
name: 'GoodsClassNav',
data () {
return {
tabBar: { // 分类数据
name: '',
first: {},
second: {}
},
multiple: false, // 多选
tagsContent: [
// 标签
{
key: '品牌',
more: false,
show: true,
values: []
}
],
multSelected: [], // 多选分类
selectedItem: [], // 已选分类集合 顶部展示
brandIds: [], // 品牌id合集
params: {}, // 请求参数
cateList: [] // 全部商品分类
};
},
watch: {
selectedItem: {
// 监听已选条件,来调用列表接口
handler (val) {
let classification = [];
if (val.length) {
val.forEach((item) => {
if (item.type === '品牌') {
this.params.brandId = this.brandIds.join('@');
} else {
const nameArr = item.name.split('、');
nameArr.forEach((name) => {
classification.push(item.type + '_' + name);
});
}
});
this.params.prop = classification.join('@');
} else {
this.params.prop = ''
this.params.brandId = ''
}
this.getFilterList(this.params);
this.$emit('getParams', this.params);
},
deep: true
},
'$route': {
handler (val, oVal) {
if (this.$route.query.categoryId) {
let cateId = this.$route.query.categoryId.split(',')
Object.assign(this.params, this.$route.query)
this.params.categoryId = cateId[cateId.length - 1]
} else {
Object.assign(this.params, this.$route.query)
}
this.getFilterList(this.params)
this.getNav()
},
deep: true
}
},
methods: {
getNav () { // 获取商品分类,分类下展示
if (!this.$route.query.categoryId) return
this.cateList = JSON.parse(localStorage.getItem('category'))
const arr = this.$route.query.categoryId.split(',')
if (arr.length > 0) {
this.tabBar = this.cateList.filter(e => {
return e.id === arr[0]
})[0]
}
if (arr.length > 1) {
const first = this.tabBar.children.filter(e => {
return e.id === arr[1]
})[0]
this.$set(this.tabBar, 'first', first)
}
if (arr.length > 2) {
const second = this.tabBar.first.children.filter(e => {
return e.id === arr[2]
})[0]
this.$set(this.tabBar, 'second', second)
}
},
cateClick (item, index) {
switch (index) {
case 1:
this.$router.push({
path: '/goodsList',
query: {categoryId: item.id}
})
break;
case 2:
this.$router.push({
path: '/goodsList',
query: {categoryId: [item.parentId, item.id].toString()}
})
break;
case 3:
this.$router.push({
path: '/goodsList',
query: {categoryId: [this.tabBar.id, item.parentId, item.id].toString()}
})
break;
}
},
selectBrand (item, index) {
// 选择筛选项
if (this.multiple !== false) {
// 非多选直接在顶部栏展示,多选则添加选择状态
let key = this.multSelected.indexOf(item);
if (key > -1) {
this.multSelected.splice(key, 1);
} else {
this.multSelected.push(item);
}
} else {
this.selectedItem.push({
type: this.tagsContent[index].key,
name: item
});
this.tagsContent[index].show = false;
if (index === 0) {
// 如果是品牌获取品牌id
let brands = this.tagsContent[0].values;
brands.forEach((val) => {
if (val.name === item) this.brandIds.push(val.value);
console.log(this.brandIds);
});
}
}
},
cancelSelected (item, index) {
// 顶部栏 取消已选中的项
this.selectedItem.splice(index, 1);
this.tagsContent.forEach((tag, index) => {
if (tag.key === item.type) {
tag.show = true;
tag.more = false;
}
});
if (item.type === '品牌') {
this.brandIds = [];
}
},
moreBrand (index) {
// 更多按钮
const flag = !this.tagsContent[index].more
this.$set(this.tagsContent[index], 'more', flag)
},
multSelectBrand (index) {
// 多选按钮
this.$set(this.tagsContent[index], 'more', true)
this.multiple = index;
},
sure (index) {
// 多选确认按钮
this.selectedItem.push({
type: this.tagsContent[index].key,
name: this.multSelected.join('、')
});
if (index === 0) {
// 如果是品牌获取品牌id
let brands = this.tagsContent[0].values;
brands.forEach((val) => {
if (this.multSelected.includes(val.name)) this.brandIds.push(val.value);
});
}
this.tagsContent[index].show = false;
this.cancel();
},
cancel () {
// 多选取消按钮
this.multSelected = [];
this.tagsContent[0].more = false;
this.multiple = false;
},
getFilterList (params) {
// 筛选、分类 列表
APIGoods.filterList(params).then((res) => {
if (res.code === 200) {
const data = res.result;
this.tagsContent = [{
key: '品牌',
more: false,
show: true,
values: []
}]
this.tagsContent[0].values = data.brands;
this.tagsContent = this.tagsContent.concat(data.paramOptions);
this.tagsContent.forEach((item) => {
this.$set(item, 'show', true)
this.$set(item, 'more', false)
});
}
});
}
},
mounted () {
if (this.$route.query.categoryId) {
let cateId = this.$route.query.categoryId.split(',')
Object.assign(this.params, this.$route.query)
this.params.categoryId = cateId[cateId.length - 1]
} else {
Object.assign(this.params, this.$route.query)
}
this.getFilterList(this.params);
this.getNav();
}
}
</script>
<style scoped lang="scss">
/** 头部展示筛选项 */
.head-bar {
width: 100%;
background: #fff;
margin-top: -13px;
display: flex;
height: 40px;
align-items: center;
> div:first-child {
padding: 0 8px;
font-size: 18px;
font-weight: bold;
&:hover {
color: $theme_color;
cursor: pointer;
}
}
.bar {
font-size: 12px;
position: relative;
background: #fff;
border: 1px solid #999;
padding: 0 8px;
width: 85px;
text-align: center;
margin: 0 3px;
&:hover {
color: $theme_color;
border-color: $theme_color;
border-bottom-color: #fff;
cursor: pointer;
ul {
display: block;
}
.ivu-icon {
transform: rotate(180deg);
}
}
ul {
display: none;
position: absolute;
top: 18px;
left: -1px;
width: 300px;
padding: 5px 10px;
background: #fff;
border: 1px solid $theme_color;
z-index: 1;
&::before {
content: "";
position: absolute;
width: 83px;
left: 0;
top: -1px;
z-index: 2;
border-top: 1px solid #fff;
}
&:hover {
display: block;
}
clear: left;
li {
color: #999;
float: left;
width: 30%;
margin: 3px 0;
text-align: left;
&:hover {
color: $theme_color;
cursor: pointer;
}
}
}
}
//所选分类
.selected-item {
font-size: 12px;
color: #000;
padding: 2px 22px 2px 8px;
margin-right: 5px;
max-width: 250px;
height: 24px;
overflow: hidden;
position: relative;
background-color: #f3f3f3;
border: 1px solid #ddd;
&:hover {
border-color: $theme_color;
background-color: #fff;
.ivu-icon {
color: #fff;
background-color: $theme_color;
}
}
span:nth-child(2) {
color: $theme_color;
}
.ivu-icon {
position: absolute;
right: 0;
top: 0;
color: $theme_color;
line-height: 22px;
width: 21px;
height: 22px;
font-size: 14px;
}
}
}
/** 筛选主体 */
.content {
background: #fff;
border-top: 1px solid #999;
border-bottom: 1px solid #999;
margin: 10px 0;
}
/** 品牌 start */
.brand {
border-bottom: 1px solid #ddd;
display: flex;
// min-height: 120px;
font-size: 12px;
> div:first-child {
width: 100px;
background: #eee;
padding: 10px 0 0 10px;
}
> div:last-child {
width: 1100px;
padding: 10px;
position: relative;
ul {
width: 900px;
max-height: 100px;
overflow: hidden;
padding-top: 1px;
clear: left;
li {
width: 100px;
height: 50px;
float: left;
line-height: 50px;
border: 1px solid #ddd;
margin: -1px -1px 0 0;
overflow: hidden;
position: relative;
padding: 2px;
img {
width: 100%;
height: 100%;
}
&:hover {
border-color: $theme_color;
top: 0;
left: 0;
position: relative;
z-index: 1;
img {
display: none;
}
}
span {
display: inline-block;
width: 100%;
height: 100%;
color: $theme_color;
text-align: center;
font-size: 12px;
cursor: pointer;
}
.corner-icon {
position: absolute;
right: -1px;
bottom: -1px;
div {
width: 0;
border-top: 20px solid transparent;
border-right: 20px solid $theme_color;
}
.ivu-icon {
font-size: 12px;
position: absolute;
bottom: 0;
right: 1px;
transform: rotate(-15deg);
color: #fff;
}
}
}
.border-color {
border-color: $theme_color;
z-index: 1;
}
}
.show-more {
height: auto;
max-height: 200px;
overflow: scroll;
}
.btn {
position: absolute;
right: 10px;
top: 10px;
span {
border: 1px solid #ddd;
margin-left: 10px;
color: #999;
display: inline-block;
padding: 1px 3px;
font-size: 12px;
&:hover {
cursor: pointer;
color: $theme_color;
border-color: $theme_color;
}
}
}
.multBtn {
text-align: center;
margin-top: 10px;
.ivu-btn {
font-size: 12px !important;
}
.ivu-btn:last-child {
margin-left: 10px;
}
}
}
}
/** 品牌 end */
/** 其他筛选项 start */
.other {
border-bottom: 1px solid #ddd;
display: flex;
min-height: 30px;
font-size: 12px;
&:last-child {
border: none;
}
> div:first-child {
width: 100px;
background: #eee;
padding: 10px 0 0 10px;
}
> div:last-child {
width: 1100px;
padding: 0 10px;
position: relative;
.list {
width: 900px;
height: 30px;
overflow: hidden;
clear: left;
.item {
width: 100px;
height: 30px;
float: left;
line-height: 30px;
color: $primary_color;
overflow: hidden;
position: relative;
font-size: 12px;
padding: 2px;
cursor: pointer;
&:hover {
color: $theme_color;
}
}
}
.show-more {
height: auto;
}
.btn {
position: absolute;
right: 10px;
top: 5px;
span {
border: 1px solid #ddd;
margin-left: 10px;
color: #999;
display: inline-block;
padding: 1px 3px;
font-size: 12px;
&:hover {
cursor: pointer;
color: $theme_color;
border-color: $theme_color;
}
}
}
.multBtn {
text-align: center;
margin-top: 10px;
margin-bottom: 10px;
.ivu-btn {
font-size: 12px !important;
}
.ivu-btn:last-child {
margin-left: 10px;
}
}
}
}
/** 其他筛选项 end */
</style>

View File

@@ -0,0 +1,285 @@
<template>
<div class="cate-nav">
<div class="nav-con">
<div class="all-categories hover-pointer" @mouseenter="showFirstList = true" @mouseleave="showFirstList = false">全部商品分类</div>
<ul class="nav-item" v-if="showNavBar">
<li
class="hover-color"
v-for="(item, index) in navList.list"
:key="index"
@click="linkTo(item.url)"
>
{{ item.name }}
</li>
</ul>
</div>
<!-- 侧边导航 -->
<div class="cate-list" v-show="showAlways || showFirstList" @mouseenter="showFirstList = true" @mouseleave="showFirstList = false">
<div class="nav-side">
<ul>
<li v-for="(item, index) in cateList" :key="index" @mouseenter="showDetail(index)" @mouseleave="panel = false">
<span class="nav-side-item" @click="goGoodsList(item.id)">{{item.name}}</span>
<span v-for="(second, secIndex) in item.children" :key="secIndex">
<span v-if="secIndex < 2" > / </span>
<span @click="goGoodsList(second.id, second.parentId)" class="nav-side-item" v-if="secIndex < 2">{{second.name}}</span>
</span>
</li>
</ul>
</div>
<transition name="fade">
<div
class="detail-item-panel"
:duration="{ enter: 100, leave: 100 }"
v-show="panel"
@mouseenter="panel = true"
ref="itemPanel1"
@mouseleave="panel = false"
>
<div class="nav-detail-item">
<template v-for="(item, index) in panelData">
<span @click="goGoodsList(item.id, item.parentId)" v-if="index < 8" :key="index">{{ item.name }}<Icon type="ios-arrow-forward" /></span>
</template>
</div>
<ul>
<li
v-for="(items, index) in panelData"
:key="index"
class="detail-item-row"
>
<span class="detail-item-title" @click="goGoodsList(items.id,items.parentId)">
{{ items.name }} <Icon type="ios-arrow-forward" />
<span class="glyphicon glyphicon-menu-right"></span>
</span>
<div>
<span v-for="(item, subIndex) in items.children" @click="goGoodsList(item.id,items.id,items.parentId)"
:key="subIndex" class="detail-item">{{ item.name }}</span>
</div>
</li>
</ul>
</div>
</transition>
</div>
</div>
</template>
<script>
import { getCategory } from '@/api/goods';
import storage from '@/plugins/storage.js'
export default {
name: 'GoodsListNav',
props: {
showAlways: { // 总是显示下拉分类
default: false,
type: Boolean
},
showNavBar: { // 显示全部商品分类右侧导航条
default: true,
type: Boolean
}
},
data () {
return {
cateList: [], // 分类数据
panel: false, // 二级分类展示
panelData: [], // 二级分类数据
showFirstList: false // 始终展示一级列表
}
},
computed: {
navList () {
return JSON.parse(storage.getItem('navList')) || []
}
},
methods: {
getCate () {
getCategory(0).then(res => {
if (res.success) {
this.cateList = res.result;
localStorage.setItem('category', JSON.stringify(res.result))
}
});
},
showDetail (index) {
this.panel = true
this.panelData = this.cateList[index].children
},
goGoodsList (id, secondId, firstId) { // 分类共有三级,传全部分类过去
const arr = [firstId, secondId, id]
if (!arr[1]) {
arr.splice(0, 2)
}
if (!arr[0]) {
arr.shift()
}
let routerUrl = this.$router.resolve({
path: '/goodsList',
query: {categoryId: arr.toString()}
})
window.open(routerUrl.href, '_blank')
}
},
mounted () {
if (localStorage.getItem('category')) {
this.cateList = JSON.parse(localStorage.getItem('category'))
} else {
this.getCate()
}
}
};
</script>
<style scoped lang="scss">
.cate-nav{
width: 1200px;
position: relative;
margin: 0 auto;
}
/** 商品分类 */
.nav-con {
width: 1200px;
height: 40px;
// background: #eee;
margin: 0 auto;
display: flex;
.all-categories {
width: 200px;
line-height: 40px;
color: #fff;
background-color: $theme_color;
text-align: center;
font-size: 16px;
}
.nav-item {
width: 1000px;
height: 40px;
line-height: 40px;
overflow: hidden;
list-style: none;
background-color: #eee;
display: flex;
li {
font-size: 16px;
font-weight: bold;
margin-left: 20px;
color: rgb(89, 88, 88);
font-size: 15px;
&:hover {
color: $theme_color;
}
}
}
}
.cate-list{
margin: 0 auto;
position: absolute;
z-index: 1000;
}
.nav-item li {
float: left;
font-size: 16px;
font-weight: bold;
margin-left: 30px;
}
.nav-item a {
text-decoration: none;
color: #555555;
}
.nav-item a:hover {
color: $theme_color;
}
.nav-side {
width: 200px;
float: left;
padding: 0px;
color: #fff;
background-color: #6e6568;
height: 335px;
overflow: hidden;
}
.nav-side ul {
width: 100%;
padding: 0px;
padding-top: 5px;
list-style: none;
}
.nav-side li {
padding: 7.5px 0;
padding-left: 12px;
font-size: 13px;
line-height: 18px;
}
.nav-side li:hover {
background: #999395;
}
.nav-side-item:hover {
cursor: pointer;
color: $theme_color;
}
/*显示商品详细信息*/
.detail-item-panel {
width: 815px;
min-height: 340px;
background-color: #fff;
box-shadow: 0px 0px 15px #ccc;
position: absolute;
top: 0;
left: 200px;
z-index: 1000;
padding: 15px;
}
.nav-detail-item {
margin-top: 5px;
margin-bottom: 15px;
cursor: pointer;
color: #eee;
}
.nav-detail-item span {
padding: 6px;
padding-left: 12px;
margin-right: 15px;
font-size: 12px;
background-color: #6e6568;
}
.nav-detail-item span:hover {
background-color: $theme_color;
}
.detail-item-panel ul {
list-style: none;
}
.detail-item-panel li {
line-height: 30px;
// margin-left: 40px;
}
.detail-item-title {
font-weight: bold;
font-size: 12px;
cursor: pointer;
color: #555555;
padding-right: 10px;
width: 81px;
text-align: right;
}
.detail-item-title:hover {
color: $theme_color;
}
.detail-item-row {
display: flex;
>div{flex: 1;}
}
.detail-item {
font-size: 12px;
padding-left: 8px;
padding-right: 8px;
cursor: pointer;
border-left: 1px solid #ccc;
&:first-child{
border: none;
padding-left: 0;
}
}
.detail-item:hover {
color: $theme_color;
}
</style>

View File

@@ -0,0 +1,14 @@
### 滑动拼图验证
### 在页面中引入 .vue文件
#### 参数
#### 在组件上添加v-if来判断组件显隐
#### verifyType 验证格式[ 'LOGIN' ,'REGISTER' ]等,详情看接口文档
#### @change方法 获取回调,参数为对象 {status:false,distance:100} status 为回调状态distance为移动距离
#### <Verify class="verify-content" verifyType='LOGIN' @change="verifyChange"></Verify>

View File

@@ -0,0 +1,185 @@
<template>
<div class="verify-content" v-if="show" @mousemove="mouseMove" @mouseup="mouseUp">
<div class="imgBox" :style="{width:data.originalWidth+'px',height:data.originalHeight + 'px'}">
<img :src="data.backImage" style="width:100%;height:100%" alt="">
<img class="slider" :src="data.slidingImage" :style="{left:distance+'px',top:data.randomY+'px'}" :width="data.sliderWidth" :height="data.sliderHeight" alt="">
<Icon type="md-refresh" class="refresh" @click="refresh" />
</div>
<div class="handle" :style="{width:data.originalWidth+'px'}">
<span class="bgcolor" :style="{width:distance + 'px',background:bgColor}"></span>
<span class="swiper" :style="{left:distance + 'px'}" @mousedown="mouseDown">
<Icon type="md-arrow-round-forward" />
</span>
<span class="text">{{verifyText}}</span>
</div>
</div>
</template>
<script>
import { getVerifyImg, postVerifyImg } from './verify.js';
export default {
props: {
verifyType: {
defalut: 'LOGIN',
type: String
}
},
data () {
return {
show: false, // 验证码显隐
type: 'LOGIN', // 请求类型
data: { // 验证码数据
backImage: '',
slidingImage: '',
originalHeight: 150,
originalWidth: 300,
sliderWidth: 60,
sliderHeight: 60
},
distance: 0, // 拼图移动距离
flag: false, // 判断滑块是否按下
downX: 0, // 鼠标按下位置
bgColor: 'aqua', // 滑动背景颜色
verifyText: '拖动滑块解锁' // 文字提示
};
},
methods: {
mouseDown (e) {
this.downX = e.clientX;
this.flag = true;
},
mouseMove (e) {
if (this.flag) {
let offset = e.clientX - this.downX;
if (offset > this.data.originalWidth - 43) {
this.distance = this.data.originalWidth - 43;
} else if (offset < 0) {
this.distance = 0;
} else {
this.distance = offset;
}
}
},
mouseUp () {
if (!this.flag) return false;
this.flag = false;
let params = {
verificationEnums: this.type,
xPos: this.distance
};
postVerifyImg(params).then(res => {
if (res.result) {
this.bgColor = 'green';
this.verifyText = '解锁成功';
this.$emit('change', { status: true, distance: this.distance });
} else {
this.bgColor = 'red';
this.verifyText = '解锁失败';
let that = this;
setTimeout(() => {
that.refresh();
}, 1000);
this.$emit('change', { status: false, distance: this.distance });
}
});
},
refresh () {
this.flag = false;
this.downX = 0;
this.distance = 0;
this.bgColor = 'aqua';
this.verifyText = '拖动滑块解锁';
this.getImg();
},
getImg () {
getVerifyImg(this.type).then(res => {
this.data = res.result;
});
}
},
created () {
this.getImg();
},
watch: {
verifyType: {
immediate: true,
handler: function (v) {
this.type = v;
this.refresh();
}
},
show (v) {
if (v) this.refresh();
}
}
};
</script>
<style lang="scss" scoped>
.verify-content{
padding: 10px;
background: #fff;
border: 1px solid #eee;
border-radius: 5px;
box-shadow: 1px 1px 3px #999;
}
.imgBox {
width: 300px;
height: 150px;
position: relative;
overflow: hidden;
.slider {
position: absolute;
cursor: pointer;
}
.refresh {
position: absolute;
right: 5px;
top: 5px;
font-size: 20px;
color: #fff;
cursor: pointer;
}
}
.handle {
border: 1px solid rgb(134, 134, 134);
margin-top: 5px;
height: 42px;
background: #ddd;
position: relative;
.bgcolor {
position: absolute;
top: 0;
left: 0;
width: 40px;
height: 40px;
opacity: 0.5;
background: aqua;
}
.swiper {
position: absolute;
width: 40px;
height: 40px;
background-color: #fff;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
.ivu-icon {
font-size: 20px;
}
}
.text {
display: inline-block;
width: inherit;
text-align: center;
line-height: 42px;
font-size: 14px;
user-select: none;
}
}
</style>

View File

@@ -0,0 +1,32 @@
import request, {Method, commonUrl} from '@/plugins/request.js';
import storage from '@/plugins/storage.js';
/**
* 获取拼图验证
*/
export function getVerifyImg (verificationEnums) {
return request({
url: `${commonUrl}/common/slider/${verificationEnums}`,
method: Method.GET,
needToken: false,
headers: {uuid: storage.getItem('uuid')}
});
}
/**
* 验证码校验
*/
export function postVerifyImg (params) {
return request({
url: `${commonUrl}/common/slider/${params.verificationEnums}`,
method: Method.POST,
needToken: false,
params,
headers: {uuid: storage.getItem('uuid')}
});
}
export function mouseup () {
console.log(111);
}