mrr.sj.front/components/common/CommonFilter.vue

489 lines
12 KiB
Vue
Raw Normal View History

2026-03-24 11:45:13 +08:00
<template>
<view class="common-filter">
<!-- 筛选触发按钮服务时间 + 主筛选 -->
<view class="filter-btns-wrap">
<!-- 服务时间按钮 -->
<view class="filter-trigger time-trigger" @click="toggleTimePopup">
<text class="filter-text" :class="{ active: timePopupShow }">
{{ timeBtnText }}
</text>
<image
:src="!timePopupShow ? sqIcon : zkIcon"
mode="aspectFit"
class="time-icon"
></image>
</view>
<!-- 原筛选按钮 -->
<view class="filter-trigger main-filter-trigger time-trigger" @click="toggleMainPopup">
<text class="filter-text" :class="{ active: mainPopupShow }">
{{ filterBtnText }}
</text>
<image
:src="!mainPopupShow ? sqIcon : zkIcon"
mode="aspectFit"
class="time-icon"
></image>
</view>
</view>
<filterPopup
ref="filterPopupRef"
v-model="mainPopupShow"
:filterList="filterList"
@reset="resetFilter"
@sure="$emit('search')"
>
<filterCard
v-for="info in filterList"
:info="info"
v-model="value"
@selectDetail="(value) => selectDetail(info.type, value)"
:isSingle="true"
:infoDetailList="info"
>
<view class="price-input" v-if="info.type == 'price'">
<input
type="number"
:value="value.start_price"
@input="(e) => selectDetail('start_price', [e.detail.value])"
placeholder="最低价"
class="price-input-field"
/>
<text class="price-separator"></text>
<input
type="number"
:value="value.end_price"
@input="(e) => selectDetail('end_price', [e.detail.value])"
placeholder="最高价"
class="price-input-field"
/>
</view>
</filterCard>
</filterPopup>
<view class="time-filter-popup" :class="{ show: timePopupShow }">
<view class="time-filter-content">
<view
class="time-option"
v-for="(item, index) in timeOptions"
:key="index"
:class="{ active: selectedTimeOption === index }"
@click="changeTime(index)"
>
<text class="time-text">{{ item.text }}</text>
<!-- <text class="time-discount" v-if="item.discount">{{ item.discount }}</text> -->
</view>
</view>
</view>
</view>
</template>
<script>
import filterPopup from "@/components/filter-popup/filter-popup.vue";
import filterCard from "@/components/filterCard/filterCard.vue";
export default {
name: "CommonFilter",
props: {
// 服务时间按钮文本
timeBtnText: {
type: String,
default: "服务时间",
},
// 服务时间展开/收起图标
sqIcon: {
type: String,
default:
"https://mrrplus.oss-cn-beijing.aliyuncs.com/wxstaic/images/sq_icon.png",
},
zkIcon: {
type: String,
default:
"https://mrrplus.oss-cn-beijing.aliyuncs.com/wxstaic/images/zk_icon.png",
},
// 主筛选按钮文本
filterBtnText: {
type: String,
default: "筛选",
},
// 主筛选图标
filterIcon: {
type: String,
default:
"https://mrrplus.oss-cn-beijing.aliyuncs.com/wxstaic/images/filter_icon.png",
},
filterDetailsLists: {
type: Array,
default: () => [
{
id: 2,
title: "价格",
type: "price",
details: [
{
id: 1,
name: "0-10元",
value: "0-10",
},
{
id: 2,
name: "10-30元",
value: "10-30",
},
{
id: 3,
name: "30-50元",
value: "30-50",
},
{
id: 4,
name: "50-100元",
value: "50-100",
},
{
id: 5,
name: "100-300元",
value: "100-300",
},
{
id: 6,
name: "300+",
value: "300-",
},
],
},
{
id: 3,
title: "排序",
type: "ordersort",
details: [
{
id: 1,
name: " 销量最高",
value: "1",
},
{
id: 2,
name: "价格最高",
value: "2",
},
{
id: 3,
name: "价格最低",
value: "3",
},
],
},
{
id: 4,
title: "服务类型",
type: "server_kind",
details: [
{
id: 1,
name: " 到家",
value: "1",
},
{
id: 2,
name: "到店",
value: "2",
},
],
},
],
},
value: {
type: Object,
default: () => {},
},
},
components: { filterPopup, filterCard },
computed: {
filterList() {
return this.filterDetailsLists.map((item) => {
if (item.type == "price") {
return {
...item,
defaultValue: [
`${this.value.start_price || ""}-${this.value.end_price || ""}`,
],
};
}
return {
...item,
defaultValue: [this.value[item.type]],
};
});
},
},
data() {
return {
timePopupShow: false, // 服务时间弹框显示状态(当前模板未实现弹框内容)
mainPopupShow: false, // 主筛选弹框显示状态(当前模板未实现弹框内容)
timeOptions: [
{ text: "今日可约" },
{ text: "近两日可约", discount: "64.31%" },
{ text: "近三日可约" },
],
selectedTimeOption: undefined,
};
},
methods: {
changeTime(index) {
this.selectedTimeOption = index;
this.selectDetail("date", [this.getDate(index)]);
this.$emit("search");
this.timePopupShow = false;
},
getDate(index) {
//今天的时间
var day1 = new Date();
day1.setTime(day1.getTime());
var m1 = day1.getMonth() + 1;
if (m1 <= 9) {
m1 = "0" + m1;
}
var d1 = day1.getDate();
if (d1 <= 9) {
d1 = "0" + d1;
}
var s1 = day1.getFullYear() + "-" + m1 + "-" + d1;
//明天的时间
var day2 = new Date();
day2.setTime(day2.getTime() + 24 * 60 * 60 * 1000);
var m2 = day2.getMonth() + 1;
if (m2 <= 9) {
m2 = "0" + m2;
}
var d2 = day2.getDate();
if (d2 <= 9) {
d2 = "0" + d2;
}
var s2 = day2.getFullYear() + "-" + m2 + "-" + d2;
//后天的时间
var day3 = new Date();
day3.setTime(day3.getTime() + 24 * 60 * 60 * 1000 * 2);
var m3 = day3.getMonth() + 1;
if (m3 <= 9) {
m3 = "0" + m3;
}
var d3 = day3.getDate();
if (d3 <= 9) {
d3 = "0" + d3;
}
var s3 = day3.getFullYear() + "-" + m3 + "-" + d3;
if (index == 0) {
return [`${s1}`];
} else if (index == 1) {
return [`${s1}`, `${s2}`];
} else if (index == 2) {
return [`${s1}`, `${s2}`, `${s3}`];
}
},
resetFilter() {
const resetObj = {};
this.filterDetailsLists.forEach((it) => {
if (it.type === "price") {
resetObj.start_price = undefined;
resetObj.end_price = undefined;
} else {
resetObj[it.type] = undefined;
}
});
this.$emit("input", {
...this.value,
...resetObj,
});
this.$emit("search");
},
// 切换服务时间弹框(弹框内容需后续补充)
toggleTimePopup() {
this.timePopupShow = !this.timePopupShow;
if (this.timePopupShow) this.mainPopupShow = false; // 互斥显示
},
// 切换主筛选弹框(弹框内容需后续补充)
toggleMainPopup() {
if (this.$refs.filterPopupRef) {
if (!this.mainPopupShow) {
this.timePopupShow = false;
this.mainPopupShow = true;
} else {
this.timePopupShow = false; // 互斥显示
}
}
},
selectDetail(type, value) {
console.log(type, value);
if (type == "price") {
if (value[0]) {
let priceList = value[0].split("-");
this.$emit("input", {
...this.value,
start_price: priceList[0],
end_price: priceList[1],
});
} else {
this.$emit("input", {
...this.value,
start_price: undefined,
end_price: undefined,
});
}
} else {
this.$emit("input", {
...this.value,
[type]: value[0],
});
}
},
},
};
</script>
<style lang="less" scoped>
.common-filter {
position: relative;
z-index: 900;
background-color: #fff;
height: 102rpx;
display: flex;
align-items: center;
/* 服务时间弹框样式 */
.time-filter-popup {
width: 750rpx;
background-color: #ffffff;
height: 0;
opacity: 0;
transition: all 0.3s ease;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
visibility: hidden;
border-radius: 0 0 20rpx 20rpx;
overflow: hidden;
position: absolute;
z-index: 10;
top: 102rpx;
left: 0;
right: 0;
}
.time-filter-popup.show {
opacity: 1;
height: 320rpx;
visibility: visible;
}
.time-filter-content {
padding: 0;
}
.time-option {
display: flex;
justify-content: space-between;
align-items: center;
padding: 32rpx;
background-color: #ffffff;
position: relative;
}
.time-option:not(:last-child)::after {
content: "";
position: absolute;
left: 32rpx;
right: 32rpx;
bottom: 0;
height: 1rpx;
background-color: #eeeeee;
}
.time-option.active {
background-color: #fff5f6;
}
.time-option.active .time-text {
color: #E8101E;
font-weight: 500;
}
.time-text {
font-size: 28rpx;
color: #333333;
}
.time-discount {
font-size: 24rpx;
color: #E8101E;
padding: 4rpx 12rpx;
background-color: #fff5f6;
border-radius: 20rpx;
}
}
/* 筛选按钮容器:横向排列两个按钮,控制间距和内边距 */
.filter-btns-wrap {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
gap: 24rpx;
padding: 0 24rpx;
}
/* 基础筛选按钮样式统一按钮的flex布局、对齐方式和行高 */
.filter-trigger {
display: flex;
align-items: center;
gap: 8rpx;
height: 60rpx;
line-height: 60rpx;
}
/* 按钮文本样式:默认灰色,选中时高亮 */
.filter-text {
font-size: 28rpx;
color: #666;
}
.active {
color: #E8101E; /* 选中态主题色 */
}
/* 服务时间按钮专属:控制下拉图标尺寸 */
.time-trigger .time-icon {
width: 16rpx;
height: 16rpx;
}
/* 主筛选按钮专属:控制筛选图标尺寸 */
.main-filter-trigger .filter-icon {
width: 32rpx;
height: 32rpx;
}
//价格区间样式
.price-input {
display: flex;
justify-content: space-between;
align-items: center;
width: 370rpx;
height: 80rpx;
background: #f3f6f8;
border-radius: 10rpx;
.price-input-field {
width: 166rpx;
height: 80rpx;
line-height: 50rpx;
text-align: center;
border-radius: 26rpx;
font-size: 26rpx;
font-weight: 400;
color: #3d3d3d;
}
.price-separator {
height: 3rpx;
width: 38rpx;
background-color: #dddddd;
}
}
</style>