Files
pupil/packageSearch/goods-category-search/category-index.vue
”chenxuelian“ 0b8b80a74b 解决冲突
2023-04-18 21:44:35 +08:00

810 lines
22 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view :style="{height: windowHeight + 'px', overflow:showMask? 'hidden':'auto'}">
<!-- 顶部导航栏 -->
<view class="top-search">
<customer-searchbar ref="search" :readOnly="true" :search-bar-top="searchBarTop"
:search-bar-height="searchBarHeight" @navigate="navigateToSearch" @back="goBack" />
</view>
<view :style="{marginTop: Number(searchBarTop + searchBarHeight + 2) + 'px',}">
<view>
<view class="category-view">
<view class="left">
<view v-for="(item,index) in categoryList" class="category-item"
@click="changeSelectedCategory(item, index)">
<view>
<view class="icon-box">
<image :src="item.icon" mode="aspectFit" class="icon"
:style="{border: item.active?'2rpx #14CA65 solid':'0',}" />
</view>
<view class="name" :style="{width: item.active?'74px':'126rpx'}">
<u-tag v-if="item.active" :text="item.name" bg-color="#14CA65" color="#fff"
borderColor="#14CA65" shape="circle" />
<text v-else class="no-active">{{item.name}}</text>
</view>
</view>
</view>
</view>
<view class="right" @click="exportView('showMask')">
<tex style="margin-bottom: 10rpx;">全部</tex>
<u-icon size="14" name="/static/category/fl_icon_qb.png"></u-icon>
</view>
</view>
<!-- 类别详情-->
<view id="category-detail" class="category-detail" :style="{height: listDataHeight + 'px'}">
<scroll-view scroll-y scroll-with-animation class="u-tab-view menu-scroll-view"
:scroll-top="scrollTop">
<view v-for="(item,index) in tabbar" :key="index" class="u-tab-item"
:class="[menuCurrent==index ? 'u-tab-item-active' : '']" :data-current="index"
@tap.stop="swichMenu(index)">
<text class="title">{{item.name}}</text>
</view>
</scroll-view>
<view class="category-last">
<view class="category-tag-box">
<scroll-view :scroll-x="true" class="left">
<view v-for="(item,index) in tagsList" @click="changeSelectedTag(index)"
class="category-tag">
<view style="padding: 16rpx; border-radius: 10rpx;line-height: 32rpx;"
:style="{color: index === tagCurrent ?'#14CA65':'#666', background: index === tagCurrent ?'#DBFFEB':'#EEEEEE'}">
<text>{{item.name}}</text>
</view>
<!-- <u-tag v-if="index === tagCurrent" :text="item.name" bg-color="#DBFFEB" color="#14CA65" borderColor="#DBFFEB" shape="square" style="width: fit-content;"></u-tag> -->
<!-- <u-tag v-else :text="item.name" bg-color="#EEEEEE" color="#666666" borderColor="#EEEEEE" shape="square" style="width: fit-content;"></u-tag> -->
</view>
</scroll-view>
<view class="right" @click="exportView('featureMask')">
<u-icon size="10" name="/static/category/fl_icon_xl.png"></u-icon>
</view>
</view>
<view class="category-order">
<u-tabs :list="tabsList" :scrollable="false" lineWidth="30" lineColor="#0A994A"
color="#969696"
:activeStyle="{color: '#15CA65', fontWeight: '400', transform: 'scale(1.05)', size:'14px'}"
lineHeight="4" :current="tabCurrent" @change="tabChange"></u-tabs>
</view>
<scroll-view scroll-y class="goods-list" @scrolltolower="reachGoodsBottom">
<block v-for="(item1,index1) in goodsList" :key="index1">
<view class="goods-item" @click="toDetailPage(item1)">
<view class="left">
<view class="image">
<image :src="item1.imageF" mode="scaleToFill"
style="width: 170rpx;height: 100%;"></image>
</view>
<view class="tag">
<view class="tag-content">
<text>{{item1.cate_name}}</text>
</view>
</view>
</view>
<view class="right">
<view class="name">
<text>{{item1.name}}</text>
</view>
<view class="describe">
<text>{{item1.title}}</text>
</view>
<view class="publish-date">
<view class="publish-date-box">
<view
style="width: fit-content; display: inline-block;margin-right:6rpx;">
<u-icon size="14" name="clock" color="#A3A3A3" />
</view>
<text style="margin-right: 6rpx;">发布日期</text>
<text>{{item1.pub_time_str}}</text>
</view>
</view>
<view class="tag">
<template v-if="item1.tagList.length">
<view class="tag-content">
<text>{{ item1.tagList[0] }}</text>
</view>
</template>
<!-- <view v-for="(tagObject, index) in item1.tagList" class="tag-content">
<text>{{ tagObject }}</text>
</view> -->
</view>
</view>
</view>
</block>
</scroll-view>
</view>
</view>
</view>
<view class="bg" bindtap='hideview'
:style="{display: showMask || featureMask ? 'block':'none', marginTop: Number(searchBarTop + searchBarHeight + 4) + 'px', height: Number(windowHeight - searchBarTop - searchBarHeight - 4) + 'px',}"
@click="showMask = false, featureMask = false"></view>
<view class="show" bindtap='hideview'
:style="{display: showMask || featureMask ? 'block':'none', top: Number(searchBarTop + searchBarHeight + 4) + 'px',}">
<view v-if="showMask" class="category-view-all">
<view v-for="(item,index) in categoryList" @click="changeSelectedCategory(item,index)"
style="width: 20%;margin-bottom: 20rpx;">
<view class="category-item">
<view class="icon-box">
<image :src="item.icon" mode="aspectFit" class="icon"
:style="{border: item.active?'2rpx #14CA65 solid':'0',}" />
</view>
<view class="name">
<view v-if="item.active" class="active">
<text>{{item.name}}</text>
</view>
<text v-else class="no-active">{{item.name}}</text>
</view>
</view>
</view>
</view>
<view v-if="featureMask" class="category-view-all" style="align-content: start;">
<view v-for="(item,index) in tagsList" @click="changeSelectedTag(index)" class="category-tag">
<view style="padding: 16rpx; border-radius: 10rpx;line-height: 32rpx;"
:style="{color: index === tagCurrent ?'#14CA65':'#666', background: index === tagCurrent ?'#DBFFEB':'#EEEEEE'}">
<text>{{item.name}}</text>
</view>
<!-- <u-tag v-if="index === tagCurrent" :text="item.name" bg-color="#DBFFEB" color="#14CA65" borderColor="#DBFFEB" shape="square" style="width: fit-content;"></u-tag> -->
<!-- <u-tag v-else :text="item.name" bg-color="#EEEEEE" color="#666666" borderColor="#EEEEEE" shape="square" style="width: fit-content;"></u-tag> -->
</view>
</view>
<view class="arrow-up" @click="showMask = false, featureMask = false">
<text style="margin-right: 4rpx;">点击收起</text>
<u-icon size="15" name="arrow-up-fill"></u-icon>
</view>
</view>
<!-- <uni-popup ref="popup" type="center" :animation="false">中间弹出 Popup</uni-popup> -->
<!-- <u-popup v-model="showMask" mode="top" border-radius="14">
<view style="margin-top: 200rpx;">出淤泥而不染濯清涟而不妖</view>
</u-popup> -->
</view>
</view>
</template>
<script>
export default {
data() {
return {
searchBarTop: 0, //搜索栏的外边框高度单位px
searchBarHeight: 0, //搜索栏的高度单位px
windowHeight: 1,
listDataHeight: 1, // 剩余高度
queryParam: '',
showMask: false,
featureMask: false,
categoryList: [],
selectedCategory: 0,
tabbar: [],
goodsParam: {
sortType: 0,
cateId: 0,
tagIds: 0,
pageSize: 10,
pageNum: 1
},
goodsList: [],
tabsList: [{
name: '新品发布' // 上架时间(改)
}, {
name: '新创意' // 点赞量(改)
}],
tagsList: [],
scrollTop: 0, //tab标题的滚动条位置
menuCurrent: 0, // 预设当前项的值
menuHeight: 0, // 左边菜单的高度
menuItemHeight: 0, // 左边菜单item的高度
tabCurrent: 0, //分类详情 上架时间, // 左边菜单item的高度
tagCurrent: 0, //分类详情 上架时间
imgUrl: '',
isAllData: false
}
},
onLoad(options) {
console.log(options)
const menuButtonInfo = uni.getMenuButtonBoundingClientRect();
this.searchBarTop = menuButtonInfo.top;
this.searchBarHeight = menuButtonInfo.height;
this.imgUrl = uni.getStorageSync('img_url')
this.goodsList = []
this.isAllData = false
this.getCategoryList(options.categoryId)
},
onReady() {
let that = this;
uni.getSystemInfo({ //调用uni-app接口获取屏幕高度
success(res) { //成功回调函数
// windowHeight
that.windowHeight = res.windowHeight //windoHeight为窗口高度主要使用的是这个
let titleH = uni.createSelectorQuery().select("#category-detail"); //想要获取高度的元素名class/id
titleH.boundingClientRect(data => {
let pH = that.windowHeight;
that.listDataHeight = pH - data.top //计算高度:元素高度=窗口高度-元素距离顶部的距离data.top
console.log(that.listDataHeight)
}).exec()
}
})
},
methods: {
//点击goodsItem跳转到详情页
toDetailPage(item1) {
uni.navigateTo({
url: '/pages/detail/productsDetail/productsDetail?id=' + item1.id
})
},
goSearch(param) {
this.queryParam = param
const index = this.recentRecordList.findIndex(item => {
return item === param
})
if (index > -1) {
this.recentRecordList.splice(index, 1)
}
this.recentRecordList.unshift(param)
},
changeSelectedCategory(item, index) {
this.$set(this.categoryList, this.selectedCategory, {
...this.categoryList[this.selectedCategory],
active: false
});
this.$set(this.categoryList, index, {
...this.categoryList[index],
active: true
});
this.selectedCategory = index
this.tabCurrent = 0
this.tagCurrent = 0
this.menuCurrent = 0
this.getSeconedCategoryList()
this.showMask = false
},
changeSelectedTag(index) {
this.tagCurrent = index
this.featureMask = false
this.getGoodsList(true)
},
// 点击左边的栏目切换
async swichMenu(index) {
if (index == this.menuCurrent) return;
this.menuCurrent = index;
// 如果为0意味着尚未初始化
if (this.menuHeight == 0 || this.menuItemHeight == 0) {
await this.getElRect('menu-scroll-view', 'menuHeight');
await this.getElRect('u-tab-item', 'menuItemHeight');
}
// 将菜单菜单活动item垂直居中
this.scrollTop = index * this.menuItemHeight + this.menuItemHeight / 2 - this.menuHeight / 2;
this.getTagList()
},
// 获取一个目标元素的高度
getElRect(elClass, dataVal) {
new Promise((resolve, reject) => {
const query = uni.createSelectorQuery().in(this);
query.select('.' + elClass).fields({
size: true
}, res => {
// 如果节点尚未生成res值为null循环调用执行
if (!res) {
setTimeout(() => {
this.getElRect(elClass);
}, 10);
return;
}
this[dataVal] = res.height;
}).exec();
})
},
exportView(str) {
if (str === 'showMask') {
this.showMask = true
} else if (str === 'featureMask') {
this.featureMask = true
}
},
tabChange(selectTab) {
console.log(selectTab)
this.tabCurrent = selectTab.index;
this.getGoodsList(true)
},
navigateToSearch() {
uni.navigateTo({
url: '../search/search'
})
},
getCategoryList(selectedCategoryId) {
this.$apiServe.getCategories().then(res => {
this.categoryList = res.data.data.map((item, index) => {
item.icon = this.imgUrl + item.icon
if (selectedCategoryId && selectedCategoryId === item.id) {
item.active = true
this.selectedCategory = index
} else if (selectedCategoryId === null && this.selectedCategory && this
.selectedCategory === index) {
item.active = true
active = true
} else if (selectedCategoryId === null && !this.selectedCategory && !index) {
item.active = true
} else {
item.active = false
}
return item
})
this.getSeconedCategoryList()
}).finally(_ => {})
},
getSeconedCategoryList() {
const data = {
pid: this.categoryList[this.selectedCategory].id
}
this.$apiServe.getCategories(data).then(res => {
this.tabbar = res.data.data.map((item, index) => {
item.icon = this.imgUrl + item.icon
return item
})
this.getTagList()
}).finally(_ => {})
},
getTagList() {
const data = {
pid: this.tabbar[this.menuCurrent].id
}
this.$apiServe.getTags(data).then(res => {
this.tagsList = res.data.data.map((item, index) => {
return item
})
}).finally(_ => {
this.getGoodsList(true)
})
},
getGoodsList(firstPage) {
this.isAllData = false
const data = {
...this.goodsParam,
sortType: this.tabCurrent + 1,
cateId: this.tabbar.length ? this.tabbar[this.menuCurrent].id : 0,
tagIds: this.tagsList.length ? this.tagsList[this.tagCurrent].id : 0
}
if (firstPage) {
this.goodsList = []
this.goodsParam.pageNum = 1
}
this.$apiServe.getProductList(data).then(res => {
if (res.data.data.length > 0) {
res.data.data.map((item, index) => {
item.tagList = item.tags.split(',')
item.imageF = this.imgUrl + item.images
this.goodsList.push(item)
// return item
})
} else {
this.isAllData = true
this.$toast.warn('暂无数据')
}
}).finally(_ => {})
},
reachGoodsBottom() {
console.log('-----触底')
//触底事件
if (!this.isAllData) {
uni.showLoading({
title: '加载中'
});
this.goodsParam.pageNum++
this.getGoodsList(false)
} else {
this.$toast.warn('暂无数据')
}
setTimeout(() => {
uni.hideLoading()
}, 500)
},
goBack() {
uni.navigateBack()
}
},
}
</script>
<style lang="less" scoped>
.top-search {
position: relative;
}
.category-view {
height: fit-content;
background-color: #F6F6F6;
display: flex;
justify-content: space-around;
.left {
width: calc(100% - 60rpx);
padding: 30rpx;
display: flex;
overflow: auto;
// flex-direction: row;
// flex-wrap: wrap;
// align-items: center;
.category-item {
margin-right: 20rpx;
display: flex;
flex-direction: column;
justify-content: center;
.icon-box {
text-align: center;
.icon {
width: 86rpx;
height: 86rpx;
padding: 4rpx;
border-radius: 50%;
}
}
.name {
// width: 126px;
text-align: center;
.no-active {
font-size: 24rpx;
font-family: PingFang-SC-Medium, PingFang-SC;
font-weight: 500;
color: #616161;
line-height: 28rpx;
}
}
}
}
.right {
width: 60rpx;
padding: 20rpx;
background: #F6F6F6;
border-left: 2rpx #F6F6F6 solid;
box-shadow: -2px 0px 4px 0px rgba(218, 218, 218, 0.5);
font-size: 28rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #343434;
line-height: 34rpx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
}
}
.category-detail {
display: flex;
background-color: #F5F5F5;
.u-tab-view {
width: 210rpx;
height: 100%;
.u-tab-item {
height: 90rpx;
background: #f6f6f6;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
font-size: 26rpx;
color: #444;
font-weight: 400;
line-height: 1;
.title {
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #343434;
line-height: 40rpx;
}
}
.u-tab-item-active {
position: relative;
color: #000;
font-size: 30rpx;
font-weight: 600;
background: #fff;
border: 2rpx solid #fff;
border-radius: 25% 0 0 0;
.title {
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #14CA65;
line-height: 40rpx;
}
}
.u-tab-item-active::before {
content: "";
position: absolute;
border: 1rpx solid #14CA65;
background-color: #14CA65;
width: 1rpx;
height: 14rpx;
left: 27rpx;
top: 37srpx;
border-radius: 1rpx;
}
}
.category-last {
width: calc(100% - 206rpx);
height: 100%;
.category-tag-box {
background-color: #fff;
height: 110rpx;
display: flex;
border-bottom: 1rpx solid #EEEEEE;
.left {
width: calc(100% - 60rpx);
padding: 12rpx;
white-space: nowrap;
overflow: auto;
line-height: 90rpx;
.category-tag {
margin-right: 15rpx;
width: fit-content;
display: inline-flex;
}
}
.right {
width: 60rpx;
padding: 20rpx;
background: #F6F6F6;
border-left: 2rpx #F6F6F6 solid;
box-shadow: -2px 0px 4px 0px rgba(218, 218, 218, 0.5);
font-size: 28rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #343434;
line-height: 34rpx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
}
}
.category-order {
width: 100%;
background-color: #fff;
border-bottom: 1rpx solid #EEEEEE;
}
.goods-list {
background-color: #fff;
height: calc(100% - 210rpx);
.goods-item {
padding: 0;
margin-bottom: 10rpx;
display: flex;
background: #FFFFFF;
box-shadow: 0px 2px 3px 0px rgba(169, 169, 169, 0.2);
border-bottom: 1px solid #EEEEEE;
.left {
width: 190rpx;
position: relative;
.image {
padding: 20rpx;
height: calc(100% - 40rpx)
}
.tag {
position: absolute;
top: 26rpx;
right: 0;
float: right;
.tag-content {
padding: 12rpx;
border-radius: 25rpx 0 0 25rpx;
line-height: 14rpx;
background: linear-gradient(135deg, #0DB658 0%, #16DD6D 100%);
color: #fff;
font-size: 20rpx;
width: fit-content;
}
}
}
.right {
padding: 20rpx;
height: calc(100% - 40rpx);
.name {
font-size: 33rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: bold;
color: #E10707;
line-height: 46rpx;
white-space: nowrap;
}
.describe {
font-size: 30rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #3E3E3E;
line-height: 37rpx;
margin: 5rpx 0 10rpx 0;
word-break: break-all;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
/* 这里是超出几行省略 */
-webkit-line-clamp: 2;
overflow: hidden;
}
.publish-date {
color: #A3A3A3;
font-size: 26rpx;
line-height: 30rpx;
margin: 14rpx 0 8rpx 0;
.publish-date-box {
display: flex;
align-items: center;
font-size: 22rpx;
}
}
.tag {
line-height: 60rpx;
// display: flex;
// text-overflow: clip;
// display: -webkit-box;
// -webkit-box-orient: vertical;
// /* 这里是超出几行省略 */
// -webkit-line-clamp: 1;
overflow: hidden;
.tag-content {
display: inline;
padding: 9rpx 17rpx;
border-radius: 25rpx;
line-height: 13rpx;
background-color: #FDD96A;
color: #fff;
font-size: 22rpx;
width: fit-content;
// margin-right: 6rpx;
}
}
}
}
}
}
}
.bg {
display: none;
position: absolute;
top: 0%;
left: 0%;
width: 100%;
background-color: black;
z-index: 1001;
-moz-opacity: 0.7;
opacity: 0.70;
filter: alpha(opacity=70);
}
.show {
display: none;
text-align: center;
position: absolute;
width: calc(100% - 20rpx);
height: fit-content;
padding: 20rpx 10rpx 0 10rpx;
border: 1rpx solid #fff;
background-color: #fff;
border-radius: 0 0 20rpx 20rpx;
z-index: 1002;
overflow: auto;
transition: all 2.4s;
.category-view-all {
width: calc(100% - 20rpx);
display: flex;
flex-direction: row;
flex-wrap: wrap;
border-bottom: 1px solid #EEEEEE;
height: 360rpx;
overflow: auto;
transition: height 1.3s ease;
.category-item {
// display: flex;
// flex-direction: column;
// justify-content: center;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
.icon-box {
text-align: center;
.icon {
width: 90rpx;
height: 90rpx;
padding: 4rpx;
border-radius: 50%;
}
}
.name {
text-align: center;
.active {
width: fit-content;
font-size: 26rpx;
text-align: center;
padding: 6rpx;
border-radius: 10rpx;
line-height: 32rpx;
color: #fff;
background-color: #14CA65;
}
.no-active {
font-size: 26rpx;
font-family: PingFang-SC-Medium, PingFang-SC;
font-weight: 500;
color: #616161;
line-height: 28rpx;
}
}
}
.category-tag {
margin-right: 17rpx;
margin-bottom: 20rpx;
width: fit-content;
height: fit-content;
display: inline-flex;
}
}
.arrow-up {
display: flex;
justify-content: center;
align-items: center;
font-size: 28rpx;
padding: 24rpx;
line-height: 32rpx;
}
}
/deep/ .u-tag {
flex: none;
width: auto;
}
</style>