2025-08-22 18:12:29 +08:00
|
|
|
<script setup>
|
2025-09-18 15:58:57 +08:00
|
|
|
import { ref, reactive, onMounted } from "vue";
|
2025-09-23 09:02:40 +08:00
|
|
|
import NetworkMap from "../card/NetworkMap.vue";
|
2025-08-22 18:12:29 +08:00
|
|
|
const state = reactive({
|
|
|
|
|
tabs: [
|
2025-09-18 15:58:57 +08:00
|
|
|
"公共服务站点 300",
|
|
|
|
|
"培训机构 130",
|
|
|
|
|
"咨询机构 220",
|
|
|
|
|
"教育中心 150",
|
|
|
|
|
"职业介绍所 180",
|
|
|
|
|
"就业服务中心 210"
|
2025-08-22 18:12:29 +08:00
|
|
|
],
|
|
|
|
|
activeIndex: 0
|
2025-09-18 15:58:57 +08:00
|
|
|
});
|
2025-08-22 18:12:29 +08:00
|
|
|
|
2025-09-18 15:58:57 +08:00
|
|
|
const scrollContainer = ref(null);
|
|
|
|
|
const canScrollLeft = ref(false);
|
|
|
|
|
const canScrollRight = ref(false);
|
2025-08-22 18:12:29 +08:00
|
|
|
|
|
|
|
|
// 检查滚动状态
|
|
|
|
|
const checkScroll = () => {
|
|
|
|
|
if (scrollContainer.value) {
|
2025-09-18 15:58:57 +08:00
|
|
|
const { scrollLeft, scrollWidth, clientWidth } = scrollContainer.value;
|
|
|
|
|
canScrollLeft.value = scrollLeft > 0;
|
|
|
|
|
canScrollRight.value = scrollLeft < scrollWidth - clientWidth - 1;
|
2025-08-22 18:12:29 +08:00
|
|
|
}
|
2025-09-18 15:58:57 +08:00
|
|
|
};
|
2025-08-22 18:12:29 +08:00
|
|
|
|
|
|
|
|
// 滚动到指定位置
|
|
|
|
|
const scrollTo = (direction) => {
|
2025-09-18 15:58:57 +08:00
|
|
|
if (!scrollContainer.value) return;
|
2025-08-22 18:12:29 +08:00
|
|
|
|
2025-09-18 15:58:57 +08:00
|
|
|
const container = scrollContainer.value;
|
|
|
|
|
const scrollAmount = 300; // 每次滚动量
|
2025-08-22 18:12:29 +08:00
|
|
|
|
2025-09-18 15:58:57 +08:00
|
|
|
if (direction === "left") {
|
|
|
|
|
container.scrollBy({ left: -scrollAmount, behavior: "smooth" });
|
2025-08-22 18:12:29 +08:00
|
|
|
} else {
|
2025-09-18 15:58:57 +08:00
|
|
|
container.scrollBy({ left: scrollAmount, behavior: "smooth" });
|
2025-08-22 18:12:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 滚动结束后检查状态
|
2025-09-18 15:58:57 +08:00
|
|
|
setTimeout(checkScroll, 300);
|
|
|
|
|
};
|
2025-08-22 18:12:29 +08:00
|
|
|
|
|
|
|
|
// 点击标签
|
|
|
|
|
const selectTab = (index) => {
|
2025-09-18 15:58:57 +08:00
|
|
|
state.activeIndex = index;
|
2025-08-22 18:12:29 +08:00
|
|
|
// 可选:自动滚动到选中标签
|
2025-09-18 15:58:57 +08:00
|
|
|
scrollToTab(index);
|
|
|
|
|
};
|
2025-08-22 18:12:29 +08:00
|
|
|
|
|
|
|
|
// 滚动到指定标签
|
|
|
|
|
const scrollToTab = (index) => {
|
2025-09-18 15:58:57 +08:00
|
|
|
if (!scrollContainer.value) return;
|
2025-08-22 18:12:29 +08:00
|
|
|
|
2025-09-18 15:58:57 +08:00
|
|
|
const container = scrollContainer.value;
|
|
|
|
|
const tab = container.children[index];
|
|
|
|
|
if (!tab) return;
|
2025-08-22 18:12:29 +08:00
|
|
|
|
2025-09-18 15:58:57 +08:00
|
|
|
const containerWidth = container.clientWidth;
|
|
|
|
|
const tabLeft = tab.offsetLeft;
|
|
|
|
|
const tabWidth = tab.offsetWidth;
|
2025-08-22 18:12:29 +08:00
|
|
|
|
|
|
|
|
container.scrollTo({
|
|
|
|
|
left: tabLeft - (containerWidth - tabWidth) / 2,
|
2025-09-18 15:58:57 +08:00
|
|
|
behavior: "smooth"
|
|
|
|
|
});
|
|
|
|
|
};
|
2025-08-22 18:12:29 +08:00
|
|
|
|
|
|
|
|
onMounted(() => {
|
2025-09-18 15:58:57 +08:00
|
|
|
checkScroll();
|
|
|
|
|
window.addEventListener("resize", checkScroll);
|
|
|
|
|
});
|
2025-08-22 18:12:29 +08:00
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
<div class="costomCaedWrapper">
|
|
|
|
|
<div class="horizontal-scroll-container">
|
|
|
|
|
<!-- 左侧滚动按钮 -->
|
2025-09-18 15:58:57 +08:00
|
|
|
<!-- <button-->
|
|
|
|
|
<!-- class="scroll-button left"-->
|
|
|
|
|
<!-- :class="{ visible: canScrollLeft }"-->
|
|
|
|
|
<!-- @click="scrollTo('left')"-->
|
|
|
|
|
<!-- >-->
|
|
|
|
|
<!-- <svg viewBox="0 0 24 24">-->
|
|
|
|
|
<!-- <path d="M15.41 16.59L10.83 12l4.58-4.59L14 6l-6 6 6 6 1.41-1.41z"/>-->
|
|
|
|
|
<!-- </svg>-->
|
|
|
|
|
<!-- </button>-->
|
2025-08-22 18:12:29 +08:00
|
|
|
|
|
|
|
|
<!-- 横向滚动区域 -->
|
2025-09-18 15:58:57 +08:00
|
|
|
<div ref="scrollContainer" class="scroll-area" @scroll="checkScroll">
|
2025-08-22 18:12:29 +08:00
|
|
|
<div
|
|
|
|
|
v-for="(tab, index) in state.tabs"
|
|
|
|
|
:key="index"
|
|
|
|
|
class="tab-item"
|
|
|
|
|
:class="{ active: state.activeIndex === index }"
|
|
|
|
|
@click="selectTab(index)"
|
|
|
|
|
>
|
|
|
|
|
{{ tab }}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 右侧滚动按钮 -->
|
2025-09-18 15:58:57 +08:00
|
|
|
<!-- <button-->
|
|
|
|
|
<!-- class="scroll-button right"-->
|
|
|
|
|
<!-- :class="{ visible: canScrollRight }"-->
|
|
|
|
|
<!-- @click="scrollTo('right')"-->
|
|
|
|
|
<!-- >-->
|
|
|
|
|
<!-- <svg viewBox="0 0 24 24">-->
|
|
|
|
|
<!-- <path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"/>-->
|
|
|
|
|
<!-- </svg>-->
|
|
|
|
|
<!-- </button>-->
|
2025-08-22 18:12:29 +08:00
|
|
|
</div>
|
|
|
|
|
|
2025-09-23 09:02:40 +08:00
|
|
|
<NetworkMap />
|
2025-08-22 18:12:29 +08:00
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
2025-09-18 15:58:57 +08:00
|
|
|
<style lang="scss" scoped>
|
2025-08-22 18:12:29 +08:00
|
|
|
.costomCaedWrapper {
|
|
|
|
|
.echart {
|
|
|
|
|
margin-top: 1.5vw;
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: auto;
|
|
|
|
|
display: block;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.horizontal-scroll-container {
|
|
|
|
|
position: relative;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
width: 100%;
|
|
|
|
|
max-width: 1200px;
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.scroll-area {
|
|
|
|
|
display: flex;
|
|
|
|
|
overflow-x: auto;
|
|
|
|
|
scroll-behavior: smooth;
|
|
|
|
|
scrollbar-width: none; /* Firefox */
|
|
|
|
|
-ms-overflow-style: none; /* IE/Edge */
|
|
|
|
|
flex: 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.scroll-area::-webkit-scrollbar {
|
|
|
|
|
display: none; /* Chrome/Safari */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.tab-item {
|
|
|
|
|
flex: 0 0 auto;
|
|
|
|
|
margin: 0 8px;
|
|
|
|
|
width: 6.771vw;
|
|
|
|
|
height: 1.875vw;
|
|
|
|
|
text-align: center;
|
|
|
|
|
font-size: 0.729vw;
|
|
|
|
|
line-height: 1.875vw;
|
|
|
|
|
background: url("~@/assets/recruitment/tabs_bg.svg") no-repeat center center;
|
|
|
|
|
background-size: 100% 100%;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.tab-item.active {
|
|
|
|
|
background-image: url("~@/assets/recruitment/tabs_bg_active.svg");
|
|
|
|
|
color: white;
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.tab-item:hover {
|
|
|
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.scroll-button {
|
|
|
|
|
position: absolute;
|
|
|
|
|
top: 50%;
|
|
|
|
|
transform: translateY(-50%);
|
|
|
|
|
width: 1.875vw;
|
|
|
|
|
height: 1.875vw;
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
background: #0b1318;
|
|
|
|
|
border: 1px solid #0b1318;
|
|
|
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
opacity: 0;
|
|
|
|
|
transition: opacity 0.3s;
|
|
|
|
|
z-index: 10;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.scroll-button.visible {
|
|
|
|
|
opacity: 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.scroll-button.left {
|
|
|
|
|
left: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.scroll-button.right {
|
|
|
|
|
right: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.scroll-button svg {
|
|
|
|
|
width: 24px;
|
|
|
|
|
height: 24px;
|
|
|
|
|
fill: #666;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.scroll-button:hover {
|
|
|
|
|
background: #f0f0f0;
|
|
|
|
|
}
|
|
|
|
|
</style>
|