Pārlūkot izejas kodu

New page info modal (#876)

* New page - info modal

* Replace `Array.some` to `for`

* Fix py-lint

* Keep original DatePicker

* Remove modal's vertical style

* Remove fake_dataBase
valleykid 8 gadi atpakaļ
vecāks
revīzija
28d3327d60
5 mainītis faili ar 245 papildinājumiem un 29 dzēšanām
  1. 2 1
      .roadhogrc.mock.js
  2. 41 0
      mock/api.js
  3. 11 11
      src/models/list.js
  4. 158 17
      src/routes/List/BasicList.js
  5. 33 0
      src/services/api.js

+ 2 - 1
.roadhogrc.mock.js

@@ -1,6 +1,6 @@
 import mockjs from 'mockjs';
 import { getRule, postRule } from './mock/rule';
-import { getActivities, getNotice, getFakeList } from './mock/api';
+import { getActivities, getNotice, getFakeList, postFakeList } from './mock/api';
 import { getFakeChartData } from './mock/chart';
 import { imgMap } from './mock/utils';
 import { getProfileBasicData } from './mock/profile';
@@ -65,6 +65,7 @@ const proxy = {
     'list|100': [{ name: '@city', 'value|1-100': 150, 'type|0-2': 1 }]
   }),
   'GET /api/fake_list': getFakeList,
+  'POST /api/fake_list': postFakeList,
   'GET /api/fake_chart_data': getFakeChartData,
   'GET /api/profile/basic': getProfileBasicData,
   'GET /api/profile/advanced': getProfileAdvancedData,

+ 41 - 0
mock/api.js

@@ -104,6 +104,8 @@ export function fakeList(count) {
   return list;
 }
 
+let sourceData;
+
 export function getFakeList(req, res, u) {
   let url = u;
   if (!url || Object.prototype.toString.call(url) !== '[object String]') {
@@ -115,6 +117,44 @@ export function getFakeList(req, res, u) {
   const count = (params.count * 1) || 20;
 
   const result = fakeList(count);
+  sourceData = result;
+
+  if (res && res.json) {
+    res.json(result);
+  } else {
+    return result;
+  }
+}
+
+export function postFakeList(req, res) {
+  const { /* url = '', */ body } = req;
+  // const params = getUrlParams(url);
+  const { method, id, ...restParams } = body;
+
+  // const count = (params.count * 1) || 20;
+  let result = sourceData;
+
+  switch (method) {
+    case 'delete':
+      result = result.filter(item => item.id !== id);
+      break;
+    case 'update':
+      result.forEach((item, i) => {
+        if (item.id === id) {
+          result[i] = Object.assign(item, restParams);
+        }
+      });
+      break;
+    case 'post':
+      result.unshift({
+        ...restParams,
+        id: `fake-list-${result.length}`,
+        createdAt: new Date().getTime(),
+      });
+      break;
+    default:
+      break;
+  }
 
   if (res && res.json) {
     res.json(result);
@@ -292,4 +332,5 @@ export default {
   getNotice,
   getActivities,
   getFakeList,
+  postFakeList,
 };

+ 11 - 11
src/models/list.js

@@ -1,4 +1,4 @@
-import { queryFakeList } from '../services/api';
+import { queryFakeList, removeFakeList, addFakeList, updateFakeList } from '../services/api';
 
 export default {
   namespace: 'list',
@@ -15,11 +15,17 @@ export default {
         payload: Array.isArray(response) ? response : [],
       });
     },
-    *appendFetch({ payload }, { call, put }) {
-      const response = yield call(queryFakeList, payload);
+    *submit({ payload }, { call, put }) {
+      let callback;
+      if (payload.id) {
+        callback = Object.keys(payload).length === 1 ? removeFakeList : updateFakeList;
+      } else {
+        callback = addFakeList;
+      }
+      const response = yield call(callback, payload); // post
       yield put({
-        type: 'appendList',
-        payload: Array.isArray(response) ? response : [],
+        type: 'queryList',
+        payload: response,
       });
     },
   },
@@ -31,11 +37,5 @@ export default {
         list: action.payload,
       };
     },
-    appendList(state, action) {
-      return {
-        ...state,
-        list: state.list.concat(action.payload),
-      };
-    },
   },
 };

+ 158 - 17
src/routes/List/BasicList.js

@@ -1,21 +1,28 @@
 import React, { PureComponent } from 'react';
 import moment from 'moment';
 import { connect } from 'dva';
-import { List, Card, Row, Col, Radio, Input, Progress, Button, Icon, Dropdown, Menu, Avatar } from 'antd';
+import { List, Card, Row, Col, Radio, Input, Progress, Button, Icon, Dropdown, Menu, Avatar,
+  Modal, Form, DatePicker, Select } from 'antd';
 
 import PageHeaderLayout from '../../layouts/PageHeaderLayout';
+import Result from '../../components/Result';
 
 import styles from './BasicList.less';
 
+const FormItem = Form.Item;
 const RadioButton = Radio.Button;
 const RadioGroup = Radio.Group;
-const { Search } = Input;
+const SelectOption = Select.Option;
+const { Search, TextArea } = Input;
 
 @connect(({ list, loading }) => ({
   list,
   loading: loading.models.list,
 }))
+@Form.create()
 export default class BasicList extends PureComponent {
+  state = { visible: false, done: false };
+
   componentDidMount() {
     this.props.dispatch({
       type: 'list/fetch',
@@ -24,9 +31,78 @@ export default class BasicList extends PureComponent {
       },
     });
   }
+  formLayout = {
+    labelCol: { span: 7 },
+    wrapperCol: { span: 13 },
+  };
+  showModal = () => {
+    this.setState({
+      visible: true,
+      current: undefined,
+    });
+  }
+  showEditModal = (item) => {
+    this.setState({
+      visible: true,
+      current: item,
+    });
+  }
+  handleDone = () => {
+    this.setState({
+      done: false,
+      visible: false,
+    });
+  }
+  handleCancel = () => {
+    this.setState({
+      visible: false,
+    });
+  }
+  handleSubmit = (e) => {
+    e.preventDefault();
+    const { dispatch, form } = this.props;
+    const id = this.state.current ? this.state.current.id : '';
+
+    form.validateFields((err, fieldsValue) => {
+      if (err) return;
+      this.setState({
+        done: true,
+      });
+      dispatch({
+        type: 'list/submit',
+        payload: { id, ...fieldsValue },
+      });
+    });
+  }
+  deleteItem = (id) => {
+    this.props.dispatch({
+      type: 'list/submit',
+      payload: { id },
+    });
+  }
 
   render() {
     const { list: { list }, loading } = this.props;
+    const { getFieldDecorator } = this.props.form;
+    const { visible, done, current = {} } = this.state;
+
+    const editAndDelete = (key, currentItem) => {
+      if (key === 'edit') this.showEditModal(currentItem);
+      else if (key === 'delete') {
+        Modal.confirm({
+          title: '删除任务',
+          content: '确定删除该任务吗?',
+          okText: '确认',
+          cancelText: '取消',
+          onOk: () => this.deleteItem(currentItem.id),
+        });
+      }
+    };
+
+    const modalFooter = done ?
+      { footer: null, onCancel: this.handleDone }
+      :
+      { okText: '保存', onOk: this.handleSubmit, onCancel: this.handleCancel };
 
     const Info = ({ title, value, bordered }) => (
       <div className={styles.headerInfo}>
@@ -74,25 +150,77 @@ export default class BasicList extends PureComponent {
       </div>
     );
 
-    const menu = (
-      <Menu>
-        <Menu.Item>
-          <a>编辑</a>
-        </Menu.Item>
-        <Menu.Item>
-          <a>删除</a>
-        </Menu.Item>
-      </Menu>
-    );
-
-    const MoreBtn = () => (
-      <Dropdown overlay={menu}>
+    const MoreBtn = props => (
+      <Dropdown overlay={
+        <Menu onClick={({ key }) => editAndDelete(key, props.current)}>
+          <Menu.Item key="edit">编辑</Menu.Item>
+          <Menu.Item key="delete">删除</Menu.Item>
+        </Menu>}
+      >
         <a>
           更多 <Icon type="down" />
         </a>
       </Dropdown>
     );
 
+    const getModalContent = () => {
+      if (done) {
+        return (
+          <Result
+            type="success"
+            title="操作成功"
+            description="一系列的信息描述,很短同样也可以带标点。"
+            actions={<Button type="primary" onClick={this.handleDone}>知道了</Button>}
+            style={{ width: '100%', marginBottom: '24px' }}
+          />
+        );
+      }
+      return (
+        <Form onSubmit={this.handleSubmit}>
+          <FormItem label="任务名称" {...this.formLayout}>
+            {getFieldDecorator('title', {
+              rules: [{ required: true, message: '请输入任务名称' }],
+              initialValue: current.title,
+            })(
+              <Input placeholder="请输入" />
+            )}
+          </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,
+            })(
+              <TextArea rows={4} placeholder="请输入至少五个字符" />
+            )}
+          </FormItem>
+        </Form>
+      );
+    };
+
     return (
       <PageHeaderLayout>
         <div className={styles.standardList}>
@@ -118,7 +246,7 @@ export default class BasicList extends PureComponent {
             bodyStyle={{ padding: '0 32px 40px 32px' }}
             extra={extraContent}
           >
-            <Button type="dashed" style={{ width: '100%', marginBottom: 8 }} icon="plus">
+            <Button type="dashed" style={{ width: '100%', marginBottom: 8 }} icon="plus" onClick={this.showModal}>
               添加
             </Button>
             <List
@@ -129,7 +257,10 @@ export default class BasicList extends PureComponent {
               dataSource={list}
               renderItem={item => (
                 <List.Item
-                  actions={[<a>编辑</a>, <MoreBtn />]}
+                  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" />}
@@ -142,6 +273,16 @@ export default class BasicList extends PureComponent {
             />
           </Card>
         </div>
+        <Modal
+          title={`任务${this.state.current ? '编辑' : '添加'}`}
+          width={640}
+          bodyStyle={{ padding: '32px 0 8px' }}
+          destroyOnClose
+          visible={visible}
+          {...modalFooter}
+        >
+          {getModalContent()}
+        </Modal>
       </PageHeaderLayout>
     );
   }

+ 33 - 0
src/services/api.js

@@ -70,6 +70,39 @@ export async function queryFakeList(params) {
   return request(`/api/fake_list?${stringify(params)}`);
 }
 
+export async function removeFakeList(params) {
+  const { count = 5, ...restParams } = params;
+  return request(`/api/fake_list?count=${count}`, {
+    method: 'POST',
+    body: {
+      ...restParams,
+      method: 'delete',
+    },
+  });
+}
+
+export async function addFakeList(params) {
+  const { count = 5, ...restParams } = params;
+  return request(`/api/fake_list?count=${count}`, {
+    method: 'POST',
+    body: {
+      ...restParams,
+      method: 'post',
+    },
+  });
+}
+
+export async function updateFakeList(params) {
+  const { count = 5, ...restParams } = params;
+  return request(`/api/fake_list?count=${count}`, {
+    method: 'POST',
+    body: {
+      ...restParams,
+      method: 'update',
+    },
+  });
+}
+
 export async function fakeAccountLogin(params) {
   return request('/api/login/account', {
     method: 'POST',