提交 8b1454d66b6a8e587844f30aeb3ecd64144d9d54

作者 愚道
1 个父辈 2f0b7335

init pro block account base setting

  1 +/yarn.lock
  2 +/package-lock.json
  3 +/dist
  4 +/node_modules
  5 +
  6 +.umi
  7 +.umi-production
... ...
  1 +export default {
  2 + plugins: [
  3 + ['umi-plugin-block-dev', {}],
  4 + ['umi-plugin-react', {
  5 + dva: true,
  6 + locale: true,
  7 + antd: true,
  8 + }]
  9 + ],
  10 +}
... ...
  1 +import request from '@/utils/request';
  2 +
  3 +export async function queryProvince() {
  4 + return request('/api/geographic/province');
  5 +}
  6 +
  7 +export async function queryCity(province) {
  8 + return request(`/api/geographic/city/${province}`);
  9 +}
... ...
  1 +import request from '@/utils/request';
  2 +
  3 +export async function query() {
  4 + return request('/api/users');
  5 +}
  6 +
  7 +export async function queryCurrent() {
  8 + return request('/api/currentUser');
  9 +}
... ...
  1 +import fetch from 'dva/fetch';
  2 +import { notification } from 'antd';
  3 +import router from 'umi/router';
  4 +import hash from 'hash.js';
  5 +import { isAntdPro } from './utils';
  6 +
  7 +const codeMessage = {
  8 + 200: '服务器成功返回请求的数据。',
  9 + 201: '新建或修改数据成功。',
  10 + 202: '一个请求已经进入后台排队(异步任务)。',
  11 + 204: '删除数据成功。',
  12 + 400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',
  13 + 401: '用户没有权限(令牌、用户名、密码错误)。',
  14 + 403: '用户得到授权,但是访问是被禁止的。',
  15 + 404: '发出的请求针对的是不存在的记录,服务器没有进行操作。',
  16 + 406: '请求的格式不可得。',
  17 + 410: '请求的资源被永久删除,且不会再得到的。',
  18 + 422: '当创建一个对象时,发生一个验证错误。',
  19 + 500: '服务器发生错误,请检查服务器。',
  20 + 502: '网关错误。',
  21 + 503: '服务不可用,服务器暂时过载或维护。',
  22 + 504: '网关超时。',
  23 +};
  24 +
  25 +const checkStatus = response => {
  26 + if (response.status >= 200 && response.status < 300) {
  27 + return response;
  28 + }
  29 + const errortext = codeMessage[response.status] || response.statusText;
  30 + notification.error({
  31 + message: `请求错误 ${response.status}: ${response.url}`,
  32 + description: errortext,
  33 + });
  34 + const error = new Error(errortext);
  35 + error.name = response.status;
  36 + error.response = response;
  37 + throw error;
  38 +};
  39 +
  40 +const cachedSave = (response, hashcode) => {
  41 + /**
  42 + * Clone a response data and store it in sessionStorage
  43 + * Does not support data other than json, Cache only json
  44 + */
  45 + const contentType = response.headers.get('Content-Type');
  46 + if (contentType && contentType.match(/application\/json/i)) {
  47 + // All data is saved as text
  48 + response
  49 + .clone()
  50 + .text()
  51 + .then(content => {
  52 + sessionStorage.setItem(hashcode, content);
  53 + sessionStorage.setItem(`${hashcode}:timestamp`, Date.now());
  54 + });
  55 + }
  56 + return response;
  57 +};
  58 +
  59 +/**
  60 + * Requests a URL, returning a promise.
  61 + *
  62 + * @param {string} url The URL we want to request
  63 + * @param {object} [option] The options we want to pass to "fetch"
  64 + * @return {object} An object containing either "data" or "err"
  65 + */
  66 +export default function request(url, option) {
  67 + const options = {
  68 + expirys: isAntdPro(),
  69 + ...option,
  70 + };
  71 + /**
  72 + * Produce fingerprints based on url and parameters
  73 + * Maybe url has the same parameters
  74 + */
  75 + const fingerprint = url + (options.body ? JSON.stringify(options.body) : '');
  76 + const hashcode = hash
  77 + .sha256()
  78 + .update(fingerprint)
  79 + .digest('hex');
  80 +
  81 + const defaultOptions = {
  82 + credentials: 'include',
  83 + };
  84 + const newOptions = { ...defaultOptions, ...options };
  85 + if (
  86 + newOptions.method === 'POST' ||
  87 + newOptions.method === 'PUT' ||
  88 + newOptions.method === 'DELETE'
  89 + ) {
  90 + if (!(newOptions.body instanceof FormData)) {
  91 + newOptions.headers = {
  92 + Accept: 'application/json',
  93 + 'Content-Type': 'application/json; charset=utf-8',
  94 + ...newOptions.headers,
  95 + };
  96 + newOptions.body = JSON.stringify(newOptions.body);
  97 + } else {
  98 + // newOptions.body is FormData
  99 + newOptions.headers = {
  100 + Accept: 'application/json',
  101 + ...newOptions.headers,
  102 + };
  103 + }
  104 + }
  105 +
  106 + const expirys = options.expirys && 60;
  107 + // options.expirys !== false, return the cache,
  108 + if (options.expirys !== false) {
  109 + const cached = sessionStorage.getItem(hashcode);
  110 + const whenCached = sessionStorage.getItem(`${hashcode}:timestamp`);
  111 + if (cached !== null && whenCached !== null) {
  112 + const age = (Date.now() - whenCached) / 1000;
  113 + if (age < expirys) {
  114 + const response = new Response(new Blob([cached]));
  115 + return response.json();
  116 + }
  117 + sessionStorage.removeItem(hashcode);
  118 + sessionStorage.removeItem(`${hashcode}:timestamp`);
  119 + }
  120 + }
  121 + return fetch(url, newOptions)
  122 + .then(checkStatus)
  123 + .then(response => cachedSave(response, hashcode))
  124 + .then(response => {
  125 + // DELETE and 204 do not return data by default
  126 + // using .json will report an error.
  127 + if (newOptions.method === 'DELETE' || response.status === 204) {
  128 + return response.text();
  129 + }
  130 + return response.json();
  131 + })
  132 + .catch(e => {
  133 + const status = e.name;
  134 + if (status === 401) {
  135 + // @HACK
  136 + /* eslint-disable no-underscore-dangle */
  137 + window.g_app._store.dispatch({
  138 + type: 'login/logout',
  139 + });
  140 + return;
  141 + }
  142 + // environment should not be used
  143 + if (status === 403) {
  144 + router.push('/exception/403');
  145 + return;
  146 + }
  147 + if (status <= 504 && status >= 500) {
  148 + router.push('/exception/500');
  149 + return;
  150 + }
  151 + if (status >= 404 && status < 422) {
  152 + router.push('/exception/404');
  153 + }
  154 + });
  155 +}
... ...
  1 +import moment from 'moment';
  2 +import React from 'react';
  3 +import nzh from 'nzh/cn';
  4 +import { parse, stringify } from 'qs';
  5 +
  6 +export function fixedZero(val) {
  7 + return val * 1 < 10 ? `0${val}` : val;
  8 +}
  9 +
  10 +export function getTimeDistance(type) {
  11 + const now = new Date();
  12 + const oneDay = 1000 * 60 * 60 * 24;
  13 +
  14 + if (type === 'today') {
  15 + now.setHours(0);
  16 + now.setMinutes(0);
  17 + now.setSeconds(0);
  18 + return [moment(now), moment(now.getTime() + (oneDay - 1000))];
  19 + }
  20 +
  21 + if (type === 'week') {
  22 + let day = now.getDay();
  23 + now.setHours(0);
  24 + now.setMinutes(0);
  25 + now.setSeconds(0);
  26 +
  27 + if (day === 0) {
  28 + day = 6;
  29 + } else {
  30 + day -= 1;
  31 + }
  32 +
  33 + const beginTime = now.getTime() - day * oneDay;
  34 +
  35 + return [moment(beginTime), moment(beginTime + (7 * oneDay - 1000))];
  36 + }
  37 +
  38 + if (type === 'month') {
  39 + const year = now.getFullYear();
  40 + const month = now.getMonth();
  41 + const nextDate = moment(now).add(1, 'months');
  42 + const nextYear = nextDate.year();
  43 + const nextMonth = nextDate.month();
  44 +
  45 + return [
  46 + moment(`${year}-${fixedZero(month + 1)}-01 00:00:00`),
  47 + moment(moment(`${nextYear}-${fixedZero(nextMonth + 1)}-01 00:00:00`).valueOf() - 1000),
  48 + ];
  49 + }
  50 +
  51 + const year = now.getFullYear();
  52 + return [moment(`${year}-01-01 00:00:00`), moment(`${year}-12-31 23:59:59`)];
  53 +}
  54 +
  55 +export function getPlainNode(nodeList, parentPath = '') {
  56 + const arr = [];
  57 + nodeList.forEach(node => {
  58 + const item = node;
  59 + item.path = `${parentPath}/${item.path || ''}`.replace(/\/+/g, '/');
  60 + item.exact = true;
  61 + if (item.children && !item.component) {
  62 + arr.push(...getPlainNode(item.children, item.path));
  63 + } else {
  64 + if (item.children && item.component) {
  65 + item.exact = false;
  66 + }
  67 + arr.push(item);
  68 + }
  69 + });
  70 + return arr;
  71 +}
  72 +
  73 +export function digitUppercase(n) {
  74 + return nzh.toMoney(n);
  75 +}
  76 +
  77 +function getRelation(str1, str2) {
  78 + if (str1 === str2) {
  79 + console.warn('Two path are equal!'); // eslint-disable-line
  80 + }
  81 + const arr1 = str1.split('/');
  82 + const arr2 = str2.split('/');
  83 + if (arr2.every((item, index) => item === arr1[index])) {
  84 + return 1;
  85 + }
  86 + if (arr1.every((item, index) => item === arr2[index])) {
  87 + return 2;
  88 + }
  89 + return 3;
  90 +}
  91 +
  92 +function getRenderArr(routes) {
  93 + let renderArr = [];
  94 + renderArr.push(routes[0]);
  95 + for (let i = 1; i < routes.length; i += 1) {
  96 + // 去重
  97 + renderArr = renderArr.filter(item => getRelation(item, routes[i]) !== 1);
  98 + // 是否包含
  99 + const isAdd = renderArr.every(item => getRelation(item, routes[i]) === 3);
  100 + if (isAdd) {
  101 + renderArr.push(routes[i]);
  102 + }
  103 + }
  104 + return renderArr;
  105 +}
  106 +
  107 +/**
  108 + * Get router routing configuration
  109 + * { path:{name,...param}}=>Array<{name,path ...param}>
  110 + * @param {string} path
  111 + * @param {routerData} routerData
  112 + */
  113 +export function getRoutes(path, routerData) {
  114 + let routes = Object.keys(routerData).filter(
  115 + routePath => routePath.indexOf(path) === 0 && routePath !== path
  116 + );
  117 + // Replace path to '' eg. path='user' /user/name => name
  118 + routes = routes.map(item => item.replace(path, ''));
  119 + // Get the route to be rendered to remove the deep rendering
  120 + const renderArr = getRenderArr(routes);
  121 + // Conversion and stitching parameters
  122 + const renderRoutes = renderArr.map(item => {
  123 + const exact = !routes.some(route => route !== item && getRelation(route, item) === 1);
  124 + return {
  125 + exact,
  126 + ...routerData[`${path}${item}`],
  127 + key: `${path}${item}`,
  128 + path: `${path}${item}`,
  129 + };
  130 + });
  131 + return renderRoutes;
  132 +}
  133 +
  134 +export function getPageQuery() {
  135 + return parse(window.location.href.split('?')[1]);
  136 +}
  137 +
  138 +export function getQueryPath(path = '', query = {}) {
  139 + const search = stringify(query);
  140 + if (search.length) {
  141 + return `${path}?${search}`;
  142 + }
  143 + return path;
  144 +}
  145 +
  146 +/* eslint no-useless-escape:0 */
  147 +const reg = /(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/;
  148 +
  149 +export function isUrl(path) {
  150 + return reg.test(path);
  151 +}
  152 +
  153 +export function formatWan(val) {
  154 + const v = val * 1;
  155 + if (!v || Number.isNaN(v)) return '';
  156 +
  157 + let result = val;
  158 + if (val > 10000) {
  159 + result = Math.floor(val / 10000);
  160 + result = (
  161 + <span>
  162 + {result}
  163 + <span
  164 + style={{
  165 + position: 'relative',
  166 + top: -2,
  167 + fontSize: 14,
  168 + fontStyle: 'normal',
  169 + marginLeft: 2,
  170 + }}
  171 + >
  172 +
  173 + </span>
  174 + </span>
  175 + );
  176 + }
  177 + return result;
  178 +}
  179 +
  180 +// 给官方演示站点用,用于关闭真实开发环境不需要使用的特性
  181 +export function isAntdPro() {
  182 + return window.location.hostname === 'preview.pro.ant.design';
  183 +}
... ...
  1 +# @umi-material/accountsettingsbase
  2 +
  3 +AccountSettingsBase
  4 +
  5 +## Usage
  6 +
  7 +```sh
  8 +umi block https://github.com/umijs/umi-blocks/tree/master/accountsettingsbase
  9 +```
  10 +
  11 +## LICENSE
  12 +
  13 +MIT
... ...
  1 +{
  2 + "name": "@umi-block/accountsettingsbase",
  3 + "version": "0.0.1",
  4 + "description": "AccountSettingsBase",
  5 + "main": "src/index.js",
  6 + "scripts": {
  7 + "dev": "umi dev"
  8 + },
  9 + "repository": {
  10 + "type": "git",
  11 + "url": "https://github.com/umijs/umi-blocks/accountsettingsbase"
  12 + },
  13 + "dependencies": {
  14 + "react": "^16.6.3",
  15 + "antd": "^3.10.9",
  16 + "dva": "^2.4.0",
  17 + "moment": "^2.22.2",
  18 + "nzh": "^1.0.3",
  19 + "qs": "^6.6.0",
  20 + "hash.js": "^1.1.5"
  21 + },
  22 + "devDependencies": {
  23 + "umi": "^2.3.0-beta.1",
  24 + "umi-plugin-react": "^1.3.0-beta.1",
  25 + "umi-plugin-block-dev": "^1.0.0"
  26 + },
  27 + "license": "ISC"
  28 +}
... ...
  1 +@import '~antd/lib/style/themes/default.less';
  2 +
  3 +.baseView {
  4 + display: flex;
  5 + padding-top: 12px;
  6 +
  7 + .left {
  8 + max-width: 448px;
  9 + min-width: 224px;
  10 + }
  11 + .right {
  12 + flex: 1;
  13 + padding-left: 104px;
  14 + .avatar_title {
  15 + height: 22px;
  16 + font-size: @font-size-base;
  17 + color: @heading-color;
  18 + line-height: 22px;
  19 + margin-bottom: 8px;
  20 + }
  21 + .avatar {
  22 + width: 144px;
  23 + height: 144px;
  24 + margin-bottom: 12px;
  25 + overflow: hidden;
  26 + img {
  27 + width: 100%;
  28 + }
  29 + }
  30 + .button_view {
  31 + width: 144px;
  32 + text-align: center;
  33 + }
  34 + }
  35 +}
  36 +
  37 +@media screen and (max-width: @screen-xl) {
  38 + .baseView {
  39 + flex-direction: column-reverse;
  40 +
  41 + .right {
  42 + padding: 20px;
  43 + display: flex;
  44 + flex-direction: column;
  45 + align-items: center;
  46 + max-width: 448px;
  47 + .avatar_title {
  48 + display: none;
  49 + }
  50 + }
  51 + }
  52 +}
... ...
  1 +import React, { PureComponent } from 'react';
  2 +import { Select, Spin } from 'antd';
  3 +import { connect } from 'dva';
  4 +import styles from './GeographicView.less';
  5 +
  6 +const { Option } = Select;
  7 +
  8 +const nullSlectItem = {
  9 + label: '',
  10 + key: '',
  11 +};
  12 +
  13 +@connect(({ geographic }) => {
  14 + const { province, isLoading, city } = geographic;
  15 + return {
  16 + province,
  17 + city,
  18 + isLoading,
  19 + };
  20 +})
  21 +class GeographicView extends PureComponent {
  22 + componentDidMount = () => {
  23 + const { dispatch } = this.props;
  24 + dispatch({
  25 + type: 'geographic/fetchProvince',
  26 + });
  27 + };
  28 +
  29 + componentDidUpdate(props) {
  30 + const { dispatch, value } = this.props;
  31 +
  32 + if (!props.value && !!value && !!value.province) {
  33 + dispatch({
  34 + type: 'geographic/fetchCity',
  35 + payload: value.province.key,
  36 + });
  37 + }
  38 + }
  39 +
  40 + getProvinceOption() {
  41 + const { province } = this.props;
  42 + return this.getOption(province);
  43 + }
  44 +
  45 + getCityOption = () => {
  46 + const { city } = this.props;
  47 + return this.getOption(city);
  48 + };
  49 +
  50 + getOption = list => {
  51 + if (!list || list.length < 1) {
  52 + return (
  53 + <Option key={0} value={0}>
  54 + 没有找到选项
  55 + </Option>
  56 + );
  57 + }
  58 + return list.map(item => (
  59 + <Option key={item.id} value={item.id}>
  60 + {item.name}
  61 + </Option>
  62 + ));
  63 + };
  64 +
  65 + selectProvinceItem = item => {
  66 + const { dispatch, onChange } = this.props;
  67 + dispatch({
  68 + type: 'geographic/fetchCity',
  69 + payload: item.key,
  70 + });
  71 + onChange({
  72 + province: item,
  73 + city: nullSlectItem,
  74 + });
  75 + };
  76 +
  77 + selectCityItem = item => {
  78 + const { value, onChange } = this.props;
  79 + onChange({
  80 + province: value.province,
  81 + city: item,
  82 + });
  83 + };
  84 +
  85 + conversionObject() {
  86 + const { value } = this.props;
  87 + if (!value) {
  88 + return {
  89 + province: nullSlectItem,
  90 + city: nullSlectItem,
  91 + };
  92 + }
  93 + const { province, city } = value;
  94 + return {
  95 + province: province || nullSlectItem,
  96 + city: city || nullSlectItem,
  97 + };
  98 + }
  99 +
  100 + render() {
  101 + const { province, city } = this.conversionObject();
  102 + const { isLoading } = this.props;
  103 + return (
  104 + <Spin spinning={isLoading} wrapperClassName={styles.row}>
  105 + <Select
  106 + className={styles.item}
  107 + value={province}
  108 + labelInValue
  109 + showSearch
  110 + onSelect={this.selectProvinceItem}
  111 + >
  112 + {this.getProvinceOption()}
  113 + </Select>
  114 + <Select
  115 + className={styles.item}
  116 + value={city}
  117 + labelInValue
  118 + showSearch
  119 + onSelect={this.selectCityItem}
  120 + >
  121 + {this.getCityOption()}
  122 + </Select>
  123 + </Spin>
  124 + );
  125 + }
  126 +}
  127 +
  128 +export default GeographicView;
... ...
  1 +@import '~antd/lib/style/themes/default.less';
  2 +
  3 +.row {
  4 + .item {
  5 + max-width: 220px;
  6 + width: 50%;
  7 + }
  8 + .item:first-child {
  9 + margin-right: 8px;
  10 + width: ~'calc(50% - 8px)';
  11 + }
  12 +}
  13 +
  14 +@media screen and (max-width: @screen-sm) {
  15 + .item:first-child {
  16 + margin: 0;
  17 + margin-bottom: 8px;
  18 + }
  19 +}
... ...
  1 +import React, { Fragment, PureComponent } from 'react';
  2 +import { Input } from 'antd';
  3 +import styles from './PhoneView.less';
  4 +
  5 +class PhoneView extends PureComponent {
  6 + render() {
  7 + const { value, onChange } = this.props;
  8 + let values = ['', ''];
  9 + if (value) {
  10 + values = value.split('-');
  11 + }
  12 + return (
  13 + <Fragment>
  14 + <Input
  15 + className={styles.area_code}
  16 + value={values[0]}
  17 + onChange={e => {
  18 + onChange(`${e.target.value}-${values[1]}`);
  19 + }}
  20 + />
  21 + <Input
  22 + className={styles.phone_number}
  23 + onChange={e => {
  24 + onChange(`${values[0]}-${e.target.value}`);
  25 + }}
  26 + value={values[1]}
  27 + />
  28 + </Fragment>
  29 + );
  30 + }
  31 +}
  32 +
  33 +export default PhoneView;
... ...
  1 +@import '~antd/lib/style/themes/default.less';
  2 +
  3 +.area_code {
  4 + max-width: 128px;
  5 + margin-right: 8px;
  6 + width: 30%;
  7 +}
  8 +.phone_number {
  9 + max-width: 312px;
  10 + width: ~'calc(70% - 8px)';
  11 +}
... ...
  1 +import city from './geographic/city.json';
  2 +import province from './geographic/province.json';
  3 +
  4 +function getProvince(req, res) {
  5 + return res.json(province);
  6 +}
  7 +
  8 +function getCity(req, res) {
  9 + return res.json(city[req.params.province]);
  10 +}
  11 +
  12 +export default {
  13 + 'GET /api/geographic/province': getProvince,
  14 + 'GET /api/geographic/city/:province': getCity,
  15 +};
... ...
  1 +module.exports = {
  2 + navTheme: 'dark', // theme for nav menu
  3 + primaryColor: '#1890FF', // primary color of ant design
  4 + layout: 'sidemenu', // nav menu position: sidemenu or topmenu
  5 + contentWidth: 'Fluid', // layout of content: Fluid or Fixed, only works when layout is topmenu
  6 + fixedHeader: false, // sticky header
  7 + autoHideHeader: false, // auto hide header
  8 + fixSiderbar: false, // sticky siderbar
  9 +};
... ...
  1 +{
  2 + "110000": [
  3 + {
  4 + "province": "北京市",
  5 + "name": "市辖区",
  6 + "id": "110100"
  7 + }
  8 + ],
  9 + "120000": [
  10 + {
  11 + "province": "天津市",
  12 + "name": "市辖区",
  13 + "id": "120100"
  14 + }
  15 + ],
  16 + "130000": [
  17 + {
  18 + "province": "河北省",
  19 + "name": "石家庄市",
  20 + "id": "130100"
  21 + },
  22 + {
  23 + "province": "河北省",
  24 + "name": "唐山市",
  25 + "id": "130200"
  26 + },
  27 + {
  28 + "province": "河北省",
  29 + "name": "秦皇岛市",
  30 + "id": "130300"
  31 + },
  32 + {
  33 + "province": "河北省",
  34 + "name": "邯郸市",
  35 + "id": "130400"
  36 + },
  37 + {
  38 + "province": "河北省",
  39 + "name": "邢台市",
  40 + "id": "130500"
  41 + },
  42 + {
  43 + "province": "河北省",
  44 + "name": "保定市",
  45 + "id": "130600"
  46 + },
  47 + {
  48 + "province": "河北省",
  49 + "name": "张家口市",
  50 + "id": "130700"
  51 + },
  52 + {
  53 + "province": "河北省",
  54 + "name": "承德市",
  55 + "id": "130800"
  56 + },
  57 + {
  58 + "province": "河北省",
  59 + "name": "沧州市",
  60 + "id": "130900"
  61 + },
  62 + {
  63 + "province": "河北省",
  64 + "name": "廊坊市",
  65 + "id": "131000"
  66 + },
  67 + {
  68 + "province": "河北省",
  69 + "name": "衡水市",
  70 + "id": "131100"
  71 + },
  72 + {
  73 + "province": "河北省",
  74 + "name": "省直辖县级行政区划",
  75 + "id": "139000"
  76 + }
  77 + ],
  78 + "140000": [
  79 + {
  80 + "province": "山西省",
  81 + "name": "太原市",
  82 + "id": "140100"
  83 + },
  84 + {
  85 + "province": "山西省",
  86 + "name": "大同市",
  87 + "id": "140200"
  88 + },
  89 + {
  90 + "province": "山西省",
  91 + "name": "阳泉市",
  92 + "id": "140300"
  93 + },
  94 + {
  95 + "province": "山西省",
  96 + "name": "长治市",
  97 + "id": "140400"
  98 + },
  99 + {
  100 + "province": "山西省",
  101 + "name": "晋城市",
  102 + "id": "140500"
  103 + },
  104 + {
  105 + "province": "山西省",
  106 + "name": "朔州市",
  107 + "id": "140600"
  108 + },
  109 + {
  110 + "province": "山西省",
  111 + "name": "晋中市",
  112 + "id": "140700"
  113 + },
  114 + {
  115 + "province": "山西省",
  116 + "name": "运城市",
  117 + "id": "140800"
  118 + },
  119 + {
  120 + "province": "山西省",
  121 + "name": "忻州市",
  122 + "id": "140900"
  123 + },
  124 + {
  125 + "province": "山西省",
  126 + "name": "临汾市",
  127 + "id": "141000"
  128 + },
  129 + {
  130 + "province": "山西省",
  131 + "name": "吕梁市",
  132 + "id": "141100"
  133 + }
  134 + ],
  135 + "150000": [
  136 + {
  137 + "province": "内蒙古自治区",
  138 + "name": "呼和浩特市",
  139 + "id": "150100"
  140 + },
  141 + {
  142 + "province": "内蒙古自治区",
  143 + "name": "包头市",
  144 + "id": "150200"
  145 + },
  146 + {
  147 + "province": "内蒙古自治区",
  148 + "name": "乌海市",
  149 + "id": "150300"
  150 + },
  151 + {
  152 + "province": "内蒙古自治区",
  153 + "name": "赤峰市",
  154 + "id": "150400"
  155 + },
  156 + {
  157 + "province": "内蒙古自治区",
  158 + "name": "通辽市",
  159 + "id": "150500"
  160 + },
  161 + {
  162 + "province": "内蒙古自治区",
  163 + "name": "鄂尔多斯市",
  164 + "id": "150600"
  165 + },
  166 + {
  167 + "province": "内蒙古自治区",
  168 + "name": "呼伦贝尔市",
  169 + "id": "150700"
  170 + },
  171 + {
  172 + "province": "内蒙古自治区",
  173 + "name": "巴彦淖尔市",
  174 + "id": "150800"
  175 + },
  176 + {
  177 + "province": "内蒙古自治区",
  178 + "name": "乌兰察布市",
  179 + "id": "150900"
  180 + },
  181 + {
  182 + "province": "内蒙古自治区",
  183 + "name": "兴安盟",
  184 + "id": "152200"
  185 + },
  186 + {
  187 + "province": "内蒙古自治区",
  188 + "name": "锡林郭勒盟",
  189 + "id": "152500"
  190 + },
  191 + {
  192 + "province": "内蒙古自治区",
  193 + "name": "阿拉善盟",
  194 + "id": "152900"
  195 + }
  196 + ],
  197 + "210000": [
  198 + {
  199 + "province": "辽宁省",
  200 + "name": "沈阳市",
  201 + "id": "210100"
  202 + },
  203 + {
  204 + "province": "辽宁省",
  205 + "name": "大连市",
  206 + "id": "210200"
  207 + },
  208 + {
  209 + "province": "辽宁省",
  210 + "name": "鞍山市",
  211 + "id": "210300"
  212 + },
  213 + {
  214 + "province": "辽宁省",
  215 + "name": "抚顺市",
  216 + "id": "210400"
  217 + },
  218 + {
  219 + "province": "辽宁省",
  220 + "name": "本溪市",
  221 + "id": "210500"
  222 + },
  223 + {
  224 + "province": "辽宁省",
  225 + "name": "丹东市",
  226 + "id": "210600"
  227 + },
  228 + {
  229 + "province": "辽宁省",
  230 + "name": "锦州市",
  231 + "id": "210700"
  232 + },
  233 + {
  234 + "province": "辽宁省",
  235 + "name": "营口市",
  236 + "id": "210800"
  237 + },
  238 + {
  239 + "province": "辽宁省",
  240 + "name": "阜新市",
  241 + "id": "210900"
  242 + },
  243 + {
  244 + "province": "辽宁省",
  245 + "name": "辽阳市",
  246 + "id": "211000"
  247 + },
  248 + {
  249 + "province": "辽宁省",
  250 + "name": "盘锦市",
  251 + "id": "211100"
  252 + },
  253 + {
  254 + "province": "辽宁省",
  255 + "name": "铁岭市",
  256 + "id": "211200"
  257 + },
  258 + {
  259 + "province": "辽宁省",
  260 + "name": "朝阳市",
  261 + "id": "211300"
  262 + },
  263 + {
  264 + "province": "辽宁省",
  265 + "name": "葫芦岛市",
  266 + "id": "211400"
  267 + }
  268 + ],
  269 + "220000": [
  270 + {
  271 + "province": "吉林省",
  272 + "name": "长春市",
  273 + "id": "220100"
  274 + },
  275 + {
  276 + "province": "吉林省",
  277 + "name": "吉林市",
  278 + "id": "220200"
  279 + },
  280 + {
  281 + "province": "吉林省",
  282 + "name": "四平市",
  283 + "id": "220300"
  284 + },
  285 + {
  286 + "province": "吉林省",
  287 + "name": "辽源市",
  288 + "id": "220400"
  289 + },
  290 + {
  291 + "province": "吉林省",
  292 + "name": "通化市",
  293 + "id": "220500"
  294 + },
  295 + {
  296 + "province": "吉林省",
  297 + "name": "白山市",
  298 + "id": "220600"
  299 + },
  300 + {
  301 + "province": "吉林省",
  302 + "name": "松原市",
  303 + "id": "220700"
  304 + },
  305 + {
  306 + "province": "吉林省",
  307 + "name": "白城市",
  308 + "id": "220800"
  309 + },
  310 + {
  311 + "province": "吉林省",
  312 + "name": "延边朝鲜族自治州",
  313 + "id": "222400"
  314 + }
  315 + ],
  316 + "230000": [
  317 + {
  318 + "province": "黑龙江省",
  319 + "name": "哈尔滨市",
  320 + "id": "230100"
  321 + },
  322 + {
  323 + "province": "黑龙江省",
  324 + "name": "齐齐哈尔市",
  325 + "id": "230200"
  326 + },
  327 + {
  328 + "province": "黑龙江省",
  329 + "name": "鸡西市",
  330 + "id": "230300"
  331 + },
  332 + {
  333 + "province": "黑龙江省",
  334 + "name": "鹤岗市",
  335 + "id": "230400"
  336 + },
  337 + {
  338 + "province": "黑龙江省",
  339 + "name": "双鸭山市",
  340 + "id": "230500"
  341 + },
  342 + {
  343 + "province": "黑龙江省",
  344 + "name": "大庆市",
  345 + "id": "230600"
  346 + },
  347 + {
  348 + "province": "黑龙江省",
  349 + "name": "伊春市",
  350 + "id": "230700"
  351 + },
  352 + {
  353 + "province": "黑龙江省",
  354 + "name": "佳木斯市",
  355 + "id": "230800"
  356 + },
  357 + {
  358 + "province": "黑龙江省",
  359 + "name": "七台河市",
  360 + "id": "230900"
  361 + },
  362 + {
  363 + "province": "黑龙江省",
  364 + "name": "牡丹江市",
  365 + "id": "231000"
  366 + },
  367 + {
  368 + "province": "黑龙江省",
  369 + "name": "黑河市",
  370 + "id": "231100"
  371 + },
  372 + {
  373 + "province": "黑龙江省",
  374 + "name": "绥化市",
  375 + "id": "231200"
  376 + },
  377 + {
  378 + "province": "黑龙江省",
  379 + "name": "大兴安岭地区",
  380 + "id": "232700"
  381 + }
  382 + ],
  383 + "310000": [
  384 + {
  385 + "province": "上海市",
  386 + "name": "市辖区",
  387 + "id": "310100"
  388 + }
  389 + ],
  390 + "320000": [
  391 + {
  392 + "province": "江苏省",
  393 + "name": "南京市",
  394 + "id": "320100"
  395 + },
  396 + {
  397 + "province": "江苏省",
  398 + "name": "无锡市",
  399 + "id": "320200"
  400 + },
  401 + {
  402 + "province": "江苏省",
  403 + "name": "徐州市",
  404 + "id": "320300"
  405 + },
  406 + {
  407 + "province": "江苏省",
  408 + "name": "常州市",
  409 + "id": "320400"
  410 + },
  411 + {
  412 + "province": "江苏省",
  413 + "name": "苏州市",
  414 + "id": "320500"
  415 + },
  416 + {
  417 + "province": "江苏省",
  418 + "name": "南通市",
  419 + "id": "320600"
  420 + },
  421 + {
  422 + "province": "江苏省",
  423 + "name": "连云港市",
  424 + "id": "320700"
  425 + },
  426 + {
  427 + "province": "江苏省",
  428 + "name": "淮安市",
  429 + "id": "320800"
  430 + },
  431 + {
  432 + "province": "江苏省",
  433 + "name": "盐城市",
  434 + "id": "320900"
  435 + },
  436 + {
  437 + "province": "江苏省",
  438 + "name": "扬州市",
  439 + "id": "321000"
  440 + },
  441 + {
  442 + "province": "江苏省",
  443 + "name": "镇江市",
  444 + "id": "321100"
  445 + },
  446 + {
  447 + "province": "江苏省",
  448 + "name": "泰州市",
  449 + "id": "321200"
  450 + },
  451 + {
  452 + "province": "江苏省",
  453 + "name": "宿迁市",
  454 + "id": "321300"
  455 + }
  456 + ],
  457 + "330000": [
  458 + {
  459 + "province": "浙江省",
  460 + "name": "杭州市",
  461 + "id": "330100"
  462 + },
  463 + {
  464 + "province": "浙江省",
  465 + "name": "宁波市",
  466 + "id": "330200"
  467 + },
  468 + {
  469 + "province": "浙江省",
  470 + "name": "温州市",
  471 + "id": "330300"
  472 + },
  473 + {
  474 + "province": "浙江省",
  475 + "name": "嘉兴市",
  476 + "id": "330400"
  477 + },
  478 + {
  479 + "province": "浙江省",
  480 + "name": "湖州市",
  481 + "id": "330500"
  482 + },
  483 + {
  484 + "province": "浙江省",
  485 + "name": "绍兴市",
  486 + "id": "330600"
  487 + },
  488 + {
  489 + "province": "浙江省",
  490 + "name": "金华市",
  491 + "id": "330700"
  492 + },
  493 + {
  494 + "province": "浙江省",
  495 + "name": "衢州市",
  496 + "id": "330800"
  497 + },
  498 + {
  499 + "province": "浙江省",
  500 + "name": "舟山市",
  501 + "id": "330900"
  502 + },
  503 + {
  504 + "province": "浙江省",
  505 + "name": "台州市",
  506 + "id": "331000"
  507 + },
  508 + {
  509 + "province": "浙江省",
  510 + "name": "丽水市",
  511 + "id": "331100"
  512 + }
  513 + ],
  514 + "340000": [
  515 + {
  516 + "province": "安徽省",
  517 + "name": "合肥市",
  518 + "id": "340100"
  519 + },
  520 + {
  521 + "province": "安徽省",
  522 + "name": "芜湖市",
  523 + "id": "340200"
  524 + },
  525 + {
  526 + "province": "安徽省",
  527 + "name": "蚌埠市",
  528 + "id": "340300"
  529 + },
  530 + {
  531 + "province": "安徽省",
  532 + "name": "淮南市",
  533 + "id": "340400"
  534 + },
  535 + {
  536 + "province": "安徽省",
  537 + "name": "马鞍山市",
  538 + "id": "340500"
  539 + },
  540 + {
  541 + "province": "安徽省",
  542 + "name": "淮北市",
  543 + "id": "340600"
  544 + },
  545 + {
  546 + "province": "安徽省",
  547 + "name": "铜陵市",
  548 + "id": "340700"
  549 + },
  550 + {
  551 + "province": "安徽省",
  552 + "name": "安庆市",
  553 + "id": "340800"
  554 + },
  555 + {
  556 + "province": "安徽省",
  557 + "name": "黄山市",
  558 + "id": "341000"
  559 + },
  560 + {
  561 + "province": "安徽省",
  562 + "name": "滁州市",
  563 + "id": "341100"
  564 + },
  565 + {
  566 + "province": "安徽省",
  567 + "name": "阜阳市",
  568 + "id": "341200"
  569 + },
  570 + {
  571 + "province": "安徽省",
  572 + "name": "宿州市",
  573 + "id": "341300"
  574 + },
  575 + {
  576 + "province": "安徽省",
  577 + "name": "六安市",
  578 + "id": "341500"
  579 + },
  580 + {
  581 + "province": "安徽省",
  582 + "name": "亳州市",
  583 + "id": "341600"
  584 + },
  585 + {
  586 + "province": "安徽省",
  587 + "name": "池州市",
  588 + "id": "341700"
  589 + },
  590 + {
  591 + "province": "安徽省",
  592 + "name": "宣城市",
  593 + "id": "341800"
  594 + }
  595 + ],
  596 + "350000": [
  597 + {
  598 + "province": "福建省",
  599 + "name": "福州市",
  600 + "id": "350100"
  601 + },
  602 + {
  603 + "province": "福建省",
  604 + "name": "厦门市",
  605 + "id": "350200"
  606 + },
  607 + {
  608 + "province": "福建省",
  609 + "name": "莆田市",
  610 + "id": "350300"
  611 + },
  612 + {
  613 + "province": "福建省",
  614 + "name": "三明市",
  615 + "id": "350400"
  616 + },
  617 + {
  618 + "province": "福建省",
  619 + "name": "泉州市",
  620 + "id": "350500"
  621 + },
  622 + {
  623 + "province": "福建省",
  624 + "name": "漳州市",
  625 + "id": "350600"
  626 + },
  627 + {
  628 + "province": "福建省",
  629 + "name": "南平市",
  630 + "id": "350700"
  631 + },
  632 + {
  633 + "province": "福建省",
  634 + "name": "龙岩市",
  635 + "id": "350800"
  636 + },
  637 + {
  638 + "province": "福建省",
  639 + "name": "宁德市",
  640 + "id": "350900"
  641 + }
  642 + ],
  643 + "360000": [
  644 + {
  645 + "province": "江西省",
  646 + "name": "南昌市",
  647 + "id": "360100"
  648 + },
  649 + {
  650 + "province": "江西省",
  651 + "name": "景德镇市",
  652 + "id": "360200"
  653 + },
  654 + {
  655 + "province": "江西省",
  656 + "name": "萍乡市",
  657 + "id": "360300"
  658 + },
  659 + {
  660 + "province": "江西省",
  661 + "name": "九江市",
  662 + "id": "360400"
  663 + },
  664 + {
  665 + "province": "江西省",
  666 + "name": "新余市",
  667 + "id": "360500"
  668 + },
  669 + {
  670 + "province": "江西省",
  671 + "name": "鹰潭市",
  672 + "id": "360600"
  673 + },
  674 + {
  675 + "province": "江西省",
  676 + "name": "赣州市",
  677 + "id": "360700"
  678 + },
  679 + {
  680 + "province": "江西省",
  681 + "name": "吉安市",
  682 + "id": "360800"
  683 + },
  684 + {
  685 + "province": "江西省",
  686 + "name": "宜春市",
  687 + "id": "360900"
  688 + },
  689 + {
  690 + "province": "江西省",
  691 + "name": "抚州市",
  692 + "id": "361000"
  693 + },
  694 + {
  695 + "province": "江西省",
  696 + "name": "上饶市",
  697 + "id": "361100"
  698 + }
  699 + ],
  700 + "370000": [
  701 + {
  702 + "province": "山东省",
  703 + "name": "济南市",
  704 + "id": "370100"
  705 + },
  706 + {
  707 + "province": "山东省",
  708 + "name": "青岛市",
  709 + "id": "370200"
  710 + },
  711 + {
  712 + "province": "山东省",
  713 + "name": "淄博市",
  714 + "id": "370300"
  715 + },
  716 + {
  717 + "province": "山东省",
  718 + "name": "枣庄市",
  719 + "id": "370400"
  720 + },
  721 + {
  722 + "province": "山东省",
  723 + "name": "东营市",
  724 + "id": "370500"
  725 + },
  726 + {
  727 + "province": "山东省",
  728 + "name": "烟台市",
  729 + "id": "370600"
  730 + },
  731 + {
  732 + "province": "山东省",
  733 + "name": "潍坊市",
  734 + "id": "370700"
  735 + },
  736 + {
  737 + "province": "山东省",
  738 + "name": "济宁市",
  739 + "id": "370800"
  740 + },
  741 + {
  742 + "province": "山东省",
  743 + "name": "泰安市",
  744 + "id": "370900"
  745 + },
  746 + {
  747 + "province": "山东省",
  748 + "name": "威海市",
  749 + "id": "371000"
  750 + },
  751 + {
  752 + "province": "山东省",
  753 + "name": "日照市",
  754 + "id": "371100"
  755 + },
  756 + {
  757 + "province": "山东省",
  758 + "name": "莱芜市",
  759 + "id": "371200"
  760 + },
  761 + {
  762 + "province": "山东省",
  763 + "name": "临沂市",
  764 + "id": "371300"
  765 + },
  766 + {
  767 + "province": "山东省",
  768 + "name": "德州市",
  769 + "id": "371400"
  770 + },
  771 + {
  772 + "province": "山东省",
  773 + "name": "聊城市",
  774 + "id": "371500"
  775 + },
  776 + {
  777 + "province": "山东省",
  778 + "name": "滨州市",
  779 + "id": "371600"
  780 + },
  781 + {
  782 + "province": "山东省",
  783 + "name": "菏泽市",
  784 + "id": "371700"
  785 + }
  786 + ],
  787 + "410000": [
  788 + {
  789 + "province": "河南省",
  790 + "name": "郑州市",
  791 + "id": "410100"
  792 + },
  793 + {
  794 + "province": "河南省",
  795 + "name": "开封市",
  796 + "id": "410200"
  797 + },
  798 + {
  799 + "province": "河南省",
  800 + "name": "洛阳市",
  801 + "id": "410300"
  802 + },
  803 + {
  804 + "province": "河南省",
  805 + "name": "平顶山市",
  806 + "id": "410400"
  807 + },
  808 + {
  809 + "province": "河南省",
  810 + "name": "安阳市",
  811 + "id": "410500"
  812 + },
  813 + {
  814 + "province": "河南省",
  815 + "name": "鹤壁市",
  816 + "id": "410600"
  817 + },
  818 + {
  819 + "province": "河南省",
  820 + "name": "新乡市",
  821 + "id": "410700"
  822 + },
  823 + {
  824 + "province": "河南省",
  825 + "name": "焦作市",
  826 + "id": "410800"
  827 + },
  828 + {
  829 + "province": "河南省",
  830 + "name": "濮阳市",
  831 + "id": "410900"
  832 + },
  833 + {
  834 + "province": "河南省",
  835 + "name": "许昌市",
  836 + "id": "411000"
  837 + },
  838 + {
  839 + "province": "河南省",
  840 + "name": "漯河市",
  841 + "id": "411100"
  842 + },
  843 + {
  844 + "province": "河南省",
  845 + "name": "三门峡市",
  846 + "id": "411200"
  847 + },
  848 + {
  849 + "province": "河南省",
  850 + "name": "南阳市",
  851 + "id": "411300"
  852 + },
  853 + {
  854 + "province": "河南省",
  855 + "name": "商丘市",
  856 + "id": "411400"
  857 + },
  858 + {
  859 + "province": "河南省",
  860 + "name": "信阳市",
  861 + "id": "411500"
  862 + },
  863 + {
  864 + "province": "河南省",
  865 + "name": "周口市",
  866 + "id": "411600"
  867 + },
  868 + {
  869 + "province": "河南省",
  870 + "name": "驻马店市",
  871 + "id": "411700"
  872 + },
  873 + {
  874 + "province": "河南省",
  875 + "name": "省直辖县级行政区划",
  876 + "id": "419000"
  877 + }
  878 + ],
  879 + "420000": [
  880 + {
  881 + "province": "湖北省",
  882 + "name": "武汉市",
  883 + "id": "420100"
  884 + },
  885 + {
  886 + "province": "湖北省",
  887 + "name": "黄石市",
  888 + "id": "420200"
  889 + },
  890 + {
  891 + "province": "湖北省",
  892 + "name": "十堰市",
  893 + "id": "420300"
  894 + },
  895 + {
  896 + "province": "湖北省",
  897 + "name": "宜昌市",
  898 + "id": "420500"
  899 + },
  900 + {
  901 + "province": "湖北省",
  902 + "name": "襄阳市",
  903 + "id": "420600"
  904 + },
  905 + {
  906 + "province": "湖北省",
  907 + "name": "鄂州市",
  908 + "id": "420700"
  909 + },
  910 + {
  911 + "province": "湖北省",
  912 + "name": "荆门市",
  913 + "id": "420800"
  914 + },
  915 + {
  916 + "province": "湖北省",
  917 + "name": "孝感市",
  918 + "id": "420900"
  919 + },
  920 + {
  921 + "province": "湖北省",
  922 + "name": "荆州市",
  923 + "id": "421000"
  924 + },
  925 + {
  926 + "province": "湖北省",
  927 + "name": "黄冈市",
  928 + "id": "421100"
  929 + },
  930 + {
  931 + "province": "湖北省",
  932 + "name": "咸宁市",
  933 + "id": "421200"
  934 + },
  935 + {
  936 + "province": "湖北省",
  937 + "name": "随州市",
  938 + "id": "421300"
  939 + },
  940 + {
  941 + "province": "湖北省",
  942 + "name": "恩施土家族苗族自治州",
  943 + "id": "422800"
  944 + },
  945 + {
  946 + "province": "湖北省",
  947 + "name": "省直辖县级行政区划",
  948 + "id": "429000"
  949 + }
  950 + ],
  951 + "430000": [
  952 + {
  953 + "province": "湖南省",
  954 + "name": "长沙市",
  955 + "id": "430100"
  956 + },
  957 + {
  958 + "province": "湖南省",
  959 + "name": "株洲市",
  960 + "id": "430200"
  961 + },
  962 + {
  963 + "province": "湖南省",
  964 + "name": "湘潭市",
  965 + "id": "430300"
  966 + },
  967 + {
  968 + "province": "湖南省",
  969 + "name": "衡阳市",
  970 + "id": "430400"
  971 + },
  972 + {
  973 + "province": "湖南省",
  974 + "name": "邵阳市",
  975 + "id": "430500"
  976 + },
  977 + {
  978 + "province": "湖南省",
  979 + "name": "岳阳市",
  980 + "id": "430600"
  981 + },
  982 + {
  983 + "province": "湖南省",
  984 + "name": "常德市",
  985 + "id": "430700"
  986 + },
  987 + {
  988 + "province": "湖南省",
  989 + "name": "张家界市",
  990 + "id": "430800"
  991 + },
  992 + {
  993 + "province": "湖南省",
  994 + "name": "益阳市",
  995 + "id": "430900"
  996 + },
  997 + {
  998 + "province": "湖南省",
  999 + "name": "郴州市",
  1000 + "id": "431000"
  1001 + },
  1002 + {
  1003 + "province": "湖南省",
  1004 + "name": "永州市",
  1005 + "id": "431100"
  1006 + },
  1007 + {
  1008 + "province": "湖南省",
  1009 + "name": "怀化市",
  1010 + "id": "431200"
  1011 + },
  1012 + {
  1013 + "province": "湖南省",
  1014 + "name": "娄底市",
  1015 + "id": "431300"
  1016 + },
  1017 + {
  1018 + "province": "湖南省",
  1019 + "name": "湘西土家族苗族自治州",
  1020 + "id": "433100"
  1021 + }
  1022 + ],
  1023 + "440000": [
  1024 + {
  1025 + "province": "广东省",
  1026 + "name": "广州市",
  1027 + "id": "440100"
  1028 + },
  1029 + {
  1030 + "province": "广东省",
  1031 + "name": "韶关市",
  1032 + "id": "440200"
  1033 + },
  1034 + {
  1035 + "province": "广东省",
  1036 + "name": "深圳市",
  1037 + "id": "440300"
  1038 + },
  1039 + {
  1040 + "province": "广东省",
  1041 + "name": "珠海市",
  1042 + "id": "440400"
  1043 + },
  1044 + {
  1045 + "province": "广东省",
  1046 + "name": "汕头市",
  1047 + "id": "440500"
  1048 + },
  1049 + {
  1050 + "province": "广东省",
  1051 + "name": "佛山市",
  1052 + "id": "440600"
  1053 + },
  1054 + {
  1055 + "province": "广东省",
  1056 + "name": "江门市",
  1057 + "id": "440700"
  1058 + },
  1059 + {
  1060 + "province": "广东省",
  1061 + "name": "湛江市",
  1062 + "id": "440800"
  1063 + },
  1064 + {
  1065 + "province": "广东省",
  1066 + "name": "茂名市",
  1067 + "id": "440900"
  1068 + },
  1069 + {
  1070 + "province": "广东省",
  1071 + "name": "肇庆市",
  1072 + "id": "441200"
  1073 + },
  1074 + {
  1075 + "province": "广东省",
  1076 + "name": "惠州市",
  1077 + "id": "441300"
  1078 + },
  1079 + {
  1080 + "province": "广东省",
  1081 + "name": "梅州市",
  1082 + "id": "441400"
  1083 + },
  1084 + {
  1085 + "province": "广东省",
  1086 + "name": "汕尾市",
  1087 + "id": "441500"
  1088 + },
  1089 + {
  1090 + "province": "广东省",
  1091 + "name": "河源市",
  1092 + "id": "441600"
  1093 + },
  1094 + {
  1095 + "province": "广东省",
  1096 + "name": "阳江市",
  1097 + "id": "441700"
  1098 + },
  1099 + {
  1100 + "province": "广东省",
  1101 + "name": "清远市",
  1102 + "id": "441800"
  1103 + },
  1104 + {
  1105 + "province": "广东省",
  1106 + "name": "东莞市",
  1107 + "id": "441900"
  1108 + },
  1109 + {
  1110 + "province": "广东省",
  1111 + "name": "中山市",
  1112 + "id": "442000"
  1113 + },
  1114 + {
  1115 + "province": "广东省",
  1116 + "name": "潮州市",
  1117 + "id": "445100"
  1118 + },
  1119 + {
  1120 + "province": "广东省",
  1121 + "name": "揭阳市",
  1122 + "id": "445200"
  1123 + },
  1124 + {
  1125 + "province": "广东省",
  1126 + "name": "云浮市",
  1127 + "id": "445300"
  1128 + }
  1129 + ],
  1130 + "450000": [
  1131 + {
  1132 + "province": "广西壮族自治区",
  1133 + "name": "南宁市",
  1134 + "id": "450100"
  1135 + },
  1136 + {
  1137 + "province": "广西壮族自治区",
  1138 + "name": "柳州市",
  1139 + "id": "450200"
  1140 + },
  1141 + {
  1142 + "province": "广西壮族自治区",
  1143 + "name": "桂林市",
  1144 + "id": "450300"
  1145 + },
  1146 + {
  1147 + "province": "广西壮族自治区",
  1148 + "name": "梧州市",
  1149 + "id": "450400"
  1150 + },
  1151 + {
  1152 + "province": "广西壮族自治区",
  1153 + "name": "北海市",
  1154 + "id": "450500"
  1155 + },
  1156 + {
  1157 + "province": "广西壮族自治区",
  1158 + "name": "防城港市",
  1159 + "id": "450600"
  1160 + },
  1161 + {
  1162 + "province": "广西壮族自治区",
  1163 + "name": "钦州市",
  1164 + "id": "450700"
  1165 + },
  1166 + {
  1167 + "province": "广西壮族自治区",
  1168 + "name": "贵港市",
  1169 + "id": "450800"
  1170 + },
  1171 + {
  1172 + "province": "广西壮族自治区",
  1173 + "name": "玉林市",
  1174 + "id": "450900"
  1175 + },
  1176 + {
  1177 + "province": "广西壮族自治区",
  1178 + "name": "百色市",
  1179 + "id": "451000"
  1180 + },
  1181 + {
  1182 + "province": "广西壮族自治区",
  1183 + "name": "贺州市",
  1184 + "id": "451100"
  1185 + },
  1186 + {
  1187 + "province": "广西壮族自治区",
  1188 + "name": "河池市",
  1189 + "id": "451200"
  1190 + },
  1191 + {
  1192 + "province": "广西壮族自治区",
  1193 + "name": "来宾市",
  1194 + "id": "451300"
  1195 + },
  1196 + {
  1197 + "province": "广西壮族自治区",
  1198 + "name": "崇左市",
  1199 + "id": "451400"
  1200 + }
  1201 + ],
  1202 + "460000": [
  1203 + {
  1204 + "province": "海南省",
  1205 + "name": "海口市",
  1206 + "id": "460100"
  1207 + },
  1208 + {
  1209 + "province": "海南省",
  1210 + "name": "三亚市",
  1211 + "id": "460200"
  1212 + },
  1213 + {
  1214 + "province": "海南省",
  1215 + "name": "三沙市",
  1216 + "id": "460300"
  1217 + },
  1218 + {
  1219 + "province": "海南省",
  1220 + "name": "儋州市",
  1221 + "id": "460400"
  1222 + },
  1223 + {
  1224 + "province": "海南省",
  1225 + "name": "省直辖县级行政区划",
  1226 + "id": "469000"
  1227 + }
  1228 + ],
  1229 + "500000": [
  1230 + {
  1231 + "province": "重庆市",
  1232 + "name": "市辖区",
  1233 + "id": "500100"
  1234 + },
  1235 + {
  1236 + "province": "重庆市",
  1237 + "name": "县",
  1238 + "id": "500200"
  1239 + }
  1240 + ],
  1241 + "510000": [
  1242 + {
  1243 + "province": "四川省",
  1244 + "name": "成都市",
  1245 + "id": "510100"
  1246 + },
  1247 + {
  1248 + "province": "四川省",
  1249 + "name": "自贡市",
  1250 + "id": "510300"
  1251 + },
  1252 + {
  1253 + "province": "四川省",
  1254 + "name": "攀枝花市",
  1255 + "id": "510400"
  1256 + },
  1257 + {
  1258 + "province": "四川省",
  1259 + "name": "泸州市",
  1260 + "id": "510500"
  1261 + },
  1262 + {
  1263 + "province": "四川省",
  1264 + "name": "德阳市",
  1265 + "id": "510600"
  1266 + },
  1267 + {
  1268 + "province": "四川省",
  1269 + "name": "绵阳市",
  1270 + "id": "510700"
  1271 + },
  1272 + {
  1273 + "province": "四川省",
  1274 + "name": "广元市",
  1275 + "id": "510800"
  1276 + },
  1277 + {
  1278 + "province": "四川省",
  1279 + "name": "遂宁市",
  1280 + "id": "510900"
  1281 + },
  1282 + {
  1283 + "province": "四川省",
  1284 + "name": "内江市",
  1285 + "id": "511000"
  1286 + },
  1287 + {
  1288 + "province": "四川省",
  1289 + "name": "乐山市",
  1290 + "id": "511100"
  1291 + },
  1292 + {
  1293 + "province": "四川省",
  1294 + "name": "南充市",
  1295 + "id": "511300"
  1296 + },
  1297 + {
  1298 + "province": "四川省",
  1299 + "name": "眉山市",
  1300 + "id": "511400"
  1301 + },
  1302 + {
  1303 + "province": "四川省",
  1304 + "name": "宜宾市",
  1305 + "id": "511500"
  1306 + },
  1307 + {
  1308 + "province": "四川省",
  1309 + "name": "广安市",
  1310 + "id": "511600"
  1311 + },
  1312 + {
  1313 + "province": "四川省",
  1314 + "name": "达州市",
  1315 + "id": "511700"
  1316 + },
  1317 + {
  1318 + "province": "四川省",
  1319 + "name": "雅安市",
  1320 + "id": "511800"
  1321 + },
  1322 + {
  1323 + "province": "四川省",
  1324 + "name": "巴中市",
  1325 + "id": "511900"
  1326 + },
  1327 + {
  1328 + "province": "四川省",
  1329 + "name": "资阳市",
  1330 + "id": "512000"
  1331 + },
  1332 + {
  1333 + "province": "四川省",
  1334 + "name": "阿坝藏族羌族自治州",
  1335 + "id": "513200"
  1336 + },
  1337 + {
  1338 + "province": "四川省",
  1339 + "name": "甘孜藏族自治州",
  1340 + "id": "513300"
  1341 + },
  1342 + {
  1343 + "province": "四川省",
  1344 + "name": "凉山彝族自治州",
  1345 + "id": "513400"
  1346 + }
  1347 + ],
  1348 + "520000": [
  1349 + {
  1350 + "province": "贵州省",
  1351 + "name": "贵阳市",
  1352 + "id": "520100"
  1353 + },
  1354 + {
  1355 + "province": "贵州省",
  1356 + "name": "六盘水市",
  1357 + "id": "520200"
  1358 + },
  1359 + {
  1360 + "province": "贵州省",
  1361 + "name": "遵义市",
  1362 + "id": "520300"
  1363 + },
  1364 + {
  1365 + "province": "贵州省",
  1366 + "name": "安顺市",
  1367 + "id": "520400"
  1368 + },
  1369 + {
  1370 + "province": "贵州省",
  1371 + "name": "毕节市",
  1372 + "id": "520500"
  1373 + },
  1374 + {
  1375 + "province": "贵州省",
  1376 + "name": "铜仁市",
  1377 + "id": "520600"
  1378 + },
  1379 + {
  1380 + "province": "贵州省",
  1381 + "name": "黔西南布依族苗族自治州",
  1382 + "id": "522300"
  1383 + },
  1384 + {
  1385 + "province": "贵州省",
  1386 + "name": "黔东南苗族侗族自治州",
  1387 + "id": "522600"
  1388 + },
  1389 + {
  1390 + "province": "贵州省",
  1391 + "name": "黔南布依族苗族自治州",
  1392 + "id": "522700"
  1393 + }
  1394 + ],
  1395 + "530000": [
  1396 + {
  1397 + "province": "云南省",
  1398 + "name": "昆明市",
  1399 + "id": "530100"
  1400 + },
  1401 + {
  1402 + "province": "云南省",
  1403 + "name": "曲靖市",
  1404 + "id": "530300"
  1405 + },
  1406 + {
  1407 + "province": "云南省",
  1408 + "name": "玉溪市",
  1409 + "id": "530400"
  1410 + },
  1411 + {
  1412 + "province": "云南省",
  1413 + "name": "保山市",
  1414 + "id": "530500"
  1415 + },
  1416 + {
  1417 + "province": "云南省",
  1418 + "name": "昭通市",
  1419 + "id": "530600"
  1420 + },
  1421 + {
  1422 + "province": "云南省",
  1423 + "name": "丽江市",
  1424 + "id": "530700"
  1425 + },
  1426 + {
  1427 + "province": "云南省",
  1428 + "name": "普洱市",
  1429 + "id": "530800"
  1430 + },
  1431 + {
  1432 + "province": "云南省",
  1433 + "name": "临沧市",
  1434 + "id": "530900"
  1435 + },
  1436 + {
  1437 + "province": "云南省",
  1438 + "name": "楚雄彝族自治州",
  1439 + "id": "532300"
  1440 + },
  1441 + {
  1442 + "province": "云南省",
  1443 + "name": "红河哈尼族彝族自治州",
  1444 + "id": "532500"
  1445 + },
  1446 + {
  1447 + "province": "云南省",
  1448 + "name": "文山壮族苗族自治州",
  1449 + "id": "532600"
  1450 + },
  1451 + {
  1452 + "province": "云南省",
  1453 + "name": "西双版纳傣族自治州",
  1454 + "id": "532800"
  1455 + },
  1456 + {
  1457 + "province": "云南省",
  1458 + "name": "大理白族自治州",
  1459 + "id": "532900"
  1460 + },
  1461 + {
  1462 + "province": "云南省",
  1463 + "name": "德宏傣族景颇族自治州",
  1464 + "id": "533100"
  1465 + },
  1466 + {
  1467 + "province": "云南省",
  1468 + "name": "怒江傈僳族自治州",
  1469 + "id": "533300"
  1470 + },
  1471 + {
  1472 + "province": "云南省",
  1473 + "name": "迪庆藏族自治州",
  1474 + "id": "533400"
  1475 + }
  1476 + ],
  1477 + "540000": [
  1478 + {
  1479 + "province": "西藏自治区",
  1480 + "name": "拉萨市",
  1481 + "id": "540100"
  1482 + },
  1483 + {
  1484 + "province": "西藏自治区",
  1485 + "name": "日喀则市",
  1486 + "id": "540200"
  1487 + },
  1488 + {
  1489 + "province": "西藏自治区",
  1490 + "name": "昌都市",
  1491 + "id": "540300"
  1492 + },
  1493 + {
  1494 + "province": "西藏自治区",
  1495 + "name": "林芝市",
  1496 + "id": "540400"
  1497 + },
  1498 + {
  1499 + "province": "西藏自治区",
  1500 + "name": "山南市",
  1501 + "id": "540500"
  1502 + },
  1503 + {
  1504 + "province": "西藏自治区",
  1505 + "name": "那曲地区",
  1506 + "id": "542400"
  1507 + },
  1508 + {
  1509 + "province": "西藏自治区",
  1510 + "name": "阿里地区",
  1511 + "id": "542500"
  1512 + }
  1513 + ],
  1514 + "610000": [
  1515 + {
  1516 + "province": "陕西省",
  1517 + "name": "西安市",
  1518 + "id": "610100"
  1519 + },
  1520 + {
  1521 + "province": "陕西省",
  1522 + "name": "铜川市",
  1523 + "id": "610200"
  1524 + },
  1525 + {
  1526 + "province": "陕西省",
  1527 + "name": "宝鸡市",
  1528 + "id": "610300"
  1529 + },
  1530 + {
  1531 + "province": "陕西省",
  1532 + "name": "咸阳市",
  1533 + "id": "610400"
  1534 + },
  1535 + {
  1536 + "province": "陕西省",
  1537 + "name": "渭南市",
  1538 + "id": "610500"
  1539 + },
  1540 + {
  1541 + "province": "陕西省",
  1542 + "name": "延安市",
  1543 + "id": "610600"
  1544 + },
  1545 + {
  1546 + "province": "陕西省",
  1547 + "name": "汉中市",
  1548 + "id": "610700"
  1549 + },
  1550 + {
  1551 + "province": "陕西省",
  1552 + "name": "榆林市",
  1553 + "id": "610800"
  1554 + },
  1555 + {
  1556 + "province": "陕西省",
  1557 + "name": "安康市",
  1558 + "id": "610900"
  1559 + },
  1560 + {
  1561 + "province": "陕西省",
  1562 + "name": "商洛市",
  1563 + "id": "611000"
  1564 + }
  1565 + ],
  1566 + "620000": [
  1567 + {
  1568 + "province": "甘肃省",
  1569 + "name": "兰州市",
  1570 + "id": "620100"
  1571 + },
  1572 + {
  1573 + "province": "甘肃省",
  1574 + "name": "嘉峪关市",
  1575 + "id": "620200"
  1576 + },
  1577 + {
  1578 + "province": "甘肃省",
  1579 + "name": "金昌市",
  1580 + "id": "620300"
  1581 + },
  1582 + {
  1583 + "province": "甘肃省",
  1584 + "name": "白银市",
  1585 + "id": "620400"
  1586 + },
  1587 + {
  1588 + "province": "甘肃省",
  1589 + "name": "天水市",
  1590 + "id": "620500"
  1591 + },
  1592 + {
  1593 + "province": "甘肃省",
  1594 + "name": "武威市",
  1595 + "id": "620600"
  1596 + },
  1597 + {
  1598 + "province": "甘肃省",
  1599 + "name": "张掖市",
  1600 + "id": "620700"
  1601 + },
  1602 + {
  1603 + "province": "甘肃省",
  1604 + "name": "平凉市",
  1605 + "id": "620800"
  1606 + },
  1607 + {
  1608 + "province": "甘肃省",
  1609 + "name": "酒泉市",
  1610 + "id": "620900"
  1611 + },
  1612 + {
  1613 + "province": "甘肃省",
  1614 + "name": "庆阳市",
  1615 + "id": "621000"
  1616 + },
  1617 + {
  1618 + "province": "甘肃省",
  1619 + "name": "定西市",
  1620 + "id": "621100"
  1621 + },
  1622 + {
  1623 + "province": "甘肃省",
  1624 + "name": "陇南市",
  1625 + "id": "621200"
  1626 + },
  1627 + {
  1628 + "province": "甘肃省",
  1629 + "name": "临夏回族自治州",
  1630 + "id": "622900"
  1631 + },
  1632 + {
  1633 + "province": "甘肃省",
  1634 + "name": "甘南藏族自治州",
  1635 + "id": "623000"
  1636 + }
  1637 + ],
  1638 + "630000": [
  1639 + {
  1640 + "province": "青海省",
  1641 + "name": "西宁市",
  1642 + "id": "630100"
  1643 + },
  1644 + {
  1645 + "province": "青海省",
  1646 + "name": "海东市",
  1647 + "id": "630200"
  1648 + },
  1649 + {
  1650 + "province": "青海省",
  1651 + "name": "海北藏族自治州",
  1652 + "id": "632200"
  1653 + },
  1654 + {
  1655 + "province": "青海省",
  1656 + "name": "黄南藏族自治州",
  1657 + "id": "632300"
  1658 + },
  1659 + {
  1660 + "province": "青海省",
  1661 + "name": "海南藏族自治州",
  1662 + "id": "632500"
  1663 + },
  1664 + {
  1665 + "province": "青海省",
  1666 + "name": "果洛藏族自治州",
  1667 + "id": "632600"
  1668 + },
  1669 + {
  1670 + "province": "青海省",
  1671 + "name": "玉树藏族自治州",
  1672 + "id": "632700"
  1673 + },
  1674 + {
  1675 + "province": "青海省",
  1676 + "name": "海西蒙古族藏族自治州",
  1677 + "id": "632800"
  1678 + }
  1679 + ],
  1680 + "640000": [
  1681 + {
  1682 + "province": "宁夏回族自治区",
  1683 + "name": "银川市",
  1684 + "id": "640100"
  1685 + },
  1686 + {
  1687 + "province": "宁夏回族自治区",
  1688 + "name": "石嘴山市",
  1689 + "id": "640200"
  1690 + },
  1691 + {
  1692 + "province": "宁夏回族自治区",
  1693 + "name": "吴忠市",
  1694 + "id": "640300"
  1695 + },
  1696 + {
  1697 + "province": "宁夏回族自治区",
  1698 + "name": "固原市",
  1699 + "id": "640400"
  1700 + },
  1701 + {
  1702 + "province": "宁夏回族自治区",
  1703 + "name": "中卫市",
  1704 + "id": "640500"
  1705 + }
  1706 + ],
  1707 + "650000": [
  1708 + {
  1709 + "province": "新疆维吾尔自治区",
  1710 + "name": "乌鲁木齐市",
  1711 + "id": "650100"
  1712 + },
  1713 + {
  1714 + "province": "新疆维吾尔自治区",
  1715 + "name": "克拉玛依市",
  1716 + "id": "650200"
  1717 + },
  1718 + {
  1719 + "province": "新疆维吾尔自治区",
  1720 + "name": "吐鲁番市",
  1721 + "id": "650400"
  1722 + },
  1723 + {
  1724 + "province": "新疆维吾尔自治区",
  1725 + "name": "哈密市",
  1726 + "id": "650500"
  1727 + },
  1728 + {
  1729 + "province": "新疆维吾尔自治区",
  1730 + "name": "昌吉回族自治州",
  1731 + "id": "652300"
  1732 + },
  1733 + {
  1734 + "province": "新疆维吾尔自治区",
  1735 + "name": "博尔塔拉蒙古自治州",
  1736 + "id": "652700"
  1737 + },
  1738 + {
  1739 + "province": "新疆维吾尔自治区",
  1740 + "name": "巴音郭楞蒙古自治州",
  1741 + "id": "652800"
  1742 + },
  1743 + {
  1744 + "province": "新疆维吾尔自治区",
  1745 + "name": "阿克苏地区",
  1746 + "id": "652900"
  1747 + },
  1748 + {
  1749 + "province": "新疆维吾尔自治区",
  1750 + "name": "克孜勒苏柯尔克孜自治州",
  1751 + "id": "653000"
  1752 + },
  1753 + {
  1754 + "province": "新疆维吾尔自治区",
  1755 + "name": "喀什地区",
  1756 + "id": "653100"
  1757 + },
  1758 + {
  1759 + "province": "新疆维吾尔自治区",
  1760 + "name": "和田地区",
  1761 + "id": "653200"
  1762 + },
  1763 + {
  1764 + "province": "新疆维吾尔自治区",
  1765 + "name": "伊犁哈萨克自治州",
  1766 + "id": "654000"
  1767 + },
  1768 + {
  1769 + "province": "新疆维吾尔自治区",
  1770 + "name": "塔城地区",
  1771 + "id": "654200"
  1772 + },
  1773 + {
  1774 + "province": "新疆维吾尔自治区",
  1775 + "name": "阿勒泰地区",
  1776 + "id": "654300"
  1777 + },
  1778 + {
  1779 + "province": "新疆维吾尔自治区",
  1780 + "name": "自治区直辖县级行政区划",
  1781 + "id": "659000"
  1782 + }
  1783 + ]
  1784 +}
... ...
  1 +[
  2 + {
  3 + "name": "北京市",
  4 + "id": "110000"
  5 + },
  6 + {
  7 + "name": "天津市",
  8 + "id": "120000"
  9 + },
  10 + {
  11 + "name": "河北省",
  12 + "id": "130000"
  13 + },
  14 + {
  15 + "name": "山西省",
  16 + "id": "140000"
  17 + },
  18 + {
  19 + "name": "内蒙古自治区",
  20 + "id": "150000"
  21 + },
  22 + {
  23 + "name": "辽宁省",
  24 + "id": "210000"
  25 + },
  26 + {
  27 + "name": "吉林省",
  28 + "id": "220000"
  29 + },
  30 + {
  31 + "name": "黑龙江省",
  32 + "id": "230000"
  33 + },
  34 + {
  35 + "name": "上海市",
  36 + "id": "310000"
  37 + },
  38 + {
  39 + "name": "江苏省",
  40 + "id": "320000"
  41 + },
  42 + {
  43 + "name": "浙江省",
  44 + "id": "330000"
  45 + },
  46 + {
  47 + "name": "安徽省",
  48 + "id": "340000"
  49 + },
  50 + {
  51 + "name": "福建省",
  52 + "id": "350000"
  53 + },
  54 + {
  55 + "name": "江西省",
  56 + "id": "360000"
  57 + },
  58 + {
  59 + "name": "山东省",
  60 + "id": "370000"
  61 + },
  62 + {
  63 + "name": "河南省",
  64 + "id": "410000"
  65 + },
  66 + {
  67 + "name": "湖北省",
  68 + "id": "420000"
  69 + },
  70 + {
  71 + "name": "湖南省",
  72 + "id": "430000"
  73 + },
  74 + {
  75 + "name": "广东省",
  76 + "id": "440000"
  77 + },
  78 + {
  79 + "name": "广西壮族自治区",
  80 + "id": "450000"
  81 + },
  82 + {
  83 + "name": "海南省",
  84 + "id": "460000"
  85 + },
  86 + {
  87 + "name": "重庆市",
  88 + "id": "500000"
  89 + },
  90 + {
  91 + "name": "四川省",
  92 + "id": "510000"
  93 + },
  94 + {
  95 + "name": "贵州省",
  96 + "id": "520000"
  97 + },
  98 + {
  99 + "name": "云南省",
  100 + "id": "530000"
  101 + },
  102 + {
  103 + "name": "西藏自治区",
  104 + "id": "540000"
  105 + },
  106 + {
  107 + "name": "陕西省",
  108 + "id": "610000"
  109 + },
  110 + {
  111 + "name": "甘肃省",
  112 + "id": "620000"
  113 + },
  114 + {
  115 + "name": "青海省",
  116 + "id": "630000"
  117 + },
  118 + {
  119 + "name": "宁夏回族自治区",
  120 + "id": "640000"
  121 + },
  122 + {
  123 + "name": "新疆维吾尔自治区",
  124 + "id": "650000"
  125 + },
  126 + {
  127 + "name": "台湾省",
  128 + "id": "710000"
  129 + },
  130 + {
  131 + "name": "香港特别行政区",
  132 + "id": "810000"
  133 + },
  134 + {
  135 + "name": "澳门特别行政区",
  136 + "id": "820000"
  137 + }
  138 +]
... ...
  1 +import React, { Component, Fragment } from 'react';
  2 +import { formatMessage, FormattedMessage } from 'umi/locale';
  3 +import { Form, Input, Upload, Select, Button } from 'antd';
  4 +import { connect } from 'dva';
  5 +import styles from './BaseView.less';
  6 +import GeographicView from './GeographicView';
  7 +import PhoneView from './PhoneView';
  8 +// import { getTimeDistance } from '@/utils/utils';
  9 +
  10 +const FormItem = Form.Item;
  11 +const { Option } = Select;
  12 +
  13 +// 头像组件 方便以后独立,增加裁剪之类的功能
  14 +const AvatarView = ({ avatar }) => (
  15 + <Fragment>
  16 + <div className={styles.avatar_title}>
  17 + <FormattedMessage id="app.settings.basic.avatar" defaultMessage="Avatar" />
  18 + </div>
  19 + <div className={styles.avatar}>
  20 + <img src={avatar} alt="avatar" />
  21 + </div>
  22 + <Upload fileList={[]}>
  23 + <div className={styles.button_view}>
  24 + <Button icon="upload">
  25 + <FormattedMessage id="app.settings.basic.change-avatar" defaultMessage="Change avatar" />
  26 + </Button>
  27 + </div>
  28 + </Upload>
  29 + </Fragment>
  30 +);
  31 +
  32 +const validatorGeographic = (rule, value, callback) => {
  33 + const { province, city } = value;
  34 + if (!province.key) {
  35 + callback('Please input your province!');
  36 + }
  37 + if (!city.key) {
  38 + callback('Please input your city!');
  39 + }
  40 + callback();
  41 +};
  42 +
  43 +const validatorPhone = (rule, value, callback) => {
  44 + const values = value.split('-');
  45 + if (!values[0]) {
  46 + callback('Please input your area code!');
  47 + }
  48 + if (!values[1]) {
  49 + callback('Please input your phone number!');
  50 + }
  51 + callback();
  52 +};
  53 +
  54 +@connect(({ user }) => ({
  55 + currentUser: user.currentUser,
  56 +}))
  57 +@Form.create()
  58 +class BaseView extends Component {
  59 + componentDidMount() {
  60 + this.setBaseInfo();
  61 + }
  62 +
  63 + setBaseInfo = () => {
  64 + const { currentUser, form } = this.props;
  65 + Object.keys(form.getFieldsValue()).forEach(key => {
  66 + const obj = {};
  67 + obj[key] = currentUser[key] || null;
  68 + form.setFieldsValue(obj);
  69 + });
  70 + };
  71 +
  72 + getAvatarURL() {
  73 + const { currentUser } = this.props;
  74 + if (currentUser.avatar) {
  75 + return currentUser.avatar;
  76 + }
  77 + const url = 'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png';
  78 + return url;
  79 + }
  80 +
  81 + getViewDom = ref => {
  82 + this.view = ref;
  83 + };
  84 +
  85 + render() {
  86 + const {
  87 + form: { getFieldDecorator },
  88 + } = this.props;
  89 + return (
  90 + <div className={styles.baseView} ref={this.getViewDom}>
  91 + <div className={styles.left}>
  92 + <Form layout="vertical" onSubmit={this.handleSubmit} hideRequiredMark>
  93 + <FormItem label={formatMessage({ id: 'app.settings.basic.email' })}>
  94 + {getFieldDecorator('email', {
  95 + rules: [
  96 + {
  97 + required: true,
  98 + message: formatMessage({ id: 'app.settings.basic.email-message' }, {}),
  99 + },
  100 + ],
  101 + })(<Input />)}
  102 + </FormItem>
  103 + <FormItem label={formatMessage({ id: 'app.settings.basic.nickname' })}>
  104 + {getFieldDecorator('name', {
  105 + rules: [
  106 + {
  107 + required: true,
  108 + message: formatMessage({ id: 'app.settings.basic.nickname-message' }, {}),
  109 + },
  110 + ],
  111 + })(<Input />)}
  112 + </FormItem>
  113 + <FormItem label={formatMessage({ id: 'app.settings.basic.profile' })}>
  114 + {getFieldDecorator('profile', {
  115 + rules: [
  116 + {
  117 + required: true,
  118 + message: formatMessage({ id: 'app.settings.basic.profile-message' }, {}),
  119 + },
  120 + ],
  121 + })(
  122 + <Input.TextArea
  123 + placeholder={formatMessage({ id: 'app.settings.basic.profile-placeholder' })}
  124 + rows={4}
  125 + />
  126 + )}
  127 + </FormItem>
  128 + <FormItem label={formatMessage({ id: 'app.settings.basic.country' })}>
  129 + {getFieldDecorator('country', {
  130 + rules: [
  131 + {
  132 + required: true,
  133 + message: formatMessage({ id: 'app.settings.basic.country-message' }, {}),
  134 + },
  135 + ],
  136 + })(
  137 + <Select style={{ maxWidth: 220 }}>
  138 + <Option value="China">中国</Option>
  139 + </Select>
  140 + )}
  141 + </FormItem>
  142 + <FormItem label={formatMessage({ id: 'app.settings.basic.geographic' })}>
  143 + {getFieldDecorator('geographic', {
  144 + rules: [
  145 + {
  146 + required: true,
  147 + message: formatMessage({ id: 'app.settings.basic.geographic-message' }, {}),
  148 + },
  149 + {
  150 + validator: validatorGeographic,
  151 + },
  152 + ],
  153 + })(<GeographicView />)}
  154 + </FormItem>
  155 + <FormItem label={formatMessage({ id: 'app.settings.basic.address' })}>
  156 + {getFieldDecorator('address', {
  157 + rules: [
  158 + {
  159 + required: true,
  160 + message: formatMessage({ id: 'app.settings.basic.address-message' }, {}),
  161 + },
  162 + ],
  163 + })(<Input />)}
  164 + </FormItem>
  165 + <FormItem label={formatMessage({ id: 'app.settings.basic.phone' })}>
  166 + {getFieldDecorator('phone', {
  167 + rules: [
  168 + {
  169 + required: true,
  170 + message: formatMessage({ id: 'app.settings.basic.phone-message' }, {}),
  171 + },
  172 + { validator: validatorPhone },
  173 + ],
  174 + })(<PhoneView />)}
  175 + </FormItem>
  176 + <Button type="primary">
  177 + <FormattedMessage
  178 + id="app.settings.basic.update"
  179 + defaultMessage="Update Information"
  180 + />
  181 + </Button>
  182 + </Form>
  183 + </div>
  184 + <div className={styles.right}>
  185 + <AvatarView avatar={this.getAvatarURL()} />
  186 + </div>
  187 + </div>
  188 + );
  189 + }
  190 +}
  191 +
  192 +export default BaseView;
... ...
  1 +export default {
  2 + 'app.settings.menuMap.basic': 'Basic Settings',
  3 + 'app.settings.menuMap.security': 'Security Settings',
  4 + 'app.settings.menuMap.binding': 'Account Binding',
  5 + 'app.settings.menuMap.notification': 'New Message Notification',
  6 + 'app.settings.basic.avatar': 'Avatar',
  7 + 'app.settings.basic.change-avatar': 'Change avatar',
  8 + 'app.settings.basic.email': 'Email',
  9 + 'app.settings.basic.email-message': 'Please input your email!',
  10 + 'app.settings.basic.nickname': 'Nickname',
  11 + 'app.settings.basic.nickname-message': 'Please input your Nickname!',
  12 + 'app.settings.basic.profile': 'Personal profile',
  13 + 'app.settings.basic.profile-message': 'Please input your personal profile!',
  14 + 'app.settings.basic.profile-placeholder': 'Brief introduction to yourself',
  15 + 'app.settings.basic.country': 'Country/Region',
  16 + 'app.settings.basic.country-message': 'Please input your country!',
  17 + 'app.settings.basic.geographic': 'Province or city',
  18 + 'app.settings.basic.geographic-message': 'Please input your geographic info!',
  19 + 'app.settings.basic.address': 'Street Address',
  20 + 'app.settings.basic.address-message': 'Please input your address!',
  21 + 'app.settings.basic.phone': 'Phone Number',
  22 + 'app.settings.basic.phone-message': 'Please input your phone!',
  23 + 'app.settings.basic.update': 'Update Information',
  24 + 'app.settings.security.strong': 'Strong',
  25 + 'app.settings.security.medium': 'Medium',
  26 + 'app.settings.security.weak': 'Weak',
  27 + 'app.settings.security.password': 'Account Password',
  28 + 'app.settings.security.password-description': 'Current password strength:',
  29 + 'app.settings.security.phone': 'Security Phone',
  30 + 'app.settings.security.phone-description': 'Bound phone:',
  31 + 'app.settings.security.question': 'Security Question',
  32 + 'app.settings.security.question-description':
  33 + 'The security question is not set, and the security policy can effectively protect the account security',
  34 + 'app.settings.security.email': 'Backup Email',
  35 + 'app.settings.security.email-description': 'Bound Email:',
  36 + 'app.settings.security.mfa': 'MFA Device',
  37 + 'app.settings.security.mfa-description':
  38 + 'Unbound MFA device, after binding, can be confirmed twice',
  39 + 'app.settings.security.modify': 'Modify',
  40 + 'app.settings.security.set': 'Set',
  41 + 'app.settings.security.bind': 'Bind',
  42 + 'app.settings.binding.taobao': 'Binding Taobao',
  43 + 'app.settings.binding.taobao-description': 'Currently unbound Taobao account',
  44 + 'app.settings.binding.alipay': 'Binding Alipay',
  45 + 'app.settings.binding.alipay-description': 'Currently unbound Alipay account',
  46 + 'app.settings.binding.dingding': 'Binding DingTalk',
  47 + 'app.settings.binding.dingding-description': 'Currently unbound DingTalk account',
  48 + 'app.settings.binding.bind': 'Bind',
  49 + 'app.settings.notification.password': 'Account Password',
  50 + 'app.settings.notification.password-description':
  51 + 'Messages from other users will be notified in the form of a station letter',
  52 + 'app.settings.notification.messages': 'System Messages',
  53 + 'app.settings.notification.messages-description':
  54 + 'System messages will be notified in the form of a station letter',
  55 + 'app.settings.notification.todo': 'To-do Notification',
  56 + 'app.settings.notification.todo-description':
  57 + 'The to-do list will be notified in the form of a letter from the station',
  58 + 'app.settings.open': 'Open',
  59 + 'app.settings.close': 'Close',
  60 +};
... ...
  1 +export default {
  2 + 'app.settings.menuMap.basic': '基本设置',
  3 + 'app.settings.menuMap.security': '安全设置',
  4 + 'app.settings.menuMap.binding': '账号绑定',
  5 + 'app.settings.menuMap.notification': '新消息通知',
  6 + 'app.settings.basic.avatar': '头像',
  7 + 'app.settings.basic.change-avatar': '更换头像',
  8 + 'app.settings.basic.email': '邮箱',
  9 + 'app.settings.basic.email-message': '请输入您的邮箱!',
  10 + 'app.settings.basic.nickname': '昵称',
  11 + 'app.settings.basic.nickname-message': '请输入您的昵称!',
  12 + 'app.settings.basic.profile': '个人简介',
  13 + 'app.settings.basic.profile-message': '请输入个人简介!',
  14 + 'app.settings.basic.profile-placeholder': '个人简介',
  15 + 'app.settings.basic.country': '国家/地区',
  16 + 'app.settings.basic.country-message': '请输入您的国家或地区!',
  17 + 'app.settings.basic.geographic': '所在省市',
  18 + 'app.settings.basic.geographic-message': '请输入您的所在省市!',
  19 + 'app.settings.basic.address': '街道地址',
  20 + 'app.settings.basic.address-message': '请输入您的街道地址!',
  21 + 'app.settings.basic.phone': '联系电话',
  22 + 'app.settings.basic.phone-message': '请输入您的联系电话!',
  23 + 'app.settings.basic.update': '更新基本信息',
  24 + 'app.settings.security.strong': '强',
  25 + 'app.settings.security.medium': '中',
  26 + 'app.settings.security.weak': '弱',
  27 + 'app.settings.security.password': '账户密码',
  28 + 'app.settings.security.password-description': '当前密码强度:',
  29 + 'app.settings.security.phone': '密保手机',
  30 + 'app.settings.security.phone-description': '已绑定手机:',
  31 + 'app.settings.security.question': '密保问题',
  32 + 'app.settings.security.question-description': '未设置密保问题,密保问题可有效保护账户安全',
  33 + 'app.settings.security.email': '备用邮箱',
  34 + 'app.settings.security.email-description': '已绑定邮箱:',
  35 + 'app.settings.security.mfa': 'MFA 设备',
  36 + 'app.settings.security.mfa-description': '未绑定 MFA 设备,绑定后,可以进行二次确认',
  37 + 'app.settings.security.modify': '修改',
  38 + 'app.settings.security.set': '设置',
  39 + 'app.settings.security.bind': '绑定',
  40 + 'app.settings.binding.taobao': '绑定淘宝',
  41 + 'app.settings.binding.taobao-description': '当前未绑定淘宝账号',
  42 + 'app.settings.binding.alipay': '绑定支付宝',
  43 + 'app.settings.binding.alipay-description': '当前未绑定支付宝账号',
  44 + 'app.settings.binding.dingding': '绑定钉钉',
  45 + 'app.settings.binding.dingding-description': '当前未绑定钉钉账号',
  46 + 'app.settings.binding.bind': '绑定',
  47 + 'app.settings.notification.password': '账户密码',
  48 + 'app.settings.notification.password-description': '其他用户的消息将以站内信的形式通知',
  49 + 'app.settings.notification.messages': '系统消息',
  50 + 'app.settings.notification.messages-description': '系统消息将以站内信的形式通知',
  51 + 'app.settings.notification.todo': '待办任务',
  52 + 'app.settings.notification.todo-description': '待办任务将以站内信的形式通知',
  53 + 'app.settings.open': '开',
  54 + 'app.settings.close': '关',
  55 +};
... ...
  1 +export default {
  2 + 'app.settings.menuMap.basic': '基本設置',
  3 + 'app.settings.menuMap.security': '安全設置',
  4 + 'app.settings.menuMap.binding': '賬號綁定',
  5 + 'app.settings.menuMap.notification': '新消息通知',
  6 + 'app.settings.basic.avatar': '頭像',
  7 + 'app.settings.basic.change-avatar': '更換頭像',
  8 + 'app.settings.basic.email': '郵箱',
  9 + 'app.settings.basic.email-message': '請輸入您的郵箱!',
  10 + 'app.settings.basic.nickname': '昵稱',
  11 + 'app.settings.basic.nickname-message': '請輸入您的昵稱!',
  12 + 'app.settings.basic.profile': '個人簡介',
  13 + 'app.settings.basic.profile-message': '請輸入個人簡介!',
  14 + 'app.settings.basic.profile-placeholder': '個人簡介',
  15 + 'app.settings.basic.country': '國家/地區',
  16 + 'app.settings.basic.country-message': '請輸入您的國家或地區!',
  17 + 'app.settings.basic.geographic': '所在省市',
  18 + 'app.settings.basic.geographic-message': '請輸入您的所在省市!',
  19 + 'app.settings.basic.address': '街道地址',
  20 + 'app.settings.basic.address-message': '請輸入您的街道地址!',
  21 + 'app.settings.basic.phone': '聯系電話',
  22 + 'app.settings.basic.phone-message': '請輸入您的聯系電話!',
  23 + 'app.settings.basic.update': '更新基本信息',
  24 + 'app.settings.security.strong': '強',
  25 + 'app.settings.security.medium': '中',
  26 + 'app.settings.security.weak': '弱',
  27 + 'app.settings.security.password': '賬戶密碼',
  28 + 'app.settings.security.password-description': '當前密碼強度:',
  29 + 'app.settings.security.phone': '密保手機',
  30 + 'app.settings.security.phone-description': '已綁定手機:',
  31 + 'app.settings.security.question': '密保問題',
  32 + 'app.settings.security.question-description': '未設置密保問題,密保問題可有效保護賬戶安全',
  33 + 'app.settings.security.email': '備用郵箱',
  34 + 'app.settings.security.email-description': '已綁定郵箱:',
  35 + 'app.settings.security.mfa': 'MFA 設備',
  36 + 'app.settings.security.mfa-description': '未綁定 MFA 設備,綁定後,可以進行二次確認',
  37 + 'app.settings.security.modify': '修改',
  38 + 'app.settings.security.set': '設置',
  39 + 'app.settings.security.bind': '綁定',
  40 + 'app.settings.binding.taobao': '綁定淘寶',
  41 + 'app.settings.binding.taobao-description': '當前未綁定淘寶賬號',
  42 + 'app.settings.binding.alipay': '綁定支付寶',
  43 + 'app.settings.binding.alipay-description': '當前未綁定支付寶賬號',
  44 + 'app.settings.binding.dingding': '綁定釘釘',
  45 + 'app.settings.binding.dingding-description': '當前未綁定釘釘賬號',
  46 + 'app.settings.binding.bind': '綁定',
  47 + 'app.settings.notification.password': '賬戶密碼',
  48 + 'app.settings.notification.password-description': '其他用戶的消息將以站內信的形式通知',
  49 + 'app.settings.notification.messages': '系統消息',
  50 + 'app.settings.notification.messages-description': '系統消息將以站內信的形式通知',
  51 + 'app.settings.notification.todo': '待辦任務',
  52 + 'app.settings.notification.todo-description': '待辦任務將以站內信的形式通知',
  53 + 'app.settings.open': '開',
  54 + 'app.settings.close': '關',
  55 +};
... ...
  1 +import { queryProvince, queryCity } from '@/services/geographic';
  2 +
  3 +export default {
  4 + namespace: 'geographic',
  5 +
  6 + state: {
  7 + province: [],
  8 + city: [],
  9 + isLoading: false,
  10 + },
  11 +
  12 + effects: {
  13 + *fetchProvince(_, { call, put }) {
  14 + yield put({
  15 + type: 'changeLoading',
  16 + payload: true,
  17 + });
  18 + const response = yield call(queryProvince);
  19 + yield put({
  20 + type: 'setProvince',
  21 + payload: response,
  22 + });
  23 + yield put({
  24 + type: 'changeLoading',
  25 + payload: false,
  26 + });
  27 + },
  28 + *fetchCity({ payload }, { call, put }) {
  29 + yield put({
  30 + type: 'changeLoading',
  31 + payload: true,
  32 + });
  33 + const response = yield call(queryCity, payload);
  34 + yield put({
  35 + type: 'setCity',
  36 + payload: response,
  37 + });
  38 + yield put({
  39 + type: 'changeLoading',
  40 + payload: false,
  41 + });
  42 + },
  43 + },
  44 +
  45 + reducers: {
  46 + setProvince(state, action) {
  47 + return {
  48 + ...state,
  49 + province: action.payload,
  50 + };
  51 + },
  52 + setCity(state, action) {
  53 + return {
  54 + ...state,
  55 + city: action.payload,
  56 + };
  57 + },
  58 + changeLoading(state, action) {
  59 + return {
  60 + ...state,
  61 + isLoading: action.payload,
  62 + };
  63 + },
  64 + },
  65 +};
... ...
  1 +import { message } from 'antd';
  2 +import defaultSettings from '../defaultSettings';
  3 +
  4 +let lessNodesAppended;
  5 +const updateTheme = primaryColor => {
  6 + // Don't compile less in production!
  7 + if (APP_TYPE !== 'site') {
  8 + return;
  9 + }
  10 + // Determine if the component is remounted
  11 + if (!primaryColor) {
  12 + return;
  13 + }
  14 + const hideMessage = message.loading('正在编译主题!', 0);
  15 + function buildIt() {
  16 + if (!window.less) {
  17 + return;
  18 + }
  19 + setTimeout(() => {
  20 + window.less
  21 + .modifyVars({
  22 + '@primary-color': primaryColor,
  23 + })
  24 + .then(() => {
  25 + hideMessage();
  26 + })
  27 + .catch(() => {
  28 + message.error('Failed to update theme');
  29 + hideMessage();
  30 + });
  31 + }, 200);
  32 + }
  33 + if (!lessNodesAppended) {
  34 + // insert less.js and color.less
  35 + const lessStyleNode = document.createElement('link');
  36 + const lessConfigNode = document.createElement('script');
  37 + const lessScriptNode = document.createElement('script');
  38 + lessStyleNode.setAttribute('rel', 'stylesheet/less');
  39 + lessStyleNode.setAttribute('href', '/color.less');
  40 + lessConfigNode.innerHTML = `
  41 + window.less = {
  42 + async: true,
  43 + env: 'production',
  44 + javascriptEnabled: true
  45 + };
  46 + `;
  47 + lessScriptNode.src = 'https://gw.alipayobjects.com/os/lib/less.js/3.8.1/less.min.js';
  48 + lessScriptNode.async = true;
  49 + lessScriptNode.onload = () => {
  50 + buildIt();
  51 + lessScriptNode.onload = null;
  52 + };
  53 + document.body.appendChild(lessStyleNode);
  54 + document.body.appendChild(lessConfigNode);
  55 + document.body.appendChild(lessScriptNode);
  56 + lessNodesAppended = true;
  57 + } else {
  58 + buildIt();
  59 + }
  60 +};
  61 +
  62 +const updateColorWeak = colorWeak => {
  63 + document.body.className = colorWeak ? 'colorWeak' : '';
  64 +};
  65 +
  66 +export default {
  67 + namespace: 'setting',
  68 + state: defaultSettings,
  69 + reducers: {
  70 + getSetting(state) {
  71 + const setting = {};
  72 + const urlParams = new URL(window.location.href);
  73 + Object.keys(state).forEach(key => {
  74 + if (urlParams.searchParams.has(key)) {
  75 + const value = urlParams.searchParams.get(key);
  76 + setting[key] = value === '1' ? true : value;
  77 + }
  78 + });
  79 + const { primaryColor, colorWeak } = setting;
  80 + if (state.primaryColor !== primaryColor) {
  81 + updateTheme(primaryColor);
  82 + }
  83 + updateColorWeak(colorWeak);
  84 + return {
  85 + ...state,
  86 + ...setting,
  87 + };
  88 + },
  89 + changeSetting(state, { payload }) {
  90 + const urlParams = new URL(window.location.href);
  91 + Object.keys(defaultSettings).forEach(key => {
  92 + if (urlParams.searchParams.has(key)) {
  93 + urlParams.searchParams.delete(key);
  94 + }
  95 + });
  96 + Object.keys(payload).forEach(key => {
  97 + if (key === 'collapse') {
  98 + return;
  99 + }
  100 + let value = payload[key];
  101 + if (value === true) {
  102 + value = 1;
  103 + }
  104 + if (defaultSettings[key] !== value) {
  105 + urlParams.searchParams.set(key, value);
  106 + }
  107 + });
  108 + const { primaryColor, colorWeak, contentWidth } = payload;
  109 + if (state.primaryColor !== primaryColor) {
  110 + updateTheme(primaryColor);
  111 + }
  112 + if (state.contentWidth !== contentWidth && window.dispatchEvent) {
  113 + window.dispatchEvent(new Event('resize'));
  114 + }
  115 + updateColorWeak(colorWeak);
  116 + window.history.replaceState(null, 'setting', urlParams.href);
  117 + return {
  118 + ...state,
  119 + ...payload,
  120 + };
  121 + },
  122 + },
  123 +};
... ...
  1 +import { query as queryUsers, queryCurrent } from '@/services/user';
  2 +
  3 +export default {
  4 + namespace: 'user',
  5 +
  6 + state: {
  7 + list: [],
  8 + currentUser: {},
  9 + },
  10 +
  11 + effects: {
  12 + *fetch(_, { call, put }) {
  13 + const response = yield call(queryUsers);
  14 + yield put({
  15 + type: 'save',
  16 + payload: response,
  17 + });
  18 + },
  19 + *fetchCurrent(_, { call, put }) {
  20 + const response = yield call(queryCurrent);
  21 + yield put({
  22 + type: 'saveCurrentUser',
  23 + payload: response,
  24 + });
  25 + },
  26 + },
  27 +
  28 + reducers: {
  29 + save(state, action) {
  30 + return {
  31 + ...state,
  32 + list: action.payload,
  33 + };
  34 + },
  35 + saveCurrentUser(state, action) {
  36 + return {
  37 + ...state,
  38 + currentUser: action.payload || {},
  39 + };
  40 + },
  41 + changeNotifyCount(state, action) {
  42 + return {
  43 + ...state,
  44 + currentUser: {
  45 + ...state.currentUser,
  46 + notifyCount: action.payload.totalCount,
  47 + unreadCount: action.payload.unreadCount,
  48 + },
  49 + };
  50 + },
  51 + },
  52 +};
... ...
注册登录 后发表评论