index.tsx 10.8 KB
Newer Older
陈帅's avatar
陈帅 committed
1
import React, { Component } from 'react';
valleykid's avatar
valleykid committed
2
import { findDOMNode } from 'react-dom';
3 4
import moment from 'moment';
import { connect } from 'dva';
jim's avatar
jim committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
import {
  List,
  Card,
  Row,
  Col,
  Radio,
  Input,
  Progress,
  Button,
  Icon,
  Dropdown,
  Menu,
  Avatar,
  Modal,
  Form,
  DatePicker,
  Select,
} from 'antd';
陈帅's avatar
陈帅 committed
23 24 25 26 27 28
import { FormComponentProps } from 'antd/lib/form';
import { IStateType } from './model';
import { Dispatch } from 'redux';
import { BasicListItemDataType } from './data';
import Result from './Result';
import { GridContent } from '@ant-design/pro-layout';
29

30
import styles from './style.less';
31

valleykid's avatar
valleykid committed
32
const FormItem = Form.Item;
33 34
const RadioButton = Radio.Button;
const RadioGroup = Radio.Group;
valleykid's avatar
valleykid committed
35 36
const SelectOption = Select.Option;
const { Search, TextArea } = Input;
37

陈帅's avatar
陈帅 committed
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
interface PAGE_NAME_UPPER_CAMEL_CASEProps extends FormComponentProps {
  BLOCK_NAME_CAMEL_CASE: IStateType;
  dispatch: Dispatch;
  loading: boolean;
}
interface PAGE_NAME_UPPER_CAMEL_CASEState {
  visible: boolean;
  done: boolean;
  current?: Partial<BasicListItemDataType>;
}
@connect(
  ({
    BLOCK_NAME_CAMEL_CASE,
    loading,
  }: {
    BLOCK_NAME_CAMEL_CASE: IStateType;
    loading: {
      models: { [key: string]: boolean };
    };
  }) => ({
    BLOCK_NAME_CAMEL_CASE,
    loading: loading.models.BLOCK_NAME_CAMEL_CASE,
  })
)
class PAGE_NAME_UPPER_CAMEL_CASE extends Component<
  PAGE_NAME_UPPER_CAMEL_CASEProps,
  PAGE_NAME_UPPER_CAMEL_CASEState
> {
  state: PAGE_NAME_UPPER_CAMEL_CASEState = { visible: false, done: false, current: undefined };
valleykid's avatar
valleykid committed
67

68 69 70 71 72
  formLayout = {
    labelCol: { span: 7 },
    wrapperCol: { span: 13 },
  };

73
  componentDidMount() {
陈帅's avatar
陈帅 committed
74 75
    const { dispatch } = this.props;
    dispatch({
76
      type: 'BLOCK_NAME_CAMEL_CASE/fetch',
77 78 79 80 81
      payload: {
        count: 5,
      },
    });
  }
陈帅's avatar
陈帅 committed
82

valleykid's avatar
valleykid committed
83 84 85 86 87
  showModal = () => {
    this.setState({
      visible: true,
      current: undefined,
    });
jim's avatar
jim committed
88
  };
陈帅's avatar
陈帅 committed
89

陈帅's avatar
陈帅 committed
90
  showEditModal = (item: BasicListItemDataType) => {
valleykid's avatar
valleykid committed
91 92 93 94
    this.setState({
      visible: true,
      current: item,
    });
jim's avatar
jim committed
95
  };
陈帅's avatar
陈帅 committed
96

valleykid's avatar
valleykid committed
97
  handleDone = () => {
陈帅's avatar
陈帅 committed
98
    setTimeout(() => this.addBtn && this.addBtn.blur(), 0);
valleykid's avatar
valleykid committed
99 100 101 102
    this.setState({
      done: false,
      visible: false,
    });
jim's avatar
jim committed
103
  };
陈帅's avatar
陈帅 committed
104

valleykid's avatar
valleykid committed
105
  handleCancel = () => {
陈帅's avatar
陈帅 committed
106
    setTimeout(() => this.addBtn && this.addBtn.blur(), 0);
valleykid's avatar
valleykid committed
107 108 109
    this.setState({
      visible: false,
    });
jim's avatar
jim committed
110
  };
陈帅's avatar
陈帅 committed
111

陈帅's avatar
陈帅 committed
112
  handleSubmit = (e: React.FormEvent) => {
valleykid's avatar
valleykid committed
113 114
    e.preventDefault();
    const { dispatch, form } = this.props;
陈帅's avatar
陈帅 committed
115 116
    const { current } = this.state;
    const id = current ? current.id : '';
valleykid's avatar
valleykid committed
117

陈帅's avatar
陈帅 committed
118 119
    setTimeout(() => this.addBtn && this.addBtn.blur(), 0);
    form.validateFields((err: string | undefined, fieldsValue: BasicListItemDataType) => {
valleykid's avatar
valleykid committed
120 121 122 123 124
      if (err) return;
      this.setState({
        done: true,
      });
      dispatch({
125
        type: 'BLOCK_NAME_CAMEL_CASE/submit',
valleykid's avatar
valleykid committed
126 127 128
        payload: { id, ...fieldsValue },
      });
    });
jim's avatar
jim committed
129
  };
陈帅's avatar
陈帅 committed
130

陈帅's avatar
陈帅 committed
131
  deleteItem = (id: string) => {
陈帅's avatar
陈帅 committed
132 133
    const { dispatch } = this.props;
    dispatch({
134
      type: 'BLOCK_NAME_CAMEL_CASE/submit',
valleykid's avatar
valleykid committed
135 136
      payload: { id },
    });
jim's avatar
jim committed
137
  };
陈帅's avatar
陈帅 committed
138
  addBtn: HTMLButtonElement | undefined | null;
139 140

  render() {
陈帅's avatar
陈帅 committed
141
    const {
142
      BLOCK_NAME_CAMEL_CASE: { list },
陈帅's avatar
陈帅 committed
143 144 145 146 147
      loading,
    } = this.props;
    const {
      form: { getFieldDecorator },
    } = this.props;
陈帅's avatar
陈帅 committed
148

valleykid's avatar
valleykid committed
149 150
    const { visible, done, current = {} } = this.state;

陈帅's avatar
陈帅 committed
151
    const editAndDelete = (key: string, currentItem: BasicListItemDataType) => {
valleykid's avatar
valleykid committed
152 153 154 155 156 157 158 159 160 161 162 163
      if (key === 'edit') this.showEditModal(currentItem);
      else if (key === 'delete') {
        Modal.confirm({
          title: '删除任务',
          content: '确定删除该任务吗?',
          okText: '确认',
          cancelText: '取消',
          onOk: () => this.deleteItem(currentItem.id),
        });
      }
    };

jim's avatar
jim committed
164 165 166
    const modalFooter = done
      ? { footer: null, onCancel: this.handleDone }
      : { okText: '保存', onOk: this.handleSubmit, onCancel: this.handleCancel };
167

陈帅's avatar
陈帅 committed
168 169 170 171 172
    const Info: React.SFC<{
      title: React.ReactNode;
      value: React.ReactNode;
      bordered?: boolean;
    }> = ({ title, value, bordered }) => (
173 174 175 176 177 178 179 180 181 182 183 184 185 186
      <div className={styles.headerInfo}>
        <span>{title}</span>
        <p>{value}</p>
        {bordered && <em />}
      </div>
    );

    const extraContent = (
      <div className={styles.extraContent}>
        <RadioGroup defaultValue="all">
          <RadioButton value="all">全部</RadioButton>
          <RadioButton value="progress">进行中</RadioButton>
          <RadioButton value="waiting">等待中</RadioButton>
        </RadioGroup>
jim's avatar
jim committed
187
        <Search className={styles.extraContentSearch} placeholder="请输入" onSearch={() => ({})} />
188 189 190 191 192 193 194 195 196 197
      </div>
    );

    const paginationProps = {
      showSizeChanger: true,
      showQuickJumper: true,
      pageSize: 5,
      total: 50,
    };

陈帅's avatar
陈帅 committed
198 199 200 201 202
    const ListContent = ({
      data: { owner, createdAt, percent, status },
    }: {
      data: BasicListItemDataType;
    }) => (
203
      <div className={styles.listContent}>
afc163's avatar
afc163 committed
204
        <div className={styles.listContentItem}>
205 206 207
          <span>Owner</span>
          <p>{owner}</p>
        </div>
afc163's avatar
afc163 committed
208
        <div className={styles.listContentItem}>
209
          <span>开始时间</span>
spiritree's avatar
spiritree committed
210
          <p>{moment(createdAt).format('YYYY-MM-DD HH:mm')}</p>
211
        </div>
afc163's avatar
afc163 committed
212 213
        <div className={styles.listContentItem}>
          <Progress percent={percent} status={status} strokeWidth={6} style={{ width: 180 }} />
214 215 216 217
        </div>
      </div>
    );

陈帅's avatar
陈帅 committed
218 219 220
    const MoreBtn: React.SFC<{
      current: BasicListItemDataType;
    }> = ({ current }) => (
jim's avatar
jim committed
221 222
      <Dropdown
        overlay={
陈帅's avatar
陈帅 committed
223
          <Menu onClick={({ key }) => editAndDelete(key, current)}>
jim's avatar
jim committed
224 225 226 227
            <Menu.Item key="edit">编辑</Menu.Item>
            <Menu.Item key="delete">删除</Menu.Item>
          </Menu>
        }
valleykid's avatar
valleykid committed
228
      >
229 230 231 232 233 234
        <a>
          更多 <Icon type="down" />
        </a>
      </Dropdown>
    );

valleykid's avatar
valleykid committed
235 236 237 238 239 240 241
    const getModalContent = () => {
      if (done) {
        return (
          <Result
            type="success"
            title="操作成功"
            description="一系列的信息描述,很短同样也可以带标点。"
jim's avatar
jim committed
242 243 244 245 246
            actions={
              <Button type="primary" onClick={this.handleDone}>
                知道了
              </Button>
            }
valleykid's avatar
valleykid committed
247
            className={styles.formResult}
valleykid's avatar
valleykid committed
248 249 250 251 252 253 254 255 256
          />
        );
      }
      return (
        <Form onSubmit={this.handleSubmit}>
          <FormItem label="任务名称" {...this.formLayout}>
            {getFieldDecorator('title', {
              rules: [{ required: true, message: '请输入任务名称' }],
              initialValue: current.title,
jim's avatar
jim committed
257
            })(<Input placeholder="请输入" />)}
valleykid's avatar
valleykid committed
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
          </FormItem>
          <FormItem label="开始时间" {...this.formLayout}>
            {getFieldDecorator('createdAt', {
              rules: [{ required: true, message: '请选择开始时间' }],
              initialValue: current.createdAt ? moment(current.createdAt) : null,
            })(
              <DatePicker
                showTime
                placeholder="请选择"
                format="YYYY-MM-DD HH:mm:ss"
                style={{ width: '100%' }}
              />
            )}
          </FormItem>
          <FormItem label="任务负责人" {...this.formLayout}>
            {getFieldDecorator('owner', {
              rules: [{ required: true, message: '请选择任务负责人' }],
              initialValue: current.owner,
            })(
              <Select placeholder="请选择">
                <SelectOption value="付晓晓">付晓晓</SelectOption>
                <SelectOption value="周毛毛">周毛毛</SelectOption>
              </Select>
            )}
          </FormItem>
          <FormItem {...this.formLayout} label="产品描述">
            {getFieldDecorator('subDescription', {
              rules: [{ message: '请输入至少五个字符的产品描述!', min: 5 }],
              initialValue: current.subDescription,
jim's avatar
jim committed
287
            })(<TextArea rows={4} placeholder="请输入至少五个字符" />)}
valleykid's avatar
valleykid committed
288 289 290 291
          </FormItem>
        </Form>
      );
    };
292
    return (
293
      <React.Fragment>
陈帅's avatar
陈帅 committed
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
        <GridContent>
          <div className={styles.standardList}>
            <Card bordered={false}>
              <Row>
                <Col sm={8} xs={24}>
                  <Info title="我的待办" value="8个任务" bordered />
                </Col>
                <Col sm={8} xs={24}>
                  <Info title="本周任务平均处理时间" value="32分钟" bordered />
                </Col>
                <Col sm={8} xs={24}>
                  <Info title="本周完成任务数" value="24个任务" />
                </Col>
              </Row>
            </Card>
309

陈帅's avatar
陈帅 committed
310 311 312 313 314 315 316
            <Card
              className={styles.listCard}
              bordered={false}
              title="基本列表"
              style={{ marginTop: 24 }}
              bodyStyle={{ padding: '0 32px 40px 32px' }}
              extra={extraContent}
valleykid's avatar
valleykid committed
317
            >
陈帅's avatar
陈帅 committed
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
              <Button
                type="dashed"
                style={{ width: '100%', marginBottom: 8 }}
                icon="plus"
                onClick={this.showModal}
                ref={component => {
                  /* eslint-disable */
                  this.addBtn = findDOMNode(component) as HTMLButtonElement;
                  /* eslint-enable */
                }}
              >
                添加
              </Button>
              <List
                size="large"
                rowKey="id"
                loading={loading}
                pagination={paginationProps}
                dataSource={list}
                renderItem={item => (
                  <List.Item
                    actions={[
                      <a
                        onClick={e => {
                          e.preventDefault();
                          this.showEditModal(item);
                        }}
                      >
                        编辑
                      </a>,
                      <MoreBtn current={item} />,
                    ]}
                  >
                    <List.Item.Meta
                      avatar={<Avatar src={item.logo} shape="square" size="large" />}
                      title={<a href={item.href}>{item.title}</a>}
                      description={item.subDescription}
                    />
                    <ListContent data={item} />
                  </List.Item>
                )}
              />
            </Card>
          </div>
        </GridContent>

valleykid's avatar
valleykid committed
364
        <Modal
陈帅's avatar
陈帅 committed
365
          title={done ? null : `任务${current ? '编辑' : '添加'}`}
valleykid's avatar
valleykid committed
366
          className={styles.standardListForm}
valleykid's avatar
valleykid committed
367
          width={640}
valleykid's avatar
valleykid committed
368
          bodyStyle={done ? { padding: '72px 0' } : { padding: '28px 0 0' }}
valleykid's avatar
valleykid committed
369 370 371 372 373 374
          destroyOnClose
          visible={visible}
          {...modalFooter}
        >
          {getModalContent()}
        </Modal>
375
      </React.Fragment>
376 377 378
    );
  }
}
lijiehua's avatar
lijiehua committed
379

陈帅's avatar
陈帅 committed
380
export default Form.create<PAGE_NAME_UPPER_CAMEL_CASEProps>()(PAGE_NAME_UPPER_CAMEL_CASE);