添加城市选择器
This commit is contained in:
parent
ca42d937ca
commit
a0a4c7198a
|
@ -122,14 +122,14 @@ export function normalizeOptions(options: string | {[propName: string]: string}
|
|||
interface SelectProps {
|
||||
classPrefix: string;
|
||||
classnames: ClassNamesFn;
|
||||
className: string;
|
||||
className?: string;
|
||||
creatable: boolean;
|
||||
multiple: boolean;
|
||||
valueField: string;
|
||||
labelField: string;
|
||||
searchable: boolean;
|
||||
searchable?: boolean;
|
||||
options: Array<Option>;
|
||||
value: Option | Array<Option>;
|
||||
value: any;
|
||||
loadOptions?: Function;
|
||||
searchPromptText: string;
|
||||
loading?: boolean;
|
||||
|
@ -175,6 +175,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||
promptTextCreator: (label: string) => `新增:${label}`,
|
||||
onNewOptionClick: noop,
|
||||
inline: false,
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
input: HTMLInputElement;
|
||||
|
|
|
@ -76,6 +76,7 @@ import './renderers/Form/Number';
|
|||
import './renderers/Form/Textarea';
|
||||
import './renderers/Form/Checkboxes';
|
||||
import './renderers/Form/Checkbox';
|
||||
import './renderers/Form/City';
|
||||
import './renderers/Form/Rating';
|
||||
import './renderers/Form/Switch';
|
||||
import './renderers/Form/Button';
|
||||
|
|
|
@ -0,0 +1,327 @@
|
|||
import * as React from 'react';
|
||||
import {
|
||||
FormItem,
|
||||
FormControlProps
|
||||
} from './Item';
|
||||
import db, {
|
||||
province,
|
||||
city,
|
||||
district
|
||||
} from './CityDB';
|
||||
import { ClassNamesFn, themeable } from '../../theme';
|
||||
import { Select } from '../../components';
|
||||
import { autobind } from '../../utils/helper';
|
||||
import { Option } from './Options';
|
||||
|
||||
|
||||
export interface CityPickerProps {
|
||||
value:any;
|
||||
onChange: (value:any) => void;
|
||||
joinValues: boolean;
|
||||
delimiter: string;
|
||||
classnames: ClassNamesFn;
|
||||
classPrefix: string;
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
allowCity: boolean;
|
||||
allowDistrict: boolean;
|
||||
allowStreet: boolean;
|
||||
};
|
||||
|
||||
export interface CityPickerState {
|
||||
code: number;
|
||||
province: string;
|
||||
provinceCode: number;
|
||||
city: string;
|
||||
cityCode: number;
|
||||
district: string;
|
||||
districtCode: number;
|
||||
street: string;
|
||||
};
|
||||
|
||||
export class CityPicker extends React.Component<CityPickerProps, CityPickerState> {
|
||||
static defaultProps = {
|
||||
joinValues: true,
|
||||
delimiter: ',',
|
||||
allowCity: true,
|
||||
allowDistrict: true,
|
||||
allowStreet: false
|
||||
};
|
||||
|
||||
state = {
|
||||
code: 0,
|
||||
province: '',
|
||||
provinceCode: 0,
|
||||
city: '',
|
||||
cityCode: 0,
|
||||
district: '',
|
||||
districtCode: 0,
|
||||
street: ''
|
||||
};
|
||||
|
||||
componentWillMount() {
|
||||
this.syncIn();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps:CityPickerProps) {
|
||||
const props = this.props;
|
||||
|
||||
if (props.value !== nextProps.value) {
|
||||
this.syncIn(nextProps);
|
||||
}
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleProvinceChange(option:Option) {
|
||||
|
||||
this.setState({
|
||||
province: option.label as string,
|
||||
provinceCode: option.value as number,
|
||||
city: '',
|
||||
cityCode: 0,
|
||||
district: '',
|
||||
districtCode: 0,
|
||||
street: '',
|
||||
code: option.value
|
||||
}, this.syncOut);
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleCityChange(option:Option) {
|
||||
if (option.value % 100) {
|
||||
return this.handleDistrictChange(option, {
|
||||
cityCode: option.value as number
|
||||
});
|
||||
}
|
||||
|
||||
this.setState({
|
||||
city: option.label as string,
|
||||
cityCode: option.value as number,
|
||||
district: '',
|
||||
districtCode: 0,
|
||||
street: '',
|
||||
code: option.value
|
||||
}, this.syncOut);
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleDistrictChange(option:Option, otherStates:Partial<CityPickerState> = {}) {
|
||||
this.setState({
|
||||
...otherStates as any,
|
||||
district: option.label as string,
|
||||
districtCode: option.value as number,
|
||||
street: '',
|
||||
code: option.value as number
|
||||
}, this.syncOut);
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleStreetChange(e:React.ChangeEvent<HTMLInputElement>) {
|
||||
this.setState({
|
||||
street: e.currentTarget.value
|
||||
});
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleStreetEnd() {
|
||||
this.syncOut();
|
||||
}
|
||||
|
||||
@autobind
|
||||
syncIn(props = this.props) {
|
||||
const {
|
||||
value,
|
||||
delimiter
|
||||
} = props;
|
||||
|
||||
const state = {
|
||||
code: 0,
|
||||
province: '',
|
||||
provinceCode: 0,
|
||||
city: '',
|
||||
cityCode: 0,
|
||||
district: '',
|
||||
districtCode: 0,
|
||||
street: ''
|
||||
};
|
||||
|
||||
let code = value && value.code
|
||||
|| typeof value === "number" && value
|
||||
|| typeof value === "string" && /(\d{6})/.test(value) && RegExp.$1;
|
||||
|
||||
if (code && db[code]) {
|
||||
code = parseInt(code, 10);
|
||||
state.code = code;
|
||||
|
||||
const provinceCode = code - (code % 10000);
|
||||
if (db[provinceCode]) {
|
||||
state.provinceCode = provinceCode;
|
||||
state.province = db[provinceCode];
|
||||
}
|
||||
|
||||
const cityCode = code - (code % 100);
|
||||
if (db[cityCode]) {
|
||||
state.cityCode = cityCode;
|
||||
state.city = db[cityCode];
|
||||
}
|
||||
|
||||
if (code % 100) {
|
||||
state.district = db[code];
|
||||
state.districtCode = code;
|
||||
}
|
||||
} else if (value) {
|
||||
// todo 模糊查找
|
||||
}
|
||||
|
||||
if (value && value.street) {
|
||||
state.street = value.street;
|
||||
} else if (typeof value === "string" && ~value.indexOf(delimiter)) {
|
||||
state.street = value.slice(value.indexOf(delimiter) + delimiter.length)
|
||||
}
|
||||
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
@autobind
|
||||
syncOut() {
|
||||
const {
|
||||
onChange,
|
||||
allowStreet,
|
||||
joinValues,
|
||||
delimiter
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
code,
|
||||
province,
|
||||
city,
|
||||
district,
|
||||
street
|
||||
} = this.state;
|
||||
|
||||
if (joinValues) {
|
||||
code ? onChange(allowStreet && street ? [code, street].join(delimiter) : String(code)) : onChange('');
|
||||
} else {
|
||||
onChange({
|
||||
code,
|
||||
province,
|
||||
city,
|
||||
district,
|
||||
street
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
classnames: cx,
|
||||
className,
|
||||
disabled,
|
||||
allowCity,
|
||||
allowDistrict,
|
||||
allowStreet
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
provinceCode,
|
||||
cityCode,
|
||||
districtCode,
|
||||
street
|
||||
} = this.state;
|
||||
|
||||
return (
|
||||
<div className={cx('CityPicker', className)}>
|
||||
<Select
|
||||
disabled={disabled}
|
||||
options={province.map(item => ({
|
||||
label: db[item],
|
||||
value: item
|
||||
}))}
|
||||
value={provinceCode}
|
||||
onChange={this.handleProvinceChange}
|
||||
/>
|
||||
|
||||
{provinceCode && allowDistrict && Array.isArray(district[provinceCode]) ? (
|
||||
<Select
|
||||
disabled={disabled}
|
||||
options={(district[provinceCode] as Array<number>).map(item => ({
|
||||
label: db[item],
|
||||
value: item
|
||||
}))}
|
||||
value={districtCode}
|
||||
onChange={this.handleDistrictChange}
|
||||
/>
|
||||
) : allowCity && city[provinceCode] ? (
|
||||
<Select
|
||||
disabled={disabled}
|
||||
options={city[provinceCode].map(item => ({
|
||||
label: db[item],
|
||||
value: item
|
||||
}))}
|
||||
value={cityCode}
|
||||
onChange={this.handleCityChange}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{cityCode && allowDistrict && district[provinceCode] && district[provinceCode][cityCode] ? (
|
||||
<Select
|
||||
disabled={disabled}
|
||||
options={(district[provinceCode][cityCode] as Array<number>).map(item => ({
|
||||
label: db[item],
|
||||
value: item
|
||||
}))}
|
||||
value={districtCode}
|
||||
onChange={this.handleDistrictChange}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{allowStreet && districtCode ? (
|
||||
<input
|
||||
className={cx('CityPicker-input')}
|
||||
value={street}
|
||||
onChange={this.handleStreetChange}
|
||||
onBlur={this.handleStreetEnd}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const ThemedCity = themeable(CityPicker);
|
||||
export default ThemedCity;
|
||||
|
||||
|
||||
export interface LocationControlProps extends FormControlProps {
|
||||
allowCity?: boolean;
|
||||
allowDistrict?: boolean;
|
||||
allowStreet?: boolean;
|
||||
};
|
||||
export class LocationControl extends React.Component<LocationControlProps> {
|
||||
|
||||
render() {
|
||||
const {
|
||||
value,
|
||||
onChange,
|
||||
allowCity,
|
||||
allowDistrict,
|
||||
allowStreet
|
||||
} = this.props;
|
||||
return (
|
||||
<ThemedCity
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
allowCity={allowCity}
|
||||
allowDistrict={allowDistrict}
|
||||
allowStreet={allowStreet}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@FormItem({
|
||||
type: 'city',
|
||||
sizeMutable: false
|
||||
})
|
||||
export class CheckboxControlRenderer extends LocationControl {};
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue