初始上传

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,93 @@
<template>
<div class="footer-bottom">
<div class="site-info">
<p v-if="siteInfo.web_phone"><i class="iconfont icondianhua"></i>{{ siteInfo.web_phone }}</p>
<p v-if="siteInfo.web_email">
<i class="iconfont iconyouxiang"></i>
<el-link :href="`mailto:${siteInfo.web_email}`">{{ siteInfo.web_email }}</el-link>
</p>
</div>
<p>
{{ copyRight.copyright_desc }}
<a v-if="copyRight.icp" class="footer-link" href="https://beian.miit.gov.cn" target="_blank">备案号{{ copyRight.icp }}</a>
</p>
<p>
<a v-if="copyRight.gov_record" class="footer-link" :href="copyRight.gov_url" target="_blank">
<img src="@/assets/images/gov_record.png" alt="公安备案" />
<span>{{ copyRight.gov_record }}</span>
</a>
<a v-if="copyRight.business_show_link" class="footer-link" :href="copyRight.business_show_link" target="_blank">
<img :src="$img('public/static/img/business_show.png')" alt="营业执照" />
<span>电子营业执照</span>
</a>
</p>
</div>
</template>
<script>
import { copyRight } from "@/api/website"
import { mapGetters } from "vuex"
export default {
props: {},
data() {
return {}
},
created() {
this.$store.dispatch("site/copyRight")
},
mounted() {},
watch: {},
methods: {},
computed: {
...mapGetters(["copyRight", "siteInfo"])
}
}
</script>
<style scoped lang="scss">
.footer-bottom {
width: 100%;
margin: 0 auto;
padding: 30px 0;
p {
margin: 0;
width: 100%;
box-sizing: border-box;
text-align: center;
img {
width: 20px;
height: 20px;
margin-right: 5px;
}
.footer-link, .el-link.el-link--default {
color: #444;
margin-left: 15px;
display: inline-flex;
align-items: center;
line-height: 22px;
}
.footer-link:hover, .el-link.el-link--default:hover {
color: $base-color;
}
.footer-link:first-child{
margin-left: 0;
}
}
.site-info {
display: flex;
justify-content: center;
align-items: center;
p {
width: auto;
margin: 0 10px;
i {
vertical-align: bottom;
margin-right: 5px;
}
}
}
}
</style>

View File

@@ -0,0 +1,121 @@
<template>
<div class="header">
<ns-header-top />
<ns-header-mid />
</div>
</template>
<script>
import NsHeaderTop from "./NsHeaderTop.vue"
import NsHeaderMid from "./NsHeaderMid.vue"
export default {
components: {
NsHeaderTop,
NsHeaderMid
},
created() {
this.$store.dispatch("cart/cart_count")
}
}
</script>
<style scoped lang="scss">
.header {
width: 100%;
background-color: #fff;
padding: 0;
}
.header-in {
width: $width;
height: 109px;
margin: 20px auto 0;
img {
margin: 22px 120px auto 0;
float: left;
}
.in-sousuo {
width: 550px;
float: left;
margin: 10px 0 0 0;
.sousuo-tag {
display: block;
height: 24px;
span {
cursor: pointer;
font-size: 12px;
padding: 0 10px;
border-right: solid 1px #e1e1e1;
&:last-child {
border-right: none;
}
}
.span-font {
color: $base-color;
}
}
.sousuo-box {
width: 100%;
height: 36px;
border: 2px solid $base-color;
box-sizing: border-box;
input {
width: 400px;
height: 22px;
background: none;
outline: none;
border: none;
float: left;
margin: 4px;
}
.box-btn {
width: 80px;
height: 100%;
background-color: $base-color;
color: #fff;
float: right;
text-align: center;
line-height: 32px;
cursor: pointer;
}
}
.sousuo-key {
width: 100%;
height: 20px;
margin-top: 5px;
font-size: 12px;
span {
float: left;
}
ul {
margin: 0;
padding: 0;
float: left;
color: $ns-text-color-black;
li {
cursor: pointer;
list-style: none;
float: left;
margin-right: 10px;
color: $ns-text-color-black;
}
}
}
}
.car {
float: left;
width: 91px;
height: 36px;
margin-top: 34px;
margin-left: 30px;
padding: 0 28px 0 19px;
border: 1px solid #dfdfdf;
color: $base-color;
font-size: 12px;
span {
cursor: pointer;
line-height: 38px;
margin-right: 10px;
}
}
}
</style>

View File

@@ -0,0 +1,382 @@
<template>
<aside class="main-sidebar clearfix">
<div class="main-sidebar-body">
<ul>
<li @click="$router.push('/goods/cart')">
<div class="li-item">
<img src="~/assets/images/index/index_card.png" />
<span>购物车</span>
<em v-show="cartCount">{{ cartCount }}</em>
</div>
</li>
<li class="mobile">
<div class="mobile-qrcode-wrap">
<div class="mobile-qrcode" v-if="qrcode">
<img :src="$img(qrcode)" />
</div>
</div>
<div class="li-item">
<img src="~/assets/images/index/index_code.png" />
<span>手机购买</span>
</div>
</li>
<li class="kefuTip" v-if="serviceConfig.type != 'none'">
<div class="li-item" @click="showServiceFn()">
<img src="~/assets/images/index/index_service.png" />
<span>联系客服</span>
</div>
</li>
<li @click="$router.push('/member')">
<div class="li-item">
<img src="~/assets/images/index/index_member.png" />
<span>会员中心</span>
</div>
</li>
</ul>
<div :class="['back-top',{ showBtn: visible }]" @click="toTop">
<img src="~/assets/images/index/index_top.png">
<span>回到顶部</span>
</div>
</div>
<div class="main-sidebar-right">
<div id="mainSidebarHistoryProduct" class="history-product"></div>
</div>
<!--联系客服弹窗-->
<servicerMessage ref="servicer" class="kefu" :shop="{shop_id:0,logo:siteInfo.logo,shop_name:'平台客服'}">
</servicerMessage>
</aside>
</template>
<script>
import servicerMessage from '@/components/message/servicerMessage.vue'
import {
mapGetters
} from "vuex"
import {
shopServiceOpen
} from "@/api/website.js"
export default {
props: {},
data() {
return {
visible: false,
hackReset: false,
serviceConfig: {
type: 'nome'
},
}
},
components: {
servicerMessage
},
computed: {
...mapGetters(["wapQrcode", "cartCount", "siteInfo", 'member']),
qrcode: function() {
return this.wapQrcode === "" ? "" : this.wapQrcode.path.h5.img
},
logined: function() {
return this.member !== undefined && this.member !== "" && this.member !== {}
}
},
created() {
this.$store.dispatch("site/qrCodes");
this.shopServiceOpen();
},
mounted() {
window.addEventListener("scroll", this.handleScroll)
},
beforeDestroy() {
window.removeEventListener("scroll", this.handleScroll)
},
watch: {},
methods: {
handleScroll() {
this.visible = window.pageYOffset > 300
},
shopServiceOpen() {
shopServiceOpen().then((res) => {
if (res && res.code == 0) {
this.serviceConfig = res.data.pc;
}
})
},
toTop() {
let timer = setInterval(function() {
let osTop = document.documentElement.scrollTop || document.body.scrollTop
let ispeed = Math.floor(-osTop / 5)
document.documentElement.scrollTop = document.body.scrollTop = osTop + ispeed
this.isTop = true
if (osTop === 0) {
clearInterval(timer)
}
}, 20)
},
// 打开客服弹窗
showServiceFn() {
if (this.logined) {
switch (this.serviceConfig.type) {
case 'third':
window.open(this.serviceConfig.third_url, "_blank");
break;
case 'niushop':
this.hackReset = true;
this.$refs.servicer.show()
break;
}
} else {
this.$message({
message: "您还未登录",
type: "warning"
})
}
}
},
}
</script>
<style scoped lang="scss">
// 公共代码部分
%flex-center {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
%li-temp {
cursor: pointer;
img {
width: 23px;
height: 23px;
}
span {
margin-top: 9px;
color: #000;
line-height: 1;
font-size: 12px;
}
}
%arrows {
&::after {
content: "";
position: absolute;
right: 0px;
top: 50%;
transform: translate(-8px, -50%) rotate(45deg);
height: 10px;
width: 10px;
background-color: #ff4649;
}
}
// 具体代码
.main-sidebar {
position: fixed;
top: 50%;
transform: translateY(-50%);
right: 148px;
z-index: 400;
.main-sidebar-body {
ul {
width: 88px;
background-color: #fff;
box-shadow: 0px 2px 12px 0px rgba(102, 128, 153, 0.16);
border-radius: 8px;
padding: 2px 0;
li {
.li-item {
@extend %flex-center;
position: relative;
height: 85px;
text-align: center;
@extend %li-temp;
em {
position: absolute;
top: 10px;
right: 19px;
min-width: 17px;
height: 15px;
line-height: 15px;
display: inline-block;
padding: 0 2px;
color: #ffffff;
font-size: 10px;
font-style: normal;
text-align: center;
border-radius: 8px;
background-color: $base-color;
}
&::after {
content: "";
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 0;
width: 60px;
height: 1px;
background: #ECECEC;
}
}
&:last-of-type>.li-item::after {
background-color: transparent;
}
&.kefuTip {
position: relative;
}
&.mobile {
position: relative;
.mobile-qrcode-wrap {
display: none;
position: absolute;
left: -160px;
top: -28px;
}
.mobile-qrcode {
position: relative;
margin-right: 10px;
width: 150px;
height: 150px;
padding: 10px;
background-color: #fff;
border: 8px;
box-sizing: border-box;
box-shadow: 0px 2px 12px 0px rgba(102, 128, 153, 0.16);
@extend %arrows;
&::after {
right: -13px;
background-color: #fff;
box-shadow: 0px 2px 12px 0px rgba(102, 128, 153, 0.16);
}
}
&:hover .mobile-qrcode-wrap {
display: block;
img {
width: 100%;
height: 100%;
}
}
}
}
}
a,
.cart,
.el-button {
width: 40px;
height: 40px;
line-height: 40px;
display: block;
margin-bottom: 10px;
color: #ffffff;
text-align: center;
-webkit-transition: background-color 0.3s;
transition: background-color 0.3s;
padding: 0;
border: none;
background: transparent;
&:hover {
background-color: $base-color;
}
}
.back-top {
@extend %flex-center;
display: none;
margin-top: 10px;
width: 88px;
height: 88px;
background-color: #fff;
box-shadow: 0px 2px 12px 0px rgba(102, 128, 153, 0.16);
border-radius: 8px;
@extend %li-temp;
}
.showBtn {
display: flex;
opacity: 1;
cursor: pointer;
}
i {
font-size: 16px;
}
}
}
@media screen and (max-width: 1750px) {
.main-sidebar {
right: 100px;
}
}
@media screen and (max-width: 1620px) {
.main-sidebar {
right: 10px;
}
}
.kefuTip .tip {
display: none;
}
.kefuTip:hover .tip {
display: block;
position: absolute;
right: 85px;
top: -20px;
.tip_item {
border-top-left-radius: 118px;
border-top-right-radius: 118px;
margin-right: 13px;
width: 100px;
background: #FF4649;
color: #fff;
padding-bottom: 1px;
@extend %arrows;
}
.kefu_logo {
width: 78px;
margin: 0 auto 10px;
border-radius: 50%;
img {
margin-top: 14px;
background: linear-gradient(to top right, #e4e4e4, #FFF);
border-radius: 50%;
width: 100%;
height: 78px
}
}
.text {
padding: 0 !important;
background: #fff;
margin: 0 10px 10px;
color: #FF4649;
border-radius: 3px;
text-align: center;
line-height: 30px;
}
}
</style>

View File

@@ -0,0 +1,324 @@
<template>
<div class="footer">
<el-tabs v-model="activeName" class="friendly-link" v-if="linkList.length > 0">
<el-tab-pane label="友情链接" name="first">
<div class="link-item" v-for="(link_item, link_index) in linkList" :key="link_index"
:title="link_item.link_title" @click="linkUrl(link_item.link_url, link_item.is_blank)">
<img :src="$img(link_item.link_pic)" />
</div>
</el-tab-pane>
</el-tabs>
<div class="footer-top" v-if="shopServiceList.length > 0">
<ul class="service">
<li v-for="(item, index) in shopServiceList" :key="index">
<div class="item-head">
<img :src="$img(item.icon.imageUrl)" alt="" v-if="item.icon.iconType == 'img'">
<span v-else :class="item.icon.icon"></span>
</div>
<div class="item-content">
<p class="name">{{ item.service_name }}</p>
<p class="desc">{{ item.desc }}</p>
</div>
</li>
</ul>
</div>
<div class="footer-bot">
<copy-right />
</div>
</div>
</template>
<script>
import {
copyRight,
shopServiceLists,
friendlyLink,
weQrcode,
} from "@/api/website"
import CopyRight from "./CopyRight"
import {
mapGetters
} from "vuex"
import {
helpList
} from "@/api/cms/help"
export default {
props: {},
data() {
return {
shopServiceList: [],
linkList: [],
helpList: [],
ishide: false,
activeName: "first",
qrcode: "",
}
},
computed: {},
created() {
this.getShopServiceLists();
this.link();
this.getHelpList();
this.getqrcodeimg();
},
mounted() {},
watch: {},
methods: {
getqrcodeimg() {
weQrcode({}).then(res => {
if (res.code == 0 && res.data) {
this.qrcode = res.data
}
})
.catch(err => {
this.$message.error(err.message)
})
},
getShopServiceLists() {
shopServiceLists({}).then(res => {
if (res.code == 0 && res.data) {
this.shopServiceList = res.data
}
})
.catch(err => {
this.shopServiceList = []
})
},
link() {
friendlyLink({})
.then(res => {
if (res.code == 0 && res.data) {
this.linkList = res.data
}
})
.catch(err => {
this.$message.error(err.message)
})
},
linkUrl(url, target) {
if (!url) return
if (url.indexOf("http") == -1 && url.indexOf("https") == -1) {
if (target) this.$util.pushToTab({
path: url
})
else this.$router.push({
path: url
})
} else {
if (target) window.open(url)
else window.location.href = url
}
},
/**
* 获取帮助列表
*/
getHelpList() {
helpList()
.then(res => {
if (res.code == 0 && res.data) {
var arr = [];
arr = res.data.slice(0, 4)
for (let i = 0; i < arr.length; i++) {
arr[i].child_list = arr[i].child_list.slice(0, 4);
}
this.helpList = arr
}
})
.catch(err => {})
},
/**
* 跳转到帮助列表
*/
clickToHelp(id) {
this.$router.push("/cms/help/listother-" + id)
},
/**
* 跳转到帮助详情
*/
clickToHelpDetail(id) {
this.$router.push("/cms/help-" + id)
},
/**
* 跳转到帮助详情
*/
clickJump(address) {
location.href = address;
}
},
components: {
CopyRight
}
}
</script>
<style scoped lang="scss">
.footer {
.footer-top {
background-color: #f2f2f2;
border-bottom: 1px solid #e2e2e2;
.service {
width: $width;
margin: 0 auto;
padding: 20px 0 40px;
box-sizing: border-box;
border-bottom: 1px solid #F5F5F5;
display: flex;
flex-wrap: wrap;
align-items: center;
li {
margin-top: 30px;
display: flex;
align-items: center;
width: 25%;
list-style: none;
padding-right: 30px;
box-sizing: border-box;
&:nth-child(4n) {
padding-right: 0;
}
.item-head {
width: 58px;
height: 58px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 15px;
img {
max-width: 100%;
max-height: 100%;
}
span {
font-size: 58px
}
}
.item-content {
flex: 1;
display: flex;
flex-direction: column;
.name {
font-size: 19px;
font-weight: bold;
color: #444;
line-height: 1;
margin-bottom: 8px;
@extend .using-hidden;
}
.desc {
font-size: 15px;
color: #444;
line-height: 1;
@extend .using-hidden;
}
}
}
}
}
.footer-bot {
background: #f2f2f2;
color: #444;
}
.friendly-link {
width: $width;
margin: 0 auto;
padding-bottom: 48px;
.link-title {
line-height: 30px;
padding: 10px 0 5px;
margin: 0px 0 15px;
border-bottom: 1px solid #e8e8e8;
}
.link-item {
width: 192px;
height: 80px;
line-height: 80px;
text-align: center;
margin: 14px 12px 4px 0;
cursor: pointer;
background-color: #fff;
img {
max-width: 100%;
max-height: 100%;
}
}
.link-item:hover {
width: 192px;
position: relative;
opacity: 1;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
}
}
</style>
<style lang="scss">
.friendly-link {
.el-tabs__nav-scroll {
border-left: 1px solid #d8d8d8;
}
.el-tabs__header {
margin-bottom: 14px;
}
.el-tabs__content {
.el-tab-pane {
display: flex;
flex-wrap: wrap;
}
}
.el-tabs__nav-wrap::after {
height: 1px;
}
.el-tabs__item {
padding: 0 10px !important;
height: 52px;
line-height: 52px;
width: 168px;
text-align: center;
box-sizing: border-box;
border-top: 1px solid #d8d8d8;
border-right: 1px solid #d8d8d8;
font-size: 18px;
&.is-active {
color: $base-color;
}
}
.el-tabs__active-bar {
margin-left: -10px;
width: 168px !important;
bottom: 50px;
background-color: $base-color;
&::after {
content: "";
position: absolute;
bottom: -50px;
left: 0;
height: 1px;
width: 100%;
background-color: #f9f9f9;
}
}
}
</style>

View File

@@ -0,0 +1,464 @@
<template>
<div class="header">
<ns-header-top />
<ns-header-mid />
<div class="nav">
<div class="shop-list-content"
:class="forceExpand || isShopHover || (isIndex && is_show) ? 'shop-list-active' : 'shadow'">
<div class="shop-list" v-if="categoryConfig.category ==1" @mouseover="shopHover" @mouseleave="shopLeave">
<div class="list-item" v-for="(item, index) in goodsCategoryTree" :key="index"
@mouseover="selectedCategory = item.category_id" @mouseleave="selectedCategory = -1">
<router-link :to="{ path: '/goods/list', query: { category_id: item.category_id, level: item.level } }"
target="_blank">
<div>
<img class="category-img" v-if="categoryConfig.img == 1 && item.image" :src="$util.img(item.image)" />
<p class="category-name">{{item.category_name }}</p>
</div>
<i class="el-icon-arrow-right" aria-hidden="true"></i>
</router-link>
</div>
</div>
<!-- 分类类型2 -->
<div class="shop-list"
:class="forceExpand || isShopHover || (isIndex && is_show) ? 'shop-list-active' : 'shadow'"
v-else-if="categoryConfig.category ==2" @mouseover="shopHover" @mouseleave="shopLeave">
<div class="list-item" v-for="(item, index) in goodsCategoryTree" :key="index"
@mouseover="selectedCategory = item.category_id" @mouseleave="selectedCategory = -1">
<router-link :to="{ path: '/goods/list', query: { category_id: item.category_id, level: item.level } }"
target="_blank">
<div>
<img class="category-img" v-if="categoryConfig.img == 1 && item.image" :src="$util.img(item.image)" />
<p class="category-name">{{ item.category_name }}</p>
</div>
<i class="el-icon-arrow-right" aria-hidden="true"></i>
</router-link>
<div class="cate-part" v-if="item.child_list" :class="{ show: selectedCategory == item.category_id }">
<div class="cate-part-col1">
<div class="cate-detail">
<div class="cate-detail-item">
<div class="cate-detail-con">
<router-link v-for="(second_item, second_index) in item.child_list" :key="second_index"
target="_blank"
:to="{ path: '/goods/list', query: { category_id: second_item.category_id, level: second_item.level } }">
<img class="cate-detail-img" v-if="categoryConfig.img == 1"
:src="$util.img(second_item.image)" />
<p class="category-name">{{second_item.category_name }}</p>
</router-link>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 分类类型3 -->
<div class="shop-list" :class="forceExpand || isShopHover || isIndex ? 'shop-list-active' : 'shadow'"
v-else-if="categoryConfig.category ==3" @mouseover="shopHover" @mouseleave="shopLeave">
<div class="list-item" v-for="(item, index) in goodsCategoryTree" :key="index"
@mouseover="selectedCategory = item.category_id" @mouseleave="selectedCategory = -1">
<router-link :to="{ path: '/goods/list', query: { category_id: item.category_id, level: item.level } }"
target="_blank">
<div class="list-item-left">
<img class="category-img" v-if="categoryConfig.img == 1 && item.image" :src="$util.img(item.image)" />
<p class="category-name">{{item.category_name }}</p>
</div>
<!-- <i class="el-icon-arrow-right" aria-hidden="true" v-if="item.child_list"></i> -->
</router-link>
<div class="item-itm " :class="{'item-itm-img':categoryConfig.img == 1}">
<router-link v-for="(second_item, second_index) in item.child_list" :key="second_index"
:to="{ path: '/goods/list', query: { category_id: second_item.category_id, level: second_item.level } }"
target="_blank" v-show="second_index < 3" style="display:inline-block;">
{{ second_item.short_name?second_item.short_name : second_item.category_name }}
</router-link>
</div>
<div class="cate-part" v-if="item.child_list" :class="{ show: selectedCategory == item.category_id }">
<div class="cate-part-col1">
<div class="cate-detail">
<dl class="cate-detail-item" v-for="(second_item, second_index) in item.child_list"
:key="second_index">
<dt class="cate-detail-tit">
<router-link target="_blank"
:to="{ path: '/goods/list', query: { category_id: second_item.category_id, level: second_item.level } }">
{{ second_item.category_name }}
</router-link>
</dt>
<dd class="cate-detail-con" v-if="second_item.child_list">
<router-link v-for="(third_item, third_index) in second_item.child_list" :key="third_index"
target="_blank"
:to="{ path: '/goods/list', query: { category_id: third_item.category_id, level: third_item.level } }">
<img class="cate-detail-img" v-if="categoryConfig.img == 1"
:src="$util.img(third_item.image)" />
<p class="category-name">{{third_item.category_name }}</p>
</router-link>
</dd>
</dl>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import NsHeaderTop from './NsHeaderTop';
import NsHeaderMid from './NsHeaderMid';
import {
tree,
categoryConfig
} from '@/api/goods/goodscategory';
import {
mapGetters
} from "vuex"
export default {
props: {
forceExpand: {
type: Boolean,
default: false
}
},
computed: {
...mapGetters(['is_show'])
},
data() {
return {
isShopHover: false,
isIndex: false,
thisRoute: '',
goodsCategoryTree: [],
categoryConfig: {},
selectedCategory: -1,
isHide: false
};
},
components: {
NsHeaderTop,
NsHeaderMid,
mapGetters
},
beforeCreate() {},
created() {
this.$store.dispatch('cart/cart_count');
this.getCategoryConfig();
// this.getTree();
if (this.$route.path == '/' || this.$route.path == '/index') {
this.isIndex = true;
}
},
watch: {
$route: function(curr) {
let judgeLength = localStorage.getItem('isAdList')
if (this.$route.path == '/' || this.$route.path == '/index') this.isIndex = true;
else this.isIndex = false;
}
},
methods: {
// 获取配置
getCategoryConfig() {
categoryConfig({
})
.then(res => {
if (res.code == 0 && res.data) {
this.categoryConfig = res.data;
this.getTree(res.data);
}
})
.catch(err => {
this.$message.error(err.message);
});
},
getTree(categoryConfig) {
tree({
level: 3,
template: 2
})
.then(res => {
if (res.code == 0 && res.data) {
this.goodsCategoryTree = res.data || [];
for (let i = 0; i < this.goodsCategoryTree.length; i++) {
if (this.goodsCategoryTree[i].child_list > 3) {
this.isHide = true
}
}
}
})
.catch(err => {
this.$message.error(err.message);
});
},
//鼠标移入显示商品分类
shopHover() {
this.isShopHover = true;
},
//鼠标移出商品分类隐藏
shopLeave() {
this.isShopHover = false;
}
}
};
</script>
<style scoped lang="scss">
.header {
width: 100%;
background-color: #fff;
.shadow {
box-shadow: -1px 3px 12px -1px rgba(0, 0, 0, 0.3);
}
.border {
border: 1px solid #f5f5f5;
}
.nav {
width: 1210px;
margin: 0 auto;
position: relative;
.shop-list-content {
width: 240px;
height: 500px;
position: absolute;
left: 0;
top: 1px;
background-color: rgba(0, 0, 0, 0.6);
display: none;
padding: 0;
box-sizing: border-box;
font-size: $ns-font-size-base;
z-index: 10;
color: #FFFFFF;
&::-webkit-scrollbar {
display: none;
}
.shop-list {
width: 240px;
height: 500px;
overflow-y: auto;
overflow-x: hidden;
&::-webkit-scrollbar {
display: none;
}
a:hover {
color: $base-color;
}
.list-item {
padding-left: 40px;
padding-right: 15px;
box-sizing: border-box;
a {
display: flex;
justify-content: space-between;
align-items: center;
height: 46px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: #FFFFFF;
>div {
display: flex;
align-items: center;
}
}
&:hover {
background-color: rgba(31,0,0,0.4);
-webkit-transition: 0.2s ease-in-out;
-moz-transition: -webkit-transform 0.2s ease-in-out;
-moz-transition: 0.2s ease-in-out;
transition: 0.2s ease-in-out;
}
span:hover {
color: #FD274A;
}
.category-img {
width: 17px;
height: 17px;
margin-right: 10px;
}
.category-name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.item-itm {
font-size: 14px;
line-height: 15px;
height: 28px;
overflow: hidden;
a {
margin-top: 5px;
margin-right: 10px;
color: #BFBFBF;
&:hover {
color: #FD274A !important;
}
}
&.item-itm-img {
margin-left: 27px;
}
}
.cate-part {
display: none;
position: absolute;
left: 240px;
top: 0;
z-index: auto;
// width: 998px;
width: 760px;
height: 498px;
overflow-y: auto;
border: 1px solid #f7f7f7;
background-color: #fff;
-webkit-box-shadow: 2px 0 5px rgba(0, 0, 0, 0.05);
-moz-box-shadow: 2px 0 5px rgba(0, 0, 0, 0.05);
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.05);
-webkit-transition: top 0.25s ease;
-o-transition: top 0.25s ease;
-moz-transition: top 0.25s ease;
transition: top 0.25s ease;
&.show {
display: block;
}
&::-webkit-scrollbar {
display: none;
}
}
.cate-part-col1 {
float: left;
width: 100%;
.cate-detail-item {
position: relative;
min-height: 36px;
padding-left: 20px;
&:last-child {
margin-bottom: 30px;
}
.cate-detail-tit {
margin-top: 30px;
margin-right: 20px;
white-space: nowrap;
text-overflow: ellipsis;
font-weight: 700;
a {
display: block;
color: #333333;
}
a:hover {
color: #FD274A;
}
}
.cate-detail-con {
overflow: hidden;
padding: 6px 0 6px 17px;
display: flex;
flex-wrap: wrap;
// border-top: 1px dashed #eee;
a {
justify-content: start;
font-size: 12px;
height: 30px;
/* float: left; */
margin: 4px 40px 4px 0;
padding: 0 10px;
white-space: nowrap;
line-height: 30px;
color: #666;
width: calc((100% - 120px) / 4);
display: flex;
box-sizing: border-box;
margin-top: 20px;
.cate-detail-img {
width: 30px;
height: 30px;
margin-right: 10px;
}
&:nth-child(4n+4) {
margin-right: 0;
}
}
a:hover {
color: #FD274A;
}
}
&:first-child .cate-detail-con {
border-top: none;
}
}
}
// .sub-class-right {
// display: block;
// width: 240px;
// height: 439px;
// float: right;
// border-left: solid 1px #e6e6e6;
// overflow: hidden;
// .adv-promotions {
// display: block;
// height: 441px;
// margin: -1px 0;
// a {
// background: #fff;
// display: block;
// width: 240px;
// height: 146px;
// border-top: solid 1px #e6e6e6;
// img {
// background: #d3d3d3;
// width: 240px;
// height: 146px;
// }
// }
// }
// }
}
}
}
.shop-list-active {
display: block;
}
}
}
</style>

View File

@@ -0,0 +1,247 @@
<template>
<div class="header-in">
<router-link to="/" class="header-left"><img v-if="siteInfo.logo" :src="$img(siteInfo.logo)" /></router-link>
<div class="header-content">
<nav>
<ul>
<li v-for="(nav_item, nav_index) in navList" :key="nav_index"
:class="nav_item.url == navSelect ? 'router-link-active' : ''"
@click="navUrl(nav_item.url, nav_item.is_blank)">
{{ nav_item.nav_title }}
</li>
</ul>
</nav>
</div>
<div class="header-right">
<span class="iconfont icon-xiaosuo"></span>
<input type="text" :placeholder="defaultSearchWords" v-model="keyword" @keyup.enter="search" maxlength="50" />
<el-button size="small" @click="search">搜索</el-button>
</div>
</div>
</template>
<script>
import {
mapGetters
} from 'vuex';
import {
apiDefaultSearchWords
} from '@/api/pc';
import {
navList
} from '@/api/website';
export default {
props: {},
data() {
return {
keyword: '',
defaultSearchWords: '请输入您要查询的商品',
cartTotalPrice: 0,
navList: [],
navSelect: '',
searchType: 'goods'
};
},
components: {},
computed: {
...mapGetters(['siteInfo', 'defaultGoodsImage', 'member'])
},
created() {
this.keyword = this.$route.query.keyword || '';
this.$store.dispatch('site/siteInfo');
this.getDefaultSearchWords();
this.nav();
},
watch: {
$route(curr) {
this.initNav(curr.path);
if (this.keyword !== curr.query.keyword) {
this.keyword = curr.query.keyword;
}
if (curr.path == '/goods/list') {
this.navSelect = '';
}
},
member() {
if (!this.member) {
this.$store.commit('cart/SET_CART_COUNT', 0);
this.cartTotalPrice = 0;
}
}
},
methods: {
search() {
if (this.searchType == 'goods') {
this.defaultSearchWords = this.defaultSearchWords == '请输入您要查询的商品' ? '' : this.defaultSearchWords;
let keyword = this.keyword ? this.keyword : this.defaultSearchWords;
let query = {};
if (keyword) {
query.keyword = keyword;
}
this.$router.push({
path: '/goods/list',
query
});
} else {
this.$router.push({
path: '/street',
query: {
keyword: this.keyword
}
});
}
},
getDefaultSearchWords() {
apiDefaultSearchWords({}).then(res => {
if (res && res.code == 0 && res.data.words) {
this.defaultSearchWords = res.data.words;
}
});
},
nav() {
navList({})
.then(res => {
if (res.code == 0 && res.data) {
this.navList = res.data;
for (let i in this.navList) {
this.navList[i]['url'] = JSON.parse(this.navList[i]['nav_url']).url;
}
this.initNav(this.$route.path);
}
})
.catch(err => {
this.$message.error(err.message);
});
},
initNav(path) {
for (let i in this.navList) {
if (this.navList[i]['url'] == path) {
this.navSelect = path;
continue;
}
}
},
navUrl(url, target) {
if (!url) return;
if (url.indexOf('http') == -1 || url.indexOf('https') == -1) {
if (target) {
let routeUrl = this.$router.resolve({
path: url
});
window.open(routeUrl.href, '_blank');
} else
this.$router.push({
path: url
});
} else {
if (target) window.open(url);
else window.location.href = url;
}
}
}
};
</script>
<style scoped lang="scss">
.header-in {
display: flex;
align-items: center;
width: $width;
height: 100px;
margin: auto;
.header-left {
max-width: 200px;
max-height: 60px;
margin-right: 40px;
overflow: hidden;
img {
max-width: 100%;
max-height: 100%;
}
}
.header-content {
overflow: hidden;
flex: 1;
&::-webkit-scrollbar {
width: 10px;
height: 5px;
}
&::-webkit-scrollbar-track {
background: rgb(179, 177, 177);
border-radius: 10px;
}
&::-webkit-scrollbar-thumb {
background: rgb(136, 136, 136);
border-radius: 10px;
}
}
.header-right {
display: flex;
align-items: center;
margin-left: 20px;
width: 250px;
height: 36px;
border-bottom: 1px solid #f2f2f2;
box-sizing: border-box;
.iconfont {
color: #999;
margin-left: 10px;
font-size: 18px;
}
input {
height: 22px;
background: none;
outline: none;
border: none;
padding: 0 10px;
font-size: 14px;
}
button {
border: none;
color: $base-color;
font-size: 16px;
padding: 0;
}
}
nav {
ul {
margin: 0;
padding: 0;
width: 100%;
height: 28px;
overflow: hidden;
li {
cursor: pointer;
list-style: none;
margin-right: 20px;
font-size: 16px;
float: left;
&:last-of-type {
margin-right: 0;
}
}
li:hover {
color: $base-color;
}
.router-link-active {
color: $base-color;
}
}
}
}
</style>

View File

@@ -0,0 +1,206 @@
<template>
<div>
<div class="header-top">
<div class="top-content">
<div class="top-left">
<div class="left-item collect" @click="addFavorite">
<span class="iconfont icon-shouzang"></span>
<span>收藏本站</span>
</div>
</div>
<div class="top-right">
<div class="member-info" v-if="logined">
<router-link to="/member">{{ member.nickname || member.username }}</router-link>
<a @click="logout">退出</a>
</div>
<div class="member-info" v-if="!logined">
<router-link to="/auth/login">登录</router-link>
<router-link to="/auth/register">注册</router-link>
</div>
<router-link to="/cms/notice/list"><span class="announcement iconfont icon-xiaoxi"></span></router-link>
<router-link to="/member/order_list">我的订单</router-link>
</div>
</div>
</div>
</div>
</template>
<script>
import {
mapGetters
} from "vuex"
import {
getToken
} from "@/utils/auth"
export default {
props: {},
data() {
return {}
},
created() {
this.$store.dispatch("member/member_detail")
this.$store.dispatch("site/defaultFiles")
this.$store.dispatch("site/addons")
},
mounted() {},
watch: {},
methods: {
logout() {
this.$store.dispatch("member/logout")
this.$router.push('/');
},
//收藏本站
addFavorite() {
let title = "Niushop PC端",
url = window.location.href;
try {
if(window.external) {
window.external.addFavorite(url, title);
}else if(window.sidebar){
window.sidebar.addPanel(title, url, "");
}
} catch (e) {
alert("抱歉,您所使用的浏览器无法完成此操作。\n\n加入收藏失败请使用Ctrl+D进行添加");
}
}
},
components: {},
computed: {
...mapGetters(["wapQrcode", "member", "addonIsExit"]),
logined: function() {
return this.member !== undefined && this.member !== "" && this.member !== {}
}
}
}
</script>
<style scoped lang="scss">
// 公共部分
%line{
content: "";
position: absolute;
left: -2px;
top: 50%;
transform: translateY(-50%);
width: 1px;
height: 12px;
}
.header-top {
width: 100%;
height: 44px;
font-size: 12px;
background-color: #242424;
.el-dropdown {
font-size: $ns-font-size-sm;
}
.top-content {
display: flex;
align-items: center;
width: $width;
height: 100%;
margin: 0 auto;
.left-item{
&.collect{
display: flex;
align-items: center;
cursor: pointer;
color: #b4b4b4;
span:nth-child(1){
font-weight: bold;
line-height: 1;
}
span:nth-child(2){
margin-left: 5px;
font-size: 14px;
line-height: 1;
}
&:hover{
color: $base-color;
}
}
}
.top-right {
display: flex;
align-items: center;
margin-left: auto;
a {
position: relative;
padding: 20px 18px;
color: #b4b4b4;
font-size: 14px;
&:hover {
color: $base-color;
}
.iconfont{
font-size: 18px;
font-weight: bold;
color: #fff;
}
.announcement{
position: absolute;
animation:mymove 3s infinite;
position: absolute;
top: 12px;
left: 9px;
line-height: 1;
}
@keyframes mymove {
5%,25%,45% {
transform:rotate(8deg)
}
0%,10%,30%,50% {
transform:rotate(-8deg)
}
15%,35%,55% {
transform:rotate(4deg)
}
20%,40%,60% {
transform:rotate(-4deg)
}
65%,to {
transform:rotate(0deg)
}
}
}
&>a:nth-last-child(1):after,
&>a:nth-last-child(2):after {
@extend %line;
background-color: #404040;
}
&>a:nth-last-child(2):after {
left: 1px;
}
.member-info {
padding: 0 10px;
> a{
position: relative;
padding: 0;
&:last-of-type{
padding-left: 8px;
margin-left: 2px;
&::after{
@extend %line;
left: 0;
background-color: #b4b4b4;
}
}
}
}
}
}
}
.mobile-qrcode {
padding: 10px 0;
}
.router-link-active {
color: $base-color;
}
</style>