Files
sociology_app/uni_modules/sx-address-picker/components/sx-address-picker/sx-address-picker.vue
2024-05-17 18:02:49 +08:00

413 lines
12 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>
<uni-popup ref="popup" type="bottom" @change="popChange">
<view class="sx-address-picker">
<view class="sx-address-picker__close">
<uni-icons
class="absolute"
size="20"
color="#ccc"
type="closeempty"
@click="$refs.popup.close"
></uni-icons>
</view>
<view class="sx-address-picker__title"> 请选择所在地区 </view>
<!-- 已选择区域 -->
<uni-list v-for="item in activeItems" :key="item.code" :border="false">
<uni-list-item show-arrow clickable @click="selectLevel(item)">
<template v-slot:header>
<view :class="activeLevel === item.level - 1 ? 'primary-text' : ''"
>{{ item.name || selectTitle }}
</view>
</template>
</uni-list-item>
</uni-list>
<view class="sx-address-picker--divider"></view>
<view class="sx-address-picker__list">
<template v-if="activeLevel === -1">
<!-- 中国/海外切换 -->
<!-- <radio-group class="sx-address-picker__list-tab" @change="typeChange">
<label
v-for="(item, index) in worlds"
:key="item"
:class="
world == index ? 'sx-address-picker__list-tab--active' : ''
"
>
<radio
class="sx-address-picker__list-tab--hide"
:checked="world === item"
:value="index + ''"
/><text>{{ item }}</text>
</label>
</radio-group> -->
<!-- 后续计划TODO 常用城市 -->
<!-- <view class="font-5 font-weight-500 mb-4">
{{quickTitle}}
</view>
<radio-group class="flex flex-wrap" @change="quickIndex = $event.detail.value">
<label class="mr-3" v-for="(item,index) in quickList" :key="item"
:class="world == index? 'active':''">
<radio class="none" :checked="world === item" :value="index + ''" />
<view class="radius bg-445 px-4 py-1 mb-3">{{item}}</view>
</label>
</radio-group> -->
</template>
<view class="sx-address-picker__list-title">
{{ selectTitle }}
</view>
<view class="sx-address-picker__list-content" @click="reGetList">
<uni-load-more
v-if="loadingStatus !== 'more'"
:status="loadingStatus"
:content-text="{ contentnomore: '加载失败请点击重试' }"
></uni-load-more>
<!-- 省市区选择 -->
<uni-list v-if="world == 0" :border="false">
<uni-list-item
v-for="(item, index) in currentList"
:key="item.code"
:title="item.name"
:border="false"
clickable
@click="selectHandle(item, index)"
>
<template v-slot:footer>
<uni-icons
v-if="
activeItems[item.level]
? activeItems[item.level].code === item.code
: false
"
type="checkmarkempty"
class="sx-address-picker__list-tab--active"
></uni-icons>
</template>
</uni-list-item>
</uni-list>
<!-- 国家地区列表选择 -->
<uni-list v-else :border="false">
<uni-list-item
v-for="(item, index) in country.filter((v, i) => v.value !== 0)"
:key="item.id"
:title="item.name"
:border="false"
clickable
@click="selectHandle(item, index, true)"
>
<template v-slot:footer>
<uni-icons
v-if="countryName == item.name"
type="checkmarkempty"
class="sx-address-picker__list-tab--active"
></uni-icons>
</template>
</uni-list-item>
</uni-list>
</view>
</view>
</view>
</uni-popup>
</template>
<script>
const cityDataUrl =
"https://static-mp-97eb3f65-f610-4509-81e4-a6cd5df3859b.next.bspapp.com/cos/data.json";
const countryDataUrl =
"https://static-mp-97eb3f65-f610-4509-81e4-a6cd5df3859b.next.bspapp.com/cos/country.json";
// 后续计划TODO 常用城市、国家
// const quickCitys = ['上海市', '北京市', '苏州市', '杭州市', '广州市', '深圳市', '南京市', '天津市']
// const quickCountys = ['中国香港', '中国澳门', '中国台湾', '新加坡']
export default {
props: {
value: Boolean,
selected: {
type: Array,
default() {
return [];
},
},
},
data() {
return {
// "港澳台地区及海外"
world: "0",
loading: true,
loadingStatus: "loading",
countryName: "",
country: [],
worlds: ["中国内地(大陆)", ],
quickIndex: "0",
list: [],
activeLevel: -1,
activeIndex: -1,
level0: "",
activeItems: [],
childList: [],
};
},
methods: {
clear() {
console.log(1111111111111111)
this.activeItems = [];
this.countryName = "";
this.level0 = "";
this.$forceUpdate()
},
// 弹窗是否显示状态事件
popChange(e) {
this.$emit("input", e.show);
},
// 已选择项切换事件
selectLevel(item) {
if (item.code && this.world === "0") {
this.activeLevel = item.level - 1;
}
},
typeChange(e) {
const value = e.detail.value;
this.world = value;
this.getList();
},
// 选择省市区/国家事件 isOhter区分选择省市区
selectHandle(item, index, isOhter = false) {
if (isOhter) {
// 选择国家
this.activeLevel = -1;
this.activeIndex = 0;
this.countryName = item.name;
this.activeItems = [item];
this.$refs.popup.close();
this.$emit("confirm", this.activeItems);
} else {
// 选择省市区
this.activeLevel = item.level;
this.activeIndex = index;
this.$set(this.activeItems, item.level, item);
this.activeItems.splice(item.level + 1);
if (item.children) {
this.$set(this.activeItems, item.level + 1, {});
} else {
this.$refs.popup.close();
this.$emit("confirm", [
{
code: "CN",
level: -1,
name: "中国",
},
...this.activeItems,
]);
}
}
},
// 获取中国省市区数据
getCityData() {
if (!this.list.length) {
this.loadingStatus = "loading";
// 循环给省市区增加level级别字段
const eachList = function (arr, level) {
arr.forEach((v) => {
v.level = level;
if (v.children) {
eachList(v.children, v.level + 1);
}
});
};
uni.request({
url: cityDataUrl,
success: (res) => {
const list = res.data;
if (Array.isArray(list)) {
eachList(list, 0);
this.list = list;
if (this.selected.length) {
const activeItems = [];
if (this.selected.length !== 1) {
activeItems[0] = this.list.find(
(v) => v.name === this.selected[1]
);
activeItems[1] = activeItems[0].children.find(
(v) => v.name === this.selected[2]
);
activeItems[2] = activeItems[1].children.find(
(v) => v.name === this.selected[3]
);
activeItems[3] = activeItems[2].children.find(
(v) => v.name === this.selected[4]
);
this.activeItems = activeItems;
this.activeLevel = 2;
} else {
this.activeLevel = -1;
}
}
this.loadingStatus = "more";
} else {
this.loadingStatus = "noMore";
}
},
fail: () => {
this.loadingStatus = "noMore";
},
});
} else {
this.loadingStatus = "more";
}
},
// 获取国家数据
getCountryData() {
if (this.world == 1 && !this.country.length) {
this.loadingStatus = "loading";
uni.request({
url: countryDataUrl,
success: (res) => {
const data = res.data;
if (data.others) {
const list = data.others.reduce((arr, v) => {
arr.push(...v.items);
return arr;
}, []);
this.country = list;
this.loadingStatus = "more";
} else {
this.loadingStatus = "noMore";
}
},
fail: () => {
this.loadingStatus = "noMore";
},
});
} else {
this.loadingStatus = "more";
}
},
reGetList() {
if (this.loadingStatus === "noMore") {
this.getList();
}
},
getList() {
switch (this.world) {
case "0":
this.getCityData();
break;
case "1":
this.getCountryData();
break;
}
},
},
computed: {
// 动态计算当前要选择的列表
currentList() {
if (this.activeLevel !== -1) {
return this.activeItems[this.activeLevel].children;
}
return this.list;
},
// 动态标题显示
selectTitle() {
const titles = {
"-1": "请选择省份/地区",
0: "请选择城市",
1: "请选择区/县",
2: "请选择街道",
};
return titles[this.activeLevel];
},
// TODO 后续更新
// quickTitle() {
// const items = {
// 0: '常用城市',
// 1: '常用国家/地区'
// }
// return items[this.world]
// },
// TODO 后续计划 常用选项
// quickList() {
// return this.world === '0' ? quickCitys : quickCountys
// }
},
watch: {
// 监听value触发弹窗显示状态以及事件处理
async value(val) {
if (val) {
this.$refs.popup.open();
const countyName = this.selected[0];
this.world = this.selected.length === 1 ? "1" : "0";
if (this.activeItems.length === 4) {
this.activeLevel = 2;
}
this.countryName = countyName;
this.getList();
} else {
this.$refs.popup.close();
}
},
},
};
</script>
<style lang="scss" scoped>
.sx-address-picker {
border-top-left-radius: 20px;
border-top-right-radius: 20px;
background-color: white;
padding-left: 8px;
padding-right: 8px;
padding-top: 16px;
font-size: 16px;
&__close {
text-align: right;
margin-right: 16px;
margin-top: 4px;
position: absolute;
left: 0;
right: 0;
}
&__title {
text-align: center;
font-weight: 500;
font-size: 18px;
margin-bottom: 20px;
}
&--divider {
border-top: 0.5px solid #ddd;
}
&__list {
max-height: 400px;
overflow-y: auto;
margin-top: 12px;
&-tab {
display: flex;
margin-bottom: 20px;
justify-content: space-between;
padding-left: 16px;
padding-right: 16px;
&--hide {
display: none;
}
&--active {
color: $uni-color-primary !important;
}
}
&-title {
font-weight: bold;
margin-bottom: 16px;
}
.uni-load-more {
padding: 100px 0;
}
}
}
</style>