Files
sweekar-app/components/araecode-popup.vue
T
2026-01-04 17:53:40 +08:00

167 lines
5.1 KiB
Vue

<template>
<!-- 区域号码选择 -->
<up-popup :show="isShow" round="20" closeable @close="close">
<view class="container flex flex-col px-[20px]">
<view class="title flex items-center justify-center mx-[15px]">
<text class="txt text-[16px] py-[15px] font-bold">{{ t('areaCode') }}</text>
</view>
<view class="search-box my-[10px]">
<up-search v-model="keyword" :showAction="false" :placeholder="t('areaCodePlace')" @change="handleKeywordChange"></up-search>
</view>
<!-- 主列表 -->
<view class="index-list relative overflow-hidden">
<scroll-view scroll-y :scroll-into-view="scrollIntoId" class="main-list h-[70vh] overflow-hidden" @scroll="handleScroll">
<template v-if="isEmpty(keyword)">
<view v-for="(group, index) in list" :key="index" :id="group.groupKey" class="group-container relative">
<!-- 吸顶标题 -->
<view class="group-title text-[14px] text-main py-[5px] sticky top-0 bg-white z-[999] sticky-title">
{{ group.name }}
</view>
<view v-for="(item, idx) in group.data" :key="idx" class="list-item text-main text-[14px] py-[10px]" @click="handleSelect(item)">
{{ `${item.name} (+${item.code})` }}
</view>
</view>
</template>
<view v-else v-for="(item, idx) in filterList" :key="idx" class="list-item text-main text-[14px] py-[10px]" @click="handleSelect(item)">
{{ `${item.name} (+${item.code})` }}
</view>
</scroll-view>
<!-- 右侧索引 -->
<view class="index-bar absolute top-0 right-0 py-[10px] gap-[10px] z-[9999]">
<view
v-for="(group, index) in list"
:key="index"
class="index-item text-center text-[12px] "
:class="currentIntoId === group.groupKey ? 'bg-[#e61e30] rounded-full text-white' : 'text-[#e61e30]'"
@click="handleIndexclick(group.groupKey)"
>
{{ group.groupKey }}
</view>
</view>
</view>
</view>
</up-popup>
</template>
<script setup>
import { nextTick, ref, watch } from 'vue';
import { onLoad, onReady } from '@dcloudio/uni-app';
import { useSystemInfo } from '@/hooks/useSystemInfo.js';
import { useI18n } from 'vue-i18n';
import { isEmpty } from '@/common/common.js';
import { apiWholeAreaCode } from '@/api/common.js';
const { t, locale } = useI18n();
const { computedDomHeight } = useSystemInfo();
const props = defineProps({
show: {
type: Boolean,
default: false,
},
});
// 获取区域码数据
const getAreaCodeList = async () => {
apiWholeAreaCode({ type: '' }).then((res) => {
if (res.success) {
list.value = res.data.codeGroups;
nextTick(() => {
calculateGroupPositions();
});
}
});
};
const isShow = ref(false);
watch(
() => props.show,
(newVal) => {
isShow.value = newVal;
if (newVal) getAreaCodeList();
},
{
immediate: true,
}
);
const emits = defineEmits(['close', 'select']);
const close = () => emits('close');
const keyword = ref('');
const filterList = ref([]);
const handleKeywordChange = (e) => {
if (!e) return (filterList.value = []);
const result = [];
for (let group of list.value) {
for (let item of group.data) {
const target = item.search?.replace(/\s+/g, '');
if (target.includes(e)) {
result.push(item);
}
}
}
filterList.value = uniqueByCode(result, 'code');
};
// 数组对象去重
const uniqueByCode = (arr, field) => {
const map = new Map(); // 用于存储已经出现过的 field
return arr.filter((item) => {
if (!map.has(item[field])) {
map.set(item[field], true); // 将 field 添加到 Map 中
return true; // 保留当前对象
}
return false; // 过滤掉重复对象
});
};
const handleSelect = (e) => {
emits('select', e);
};
// 数据
const list = ref([]);
const scrollIntoId = ref(''); // 当前滚动到的锚点ID
const currentIntoId = ref(''); // 当前的索引
const groupPositions = ref([]); // 存储每个组的顶部位置
// 点击索引跳转
const handleIndexclick = (title) => {
keyword.value = '';
scrollIntoId.value = title;
currentIntoId.value = title;
};
// 处理滚动事件
const handleScroll = (event) => {
const scrollTop = event.detail.scrollTop;
// 根据滚动位置判断当前吸顶的标题
for (let i = groupPositions.value.length - 1; i >= 0; i--) {
if (scrollTop > groupPositions.value[i].top) {
currentIntoId.value = groupPositions.value[i].title;
break;
}
}
};
// 计算每个组的顶部位置
const calculateGroupPositions = async () => {
let heightList = [];
for (let i = 0; i < list.value.length; i++) {
const group = list.value[i];
const data = await computedDomHeight(`#${group.groupKey}`);
if (data) {
heightList[i] = data.height || 0;
groupPositions.value.push({
title: group.groupKey,
top: i > 0 ? heightList.slice(0, i).reduce((pre, cur) => cur + pre, 0) : 0,
});
}
}
};
</script>
<style scoped lang="scss"></style>