mrr.sj.front/pages/jingxuan/selected-brands.vue

545 lines
14 KiB
Vue
Raw Permalink 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>
<custom-navbar title="精选品牌"
:leftImg="'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/60ae3383-6ff6-4f42-818b-d9b09a9bd0e0.png'"
:showUser="true"
backgroundColor="url('https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/ce2e62e1-c26a-45c8-a49d-7ed00b2ce02c.png') center 20%/cover no-repeat"
titleColor="#333" borderBottom="none" :show-headle="true"
headleSrc="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/51ebca5d-95c5-4fb8-8aa3-560a79100d25.png"
@onHeadleClick="goToSearch" class="nav-img-size">
</custom-navbar>
<serviecFirstTab :tabs="tabs" :activeId="activeId" activeColor="#FF4767" @tab-click="tabClick" bgColor="#fff">
</serviecFirstTab>
<CommonList ref="brandListRef" :apiUrl="'/sj/brand/list'" :initialQuery="{}"
:listScrollHeight="`calc(100vh - ${statusBarHeight * 2 + 250}rpx)`" @data-loaded="handleDataLoaded">
<template #headerScroll>
<view class="icon-tabs">
<view v-for="item in iconTabs" :key="item.id" class="icon-tab"
:class="{ active: currentSecondClass == item.id }" @click="selectSecondClass(item.id)">
<image :src="item.photo" class="icon-img" mode="aspectFill"></image>
<text class="icon-text">{{ item.title }}</text>
</view>
</view>
<view class="sort-bar">
<view class="sort-item" @tap="toggleSort('time')">
<text class="sort-text" :class="{ active: orderType === 1 || orderType === 2 }">发布时间</text>
<view class="arrows">
<image class="arrow-icon" :src="orderType === 2 ? iconPinkUp : iconGreyUp"></image>
<image class="arrow-icon" :src="orderType === 1 ? iconPinkDown : iconGreyDown"></image>
</view>
</view>
<view class="sort-item" @tap="toggleSort('view')">
<text class="sort-text" :class="{ active: orderType === 3 || orderType === 4 }">浏览量</text>
<view class="arrows">
<image class="arrow-icon" :src="orderType === 4 ? iconPinkUp : iconGreyUp"></image>
<image class="arrow-icon" :src="orderType === 3 ? iconPinkDown : iconGreyDown"></image>
</view>
</view>
</view>
</template>
<template #listData="{ list }">
<view class="zhanwei">
<view class="brand-grid">
<brand-card class="brand-card-wrap" v-for="(brand, idx) in enrichedBrandList(list)" :key="brand.id || idx"
:item="brand" :tagKeys="brand._tagKeys" @click="handleBrandClick(brand)" />
</view>
</view>
</template>
<template #empty>
<noData></noData>
</template>
</CommonList>
</view>
</template>
<script>
import request from "../../utils/request";
import serviecFirstTab from "@/components/common/service-first-tab.vue";
import CommonList from "@/components/common/CommonList.vue";
import brandCard from "@/pages/home/components/brand-card.vue";
import noData from "@/components/noData/noData.vue";
export default {
components: {
serviecFirstTab,
CommonList,
brandCard,
noData
},
data() {
return {
statusBarHeight: 0,
navHeight: 0,
// 当前选中的一级/二级分类ID页面顶部点击用
activeId: "",
currentSecondClass: "",
tabs: [],
iconTabs: [],
selectedSecondIds: [], // 抽屉里选中的分类ID
// 额外筛选参数
orderType: 0,
// 排序图标资源
iconGreyUp: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/e00ab2ac-bccf-42d8-820c-65727327e279.png',
iconGreyDown: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/dfffb601-6877-4608-a3eb-88695b05c6c2.png',
iconPinkUp: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/5bc84dff-e120-4d4b-a33e-25d68e065654.png',
iconPinkDown: 'https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/ff2c2c9d-694a-4adf-b737-66b07f4a63ae.png',
};
},
onLoad(options) {
const systemInfo = uni.getSystemInfoSync();
this.statusBarHeight = systemInfo.statusBarHeight;
this.navHeight = this.statusBarHeight + 44;
if (options.id) {
this.activeId = options.id;
}
this.getFirstClass();
// 初始化时一并获取抽屉内的级联字典数据
this.loadFilterCategories();
},
methods: {
// 跳转搜索页
goToSearch() {
uni.navigateTo({
url: '/pages/search_common/search?type=brand' // 告诉搜索页,我要搜品牌
});
},
// 加载一级分类并自动组装其对应的二级分类,兼容 state === 1
async loadFilterCategories() {
try {
const syrId = uni.getStorageSync('syrId') || 1;
const res = await request.post('/sj/firstclass', { id: syrId })
if ((res.code === 200 || res.state === 1) && res.data) {
const firstClasses = res.data;
// 并发请求所有的二级分类
const promises = firstClasses.map(async (first) => {
try {
const subRes = await request.post('/sj/secondclass', { id: first.id })
return {
id: first.id,
title: first.title,
children: ((subRes.code === 200 || subRes.state === 1) && subRes.data) ? subRes.data : []
}
} catch (e) {
return { id: first.id, title: first.title, children: [] }
}
});
const filterData = await Promise.all(promises);
// 过滤掉没有子分类的项,避免面板出现光秃秃的标题
this.brandFilterData = filterData.filter(group => group.children.length > 0);
} else {
this.brandFilterData = []
}
} catch (error) {
console.error('获取分类字典失败', error)
}
},
// ============ 排序逻辑 ============
toggleSort(type) {
if (type === 'time') {
if (this.orderType === 1) {
this.orderType = 2;
} else if (this.orderType === 2) {
this.orderType = 0;
} else {
this.orderType = 1;
}
} else if (type === 'view') {
if (this.orderType === 3) {
this.orderType = 4;
} else if (this.orderType === 4) {
this.orderType = 0;
} else {
this.orderType = 3;
}
}
this.refreshBrandList();
},
// ============ 页面内分类逻辑 ============
getFirstClass() {
request.post("/sj/firstclass").then((res) => {
this.tabs = res.data || [];
if (this.tabs.length && !this.activeId) {
this.activeId = this.tabs[0].id;
}
this.getSecondClassList();
this.refreshBrandList();
});
},
getSecondClassList() {
if (!this.activeId) return;
request.post('/sj/secondclass', { id: this.activeId }).then((res) => {
this.iconTabs = res.data || [];
});
},
selectSecondClass(id) {
if (this.currentSecondClass === id) {
this.currentSecondClass = "";
} else {
this.currentSecondClass = id;
}
// 页面上点击了圆形图标,则清空抽屉里的选择
this.selectedSecondIds = [];
this.refreshBrandList();
},
tabClick(id) {
if (this.activeId === id) return;
this.activeId = id;
this.currentSecondClass = "";
this.selectedSecondIds = [];
this.getSecondClassList();
this.refreshBrandList();
},
// ============ 刷新列表核心 ============
refreshBrandList() {
// 如果抽屉里选了分类,优先传抽屉的参数;否则传圆形图标选中的分类
const targetSecondClass = this.selectedSecondIds.length > 0
? this.selectedSecondIds.join(',')
: this.currentSecondClass;
const params = {
first_class: this.activeId || undefined,
second_class: targetSecondClass || undefined,
// 如果 orderType 是 0则设为 undefined使其不传给后端
order_type: this.orderType === 0 ? undefined : this.orderType
};
Object.keys(params).forEach(key => {
if (params[key] === undefined) delete params[key];
});
if (this.$refs.brandListRef) {
// CommonList 会合并旧 queryData清空筛选时需要同步移除旧字段。
['first_class', 'second_class', 'order_type'].forEach(key => {
if (!Object.prototype.hasOwnProperty.call(params, key) && this.$refs.brandListRef.queryData) {
this.$delete(this.$refs.brandListRef.queryData, key);
}
});
this.$refs.brandListRef.manualRefresh(params);
}
},
enrichedBrandList(list) {
if (!list || !list.length) return [];
return list.map(brand => {
const tagKeys = [];
if (brand.franchise_state === 1) tagKeys.push('franchise');
if (brand.student_state === 1) tagKeys.push('recruit');
if (tagKeys.length === 0) tagKeys.push('more');
return {
...brand,
name: brand.name,
bgSrc: brand.cover_img || 'https://dummyimage.com/300x200/ccc/fff.png',
avatar: brand.logo_img || 'https://dummyimage.com/100x100/ccc/fff.png',
_tagKeys: tagKeys
};
});
},
handleBrandClick(brand) {
uni.navigateTo({
url: `/pages/brand/detail?id=${brand.id}`
});
},
handleDataLoaded(data) {
console.log("品牌列表加载完成", data);
}
}
};
</script>
<style lang="less" scoped>
// 保证右侧搜索图标大小合适
::v-deep .icon-headle {
width: 32rpx !important;
height: 32rpx !important;
}
// 一级类目 Tab 样式微调
.service-first-tab {
border-bottom: none;
padding-bottom: 27rpx;
position: relative;
z-index: 101;
}
::v-deep .service-first-tab {
box-shadow: none !important;
}
/* ================= 抽屉下拉样式 ================= */
.filter-panel {
position: fixed;
left: 0;
right: 0;
bottom: 0;
z-index: 100;
pointer-events: none;
overflow: hidden;
&.show {
pointer-events: auto;
.filter-mask {
opacity: 1;
}
.filter-container {
transform: translateY(0);
}
}
.filter-mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.4);
opacity: 0;
transition: opacity 0.3s ease-in-out;
}
.filter-container {
position: absolute;
top: 0;
left: 0;
right: 0;
background: #fff;
border-radius: 0 0 30rpx 30rpx;
padding: 140rpx 30rpx 40rpx;
display: flex;
flex-direction: column;
box-shadow: 0 10rpx 20rpx rgba(0, 0, 0, 0.05);
transform: translateY(-100%);
transition: transform 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
}
}
.filter-scroll {
max-height: 50vh;
}
.filter-group {
margin-bottom: 30rpx;
.group-title {
font-weight: 500;
font-size: 28rpx;
color: #333333;
line-height: 40rpx;
margin-bottom: 20rpx;
}
.pill-list {
display: flex;
flex-wrap: wrap;
gap: 20rpx 10rpx;
/* 控制行间距和列间距 */
}
}
/* 通用胶囊按钮 (一行四个) */
.pill-item {
width: calc(25% - 8rpx);
/* 精确计算一行四个 */
height: 58rpx;
background: #F5F5F5;
font-weight: 400;
font-size: 24rpx;
/* 字号略小以防溢出 */
color: #333333;
line-height: 37rpx;
/* flex 居中文字 */
display: flex;
align-items: center;
justify-content: center;
border-radius: 12rpx;
transition: all 0.3s;
box-sizing: border-box;
white-space: nowrap;
&.active {
background: #FFF0F2;
color: #FF4767;
border: 1rpx solid #FFB0BD;
}
}
.filter-footer {
display: flex;
justify-content: space-between;
margin-top: 40rpx;
.reset-btn,
.confirm-btn {
width: 47%;
text-align: center;
padding: 22rpx 0;
border-radius: 40rpx;
font-size: 28rpx;
}
.reset-btn {
background: #F5F5F5;
color: #666;
}
.confirm-btn {
background: #FF4767;
color: #fff;
}
}
/* ================= 其他页面样式 ================= */
// 二级类目图标行
.icon-tabs {
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
align-items: center;
column-gap: 36rpx;
row-gap: 30rpx;
background: transparent;
padding: 0 0 0 30rpx;
margin-bottom: 30rpx;
}
.icon-tab {
display: flex;
flex-direction: column;
align-items: center;
}
.icon-img {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
border: 2rpx solid transparent;
}
.icon-text {
margin-top: 10rpx;
font-weight: 400;
font-size: 24rpx;
color: #333333;
line-height: 33rpx;
text-align: left;
}
.icon-tab.active .icon-text {
color: #FF4767;
line-height: 33rpx;
}
.icon-tab.active .icon-img {
border: 2rpx solid #FF4767;
}
// 排序栏样式
.sort-bar {
display: flex;
align-items: center;
padding: 0 30rpx;
margin-bottom: 24rpx;
gap: 100rpx;
.sort-item {
display: flex;
align-items: center;
.sort-text {
font-weight: 400;
font-size: 26rpx;
color: #666666;
line-height: 37rpx;
margin-right: 6rpx;
&.active {
color: #FF4767;
font-weight: 500;
}
}
.arrows {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.arrow-icon {
width: 13rpx;
height: 8rpx;
margin: 2rpx 0;
}
}
}
}
// 品牌卡片网格
.zhanwei {
background-color: #f5f5f5;
padding: 20rpx 0 0 0;
border-radius: 20rpx 20rpx 0rpx 0rpx;
}
.brand-grid {
background-color: #ffffff;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
padding: 20rpx 24rpx;
row-gap: 24rpx;
border-radius: 20rpx 20rpx 0rpx 0rpx;
.brand-card-wrap {
width: 48.5%;
}
}
.common-list {
::v-deep .list-container {
padding: 0;
}
::v-deep .list-scroll {
margin-top: 0rpx;
}
}
.service-list {
background-color: #f5f5f5;
border-radius: 20rpx 20rpx 0 0;
}
.nav-img-size::v-deep .icon-headle {
width: 36rpx !important;
height: 36rpx !important;
}
</style>