初始化项目模板
This commit is contained in:
1 parent
80fd6a1d4b
commit
b3a69a1f27
69 files changed
+11088
No files matched your search
@@ -0,0 +1,166 @@
|
||||
<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>
|
||||
Reference in new issue
Block a user