mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
317 lines
6.8 KiB
JavaScript
317 lines
6.8 KiB
JavaScript
import { createNamespace } from '../utils';
|
|
import { pickerProps } from '../picker/shared';
|
|
import Picker from '../picker';
|
|
|
|
const [createComponent, bem] = createNamespace('area');
|
|
|
|
const PLACEHOLDER_CODE = '000000';
|
|
|
|
function isOverseaCode(code) {
|
|
return code[0] === '9';
|
|
}
|
|
|
|
export default createComponent({
|
|
props: {
|
|
...pickerProps,
|
|
value: String,
|
|
areaList: {
|
|
type: Object,
|
|
default: () => ({}),
|
|
},
|
|
columnsNum: {
|
|
type: [Number, String],
|
|
default: 3,
|
|
},
|
|
isOverseaCode: {
|
|
type: Function,
|
|
default: isOverseaCode,
|
|
},
|
|
columnsPlaceholder: {
|
|
type: Array,
|
|
default: () => [],
|
|
},
|
|
},
|
|
|
|
emits: ['change', 'confirm'],
|
|
|
|
data() {
|
|
return {
|
|
code: this.value,
|
|
columns: [{ values: [] }, { values: [] }, { values: [] }],
|
|
};
|
|
},
|
|
|
|
computed: {
|
|
province() {
|
|
return this.areaList.province_list || {};
|
|
},
|
|
|
|
city() {
|
|
return this.areaList.city_list || {};
|
|
},
|
|
|
|
county() {
|
|
return this.areaList.county_list || {};
|
|
},
|
|
|
|
displayColumns() {
|
|
return this.columns.slice(0, +this.columnsNum);
|
|
},
|
|
|
|
placeholderMap() {
|
|
return {
|
|
province: this.columnsPlaceholder[0] || '',
|
|
city: this.columnsPlaceholder[1] || '',
|
|
county: this.columnsPlaceholder[2] || '',
|
|
};
|
|
},
|
|
|
|
pickerSlots() {
|
|
return ['title', 'columns-top', 'columns-bottom'].reduce((slots, key) => {
|
|
slots[key] = this.$slots[key];
|
|
return slots;
|
|
}, {});
|
|
},
|
|
},
|
|
|
|
watch: {
|
|
value(val) {
|
|
this.code = val;
|
|
this.setValues();
|
|
},
|
|
|
|
areaList: {
|
|
deep: true,
|
|
handler() {
|
|
this.setValues();
|
|
},
|
|
},
|
|
|
|
columnsNum() {
|
|
this.$nextTick(() => {
|
|
this.setValues();
|
|
});
|
|
},
|
|
},
|
|
|
|
mounted() {
|
|
this.setValues();
|
|
},
|
|
|
|
methods: {
|
|
// get list by code
|
|
getList(type, code) {
|
|
let result = [];
|
|
if (type !== 'province' && !code) {
|
|
return result;
|
|
}
|
|
|
|
const list = this[type];
|
|
result = Object.keys(list).map((listCode) => ({
|
|
code: listCode,
|
|
name: list[listCode],
|
|
}));
|
|
|
|
if (code) {
|
|
// oversea code
|
|
if (this.isOverseaCode(code) && type === 'city') {
|
|
code = '9';
|
|
}
|
|
|
|
result = result.filter((item) => item.code.indexOf(code) === 0);
|
|
}
|
|
|
|
if (this.placeholderMap[type] && result.length) {
|
|
// set columns placeholder
|
|
let codeFill = '';
|
|
if (type === 'city') {
|
|
codeFill = PLACEHOLDER_CODE.slice(2, 4);
|
|
} else if (type === 'county') {
|
|
codeFill = PLACEHOLDER_CODE.slice(4, 6);
|
|
}
|
|
|
|
result.unshift({
|
|
code: `${code}${codeFill}`,
|
|
name: this.placeholderMap[type],
|
|
});
|
|
}
|
|
|
|
return result;
|
|
},
|
|
|
|
// get index by code
|
|
getIndex(type, code) {
|
|
let compareNum = type === 'province' ? 2 : type === 'city' ? 4 : 6;
|
|
const list = this.getList(type, code.slice(0, compareNum - 2));
|
|
|
|
// oversea code
|
|
if (this.isOverseaCode(code) && type === 'province') {
|
|
compareNum = 1;
|
|
}
|
|
|
|
code = code.slice(0, compareNum);
|
|
|
|
for (let i = 0; i < list.length; i++) {
|
|
if (list[i].code.slice(0, compareNum) === code) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
},
|
|
|
|
// parse output columns data
|
|
parseOutputValues(values) {
|
|
return values.map((value, index) => {
|
|
// save undefined value
|
|
if (!value) return value;
|
|
|
|
value = JSON.parse(JSON.stringify(value));
|
|
|
|
if (!value.code || value.name === this.columnsPlaceholder[index]) {
|
|
value.code = '';
|
|
value.name = '';
|
|
}
|
|
|
|
return value;
|
|
});
|
|
},
|
|
|
|
onChange(picker, values, index) {
|
|
this.code = values[index].code;
|
|
this.setValues();
|
|
|
|
const parsedValues = this.parseOutputValues(picker.getValues());
|
|
this.$emit('change', picker, parsedValues, index);
|
|
},
|
|
|
|
onConfirm(values, index) {
|
|
values = this.parseOutputValues(values);
|
|
this.setValues();
|
|
this.$emit('confirm', values, index);
|
|
},
|
|
|
|
getDefaultCode() {
|
|
if (this.columnsPlaceholder.length) {
|
|
return PLACEHOLDER_CODE;
|
|
}
|
|
|
|
const countyCodes = Object.keys(this.county);
|
|
if (countyCodes[0]) {
|
|
return countyCodes[0];
|
|
}
|
|
|
|
const cityCodes = Object.keys(this.city);
|
|
if (cityCodes[0]) {
|
|
return cityCodes[0];
|
|
}
|
|
|
|
return '';
|
|
},
|
|
|
|
setValues() {
|
|
let { code } = this;
|
|
|
|
if (!code) {
|
|
code = this.getDefaultCode();
|
|
}
|
|
|
|
const { picker } = this.$refs;
|
|
const province = this.getList('province');
|
|
const city = this.getList('city', code.slice(0, 2));
|
|
|
|
if (!picker) {
|
|
return;
|
|
}
|
|
|
|
picker.setColumnValues(0, province);
|
|
picker.setColumnValues(1, city);
|
|
|
|
if (
|
|
city.length &&
|
|
code.slice(2, 4) === '00' &&
|
|
!this.isOverseaCode(code)
|
|
) {
|
|
[{ code }] = city;
|
|
}
|
|
|
|
picker.setColumnValues(2, this.getList('county', code.slice(0, 4)));
|
|
picker.setIndexes([
|
|
this.getIndex('province', code),
|
|
this.getIndex('city', code),
|
|
this.getIndex('county', code),
|
|
]);
|
|
},
|
|
|
|
getValues() {
|
|
const { picker } = this.$refs;
|
|
let getValues = picker
|
|
? picker.getValues().filter((value) => !!value)
|
|
: [];
|
|
getValues = this.parseOutputValues(getValues);
|
|
return getValues;
|
|
},
|
|
|
|
getArea() {
|
|
const values = this.getValues();
|
|
const area = {
|
|
code: '',
|
|
country: '',
|
|
province: '',
|
|
city: '',
|
|
county: '',
|
|
};
|
|
|
|
if (!values.length) {
|
|
return area;
|
|
}
|
|
|
|
const names = values.map((item) => item.name);
|
|
const validValues = values.filter((value) => !!value.code);
|
|
|
|
area.code = validValues.length
|
|
? validValues[validValues.length - 1].code
|
|
: '';
|
|
|
|
if (this.isOverseaCode(area.code)) {
|
|
area.country = names[1] || '';
|
|
area.province = names[2] || '';
|
|
} else {
|
|
area.province = names[0] || '';
|
|
area.city = names[1] || '';
|
|
area.county = names[2] || '';
|
|
}
|
|
|
|
return area;
|
|
},
|
|
|
|
// @exposed-api
|
|
reset(code) {
|
|
this.code = code || '';
|
|
this.setValues();
|
|
},
|
|
},
|
|
|
|
render() {
|
|
return (
|
|
<Picker
|
|
v-slots={this.pickerSlots}
|
|
ref="picker"
|
|
class={bem()}
|
|
showToolbar
|
|
valueKey="name"
|
|
title={this.title}
|
|
loading={this.loading}
|
|
columns={this.displayColumns}
|
|
itemHeight={this.itemHeight}
|
|
swipeDuration={this.swipeDuration}
|
|
visibleItemCount={this.visibleItemCount}
|
|
cancelButtonText={this.cancelButtonText}
|
|
confirmButtonText={this.confirmButtonText}
|
|
onChange={this.onChange}
|
|
onConfirm={this.onConfirm}
|
|
/>
|
|
);
|
|
},
|
|
});
|