添加城市选择器

This commit is contained in:
liaoxuezhi 2019-05-23 16:08:43 +08:00
parent 2964ae801b
commit d1a8980625
4 changed files with 3909 additions and 3 deletions

View File

@ -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;

View File

@ -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';

327
src/renderers/Form/City.tsx Normal file
View File

@ -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 {};

3577
src/renderers/Form/CityDB.ts Normal file

File diff suppressed because it is too large Load Diff