Przeglądaj źródła

Refactor search list routes (#440)

* refactor search list

* Fix third level breadcrumb name, close #304

* use match.url

* use match.url

* use match.path

* fix match url & path
偏右 8 lat temu
rodzic
commit
e111d7bfa9

+ 15 - 12
src/common/nav.js

@@ -90,19 +90,22 @@ export const getNavData = app => [
             component: dynamicWrapper(app, ['list'], () => import('../routes/List/CardList')),
           },
           {
-            name: '搜索列表(项目)',
-            path: 'cover-card-list',
-            component: dynamicWrapper(app, ['list'], () => import('../routes/List/CoverCardList')),
-          },
-          {
-            name: '搜索列表(应用)',
-            path: 'filter-card-list',
-            component: dynamicWrapper(app, ['list'], () => import('../routes/List/FilterCardList')),
-          },
-          {
-            name: '搜索列表(文章)',
+            name: '搜索列表',
             path: 'search',
-            component: dynamicWrapper(app, ['list'], () => import('../routes/List/SearchList')),
+            component: dynamicWrapper(app, [], () => import('../routes/List/List')),
+            children: [{
+              name: '搜索列表(项目)',
+              path: 'projects',
+              component: dynamicWrapper(app, ['list'], () => import('../routes/List/Projects')),
+            }, {
+              name: '搜索列表(应用)',
+              path: 'applications',
+              component: dynamicWrapper(app, ['list'], () => import('../routes/List/Applications')),
+            }, {
+              name: '搜索列表(文章)',
+              path: 'articles',
+              component: dynamicWrapper(app, ['list'], () => import('../routes/List/Articles')),
+            }],
           },
         ],
       },

+ 5 - 2
src/layouts/BasicLayout.js

@@ -38,6 +38,7 @@ class BasicLayout extends React.PureComponent {
   static childContextTypes = {
     location: PropTypes.object,
     breadcrumbNameMap: PropTypes.object,
+    routeData: PropTypes.array,
   }
   getChildContext() {
     const { location, navData, getRouteData } = this.props;
@@ -52,7 +53,7 @@ class BasicLayout extends React.PureComponent {
         component: item.component,
       };
     });
-    return { location, breadcrumbNameMap };
+    return { location, breadcrumbNameMap, routeData };
   }
   getPageTitle() {
     const { location, getRouteData } = this.props;
@@ -68,8 +69,10 @@ class BasicLayout extends React.PureComponent {
   getMenuData = (data, parentPath) => {
     let arr = [];
     data.forEach((item) => {
-      if (item.children) {
+      if (item.name) {
         arr.push({ path: `${parentPath}/${item.path}`, name: item.name });
+      }
+      if (item.children) {
         arr = arr.concat(this.getMenuData(item.children, `${parentPath}/${item.path}`));
       }
     });

+ 199 - 0
src/routes/List/Applications.js

@@ -0,0 +1,199 @@
+import React, { PureComponent } from 'react';
+import numeral from 'numeral';
+import { connect } from 'dva';
+import { Row, Col, Form, Card, Select, Icon, Avatar, List, Tooltip, Dropdown, Menu } from 'antd';
+
+import StandardFormRow from '../../components/StandardFormRow';
+import TagSelect from '../../components/TagSelect';
+
+import styles from './Projects.less';
+
+const { Option } = Select;
+const FormItem = Form.Item;
+
+const formatWan = (val) => {
+  const v = val * 1;
+  if (!v || isNaN(v)) return '';
+
+  let result = val;
+  if (val > 10000) {
+    result = Math.floor(val / 10000);
+    result = <span>{result}<em className={styles.wan}>万</em></span>;
+  }
+  return result;
+};
+
+/* eslint react/no-array-index-key: 0 */
+@Form.create()
+@connect(state => ({
+  list: state.list,
+}))
+export default class FilterCardList extends PureComponent {
+  componentDidMount() {
+    this.props.dispatch({
+      type: 'list/fetch',
+      payload: {
+        count: 8,
+      },
+    });
+  }
+
+  handleFormSubmit = () => {
+    const { form, dispatch } = this.props;
+    // setTimeout 用于保证获取表单值是在所有表单字段更新完毕的时候
+    setTimeout(() => {
+      form.validateFields((err) => {
+        if (!err) {
+          // eslint-disable-next-line
+          dispatch({
+            type: 'list/fetch',
+            payload: {
+              count: 8,
+            },
+          });
+        }
+      });
+    }, 0);
+  }
+
+  render() {
+    const { list: { list, loading }, form } = this.props;
+    const { getFieldDecorator } = form;
+
+    const CardInfo = ({ activeUser, newUser }) => (
+      <div className={styles.cardInfo}>
+        <div>
+          <p>活跃用户</p>
+          <p>{activeUser}</p>
+        </div>
+        <div>
+          <p>新增用户</p>
+          <p>{newUser}</p>
+        </div>
+      </div>
+    );
+
+    const formItemLayout = {
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 },
+      },
+    };
+
+    const itemMenu = (
+      <Menu>
+        <Menu.Item>
+          <a target="_blank" rel="noopener noreferrer" href="http://www.alipay.com/">1st menu item</a>
+        </Menu.Item>
+        <Menu.Item>
+          <a target="_blank" rel="noopener noreferrer" href="http://www.taobao.com/">2nd menu item</a>
+        </Menu.Item>
+        <Menu.Item>
+          <a target="_blank" rel="noopener noreferrer" href="http://www.tmall.com/">3d menu item</a>
+        </Menu.Item>
+      </Menu>
+    );
+
+    return (
+      <div className={styles.filterCardList}>
+        <Card bordered={false}>
+          <Form layout="inline">
+            <StandardFormRow title="所属类目" block style={{ paddingBottom: 11 }}>
+              <FormItem>
+                {getFieldDecorator('category')(
+                  <TagSelect onChange={this.handleFormSubmit} expandable>
+                    <TagSelect.Option value="cat1">类目一</TagSelect.Option>
+                    <TagSelect.Option value="cat2">类目二</TagSelect.Option>
+                    <TagSelect.Option value="cat3">类目三</TagSelect.Option>
+                    <TagSelect.Option value="cat4">类目四</TagSelect.Option>
+                    <TagSelect.Option value="cat5">类目五</TagSelect.Option>
+                    <TagSelect.Option value="cat6">类目六</TagSelect.Option>
+                    <TagSelect.Option value="cat7">类目七</TagSelect.Option>
+                    <TagSelect.Option value="cat8">类目八</TagSelect.Option>
+                    <TagSelect.Option value="cat9">类目九</TagSelect.Option>
+                    <TagSelect.Option value="cat10">类目十</TagSelect.Option>
+                    <TagSelect.Option value="cat11">类目十一</TagSelect.Option>
+                    <TagSelect.Option value="cat12">类目十二</TagSelect.Option>
+                  </TagSelect>
+                )}
+              </FormItem>
+            </StandardFormRow>
+            <StandardFormRow
+              title="其它选项"
+              grid
+              last
+            >
+              <Row gutter={16}>
+                <Col lg={8} md={10} sm={10} xs={24}>
+                  <FormItem
+                    {...formItemLayout}
+                    label="作者"
+                  >
+                    {getFieldDecorator('author', {})(
+                      <Select
+                        onChange={this.handleFormSubmit}
+                        placeholder="不限"
+                        style={{ maxWidth: 200, width: '100%' }}
+                      >
+                        <Option value="lisa">王昭君</Option>
+                      </Select>
+                    )}
+                  </FormItem>
+                </Col>
+                <Col lg={8} md={10} sm={10} xs={24}>
+                  <FormItem
+                    {...formItemLayout}
+                    label="好评度"
+                  >
+                    {getFieldDecorator('rate', {})(
+                      <Select
+                        onChange={this.handleFormSubmit}
+                        placeholder="不限"
+                        style={{ maxWidth: 200, width: '100%' }}
+                      >
+                        <Option value="good">优秀</Option>
+                        <Option value="normal">普通</Option>
+                      </Select>
+                    )}
+                  </FormItem>
+                </Col>
+              </Row>
+            </StandardFormRow>
+          </Form>
+        </Card>
+        <List
+          rowKey="id"
+          style={{ marginTop: 24 }}
+          grid={{ gutter: 24, xl: 4, lg: 3, md: 3, sm: 2, xs: 1 }}
+          loading={loading}
+          dataSource={list}
+          renderItem={item => (
+            <List.Item key={item.id}>
+              <Card
+                hoverable
+                bodyStyle={{ paddingBottom: 20 }}
+                actions={[
+                  <Tooltip title="下载"><Icon type="download" /></Tooltip>,
+                  <Tooltip title="编辑"><Icon type="edit" /></Tooltip>,
+                  <Tooltip title="分享"><Icon type="share-alt" /></Tooltip>,
+                  <Dropdown overlay={itemMenu}><Icon type="ellipsis" /></Dropdown>,
+                ]}
+              >
+                <Card.Meta
+                  avatar={<Avatar size="small" src={item.avatar} />}
+                  title={item.title}
+                />
+                <div className={styles.cardItemContent}>
+                  <CardInfo
+                    activeUser={formatWan(item.activeUser)}
+                    newUser={numeral(item.newUser).format('0,0')}
+                  />
+                </div>
+              </Card>
+            </List.Item>
+          )}
+        />
+      </div>
+    );
+  }
+}

src/routes/List/FilterCardList.less → src/routes/List/Applications.less


+ 241 - 0
src/routes/List/Articles.js

@@ -0,0 +1,241 @@
+import React, { Component } from 'react';
+import moment from 'moment';
+import { connect } from 'dva';
+import { Form, Card, Select, List, Tag, Icon, Avatar, Row, Col, Button } from 'antd';
+
+import StandardFormRow from '../../components/StandardFormRow';
+import TagSelect from '../../components/TagSelect';
+import styles from './Articles.less';
+
+const { Option } = Select;
+const FormItem = Form.Item;
+
+const pageSize = 5;
+
+@Form.create()
+@connect(state => ({
+  list: state.list,
+}))
+export default class SearchList extends Component {
+  componentDidMount() {
+    this.fetchMore();
+  }
+
+  setOwner = () => {
+    const { form } = this.props;
+    form.setFieldsValue({
+      owner: ['wzj'],
+    });
+  }
+
+  fetchMore = () => {
+    this.props.dispatch({
+      type: 'list/appendFetch',
+      payload: {
+        count: pageSize,
+      },
+    });
+  }
+
+  render() {
+    const { form, list: { list, loading } } = this.props;
+    const { getFieldDecorator } = form;
+
+    const owners = [
+      {
+        id: 'wzj',
+        name: '我自己',
+      },
+      {
+        id: 'wjh',
+        name: '吴家豪',
+      },
+      {
+        id: 'zxx',
+        name: '周星星',
+      },
+      {
+        id: 'zly',
+        name: '赵丽颖',
+      },
+      {
+        id: 'ym',
+        name: '姚明',
+      },
+    ];
+
+    const IconText = ({ type, text }) => (
+      <span>
+        <Icon type={type} style={{ marginRight: 8 }} />
+        {text}
+      </span>
+    );
+
+    const ListContent = ({ data: { content, updatedAt, avatar, owner, href } }) => (
+      <div className={styles.listContent}>
+        <div className={styles.description}>{content}</div>
+        <div className={styles.extra}>
+          <Avatar src={avatar} size="small" /><a href={href}>{owner}</a> 发布在 <a href={href}>{href}</a>
+          <em>{moment(updatedAt).format('YYYY-MM-DD hh:mm')}</em>
+        </div>
+      </div>
+    );
+
+    const formItemLayout = {
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 24 },
+        md: { span: 12 },
+      },
+    };
+
+    const loadMore = list.length > 0 ? (
+      <div style={{ textAlign: 'center', marginTop: 16 }}>
+        <Button onClick={this.fetchMore} style={{ paddingLeft: 48, paddingRight: 48 }}>
+          {loading ? <span><Icon type="loading" /> 加载中...</span> : '加载更多'}
+        </Button>
+      </div>
+    ) : null;
+
+    return (
+      <div>
+        <Card bordered={false}>
+          <Form layout="inline">
+            <StandardFormRow title="所属类目" block style={{ paddingBottom: 11 }}>
+              <FormItem>
+                {getFieldDecorator('category')(
+                  <TagSelect onChange={this.handleFormSubmit} expandable>
+                    <TagSelect.Option value="cat1">类目一</TagSelect.Option>
+                    <TagSelect.Option value="cat2">类目二</TagSelect.Option>
+                    <TagSelect.Option value="cat3">类目三</TagSelect.Option>
+                    <TagSelect.Option value="cat4">类目四</TagSelect.Option>
+                    <TagSelect.Option value="cat5">类目五</TagSelect.Option>
+                    <TagSelect.Option value="cat6">类目六</TagSelect.Option>
+                    <TagSelect.Option value="cat7">类目七</TagSelect.Option>
+                    <TagSelect.Option value="cat8">类目八</TagSelect.Option>
+                    <TagSelect.Option value="cat9">类目九</TagSelect.Option>
+                    <TagSelect.Option value="cat10">类目十</TagSelect.Option>
+                    <TagSelect.Option value="cat11">类目十一</TagSelect.Option>
+                    <TagSelect.Option value="cat12">类目十二</TagSelect.Option>
+                  </TagSelect>
+                )}
+              </FormItem>
+            </StandardFormRow>
+            <StandardFormRow
+              title="owner"
+              grid
+            >
+              <Row>
+                <Col lg={16} md={24} sm={24} xs={24}>
+                  <FormItem>
+                    {getFieldDecorator('owner', {
+                      initialValue: ['wjh', 'zxx'],
+                    })(
+                      <Select
+                        mode="multiple"
+                        style={{ maxWidth: 286, width: '100%' }}
+                        placeholder="选择 owner"
+                      >
+                        {
+                          owners.map(owner =>
+                            <Option key={owner.id} value={owner.id}>{owner.name}</Option>
+                          )
+                        }
+                      </Select>
+                    )}
+                    <a className={styles.selfTrigger} onClick={this.setOwner}>只看自己的</a>
+                  </FormItem>
+                </Col>
+              </Row>
+            </StandardFormRow>
+            <StandardFormRow
+              title="其它选项"
+              grid
+              last
+            >
+              <Row gutter={16}>
+                <Col xl={8} lg={10} md={12} sm={24} xs={24}>
+                  <FormItem
+                    {...formItemLayout}
+                    label="活跃用户"
+                  >
+                    {getFieldDecorator('user', {})(
+                      <Select
+                        onChange={this.handleFormSubmit}
+                        placeholder="不限"
+                        style={{ maxWidth: 200, width: '100%' }}
+                      >
+                        <Option value="lisa">李三</Option>
+                      </Select>
+                    )}
+                  </FormItem>
+                </Col>
+                <Col xl={8} lg={10} md={12} sm={24} xs={24}>
+                  <FormItem
+                    {...formItemLayout}
+                    label="好评度"
+                  >
+                    {getFieldDecorator('rate', {})(
+                      <FormItem
+                        label="好评度"
+                      >
+                        {getFieldDecorator('rate', {})(
+                          <Select
+                            onChange={this.handleFormSubmit}
+                            placeholder="不限"
+                            style={{ maxWidth: 200, width: '100%' }}
+                          >
+                            <Option value="good">优秀</Option>
+                          </Select>
+                        )}
+                      </FormItem>
+                    )}
+                  </FormItem>
+                </Col>
+              </Row>
+            </StandardFormRow>
+          </Form>
+        </Card>
+        <Card
+          style={{ marginTop: 24 }}
+          bordered={false}
+          bodyStyle={{ padding: '8px 32px 32px 32px' }}
+        >
+          <List
+            size="large"
+            loading={list.length === 0 ? loading : false}
+            rowKey="id"
+            itemLayout="vertical"
+            loadMore={loadMore}
+            dataSource={list}
+            renderItem={item => (
+              <List.Item
+                key={item.id}
+                actions={[
+                  <IconText type="star-o" text={item.star} />,
+                  <IconText type="like-o" text={item.like} />,
+                  <IconText type="message" text={item.message} />,
+                ]}
+                extra={<div className={styles.listItemExtra} />}
+              >
+                <List.Item.Meta
+                  title={(
+                    <a className={styles.listItemMetaTitle} href={item.href}>{item.title}</a>
+                  )}
+                  description={
+                    <span>
+                      <Tag>Ant Design</Tag>
+                      <Tag>设计语言</Tag>
+                      <Tag>蚂蚁金服</Tag>
+                    </span>
+                  }
+                />
+                <ListContent data={item} />
+              </List.Item>
+            )}
+          />
+        </Card>
+      </div>
+    );
+  }
+}

src/routes/List/SearchList.less → src/routes/List/Articles.less


+ 0 - 225
src/routes/List/CoverCardList.js

@@ -1,225 +0,0 @@
-import React, { PureComponent } from 'react';
-import moment from 'moment';
-import { connect } from 'dva';
-import { routerRedux } from 'dva/router';
-import { Row, Col, Form, Card, Select, List, Input } from 'antd';
-
-import PageHeaderLayout from '../../layouts/PageHeaderLayout';
-import StandardFormRow from '../../components/StandardFormRow';
-import TagSelect from '../../components/TagSelect';
-import AvatarList from '../../components/AvatarList';
-
-import styles from './CoverCardList.less';
-
-const { Option } = Select;
-const FormItem = Form.Item;
-
-/* eslint react/no-array-index-key: 0 */
-@Form.create()
-@connect(state => ({
-  list: state.list,
-}))
-export default class CoverCardList extends PureComponent {
-  componentDidMount() {
-    this.props.dispatch({
-      type: 'list/fetch',
-      payload: {
-        count: 8,
-      },
-    });
-  }
-
-  handleFormSubmit = () => {
-    const { form, dispatch } = this.props;
-    // setTimeout 用于保证获取表单值是在所有表单字段更新完毕的时候
-    setTimeout(() => {
-      form.validateFields((err) => {
-        if (!err) {
-          // eslint-disable-next-line
-          dispatch({
-            type: 'list/fetch',
-            payload: {
-              count: 8,
-            },
-          });
-        }
-      });
-    }, 0);
-  }
-
-  handleTabChange = (key) => {
-    const { dispatch } = this.props;
-    switch (key) {
-      case 'doc':
-        dispatch(routerRedux.push('/list/search'));
-        break;
-      case 'app':
-        dispatch(routerRedux.push('/list/filter-card-list'));
-        break;
-      case 'project':
-        dispatch(routerRedux.push('/list/cover-card-list'));
-        break;
-      default:
-        break;
-    }
-  }
-
-  render() {
-    const { list: { list = [], loading }, form } = this.props;
-    const { getFieldDecorator } = form;
-
-    const cardList = list ? (
-      <List
-        rowKey="id"
-        loading={loading}
-        grid={{ gutter: 24, lg: 4, md: 3, sm: 2, xs: 1 }}
-        dataSource={list}
-        renderItem={item => (
-          <List.Item>
-            <Card
-              className={styles.card}
-              hoverable
-              cover={<img alt={item.title} src={item.cover} height={154} />}
-            >
-              <Card.Meta
-                title={<a href="#">{item.title}</a>}
-                description={item.subDescription}
-              />
-              <div className={styles.cardItemContent}>
-                <span>{moment(item.updatedAt).fromNow()}</span>
-                <div className={styles.avatarList}>
-                  <AvatarList size="mini">
-                    {
-                      item.members.map((member, i) => (
-                        <AvatarList.Item
-                          key={`${item.id}-avatar-${i}`}
-                          src={member.avatar}
-                          tips={member.name}
-                        />
-                      ))
-                    }
-                  </AvatarList>
-                </div>
-              </div>
-            </Card>
-          </List.Item>
-        )}
-      />
-    ) : null;
-
-    const tabList = [
-      {
-        key: 'doc',
-        tab: '文章',
-      },
-      {
-        key: 'app',
-        tab: '应用',
-      },
-      {
-        key: 'project',
-        tab: '项目',
-        default: true,
-      },
-    ];
-
-    const pageHeaderContent = (
-      <div style={{ textAlign: 'center' }}>
-        <Input.Search
-          placeholder="请输入"
-          enterButton="搜索"
-          size="large"
-          onSearch={this.handleFormSubmit}
-          style={{ width: 522 }}
-        />
-      </div>
-    );
-
-    const formItemLayout = {
-      wrapperCol: {
-        xs: { span: 24 },
-        sm: { span: 16 },
-      },
-    };
-
-    return (
-      <PageHeaderLayout
-        title="搜索列表"
-        content={pageHeaderContent}
-        tabList={tabList}
-        onTabChange={this.handleTabChange}
-      >
-        <div className={styles.coverCardList}>
-          <Card bordered={false}>
-            <Form layout="inline">
-              <StandardFormRow title="所属类目" block style={{ paddingBottom: 11 }}>
-                <FormItem>
-                  {getFieldDecorator('category')(
-                    <TagSelect onChange={this.handleFormSubmit} expandable>
-                      <TagSelect.Option value="cat1">类目一</TagSelect.Option>
-                      <TagSelect.Option value="cat2">类目二</TagSelect.Option>
-                      <TagSelect.Option value="cat3">类目三</TagSelect.Option>
-                      <TagSelect.Option value="cat4">类目四</TagSelect.Option>
-                      <TagSelect.Option value="cat5">类目五</TagSelect.Option>
-                      <TagSelect.Option value="cat6">类目六</TagSelect.Option>
-                      <TagSelect.Option value="cat7">类目七</TagSelect.Option>
-                      <TagSelect.Option value="cat8">类目八</TagSelect.Option>
-                      <TagSelect.Option value="cat9">类目九</TagSelect.Option>
-                      <TagSelect.Option value="cat10">类目十</TagSelect.Option>
-                      <TagSelect.Option value="cat11">类目十一</TagSelect.Option>
-                      <TagSelect.Option value="cat12">类目十二</TagSelect.Option>
-                    </TagSelect>
-                  )}
-                </FormItem>
-              </StandardFormRow>
-              <StandardFormRow
-                title="其它选项"
-                grid
-                last
-              >
-                <Row gutter={24}>
-                  <Col lg={8} md={10} sm={10} xs={24}>
-                    <FormItem
-                      {...formItemLayout}
-                      label="作者"
-                    >
-                      {getFieldDecorator('author', {})(
-                        <Select
-                          onChange={this.handleFormSubmit}
-                          placeholder="不限"
-                          style={{ maxWidth: 200, width: '100%' }}
-                        >
-                          <Option value="lisa">王昭君</Option>
-                        </Select>
-                      )}
-                    </FormItem>
-                  </Col>
-                  <Col lg={8} md={10} sm={10} xs={24}>
-                    <FormItem
-                      {...formItemLayout}
-                      label="好评度"
-                    >
-                      {getFieldDecorator('rate', {})(
-                        <Select
-                          onChange={this.handleFormSubmit}
-                          placeholder="不限"
-                          style={{ maxWidth: 200, width: '100%' }}
-                        >
-                          <Option value="good">优秀</Option>
-                          <Option value="normal">普通</Option>
-                        </Select>
-                      )}
-                    </FormItem>
-                  </Col>
-                </Row>
-              </StandardFormRow>
-            </Form>
-          </Card>
-          <div className={styles.cardList}>
-            {cardList}
-          </div>
-        </div>
-      </PageHeaderLayout>
-    );
-  }
-}

+ 0 - 253
src/routes/List/FilterCardList.js

@@ -1,253 +0,0 @@
-import React, { PureComponent } from 'react';
-import numeral from 'numeral';
-import { connect } from 'dva';
-import { routerRedux } from 'dva/router';
-import { Row, Col, Form, Card, Select, Icon, Avatar, List, Tooltip, Input, Dropdown, Menu } from 'antd';
-
-import PageHeaderLayout from '../../layouts/PageHeaderLayout';
-import StandardFormRow from '../../components/StandardFormRow';
-import TagSelect from '../../components/TagSelect';
-
-import styles from './FilterCardList.less';
-
-const { Option } = Select;
-const FormItem = Form.Item;
-
-const formatWan = (val) => {
-  const v = val * 1;
-  if (!v || isNaN(v)) return '';
-
-  let result = val;
-  if (val > 10000) {
-    result = Math.floor(val / 10000);
-    result = <span>{result}<em className={styles.wan}>万</em></span>;
-  }
-  return result;
-};
-
-/* eslint react/no-array-index-key: 0 */
-@Form.create()
-@connect(state => ({
-  list: state.list,
-}))
-export default class FilterCardList extends PureComponent {
-  componentDidMount() {
-    this.props.dispatch({
-      type: 'list/fetch',
-      payload: {
-        count: 8,
-      },
-    });
-  }
-
-  handleFormSubmit = () => {
-    const { form, dispatch } = this.props;
-    // setTimeout 用于保证获取表单值是在所有表单字段更新完毕的时候
-    setTimeout(() => {
-      form.validateFields((err) => {
-        if (!err) {
-          // eslint-disable-next-line
-          dispatch({
-            type: 'list/fetch',
-            payload: {
-              count: 8,
-            },
-          });
-        }
-      });
-    }, 0);
-  }
-
-  handleTabChange = (key) => {
-    const { dispatch } = this.props;
-    switch (key) {
-      case 'doc':
-        dispatch(routerRedux.push('/list/search'));
-        break;
-      case 'app':
-        dispatch(routerRedux.push('/list/filter-card-list'));
-        break;
-      case 'project':
-        dispatch(routerRedux.push('/list/cover-card-list'));
-        break;
-      default:
-        break;
-    }
-  }
-
-  render() {
-    const { list: { list, loading }, form } = this.props;
-    const { getFieldDecorator } = form;
-
-    const tabList = [
-      {
-        key: 'doc',
-        tab: '文章',
-      },
-      {
-        key: 'app',
-        tab: '应用',
-        default: true,
-      },
-      {
-        key: 'project',
-        tab: '项目',
-      },
-    ];
-
-    const CardInfo = ({ activeUser, newUser }) => (
-      <div className={styles.cardInfo}>
-        <div>
-          <p>活跃用户</p>
-          <p>{activeUser}</p>
-        </div>
-        <div>
-          <p>新增用户</p>
-          <p>{newUser}</p>
-        </div>
-      </div>
-    );
-
-    const pageHeaderContent = (
-      <div style={{ textAlign: 'center' }}>
-        <Input.Search
-          placeholder="请输入"
-          enterButton="搜索"
-          size="large"
-          onSearch={this.handleFormSubmit}
-          style={{ width: 522 }}
-        />
-      </div>
-    );
-
-    const formItemLayout = {
-      wrapperCol: {
-        xs: { span: 24 },
-        sm: { span: 16 },
-      },
-    };
-
-    const itemMenu = (
-      <Menu>
-        <Menu.Item>
-          <a target="_blank" rel="noopener noreferrer" href="http://www.alipay.com/">1st menu item</a>
-        </Menu.Item>
-        <Menu.Item>
-          <a target="_blank" rel="noopener noreferrer" href="http://www.taobao.com/">2nd menu item</a>
-        </Menu.Item>
-        <Menu.Item>
-          <a target="_blank" rel="noopener noreferrer" href="http://www.tmall.com/">3d menu item</a>
-        </Menu.Item>
-      </Menu>
-    );
-
-    return (
-      <PageHeaderLayout
-        title="搜索列表"
-        content={pageHeaderContent}
-        tabList={tabList}
-        onTabChange={this.handleTabChange}
-      >
-        <div className={styles.filterCardList}>
-          <Card bordered={false}>
-            <Form layout="inline">
-              <StandardFormRow title="所属类目" block style={{ paddingBottom: 11 }}>
-                <FormItem>
-                  {getFieldDecorator('category')(
-                    <TagSelect onChange={this.handleFormSubmit} expandable>
-                      <TagSelect.Option value="cat1">类目一</TagSelect.Option>
-                      <TagSelect.Option value="cat2">类目二</TagSelect.Option>
-                      <TagSelect.Option value="cat3">类目三</TagSelect.Option>
-                      <TagSelect.Option value="cat4">类目四</TagSelect.Option>
-                      <TagSelect.Option value="cat5">类目五</TagSelect.Option>
-                      <TagSelect.Option value="cat6">类目六</TagSelect.Option>
-                      <TagSelect.Option value="cat7">类目七</TagSelect.Option>
-                      <TagSelect.Option value="cat8">类目八</TagSelect.Option>
-                      <TagSelect.Option value="cat9">类目九</TagSelect.Option>
-                      <TagSelect.Option value="cat10">类目十</TagSelect.Option>
-                      <TagSelect.Option value="cat11">类目十一</TagSelect.Option>
-                      <TagSelect.Option value="cat12">类目十二</TagSelect.Option>
-                    </TagSelect>
-                  )}
-                </FormItem>
-              </StandardFormRow>
-              <StandardFormRow
-                title="其它选项"
-                grid
-                last
-              >
-                <Row gutter={16}>
-                  <Col lg={8} md={10} sm={10} xs={24}>
-                    <FormItem
-                      {...formItemLayout}
-                      label="作者"
-                    >
-                      {getFieldDecorator('author', {})(
-                        <Select
-                          onChange={this.handleFormSubmit}
-                          placeholder="不限"
-                          style={{ maxWidth: 200, width: '100%' }}
-                        >
-                          <Option value="lisa">王昭君</Option>
-                        </Select>
-                      )}
-                    </FormItem>
-                  </Col>
-                  <Col lg={8} md={10} sm={10} xs={24}>
-                    <FormItem
-                      {...formItemLayout}
-                      label="好评度"
-                    >
-                      {getFieldDecorator('rate', {})(
-                        <Select
-                          onChange={this.handleFormSubmit}
-                          placeholder="不限"
-                          style={{ maxWidth: 200, width: '100%' }}
-                        >
-                          <Option value="good">优秀</Option>
-                          <Option value="normal">普通</Option>
-                        </Select>
-                      )}
-                    </FormItem>
-                  </Col>
-                </Row>
-              </StandardFormRow>
-            </Form>
-          </Card>
-          <List
-            rowKey="id"
-            style={{ marginTop: 24 }}
-            grid={{ gutter: 24, xl: 4, lg: 3, md: 3, sm: 2, xs: 1 }}
-            loading={loading}
-            dataSource={list}
-            renderItem={item => (
-              <List.Item key={item.id}>
-                <Card
-                  hoverable
-                  bodyStyle={{ paddingBottom: 20 }}
-                  actions={[
-                    <Tooltip title="下载"><Icon type="download" /></Tooltip>,
-                    <Tooltip title="编辑"><Icon type="edit" /></Tooltip>,
-                    <Tooltip title="分享"><Icon type="share-alt" /></Tooltip>,
-                    <Dropdown overlay={itemMenu}><Icon type="ellipsis" /></Dropdown>,
-                  ]}
-                >
-                  <Card.Meta
-                    avatar={<Avatar size="small" src={item.avatar} />}
-                    title={item.title}
-                  />
-                  <div className={styles.cardItemContent}>
-                    <CardInfo
-                      activeUser={formatWan(item.activeUser)}
-                      newUser={numeral(item.newUser).format('0,0')}
-                    />
-                  </div>
-                </Card>
-              </List.Item>
-            )}
-          />
-        </div>
-      </PageHeaderLayout>
-    );
-  }
-}

+ 82 - 0
src/routes/List/List.js

@@ -0,0 +1,82 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { routerRedux, Route, Switch } from 'dva/router';
+import { connect } from 'dva';
+import { Input } from 'antd';
+import PageHeaderLayout from '../../layouts/PageHeaderLayout';
+
+@connect()
+export default class SearchList extends Component {
+  static contextTypes = {
+    routeData: PropTypes.array,
+  };
+
+  handleTabChange = (key) => {
+    const { dispatch, match } = this.props;
+    switch (key) {
+      case 'articles':
+        dispatch(routerRedux.push(`${match.url}/articles`));
+        break;
+      case 'applications':
+        dispatch(routerRedux.push(`${match.url}/applications`));
+        break;
+      case 'projects':
+        dispatch(routerRedux.push(`${match.url}/projects`));
+        break;
+      default:
+        break;
+    }
+  }
+
+  render() {
+    const tabList = [{
+      key: 'articles',
+      tab: '文章',
+    }, {
+      key: 'applications',
+      tab: '应用',
+    }, {
+      key: 'projects',
+      tab: '项目',
+    }];
+
+    const mainSearch = (
+      <div style={{ textAlign: 'center' }}>
+        <Input.Search
+          placeholder="请输入"
+          enterButton="搜索"
+          size="large"
+          onSearch={this.handleFormSubmit}
+          style={{ width: 522 }}
+        />
+      </div>
+    );
+
+    const { match } = this.props;
+    const { routeData } = this.context;
+    const routes = routeData.filter(item => item.path === match.path)[0].children;
+
+    return (
+      <PageHeaderLayout
+        title="搜索列表"
+        content={mainSearch}
+        tabList={tabList}
+        onTabChange={this.handleTabChange}
+      >
+        <Switch>
+          {
+            routes.map(item =>
+              (
+                <Route
+                  key={item.path}
+                  path={`${match.path}/${item.path}`}
+                  component={item.component}
+                />
+              )
+            )
+          }
+        </Switch>
+      </PageHeaderLayout>
+    );
+  }
+}

+ 171 - 0
src/routes/List/Projects.js

@@ -0,0 +1,171 @@
+import React, { PureComponent } from 'react';
+import moment from 'moment';
+import { connect } from 'dva';
+import { Row, Col, Form, Card, Select, List } from 'antd';
+
+import StandardFormRow from '../../components/StandardFormRow';
+import TagSelect from '../../components/TagSelect';
+import AvatarList from '../../components/AvatarList';
+
+import styles from './Projects.less';
+
+const { Option } = Select;
+const FormItem = Form.Item;
+
+/* eslint react/no-array-index-key: 0 */
+@Form.create()
+@connect(state => ({
+  list: state.list,
+}))
+export default class CoverCardList extends PureComponent {
+  componentDidMount() {
+    this.props.dispatch({
+      type: 'list/fetch',
+      payload: {
+        count: 8,
+      },
+    });
+  }
+
+  handleFormSubmit = () => {
+    const { form, dispatch } = this.props;
+    // setTimeout 用于保证获取表单值是在所有表单字段更新完毕的时候
+    setTimeout(() => {
+      form.validateFields((err) => {
+        if (!err) {
+          // eslint-disable-next-line
+          dispatch({
+            type: 'list/fetch',
+            payload: {
+              count: 8,
+            },
+          });
+        }
+      });
+    }, 0);
+  }
+
+  render() {
+    const { list: { list = [], loading }, form } = this.props;
+    const { getFieldDecorator } = form;
+
+    const cardList = list ? (
+      <List
+        rowKey="id"
+        loading={loading}
+        grid={{ gutter: 24, lg: 4, md: 3, sm: 2, xs: 1 }}
+        dataSource={list}
+        renderItem={item => (
+          <List.Item>
+            <Card
+              className={styles.card}
+              hoverable
+              cover={<img alt={item.title} src={item.cover} height={154} />}
+            >
+              <Card.Meta
+                title={<a href="#">{item.title}</a>}
+                description={item.subDescription}
+              />
+              <div className={styles.cardItemContent}>
+                <span>{moment(item.updatedAt).fromNow()}</span>
+                <div className={styles.avatarList}>
+                  <AvatarList size="mini">
+                    {
+                      item.members.map((member, i) => (
+                        <AvatarList.Item
+                          key={`${item.id}-avatar-${i}`}
+                          src={member.avatar}
+                          tips={member.name}
+                        />
+                      ))
+                    }
+                  </AvatarList>
+                </div>
+              </div>
+            </Card>
+          </List.Item>
+        )}
+      />
+    ) : null;
+
+    const formItemLayout = {
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 },
+      },
+    };
+
+    return (
+      <div className={styles.coverCardList}>
+        <Card bordered={false}>
+          <Form layout="inline">
+            <StandardFormRow title="所属类目" block style={{ paddingBottom: 11 }}>
+              <FormItem>
+                {getFieldDecorator('category')(
+                  <TagSelect onChange={this.handleFormSubmit} expandable>
+                    <TagSelect.Option value="cat1">类目一</TagSelect.Option>
+                    <TagSelect.Option value="cat2">类目二</TagSelect.Option>
+                    <TagSelect.Option value="cat3">类目三</TagSelect.Option>
+                    <TagSelect.Option value="cat4">类目四</TagSelect.Option>
+                    <TagSelect.Option value="cat5">类目五</TagSelect.Option>
+                    <TagSelect.Option value="cat6">类目六</TagSelect.Option>
+                    <TagSelect.Option value="cat7">类目七</TagSelect.Option>
+                    <TagSelect.Option value="cat8">类目八</TagSelect.Option>
+                    <TagSelect.Option value="cat9">类目九</TagSelect.Option>
+                    <TagSelect.Option value="cat10">类目十</TagSelect.Option>
+                    <TagSelect.Option value="cat11">类目十一</TagSelect.Option>
+                    <TagSelect.Option value="cat12">类目十二</TagSelect.Option>
+                  </TagSelect>
+                )}
+              </FormItem>
+            </StandardFormRow>
+            <StandardFormRow
+              title="其它选项"
+              grid
+              last
+            >
+              <Row gutter={24}>
+                <Col lg={8} md={10} sm={10} xs={24}>
+                  <FormItem
+                    {...formItemLayout}
+                    label="作者"
+                  >
+                    {getFieldDecorator('author', {})(
+                      <Select
+                        onChange={this.handleFormSubmit}
+                        placeholder="不限"
+                        style={{ maxWidth: 200, width: '100%' }}
+                      >
+                        <Option value="lisa">王昭君</Option>
+                      </Select>
+                    )}
+                  </FormItem>
+                </Col>
+                <Col lg={8} md={10} sm={10} xs={24}>
+                  <FormItem
+                    {...formItemLayout}
+                    label="好评度"
+                  >
+                    {getFieldDecorator('rate', {})(
+                      <Select
+                        onChange={this.handleFormSubmit}
+                        placeholder="不限"
+                        style={{ maxWidth: 200, width: '100%' }}
+                      >
+                        <Option value="good">优秀</Option>
+                        <Option value="normal">普通</Option>
+                      </Select>
+                    )}
+                  </FormItem>
+                </Col>
+              </Row>
+            </StandardFormRow>
+          </Form>
+        </Card>
+        <div className={styles.cardList}>
+          {cardList}
+        </div>
+      </div>
+    );
+  }
+}

src/routes/List/CoverCardList.less → src/routes/List/Projects.less


+ 0 - 294
src/routes/List/SearchList.js

@@ -1,294 +0,0 @@
-import React, { Component } from 'react';
-import moment from 'moment';
-import { connect } from 'dva';
-import { routerRedux } from 'dva/router';
-import { Form, Card, Select, List, Tag, Icon, Avatar, Row, Col, Button, Input } from 'antd';
-
-import PageHeaderLayout from '../../layouts/PageHeaderLayout';
-import StandardFormRow from '../../components/StandardFormRow';
-import TagSelect from '../../components/TagSelect';
-import styles from './SearchList.less';
-
-const { Option } = Select;
-const FormItem = Form.Item;
-
-const pageSize = 5;
-
-@Form.create()
-@connect(state => ({
-  list: state.list,
-}))
-export default class SearchList extends Component {
-  componentDidMount() {
-    this.fetchMore();
-  }
-
-  setOwner = () => {
-    const { form } = this.props;
-    form.setFieldsValue({
-      owner: ['wzj'],
-    });
-  }
-
-  fetchMore = () => {
-    this.props.dispatch({
-      type: 'list/appendFetch',
-      payload: {
-        count: pageSize,
-      },
-    });
-  }
-
-  handleTabChange = (key) => {
-    const { dispatch } = this.props;
-    switch (key) {
-      case 'docs':
-        dispatch(routerRedux.push('/list/search'));
-        break;
-      case 'app':
-        dispatch(routerRedux.push('/list/filter-card-list'));
-        break;
-      case 'project':
-        dispatch(routerRedux.push('/list/cover-card-list'));
-        break;
-      default:
-        break;
-    }
-  }
-
-  render() {
-    const { form, list: { list, loading } } = this.props;
-    const { getFieldDecorator } = form;
-
-    const owners = [
-      {
-        id: 'wzj',
-        name: '我自己',
-      },
-      {
-        id: 'wjh',
-        name: '吴家豪',
-      },
-      {
-        id: 'zxx',
-        name: '周星星',
-      },
-      {
-        id: 'zly',
-        name: '赵丽颖',
-      },
-      {
-        id: 'ym',
-        name: '姚明',
-      },
-    ];
-
-    const tabList = [
-      {
-        key: 'doc',
-        tab: '文章',
-      },
-      {
-        key: 'app',
-        tab: '应用',
-      },
-      {
-        key: 'project',
-        tab: '项目',
-      },
-    ];
-
-    const IconText = ({ type, text }) => (
-      <span>
-        <Icon type={type} style={{ marginRight: 8 }} />
-        {text}
-      </span>
-    );
-
-    const ListContent = ({ data: { content, updatedAt, avatar, owner, href } }) => (
-      <div className={styles.listContent}>
-        <div className={styles.description}>{content}</div>
-        <div className={styles.extra}>
-          <Avatar src={avatar} size="small" /><a href={href}>{owner}</a> 发布在 <a href={href}>{href}</a>
-          <em>{moment(updatedAt).format('YYYY-MM-DD hh:mm')}</em>
-        </div>
-      </div>
-    );
-
-    const pageHeaderContent = (
-      <div style={{ textAlign: 'center' }}>
-        <Input.Search
-          placeholder="请输入"
-          enterButton="搜索"
-          size="large"
-          onSearch={this.handleFormSubmit}
-          style={{ width: 522 }}
-        />
-      </div>
-    );
-
-    const formItemLayout = {
-      wrapperCol: {
-        xs: { span: 24 },
-        sm: { span: 24 },
-        md: { span: 12 },
-      },
-    };
-
-    const loadMore = list.length > 0 ? (
-      <div style={{ textAlign: 'center', marginTop: 16 }}>
-        <Button onClick={this.fetchMore} style={{ paddingLeft: 48, paddingRight: 48 }}>
-          {loading ? <span><Icon type="loading" /> 加载中...</span> : '加载更多'}
-        </Button>
-      </div>
-    ) : null;
-
-    return (
-      <PageHeaderLayout
-        title="搜索列表"
-        content={pageHeaderContent}
-        tabList={tabList}
-        onTabChange={this.handleTabChange}
-      >
-        <div>
-          <Card bordered={false}>
-            <Form layout="inline">
-              <StandardFormRow title="所属类目" block style={{ paddingBottom: 11 }}>
-                <FormItem>
-                  {getFieldDecorator('category')(
-                    <TagSelect onChange={this.handleFormSubmit} expandable>
-                      <TagSelect.Option value="cat1">类目一</TagSelect.Option>
-                      <TagSelect.Option value="cat2">类目二</TagSelect.Option>
-                      <TagSelect.Option value="cat3">类目三</TagSelect.Option>
-                      <TagSelect.Option value="cat4">类目四</TagSelect.Option>
-                      <TagSelect.Option value="cat5">类目五</TagSelect.Option>
-                      <TagSelect.Option value="cat6">类目六</TagSelect.Option>
-                      <TagSelect.Option value="cat7">类目七</TagSelect.Option>
-                      <TagSelect.Option value="cat8">类目八</TagSelect.Option>
-                      <TagSelect.Option value="cat9">类目九</TagSelect.Option>
-                      <TagSelect.Option value="cat10">类目十</TagSelect.Option>
-                      <TagSelect.Option value="cat11">类目十一</TagSelect.Option>
-                      <TagSelect.Option value="cat12">类目十二</TagSelect.Option>
-                    </TagSelect>
-                  )}
-                </FormItem>
-              </StandardFormRow>
-              <StandardFormRow
-                title="owner"
-                grid
-              >
-                <Row>
-                  <Col lg={16} md={24} sm={24} xs={24}>
-                    <FormItem>
-                      {getFieldDecorator('owner', {
-                        initialValue: ['wjh', 'zxx'],
-                      })(
-                        <Select
-                          mode="multiple"
-                          style={{ maxWidth: 286, width: '100%' }}
-                          placeholder="选择 owner"
-                        >
-                          {
-                            owners.map(owner =>
-                              <Option key={owner.id} value={owner.id}>{owner.name}</Option>
-                            )
-                          }
-                        </Select>
-                      )}
-                      <a className={styles.selfTrigger} onClick={this.setOwner}>只看自己的</a>
-                    </FormItem>
-                  </Col>
-                </Row>
-              </StandardFormRow>
-              <StandardFormRow
-                title="其它选项"
-                grid
-                last
-              >
-                <Row gutter={16}>
-                  <Col xl={8} lg={10} md={12} sm={24} xs={24}>
-                    <FormItem
-                      {...formItemLayout}
-                      label="活跃用户"
-                    >
-                      {getFieldDecorator('user', {})(
-                        <Select
-                          onChange={this.handleFormSubmit}
-                          placeholder="不限"
-                          style={{ maxWidth: 200, width: '100%' }}
-                        >
-                          <Option value="lisa">李三</Option>
-                        </Select>
-                      )}
-                    </FormItem>
-                  </Col>
-                  <Col xl={8} lg={10} md={12} sm={24} xs={24}>
-                    <FormItem
-                      {...formItemLayout}
-                      label="好评度"
-                    >
-                      {getFieldDecorator('rate', {})(
-                        <FormItem
-                          label="好评度"
-                        >
-                          {getFieldDecorator('rate', {})(
-                            <Select
-                              onChange={this.handleFormSubmit}
-                              placeholder="不限"
-                              style={{ maxWidth: 200, width: '100%' }}
-                            >
-                              <Option value="good">优秀</Option>
-                            </Select>
-                          )}
-                        </FormItem>
-                      )}
-                    </FormItem>
-                  </Col>
-                </Row>
-              </StandardFormRow>
-            </Form>
-          </Card>
-          <Card
-            style={{ marginTop: 24 }}
-            bordered={false}
-            bodyStyle={{ padding: '8px 32px 32px 32px' }}
-          >
-            <List
-              size="large"
-              loading={list.length === 0 ? loading : false}
-              rowKey="id"
-              itemLayout="vertical"
-              loadMore={loadMore}
-              dataSource={list}
-              renderItem={item => (
-                <List.Item
-                  key={item.id}
-                  actions={[
-                    <IconText type="star-o" text={item.star} />,
-                    <IconText type="like-o" text={item.like} />,
-                    <IconText type="message" text={item.message} />,
-                  ]}
-                  extra={<div className={styles.listItemExtra} />}
-                >
-                  <List.Item.Meta
-                    title={(
-                      <a className={styles.listItemMetaTitle} href={item.href}>{item.title}</a>
-                    )}
-                    description={
-                      <span>
-                        <Tag>Ant Design</Tag>
-                        <Tag>设计语言</Tag>
-                        <Tag>蚂蚁金服</Tag>
-                      </span>
-                    }
-                  />
-                  <ListContent data={item} />
-                </List.Item>
-              )}
-            />
-          </Card>
-        </div>
-      </PageHeaderLayout>
-    );
-  }
-}