Files
qingdao-employment-service/components/selectFilter/selectFilter2col.vue
2025-11-07 11:30:07 +08:00

346 lines
9.1 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>
<uni-popup
ref="popup"
type="bottom"
borderRadius="10px 10px 0 0"
background-color="#FFFFFF"
@maskClick="maskClickFn"
:mask-click="maskClick"
class="popup-fix"
>
<view class="popup-content">
<view class="popup-header">
<view class="btn-cancel" @click="cancel">取消</view>
<view class="title">
<text>{{ title }}</text>
</view>
<view class="btn-confirm"></view>
</view>
<view class="popup-list">
<view class="content-wrapper">
<scroll-view class="filter-nav" scroll-y>
<view
v-for="(item, index) in filterOptions"
:key="index"
class="nav-item button-click"
:class="{ active: activeTab === item.key }"
@click="scrollTo(item.key)"
>
{{ item.label }}
</view>
</scroll-view>
<scroll-view class="filter-content" :scroll-into-view="activeTab" scroll-y>
<template v-for="(item, index) in filterOptions" :key="index">
<view class="content-item">
<view class="item-title" :id="item.key">{{ item.label }}</view>
<view class="check-content">
<view
v-for="option in item.options"
:key="option.value"
class="checkbox-item button-click"
:class="{
checkedstyle: activeValue === option.value,
}"
@click="handleItemClick(option)"
>
<text class="option-label">{{ option.label }}</text>
</view>
</view>
</view>
</template>
</scroll-view>
</view>
</view>
</view>
</uni-popup>
</template>
<script setup>
import { ref, reactive, nextTick, onBeforeMount } from 'vue';
import useDictStore from '@/stores/useDictStore';
const { getTransformChildren } = useDictStore();
const area = ref(true);
const maskClick = ref(false);
const maskClickFn = ref(null);
const title = ref('标题');
const confirmCallback = ref(null);
const cancelCallback = ref(null);
const changeCallback = ref(null);
const popup = ref(null);
// MODIFIED: 新增 ref用于存储当前激活的选项值
const activeValue = ref(null);
const activeTab = ref('');
const filterOptions = ref([]);
const listData = ref([]);
// MODIFIED: open 方法增加一个 currentValue 参数
const open = (newConfig = {}) => {
const {
title: configTitle,
success,
cancel,
change,
data,
maskClick: configMaskClick = false,
currentValue, // MODIFIED: 接收父组件传入的当前值
} = newConfig;
// reset();
if (configTitle) title.value = configTitle;
if (typeof success === 'function') confirmCallback.value = success;
if (typeof cancel === 'function') cancelCallback.value = cancel;
if (typeof change === 'function') changeCallback.value = change;
if (Array.isArray(data)) listData.value = data;
// MODIFIED: 将父组件传入的值
activeValue.value = currentValue;
if (configMaskClick) {
maskClick.value = configMaskClick;
maskClickFn.value = cancel;
}
getoptions();
nextTick(() => {
popup.value?.open();
});
};
const close = () => {
popup.value?.close();
};
const cancel = () => {
handleClick(cancelCallback.value, null);
};
const handleClick = async (callback, selectedItem) => {
if (typeof callback !== 'function') {
close();
return;
}
try {
const result = await callback(selectedItem);
if (result !== false) close();
} catch (error) {
console.error('Callback execution error:', error);
}
};
const handleItemClick = (option) => {
// MODIFIED: 点击时,更新本地的 activeValue
activeValue.value = option.value;
// 立即调用回调并传递所选的完整 option
handleClick(confirmCallback.value, option);
};
const scrollTo = (key) => {
activeTab.value = key;
};
function getoptions() {
filterOptions.value = transformRegionalData(listData.value);
activeTab.value = listData.value[0].key;
}
const reset = () => {
maskClick.value = false;
confirmCallback.value = null;
cancelCallback.value = null;
changeCallback.value = null;
// MODIFIED: 重置时也清空 activeValue
activeValue.value = null;
};
function transformRegionalData(sourceData) {
const options = sourceData.map((region, index) => {
const ls = region.areaList.map((commercial) => ({
...commercial,
text: commercial.commercialAreaName,
label: commercial.commercialAreaName,
value: commercial.commercialAreaId,
key: commercial.commercialAreaId,
listClass: 'default',
status: 'default',
}));
return {
label: region.regionalName,
key: 'lx' + region.regionalId,
options: ls,
};
});
return options;
}
// 暴露方法给父组件
defineExpose({
open,
close,
});
</script>
<style lang="scss" scoped>
/* 样式表无变化,保持原样即可 */
.popup-fix {
position: fixed !important;
left: 0;
right: 0;
bottom: 0;
top: 0;
height: 100vh;
z-index: 9999;
}
.popup-content {
color: #000000;
height: 80vh;
}
.popup-bottom {
display: none;
}
.popup-list {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-items: center;
justify-content: space-evenly;
height: calc(80vh - 100rpx);
overflow: hidden;
.picker-view {
width: 100%;
height: 500rpx;
margin-top: 20rpx;
.uni-picker-view-mask {
background: rgba(0, 0, 0, 0);
}
.item {
line-height: 84rpx;
height: 84rpx;
text-align: center;
font-weight: 400;
font-size: 32rpx;
color: #cccccc;
}
.item-active {
color: #333333;
}
.uni-picker-view-indicator:after {
border-color: #e3e3e3;
}
.uni-picker-view-indicator:before {
border-color: #e3e3e3;
}
}
}
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 40rpx 40rpx 10rpx 40rpx;
.title {
font-weight: 500;
font-size: 36rpx;
color: #333333;
text-align: center;
}
.btn-cancel {
font-weight: 400;
font-size: 32rpx;
color: #666d7f;
line-height: 38rpx;
}
.btn-confirm {
font-weight: 400;
font-size: 32rpx;
color: #256bfa;
min-width: 60rpx;
}
}
.content-wrapper {
flex: 1;
display: flex;
overflow: hidden;
height: 100%;
}
.filter-nav {
width: 200rpx;
background-color: #ffffff;
.nav-item {
height: 100rpx;
line-height: 100rpx;
text-align: center;
font-weight: 400;
font-size: 28rpx;
color: #666d7f;
&.active {
font-weight: 500;
font-size: 28rpx;
color: #256bfa;
}
}
}
.filter-content {
flex: 1;
padding: 20rpx;
background-color: #f6f6f6;
.content-item {
margin-top: 30rpx;
.item-title {
font-weight: 400;
font-size: 28rpx;
color: #333333;
margin-bottom: 15rpx;
}
}
.content-item:first-child {
margin-top: 0rpx;
}
.check-content {
display: grid;
gap: 16rpx;
grid-template-columns: repeat(auto-fill, minmax(180rpx, 1fr));
place-items: stretch;
.checkbox-item {
display: flex;
align-items: center;
text-align: center;
background-color: #d9d9d9;
min-width: 0;
padding: 0 10rpx;
height: 80rpx;
background: #e8eaee;
border-radius: 12rpx 12rpx 12rpx 12rpx;
.option-label {
font-size: 28rpx;
width: 100%;
white-space: nowrap;
overflow: hidden;
}
}
/* 这个样式现在会根据 activeValue 动态应用 */
.checkedstyle {
height: 76rpx;
background: rgba(37, 107, 250, 0.06);
border-radius: 12rpx 12rpx 12rpx 12rpx;
border: 2rpx solid #256bfa;
color: #256bfa;
}
}
}
</style>