初始上传

This commit is contained in:
2026-04-04 17:27:12 +08:00
parent 4d80d28eb4
commit b7e11774ee
11191 changed files with 1588469 additions and 0 deletions

View File

@@ -0,0 +1,213 @@
<template>
<div class="ns-brand">
<el-carousel height="400px" v-loading="loadingAd">
<el-carousel-item v-for="item in adList" :key="item.adv_id">
<el-image :src="$img(item.adv_image)" fit="cover" @click="$util.pushToTab(item.adv_url.url)" />
</el-carousel-item>
</el-carousel>
<!-- 品牌列表 -->
<div class="ns-brand-box" v-loading="loading">
<div>
<div class="ns-brand-title-wrap ns-text-align">
<p class="ns-brand-title">品牌专区</p>
<img src="@/assets/images/goods/split.png" alt="" />
<p class="ns-brand-en">Brand zone</p>
</div>
<div class="ns-brand-list" v-if="brandList.length > 0">
<div class="ns-brand-li" v-for="(item, index) in brandList" :key="index" @click="$router.push({ path: '/goods/list', query: { brand_id: item.brand_id } })">
<div class="ns-brand-wrap">
<el-image fit="scale-down" :src="$img(item.image_url)" lazy @error="imageError(index)" />
<p :title="item.brand_name">{{ item.brand_name }}</p>
</div>
</div>
</div>
<div class="empty-wrap" v-if="brandList.length <= 0">
<div class="ns-text-align">暂无更多品牌,去首页看看吧</div>
</div>
<div class="pager">
<el-pagination
background
:pager-count="5"
:total="total"
prev-text="上一页"
next-text="下一页"
:current-page.sync="currentPage"
:page-size.sync="pageSize"
@size-change="handlePageSizeChange"
@current-change="handleCurrentPageChange"
hide-on-single-page
></el-pagination>
</div>
</div>
</div>
</div>
</template>
<script>
import {brandPage} from '@/api/goods/goods';
import {mapGetters} from 'vuex';
import {adList} from '@/api/website';
export default {
name: 'brand',
components: {},
data: () => {
return {
total: 0,
currentPage: 1,
pageSize: 20,
brandList: [],
siteId: 0,
loading: true,
loadingAd: true,
adList: []
};
},
created() {
this.getAdList();
this.getBrandList();
},
computed: {
...mapGetters(['defaultBrandImage', 'siteInfo'])
},
methods: {
handlePageSizeChange(size) {
this.pageSize = size;
this.refresh();
},
handleCurrentPageChange(page) {
this.currentPage = page;
this.refresh();
},
refresh() {
this.loading = true;
this.getBrandList();
},
getBrandList() {
brandPage({
page_size: this.pageSize,
page: this.currentPage,
site_id: this.siteId
}).then(res => {
this.brandList = res.data.list;
this.total = res.data.count;
this.loading = false;
window.document.title = `品牌专区 - ${this.siteInfo.site_name}`;
}).catch(err => {
this.loading = false;
this.$message.error(err.message);
});
},
/**
* 图片加载失败
*/
imageError(index) {
this.brandList[index].image_url = this.defaultBrandImage;
},
getAdList() {
adList({keyword: 'NS_PC_BRAND'}).then(res => {
this.adList = res.data.adv_list;
for (let i = 0; i < this.adList.length; i++) {
if (this.adList[i].adv_url) this.adList[i].adv_url = JSON.parse(this.adList[i].adv_url);
}
this.loadingAd = false;
}).catch(err => {
this.loadingAd = false;
});
}
}
};
</script>
<style lang="scss" scoped>
.ns-text-align {
text-align: center;
}
.ns-brand-box {
width: 100%;
background: #ffffff;
> div {
width: $width;
margin: 0 auto;
}
}
.ns-brand-title-wrap {
padding-top: 54px;
.ns-brand-title {
font-size: 26px;
font-weight: 600;
line-height: 30px;
}
.ns-brand-en {
font-size: 24px;
font-weight: 600;
color: #383838;
opacity: 0.2;
text-transform: uppercase;
letter-spacing: 5px;
line-height: 30px;
}
}
.ns-brand-list {
display: flex;
flex-wrap: wrap;
padding-top: 30px;
.ns-brand-li {
width: 20%;
padding: 8px 6px;
box-sizing: border-box;
.ns-brand-wrap {
width: 100%;
border: 1px solid #f1f1f1;
overflow: hidden;
color: #303133;
padding: 15px;
box-sizing: border-box;
cursor: pointer;
text-align: center;
.el-image {
width: 100%;
height: 120px;
line-height: 120px;
}
p {
font-size: 22px;
color: #383838;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}
.empty-wrap {
margin-top: 30px;
}
</style>
<style lang="scss">
.ns-brand {
.el-carousel {
.el-image__inner {
width: auto;
}
}
.el-carousel__arrow--right {
right: 60px;
}
}
</style>

View File

@@ -0,0 +1,133 @@
<template>
<div class="cart" v-loading="loading">
<template v-if="cartList.length || invalidGoods.length">
<nav>
<li>
<el-checkbox v-model="checkAll" @change="allElection"></el-checkbox>
</li>
<li>商品信息</li>
<li>价格</li>
<li>数量</li>
<li>小计</li>
<li>操作</li>
</nav>
<div class="list" v-for="(siteItem, siteIndex) in cartList" :key="siteIndex">
<div class="item">
<!-- <div class="head">
<el-checkbox v-model="siteItem.checked" @change="siteAllElection(siteIndex)"></el-checkbox>
<router-link to="/shop" target="_blank">{{ siteItem.siteName }}</router-link>
<el-tag size="small" v-if="siteItem.cartList[0].is_own == 1">自营</el-tag>
</div> -->
<ul v-for="(item, cartIndex) in siteItem.cartList" :key="cartIndex">
<li>
<el-checkbox v-model="item.checked" @change="singleElection(siteIndex, cartIndex)"></el-checkbox>
</li>
<li class="goods-info-wrap" @click="$util.pushToTab({ path: '/sku/' + item.sku_id })">
<div class="img-wrap">
<img class="img-thumbnail" :src="$img(item.sku_image, { size: 'mid' })" @error="imageError(siteIndex, cartIndex)" />
</div>
<div class="info-wrap">
<h5>{{ item.sku_name }}</h5>
<template v-if="item.sku_spec_format">
<span v-for="(x, i) in item.sku_spec_format" :key="i">
{{ x.spec_name }}{{ x.spec_value_name }} {{ i < item.sku_spec_format.length - 1 ? '' : '' }}
</span>
</template>
</div>
</li>
<li>
<span>{{ item.discount_price }}</span>
</li>
<li>
<el-input-number v-model="item.num" :step="modifyNum" size="mini" :min="item.min_buy>0 ? item.min_buy :1"
:max="item.max_buy > 0 && item.max_buy < item.stock ? item.max_buy : item.stock"
@change="cartNumChange($event, { siteIndex, cartIndex })"/>
</li>
<li>
<strong class="subtotal ns-text-color" v-if="item.discount_price * item.num">{{ $util.filterPrice(item.discount_price * item.num) }}</strong>
<strong class="subtotal ns-text-color" v-else>0</strong>
</li>
<li>
<el-button type="text" @click="deleteCart(siteIndex, cartIndex)">删除</el-button>
</li>
</ul>
</div>
</div>
<div class="lose-list" v-if="invalidGoods.length">
<div class="head">
失效商品
<span class="ns-text-color">{{ invalidGoods.length }}</span>
</div>
<ul v-for="(goodsItem, goodsIndex) in invalidGoods" :key="goodsIndex">
<li>
<el-tag size="small" type="info">失效</el-tag>
</li>
<li class="goods-info-wrap">
<div class="img-wrap">
<img class="img-thumbnail" :src="$img(goodsItem.sku_image, { size: 'mid' })" @error="imageErrorInvalid(goodsIndex)" />
</div>
<div class="info-wrap">
<h5>{{ goodsItem.sku_name }}</h5>
<template v-if="goodsItem.sku_spec_format">
<span v-for="(x, i) in goodsItem.sku_spec_format" :key="i">
{{ x.spec_name }}{{ x.spec_value_name }}{{ i < goodsItem.sku_spec_format.length - 1 ? '' : '' }}
</span>
</template>
</div>
</li>
<li>
<span>{{ goodsItem.discount_price }}</span>
</li>
<li>{{ goodsItem.num }}</li>
<li>
<strong class="subtotal">{{ $util.filterPrice(goodsItem.discount_price * goodsItem.num) }}</strong>
</li>
</ul>
</div>
<footer>
<el-checkbox v-model="checkAll" @change="allElection">全选</el-checkbox>
<ul class="operation">
<li>
<el-button type="text" @click="deleteCartSelected">删除</el-button>
</li>
<li>
<el-button type="text" @click="clearInvalidGoods" v-if="invalidGoods.length!=0">清除失效宝贝</el-button>
</li>
</ul>
<div class="sum-wrap">
<div class="selected-sum">
<span>已选商品</span>
<em class="total-count">{{ totalCount }}</em>
<span></span>
</div>
<div class="price-wrap">
<span>合计不含运费</span>
<strong class="ns-text-color">{{ totalPrice }}</strong>
</div>
<el-button type="primary" v-if="totalCount != 0" @click="settlement">结算</el-button>
<el-button type="info" v-else disabled @click="settlement">结算</el-button>
</div>
</footer>
</template>
<div class="empty-wrap" v-else-if="!loading && (!cartList.length || !invalidGoods.length)">
<img src="~assets/images/goods_empty.png">
<router-link to="/">您的购物车是空的赶快去逛逛挑选商品吧</router-link>
</div>
</div>
</template>
<script>
import cart from '@/assets/js/goods/cart';
export default {
name: 'cart',
mixins: [cart]
};
</script>
<style lang="scss" scoped>
@import '@/assets/css/goods/cart.scss';
</style>

View File

@@ -0,0 +1,226 @@
<template>
<div>
<div class="newCategory" v-loading="loading">
<div class="categoryLink">
<ul id="categoryUl" :class="categoryFixed == true ? 'category-fixed' : ''">
<li v-for="(item, index) in goodsCategory" :key="index" :class="index == clickIndex ? 'selected' : ''" @click="changeCate(index, '#category' + index)">
<a>
<span>{{ item.category_name }}</span>
</a>
</li>
</ul>
</div>
<div class="categoryCon">
<div :id="'category' + index" :ref="'category' + index" class="items" :class="'items-' + index" v-for="(cate1, index) in goodsCategory" :key="index">
<h2>
<router-link :to="{ path: '/goods/list', query: { category_id: cate1.category_id, level: cate1.level } }" target="_blank">{{ cate1.category_name }}</router-link>
</h2>
<dl v-for="(cate2, index) in cate1.child_list" :key="index">
<dt>
<router-link :to="{ path: '/goods/list', query: { category_id: cate2.category_id, level: cate2.level } }" target="_blank">{{ cate2.category_name }}</router-link>
</dt>
<dd>
<router-link v-for="(cate3, index) in cate2.child_list" :key="index" :to="{ path: '/goods/list', query: { category_id: cate3.category_id, level: cate3.level } }" target="_blank">{{ cate3.category_name }}</router-link>
</dd>
</dl>
</div>
</div>
<div class="empty-wrap" v-if="goodsCategory.length <= 0">
<div class="ns-text-align">暂无商品分类</div>
</div>
</div>
</div>
</template>
<script>
import {tree} from '@/api/goods/goodscategory';
export default {
name: 'category',
components: {},
data: () => {
return {
goodsCategory: [],
categoryFixed: false,
clickIndex: 0,
loading: true
};
},
created() {
this.getGoodsCategory();
},
mounted() {
window.addEventListener('scroll', this.handleScroll);
},
methods: {
// 分类列表
getGoodsCategory() {
tree({
level: 3,
template: 2
}).then(res => {
if (res.code == 0) {
this.goodsCategory = res.data;
}
this.loading = false;
}).catch(err => {
this.$message.error(err.message);
this.loading = false;
});
},
// 监听滚动条
handleScroll() {
var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
var offsetTop = document.querySelector('.newCategory').offsetTop;
if (scrollTop > offsetTop) {
this.categoryFixed = true;
} else {
this.categoryFixed = false;
}
var divTopArr = [];
for (let i = 0; i < this.goodsCategory.length; i++) {
var _top = this.$refs['category' + i][0].offsetTop;
divTopArr.push(_top);
var _offset = scrollTop - offsetTop;
if (_offset < divTopArr[divTopArr.length - 1]) {
if (_offset >= divTopArr[i] && _offset < divTopArr[i + 1]) {
this.clickIndex = i;
}
} else {
this.clickIndex = divTopArr.length - 1;
}
}
},
// 点击左侧分类
changeCate(index, obj) {
this.clickIndex = index;
document.querySelector(obj).scrollIntoView(true);
}
},
destroyed() {
// 离开该页面需要移除这个监听的事件,不然会报错
window.removeEventListener('scroll', this.handleScroll);
}
};
</script>
<style lang="scss" scoped>
.newCategory {
width: $width;
margin: 0 auto;
overflow: hidden;
background-color: #fff;
.categoryLink {
padding-top: 10px;
float: left;
position: relative;
width: 210px;
ul {
width: 210px;
padding-top: 20px;
background-color: #ffffff;
li {
width: 200px;
height: 30px;
text-align: left;
background-color: #f5f5f5;
border-radius: 30px;
color: #333;
line-height: 30px;
overflow: hidden;
position: relative;
cursor: pointer;
margin: 0 auto 15px;
&.selected {
background-color: $base-color;
background: -moz-linear-gradient(45deg, $base-color 0%, #ffffff 100%);
background: -webkit-gradient(45deg, color-stop(0%, $base-color), color-stop(100%, #ffffff));
background: -webkit-linear-gradient(45deg, $base-color 0%, #ffffff 100%);
background: -o-linear-gradient(45deg, $base-color 0%, #ffffff 100%);
background: -ms-linear-gradient(45deg, $base-color 0%, #ffffff 100%);
background: linear-gradient(45deg, $base-color 0%, #ffffff 100%);
a {
color: #fff;
}
}
a {
display: block;
margin-left: 30px;
}
}
}
}
.category-fixed {
position: fixed;
top: 0;
z-index: 99;
}
.categoryCon {
float: left;
padding: 0px 0 60px;
overflow: hidden;
width: 990px;
position: relative;
.items {
padding-left: 40px;
h2 {
font-size: 18px;
font-weight: 600;
line-height: 40px;
margin-top: 30px;
border-bottom: 1px solid transparent;
}
dl {
padding: 15px 0 5px;
border-bottom: 1px solid #efefef;
overflow: hidden;
display: flex;
dt {
padding-right: 10px;
width: 100px;
position: relative;
background: #fff;
float: left;
a {
float: left;
max-width: 120px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
font-weight: 600;
}
}
dd {
a {
color: #666;
float: left;
padding: 0 12px;
margin: 0 0 10px -1px;
border-left: 1px solid #e0e0e0;
white-space: nowrap;
}
}
}
}
}
}
</style>

View File

@@ -0,0 +1,518 @@
<template>
<div class="ns-coupon">
<div class="ns-coupon-info" v-if="adList.length">
<div class="ns-coupon-wrap">
<div class="coupon-name">
<span class="ns-text-color">优惠券中心</span>
<span class="ns-text-color-gray text12">省钱更多领券更多</span>
</div>
<ul class="coupon-type clear-float">
<li>
<i></i>
<span>限时抢券</span>
</li>
<li>
<i></i>
<span>叠加使用</span>
</li>
<li>
<i></i>
<span>种类多样</span>
</li>
</ul>
<el-button @click="myCoupon">我的优惠券</el-button>
</div>
<div class="ns-coupon-img" v-loading="loadingAd">
<el-carousel height="406px">
<el-carousel-item v-for="item in adList" :key="item.adv_id">
<el-image :src="$img(item.adv_image)" fit="cover" @click="$util.pushToTab(item.adv_url.url)" />
</el-carousel-item>
</el-carousel>
</div>
</div>
<el-tabs>
<div v-loading="loading">
<ul class="ns-coupon-list">
<li class="ns-bg-color ns-coupon-li" v-for="(item, index) in couponList" :key="index" :class="item.useState == 2 ? 'no-coupon' : '' ">
<div class="describe">
<template>
<span v-if="!item.discount || item.discount == '0.00'">{{ item.money }}</span>
<span v-else>{{ item.discount }}</span>
</template>
<span>{{ activeName == 'first' ? item.coupon_name : item.platformcoupon_name }}</span>
<span v-if="activeName == 'first'">
{{item.goods_type_name}}
</span>
<template>
<span v-if="item.at_least == '0.00'">无门槛优惠券</span>
<span v-else>{{ item.at_least }}可使用</span>
</template>
<template>
<span class="coupon-wrap-time" v-if="item.validity_type == 0">领取之日起{{ item.fixed_term }}日内有效</span>
<span class="coupon-wrap-time" v-else-if="item.validity_type == 1">有效期至{{ $timeStampTurnTime(item.end_time) }}</span>
<span class="coupon-wrap-time" v-else>长期有效</span>
</template>
</div>
<div class="receive">
<!-- 如果限领数为0 或者 领取数小于最大领取数 -->
<a v-if="item.useState == 0" class="ns-text-color" @click="couponTap(item, index)">
<span>立即领取</span>
</a>
<a v-if="item.useState == 1" class="ns-text-color" @click="couponTap(item, index)">
<span>去使用</span>
</a>
<a v-if="!item.received_type && item.useState == 2" class="ns-text-color">
<span>已抢光</span>
</a>
<a v-if="item.received_type == 'out'" class="ns-text-color">
<span>已抢光</span>
</a>
<a v-if="item.received_type == 'expire'" class="ns-text-color">
<span>已过期</span>
</a>
<a v-if="item.received_type == 'limit'" class="ns-text-color">
<span>已达上限</span>
</a>
</div>
</li>
</ul>
<div class="empty-wrap" v-if="couponList.length <= 0">
<div class="ns-text-align">暂无优惠券</div>
</div>
<div class="pager">
<el-pagination background :pager-count="5" :total="total" prev-text="上一页" next-text="下一页"
:current-page.sync="currentPage" :page-size.sync="pageSize" @size-change="handlePageSizeChange"
@current-change="handleCurrentPageChange" hide-on-single-page></el-pagination>
</div>
</div>
</el-tabs>
</div>
</template>
<script>
import {
couponTypeList,
couponReceive
} from '@/api/coupon';
import {
mapGetters
} from 'vuex';
import {
adList
} from '@/api/website';
export default {
name: 'coupon',
components: {},
data: () => {
return {
couponList: [],
total: 0,
currentPage: 1,
pageSize: 9,
couponBtnSwitch: false,
activeName: 'first',
loading: true,
loadingAd: true,
adList: []
};
},
created() {
if (this.addonIsExit && this.addonIsExit.coupon != 1) {
this.$message({
message: '优惠券插件未安装',
type: 'warning',
duration: 2000,
onClose: () => {
this.$route.push('/');
}
});
} else {
this.getAdList();
this.getCanReceiveCouponQuery();
}
},
computed: {
...mapGetters(['addonIsExit'])
},
watch: {
addonIsExit() {
if (this.addonIsExit.coupon != 1) {
this.$message({
message: '优惠券插件未安装',
type: 'warning',
duration: 2000,
onClose: () => {
this.$route.push('/');
}
});
}
}
},
head() {
return {
title: '领券专区-' + this.$store.state.site.siteInfo.site_name,
meta: [{
name: 'description',
content: this.$store.state.site.siteInfo.seo_description
}, {
name: 'keyword',
content: this.$store.state.site.siteInfo.seo_keywords
}]
}
},
methods: {
getAdList() {
adList({
keyword: 'NS_PC_COUPON'
}).then(res => {
this.adList = res.data.adv_list;
for (let i = 0; i < this.adList.length; i++) {
if (this.adList[i].adv_url) this.adList[i].adv_url = JSON.parse(this.adList[i].adv_url);
}
this.loadingAd = false;
}).catch(err => {
this.loadingAd = false;
});
},
handleClick(tab, event) {
this.loading = true;
// (this.currentPage = 1), this.getCanReceiveCouponQuery();
},
/**
* 我的优惠券
*/
myCoupon() {
this.$util.pushToTab('/member/coupon');
},
/**
* 获取优惠券列表
*/
getCanReceiveCouponQuery() {
couponTypeList({
page: this.currentPage,
page_size: this.pageSize,
activeName: this.activeName
}).then(res => {
this.couponList = res.data.list;
this.total = res.data.count;
this.couponList.forEach(v => {
if (v.count == v.lead_count) v.useState = 2;
else if (v.max_fetch != 0 && v.member_coupon_num && v.member_coupon_num >= v.max_fetch) v.useState = 1;
else v.useState = 0;
if(v.received_type && v.received_type == 'expire'){
v.useState = 2;
}
});
this.loading = false;
}).catch(err => {
this.loading = false;
this.$message.error(err.message);
});
},
handlePageSizeChange(size) {
this.pageSize = size;
this.loading = true;
this.getCanReceiveCouponQuery();
},
handleCurrentPageChange(page) {
this.currentPage = page;
this.loading = true;
this.getCanReceiveCouponQuery();
},
/**
* 点击优惠券
*/
couponTap(item, index) {
if (item.useState == 0) this.receiveCoupon(item, index);
else this.toGoodsList(item);
},
/**
* 领取优惠券
*/
receiveCoupon(item, index) {
if (this.couponBtnSwitch) return;
this.couponBtnSwitch = true;
var data = {
site_id: item.site_id,
activeName: this.activeName
};
data.coupon_type_id = item.coupon_type_id;
couponReceive(data).then(res => {
var data = res.data;
let msg = res.message;
if (res.code == 0) {
msg = '领取成功';
this.$message({
message: msg,
type: 'success'
});
} else {
this.$message({
message: msg,
type: 'warning'
});
}
let list = this.couponList;
if (res.data.is_exist == 1) {
for (let i = 0; i < list.length; i++) {
if (this.activeName == 'first') {
if (list[i].coupon_type_id == item.coupon_type_id) {
list[i].useState = 1;
}
} else {
if (list[i].platformcoupon_type_id == item.platformcoupon_type_id) {
list[i].useState = 1;
}
}
}
} else {
for (let i = 0; i < list.length; i++) {
if (this.activeName == 'first') {
if (list[i].coupon_type_id == item.coupon_type_id) {
list[i].received_type = res.data.type;
list[i].useState = 2;
}
} else {
if (list[i].platformcoupon_type_id == item.platformcoupon_type_id) {
list[i].useState = 2;
}
}
}
}
this.couponBtnSwitch = false;
this.$forceUpdate();
}).catch(err => {
if (err.message == '您尚未登录,请先进行登录') {
this.$router.push('/auth/login');
} else {
this.$message.error(err.message)
}
this.couponBtnSwitch = false;
});
},
/**
* 去购买
*/
toGoodsList(item) {
if (this.activeName == 'first') {
if (item.goods_type != 1) {
this.$router.push({
path: '/goods/list',
query: {
coupon: item.coupon_type_id
}
});
} else {
this.$router.push({
path: '/goods/list',
});
}
} else {
this.$router.push('/goods/list');
}
}
}
};
</script>
<style lang="scss" scoped>
.empty-wrap {
margin-top: 20px;
}
.ns-coupon {
width: $width;
padding: 20px 0;
margin: 0 auto;
box-sizing: border-box;
}
.ns-coupon-info {
background: url(../../assets/images/coupon-bg.png) no-repeat;
background-size: cover;
width: 100%;
height: 450px;
display: flex;
.ns-coupon-wrap {
width: 320px;
padding: 20px;
box-sizing: border-box;
text-align: center;
.coupon-name {
margin: 45px 0 50px;
span:nth-child(1) {
display: block;
line-height: 45px;
font-size: 30px;
}
.ns-text-color-gray {
color: #898989 !important;
}
.text12 {
font-size: 12px;
}
}
.coupon-type {
margin-left: 20px;
li {
float: left;
width: 80px;
height: 100px;
i {
display: block;
width: 50px;
height: 50px;
margin: 8px auto;
}
&:nth-child(1) i {
background: url(../../assets/images/limited_time.png) no-repeat center;
}
&:nth-child(2) i {
background: url(../../assets/images/superposition.png) no-repeat center;
}
&:nth-child(3) i {
background: url(../../assets/images/coupon_type.png) no-repeat center;
}
}
}
.el-button {
width: 200px;
background-color: $base-color;
color: #fff;
margin-top: 70px;
font-size: 18px;
}
}
.ns-coupon-img {
width: 850px;
padding: 20px;
box-sizing: border-box;
img {
width: 100%;
height: 100%;
}
.el-carousel__item:nth-child(2n) {
background-color: #99a9bf;
}
.el-carousel__item:nth-child(2n + 1) {
background-color: #d3dce6;
}
}
}
.el-tabs {
margin-top: 20px;
}
.ns-coupon-list {
display: flex;
flex-wrap: wrap;
padding: 0 20px;
.ns-coupon-li {
background: url(../../assets/images/list_bj.png) no-repeat;
width: 32%;
height: 169px;
margin-bottom: 20px;
margin-right: 2%;
background-size: cover;
&.no-coupon {
background: url(../../assets/images/no_coupon.png) no-repeat !important;
background-color: #e6e6e6 !important;
.describe {
color: #999 !important;
}
.receive {
.ns-text-color {
color: #999 !important;
}
}
}
.describe {
float: left;
width: 250px;
height: inherit;
text-align: center;
color: #fff;
span {
display: block;
}
span:nth-child(1) {
font-size: 40px;
margin-top: 20px;
margin-bottom: 3px;
line-height: 50px;
}
span:nth-child(3),
span:nth-child(4),
span:nth-child(5) {
font-size: 12px;
margin-left: 15px;
line-height: 20px;
}
}
.receive {
float: right;
width: 95px;
height: inherit;
text-align: center;
a {
display: inline-block;
width: 30px;
height: 120px;
line-height: 120px;
padding: 0 5px;
margin-top: 25px;
background-color: #fff;
border-radius: 15px;
cursor: pointer;
box-sizing: border-box;
span {
display: inline-block;
line-height: 20px;
vertical-align: middle;
}
}
}
&:nth-child(3n) {
margin-right: 0;
}
}
}
</style>

View File

@@ -0,0 +1,704 @@
<template>
<div class="goods-container">
<div class="goods-list" v-loading="loading">
<!-- 搜索关键字 -->
<div class="goods-nav" v-if="keyword">
<router-link to="/">首页</router-link>
<span>/</span>
<span class="keyword">{{ keyword }}</span>
</div>
<div class="goods-nav" v-else-if="catewords">
<router-link to="/">首页</router-link>
<span>/</span>
<router-link :to="{ path: '/goods/list', query: $util.handleLink({ category_id: first_index, level: 1, brand_id: filters.brand_id }) }">{{ catewords.split('$_SPLIT_$')[0] }}</router-link>
<span v-if="(filters.category_level == 2 || filters.category_level == 3) && catewords.split('$_SPLIT_$')[1]">/</span>
<span v-if="(filters.category_level == 2 || filters.category_level == 3) && catewords.split('$_SPLIT_$')[1]" class="keyword">{{ catewords.split('$_SPLIT_$')[1] }}</span></div>
<!-- 品牌过滤记录区 -->
<div class="attr_filter" v-if="choosedBrand">
<el-tag type="info" closable @close="closeBrand" effect="plain">
<span v-if="choosedBrand" class="title">品牌</span>
{{ choosedBrand.brand_name }}
</el-tag>
</div>
<div class="goods-screen-wrap">
<div v-if="!keyword" class="goods-screen-item classify-info">
<span class="screen-item-name">分类</span>
<ul class="screen-item-content">
<li :class="{ active: categoryAll.isAllow && (categoryAll.id == 0 || categoryAll.id == filters.category_id) }">
<router-link :to="{ path: '/goods/list', query: $util.handleLink({ category_id: categoryAll.id, level: categoryAll.level, brand_id: filters.brand_id }) }">全部</router-link>
</li>
<li v-for="item in categoryList" :class="{ active: item.category_id == selectCategoryId }">
<router-link :to="{ path: '/goods/list', query: $util.handleLink({ category_id: item.category_id, level: item.level, brand_id: filters.brand_id }) }">{{ item.category_name }}</router-link>
</li>
</ul>
</div>
<!-- 品牌 -->
<div class="brand" v-if="brandList.length > 0">
<div class="table_head">品牌</div>
<div class="table_body" :class="{ 'more' : isShowMoreBrand }">
<!-- <div class="initial">
<span type="info" effect="plain" hit @mouseover="handleChangeInitial('')">所有品牌</span>
<span type="info" effect="plain" hit v-for="item in brandInitialList" :key="item" @mouseover="handleChangeInitial(item)">{{ (item || '').toUpperCase() }}</span>
</div> -->
<el-card v-for="item in brandList" :key="item.id" body-style="padding: 0;height: 100%;" shadow="hover" v-show="currentInitial === '' || item.brand_initial === currentInitial" class="brand-item">
<el-image :src="$img(item.image_url || defaultGoodsImage)" :alt="item.brand_name" :title="item.brand_name" fit="contain" @click="onChooseBrand(item)" />
</el-card>
</div>
<div class="more-wrap" v-if="brandList.length>14" @click="isShowMoreBrand=!isShowMoreBrand">
{{ isShowMoreBrand ? '收起' : '更多' }}
</div>
</div>
<div class="goods-screen-item other-screen-info">
<span class="screen-item-name">筛选</span>
<div class="screen-item-content">
<div class="item" @click="changeSort('')">
<div class="item-name">综合</div>
</div>
<div :class="['item', 'search-arrow', salesArrowDirection]" @click="changeSort('sale_num')">销量</div>
<div :class="['item', 'search-arrow', priceArrowDirection]" @click="changeSort('discount_price')">价格</div>
<div class="item-other">
<el-checkbox label="包邮" v-model="is_free_shipping"></el-checkbox>
</div>
<div class="input-wrap">
<div class="price_range">
<el-input placeholder="最低价格" v-model="filters.min_price"></el-input>
<span></span>
<el-input placeholder="最高价格" v-model="filters.max_price"></el-input>
</div>
<el-button plain size="mini" @click="handlePriceRange">确定</el-button>
</div>
</div>
</div>
</div>
<div class="list-wrap">
<!-- <div class="goods-recommended" v-if="goodsList.length">
<goods-recommend :page-size="goodsList.length < 5 ? 2 : 5" />
</div> -->
<div class="list-right">
<!-- 排序筛选区 -->
<div class="cargo-list" v-if="goodsList.length">
<div class="goods-info">
<div class="item" v-for="(item, index) in goodsList" :key="item.goods_id" @click="$router.push({ path: '/sku/' + item.sku_id })">
<img class="img-wrap" :src="$img(item.goods_image, { size: 'mid' })" @error="item.goods_image = defaultGoodsImage" />
<div class="price-wrap">
<div class="price">
<span></span>
<span>{{ showPrice(item) }}</span>
<div class="price-icon-wrap">
<img v-if="item.member_price && item.member_price == showPrice(item)" :src="$img('public/uniapp/index/VIP.png')" />
<img v-else-if="item.promotion_type == 1" :src="$img('public/uniapp/index/discount.png')" />
</div>
</div>
<div v-if="parseInt(item.market_price)" class="market-price">{{ item.market_price }}</div>
</div>
<div class="goods-name">{{ item.goods_name }}</div>
<div class="other-info">
<span class="sale-num">{{ item.sale_num || 0 }}人付款</span>
<div class="saling">
<div v-if="item.is_free_shipping == 1" class="free-shipping">包邮</div>
<div v-if="item.promotion_type == 1" class="free-shipping">限时折扣</div>
</div>
</div>
</div>
</div>
<div class="pager">
<el-pagination background :pager-count="5" :total="total" prev-text="上一页" next-text="下一页"
:current-page.sync="currentPage" :page-size.sync="pageSize"
@size-change="handlePageSizeChange"
@current-change="handleCurrentPageChange" hide-on-single-page></el-pagination>
</div>
</div>
<div class="empty" v-else-if="!loading">
<img src="~assets/images/goods_empty.png" />
<span>没有找到您想要的商品换个条件试试吧</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import BreadCrumbs from '@/components/BreadCrumbs';
import GoodsRecommend from '@/components/GoodsRecommend';
import list from '@/assets/js/goods/list';
export default {
name: 'list',
components: {
BreadCrumbs,
GoodsRecommend
},
mixins: [list]
};
</script>
<style lang="scss" scoped>
.goods-container {
width: 100%;
background-color: #f9f9f9;
}
.goods-list {
width: $width;
margin: 0 auto;
}
%flex-center {
display: flex;
align-items: center;
}
.padd-10 {
padding: 0 10px;
}
.goods-nav {
padding: 15px 0 0 0 !important;
span,
.nuxt-link-active {
color: #666;
}
.keyword {
color: $base-color;
}
}
.goods-screen-wrap {
margin-top: 20px;
background-color: #fff;
.goods-screen-item {
display: flex;
align-items: center;
padding: 0 20px;
box-sizing: border-box;
.screen-item-name {
width: 42px;
margin-right: 35px;
font-size: 14px;
color: #999;
}
.screen-item-content {
flex: 1;
display: flex;
align-items: center;
height: 100%;
border-bottom: 1px dashed #ebeff3;
padding: 10px 0;
flex-wrap: wrap;
}
&:last-of-type .screen-item-content {
border-bottom: none;
}
}
.classify-info {
.screen-item-content > li {
padding-right: 30px;
a {
font-size: 14px;
color: #4a4a4a;
}
&:last-of-type {
padding-right: 0;
}
&.active a,
& a:hover {
color: $base-color;
}
}
}
.other-screen-info {
.screen-item-content > div {
cursor: pointer;
margin-right: 40px;
&:last-of-type {
margin-right: 0;
}
}
.input-wrap {
@extend %flex-center;
.price_range {
@extend %flex-center;
& > span {
overflow: hidden;
margin: 0 5px;
width: 10px;
}
.el-input__inner {
border: none;
width: 90px;
height: 28px;
background-color: #f3f5f7;
border-radius: 6px;
}
}
.el-button {
margin-left: 12px;
width: 56px;
height: 28px;
border-radius: 6px;
&.is-plain:focus,
&.is-plain:hover {
border-color: $base-color;
color: $base-color;
}
}
}
.search-arrow {
position: relative;
&::after,
&::before {
content: '';
position: absolute;
right: -12px;
border: 5px solid transparent;
}
&::after {
top: 1px;
border-bottom-color: #999;
}
&::before {
border-top-color: #999;
bottom: 2px;
}
&.arrow-down::before {
border-top-color: $base-color;
}
&.arrow-up::after {
border-bottom-color: $base-color;
}
}
.item-other {
.el-checkbox__inner {
&:hover {
border-color: $base-color;
}
}
.el-checkbox__input.is-checked .el-checkbox__inner,
.el-checkbox__input.is-indeterminate .el-checkbox__inner {
background-color: $base-color;
border-color: $base-color;
}
.el-checkbox__input.is-checked + .el-checkbox__label {
color: $base-color;
}
}
}
}
.search_bread {
display: inline-block;
font-size: 14px;
margin: 0px auto;
width: 100%;
padding: 10px;
p {
float: left;
}
li {
float: left;
padding: 0 10px;
}
.active a {
color: #ff547b !important;
}
}
.selected_border {
border: 1px solid $base-color;
}
.attr_filter {
margin-top: 10px;
.el-tag {
margin-right: 5px;
margin-bottom: 10px;
border-radius: 0;
.title {
color: $base-color;
font-size: 15px;
}
}
}
.category {
margin: 0 auto 10px auto;
border: 1px solid #eeeeee;
}
.brand {
border-bottom: 1px solid #eeeeee;
display: flex;
flex-direction: row;
padding: 10px 20px 10px;
&:last-child {
border-bottom: none;
}
.table_head {
color: #999;
margin-right: 15px;
width: 60px;
}
.table_body {
display: flex;
flex-direction: row;
flex-wrap: wrap;
flex: 1;
height: 105px;
overflow: hidden;
&.more {
height: 170px;
overflow-y: auto;
}
.initial {
margin: 5px auto 10px 10px;
span {
border: 0;
margin: 0;
padding: 5px 10px;
border-radius: 0;
&:hover {
background-color: $base-color;
color: #ffffff;
}
}
}
.brand-item {
margin-right: 10px;
margin-bottom: 10px;
}
.el-card {
width: 125px;
height: 45px;
&:hover {
border: 1px solid $base-color;
cursor: pointer;
}
}
span {
margin: auto 25px;
}
}
.table_op {
margin-top: 5px;
margin-right: 5px;
}
.more-wrap {
cursor: pointer;
margin-left: 15px;
}
.el-image {
width: 100%;
height: 100%;
}
}
.list-wrap {
overflow: hidden;
}
.goods-recommended {
width: 200px;
background-color: #fff;
float: left;
margin-right: 10px;
}
.sort {
display: flex;
align-items: center;
.item {
display: flex;
align-items: center;
padding: 5px 15px;
border: 1px solid #f1f1f1;
border-left: none;
cursor: pointer;
&:hover {
background: $base-color;
color: #fff;
}
}
.item-other {
display: flex;
align-items: center;
padding: 5px 15px;
border: 1px solid #f1f1f1;
border-left: none;
cursor: pointer;
}
.input-wrap {
display: flex;
align-items: center;
.price_range {
margin-left: 60px;
}
span {
padding-left: 10px;
}
.el-input {
width: 150px;
margin-left: 10px;
}
.el-button {
margin: 0 17px;
}
}
> div:first-child {
border-left: 1px solid #f1f1f1;
}
}
.cargo-list {
padding-bottom: 40px;
}
.goods-info {
margin-top: 20px;
display: flex;
flex-wrap: wrap;
.item {
width: 228px;
margin: 0 17px 18px 0;
padding: 18px;
position: relative;
background-color: #fff;
box-sizing: border-box;
&:nth-child(5n + 5) {
margin-right: 0;
}
.img-wrap {
width: 192px;
height: 192px;
cursor: pointer;
}
.goods-name {
margin-top: 5px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
word-break: break-all;
cursor: pointer;
line-height: 1.4;
&:hover {
color: $base-color;
}
}
.other-info {
margin-top: 12px;
display: flex;
align-items: center;
justify-content: space-between;
}
.price-wrap {
margin-top: 10px;
display: flex;
align-items: center;
.price {
display: flex;
align-items: center;
color: $base-color;
& > span {
font-weight: bold;
line-height: 1;
}
span:nth-child(1) {
font-size: 12px;
}
span:nth-child(2) {
font-size: 16px;
}
}
.market-price {
color: #838383;
text-decoration: line-through;
margin-left: 10px;
line-height: 1;
}
}
.sale-num {
display: flex;
color: #999999;
font-size: $ns-font-size-sm;
p {
color: #4759a8;
}
}
.shop_name {
padding: 0 10px;
display: flex;
color: #838383;
}
.saling {
display: flex;
font-size: $ns-font-size-sm;
line-height: 1;
.free-shipping {
background: $base-color;
color: #ffffff;
padding: 3px 4px;
border-radius: 2px;
margin-right: 5px;
}
.promotion-type {
color: $base-color;
border: 1px solid $base-color;
display: flex;
align-items: center;
padding: 1px 3px;
}
}
.item-bottom {
display: flex;
margin-top: 5px;
.collection {
flex: 1;
border: 1px solid #e9e9e9;
border-right: none;
border-left: none;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.cart {
flex: 2;
border: 1px solid #e9e9e9;
border-right: none;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
}
}
}
.price-icon-wrap {
display: inline-block;
max-width: 35px;
margin-left: 3px;
line-height: 1;
padding-bottom: 3px;
img {
max-width: 100%;
}
}
.empty {
padding: 50px 0 60px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
img {
width: 400px;
height: 244px;
}
span {
font-size: 14px;
color: #4a4a4a;
}
}
.pager {
text-align: center;
margin-top: 30px;
}
.el-pagination.is-background .el-pager li:not(.disabled).active {
background-color: $base-color;
}
.el-pagination.is-background .el-pager li:not(.disabled):hover {
color: $base-color;
}
</style>