You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

625 lines
19 KiB
Vue

1 year ago
<template>
<view class="tm-quickCity fulled">
<view @click="qiehuan"><slot ></slot></view>
<view @click.stop="qiehuan" v-if="showbgOpen" class="tm-quickCity-fullbg fulled fixed b-0 l-0" :style="{height:sysHeight+'px'}">
<view :style="{height:(height+250+content_jian_height)+'rpx'}" @click.stop="" :class="[black_tmeme?'grey-darken-5 bk':'white']" class=" tm-quickCity-wk absolute fulled round-t-10" >
<view class="tm-quickCity-title px-32 pt-32 shadow-4 relative">
<view class="text-size-g text-weight-b mb-32 relative">
<view>
请选择城市位置
</view>
<view @click.stop="qiehuan" class="tm-calendar-close rounded flex-center" :class="black_tmeme?'grey-darken-3':'grey-lighten-3'">
<tm-icons dense name="icon-times" size="24" :color="black_tmeme?'white':'grey'"></tm-icons>
</view>
</view>
<view class="flex-start pb-24">
<view :class="[pageIndex==0?`outlined ${color_tmeme} text-weight-b`:'outlined grey',black_tmeme?'bk':'']" @click="indexChange(0)" class=" px-12 py-6 round-10 flex-center text-size-s mr-24 flex-shrink">
<text>{{childrenIndx[0]!==null?childrenIndx[0].title:'请选择省'}}</text>
</view>
<view v-if="childrenIndx[0]!==null" class="flex-center pr-24">
<tm-icons :color="black_tmeme?'white':'grey'" :size="24" dense name="icon-angle-right"></tm-icons>
</view>
<view style="max-width: 120rpx;" :class="[pageIndex==1?`outlined ${color_tmeme} text-weight-b`:'outlined grey',black_tmeme?'bk':'']" @click="indexChange(1)" v-if="childrenIndx[0]!==null" class="px-12 py-6 round-10 flex-center text-size-s mr-24 pb-10 ">
<text class="text-overflow">{{childrenIndx[1]!==null?childrenIndx[1].title:'请选择市'}}</text>
</view>
<view v-if="childrenIndx[1]!==null" class="flex-center pr-24">
<tm-icons :color="black_tmeme?'white':'grey'" :size="24" dense name="icon-angle-right"></tm-icons>
</view>
<view style="max-width: 220rpx;" :class="[pageIndex==2?`outlined ${color_tmeme} text-weight-b`:'outlined grey',black_tmeme?'bk':'']" @click="indexChange(2)" v-if="childrenIndx[1]!==null" class="px-12 py-6 round-10 flex-center text-size-s mr-24 pb-10 ">
<text class="text-overflow">{{childrenIndx[2]!==null?childrenIndx[2].title:'请选择县/区'}}</text>
</view>
</view>
</view>
<view v-if="hotCity_chuli.length>0" class="tm-quickCity-jg py-24">
<view :class="[black_tmeme?'grey-darken-5':'grey-lighten-4 text']" class="text-size-s text-weight-b py-12 px-32">热门城市</view>
<view class="px-20 pt-12">
<tm-tags model="text" rounded :black="black_tmeme" @click="selectedDefaultHot(index)" v-for="(item,index) in hotCity_chuli" :key="index" color="white" :fllowTheme="fllowTheme">
{{item[1]?item[1]:item[0]}}
</tm-tags>
</view>
</view>
<view v-show="pageIndex==0">
<tm-quickIndex :black="black_tmeme" :fllowTheme="false" :color="color_tmeme" key="ref_k_1" v-model="active" :height="content_height" :list="list">
<template v-slot:cell="{data}">
<view @click="cityClick_pr(data,0)" :class="[data.black?'bk':'',data.children!==data.total-1?'border-grey-lighten-4-b-1':'']" class="py-24 mx-32 flex-between">
<view class="text-size-n flex-start" >
<view v-if="data.item['checked']" class="mr-24">
<tm-icons :color="data.color" dense name="icon-check"></tm-icons>
</view>
<text :class="[data.item['checked']?'text-'+data.color+' text-weight-b':'']" class="text-size-n">
{{data.title}}
</text>
</view>
</view>
</template>
</tm-quickIndex>
</view>
<view v-if="pageIndex==1">
<tm-quickIndex :black="black_tmeme" :fllowTheme="false" :color="color_tmeme" key="ref_k_2" v-model="active_2" v-if="childrenIndx[0]" :height="content_height" :list="childrenIndx[0].children">
<template #cell="{data}">
<view @click="cityClick_pr(data,1)" :class="[data.black?'bk':'',data.children!==data.total-1?'border-grey-lighten-4-b-1':'']" class="py-24 mx-32 border-grey-lighten-4-b-1 flex-between">
<view class="text-size-n flex-start" >
<view v-if="data.item['checked']" class="mr-24">
<tm-icons :color="data.color" dense name="icon-check"></tm-icons>
</view>
<text :class="[data.item['checked']?'text-'+data.color+' text-weight-b':'']" class="text-size-n">
{{data.title}}
</text>
</view>
</view>
</template>
</tm-quickIndex>
</view>
<view v-if="pageIndex==2">
<tm-quickIndex :black="black_tmeme" :fllowTheme="false" :color="color_tmeme" key="ref_k_3" v-model="active_3" v-if="childrenIndx[1]" :height="content_height" :list="childrenIndx[1].children">
<template #cell="{data}">
<view @click="cityClick_pr(data,2)" :class="[data.black?'bk':'',data.children!==data.total-1?'border-grey-lighten-4-b-1':'']" class="py-24 mx-32 border-grey-lighten-4-b-1 flex-between">
<view class="text-size-n flex-start" >
<view v-if="data.item['checked']" class="mr-24">
<tm-icons :color="data.color" dense name="icon-check"></tm-icons>
</view>
<text :class="[data.item['checked']?'text-'+data.color+' text-weight-b':'']" class="text-size-n">
{{data.title}}
</text>
</view>
</view>
</template>
</tm-quickIndex>
</view>
</view>
</view>
</view>
</template>
<script>
/**
* 城区索引选择
* @property {Boolean} value = [true|false] 显示和隐藏组件请使用v-model或者value.sync你也可以不提供些参数使用默认插槽也可打开请见示例
* @property {Array} default-value = [] 默认选择的地址:[],字符串数组["江西省","南昌市"]使用.sync双向绑定
* @property {Array} hot-city = [] 默认选择的地址:[],格式同default-value
* @property {String} color = [] 默认primary,主题色
* @property {Number} height = [] 默认1000,组件高度单位rpx
* @property {Boolean} black = [true|false] 默认false,是否深色模式
* @property {Function} change 选中地址时触发返回当前选中的地区数组
*/
import provinceData from '@/tm-vuetify/tool/util/province.js';
import cityData from '@/tm-vuetify/tool/util/city.js';
import areaData from '@/tm-vuetify/tool/util/area.js';
import queryCnChart from "@/tm-vuetify/tool/function/findCnChart.js";
import tmQuickIndex from "@/tm-vuetify/components/tm-quickIndex/tm-quickIndex.vue"
import tmListitem from "@/tm-vuetify/components/tm-listitem/tm-listitem.vue"
import tmGrouplist from "@/tm-vuetify/components/tm-grouplist/tm-grouplist.vue"
import tmIcons from "@/tm-vuetify/components/tm-icons/tm-icons.vue"
import tmTags from "@/tm-vuetify/components/tm-tags/tm-tags.vue"
export default {
components:{tmQuickIndex,tmListitem,tmGrouplist,tmIcons,tmTags
},
name:"tm-quickCity",
model:{
event:'input',
prop:'value'
},
props:{
defaultValue:{
type:Array,
default:()=>{
return [];
}
},
hotCity:{
type:Array,
default:()=>[["江西省","南昌市"],["北京市"],["广东省","广州市"],["浙江省","杭州市"],["重庆市"],["湖南省","长沙市"],["湖北省","武汉市"],["四川省","成都市"]]
},
color:{
type:String,
default:"primary"
},
height:{
type:String|Number,
default:900
},
value:{
type:Boolean,
default:false
},
black:{
type:Boolean,
default:null
},
// 跟随主题色的改变而改变。
fllowTheme:{
type:Boolean|String,
default:true
}
},
data() {
return {
list:[],
active:0,
active_2:0,
active_3:0,
childrenIndx:[null,null,null],
indexobj:{
pr:null,
ar:null,
co:null
},
pageIndex:0,
sysHeight:0,
showbgOpen:false,
content_height:0,
content_jian_height:0,
hotCity_chuli:[]
};
},
watch:{
value:function(val){
this.show = val;
}
},
destroyed() {
this.list=[];
this.childrenIndx=[];
},
computed:{
black_tmeme: function() {
if (this.black !== null) return this.black;
return this.$tm.vx.state().tmVuetify.black;
},
color_tmeme:function(){
if(this.$tm.vx.state().tmVuetify.color!==null&&this.$tm.vx.state().tmVuetify.color && this.fllowTheme){
return this.$tm.vx.state().tmVuetify.color;
}
return this.color;
},
show:{
get:function(){
return this.showbgOpen;
},
set:function(val){
this.showbgOpen = val;
this.$emit('input',val);
this.$emit('update:value',val);
}
}
},
async mounted() {
this.sysHeight = uni.getSystemInfoSync().windowHeight;
this.show = this.value;
this.content_height = this.height;
this.hotCity_chuli_fun();
await this.chiliFormatCity_area()
await this.setDefaultValue();
await this.content_heightToh();
},
methods: {
hotCity_chuli_fun(){
let hot = uni.$tm.deepClone(this.hotCity);
let hostar = [];
hot.forEach(item=>{
if(item.length==1) hostar.push([item[0],null,null])
if(item.length==2) hostar.push([item[0],item[1],null])
if(item.length==3) hostar.push([item[0],item[1],item[2]])
})
this.hotCity_chuli = [...hostar];
},
async qiehuan(){
this.show = !this.showbgOpen
await this.content_heightToh();
},
async content_heightToh(){
// if(!this.showbgOpen) return;
if(this.hotCity_chuli.length==0){
return this.height;
}
this.$nextTick(async function(){
let h = await this.$Querey(".tm-quickCity-jg",this).catch(e=>{});
if(!h[0]) return;
h = h[0].height;
let blv = uni.upx2px(4) / 4;
this.content_jian_height = (h+h*blv)
this.content_height = parseInt(this.height - this.content_jian_height);
})
},
async selectedDefaultHot(index){
this.$emit('update:defaultValue',this.hotCity[index]);
let chl = this.childrenIndx[0];
if(chl){
this.$set(this.list[chl.index].children[chl.childrenIndex],'checked',false)
}
this.childrenIndx=[null,null,null];
this.$nextTick(async function(){
await this.setDefaultValue()
this.cityClick_pr(this.list[this.childrenIndx[0]],this.childrenIndx[0])
})
},
async setDefaultValue(){
let t = this;
function chuili(ix){
let pitem = null;
let chilIndex=-1;
let pdindex = -1;
if(ix==0&&t.defaultValue[ix]){
pdindex = t.list.findIndex((item)=>{
let citem = item.children
let index = citem.findIndex(ditem=>{
if(ditem.title == t.defaultValue[ix]){
pitem = ditem;
}
return ditem.title == t.defaultValue[ix]
})
if(index>-1){
chilIndex = index;
}
return index>-1;
})
}else if(t.defaultValue[ix]){
let dsst = t.childrenIndx[ix-1].children
pdindex = dsst.findIndex((item)=>{
let citem = item.children
let index = citem.findIndex(ditem=>{
if(ditem.title == t.defaultValue[ix]){
pitem = ditem;
}
return ditem.title == t.defaultValue[ix]
})
if(index>-1){
chilIndex = index;
}
return index>-1;
})
}
return {prevent:pdindex,chileIndex:chilIndex,item:pitem};
}
let d = chuili(0)
if(d.prevent>-1){
let chl = this.childrenIndx[0];
if(chl){
this.$set(this.list[chl.index].children[chl.childrenIndex],'checked',false)
}
t.childrenIndx.splice(0,1,{
index:d.prevent,
childrenIndex:d.chileIndex,
title:d.item.title,
children:t.chuliKey(d.item.children)
})
t.active = d.prevent;
this.$set(this.list[d.prevent].children[d.chileIndex],'checked',true)
}
if(t.defaultValue[1]){
let d = chuili(1)
let chl = this.childrenIndx[1];
if(chl){
this.$set(this.childrenIndx[0].children[chl.index].children[chl.childrenIndex],'checked',false)
}
t.childrenIndx.splice(1,1,{
index:d.prevent,
childrenIndex:d.chileIndex,
title:d.item.title,
children:t.chuliKey(d.item.children)
})
this.$set(this.childrenIndx[0].children[d.prevent].children[d.chileIndex],'checked',true)
}else{
}
await uni.$tm.sleep(50)
if(t.defaultValue[2]){
let d = chuili(2)
let chl = this.childrenIndx[2];
if(chl){
this.$set(this.childrenIndx[1].children[chl.index].children[chl.childrenIndex],'checked',false)
}
t.childrenIndx.splice(2,1,{
index:d.prevent,
childrenIndex:d.chileIndex,
title:d.item.title,
children:[]
})
this.$set(this.childrenIndx[1].children[d.prevent].children[d.chileIndex],'checked',true)
}
},
indexChange(index){
let t= this;
this.pageIndex = index;
this.childrenIndx.forEach((item,idx)=>{
if(idx===index && item!==null){
if(t.defaultValue[idx]==item.title){
if(idx==0){
t.active = item.index;
}else if(idx==1){
t.active_2 = item.index;
}else if(idx==2){
t.active_3 = item.index;
}
}
}
})
},
cityClick_pr(data_item,tindex){
if(tindex===0){
let chl = this.childrenIndx[0];
if(chl){
this.$set(this.list[chl.index].children[chl.childrenIndex],'checked',false)
}
this.childrenIndx=[{
index:data_item.prevent,
childrenIndex:data_item.children,
title:data_item.title,
children:this.chuliKey(data_item.item.children)
},null,null]
this.$set(this.indexobj,'pr',data_item.prevent)
this.$set(this.indexobj,'ar',null)
this.$set(this.indexobj,'co',null)
this.pageIndex=1;
this.$set(this.list[data_item.prevent].children[data_item.children],'checked',true)
}else if(tindex===1){
let chl = this.childrenIndx[1]
if(chl){
this.$set(this.childrenIndx[0].children[chl.index].children[chl.childrenIndex],'checked',false)
}
this.childrenIndx.splice(1,1,{
index:data_item.prevent,
childrenIndex:data_item.children,
title:data_item.title,
children:this.chuliKey(data_item.item.children)
})
this.childrenIndx.splice(2,1,null)
this.$set(this.indexobj,'pr',data_item.prevent)
this.$set(this.indexobj,'ar',data_item.prevent)
this.$set(this.indexobj,'co',null)
this.pageIndex=2;
this.$set(this.childrenIndx[0].children[data_item.prevent].children[data_item.children],'checked',true)
}else if(tindex===2){
let chl = this.childrenIndx[2]
if(chl){
this.$set(this.childrenIndx[1].children[chl.index].children[chl.childrenIndex],'checked',false)
}
this.childrenIndx.splice(2,1,{
index:data_item.prevent,
childrenIndex:data_item.children,
title:data_item.title,
children:[]
})
this.$set(this.indexobj,'pr',data_item.prevent)
this.$set(this.indexobj,'ar',data_item.prevent)
this.$set(this.indexobj,'co',data_item.prevent)
this.$set(this.childrenIndx[1].children[data_item.prevent].children[data_item.children],'checked',true)
}
let cdite = this.defaultValue;
this.childrenIndx.forEach((item,index)=>{
if(item){
cdite.splice(index,1,item.title)
}else{
cdite.splice(index,1,null)
}
})
this.$emit("update:defaultValue",cdite)
this.$emit("change",cdite)
},
//处理地区数据以便符合规范。
async chiliFormatCity_area() {
let list = [];
let list_index_Str = []
provinceData.forEach((item,index)=>{
let quick = queryCnChart(item.label[0])["0"];
if(item.label=='重庆市'){
quick = 'C'
}
list.push({
id:item.value,
text:item.label,
quick:quick,
children:[]
})
})
cityData.forEach((item,index)=>{
item.forEach((citem,cindex)=>{
list[index].children.push({
id:citem.value,
text:citem.label,
quick:queryCnChart(citem.label[0])["0"],
children:[]
})
})
})
list.forEach((item,index)=>{
item.children.forEach((citem,cindex)=>{
areaData[index][cindex].forEach(jitem=>{
list[index].children[cindex].children.push({
id:jitem.value,
quick:queryCnChart(jitem.label[0])["0"],
text:jitem.label
})
})
})
})
function sortFun(a,b){
var nameA = a.quick.toUpperCase(); // ignore upper and lowercase
var nameB = b.quick.toUpperCase(); // ignore upper and lowercase
if (nameA < nameB) {
return -1;
}
if (nameA > nameB) {
return 1;
}
// names must be equal
return 0;
}
function sort(itemArray){
if(typeof itemArray === 'object' && Array.isArray(itemArray)){
itemArray.sort(sortFun)
}else{
return itemArray;
}
for(let i=0;i<itemArray.length;i++){
let cl = itemArray[i]['children'];
if(typeof cl === 'object' && Array.isArray(cl)){
itemArray[i]['children'] = sort(cl);
}
}
return itemArray;
}
let plst = sort(list);
function fenzu(ar){
let jg = {};
for(let i=0;i<ar.length;i++){
let cl = ar[i]['children'];
if(typeof cl === 'object' && Array.isArray(cl)){
if(typeof jg[ar[i].quick] !=='undefined'){
jg[ar[i].quick].push({
title:ar[i].text,
index:ar[i].quick,
children:fenzu(cl)
})
}else{
jg[ar[i].quick] = [];
jg[ar[i].quick].push({
title:ar[i].text,
index:ar[i].quick,
children:fenzu(cl)
})
}
}else{
if(typeof jg[ar[i].quick] !=='undefined'){
jg[ar[i].quick].push({
title:ar[i].text,
index:ar[i].quick,
children:ar[i]
})
}else{
jg[ar[i].quick] = [];
jg[ar[i].quick].push({
title:ar[i].text,
index:ar[i].quick,
children:ar[i]
})
}
}
}
return jg;
}
let ruslt = fenzu(plst);
let tddd = this.chuliKey(ruslt);
this.list = tddd;
return tddd;
},
chuliKey(arritem){
let ruslt = arritem;
let zuihojg = [];
let keyarray = Object.keys(arritem);
for(let i=0;i<keyarray.length;i++){
zuihojg.push({
title:keyarray[i],
index:keyarray[i],
children:ruslt[keyarray[i]]
})
}
return zuihojg;
}
},
}
</script>
<style lang="scss" scoped>
.tm-quickCity{
.tm-quickCity-fullbg{
background-color: rgba(0,0,0,0.3);
z-index: 501;
.tm-quickCity-wk{
bottom: 0;
left: 0;
.tm-quickCity-title{
z-index: 10;
.tm-calendar-close {
position: absolute;
top: 0rpx;
right: 0rpx;
height: 50rpx;
line-height: 50rpx;
width: 50rpx;
}
}
}
}
}
</style>