Files
ks-app-employment-service/components/expected-station/expected-station.vue
2025-11-13 19:28:00 +08:00

351 lines
13 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 class="expected-station">
<view class="sex-search" v-if="search">
<uni-icons class="iconsearch" type="search" size="20"></uni-icons>
<input class="uni-input searchinput" confirm-type="search" />
</view>
<view class="sex-content">
<scroll-view ref="leftScroll" :show-scrollbar="false" :scroll-y="true" class="sex-content-left">
<view
v-for="item in copyTree"
:key="item.id"
class="left-list-btn"
:class="{ 'left-list-btned': item.id === leftValue.id }"
@click="changeStationLog(item)"
>
{{ item.label }}
<!-- <view class="positionNum" v-show="item.checkednumber">
{{ item.checkednumber }}
</view> -->
</view>
</scroll-view>
<scroll-view
:show-scrollbar="false"
:scroll-top="scrollTop"
@scroll="scrollTopBack"
:scroll-y="true"
class="sex-content-right"
@wheel="handleWheel"
>
<view v-for="item in rightValue" :key="item.id">
<view class="secondary-title">{{ item.label }}</view>
<view class="grid-sex">
<view
v-for="item in item.children"
:key="item.id"
:class="{ 'sex-right-btned': item.checked }"
class="sex-right-btn"
@click="addItem(item)"
>
{{ item.label }}
</view>
<!-- <view class="sex-right-btn sex-right-btned" @click="addItem()">客户经理</view>
<view class="sex-right-btn" @click="addItem()">客户经理</view> -->
</view>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
export default {
name: 'expected-station',
data() {
return {
leftValue: {},
rightValue: [],
stationCateLog: 0,
copyTree: [],
scrollTop: 0,
};
},
props: {
station: {
type: Array,
default: [],
},
search: {
type: Boolean,
default: true,
},
max: {
type: Number,
default: 5,
},
},
created() {
this.copyTree = this.station;
if (this.copyTree.length) {
this.leftValue = this.copyTree[0];
this.rightValue = this.copyTree[0].children;
}
},
watch: {
station(newVal) {
this.copyTree = this.station;
if (this.copyTree.length) {
this.leftValue = this.copyTree[0];
this.rightValue = this.copyTree[0].children;
}
},
},
methods: {
changeStationLog(item) {
this.leftValue = item;
this.rightValue = item.children;
this.scrollTop = 0;
// 确保左侧列表滚动到正确位置,让当前选中的标签可见
this.$nextTick(() => {
const index = this.copyTree.findIndex(i => i.id === item.id);
if (index !== -1 && this.$refs.leftScroll) {
// 计算需要滚动的距离每个选项高度约160rpx
const scrollTop = index * 160;
// 获取左侧列表的可见高度假设可见区域能显示约3-4个选项
const visibleHeight = 4 * 160; // 约4个选项的高度
// 确保选中的标签在可见区域内
let targetScrollTop = scrollTop;
// 如果选中的标签在底部,确保它不会滚动出可见区域
if (scrollTop > this.$refs.leftScroll.scrollHeight - visibleHeight) {
targetScrollTop = Math.max(0, this.$refs.leftScroll.scrollHeight - visibleHeight);
}
this.$refs.leftScroll.scrollTo({
top: targetScrollTop,
duration: 300
});
}
});
},
scrollTopBack(e) {
this.scrollTop = e.detail.scrollTop;
// 滚动时自动选中对应的左侧标签
const scrollTop = e.detail.scrollTop;
let currentSection = null;
let minDistance = Infinity;
// 遍历所有右侧的二级标题,找到当前最接近顶部的那个
this.rightValue.forEach((section, index) => {
// 估算每个section的位置假设每个section高度大约为 200rpx
const sectionTop = index * 200;
const distance = Math.abs(sectionTop - scrollTop);
if (distance < minDistance) {
minDistance = distance;
currentSection = section;
}
});
// 如果找到了对应的section并且不是当前选中的左侧标签则切换左侧标签
if (currentSection && this.leftValue.id !== currentSection.parentId) {
const parentItem = this.copyTree.find(item => item.id === currentSection.parentId);
if (parentItem) {
this.leftValue = parentItem;
// 确保左侧列表滚动到正确位置,让当前选中的标签可见
this.$nextTick(() => {
const index = this.copyTree.findIndex(i => i.id === parentItem.id);
if (index !== -1 && this.$refs.leftScroll) {
// 计算需要滚动的距离每个选项高度约160rpx
const scrollTop = index * 160;
// 获取左侧列表的可见高度假设可见区域能显示约3-4个选项
const visibleHeight = 4 * 160; // 约4个选项的高度
// 确保选中的标签在可见区域内
let targetScrollTop = scrollTop;
// 如果选中的标签在底部,确保它不会滚动出可见区域
if (scrollTop > this.$refs.leftScroll.scrollHeight - visibleHeight) {
targetScrollTop = Math.max(0, this.$refs.leftScroll.scrollHeight - visibleHeight);
}
this.$refs.leftScroll.scrollTo({
top: targetScrollTop,
duration: 300
});
}
});
}
}
},
handleWheel(e) {
// 处理鼠标滚轮事件,让右侧内容可以滚动
e.preventDefault();
const delta = e.deltaY || e.wheelDelta;
// 更平滑的滚动,根据滚轮速度调整滚动量
const scrollAmount = Math.abs(delta) > 100 ? 80 : 40;
const direction = delta > 0 ? 1 : -1;
// 更新scrollTop来模拟滚动
this.scrollTop += scrollAmount * direction;
// 确保scrollTop在合理范围内
this.scrollTop = Math.max(0, this.scrollTop);
// 触发scroll事件来更新左侧标签选中状态
this.$nextTick(() => {
this.scrollTopBack({ detail: { scrollTop: this.scrollTop } });
});
},
addItem(item) {
let titiles = [];
let labels = [];
let count = 0;
// 先统计已选中的职位数量
for (const firstLayer of this.copyTree) {
for (const secondLayer of firstLayer.children) {
for (const thirdLayer of secondLayer.children) {
if (thirdLayer.checked) {
count++;
}
}
}
}
for (const firstLayer of this.copyTree) {
firstLayer.checkednumber = 0; // 初始化当前层级的 checked 计数
for (const secondLayer of firstLayer.children) {
for (const thirdLayer of secondLayer.children) {
// **如果是当前点击的职位**
if (thirdLayer.id === item.id) {
if (!thirdLayer.checked && count >= 5) {
// 如果已经选了 5 个,并且点击的是未选中的职位,则禁止选择
uni.showToast({
title: `最多选择5个职位`,
icon: 'none',
});
continue; // 跳过后续逻辑,继续循环
}
// 切换选中状态
thirdLayer.checked = !thirdLayer.checked;
}
// 统计被选中的第三层节点
if (thirdLayer.checked) {
titiles.push(`${thirdLayer.id}`);
labels.push(`${thirdLayer.label}`);
firstLayer.checkednumber++; // 累加计数器
}
}
}
}
titiles = titiles.join(',');
labels = labels.join(',');
this.$emit('onChange', {
ids: titiles,
labels,
});
},
},
};
</script>
<style lang="stylus" scoped>
.secondary-title{
color: #333333
font-size: 28rpx
padding: 40rpx 0 10rpx 30rpx;
}
.expected-station{
width: 100%;
overflow: hidden;
display: flex;
flex-direction: column;
height: 100%
}
.sex-search
width: calc(100% - 28rpx - 28rpx);
padding: 10rpx 28rpx;
display: grid;
// grid-template-columns: 50rpx auto;
position: relative;
.iconsearch
position: absolute;
left: 40rpx;
top: 20rpx;
.searchinput
border-radius: 10rpx;
background: #FFFFFF;
padding: 10rpx 0 10rpx 58rpx;
.sex-content
background: #FFFFFF;
// border-radius: 20rpx;
width: 100%;
margin-top: 20rpx;
display: flex;
border-bottom: 2px solid #D9D9D9;
overflow: hidden;
height: 100%;
.sex-content-left
width: 198rpx;
padding: 20rpx 0 0 0;
.left-list-btn
padding: 0 40rpx 0 24rpx;
display: grid;
place-items: center;
height: 100rpx;
text-align: center;
color: #606060;
font-size: 28rpx;
position: relative
margin-top: 60rpx
.left-list-btn:first-child
margin-top: 0
// .positionNum
// position: absolute
// right: 0
// top: 50%;
// transform: translate(0, -50%)
// color: #FFFFFF
// background: #4778EC
// border-radius: 50%
// width: 36rpx;
// height: 36rpx;
.left-list-btned
color: #4778EC;
position: relative;
// .left-list-btned::after
// position: absolute;
// left: 20rpx;
// content: '';
// width: 7rpx;
// height: 38rpx;
// background: #4778EC;
// border-radius: 0rpx 0rpx 0rpx 0rpx;
.sex-content-right
// border-left: 2px solid #D9D9D9;
background: #F6F6F6;
flex: 1;
.grid-sex
display: grid;
grid-template-columns: 50% 50%;
place-items: center;
padding: 0 20rpx 40rpx 20rpx;
.sex-right-btn
width: 228rpx;
height: 80rpx;
font-size: 28rpx;
line-height: 41rpx;
text-align: center;
display: grid;
place-items: center;
border-radius: 12rpx;
margin-top: 30rpx;
background: #E8EAEE;
color: #606060;
.sex-right-btned
font-weight: 500
width: 224rpx;
height: 76rpx;
background: rgba(37,107,250,0.06);
border: 2rpx solid #256BFA;
color: #256BFA
</style>