提交 190c6de91dcfe084ffbef91018aa78905595f36c

作者 陈帅
提交者 GitHub
1 个父辈 1b79788e

Revert "use pro submodule (#36)" (#38)

This reverts commit 1b79788e.
正在显示 55 个修改的文件 包含 4826 行增加4 行删除

要显示太多修改。

为保证性能只显示 55 of 55+ 个文件。

1   -[submodule "ant-design-pro"]
2   - path = ant-design-pro
3   - url = https://github.com/ant-design/pro-blocks
ant-design-pro @ f0fff39a
1   -Subproject commit f0fff39a40abd7a5c8611075ebe3aca0e3d5c715
  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', { layout: 'ant-design-pro' }],
  4 + [
  5 + 'umi-plugin-react',
  6 + {
  7 + dva: true,
  8 + locale: true,
  9 + antd: true,
  10 + },
  11 + ],
  12 + ],
  13 +};
... ...
  1 +# @umi-blocks/ant-design-pro/accountcenter
  2 +
  3 +AccountCenter
  4 +
  5 +## Usage
  6 +
  7 +```sh
  8 +umi block add ant-design-pro/AccountCenter
  9 +```
  10 +
  11 +## SNAPSHOT
  12 +
  13 +![SNAPSHOT](./snapshot.png)
  14 +
  15 +## LICENSE
  16 +
  17 +MIT
... ...
  1 +{
  2 + "name": "@umi-block/account-center",
  3 + "version": "0.0.1",
  4 + "description": "AccountCenter",
  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/ant-design-pro/accountcenter"
  12 + },
  13 + "dependencies": {
  14 + "antd": "^3.10.9",
  15 + "dva": "^2.4.0",
  16 + "react": "^16.6.3",
  17 + "umi-request": "^1.0.0"
  18 + },
  19 + "devDependencies": {
  20 + "umi": "^2.3.0-beta.1",
  21 + "umi-plugin-react": "^1.3.0-beta.1",
  22 + "umi-plugin-block-dev": "^2.0.0"
  23 + },
  24 + "license": "ISC",
  25 + "blockConfig": {
  26 + "specVersion": "0.1"
  27 + }
  28 +}
\ No newline at end of file
... ...
  1 +@import '~antd/lib/style/themes/default.less';
  2 +
  3 +.avatarHolder {
  4 + text-align: center;
  5 + margin-bottom: 24px;
  6 +
  7 + & > img {
  8 + width: 104px;
  9 + height: 104px;
  10 + margin-bottom: 20px;
  11 + }
  12 +
  13 + .name {
  14 + font-size: 20px;
  15 + line-height: 28px;
  16 + font-weight: 500;
  17 + color: @heading-color;
  18 + margin-bottom: 4px;
  19 + }
  20 +}
  21 +
  22 +.detail {
  23 + p {
  24 + margin-bottom: 8px;
  25 + padding-left: 26px;
  26 + position: relative;
  27 +
  28 + &:last-child {
  29 + margin-bottom: 0;
  30 + }
  31 + }
  32 +
  33 + i {
  34 + position: absolute;
  35 + height: 14px;
  36 + width: 14px;
  37 + left: 0;
  38 + top: 4px;
  39 + background: url(https://gw.alipayobjects.com/zos/rmsportal/pBjWzVAHnOOtAUvZmZfy.svg);
  40 +
  41 + &.title {
  42 + background-position: 0 0;
  43 + }
  44 +
  45 + &.group {
  46 + background-position: 0 -22px;
  47 + }
  48 +
  49 + &.address {
  50 + background-position: 0 -44px;
  51 + }
  52 + }
  53 +}
  54 +
  55 +.tagsTitle,
  56 +.teamTitle {
  57 + font-weight: 500;
  58 + color: @heading-color;
  59 + margin-bottom: 12px;
  60 +}
  61 +
  62 +.tags {
  63 + :global {
  64 + .ant-tag {
  65 + margin-bottom: 8px;
  66 + }
  67 + }
  68 +}
  69 +
  70 +.team {
  71 + :global {
  72 + .ant-avatar {
  73 + margin-right: 12px;
  74 + }
  75 + }
  76 +
  77 + a {
  78 + display: block;
  79 + margin-bottom: 24px;
  80 + color: @text-color;
  81 + transition: color 0.3s;
  82 + overflow: hidden;
  83 + text-overflow: ellipsis;
  84 + word-break: break-all;
  85 + white-space: nowrap;
  86 +
  87 + &:hover {
  88 + color: @primary-color;
  89 + }
  90 + }
  91 +}
  92 +
  93 +.tabsCard {
  94 + :global {
  95 + .ant-card-head {
  96 + padding: 0 16px;
  97 + }
  98 + }
  99 +}
... ...
  1 +const titles = [
  2 + 'Alipay',
  3 + 'Angular',
  4 + 'Ant Design',
  5 + 'Ant Design Pro',
  6 + 'Bootstrap',
  7 + 'React',
  8 + 'Vue',
  9 + 'Webpack',
  10 +];
  11 +const avatars = [
  12 + 'https://gw.alipayobjects.com/zos/rmsportal/WdGqmHpayyMjiEhcKoVE.png', // Alipay
  13 + 'https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png', // Angular
  14 + 'https://gw.alipayobjects.com/zos/rmsportal/dURIMkkrRFpPgTuzkwnB.png', // Ant Design
  15 + 'https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png', // Ant Design Pro
  16 + 'https://gw.alipayobjects.com/zos/rmsportal/siCrBXXhmvTQGWPNLBow.png', // Bootstrap
  17 + 'https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png', // React
  18 + 'https://gw.alipayobjects.com/zos/rmsportal/ComBAopevLwENQdKWiIn.png', // Vue
  19 + 'https://gw.alipayobjects.com/zos/rmsportal/nxkuOJlFJuAUhzlMTCEe.png', // Webpack
  20 +];
  21 +
  22 +const getNotice = [
  23 + {
  24 + id: 'xxx1',
  25 + title: titles[0],
  26 + logo: avatars[0],
  27 + description: '那是一种内在的东西,他们到达不了,也无法触及的',
  28 + updatedAt: new Date(),
  29 + member: '科学搬砖组',
  30 + href: '',
  31 + memberLink: '',
  32 + },
  33 + {
  34 + id: 'xxx2',
  35 + title: titles[1],
  36 + logo: avatars[1],
  37 + description: '希望是一个好东西,也许是最好的,好东西是不会消亡的',
  38 + updatedAt: new Date('2017-07-24'),
  39 + member: '全组都是吴彦祖',
  40 + href: '',
  41 + memberLink: '',
  42 + },
  43 + {
  44 + id: 'xxx3',
  45 + title: titles[2],
  46 + logo: avatars[2],
  47 + description: '城镇中有那么多的酒馆,她却偏偏走进了我的酒馆',
  48 + updatedAt: new Date(),
  49 + member: '中二少女团',
  50 + href: '',
  51 + memberLink: '',
  52 + },
  53 + {
  54 + id: 'xxx4',
  55 + title: titles[3],
  56 + logo: avatars[3],
  57 + description: '那时候我只会想自己想要什么,从不想自己拥有什么',
  58 + updatedAt: new Date('2017-07-23'),
  59 + member: '程序员日常',
  60 + href: '',
  61 + memberLink: '',
  62 + },
  63 + {
  64 + id: 'xxx5',
  65 + title: titles[4],
  66 + logo: avatars[4],
  67 + description: '凛冬将至',
  68 + updatedAt: new Date('2017-07-23'),
  69 + member: '高逼格设计天团',
  70 + href: '',
  71 + memberLink: '',
  72 + },
  73 + {
  74 + id: 'xxx6',
  75 + title: titles[5],
  76 + logo: avatars[5],
  77 + description: '生命就像一盒巧克力,结果往往出人意料',
  78 + updatedAt: new Date('2017-07-23'),
  79 + member: '骗你来学计算机',
  80 + href: '',
  81 + memberLink: '',
  82 + },
  83 +];
  84 +
  85 +export default {
  86 + // 支持值为 Object 和 Array
  87 + 'GET /api/BLOCK_NAME/currentUser': {
  88 + name: 'Serati Ma',
  89 + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png',
  90 + userid: '00000001',
  91 + email: 'antdesign@alipay.com',
  92 + signature: '海纳百川,有容乃大',
  93 + title: '交互专家',
  94 + group: '蚂蚁金服-某某某事业群-某某平台部-某某技术部-UED',
  95 + notice: getNotice,
  96 + tags: [
  97 + {
  98 + key: '0',
  99 + label: '很有想法的',
  100 + },
  101 + {
  102 + key: '1',
  103 + label: '专注设计',
  104 + },
  105 + {
  106 + key: '2',
  107 + label: '辣~',
  108 + },
  109 + {
  110 + key: '3',
  111 + label: '大长腿',
  112 + },
  113 + {
  114 + key: '4',
  115 + label: '川妹子',
  116 + },
  117 + {
  118 + key: '5',
  119 + label: '海纳百川',
  120 + },
  121 + ],
  122 + notifyCount: 12,
  123 + unreadCount: 11,
  124 + country: 'China',
  125 + geographic: {
  126 + province: {
  127 + label: '浙江省',
  128 + key: '330000',
  129 + },
  130 + city: {
  131 + label: '杭州市',
  132 + key: '330100',
  133 + },
  134 + },
  135 + address: '西湖区工专路 77 号',
  136 + phone: '0752-268888888',
  137 + },
  138 +};
... ...
  1 +import React, { PureComponent } from 'react';
  2 +import { connect } from 'dva';
  3 +import Link from 'umi/link';
  4 +import { Card, Row, Col, Icon, Avatar, Tag, Divider, Input } from 'antd';
  5 +import styles from './Center.less';
  6 +
  7 +const operationTabList = [
  8 + {
  9 + key: 'articles',
  10 + tab: (
  11 + <span>
  12 + 文章 <span style={{ fontSize: 14 }}>(8)</span>
  13 + </span>
  14 + ),
  15 + },
  16 + {
  17 + key: 'applications',
  18 + tab: (
  19 + <span>
  20 + 应用 <span style={{ fontSize: 14 }}>(8)</span>
  21 + </span>
  22 + ),
  23 + },
  24 + {
  25 + key: 'projects',
  26 + tab: (
  27 + <span>
  28 + 项目 <span style={{ fontSize: 14 }}>(8)</span>
  29 + </span>
  30 + ),
  31 + },
  32 +];
  33 +
  34 +@connect(({ loading, BLOCK_NAME_CAMEL_CASE }) => ({
  35 + currentUser: BLOCK_NAME_CAMEL_CASE.currentUser,
  36 + currentUserLoading: loading.effects['BLOCK_NAME_CAMEL_CASE/fetchCurrent'],
  37 +}))
  38 +class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent {
  39 + static getDerivedStateFromProps(props, state) {
  40 + const { match, location } = props;
  41 + const { tabKey } = state;
  42 + const urlTabKey = location.pathname.replace(`${match.path}/`, '');
  43 + if (urlTabKey && urlTabKey !== '/' && tabKey !== urlTabKey) {
  44 + return {
  45 + tabKey: urlTabKey,
  46 + };
  47 + }
  48 + return null;
  49 + }
  50 +
  51 + state = {
  52 + newTags: [],
  53 + inputVisible: false,
  54 + inputValue: '',
  55 + tabKey: 'articles',
  56 + };
  57 +
  58 + componentDidMount() {
  59 + const { dispatch } = this.props;
  60 + dispatch({
  61 + type: 'BLOCK_NAME_CAMEL_CASE/fetchCurrent',
  62 + });
  63 + }
  64 +
  65 + onTabChange = key => {
  66 + // If you need to sync state to url
  67 + // const { match } = this.props;
  68 + // router.push(`${match.url}/${key}`);
  69 + this.setState({
  70 + tabKey: key,
  71 + });
  72 + };
  73 +
  74 + showInput = () => {
  75 + this.setState({ inputVisible: true }, () => this.input.focus());
  76 + };
  77 +
  78 + saveInputRef = input => {
  79 + this.input = input;
  80 + };
  81 +
  82 + handleInputChange = e => {
  83 + this.setState({ inputValue: e.target.value });
  84 + };
  85 +
  86 + handleInputConfirm = () => {
  87 + const { state } = this;
  88 + const { inputValue } = state;
  89 + let { newTags } = state;
  90 + if (inputValue && newTags.filter(tag => tag.label === inputValue).length === 0) {
  91 + newTags = [...newTags, { key: `new-${newTags.length}`, label: inputValue }];
  92 + }
  93 + this.setState({
  94 + newTags,
  95 + inputVisible: false,
  96 + inputValue: '',
  97 + });
  98 + };
  99 +
  100 + render() {
  101 + const { newTags, inputVisible, inputValue, tabKey } = this.state;
  102 + const { currentUser, currentUserLoading, children } = this.props;
  103 + const dataLoading = currentUserLoading || !(currentUser && Object.keys(currentUser).length);
  104 + return (
  105 + <Row gutter={24}>
  106 + <Col lg={7} md={24}>
  107 + <Card bordered={false} style={{ marginBottom: 24 }} loading={dataLoading}>
  108 + {!dataLoading ? (
  109 + <div>
  110 + <div className={styles.avatarHolder}>
  111 + <img alt="" src={currentUser.avatar} />
  112 + <div className={styles.name}>{currentUser.name}</div>
  113 + <div>{currentUser.signature}</div>
  114 + </div>
  115 + <div className={styles.detail}>
  116 + <p>
  117 + <i className={styles.title} />
  118 + {currentUser.title}
  119 + </p>
  120 + <p>
  121 + <i className={styles.group} />
  122 + {currentUser.group}
  123 + </p>
  124 + <p>
  125 + <i className={styles.address} />
  126 + {currentUser.geographic.province.label}
  127 + {currentUser.geographic.city.label}
  128 + </p>
  129 + </div>
  130 + <Divider dashed />
  131 + <div className={styles.tags}>
  132 + <div className={styles.tagsTitle}>标签</div>
  133 + {currentUser.tags.concat(newTags).map(item => (
  134 + <Tag key={item.key}>{item.label}</Tag>
  135 + ))}
  136 + {inputVisible && (
  137 + <Input
  138 + ref={this.saveInputRef}
  139 + type="text"
  140 + size="small"
  141 + style={{ width: 78 }}
  142 + value={inputValue}
  143 + onChange={this.handleInputChange}
  144 + onBlur={this.handleInputConfirm}
  145 + onPressEnter={this.handleInputConfirm}
  146 + />
  147 + )}
  148 + {!inputVisible && (
  149 + <Tag
  150 + onClick={this.showInput}
  151 + style={{ background: '#fff', borderStyle: 'dashed' }}
  152 + >
  153 + <Icon type="plus" />
  154 + </Tag>
  155 + )}
  156 + </div>
  157 + <Divider style={{ marginTop: 16 }} dashed />
  158 + <div className={styles.team}>
  159 + <div className={styles.teamTitle}>团队</div>
  160 + <Row gutter={36}>
  161 + {currentUser.notice.map(item => (
  162 + <Col key={item.id} lg={24} xl={12}>
  163 + <Link to={item.href}>
  164 + <Avatar size="small" src={item.logo} />
  165 + {item.member}
  166 + </Link>
  167 + </Col>
  168 + ))}
  169 + </Row>
  170 + </div>
  171 + </div>
  172 + ) : null}
  173 + </Card>
  174 + </Col>
  175 + <Col lg={17} md={24}>
  176 + <Card
  177 + className={styles.tabsCard}
  178 + bordered={false}
  179 + tabList={operationTabList}
  180 + activeTabKey={tabKey}
  181 + onTabChange={this.onTabChange}
  182 + >
  183 + {children || tabKey}
  184 + </Card>
  185 + </Col>
  186 + </Row>
  187 + );
  188 + }
  189 +}
  190 +
  191 +export default PAGE_NAME_UPPER_CAMEL_CASE;
... ...
  1 +import { query as queryUsers, queryCurrent } from './service';
  2 +
  3 +export default {
  4 + namespace: 'BLOCK_NAME_CAMEL_CASE',
  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 +};
... ...
  1 +import request from 'umi-request';
  2 +
  3 +export async function query() {
  4 + return request('/api/BLOCK_NAME/users');
  5 +}
  6 +
  7 +export async function queryCurrent() {
  8 + return request('/api/BLOCK_NAME/currentUser');
  9 +}
... ...
  1 +/yarn.lock
  2 +/package-lock.json
  3 +/dist
  4 +/node_modules
  5 +
  6 +.umi
  7 +.umi-production
... ...
  1 +export default {
  2 + plugins: [
  3 + [
  4 + 'umi-plugin-block-dev',
  5 + {
  6 + layout: 'ant-design-pro',
  7 + },
  8 + ],
  9 + [
  10 + 'umi-plugin-react',
  11 + {
  12 + dva: true,
  13 + locale: true,
  14 + antd: true,
  15 + },
  16 + ],
  17 + ],
  18 +};
... ...
  1 +# @umi-blocks/ant-design-pro/accountsettings
  2 +
  3 +AccountSettings
  4 +
  5 +## Usage
  6 +
  7 +```sh
  8 +umi block add ant-design-pro/AccountSettings
  9 +```
  10 +
  11 +## SNAPSHOT
  12 +
  13 +![SNAPSHOT](./snapshot.png)
  14 +
  15 +## LICENSE
  16 +
  17 +MIT
... ...
  1 +{
  2 + "compilerOptions": {
  3 + "emitDecoratorMetadata": true,
  4 + "experimentalDecorators": true,
  5 + "baseUrl": ".",
  6 + "paths": {
  7 + "@/*": ["./src/*"]
  8 + }
  9 + }
  10 +}
... ...
  1 +{
  2 + "name": "@umi-block/account-settings",
  3 + "version": "0.0.1",
  4 + "description": "AccountSettings",
  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/ant-design-pro/accountsettings"
  12 + },
  13 + "dependencies": {
  14 + "antd": "^3.10.9",
  15 + "dva": "^2.4.0",
  16 + "react": "^16.6.3",
  17 + "umi-request": "^1.0.0"
  18 + },
  19 + "devDependencies": {
  20 + "umi": "^2.3.0-beta.1",
  21 + "umi-plugin-block-dev": "^2.0.0",
  22 + "umi-plugin-react": "^1.3.0-beta.1"
  23 + },
  24 + "license": "ISC",
  25 + "blockConfig": {
  26 + "specVersion": "0.1"
  27 + }
  28 +}
\ No newline at end of file
... ...
  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 +// 代码中会兼容本地 service mock 以及部署站点的静态数据
  12 +export default {
  13 + // 支持值为 Object 和 Array
  14 + 'GET /api/BLOCK_NAME/currentUser': {
  15 + name: 'Serati Ma',
  16 + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png',
  17 + userid: '00000001',
  18 + email: 'antdesign@alipay.com',
  19 + signature: '海纳百川,有容乃大',
  20 + title: '交互专家',
  21 + group: '蚂蚁金服-某某某事业群-某某平台部-某某技术部-UED',
  22 + tags: [
  23 + {
  24 + key: '0',
  25 + label: '很有想法的',
  26 + },
  27 + {
  28 + key: '1',
  29 + label: '专注设计',
  30 + },
  31 + {
  32 + key: '2',
  33 + label: '辣~',
  34 + },
  35 + {
  36 + key: '3',
  37 + label: '大长腿',
  38 + },
  39 + {
  40 + key: '4',
  41 + label: '川妹子',
  42 + },
  43 + {
  44 + key: '5',
  45 + label: '海纳百川',
  46 + },
  47 + ],
  48 + notifyCount: 12,
  49 + unreadCount: 11,
  50 + country: 'China',
  51 + geographic: {
  52 + province: {
  53 + label: '浙江省',
  54 + key: '330000',
  55 + },
  56 + city: {
  57 + label: '杭州市',
  58 + key: '330100',
  59 + },
  60 + },
  61 + address: '西湖区工专路 77 号',
  62 + phone: '0752-268888888',
  63 + },
  64 + 'GET /api/BLOCK_NAME/province': getProvince,
  65 + 'GET /api/BLOCK_NAME/city/:province': getCity,
  66 +};
... ...
  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(({ BLOCK_NAME_CAMEL_CASE, loading }) => {
  14 + const { province, city } = BLOCK_NAME_CAMEL_CASE;
  15 + return {
  16 + province,
  17 + city,
  18 + loading: loading.models.BLOCK_NAME_CAMEL_CASE,
  19 + };
  20 +})
  21 +class GeographicView extends PureComponent {
  22 + componentDidMount = () => {
  23 + const { dispatch } = this.props;
  24 + dispatch({
  25 + type: 'BLOCK_NAME_CAMEL_CASE/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: 'BLOCK_NAME_CAMEL_CASE/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: 'BLOCK_NAME_CAMEL_CASE/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 { loading } = this.props;
  103 + return (
  104 + <Spin spinning={loading} 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 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 +
  9 +const FormItem = Form.Item;
  10 +const { Option } = Select;
  11 +
  12 +// 头像组件 方便以后独立,增加裁剪之类的功能
  13 +const AvatarView = ({ avatar }) => (
  14 + <Fragment>
  15 + <div className={styles.avatar_title}>
  16 + <FormattedMessage id="BLOCK_NAME.basic.avatar" defaultMessage="Avatar" />
  17 + </div>
  18 + <div className={styles.avatar}>
  19 + <img src={avatar} alt="avatar" />
  20 + </div>
  21 + <Upload fileList={[]}>
  22 + <div className={styles.button_view}>
  23 + <Button icon="upload">
  24 + <FormattedMessage id="BLOCK_NAME.basic.change-avatar" defaultMessage="Change avatar" />
  25 + </Button>
  26 + </div>
  27 + </Upload>
  28 + </Fragment>
  29 +);
  30 +
  31 +const validatorGeographic = (rule, value, callback) => {
  32 + const { province, city } = value;
  33 + if (!province.key) {
  34 + callback('Please input your province!');
  35 + }
  36 + if (!city.key) {
  37 + callback('Please input your city!');
  38 + }
  39 + callback();
  40 +};
  41 +
  42 +const validatorPhone = (rule, value, callback) => {
  43 + const values = value.split('-');
  44 + if (!values[0]) {
  45 + callback('Please input your area code!');
  46 + }
  47 + if (!values[1]) {
  48 + callback('Please input your phone number!');
  49 + }
  50 + callback();
  51 +};
  52 +
  53 +@connect(({ BLOCK_NAME_CAMEL_CASE }) => ({
  54 + currentUser: BLOCK_NAME_CAMEL_CASE.currentUser,
  55 +}))
  56 +@Form.create()
  57 +class BaseView extends Component {
  58 + componentDidMount() {
  59 + this.setBaseInfo();
  60 + }
  61 +
  62 + setBaseInfo = () => {
  63 + const { currentUser, form } = this.props;
  64 + Object.keys(form.getFieldsValue()).forEach(key => {
  65 + const obj = {};
  66 + obj[key] = currentUser[key] || null;
  67 + form.setFieldsValue(obj);
  68 + });
  69 + };
  70 +
  71 + getAvatarURL() {
  72 + const { currentUser } = this.props;
  73 + if (currentUser.avatar) {
  74 + return currentUser.avatar;
  75 + }
  76 + const url = 'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png';
  77 + return url;
  78 + }
  79 +
  80 + getViewDom = ref => {
  81 + this.view = ref;
  82 + };
  83 +
  84 + render() {
  85 + const {
  86 + form: { getFieldDecorator },
  87 + } = this.props;
  88 + return (
  89 + <div className={styles.baseView} ref={this.getViewDom}>
  90 + <div className={styles.left}>
  91 + <Form layout="vertical" onSubmit={this.handleSubmit} hideRequiredMark>
  92 + <FormItem label={formatMessage({ id: 'BLOCK_NAME.basic.email' })}>
  93 + {getFieldDecorator('email', {
  94 + rules: [
  95 + {
  96 + required: true,
  97 + message: formatMessage({ id: 'BLOCK_NAME.basic.email-message' }, {}),
  98 + },
  99 + ],
  100 + })(<Input />)}
  101 + </FormItem>
  102 + <FormItem label={formatMessage({ id: 'BLOCK_NAME.basic.nickname' })}>
  103 + {getFieldDecorator('name', {
  104 + rules: [
  105 + {
  106 + required: true,
  107 + message: formatMessage({ id: 'BLOCK_NAME.basic.nickname-message' }, {}),
  108 + },
  109 + ],
  110 + })(<Input />)}
  111 + </FormItem>
  112 + <FormItem label={formatMessage({ id: 'BLOCK_NAME.basic.profile' })}>
  113 + {getFieldDecorator('profile', {
  114 + rules: [
  115 + {
  116 + required: true,
  117 + message: formatMessage({ id: 'BLOCK_NAME.basic.profile-message' }, {}),
  118 + },
  119 + ],
  120 + })(
  121 + <Input.TextArea
  122 + placeholder={formatMessage({ id: 'BLOCK_NAME.basic.profile-placeholder' })}
  123 + rows={4}
  124 + />
  125 + )}
  126 + </FormItem>
  127 + <FormItem label={formatMessage({ id: 'BLOCK_NAME.basic.country' })}>
  128 + {getFieldDecorator('country', {
  129 + rules: [
  130 + {
  131 + required: true,
  132 + message: formatMessage({ id: 'BLOCK_NAME.basic.country-message' }, {}),
  133 + },
  134 + ],
  135 + })(
  136 + <Select style={{ maxWidth: 220 }}>
  137 + <Option value="China">中国</Option>
  138 + </Select>
  139 + )}
  140 + </FormItem>
  141 + <FormItem label={formatMessage({ id: 'BLOCK_NAME.basic.geographic' })}>
  142 + {getFieldDecorator('geographic', {
  143 + rules: [
  144 + {
  145 + required: true,
  146 + message: formatMessage({ id: 'BLOCK_NAME.basic.geographic-message' }, {}),
  147 + },
  148 + {
  149 + validator: validatorGeographic,
  150 + },
  151 + ],
  152 + })(<GeographicView />)}
  153 + </FormItem>
  154 + <FormItem label={formatMessage({ id: 'BLOCK_NAME.basic.address' })}>
  155 + {getFieldDecorator('address', {
  156 + rules: [
  157 + {
  158 + required: true,
  159 + message: formatMessage({ id: 'BLOCK_NAME.basic.address-message' }, {}),
  160 + },
  161 + ],
  162 + })(<Input />)}
  163 + </FormItem>
  164 + <FormItem label={formatMessage({ id: 'BLOCK_NAME.basic.phone' })}>
  165 + {getFieldDecorator('phone', {
  166 + rules: [
  167 + {
  168 + required: true,
  169 + message: formatMessage({ id: 'BLOCK_NAME.basic.phone-message' }, {}),
  170 + },
  171 + { validator: validatorPhone },
  172 + ],
  173 + })(<PhoneView />)}
  174 + </FormItem>
  175 + <Button type="primary">
  176 + <FormattedMessage
  177 + id="BLOCK_NAME.basic.update"
  178 + defaultMessage="Update Information"
  179 + />
  180 + </Button>
  181 + </Form>
  182 + </div>
  183 + <div className={styles.right}>
  184 + <AvatarView avatar={this.getAvatarURL()} />
  185 + </div>
  186 + </div>
  187 + );
  188 + }
  189 +}
  190 +
  191 +export default BaseView;
... ...
  1 +import React, { Component, Fragment } from 'react';
  2 +import { formatMessage, FormattedMessage } from 'umi/locale';
  3 +import { Icon, List } from 'antd';
  4 +
  5 +class BindingView extends Component {
  6 + getData = () => [
  7 + {
  8 + title: formatMessage({ id: 'BLOCK_NAME.binding.taobao' }, {}),
  9 + description: formatMessage({ id: 'BLOCK_NAME.binding.taobao-description' }, {}),
  10 + actions: [
  11 + <a>
  12 + <FormattedMessage id="BLOCK_NAME.binding.bind" defaultMessage="Bind" />
  13 + </a>,
  14 + ],
  15 + avatar: <Icon type="taobao" className="taobao" />,
  16 + },
  17 + {
  18 + title: formatMessage({ id: 'BLOCK_NAME.binding.alipay' }, {}),
  19 + description: formatMessage({ id: 'BLOCK_NAME.binding.alipay-description' }, {}),
  20 + actions: [
  21 + <a>
  22 + <FormattedMessage id="BLOCK_NAME.binding.bind" defaultMessage="Bind" />
  23 + </a>,
  24 + ],
  25 + avatar: <Icon type="alipay" className="alipay" />,
  26 + },
  27 + {
  28 + title: formatMessage({ id: 'BLOCK_NAME.binding.dingding' }, {}),
  29 + description: formatMessage({ id: 'BLOCK_NAME.binding.dingding-description' }, {}),
  30 + actions: [
  31 + <a>
  32 + <FormattedMessage id="BLOCK_NAME.binding.bind" defaultMessage="Bind" />
  33 + </a>,
  34 + ],
  35 + avatar: <Icon type="dingding" className="dingding" />,
  36 + },
  37 + ];
  38 +
  39 + render() {
  40 + return (
  41 + <Fragment>
  42 + <List
  43 + itemLayout="horizontal"
  44 + dataSource={this.getData()}
  45 + renderItem={item => (
  46 + <List.Item actions={item.actions}>
  47 + <List.Item.Meta
  48 + avatar={item.avatar}
  49 + title={item.title}
  50 + description={item.description}
  51 + />
  52 + </List.Item>
  53 + )}
  54 + />
  55 + </Fragment>
  56 + );
  57 + }
  58 +}
  59 +
  60 +export default BindingView;
... ...
  1 +import React, { Component, Fragment } from 'react';
  2 +import { formatMessage } from 'umi/locale';
  3 +import { Switch, List } from 'antd';
  4 +
  5 +class NotificationView extends Component {
  6 + getData = () => {
  7 + const Action = (
  8 + <Switch
  9 + checkedChildren={formatMessage({ id: 'BLOCK_NAME.settings.open' })}
  10 + unCheckedChildren={formatMessage({ id: 'BLOCK_NAME.settings.close' })}
  11 + defaultChecked
  12 + />
  13 + );
  14 + return [
  15 + {
  16 + title: formatMessage({ id: 'BLOCK_NAME.notification.password' }, {}),
  17 + description: formatMessage({ id: 'BLOCK_NAME.notification.password-description' }, {}),
  18 + actions: [Action],
  19 + },
  20 + {
  21 + title: formatMessage({ id: 'BLOCK_NAME.notification.messages' }, {}),
  22 + description: formatMessage({ id: 'BLOCK_NAME.notification.messages-description' }, {}),
  23 + actions: [Action],
  24 + },
  25 + {
  26 + title: formatMessage({ id: 'BLOCK_NAME.notification.todo' }, {}),
  27 + description: formatMessage({ id: 'BLOCK_NAME.notification.todo-description' }, {}),
  28 + actions: [Action],
  29 + },
  30 + ];
  31 + };
  32 +
  33 + render() {
  34 + return (
  35 + <Fragment>
  36 + <List
  37 + itemLayout="horizontal"
  38 + dataSource={this.getData()}
  39 + renderItem={item => (
  40 + <List.Item actions={item.actions}>
  41 + <List.Item.Meta title={item.title} description={item.description} />
  42 + </List.Item>
  43 + )}
  44 + />
  45 + </Fragment>
  46 + );
  47 + }
  48 +}
  49 +
  50 +export default NotificationView;
... ...
  1 +import React, { Component, Fragment } from 'react';
  2 +import { formatMessage, FormattedMessage } from 'umi/locale';
  3 +import { List } from 'antd';
  4 +// import { getTimeDistance } from '@/utils/utils';
  5 +
  6 +const passwordStrength = {
  7 + strong: (
  8 + <font className="strong">
  9 + <FormattedMessage id="BLOCK_NAME.security.strong" defaultMessage="Strong" />
  10 + </font>
  11 + ),
  12 + medium: (
  13 + <font className="medium">
  14 + <FormattedMessage id="BLOCK_NAME.security.medium" defaultMessage="Medium" />
  15 + </font>
  16 + ),
  17 + weak: (
  18 + <font className="weak">
  19 + <FormattedMessage id="BLOCK_NAME.security.weak" defaultMessage="Weak" />
  20 + Weak
  21 + </font>
  22 + ),
  23 +};
  24 +
  25 +class SecurityView extends Component {
  26 + getData = () => [
  27 + {
  28 + title: formatMessage({ id: 'BLOCK_NAME.security.password' }, {}),
  29 + description: (
  30 + <Fragment>
  31 + {formatMessage({ id: 'BLOCK_NAME.security.password-description' })}
  32 + {passwordStrength.strong}
  33 + </Fragment>
  34 + ),
  35 + actions: [
  36 + <a>
  37 + <FormattedMessage id="BLOCK_NAME.security.modify" defaultMessage="Modify" />
  38 + </a>,
  39 + ],
  40 + },
  41 + {
  42 + title: formatMessage({ id: 'BLOCK_NAME.security.phone' }, {}),
  43 + description: `${formatMessage(
  44 + { id: 'BLOCK_NAME.security.phone-description' },
  45 + {}
  46 + )}138****8293`,
  47 + actions: [
  48 + <a>
  49 + <FormattedMessage id="BLOCK_NAME.security.modify" defaultMessage="Modify" />
  50 + </a>,
  51 + ],
  52 + },
  53 + {
  54 + title: formatMessage({ id: 'BLOCK_NAME.security.question' }, {}),
  55 + description: formatMessage({ id: 'BLOCK_NAME.security.question-description' }, {}),
  56 + actions: [
  57 + <a>
  58 + <FormattedMessage id="BLOCK_NAME.security.set" defaultMessage="Set" />
  59 + </a>,
  60 + ],
  61 + },
  62 + {
  63 + title: formatMessage({ id: 'BLOCK_NAME.security.email' }, {}),
  64 + description: `${formatMessage(
  65 + { id: 'BLOCK_NAME.security.email-description' },
  66 + {}
  67 + )}ant***sign.com`,
  68 + actions: [
  69 + <a>
  70 + <FormattedMessage id="BLOCK_NAME.security.modify" defaultMessage="Modify" />
  71 + </a>,
  72 + ],
  73 + },
  74 + {
  75 + title: formatMessage({ id: 'BLOCK_NAME.security.mfa' }, {}),
  76 + description: formatMessage({ id: 'BLOCK_NAME.security.mfa-description' }, {}),
  77 + actions: [
  78 + <a>
  79 + <FormattedMessage id="BLOCK_NAME.security.bind" defaultMessage="Bind" />
  80 + </a>,
  81 + ],
  82 + },
  83 + ];
  84 +
  85 + render() {
  86 + return (
  87 + <Fragment>
  88 + <List
  89 + itemLayout="horizontal"
  90 + dataSource={this.getData()}
  91 + renderItem={item => (
  92 + <List.Item actions={item.actions}>
  93 + <List.Item.Meta title={item.title} description={item.description} />
  94 + </List.Item>
  95 + )}
  96 + />
  97 + </Fragment>
  98 + );
  99 + }
  100 +}
  101 +
  102 +export default SecurityView;
... ...
  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 } from 'react';
  2 +import { connect } from 'dva';
  3 +import { FormattedMessage } from 'umi/locale';
  4 +import { Menu } from 'antd';
  5 +import styles from './style.less';
  6 +import BaseView from './components/base';
  7 +import SecurityView from './components/security';
  8 +import BindingView from './components/binding';
  9 +import NotificationView from './components/notification';
  10 +
  11 +const { Item } = Menu;
  12 +
  13 +@connect(({ BLOCK_NAME_CAMEL_CASE }) => ({
  14 + currentUser: BLOCK_NAME_CAMEL_CASE.currentUser,
  15 +}))
  16 +class PAGE_NAME_UPPER_CAMEL_CASE extends Component {
  17 + constructor(props) {
  18 + super(props);
  19 + const menuMap = {
  20 + base: <FormattedMessage id="BLOCK_NAME.menuMap.basic" defaultMessage="Basic Settings" />,
  21 + security: (
  22 + <FormattedMessage id="BLOCK_NAME.menuMap.security" defaultMessage="Security Settings" />
  23 + ),
  24 + binding: (
  25 + <FormattedMessage id="BLOCK_NAME.menuMap.binding" defaultMessage="Account Binding" />
  26 + ),
  27 + notification: (
  28 + <FormattedMessage
  29 + id="BLOCK_NAME.menuMap.notification"
  30 + defaultMessage="New Message Notification"
  31 + />
  32 + ),
  33 + };
  34 + this.state = {
  35 + mode: 'inline',
  36 + menuMap,
  37 + selectKey: 'base',
  38 + };
  39 + }
  40 +
  41 + componentDidMount() {
  42 + const { dispatch } = this.props;
  43 + dispatch({
  44 + type: 'BLOCK_NAME_CAMEL_CASE/fetchCurrent',
  45 + });
  46 + window.addEventListener('resize', this.resize);
  47 + this.resize();
  48 + }
  49 +
  50 + componentWillUnmount() {
  51 + window.removeEventListener('resize', this.resize);
  52 + }
  53 +
  54 + getmenu = () => {
  55 + const { menuMap } = this.state;
  56 + return Object.keys(menuMap).map(item => <Item key={item}>{menuMap[item]}</Item>);
  57 + };
  58 +
  59 + getRightTitle = () => {
  60 + const { selectKey, menuMap } = this.state;
  61 + return menuMap[selectKey];
  62 + };
  63 +
  64 + selectKey = ({ key }) => {
  65 + this.setState({
  66 + selectKey: key,
  67 + });
  68 + };
  69 +
  70 + resize = () => {
  71 + if (!this.main) {
  72 + return;
  73 + }
  74 + requestAnimationFrame(() => {
  75 + if (!this.main) {
  76 + return;
  77 + }
  78 + let mode = 'inline';
  79 + const { offsetWidth } = this.main;
  80 + if (this.main.offsetWidth < 641 && offsetWidth > 400) {
  81 + mode = 'horizontal';
  82 + }
  83 + if (window.innerWidth < 768 && offsetWidth > 400) {
  84 + mode = 'horizontal';
  85 + }
  86 + this.setState({
  87 + mode,
  88 + });
  89 + });
  90 + };
  91 +
  92 + renderChildren = () => {
  93 + const { selectKey } = this.state;
  94 + switch (selectKey) {
  95 + case 'base':
  96 + return <BaseView />;
  97 + case 'security':
  98 + return <SecurityView />;
  99 + case 'binding':
  100 + return <BindingView />;
  101 + case 'notification':
  102 + return <NotificationView />;
  103 + default:
  104 + break;
  105 + }
  106 +
  107 + return null;
  108 + };
  109 +
  110 + render() {
  111 + const { currentUser } = this.props;
  112 + if (!currentUser.userid) {
  113 + return '';
  114 + }
  115 + const { mode, selectKey } = this.state;
  116 + return (
  117 + <div
  118 + className={styles.main}
  119 + ref={ref => {
  120 + this.main = ref;
  121 + }}
  122 + >
  123 + <div className={styles.leftmenu}>
  124 + <Menu mode={mode} selectedKeys={[selectKey]} onClick={this.selectKey}>
  125 + {this.getmenu()}
  126 + </Menu>
  127 + </div>
  128 + <div className={styles.right}>
  129 + <div className={styles.title}>{this.getRightTitle()}</div>
  130 + {this.renderChildren()}
  131 + </div>
  132 + </div>
  133 + );
  134 + }
  135 +}
  136 +
  137 +export default PAGE_NAME_UPPER_CAMEL_CASE;
... ...
  1 +export default {
  2 + 'BLOCK_NAME.menuMap.basic': 'Basic Settings',
  3 + 'BLOCK_NAME.menuMap.security': 'Security Settings',
  4 + 'BLOCK_NAME.menuMap.binding': 'Account Binding',
  5 + 'BLOCK_NAME.menuMap.notification': 'New Message Notification',
  6 + 'BLOCK_NAME.basic.avatar': 'Avatar',
  7 + 'BLOCK_NAME.basic.change-avatar': 'Change avatar',
  8 + 'BLOCK_NAME.basic.email': 'Email',
  9 + 'BLOCK_NAME.basic.email-message': 'Please input your email!',
  10 + 'BLOCK_NAME.basic.nickname': 'Nickname',
  11 + 'BLOCK_NAME.basic.nickname-message': 'Please input your Nickname!',
  12 + 'BLOCK_NAME.basic.profile': 'Personal profile',
  13 + 'BLOCK_NAME.basic.profile-message': 'Please input your personal profile!',
  14 + 'BLOCK_NAME.basic.profile-placeholder': 'Brief introduction to yourself',
  15 + 'BLOCK_NAME.basic.country': 'Country/Region',
  16 + 'BLOCK_NAME.basic.country-message': 'Please input your country!',
  17 + 'BLOCK_NAME.basic.geographic': 'Province or city',
  18 + 'BLOCK_NAME.basic.geographic-message': 'Please input your geographic info!',
  19 + 'BLOCK_NAME.basic.address': 'Street Address',
  20 + 'BLOCK_NAME.basic.address-message': 'Please input your address!',
  21 + 'BLOCK_NAME.basic.phone': 'Phone Number',
  22 + 'BLOCK_NAME.basic.phone-message': 'Please input your phone!',
  23 + 'BLOCK_NAME.basic.update': 'Update Information',
  24 + 'BLOCK_NAME.security.strong': 'Strong',
  25 + 'BLOCK_NAME.security.medium': 'Medium',
  26 + 'BLOCK_NAME.security.weak': 'Weak',
  27 + 'BLOCK_NAME.security.password': 'Account Password',
  28 + 'BLOCK_NAME.security.password-description': 'Current password strength:',
  29 + 'BLOCK_NAME.security.phone': 'Security Phone',
  30 + 'BLOCK_NAME.security.phone-description': 'Bound phone:',
  31 + 'BLOCK_NAME.security.question': 'Security Question',
  32 + 'BLOCK_NAME.security.question-description':
  33 + 'The security question is not set, and the security policy can effectively protect the account security',
  34 + 'BLOCK_NAME.security.email': 'Backup Email',
  35 + 'BLOCK_NAME.security.email-description': 'Bound Email:',
  36 + 'BLOCK_NAME.security.mfa': 'MFA Device',
  37 + 'BLOCK_NAME.security.mfa-description':
  38 + 'Unbound MFA device, after binding, can be confirmed twice',
  39 + 'BLOCK_NAME.security.modify': 'Modify',
  40 + 'BLOCK_NAME.security.set': 'Set',
  41 + 'BLOCK_NAME.security.bind': 'Bind',
  42 + 'BLOCK_NAME.binding.taobao': 'Binding Taobao',
  43 + 'BLOCK_NAME.binding.taobao-description': 'Currently unbound Taobao account',
  44 + 'BLOCK_NAME.binding.alipay': 'Binding Alipay',
  45 + 'BLOCK_NAME.binding.alipay-description': 'Currently unbound Alipay account',
  46 + 'BLOCK_NAME.binding.dingding': 'Binding DingTalk',
  47 + 'BLOCK_NAME.binding.dingding-description': 'Currently unbound DingTalk account',
  48 + 'BLOCK_NAME.binding.bind': 'Bind',
  49 + 'BLOCK_NAME.notification.password': 'Account Password',
  50 + 'BLOCK_NAME.notification.password-description':
  51 + 'Messages from other users will be notified in the form of a station letter',
  52 + 'BLOCK_NAME.notification.messages': 'System Messages',
  53 + 'BLOCK_NAME.notification.messages-description':
  54 + 'System messages will be notified in the form of a station letter',
  55 + 'BLOCK_NAME.notification.todo': 'To-do Notification',
  56 + 'BLOCK_NAME.notification.todo-description':
  57 + 'The to-do list will be notified in the form of a letter from the station',
  58 + 'BLOCK_NAME.settings.open': 'Open',
  59 + 'BLOCK_NAME.settings.close': 'Close',
  60 +};
... ...
  1 +export default {
  2 + 'BLOCK_NAME.menuMap.basic': '基本设置',
  3 + 'BLOCK_NAME.menuMap.security': '安全设置',
  4 + 'BLOCK_NAME.menuMap.binding': '账号绑定',
  5 + 'BLOCK_NAME.menuMap.notification': '新消息通知',
  6 + 'BLOCK_NAME.basic.avatar': '头像',
  7 + 'BLOCK_NAME.basic.change-avatar': '更换头像',
  8 + 'BLOCK_NAME.basic.email': '邮箱',
  9 + 'BLOCK_NAME.basic.email-message': '请输入您的邮箱!',
  10 + 'BLOCK_NAME.basic.nickname': '昵称',
  11 + 'BLOCK_NAME.basic.nickname-message': '请输入您的昵称!',
  12 + 'BLOCK_NAME.basic.profile': '个人简介',
  13 + 'BLOCK_NAME.basic.profile-message': '请输入个人简介!',
  14 + 'BLOCK_NAME.basic.profile-placeholder': '个人简介',
  15 + 'BLOCK_NAME.basic.country': '国家/地区',
  16 + 'BLOCK_NAME.basic.country-message': '请输入您的国家或地区!',
  17 + 'BLOCK_NAME.basic.geographic': '所在省市',
  18 + 'BLOCK_NAME.basic.geographic-message': '请输入您的所在省市!',
  19 + 'BLOCK_NAME.basic.address': '街道地址',
  20 + 'BLOCK_NAME.basic.address-message': '请输入您的街道地址!',
  21 + 'BLOCK_NAME.basic.phone': '联系电话',
  22 + 'BLOCK_NAME.basic.phone-message': '请输入您的联系电话!',
  23 + 'BLOCK_NAME.basic.update': '更新基本信息',
  24 + 'BLOCK_NAME.security.strong': '强',
  25 + 'BLOCK_NAME.security.medium': '中',
  26 + 'BLOCK_NAME.security.weak': '弱',
  27 + 'BLOCK_NAME.security.password': '账户密码',
  28 + 'BLOCK_NAME.security.password-description': '当前密码强度:',
  29 + 'BLOCK_NAME.security.phone': '密保手机',
  30 + 'BLOCK_NAME.security.phone-description': '已绑定手机:',
  31 + 'BLOCK_NAME.security.question': '密保问题',
  32 + 'BLOCK_NAME.security.question-description': '未设置密保问题,密保问题可有效保护账户安全',
  33 + 'BLOCK_NAME.security.email': '备用邮箱',
  34 + 'BLOCK_NAME.security.email-description': '已绑定邮箱:',
  35 + 'BLOCK_NAME.security.mfa': 'MFA 设备',
  36 + 'BLOCK_NAME.security.mfa-description': '未绑定 MFA 设备,绑定后,可以进行二次确认',
  37 + 'BLOCK_NAME.security.modify': '修改',
  38 + 'BLOCK_NAME.security.set': '设置',
  39 + 'BLOCK_NAME.security.bind': '绑定',
  40 + 'BLOCK_NAME.binding.taobao': '绑定淘宝',
  41 + 'BLOCK_NAME.binding.taobao-description': '当前未绑定淘宝账号',
  42 + 'BLOCK_NAME.binding.alipay': '绑定支付宝',
  43 + 'BLOCK_NAME.binding.alipay-description': '当前未绑定支付宝账号',
  44 + 'BLOCK_NAME.binding.dingding': '绑定钉钉',
  45 + 'BLOCK_NAME.binding.dingding-description': '当前未绑定钉钉账号',
  46 + 'BLOCK_NAME.binding.bind': '绑定',
  47 + 'BLOCK_NAME.notification.password': '账户密码',
  48 + 'BLOCK_NAME.notification.password-description': '其他用户的消息将以站内信的形式通知',
  49 + 'BLOCK_NAME.notification.messages': '系统消息',
  50 + 'BLOCK_NAME.notification.messages-description': '系统消息将以站内信的形式通知',
  51 + 'BLOCK_NAME.notification.todo': '待办任务',
  52 + 'BLOCK_NAME.notification.todo-description': '待办任务将以站内信的形式通知',
  53 + 'BLOCK_NAME.settings.open': '开',
  54 + 'BLOCK_NAME.settings.close': '关',
  55 +};
... ...
  1 +export default {
  2 + 'BLOCK_NAME.menuMap.basic': '基本設置',
  3 + 'BLOCK_NAME.menuMap.security': '安全設置',
  4 + 'BLOCK_NAME.menuMap.binding': '賬號綁定',
  5 + 'BLOCK_NAME.menuMap.notification': '新消息通知',
  6 + 'BLOCK_NAME.basic.avatar': '頭像',
  7 + 'BLOCK_NAME.basic.change-avatar': '更換頭像',
  8 + 'BLOCK_NAME.basic.email': '郵箱',
  9 + 'BLOCK_NAME.basic.email-message': '請輸入您的郵箱!',
  10 + 'BLOCK_NAME.basic.nickname': '昵稱',
  11 + 'BLOCK_NAME.basic.nickname-message': '請輸入您的昵稱!',
  12 + 'BLOCK_NAME.basic.profile': '個人簡介',
  13 + 'BLOCK_NAME.basic.profile-message': '請輸入個人簡介!',
  14 + 'BLOCK_NAME.basic.profile-placeholder': '個人簡介',
  15 + 'BLOCK_NAME.basic.country': '國家/地區',
  16 + 'BLOCK_NAME.basic.country-message': '請輸入您的國家或地區!',
  17 + 'BLOCK_NAME.basic.geographic': '所在省市',
  18 + 'BLOCK_NAME.basic.geographic-message': '請輸入您的所在省市!',
  19 + 'BLOCK_NAME.basic.address': '街道地址',
  20 + 'BLOCK_NAME.basic.address-message': '請輸入您的街道地址!',
  21 + 'BLOCK_NAME.basic.phone': '聯系電話',
  22 + 'BLOCK_NAME.basic.phone-message': '請輸入您的聯系電話!',
  23 + 'BLOCK_NAME.basic.update': '更新基本信息',
  24 + 'BLOCK_NAME.security.strong': '強',
  25 + 'BLOCK_NAME.security.medium': '中',
  26 + 'BLOCK_NAME.security.weak': '弱',
  27 + 'BLOCK_NAME.security.password': '賬戶密碼',
  28 + 'BLOCK_NAME.security.password-description': '當前密碼強度:',
  29 + 'BLOCK_NAME.security.phone': '密保手機',
  30 + 'BLOCK_NAME.security.phone-description': '已綁定手機:',
  31 + 'BLOCK_NAME.security.question': '密保問題',
  32 + 'BLOCK_NAME.security.question-description': '未設置密保問題,密保問題可有效保護賬戶安全',
  33 + 'BLOCK_NAME.security.email': '備用郵箱',
  34 + 'BLOCK_NAME.security.email-description': '已綁定郵箱:',
  35 + 'BLOCK_NAME.security.mfa': 'MFA 設備',
  36 + 'BLOCK_NAME.security.mfa-description': '未綁定 MFA 設備,綁定後,可以進行二次確認',
  37 + 'BLOCK_NAME.security.modify': '修改',
  38 + 'BLOCK_NAME.security.set': '設置',
  39 + 'BLOCK_NAME.security.bind': '綁定',
  40 + 'BLOCK_NAME.binding.taobao': '綁定淘寶',
  41 + 'BLOCK_NAME.binding.taobao-description': '當前未綁定淘寶賬號',
  42 + 'BLOCK_NAME.binding.alipay': '綁定支付寶',
  43 + 'BLOCK_NAME.binding.alipay-description': '當前未綁定支付寶賬號',
  44 + 'BLOCK_NAME.binding.dingding': '綁定釘釘',
  45 + 'BLOCK_NAME.binding.dingding-description': '當前未綁定釘釘賬號',
  46 + 'BLOCK_NAME.binding.bind': '綁定',
  47 + 'BLOCK_NAME.notification.password': '賬戶密碼',
  48 + 'BLOCK_NAME.notification.password-description': '其他用戶的消息將以站內信的形式通知',
  49 + 'BLOCK_NAME.notification.messages': '系統消息',
  50 + 'BLOCK_NAME.notification.messages-description': '系統消息將以站內信的形式通知',
  51 + 'BLOCK_NAME.notification.todo': '待辦任務',
  52 + 'BLOCK_NAME.notification.todo-description': '待辦任務將以站內信的形式通知',
  53 + 'BLOCK_NAME.settings.open': '開',
  54 + 'BLOCK_NAME.settings.close': '關',
  55 +};
... ...
  1 +import { query as queryUsers, queryCurrent, queryProvince, queryCity } from './service';
  2 +
  3 +export default {
  4 + namespace: 'BLOCK_NAME_CAMEL_CASE',
  5 +
  6 + state: {
  7 + list: [],
  8 + currentUser: {},
  9 + province: [],
  10 + city: [],
  11 + },
  12 +
  13 + effects: {
  14 + *fetch(_, { call, put }) {
  15 + const response = yield call(queryUsers);
  16 + yield put({
  17 + type: 'save',
  18 + payload: response,
  19 + });
  20 + },
  21 + *fetchCurrent(_, { call, put }) {
  22 + const response = yield call(queryCurrent);
  23 + yield put({
  24 + type: 'saveCurrentUser',
  25 + payload: response,
  26 + });
  27 + },
  28 + *fetchProvince(_, { call, put }) {
  29 + yield put({
  30 + type: 'changeLoading',
  31 + payload: true,
  32 + });
  33 + const response = yield call(queryProvince);
  34 + yield put({
  35 + type: 'setProvince',
  36 + payload: response,
  37 + });
  38 + },
  39 + *fetchCity({ payload }, { call, put }) {
  40 + const response = yield call(queryCity, payload);
  41 + yield put({
  42 + type: 'setCity',
  43 + payload: response,
  44 + });
  45 + },
  46 + },
  47 +
  48 + reducers: {
  49 + save(state, action) {
  50 + return {
  51 + ...state,
  52 + list: action.payload,
  53 + };
  54 + },
  55 + saveCurrentUser(state, action) {
  56 + return {
  57 + ...state,
  58 + currentUser: action.payload || {},
  59 + };
  60 + },
  61 + changeNotifyCount(state, action) {
  62 + return {
  63 + ...state,
  64 + currentUser: {
  65 + ...state.currentUser,
  66 + notifyCount: action.payload.totalCount,
  67 + unreadCount: action.payload.unreadCount,
  68 + },
  69 + };
  70 + },
  71 + setProvince(state, action) {
  72 + return {
  73 + ...state,
  74 + province: action.payload,
  75 + };
  76 + },
  77 + setCity(state, action) {
  78 + return {
  79 + ...state,
  80 + city: action.payload,
  81 + };
  82 + },
  83 + changeLoading(state, action) {
  84 + return {
  85 + ...state,
  86 + isLoading: action.payload,
  87 + };
  88 + },
  89 + },
  90 +};
... ...
  1 +import request from 'umi-request';
  2 +
  3 +export async function queryCurrent() {
  4 + return request('/api/BLOCK_NAME/currentUser');
  5 +}
  6 +
  7 +export async function queryProvince() {
  8 + return request('/api/BLOCK_NAME/province');
  9 +}
  10 +
  11 +export async function queryCity(province) {
  12 + return request(`/api/BLOCK_NAME/city/${province}`);
  13 +}
  14 +
  15 +export async function query() {
  16 + return request('/api/BLOCK_NAME/users');
  17 +}
... ...
  1 +@import '~antd/lib/style/themes/default.less';
  2 +
  3 +.main {
  4 + width: 100%;
  5 + height: 100%;
  6 + background-color: @body-background;
  7 + display: flex;
  8 + padding-top: 16px;
  9 + padding-bottom: 16px;
  10 + overflow: auto;
  11 + .leftmenu {
  12 + width: 224px;
  13 + border-right: @border-width-base @border-style-base @border-color-split;
  14 + :global {
  15 + .ant-menu-inline {
  16 + border: none;
  17 + }
  18 + .ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected {
  19 + font-weight: bold;
  20 + }
  21 + }
  22 + }
  23 + .right {
  24 + flex: 1;
  25 + padding-left: 40px;
  26 + padding-right: 40px;
  27 + padding-top: 8px;
  28 + padding-bottom: 8px;
  29 + .title {
  30 + font-size: 20px;
  31 + color: @heading-color;
  32 + line-height: 28px;
  33 + font-weight: 500;
  34 + margin-bottom: 12px;
  35 + }
  36 + }
  37 + :global {
  38 + .ant-list-split .ant-list-item:last-child {
  39 + border-bottom: 1px solid #e8e8e8;
  40 + }
  41 + .ant-list-item {
  42 + padding-top: 14px;
  43 + padding-bottom: 14px;
  44 + }
  45 + }
  46 +}
  47 +:global {
  48 + .ant-list-item-meta {
  49 + // 账号绑定图标
  50 + .taobao {
  51 + color: #ff4000;
  52 + display: block;
  53 + font-size: 48px;
  54 + line-height: 48px;
  55 + border-radius: @border-radius-base;
  56 + }
  57 + .dingding {
  58 + background-color: #2eabff;
  59 + color: #fff;
  60 + font-size: 32px;
  61 + line-height: 32px;
  62 + padding: 6px;
  63 + margin: 2px;
  64 + border-radius: @border-radius-base;
  65 + }
  66 + .alipay {
  67 + color: #2eabff;
  68 + font-size: 48px;
  69 + line-height: 48px;
  70 + border-radius: @border-radius-base;
  71 + }
  72 + }
  73 +
  74 + // 密码强度
  75 + font.strong {
  76 + color: @success-color;
  77 + }
  78 + font.medium {
  79 + color: @warning-color;
  80 + }
  81 + font.weak {
  82 + color: @error-color;
  83 + }
  84 +}
  85 +
  86 +@media screen and (max-width: @screen-md) {
  87 + .main {
  88 + flex-direction: column;
  89 + .leftmenu {
  90 + width: 100%;
  91 + border: none;
  92 + }
  93 + .right {
  94 + padding: 40px;
  95 + }
  96 + }
  97 +}
... ...
  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 + layout: 'ant-design-pro',
  5 + }],
  6 + ['umi-plugin-react', {
  7 + dva: true,
  8 + locale: true,
  9 + antd: true,
  10 + }]
  11 + ],
  12 +}
... ...
  1 +# @umi-blocks/ant-design-pro/advancedform
  2 +
  3 +AdvancedForm
  4 +
  5 +## Usage
  6 +
  7 +```sh
  8 +umi block add ant-design-pro/AdvancedForm
  9 +```
  10 +
  11 +## SNAPSHOT
  12 +
  13 +![SNAPSHOT](./snapshot.png)
  14 +
  15 +## LICENSE
  16 +
  17 +MIT
... ...
  1 +{
  2 + "name": "@umi-block/advanced-form",
  3 + "version": "0.0.1",
  4 + "description": "AdvancedForm",
  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/ant-design-pro/advancedform"
  12 + },
  13 + "dependencies": {
  14 + "ant-design-pro": "^2.1.1",
  15 + "antd": "^3.10.9",
  16 + "dva": "^2.4.0",
  17 + "lodash": "^4.17.10",
  18 + "react": "^16.6.3",
  19 + "umi-request": "^1.0.0"
  20 + },
  21 + "devDependencies": {
  22 + "umi": "^2.3.0-beta.1",
  23 + "umi-plugin-react": "^1.3.0-beta.1",
  24 + "umi-plugin-block-dev": "^2.0.0"
  25 + },
  26 + "license": "ISC",
  27 + "blockConfig": {
  28 + "specVersion": "0.1"
  29 + }
  30 +}
\ No newline at end of file
... ...
  1 +export default {
  2 + 'POST /api/BLOCK_NAME/forms': (req, res) => {
  3 + res.send({ message: 'Ok' });
  4 + },
  5 +};
... ...
  1 +import React from 'react';
  2 +import { FormattedMessage } from 'umi/locale';
  3 +import Link from 'umi/link';
  4 +import { PageHeader } from 'ant-design-pro';
  5 +import styles from './index.less';
  6 +
  7 +const PageHeaderWrapper = ({ children, wrapperClassName, ...restProps }) => (
  8 + <div style={{ margin: '-24px -24px 0' }} className={wrapperClassName}>
  9 + <PageHeader
  10 + home={<FormattedMessage id="BLOCK_NAME.menu.home" defaultMessage="Home" />}
  11 + key="pageheader"
  12 + {...restProps}
  13 + linkElement={Link}
  14 + itemRender={item => {
  15 + if (item.locale) {
  16 + return <FormattedMessage id={item.locale} defaultMessage={item.title} />;
  17 + }
  18 + return item.title;
  19 + }}
  20 + />
  21 + {children ? <div className={styles.content}>{children}</div> : null}
  22 + </div>
  23 +);
  24 +
  25 +export default PageHeaderWrapper;
... ...
  1 +@import '~antd/lib/style/themes/default.less';
  2 +
  3 +.content {
  4 + margin: 24px 24px 0;
  5 +}
  6 +
  7 +@media screen and (max-width: @screen-sm) {
  8 + .content {
  9 + margin: 24px 0 0;
  10 + }
  11 +}
... ...
  1 +import React, { PureComponent, Fragment } from 'react';
  2 +import { Table, Button, Input, message, Popconfirm, Divider } from 'antd';
  3 +import { isEqual } from 'lodash';
  4 +import styles from '../style.less';
  5 +
  6 +class TableForm extends PureComponent {
  7 + index = 0;
  8 +
  9 + cacheOriginData = {};
  10 +
  11 + constructor(props) {
  12 + super(props);
  13 +
  14 + this.state = {
  15 + data: props.value,
  16 + loading: false,
  17 + /* eslint-disable-next-line react/no-unused-state */
  18 + value: props.value,
  19 + };
  20 + }
  21 +
  22 + static getDerivedStateFromProps(nextProps, preState) {
  23 + if (isEqual(nextProps.value, preState.value)) {
  24 + return null;
  25 + }
  26 + return {
  27 + data: nextProps.value,
  28 + value: nextProps.value,
  29 + };
  30 + }
  31 +
  32 + getRowByKey(key, newData) {
  33 + const { data } = this.state;
  34 + return (newData || data).filter(item => item.key === key)[0];
  35 + }
  36 +
  37 + toggleEditable = (e, key) => {
  38 + e.preventDefault();
  39 + const { data } = this.state;
  40 + const newData = data.map(item => ({ ...item }));
  41 + const target = this.getRowByKey(key, newData);
  42 + if (target) {
  43 + // 进入编辑状态时保存原始数据
  44 + if (!target.editable) {
  45 + this.cacheOriginData[key] = { ...target };
  46 + }
  47 + target.editable = !target.editable;
  48 + this.setState({ data: newData });
  49 + }
  50 + };
  51 +
  52 + newMember = () => {
  53 + const { data } = this.state;
  54 + const newData = data.map(item => ({ ...item }));
  55 + newData.push({
  56 + key: `NEW_TEMP_ID_${this.index}`,
  57 + workId: '',
  58 + name: '',
  59 + department: '',
  60 + editable: true,
  61 + isNew: true,
  62 + });
  63 + this.index += 1;
  64 + this.setState({ data: newData });
  65 + };
  66 +
  67 + remove(key) {
  68 + const { data } = this.state;
  69 + const { onChange } = this.props;
  70 + const newData = data.filter(item => item.key !== key);
  71 + this.setState({ data: newData });
  72 + onChange(newData);
  73 + }
  74 +
  75 + handleKeyPress(e, key) {
  76 + if (e.key === 'Enter') {
  77 + this.saveRow(e, key);
  78 + }
  79 + }
  80 +
  81 + handleFieldChange(e, fieldName, key) {
  82 + const { data } = this.state;
  83 + const newData = data.map(item => ({ ...item }));
  84 + const target = this.getRowByKey(key, newData);
  85 + if (target) {
  86 + target[fieldName] = e.target.value;
  87 + this.setState({ data: newData });
  88 + }
  89 + }
  90 +
  91 + saveRow(e, key) {
  92 + e.persist();
  93 + this.setState({
  94 + loading: true,
  95 + });
  96 + setTimeout(() => {
  97 + if (this.clickedCancel) {
  98 + this.clickedCancel = false;
  99 + return;
  100 + }
  101 + const target = this.getRowByKey(key) || {};
  102 + if (!target.workId || !target.name || !target.department) {
  103 + message.error('请填写完整成员信息。');
  104 + e.target.focus();
  105 + this.setState({
  106 + loading: false,
  107 + });
  108 + return;
  109 + }
  110 + delete target.isNew;
  111 + this.toggleEditable(e, key);
  112 + const { data } = this.state;
  113 + const { onChange } = this.props;
  114 + onChange(data);
  115 + this.setState({
  116 + loading: false,
  117 + });
  118 + }, 500);
  119 + }
  120 +
  121 + cancel(e, key) {
  122 + this.clickedCancel = true;
  123 + e.preventDefault();
  124 + const { data } = this.state;
  125 + const newData = data.map(item => ({ ...item }));
  126 + const target = this.getRowByKey(key, newData);
  127 + if (this.cacheOriginData[key]) {
  128 + Object.assign(target, this.cacheOriginData[key]);
  129 + delete this.cacheOriginData[key];
  130 + }
  131 + target.editable = false;
  132 + this.setState({ data: newData });
  133 + this.clickedCancel = false;
  134 + }
  135 +
  136 + render() {
  137 + const columns = [
  138 + {
  139 + title: '成员姓名',
  140 + dataIndex: 'name',
  141 + key: 'name',
  142 + width: '20%',
  143 + render: (text, record) => {
  144 + if (record.editable) {
  145 + return (
  146 + <Input
  147 + value={text}
  148 + autoFocus
  149 + onChange={e => this.handleFieldChange(e, 'name', record.key)}
  150 + onKeyPress={e => this.handleKeyPress(e, record.key)}
  151 + placeholder="成员姓名"
  152 + />
  153 + );
  154 + }
  155 + return text;
  156 + },
  157 + },
  158 + {
  159 + title: '工号',
  160 + dataIndex: 'workId',
  161 + key: 'workId',
  162 + width: '20%',
  163 + render: (text, record) => {
  164 + if (record.editable) {
  165 + return (
  166 + <Input
  167 + value={text}
  168 + onChange={e => this.handleFieldChange(e, 'workId', record.key)}
  169 + onKeyPress={e => this.handleKeyPress(e, record.key)}
  170 + placeholder="工号"
  171 + />
  172 + );
  173 + }
  174 + return text;
  175 + },
  176 + },
  177 + {
  178 + title: '所属部门',
  179 + dataIndex: 'department',
  180 + key: 'department',
  181 + width: '40%',
  182 + render: (text, record) => {
  183 + if (record.editable) {
  184 + return (
  185 + <Input
  186 + value={text}
  187 + onChange={e => this.handleFieldChange(e, 'department', record.key)}
  188 + onKeyPress={e => this.handleKeyPress(e, record.key)}
  189 + placeholder="所属部门"
  190 + />
  191 + );
  192 + }
  193 + return text;
  194 + },
  195 + },
  196 + {
  197 + title: '操作',
  198 + key: 'action',
  199 + render: (text, record) => {
  200 + const { loading } = this.state;
  201 + if (!!record.editable && loading) {
  202 + return null;
  203 + }
  204 + if (record.editable) {
  205 + if (record.isNew) {
  206 + return (
  207 + <span>
  208 + <a onClick={e => this.saveRow(e, record.key)}>添加</a>
  209 + <Divider type="vertical" />
  210 + <Popconfirm title="是否要删除此行?" onConfirm={() => this.remove(record.key)}>
  211 + <a>删除</a>
  212 + </Popconfirm>
  213 + </span>
  214 + );
  215 + }
  216 + return (
  217 + <span>
  218 + <a onClick={e => this.saveRow(e, record.key)}>保存</a>
  219 + <Divider type="vertical" />
  220 + <a onClick={e => this.cancel(e, record.key)}>取消</a>
  221 + </span>
  222 + );
  223 + }
  224 + return (
  225 + <span>
  226 + <a onClick={e => this.toggleEditable(e, record.key)}>编辑</a>
  227 + <Divider type="vertical" />
  228 + <Popconfirm title="是否要删除此行?" onConfirm={() => this.remove(record.key)}>
  229 + <a>删除</a>
  230 + </Popconfirm>
  231 + </span>
  232 + );
  233 + },
  234 + },
  235 + ];
  236 +
  237 + const { loading, data } = this.state;
  238 +
  239 + return (
  240 + <Fragment>
  241 + <Table
  242 + loading={loading}
  243 + columns={columns}
  244 + dataSource={data}
  245 + pagination={false}
  246 + rowClassName={record => (record.editable ? styles.editable : '')}
  247 + />
  248 + <Button
  249 + style={{ width: '100%', marginTop: 16, marginBottom: 8 }}
  250 + type="dashed"
  251 + onClick={this.newMember}
  252 + icon="plus"
  253 + >
  254 + 新增成员
  255 + </Button>
  256 + </Fragment>
  257 + );
  258 + }
  259 +}
  260 +
  261 +export default TableForm;
... ...
  1 +import React, { PureComponent } from 'react';
  2 +import {
  3 + Card,
  4 + Button,
  5 + Form,
  6 + Icon,
  7 + Col,
  8 + Row,
  9 + DatePicker,
  10 + TimePicker,
  11 + Input,
  12 + Select,
  13 + Popover,
  14 +} from 'antd';
  15 +import { connect } from 'dva';
  16 +import { FooterToolbar } from 'ant-design-pro';
  17 +import PageHeaderWrapper from './components/PageHeaderWrapper';
  18 +import TableForm from './components/TableForm';
  19 +import styles from './style.less';
  20 +
  21 +const { Option } = Select;
  22 +const { RangePicker } = DatePicker;
  23 +
  24 +const fieldLabels = {
  25 + name: '仓库名',
  26 + url: '仓库域名',
  27 + owner: '仓库管理员',
  28 + approver: '审批人',
  29 + dateRange: '生效日期',
  30 + type: '仓库类型',
  31 + name2: '任务名',
  32 + url2: '任务描述',
  33 + owner2: '执行人',
  34 + approver2: '责任人',
  35 + dateRange2: '生效日期',
  36 + type2: '任务类型',
  37 +};
  38 +
  39 +const tableData = [
  40 + {
  41 + key: '1',
  42 + workId: '00001',
  43 + name: 'John Brown',
  44 + department: 'New York No. 1 Lake Park',
  45 + },
  46 + {
  47 + key: '2',
  48 + workId: '00002',
  49 + name: 'Jim Green',
  50 + department: 'London No. 1 Lake Park',
  51 + },
  52 + {
  53 + key: '3',
  54 + workId: '00003',
  55 + name: 'Joe Black',
  56 + department: 'Sidney No. 1 Lake Park',
  57 + },
  58 +];
  59 +
  60 +@connect(({ loading }) => ({
  61 + submitting: loading.effects['BLOCK_NAME_CAMEL_CASE/submitAdvancedForm'],
  62 +}))
  63 +@Form.create()
  64 +class PAGE_NAME_UPPER_CAMEL_CASE extends PureComponent {
  65 + state = {
  66 + width: '100%',
  67 + };
  68 +
  69 + componentDidMount() {
  70 + window.addEventListener('resize', this.resizeFooterToolbar, { passive: true });
  71 + }
  72 +
  73 + componentWillUnmount() {
  74 + window.removeEventListener('resize', this.resizeFooterToolbar);
  75 + }
  76 +
  77 + getErrorInfo = () => {
  78 + const {
  79 + form: { getFieldsError },
  80 + } = this.props;
  81 + const errors = getFieldsError();
  82 + const errorCount = Object.keys(errors).filter(key => errors[key]).length;
  83 + if (!errors || errorCount === 0) {
  84 + return null;
  85 + }
  86 + const scrollToField = fieldKey => {
  87 + const labelNode = document.querySelector(`label[for="${fieldKey}"]`);
  88 + if (labelNode) {
  89 + labelNode.scrollIntoView(true);
  90 + }
  91 + };
  92 + const errorList = Object.keys(errors).map(key => {
  93 + if (!errors[key]) {
  94 + return null;
  95 + }
  96 + return (
  97 + <li key={key} className={styles.errorListItem} onClick={() => scrollToField(key)}>
  98 + <Icon type="cross-circle-o" className={styles.errorIcon} />
  99 + <div className={styles.errorMessage}>{errors[key][0]}</div>
  100 + <div className={styles.errorField}>{fieldLabels[key]}</div>
  101 + </li>
  102 + );
  103 + });
  104 + return (
  105 + <span className={styles.errorIcon}>
  106 + <Popover
  107 + title="表单校验信息"
  108 + content={errorList}
  109 + overlayClassName={styles.errorPopover}
  110 + trigger="click"
  111 + getPopupContainer={trigger => trigger.parentNode}
  112 + >
  113 + <Icon type="exclamation-circle" />
  114 + </Popover>
  115 + {errorCount}
  116 + </span>
  117 + );
  118 + };
  119 +
  120 + resizeFooterToolbar = () => {
  121 + requestAnimationFrame(() => {
  122 + const sider = document.querySelectorAll('.ant-layout-sider')[0];
  123 + if (sider) {
  124 + const width = `calc(100% - ${sider.style.width})`;
  125 + const { width: stateWidth } = this.state;
  126 + if (stateWidth !== width) {
  127 + this.setState({ width });
  128 + }
  129 + }
  130 + });
  131 + };
  132 +
  133 + validate = () => {
  134 + const {
  135 + form: { validateFieldsAndScroll },
  136 + dispatch,
  137 + } = this.props;
  138 + validateFieldsAndScroll((error, values) => {
  139 + if (!error) {
  140 + // submit the values
  141 + dispatch({
  142 + type: 'BLOCK_NAME_CAMEL_CASE/submitAdvancedForm',
  143 + payload: values,
  144 + });
  145 + }
  146 + });
  147 + };
  148 +
  149 + render() {
  150 + const {
  151 + form: { getFieldDecorator },
  152 + submitting,
  153 + } = this.props;
  154 + const { width } = this.state;
  155 +
  156 + return (
  157 + <PageHeaderWrapper
  158 + title="高级表单"
  159 + content="高级表单常见于一次性输入和提交大批量数据的场景。"
  160 + wrapperClassName={styles.advancedForm}
  161 + >
  162 + <Card title="仓库管理" className={styles.card} bordered={false}>
  163 + <Form layout="vertical" hideRequiredMark>
  164 + <Row gutter={16}>
  165 + <Col lg={6} md={12} sm={24}>
  166 + <Form.Item label={fieldLabels.name}>
  167 + {getFieldDecorator('name', {
  168 + rules: [{ required: true, message: '请输入仓库名称' }],
  169 + })(<Input placeholder="请输入仓库名称" />)}
  170 + </Form.Item>
  171 + </Col>
  172 + <Col xl={{ span: 6, offset: 2 }} lg={{ span: 8 }} md={{ span: 12 }} sm={24}>
  173 + <Form.Item label={fieldLabels.url}>
  174 + {getFieldDecorator('url', {
  175 + rules: [{ required: true, message: '请选择' }],
  176 + })(
  177 + <Input
  178 + style={{ width: '100%' }}
  179 + addonBefore="http://"
  180 + addonAfter=".com"
  181 + placeholder="请输入"
  182 + />
  183 + )}
  184 + </Form.Item>
  185 + </Col>
  186 + <Col xl={{ span: 8, offset: 2 }} lg={{ span: 10 }} md={{ span: 24 }} sm={24}>
  187 + <Form.Item label={fieldLabels.owner}>
  188 + {getFieldDecorator('owner', {
  189 + rules: [{ required: true, message: '请选择管理员' }],
  190 + })(
  191 + <Select placeholder="请选择管理员">
  192 + <Option value="xiao">付晓晓</Option>
  193 + <Option value="mao">周毛毛</Option>
  194 + </Select>
  195 + )}
  196 + </Form.Item>
  197 + </Col>
  198 + </Row>
  199 + <Row gutter={16}>
  200 + <Col lg={6} md={12} sm={24}>
  201 + <Form.Item label={fieldLabels.approver}>
  202 + {getFieldDecorator('approver', {
  203 + rules: [{ required: true, message: '请选择审批员' }],
  204 + })(
  205 + <Select placeholder="请选择审批员">
  206 + <Option value="xiao">付晓晓</Option>
  207 + <Option value="mao">周毛毛</Option>
  208 + </Select>
  209 + )}
  210 + </Form.Item>
  211 + </Col>
  212 + <Col xl={{ span: 6, offset: 2 }} lg={{ span: 8 }} md={{ span: 12 }} sm={24}>
  213 + <Form.Item label={fieldLabels.dateRange}>
  214 + {getFieldDecorator('dateRange', {
  215 + rules: [{ required: true, message: '请选择生效日期' }],
  216 + })(
  217 + <RangePicker placeholder={['开始日期', '结束日期']} style={{ width: '100%' }} />
  218 + )}
  219 + </Form.Item>
  220 + </Col>
  221 + <Col xl={{ span: 8, offset: 2 }} lg={{ span: 10 }} md={{ span: 24 }} sm={24}>
  222 + <Form.Item label={fieldLabels.type}>
  223 + {getFieldDecorator('type', {
  224 + rules: [{ required: true, message: '请选择仓库类型' }],
  225 + })(
  226 + <Select placeholder="请选择仓库类型">
  227 + <Option value="private">私密</Option>
  228 + <Option value="public">公开</Option>
  229 + </Select>
  230 + )}
  231 + </Form.Item>
  232 + </Col>
  233 + </Row>
  234 + </Form>
  235 + </Card>
  236 + <Card title="任务管理" className={styles.card} bordered={false}>
  237 + <Form layout="vertical" hideRequiredMark>
  238 + <Row gutter={16}>
  239 + <Col lg={6} md={12} sm={24}>
  240 + <Form.Item label={fieldLabels.name2}>
  241 + {getFieldDecorator('name2', {
  242 + rules: [{ required: true, message: '请输入' }],
  243 + })(<Input placeholder="请输入" />)}
  244 + </Form.Item>
  245 + </Col>
  246 + <Col xl={{ span: 6, offset: 2 }} lg={{ span: 8 }} md={{ span: 12 }} sm={24}>
  247 + <Form.Item label={fieldLabels.url2}>
  248 + {getFieldDecorator('url2', {
  249 + rules: [{ required: true, message: '请选择' }],
  250 + })(<Input placeholder="请输入" />)}
  251 + </Form.Item>
  252 + </Col>
  253 + <Col xl={{ span: 8, offset: 2 }} lg={{ span: 10 }} md={{ span: 24 }} sm={24}>
  254 + <Form.Item label={fieldLabels.owner2}>
  255 + {getFieldDecorator('owner2', {
  256 + rules: [{ required: true, message: '请选择管理员' }],
  257 + })(
  258 + <Select placeholder="请选择管理员">
  259 + <Option value="xiao">付晓晓</Option>
  260 + <Option value="mao">周毛毛</Option>
  261 + </Select>
  262 + )}
  263 + </Form.Item>
  264 + </Col>
  265 + </Row>
  266 + <Row gutter={16}>
  267 + <Col lg={6} md={12} sm={24}>
  268 + <Form.Item label={fieldLabels.approver2}>
  269 + {getFieldDecorator('approver2', {
  270 + rules: [{ required: true, message: '请选择审批员' }],
  271 + })(
  272 + <Select placeholder="请选择审批员">
  273 + <Option value="xiao">付晓晓</Option>
  274 + <Option value="mao">周毛毛</Option>
  275 + </Select>
  276 + )}
  277 + </Form.Item>
  278 + </Col>
  279 + <Col xl={{ span: 6, offset: 2 }} lg={{ span: 8 }} md={{ span: 12 }} sm={24}>
  280 + <Form.Item label={fieldLabels.dateRange2}>
  281 + {getFieldDecorator('dateRange2', {
  282 + rules: [{ required: true, message: '请输入' }],
  283 + })(
  284 + <TimePicker
  285 + placeholder="提醒时间"
  286 + style={{ width: '100%' }}
  287 + getPopupContainer={trigger => trigger.parentNode}
  288 + />
  289 + )}
  290 + </Form.Item>
  291 + </Col>
  292 + <Col xl={{ span: 8, offset: 2 }} lg={{ span: 10 }} md={{ span: 24 }} sm={24}>
  293 + <Form.Item label={fieldLabels.type2}>
  294 + {getFieldDecorator('type2', {
  295 + rules: [{ required: true, message: '请选择仓库类型' }],
  296 + })(
  297 + <Select placeholder="请选择仓库类型">
  298 + <Option value="private">私密</Option>
  299 + <Option value="public">公开</Option>
  300 + </Select>
  301 + )}
  302 + </Form.Item>
  303 + </Col>
  304 + </Row>
  305 + </Form>
  306 + </Card>
  307 + <Card title="成员管理" bordered={false}>
  308 + {getFieldDecorator('members', {
  309 + initialValue: tableData,
  310 + })(<TableForm />)}
  311 + </Card>
  312 + <FooterToolbar style={{ width }}>
  313 + {this.getErrorInfo()}
  314 + <Button type="primary" onClick={this.validate} loading={submitting}>
  315 + 提交
  316 + </Button>
  317 + </FooterToolbar>
  318 + </PageHeaderWrapper>
  319 + );
  320 + }
  321 +}
  322 +
  323 +export default PAGE_NAME_UPPER_CAMEL_CASE;
... ...
  1 +export default {
  2 + 'BLOCK_NAME.basic.title': 'Basic form',
  3 + 'BLOCK_NAME.basic.description':
  4 + 'Form pages are used to collect or verify information to users, and basic forms are common in scenarios where there are fewer data items.',
  5 +
  6 + 'BLOCK_NAME.email.required': 'Please enter your email!',
  7 + 'BLOCK_NAME.email.wrong-format': 'The email address is in the wrong format!',
  8 + 'BLOCK_NAME.userName.required': 'Please enter your userName!',
  9 + 'BLOCK_NAME.password.required': 'Please enter your password!',
  10 + 'BLOCK_NAME.password.twice': 'The passwords entered twice do not match!',
  11 + 'BLOCK_NAME.strength.msg':
  12 + "Please enter at least 6 characters and don't use passwords that are easy to guess.",
  13 + 'BLOCK_NAME.strength.strong': 'Strength: strong',
  14 + 'BLOCK_NAME.strength.medium': 'Strength: medium',
  15 + 'BLOCK_NAME.strength.short': 'Strength: too short',
  16 + 'BLOCK_NAME.confirm-password.required': 'Please confirm your password!',
  17 + 'BLOCK_NAME.phone-number.required': 'Please enter your phone number!',
  18 + 'BLOCK_NAME.phone-number.wrong-format': 'Malformed phone number!',
  19 + 'BLOCK_NAME.verification-code.required': 'Please enter the verification code!',
  20 + 'BLOCK_NAME.title.required': 'Please enter a title',
  21 + 'BLOCK_NAME.date.required': 'Please select the start and end date',
  22 + 'BLOCK_NAME.goal.required': 'Please enter a description of the goal',
  23 + 'BLOCK_NAME.standard.required': 'Please enter a metric',
  24 +
  25 + 'BLOCK_NAME.form.get-captcha': 'Get Captcha',
  26 + 'BLOCK_NAME.captcha.second': 'sec',
  27 + 'BLOCK_NAME.form.optional': ' (optional) ',
  28 + 'BLOCK_NAME.form.submit': 'Submit',
  29 + 'BLOCK_NAME.form.save': 'Save',
  30 + 'BLOCK_NAME.email.placeholder': 'Email',
  31 + 'BLOCK_NAME.password.placeholder': 'Password',
  32 + 'BLOCK_NAME.confirm-password.placeholder': 'Confirm password',
  33 + 'BLOCK_NAME.phone-number.placeholder': 'Phone number',
  34 + 'BLOCK_NAME.verification-code.placeholder': 'Verification code',
  35 + 'BLOCK_NAME.title.label': 'Title',
  36 + 'BLOCK_NAME.title.placeholder': 'Give the target a name',
  37 + 'BLOCK_NAME.date.label': 'Start and end date',
  38 + 'BLOCK_NAME.placeholder.start': 'Start date',
  39 + 'BLOCK_NAME.placeholder.end': 'End date',
  40 + 'BLOCK_NAME.goal.label': 'Goal description',
  41 + 'BLOCK_NAME.goal.placeholder': 'Please enter your work goals',
  42 + 'BLOCK_NAME.standard.label': 'Metrics',
  43 + 'BLOCK_NAME.standard.placeholder': 'Please enter a metric',
  44 + 'BLOCK_NAME.client.label': 'Client',
  45 + 'BLOCK_NAME.label.tooltip': 'Target service object',
  46 + 'BLOCK_NAME.client.placeholder':
  47 + 'Please describe your customer service, internal customers directly @ Name / job number',
  48 + 'BLOCK_NAME.invites.label': 'Inviting critics',
  49 + 'BLOCK_NAME.invites.placeholder': 'Please direct @ Name / job number, you can invite up to 5 people',
  50 + 'BLOCK_NAME.weight.label': 'Weight',
  51 + 'BLOCK_NAME.weight.placeholder': 'Please enter weight',
  52 + 'BLOCK_NAME.public.label': 'Target disclosure',
  53 + 'BLOCK_NAME.label.help': 'Customers and invitees are shared by default',
  54 + 'BLOCK_NAME.radio.public': 'Public',
  55 + 'BLOCK_NAME.radio.partially-public': 'Partially public',
  56 + 'BLOCK_NAME.radio.private': 'Private',
  57 + 'BLOCK_NAME.publicUsers.placeholder': 'Open to',
  58 + 'BLOCK_NAME.option.A': 'Colleague A',
  59 + 'BLOCK_NAME.option.B': 'Colleague B',
  60 + 'BLOCK_NAME.option.C': 'Colleague C',
  61 +};
... ...
  1 +export default {
  2 + 'BLOCK_NAME.basic.title': 'Basic form',
  3 + 'BLOCK_NAME.basic.description':
  4 + 'Form pages are used to collect or verify information to users, and basic forms are common in scenarios where there are fewer data items.',
  5 +
  6 + 'BLOCK_NAME.email.required': 'Por favor insira seu email!',
  7 + 'BLOCK_NAME.email.wrong-format': 'O email está errado!',
  8 + 'BLOCK_NAME.userName.required': 'Por favor insira nome de usuário!',
  9 + 'BLOCK_NAME.password.required': 'Por favor insira sua senha!',
  10 + 'BLOCK_NAME.password.twice': 'As senhas não estão iguais!',
  11 + 'BLOCK_NAME.strength.msg':
  12 + 'Por favor insira pelo menos 6 caracteres e não use senhas fáceis de adivinhar.',
  13 + 'BLOCK_NAME.strength.strong': 'Força: forte',
  14 + 'BLOCK_NAME.strength.medium': 'Força: média',
  15 + 'BLOCK_NAME.strength.short': 'Força: curta',
  16 + 'BLOCK_NAME.confirm-password.required': 'Por favor confirme sua senha!',
  17 + 'BLOCK_NAME.phone-number.required': 'Por favor insira seu telefone!',
  18 + 'BLOCK_NAME.phone-number.wrong-format': 'Formato de telefone errado!',
  19 + 'BLOCK_NAME.verification-code.required': 'Por favor insira seu código de verificação!',
  20 +
  21 + 'BLOCK_NAME.form.get-captcha': 'Get Captcha',
  22 + 'BLOCK_NAME.captcha.second': 'sec',
  23 + 'BLOCK_NAME.email.placeholder': 'Email',
  24 + 'BLOCK_NAME.password.placeholder': 'Senha',
  25 + 'BLOCK_NAME.confirm-password.placeholder': 'Confirme a senha',
  26 + 'BLOCK_NAME.phone-number.placeholder': 'Telefone',
  27 + 'BLOCK_NAME.verification-code.placeholder': 'Código de verificação',
  28 + 'BLOCK_NAME.form.optional': ' (optional) ',
  29 + 'BLOCK_NAME.form.submit': 'Submit',
  30 + 'BLOCK_NAME.form.save': 'Save',
  31 + 'BLOCK_NAME.title.label': 'Title',
  32 + 'BLOCK_NAME.title.placeholder': 'Give the target a name',
  33 + 'BLOCK_NAME.date.label': 'Start and end date',
  34 + 'BLOCK_NAME.placeholder.start': 'Start date',
  35 + 'BLOCK_NAME.placeholder.end': 'End date',
  36 + 'BLOCK_NAME.goal.label': 'Goal description',
  37 + 'BLOCK_NAME.goal.placeholder': 'Please enter your work goals',
  38 + 'BLOCK_NAME.standard.label': 'Metrics',
  39 + 'BLOCK_NAME.standard.placeholder': 'Please enter a metric',
  40 + 'BLOCK_NAME.client.label': 'Client',
  41 + 'BLOCK_NAME.label.tooltip': 'Target service object',
  42 + 'BLOCK_NAME.client.placeholder':
  43 + 'Please describe your customer service, internal customers directly @ Name / job number',
  44 + 'BLOCK_NAME.invites.label': 'Inviting critics',
  45 + 'BLOCK_NAME.invites.placeholder': 'Please direct @ Name / job number, you can invite up to 5 people',
  46 + 'BLOCK_NAME.weight.label': 'Weight',
  47 + 'BLOCK_NAME.weight.placeholder': 'Please enter weight',
  48 + 'BLOCK_NAME.public.label': 'Target disclosure',
  49 + 'BLOCK_NAME.label.help': 'Customers and invitees are shared by default',
  50 + 'BLOCK_NAME.radio.public': 'Public',
  51 + 'BLOCK_NAME.radio.partially-public': 'Partially public',
  52 + 'BLOCK_NAME.radio.private': 'Private',
  53 + 'BLOCK_NAME.publicUsers.placeholder': 'Open to',
  54 + 'BLOCK_NAME.option.A': 'Colleague A',
  55 + 'BLOCK_NAME.option.B': 'Colleague B',
  56 + 'BLOCK_NAME.option.C': 'Colleague C',
  57 +};
... ...
  1 +export default {
  2 + 'BLOCK_NAME.basic.title': '基础表单',
  3 + 'BLOCK_NAME.basic.description':
  4 + '表单页用于向用户收集或验证信息,基础表单常见于数据项较少的表单场景。',
  5 +
  6 + 'BLOCK_NAME.email.required': '请输入邮箱地址!',
  7 + 'BLOCK_NAME.email.wrong-format': '邮箱地址格式错误!',
  8 + 'BLOCK_NAME.userName.required': '请输入用户名!',
  9 + 'BLOCK_NAME.password.required': '请输入密码!',
  10 + 'BLOCK_NAME.password.twice': '两次输入的密码不匹配!',
  11 + 'BLOCK_NAME.strength.msg': '请至少输入 6 个字符。请不要使用容易被猜到的密码。',
  12 + 'BLOCK_NAME.strength.strong': '强度:强',
  13 + 'BLOCK_NAME.strength.medium': '强度:中',
  14 + 'BLOCK_NAME.strength.short': '强度:太短',
  15 + 'BLOCK_NAME.confirm-password.required': '请确认密码!',
  16 + 'BLOCK_NAME.phone-number.required': '请输入手机号!',
  17 + 'BLOCK_NAME.phone-number.wrong-format': '手机号格式错误!',
  18 + 'BLOCK_NAME.verification-code.required': '请输入验证码!',
  19 + 'BLOCK_NAME.title.required': '请输入标题',
  20 + 'BLOCK_NAME.date.required': '请选择起止日期',
  21 + 'BLOCK_NAME.goal.required': '请输入目标描述',
  22 + 'BLOCK_NAME.standard.required': '请输入衡量标准',
  23 +
  24 + 'BLOCK_NAME.form.get-captcha': '获取验证码',
  25 + 'BLOCK_NAME.captcha.second': '秒',
  26 + 'BLOCK_NAME.form.optional': '(选填)',
  27 + 'BLOCK_NAME.form.submit': '提交',
  28 + 'BLOCK_NAME.form.save': '保存',
  29 + 'BLOCK_NAME.email.placeholder': '邮箱',
  30 + 'BLOCK_NAME.password.placeholder': '至少6位密码,区分大小写',
  31 + 'BLOCK_NAME.confirm-password.placeholder': '确认密码',
  32 + 'BLOCK_NAME.phone-number.placeholder': '手机号',
  33 + 'BLOCK_NAME.verification-code.placeholder': '验证码',
  34 + 'BLOCK_NAME.title.label': '标题',
  35 + 'BLOCK_NAME.title.placeholder': '给目标起个名字',
  36 + 'BLOCK_NAME.date.label': '起止日期',
  37 + 'BLOCK_NAME.placeholder.start': '开始日期',
  38 + 'BLOCK_NAME.placeholder.end': '结束日期',
  39 + 'BLOCK_NAME.goal.label': '目标描述',
  40 + 'BLOCK_NAME.goal.placeholder': '请输入你的阶段性工作目标',
  41 + 'BLOCK_NAME.standard.label': '衡量标准',
  42 + 'BLOCK_NAME.standard.placeholder': '请输入衡量标准',
  43 + 'BLOCK_NAME.client.label': '客户',
  44 + 'BLOCK_NAME.label.tooltip': '目标的服务对象',
  45 + 'BLOCK_NAME.client.placeholder': '请描述你服务的客户,内部客户直接 @姓名/工号',
  46 + 'BLOCK_NAME.invites.label': '邀评人',
  47 + 'BLOCK_NAME.invites.placeholder': '请直接 @姓名/工号,最多可邀请 5 人',
  48 + 'BLOCK_NAME.weight.label': '权重',
  49 + 'BLOCK_NAME.weight.placeholder': '请输入',
  50 + 'BLOCK_NAME.public.label': '目标公开',
  51 + 'BLOCK_NAME.label.help': '客户、邀评人默认被分享',
  52 + 'BLOCK_NAME.radio.public': '公开',
  53 + 'BLOCK_NAME.radio.partially-public': '部分公开',
  54 + 'BLOCK_NAME.radio.private': '不公开',
  55 + 'BLOCK_NAME.publicUsers.placeholder': '公开给',
  56 + 'BLOCK_NAME.option.A': '同事甲',
  57 + 'BLOCK_NAME.option.B': '同事乙',
  58 + 'BLOCK_NAME.option.C': '同事丙',
  59 +};
... ...
  1 +export default {
  2 + 'BLOCK_NAME.basic.title': '基礎表單',
  3 + 'BLOCK_NAME.basic.description':
  4 + '表單頁用於向用戶收集或驗證信息,基礎表單常見於數據項較少的表單場景。',
  5 +
  6 + 'BLOCK_NAME.email.required': '請輸入郵箱地址!',
  7 + 'BLOCK_NAME.email.wrong-format': '郵箱地址格式錯誤!',
  8 + 'BLOCK_NAME.userName.required': '請輸入賬戶!',
  9 + 'BLOCK_NAME.password.required': '請輸入密碼!',
  10 + 'BLOCK_NAME.password.twice': '兩次輸入的密碼不匹配!',
  11 + 'BLOCK_NAME.strength.msg': '請至少輸入 6 個字符。請不要使用容易被猜到的密碼。',
  12 + 'BLOCK_NAME.strength.strong': '強度:強',
  13 + 'BLOCK_NAME.strength.medium': '強度:中',
  14 + 'BLOCK_NAME.strength.short': '強度:太短',
  15 + 'BLOCK_NAME.confirm-password.required': '請確認密碼!',
  16 + 'BLOCK_NAME.phone-number.required': '請輸入手機號!',
  17 + 'BLOCK_NAME.phone-number.wrong-format': '手機號格式錯誤!',
  18 + 'BLOCK_NAME.verification-code.required': '請輸入驗證碼!',
  19 + 'BLOCK_NAME.title.required': '請輸入標題',
  20 + 'BLOCK_NAME.date.required': '請選擇起止日期',
  21 + 'BLOCK_NAME.goal.required': '請輸入目標描述',
  22 + 'BLOCK_NAME.standard.required': '請輸入衡量標淮',
  23 +
  24 + 'BLOCK_NAME.form.get-captcha': '獲取驗證碼',
  25 + 'BLOCK_NAME.captcha.second': '秒',
  26 + 'BLOCK_NAME.form.optional': '(選填)',
  27 + 'BLOCK_NAME.form.submit': '提交',
  28 + 'BLOCK_NAME.form.save': '保存',
  29 + 'BLOCK_NAME.email.placeholder': '郵箱',
  30 + 'BLOCK_NAME.password.placeholder': '至少6位密碼,區分大小寫',
  31 + 'BLOCK_NAME.confirm-password.placeholder': '確認密碼',
  32 + 'BLOCK_NAME.phone-number.placeholder': '手機號',
  33 + 'BLOCK_NAME.verification-code.placeholder': '驗證碼',
  34 + 'BLOCK_NAME.title.label': '標題',
  35 + 'BLOCK_NAME.title.placeholder': '給目標起個名字',
  36 + 'BLOCK_NAME.date.label': '起止日期',
  37 + 'BLOCK_NAME.placeholder.start': '開始日期',
  38 + 'BLOCK_NAME.placeholder.end': '結束日期',
  39 + 'BLOCK_NAME.goal.label': '目標描述',
  40 + 'BLOCK_NAME.goal.placeholder': '請輸入妳的階段性工作目標',
  41 + 'BLOCK_NAME.standard.label': '衡量標淮',
  42 + 'BLOCK_NAME.standard.placeholder': '請輸入衡量標淮',
  43 + 'BLOCK_NAME.client.label': '客戶',
  44 + 'BLOCK_NAME.label.tooltip': '目標的服務對象',
  45 + 'BLOCK_NAME.client.placeholder': '請描述妳服務的客戶,內部客戶直接 @姓名/工號',
  46 + 'BLOCK_NAME.invites.label': '邀評人',
  47 + 'BLOCK_NAME.invites.placeholder': '請直接 @姓名/工號,最多可邀請 5 人',
  48 + 'BLOCK_NAME.weight.label': '權重',
  49 + 'BLOCK_NAME.weight.placeholder': '請輸入',
  50 + 'BLOCK_NAME.public.label': '目標公開',
  51 + 'BLOCK_NAME.label.help': '客戶、邀評人默認被分享',
  52 + 'BLOCK_NAME.radio.public': '公開',
  53 + 'BLOCK_NAME.radio.partially-public': '部分公開',
  54 + 'BLOCK_NAME.radio.private': '不公開',
  55 + 'BLOCK_NAME.publicUsers.placeholder': '公開給',
  56 + 'BLOCK_NAME.option.A': '同事甲',
  57 + 'BLOCK_NAME.option.B': '同事乙',
  58 + 'BLOCK_NAME.option.C': '同事丙',
  59 +};
... ...
  1 +import { message } from 'antd';
  2 +import { fakeSubmitForm } from './service';
  3 +
  4 +export default {
  5 + namespace: 'BLOCK_NAME_CAMEL_CASE',
  6 +
  7 + state: {},
  8 +
  9 + effects: {
  10 + *submitAdvancedForm({ payload }, { call }) {
  11 + yield call(fakeSubmitForm, payload);
  12 + message.success('提交成功');
  13 + },
  14 + },
  15 +};
... ...
  1 +import request from 'umi-request';
  2 +
  3 +export async function fakeSubmitForm(params) {
  4 + return request('/api/BLOCK_NAME/forms', {
  5 + method: 'POST',
  6 + data: params,
  7 + });
  8 +}
... ...
  1 +@import '~antd/lib/style/themes/default.less';
  2 +
  3 +.card {
  4 + margin-bottom: 24px;
  5 +}
  6 +
  7 +.heading {
  8 + font-size: 14px;
  9 + line-height: 22px;
  10 + margin: 0 0 16px 0;
  11 +}
  12 +
  13 +.steps:global(.ant-steps) {
  14 + max-width: 750px;
  15 + margin: 16px auto;
  16 +}
  17 +
  18 +.errorIcon {
  19 + cursor: pointer;
  20 + color: @error-color;
  21 + margin-right: 24px;
  22 + i {
  23 + margin-right: 4px;
  24 + }
  25 +}
  26 +
  27 +.errorPopover {
  28 + :global {
  29 + .ant-popover-inner-content {
  30 + padding: 0;
  31 + max-height: 290px;
  32 + overflow: auto;
  33 + min-width: 256px;
  34 + }
  35 + }
  36 +}
  37 +
  38 +.errorListItem {
  39 + list-style: none;
  40 + border-bottom: 1px solid @border-color-split;
  41 + padding: 8px 16px;
  42 + cursor: pointer;
  43 + transition: all 0.3s;
  44 + &:hover {
  45 + background: @primary-1;
  46 + }
  47 + &:last-child {
  48 + border: 0;
  49 + }
  50 + .errorIcon {
  51 + color: @error-color;
  52 + float: left;
  53 + margin-top: 4px;
  54 + margin-right: 12px;
  55 + padding-bottom: 22px;
  56 + }
  57 + .errorField {
  58 + font-size: 12px;
  59 + color: @text-color-secondary;
  60 + margin-top: 2px;
  61 + }
  62 +}
  63 +
  64 +.editable {
  65 + td {
  66 + padding-top: 13px !important;
  67 + padding-bottom: 12.5px !important;
  68 + }
  69 +}
  70 +
  71 +// custom footer for fixed footer toolbar
  72 +.advancedForm + div {
  73 + padding-bottom: 64px;
  74 +}
  75 +
  76 +.advancedForm {
  77 + :global {
  78 + .ant-form .ant-row:last-child .ant-form-item {
  79 + margin-bottom: 24px;
  80 + }
  81 + .ant-table td {
  82 + transition: none !important;
  83 + }
  84 + }
  85 +}
  86 +
  87 +.optional {
  88 + color: @text-color-secondary;
  89 + font-style: normal;
  90 +}
... ...
  1 +/yarn.lock
  2 +/package-lock.json
  3 +/dist
  4 +/node_modules
  5 +
  6 +.umi
  7 +.umi-production
... ...
注册登录 后发表评论