Forráskód Böngészése

1.CMS用户管理创建;
2.终端用户管理完善;

zhanghe 7 éve
szülő
commit
8cab19f8ff

+ 10 - 2
src/common/router.js

@@ -46,7 +46,15 @@ export const getRouterData = (app) => {
       component: dynamicWrapper(app, ['campus', 'merchant/merchant'], () => import('../routes/Campus')),
     },
     '/terminal/user': {
-      component: dynamicWrapper(app, ['terminal'], () => import('../routes/Terminal')),
+      component: dynamicWrapper(app, ['terminal/terminal'], () => import('../routes/Terminal/List')),
+    },
+    '/terminal/user/add': {
+      component: dynamicWrapper(app, ['terminal/detail', 'campus'], () => import('../routes/Terminal/Edit')),
+      name: '添加终端',
+    },
+    '/terminal/user/edit/:id': {
+      component: dynamicWrapper(app, ['terminal/detail', 'campus'], () => import('../routes/Terminal/Edit')),
+      name: '编辑终端',
     },
     '/merchant': {
       component: dynamicWrapper(app, ['merchant/merchant'], () => import('../routes/Merchant/List')),
@@ -169,7 +177,7 @@ export const getRouterData = (app) => {
       component: dynamicWrapper(app, ['login'], () => import('../routes/Login')),
     },
     '/cms/user': {
-      component: dynamicWrapper(app, ['cmsUser'], () => import('../routes/CmsUser')),
+      component: dynamicWrapper(app, ['cmsUser', 'merchant/merchant'], () => import('../routes/CmsUser')),
     },
   };
   // Get name from ./menu.js or just set it in the router data.

+ 7 - 4
src/models/cmsUser.js

@@ -1,8 +1,9 @@
 import { query, create, update, remove } from '../services/cmsUser';
 import modelExtend from 'dva-model-extend';
 import queryString from 'query-string';
+import { message } from 'antd';
 import { pageModel } from './common';
-import config from '../utils/config';
+import { pageSize } from '../utils/config';
 import { checkSearchParams } from '../utils/utils';
 
 export default modelExtend(pageModel, {
@@ -41,7 +42,7 @@ export default modelExtend(pageModel, {
             list: data.list,
             pagination: {
               current: Number(payload.pageNo) || 1,
-              pageSize: Number(payload.pageSize) || config.pageSize,
+              pageSize: Number(payload.pageSize) || pageSize,
               total: data.totalSize,
             }
           }
@@ -52,6 +53,7 @@ export default modelExtend(pageModel, {
     * create ({ payload, callback }, { call, put }) {
       const { data, success } = yield call(create, payload);
       if (success) {
+        message.success('创建成功!');
         if (callback) callback();
       }
     },
@@ -59,18 +61,21 @@ export default modelExtend(pageModel, {
       const { data, success } = yield call(update, payload);
       if (success) {
         yield put({ type: 'hideModal' });
+        message.success('更新成功!');
         if (callback) callback();
       }
     },
     * delete ({ payload, callback }, { call, put }) {
       const { data, success } = yield call(remove, payload);
       if (success) {
+        message.success('禁用成功!');
         if (callback) callback();
       }
     },
     * recover ({ payload, callback }, { call, put }) {
       const { data, success } = yield call(update, payload);
       if (success) {
+        message.success('解禁成功!');
         if (callback) callback();
       }
     },
@@ -80,11 +85,9 @@ export default modelExtend(pageModel, {
     changeLoading(state, { payload }) {
       return { ...state, ...payload };
     },
-
     showModal(state, { payload }) {
       return { ...state, ...payload, modalVisible: true };
     },
-
     hideModal(state) {
       return { ...state, modalVisible: false };
     },

+ 80 - 0
src/models/terminal/detail.js

@@ -0,0 +1,80 @@
+import { create, update } from '../../services/terminal';
+import pathToRegexp from 'path-to-regexp';
+import { message } from 'antd';
+
+export default {
+  namespace: 'terminalDetail',
+
+  state: {
+    filters: {},
+    operType: 'create',
+    currentItem: {},
+    modalShow: false,
+  },
+
+  subscriptions: {
+    setup({ dispatch, history }) {
+      history.listen(({ pathname, state, record }) => {
+        const match = pathToRegexp('/terminal/user/edit/:id').exec(pathname);
+        if (match && record) {
+          dispatch({
+            type: 'saveOuterData',
+            payload: { filters: state, operType: 'update', currentItem: record },
+          });
+        } else if (pathname === '/terminal/user/add') {
+          dispatch({
+            type: 'saveOuterData',
+            payload: { filters: state, operType: 'create', currentItem: {} },
+          });
+        }
+      });
+    }
+  },
+
+  effects: {
+    * create ({ payload, callback }, { call, put }) {
+      const { data, success } = yield call(create, payload);
+      if (success) {
+        message.success('创建成功!');
+        yield put({ type: 'initState' });
+        if (callback) callback();
+      }
+    },
+    * update ({ payload, callback }, { call, put }) {
+      const { data, success } = yield call(update, payload);
+      if (success) {
+        message.success('修改成功!');
+        yield put({ type: 'initState' });
+        if (callback) callback();
+      }
+    },
+  },
+
+  reducers: {
+    saveOuterData(state, action) {
+      return { ...state, ...action.payload };
+    },
+    saveCampus(state, action) {
+      const { code, name, id } = action.payload;
+      return {
+        ...state,
+        modalShow: false,
+        currentItem: {
+          ...state.currentItem,
+          campusId: id,
+          campusName: name,
+          campusCode: code,
+        },
+      };
+    },
+    showModal(state) {
+      return { ...state, modalShow: true };
+    },
+    hideModal(state) {
+      return { ...state, modalShow: false };
+    },
+    initState(state) {
+      return { ...state, currentItem: {} };
+    }
+  }
+}

+ 13 - 32
src/models/terminal.js

@@ -1,20 +1,15 @@
-import { query, create, update, remove } from '../services/terminal';
+import { query, create, update, remove } from '../../services/terminal';
 import modelExtend from 'dva-model-extend';
+import { message } from 'antd';
 import queryString from 'query-string';
-import { pageModel } from './common';
-import config from '../utils/config';
-import { checkSearchParams } from '../utils/utils';
+import { pageModel } from '../common';
+import config from '../../utils/config';
+import { checkSearchParams } from '../../utils/utils';
 
 export default modelExtend(pageModel, {
   namespace: 'terminal',
 
-  state: {
-    currentItem: {},
-    itemLoading: false,
-    listLoading: false,
-    modalVisible: false,
-    modalType: 'create',
-  },
+  state: { listLoading: false },
 
   subscriptions: {
     setup({ dispatch, history }) {
@@ -49,24 +44,18 @@ export default modelExtend(pageModel, {
       }
       yield put({ type: 'changeLoading', payload: { listLoading: false }});
     },
-    * create ({ payload }, { call, put }) {
-      const { data, success } = yield call(create, payload);
+    * delete ({ payload, callback }, { call, put }) {
+      const { data, success } = yield call(remove, payload);
       if (success) {
-        yield put({ type: 'hideModal' });
-        yield put({ type: 'query' }, payload: { pageNo: 1, pageSize: config.pageSize });
+        message.success('禁用成功!');
+        if (callback) callback();
       }
     },
-    * update ({ payload }, { call, put }) {
+    * recover ({ payload, callback }, { call, put }) {
       const { data, success } = yield call(update, payload);
       if (success) {
-        yield put({ type: 'hideModal' });
-        yield put({ type: 'query', payload: { pageNo: 1, pageSize: config.pageSize } });
-      }
-    },
-    * delete ({ payload }, { call, put }) {
-      const { data, success } = yield call(remove, { id: payload });
-      if (success) {
-        yield put({ type: 'query', payload: { pageNo: 1, pageSize: config.pageSize } });
+        message.success('解禁成功!');
+        if (callback) callback();
       }
     }
   },
@@ -75,13 +64,5 @@ export default modelExtend(pageModel, {
     changeLoading(state, { payload }) {
       return { ...state, ...payload };
     },
-
-    showModal(state, { payload }) {
-      return { ...state, ...payload, modalVisible: true };
-    },
-
-    hideModal(state) {
-      return { ...state, modalVisible: false };
-    },
   }
 })

+ 23 - 11
src/routes/CmsUser/index.js

@@ -4,12 +4,15 @@ import queryString from 'query-string';
 import { connect } from 'dva';
 import { routerRedux } from 'dva/router';
 import { Card } from 'antd';
-import TableList from './table';
-import ModalForm from './modal';
-import Search from './search';
+import CMSUserTableList from './table';
+import CMSUserModalForm from './modal';
+import CMSUserSearch from './search';
 import PageHeaderLayout from '../../layouts/PageHeaderLayout';
 
-@connect(state => ({ cmsUser: state.cmsUser }))
+@connect(state => ({
+  cmsUser: state.cmsUser,
+  merchant: state.merchant,
+}))
 export default class CMSUser extends Component {
   static propTypes = {
     cmsUser: PropTypes.object,
@@ -17,17 +20,25 @@ export default class CMSUser extends Component {
     dispatch: PropTypes.func,
   };
 
+  componentDidMount() {
+    this.props.dispatch({
+      type: 'merchant/query',
+      payload: {
+        pageNo: 1,
+        pageSize: 1000,
+      },
+    });
+  }
+
   render() {
-    const { location, dispatch, cmsUser } = this.props;
+    const { location, dispatch, cmsUser, merchant } = this.props;
 
     location.query = queryString.parse(location.search);
     const { query, pathname } = location;
     const { field, keyword, ...filters } = query;
     const { list, listLoading, pagination, currentItem, itemLoading, modalVisible, modalType } = cmsUser;
 
-    // 把携带的参数中空值项删除
     Object.keys(filters).map(key => { filters[key] ? null : delete filters[key] });
-    // 如果搜索内容不为空则添加进filters中
     if (field && keyword) {
       filters.field = field;
       filters.keyword = keyword;
@@ -36,8 +47,9 @@ export default class CMSUser extends Component {
     const modalProps = {
       item: modalType === 'create' ? {} : currentItem,
       visible: modalVisible,
-      width: 550,
+      merchantList: merchant.list,
       maskClosable: false,
+      modalType,
       title: `${modalType === 'create' ? '添加CMS用户' : '编辑CMS用户'}`,
       wrapClassName: 'vertical-center-modal',
       onOk (data) {
@@ -148,9 +160,9 @@ export default class CMSUser extends Component {
     return (
       <PageHeaderLayout>
         <Card>
-          <Search { ...searchProps } />
-          <TableList { ...listProps } />
-          {modalVisible && <ModalForm { ...modalProps } />}
+          <CMSUserSearch { ...searchProps } />
+          <CMSUserTableList { ...listProps } />
+          {modalVisible && <CMSUserModalForm { ...modalProps } />}
         </Card>
       </PageHeaderLayout>
     );

+ 112 - 109
src/routes/CmsUser/modal.js

@@ -1,120 +1,123 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { Form, Cascader, Switch, Radio, Input, Modal, Icon } from 'antd';
+import React, { Component } from 'react';
+import { Form, Select, Switch, Radio, Input, Modal, Icon } from 'antd';
 import { Codes, domains } from '../../utils/config';
 
-const RadioGroup = Radio.Group;
-const FormItem = Form.Item
+@Form.create()
+export default class CMSUserModalForm extends Component {
+  handleModalOk = () => {
+    const { form, onOk, modalType, item } = this.props;
+    const { validateFields, getFieldsValue } = form;
 
-const formItemLayout = {
-  labelCol: {
-    span: 6,
-  },
-  wrapperCol: {
-    span: 15,
-  },
-}
-
-const ModalForm = ({
-  item = {},
-  onOk,
-  form: {
-    getFieldDecorator,
-    getFieldsValue,
-    validateFields,
-  },
-  ...modalProps,
-}) => {
-  const handleOk = () => {
     validateFields((errors) => {
       if (errors) return;
-      const data = {
-        ...getFieldsValue(),
-      };
-      item.id ? data.id = item.id : null;
+      const data = { ...getFieldsValue() };
+
+      data.status ? data.status = Codes.CODE_NORMAL : data.status = Codes.CODE_DELETE;
+
+      if (modalType === 'update') {
+        data.id = item.id;
+      }
+
       onOk(data);
-    })
+    });
   }
 
-  const modalOpts = {
-    ...modalProps,
-    onOk: handleOk,
-  }
+  render() {
+    const { item, merchantList, onOk, form, modalType, ...modalProps } = this.props;
+    const { getFieldDecorator } = form;
 
-  return (
-    <Modal {...modalOpts}>
-      <Form layout="horizontal">
-        <FormItem label="所属平台:" {...formItemLayout}>
-          {getFieldDecorator('domain', {
-            rules: [{ required: true, type: 'number', message: '请选择平台!' }],
-            initialValue: item.domain || Codes.CODE_LJ,
-          })(
-            <RadioGroup>
-            {Object.keys(domains).map(key => <Radio value={Number(key)} key={key}>{domains[Number(key)]}</Radio>)}
-            </RadioGroup>
-          )}
-        </FormItem>
-        <FormItem label="用户名称:" hasFeedback {...formItemLayout}>
-          {getFieldDecorator('name', {
-            rules: [{ required: true, type: 'string', message: '用户名为必填项!' }],
-            initialValue: item.name,
-          })(<Input />)}
-        </FormItem>
-        <FormItem label="用户昵称:" hasFeedback {...formItemLayout}>
-          {getFieldDecorator('nickname', {
-            initialValue: item.nickname,
-          })(<Input />)}
-        </FormItem>
-        <FormItem label="用户性别:" {...formItemLayout}>
-          {getFieldDecorator('gender', {
-            initialValue: item.gender || 0,
-          })(
-            <RadioGroup>
-              <Radio value={0} key={0}>男</Radio>
-              <Radio value={1} key={1}>女</Radio>
-            </RadioGroup>
-          )}
-        </FormItem>
-        <FormItem label="出生日期:" hasFeedback {...formItemLayout}>
-          {getFieldDecorator('birthday', {
-            initialValue: item.birthday,
-          })(<Input />)}
-        </FormItem>
-        <FormItem label="电话:" hasFeedback {...formItemLayout}>
-          {getFieldDecorator('mobile', {
-            initialValue: item.mobile,
-          })(<Input />)}
-        </FormItem>
-        <FormItem label="邮箱:" hasFeedback {...formItemLayout}>
-          {getFieldDecorator('mail', {
-            initialValue: item.mail,
-          })(<Input />)}
-        </FormItem>
-        <FormItem label="QQ:" hasFeedback {...formItemLayout}>
-          {getFieldDecorator('qq', {
-            initialValue: item.qq,
-          })(<Input />)}
-        </FormItem>
-        <FormItem label="微信:" hasFeedback {...formItemLayout}>
-          {getFieldDecorator('weChat', {
-            initialValue: item.weChat,
-          })(<Input />)}
-        </FormItem>
-        <FormItem label="账号状态:" {...formItemLayout}>
-          {getFieldDecorator('status', {
-            valuePropsName: 'checked',
-        })(<Switch defaultChecked={item.status === Codes.CODE_NORMAL ? true : false} checkedChildren="使用中" unCheckedChildren="禁用中" />)}
-        </FormItem>
-      </Form>
-    </Modal>
-  )
-}
+    const modalOpts = { ...modalProps, onOk: this.handleModalOk };
+    const formItemLayout = {
+      labelCol: { span: 6 },
+      wrapperCol: { span: 15 },
+    };
 
-ModalForm.propTypes = {
-  item: PropTypes.object,
-  form: PropTypes.object,
-  type: PropTypes.string,
-  onOk: PropTypes.func,
+    return (
+      <Modal {...modalOpts}>
+        <Form layout="horizontal">
+          <Form.Item label="选择厂商" hasFeedback {...formItemLayout}>
+            {getFieldDecorator('merchantId', {
+              rules: [{ required: true, type: 'string', message: "该项为必选项!" }],
+              initialValue: item.merchantId,
+            })(
+              <Select
+                showSearch
+                allowClear
+                placeholder="请选择"
+                optionFilterProp="children"
+                filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+              >
+                {merchantList.map(selItem => <Select.Option value={selItem.id} key={selItem.id}>{`${selItem.code}/${selItem.name}`}</Select.Option>)}
+              </Select>
+            )}
+          </Form.Item>
+          <Form.Item label="用户名称:" hasFeedback {...formItemLayout}>
+            {getFieldDecorator('name', {
+              rules: [{ required: true, type: 'string', message: '用户名为必填项!' }],
+              initialValue: item.name,
+            })(<Input placeholder="请输入" />)}
+          </Form.Item>
+          {modalType === 'create' ?
+            <Form.Item label="用户密码:" hasFeedback {...formItemLayout}>
+              {getFieldDecorator('password', {
+                rules: [{ required: true, type: 'string', message: '密码为必填项!' }],
+                initialValue: item.password,
+              })(<Input placeholder="请输入" />)}
+            </Form.Item>
+            :
+            <Form.Item label="用户密码:" hasFeedback {...formItemLayout}>
+              {getFieldDecorator('password', {
+                initialValue: item.password,
+              })(<Input placeholder="修改密码时填写"/>)}
+            </Form.Item>
+          }
+          <Form.Item label="用户昵称:" hasFeedback {...formItemLayout}>
+            {getFieldDecorator('nickName', {
+              initialValue: item.nickName,
+            })(<Input />)}
+          </Form.Item>
+          <Form.Item label="用户性别:" {...formItemLayout}>
+            {getFieldDecorator('gender', {
+              initialValue: item.gender || 'MALE',
+            })(
+              <Radio.Group>
+                <Radio value={'MALE'} key={'MALE'}>男</Radio>
+                <Radio value={'FEMALE'} key={'FEMALE'}>女</Radio>
+              </Radio.Group>
+            )}
+          </Form.Item>
+          <Form.Item label="出生日期:" hasFeedback {...formItemLayout}>
+            {getFieldDecorator('birthday', {
+              initialValue: item.birthday,
+            })(<Input />)}
+          </Form.Item>
+          <Form.Item label="电话:" hasFeedback {...formItemLayout}>
+            {getFieldDecorator('mobile', {
+              initialValue: item.mobile,
+            })(<Input />)}
+          </Form.Item>
+          <Form.Item label="邮箱:" hasFeedback {...formItemLayout}>
+            {getFieldDecorator('mail', {
+              initialValue: item.mail,
+            })(<Input />)}
+          </Form.Item>
+          <Form.Item label="QQ:" hasFeedback {...formItemLayout}>
+            {getFieldDecorator('qq', {
+              initialValue: item.qq,
+            })(<Input />)}
+          </Form.Item>
+          <Form.Item label="微信:" hasFeedback {...formItemLayout}>
+            {getFieldDecorator('weChat', {
+              initialValue: item.weChat,
+            })(<Input />)}
+          </Form.Item>
+          <Form.Item label="账号状态:" {...formItemLayout}>
+            {getFieldDecorator('status', {
+              valuePropsName: 'checked',
+          })(<Switch defaultChecked={item.status === Codes.CODE_NORMAL ? true : false} checkedChildren="使用中" unCheckedChildren="禁用中" />)}
+          </Form.Item>
+        </Form>
+      </Modal>
+    );
+  }
 }
-
-export default Form.create()(ModalForm);

+ 37 - 43
src/routes/CmsUser/search.js

@@ -1,49 +1,43 @@
-import react, { PureComponent } from 'react';
+import react, { Component } from 'react';
 import PropTypes from 'prop-types';
 import { Button, Form, Row, Col, Icon } from 'antd';
 import DataSearch from '../../components/DataSearch';
 
-const Search = ({
-  field,
-  keyword,
-  onSearch,
-  onAdd
-}) => {
-  const searchGroupProps = {
-    field,
-    keyword,
-    size: 'default',
-    select: true,
-    selectOptions: [{
-      value: 'name', name: '用户名称',
-    },{
-      value: 'nickname', name: '用户昵称',
-    }],
-    selectProps: {
-      defaultValue: field || 'name',
-    },
-    onSearch: (value) => {
-      onSearch(value);
-    },
-  }
-  return (
-    <Row gutter={24}>
-      <Col lg={10} md={12} sm={16} xs={24} style={{ marginBottom: 16 }}>
-        <DataSearch { ...searchGroupProps } />
-      </Col>
-      <Col lg={{ offset: 7, span: 7 }} md={12} sm={8} xs={24} style={{ marginBottom: 16, textAlign: 'right' }}>
-        <Button type="primary" onClick={onAdd}><Icon type="plus-circle" />创建用户</Button>
-      </Col>
-    </Row>
-  )
-}
+export default class CMSUserSearch extends Component {
+  static propTypes = {
+    onSearch: PropTypes.func,
+    onAdd: PropTypes.func,
+    field: PropTypes.string,
+    keyword: PropTypes.string,
+  };
 
-Search.propTypes = {
-  form: PropTypes.object.isRequired,
-  onSearch: PropTypes.func,
-  onAdd: PropTypes.func,
-  field: PropTypes.string,
-  keyword: PropTypes.string,
-}
+  render() {
+    const { field, keyword, onSearch, onAdd } = this.props;
+    const searchGroupProps = {
+      field,
+      keyword,
+      size: 'default',
+      select: true,
+      selectOptions: [{
+        value: 'name', name: '用户名称', type: 'input',
+      }],
+      selectProps: {
+        defaultValue: field || 'name',
+      },
+      onSearch: (value) => {
+        onSearch(value);
+      },
+    };
 
-export default Form.create()(Search);
+    return (
+      <Row gutter={24}>
+        <Col lg={10} md={12} sm={16} xs={24} style={{ marginBottom: 16 }}>
+          <DataSearch { ...searchGroupProps } />
+        </Col>
+        <Col lg={{ offset: 7, span: 7 }} md={12} sm={8} xs={24} style={{ marginBottom: 16, textAlign: 'right' }}>
+          <Button type="primary" onClick={onAdd}><Icon type="plus-circle" />添加用户</Button>
+        </Col>
+      </Row>
+    );
+  }
+}

+ 96 - 94
src/routes/CmsUser/table.js

@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { Component } from 'react';
 import PropTypes from 'prop-types';
 import moment from 'moment';
 import classnames from 'classnames';
@@ -8,110 +8,112 @@ import AnimTableBody from '../../components/Animation/AnimTableBody';
 import { Codes, statuses, domains } from '../../utils/config';
 import styles from './table.less';
 
-const confirm = Modal.confirm;
+export default class CMSUserTableList extends Component {
 
-const colorList = ['#f56a00', '#7265e6', '#ffbf00', '#00a2ae'];
-
-const TableList = ({ onDeleteItem, onEditItem, onRecoverItem, location, curStatus, pagination, ...tableProps }) => {
-  // 从url中提取查询参数
-  location.query = queryString.parse(location.search);
-  const handleOperateItem = (record) => {
-    confirm({
+  handleOperateItem = (record) => {
+    Modal.confirm({
       title: `您确定要${record.status === Codes.CODE_NORMAL ? '禁用' : '解禁'}该账户?`,
       onOk () {
         if (record.status === Codes.CODE_NORMAL) {
           onDeleteItem({id: record.id});
-        } else if (record.status === Codes.CODE_DELETE) {
+        } else {
           onRecoverItem({ id: record.id, status: Codes.CODE_NORMAL });
         }
       },
     });
   }
-  const columns = [{
-    title: '头像',
-    dataIndex: 'avatar',
-    key: 'avatar',
-    render: (text, record) => (
-      <Avatar
-        src={text}
-        style={{ backgroundColor: colorList[Math.floor(Math.random()*(colorList.length -1))], verticalAlign: 'middle' }}
-      >
-        {record.nickname}
-      </Avatar>
-    )
-  },{
-    title: '用户名称',
-    dataIndex: 'name',
-    key: 'name',
-  },{
-    title: '用户昵称',
-    dataIndex: 'nickname',
-    key: 'nickname',
-  },{
-    title: '电话',
-    dataIndex: 'mobile',
-    key: 'mobile',
-  },{
-    title: '类型',
-    dataIndex: 'domain',
-    key: 'domain',
-    render: (text, record) => domains[record.domain]
-  },{
-    title: '状态',
-    dataIndex: 'status',
-    key: 'status',
-    render: (text, record) => {
-      const statusMap = {[Codes.CODE_NORMAL]: 'success', [Codes.CODE_DELETE]: 'error'};
-      return (<Badge status={statusMap[record.status]} text={statuses[record.status]} />);
-    },
-    filters: Object.keys(statuses).map(key => ({ text: statuses[key], value: key })),
-    filterMultiple: false,
-    filteredValue: curStatus,
-  },{
-    title: '添加时间',
-    dataIndex: 'gmtCreated',
-    key: 'gmtCreated',
-    render: (text, record) => (
-      <div>{moment(text).format('YYYY-MM-DD')}</div>
-    )
-  },{
-    title: '操作',
-    dataIndex: 'operation',
-    key: 'operation',
-    render: (text, record) => (
-      <div>
-        <a onClick={() => onEditItem(record)}>编辑</a>
-        <span className={styles.splitLine} />
-        <a onClick={() => handleOperateItem(record)}>{record.status === Codes.CODE_NORMAL ? '禁用' : '解禁'}</a>
-      </div>
-    )
-  }];
 
-  tableProps.pagination = !!pagination && { ...pagination, showSizeChanger: true, showQuickJumper: true, showTotal: total => `共 ${total} 条`};
-  const getBodyWrapperProps = {
-    page: location.query.page,
-    current: tableProps.pagination.current,
-  };
-  const getBodyWrapper = (body) => (<AnimTableBody {...getBodyWrapperProps} body={body} />);
+  render() {
+    const {
+      onDeleteItem,
+      onEditItem,
+      onRecoverItem,
+      location,
+      curStatus,
+      pagination,
+      ...tableProps
+    } = this.props;
 
-  return (
-    <Table
-      simple
-      bordered
-      { ...tableProps }
-      columns={columns}
-      className={classnames({ [styles.table]: true, [styles.motion]: true })}
-      rowKey={record => record.id}
-      getBodyWrapper={getBodyWrapper}
-    />
-  );
-}
+    const colorList = ['#f56a00', '#7265e6', '#ffbf00', '#00a2ae'];
 
-TableList.propTypes = {
-  location: PropTypes.object,
-  onChange: PropTypes.func.isRequired,
-  onDeleteItem: PropTypes.func.isRequired,
-  onEditItem: PropTypes.func.isRequired,
-}
+    const columns = [{
+      title: '头像',
+      dataIndex: 'avatar',
+      key: 'avatar',
+      render: (text, record) => (
+        <Avatar
+          src={text}
+          style={{ backgroundColor: colorList[Math.floor(Math.random()*(colorList.length -1))], verticalAlign: 'middle' }}
+        >
+          {record.nickname}
+        </Avatar>
+      )
+    },{
+      title: '用户名称',
+      dataIndex: 'name',
+      key: 'name',
+    },{
+      title: '用户昵称',
+      dataIndex: 'nickname',
+      key: 'nickname',
+    },{
+      title: '厂商名称',
+      dataIndex: 'merchantId',
+      key: 'merchantId',
+      render: (text, record) => record.merchantName,
+    },{
+      title: '厂商类型',
+      dataIndex: 'domain',
+      key: 'domain',
+      render: (text, record) => domains[record.domain]
+    },{
+      title: '状态',
+      dataIndex: 'status',
+      key: 'status',
+      render: (text, record) => {
+        const statusMap = {[Codes.CODE_NORMAL]: 'success', [Codes.CODE_DELETE]: 'error'};
+        return (<Badge status={statusMap[record.status]} text={statuses[record.status]} />);
+      },
+      filters: Object.keys(statuses).map(key => ({ text: statuses[key], value: key })),
+      filterMultiple: false,
+      filteredValue: curStatus,
+    },{
+      title: '修改时间',
+      dataIndex: 'gmtModified',
+      key: 'gmtModified',
+      render: (text, record) => (
+        <div>{moment(text).format('YYYY-MM-DD HH:mm:ss')}</div>
+      ),
+    },{
+      title: '操作',
+      dataIndex: 'operation',
+      key: 'operation',
+      render: (text, record) => (
+        <div>
+          <a onClick={() => onEditItem(record)}>编辑</a>
+          <span className={styles.splitLine} />
+          <a onClick={() => this.handleOperateItem(record)}>{record.status === Codes.CODE_NORMAL ? '禁用' : '解禁'}</a>
+        </div>
+      )
+    }];
 
-export default TableList;
+    tableProps.pagination = !!pagination && { ...pagination, showSizeChanger: true, showQuickJumper: true, showTotal: total => `共 ${total} 条`};
+    const getBodyWrapperProps = {
+      page: tableProps.pagination.page,
+      current: tableProps.pagination.current,
+    };
+    const getBodyWrapper = (body) => (<AnimTableBody {...getBodyWrapperProps} body={body} />);
+
+    return (
+      <Table
+        simple
+        bordered
+        { ...tableProps }
+        columns={columns}
+        className={classnames({ [styles.table]: true, [styles.motion]: true })}
+        rowKey={record => record.id}
+        getBodyWrapper={getBodyWrapper}
+      />
+    );
+  }
+}

+ 5 - 5
src/routes/CmsUser/table.less

@@ -14,19 +14,19 @@
       .ant-table-tbody > tr > td,
       .ant-table-thead > tr > th {
         &:nth-child(1) {
-          width: 10%;
+          width: 8%;
         }
 
         &:nth-child(2) {
-          width: 16%;
+          width: 14%;
         }
 
         &:nth-child(3) {
-          width: 14%;
+          width: 13%;
         }
 
         &:nth-child(4) {
-          width: 15%;
+          width: 13%;
         }
 
         &:nth-child(5) {
@@ -38,7 +38,7 @@
         }
 
         &:nth-child(7) {
-          width: 12%;
+          width: 19%;
         }
 
         &:nth-child(8) {

+ 2 - 3
src/routes/Merchant/Edit/baseInfo.js

@@ -64,12 +64,11 @@ export default class BaseInfoCard extends PureComponent {
             </Form.Item>
             <Form.Item label="厂商类型" {...formItemLayout}>
               {getFieldDecorator('domain',{
-                initialValue: item.domain || 2010,
+                initialValue: item.domain || Codes.CODE_PJ,
               })(
                 <Radio.Group>
                   {Object.keys(domains).map(key =>
-                    Number(key) === Codes.CODE_LJ ? null :
-                      <Radio value={Number(key)} key={`domain-${key}`}>{domains[key]}</Radio>
+                    <Radio value={Number(key)} key={`domain-${key}`}>{domains[Number(key)]}</Radio>
                   )}
                 </Radio.Group>
               )}

+ 72 - 0
src/routes/Terminal/Edit/campus.js

@@ -0,0 +1,72 @@
+import React, { PureComponent } from 'react';
+import PropTypes from 'prop-types';
+import SelectModal from '../../../components/SelectModal';
+import { Codes } from '../../../utils/config';
+
+export default class CampusSelectModal extends PureComponent {
+
+  render() {
+    const {
+      modalVisible,
+      onCancel,
+      onOk,
+      onSearch,
+      ...fsTableOpts
+    } = this.props;
+
+    const modalProps = {
+      title: '选择校区',
+      maskClosable: false,
+      visible: modalVisible,
+      onCancel,
+      onOk,
+    };
+
+    const searchProps = {
+      searchField: 'name',
+      searchKeyWord: '',
+      searchSize: 'default',
+      searchSelect: true,
+      searchSelectOptions: [{
+        value: 'name', name: '校区名称', mode: 'input',
+      },{
+        value: 'code', name: '校区编号', mode: 'input',
+      }],
+      searchSelectProps: {
+        defaultValue: 'name',
+      },
+      onSearch: (value) => {
+        onSearch(value);
+      },
+    };
+
+    const fsTableProps = {
+      fsTableColumns: [{
+        title: '校区编号',
+        dataIndex: 'code',
+        key: 'code',
+        width: '30%',
+      },{
+        title: '校区名称',
+        dataIndex: 'name',
+        key: 'name',
+        width: '35%',
+      },{
+        title: '渠道名称',
+        dataIndex: 'merchantName',
+        key: 'merchantName',
+        width: '20%',
+      }],
+      ...fsTableOpts,
+    }
+
+    return (
+      <SelectModal
+        mode="single"
+        { ...searchProps }
+        { ...fsTableProps }
+        { ...modalProps }
+      />
+    );
+  }
+}

+ 178 - 0
src/routes/Terminal/Edit/index.js

@@ -0,0 +1,178 @@
+import React, { Component } from 'react';
+import { Card, Form, Input, Select, Switch, Tooltip, Button, message } from 'antd';
+import { routerRedux } from 'dva/router';
+import { connect } from 'dva';
+import queryString from 'query-string';
+import PageHeaderLayout from '../../../layouts/PageHeaderLayout';
+import CampusSelectModal from './campus';
+import { Codes, pageSize } from '../../../utils/config';
+
+@Form.create()
+@connect(state => ({
+  terminalDetail: state.terminalDetail,
+  campus: state.campus,
+}))
+export default class TerminalProfile extends Component {
+
+  handleCampusSelectClick = () => {
+    this.props.dispatch({ type: 'terminalDetail/showModal' });
+    this.props.dispatch({
+      type: 'campus/query',
+      payload: { pageNo: 1, pageSize },
+    });
+  }
+
+  handleCampusModalOk = (data) => {
+    this.props.dispatch({
+      type: 'terminalDetail/saveCampus',
+      payload: data,
+    });
+  }
+
+  handleCampusModalCancel = () => {
+    this.props.dispatch({ type: 'terminalDetail/hideModal' });
+  }
+
+  handleCampusModalSearch = () => {
+
+  }
+
+  handleCampusModalTableChange = () => {
+
+  }
+
+  handlePageCancel = () => {
+    const { dispatch, terminalDetail } = this.props;
+    const { filters } = terminalDetail;
+    dispatch(routerRedux.push({
+      pathname: '/terminal/user',
+      search: queryString.stringify(filters),
+    }));
+  }
+
+  handlePageSubmit = (e) => {
+    e.preventDefault();
+
+    const { dispatch, form, terminalDetail } = this.props;
+    const { validateFields, getFieldsValue } = form;
+    const { currentItem, operType, filters } = terminalDetail;
+    const { campusId, id, status } = currentItem;
+
+    validateFields((errors) => {
+      if (errors) return;
+      if (!campusId) {
+        message.error('请选择校区!');
+        return;
+      }
+
+      const data = { ...getFieldsValue(), campusId };
+      if (operType === 'create') {
+        data.status = Codes.CODE_NORMAL;
+      } else if (operType === 'update') {
+        data.status = status;
+        data.id = id;
+      }
+
+      dispatch({
+        type: `terminalDetail/${operType}`,
+        payload: data,
+        callback: () => {
+          dispatch(routerRedux.push({
+            pathname: '/terminal/user',
+            search: queryString.stringify(filters),
+          }));
+        },
+      });
+    });
+  }
+
+  render() {
+    const { form, terminalDetail, campus } = this.props;
+    const { currentItem, modalShow, operType } = terminalDetail;
+    const { name, password, status, campusId, campusName, campusCode } = currentItem;
+    const { getFieldDecorator } = form;
+
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 7 },
+        md: { span: 8 },
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 12 },
+        md: { span: 10 },
+      },
+    };
+
+    const submitFormLayout = {
+      wrapperCol: {
+        xs: { span: 24, offset: 0 },
+        sm: { span: 10, offset: 8 },
+      },
+    };
+
+    return (
+      <PageHeaderLayout>
+        <Card title="终端用户">
+          <Form layout="horizontal" onSubmit={this.handlePageSubmit}>
+            <Form.Item hasFeedback label="所属校区" {...formItemLayout}>
+              <Tooltip placement="top" title="点击选择校区">
+                <Button disabled={operType === "update" ? true: false} style={{ marginRight: 20 }} type="primary" size="small" icon="select" onClick={this.handleCampusSelectClick}>选择</Button>
+              </Tooltip>
+              {campusName && <strong>{`${campusName}`}</strong>}
+            </Form.Item>
+            <Form.Item label="终端名称:" hasFeedback {...formItemLayout}>
+              {getFieldDecorator('name', {
+                initialValue: name,
+              })(<Input placeholder="请输入(例: 教室三/教室四...)"/>)}
+            </Form.Item>
+            {operType === 'create' ?
+              <Form.Item label="终端密码:" hasFeedback {...formItemLayout}>
+                {getFieldDecorator('password', {
+                  rules: [{ required: true, type: 'string', message: '密码为必填项!' }],
+                  initialValue: password,
+                })(<Input placeholder="请输入" />)}
+              </Form.Item>
+              :
+              <Form.Item label="终端密码:" hasFeedback {...formItemLayout}>
+                {getFieldDecorator('password', {
+                  initialValue: password,
+                })(<Input placeholder="修改密码时填写" />)}
+              </Form.Item>
+            }
+            <Form.Item label="账号状态:" {...formItemLayout}>
+              {getFieldDecorator('status', {
+                valuePropsName: 'checked',
+            })(
+              <Switch
+                defaultChecked={status === Codes.CODE_NORMAL ? true : false}
+                checkedChildren="使用中"
+                unCheckedChildren="禁用中"
+              />
+            )}
+            </Form.Item>
+            <Form.Item {...submitFormLayout} style={{ marginTop: 32 }}>
+              <Button onClick={this.handlePageCancel}>取消</Button>
+              <Button type="primary" style={{ marginLeft: 35 }} htmlType="submit">提交</Button>
+            </Form.Item>
+          </Form>
+          {/*校区模态选择框*/}
+          <CampusSelectModal
+            rowKeyName="id"
+            modalVisible={modalShow}
+            style={{ top: 20 }}
+            width={600}
+            onOk={this.handleCampusModalOk}
+            onCancel={this.handleCampusModalCancel}
+            onSearch={this.handleCampusModalSearch}
+            fsTableDataSource={campus.list || []}
+            fsTableLoading={campus.listLoading}
+            fsTablePagination={campus.pagination}
+            fsTableOnChange={this.handleCampusModalTableChange}
+          />
+        </Card>
+      </PageHeaderLayout>
+    );
+  }
+}

+ 128 - 0
src/routes/Terminal/List/index.js

@@ -0,0 +1,128 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import queryString from 'query-string';
+import { connect } from 'dva';
+import { routerRedux } from 'dva/router';
+import { Card } from 'antd';
+import TerminalTableList from './table';
+import TerminalSearch from './search';
+import PageHeaderLayout from '../../../layouts/PageHeaderLayout';
+
+@connect(state => ({ terminal: state.terminal }))
+export default class TerminalList extends Component {
+  static propTypes = {
+    Terminal: PropTypes.object,
+    location: PropTypes.object,
+    dispatch: PropTypes.func,
+  };
+
+  render() {
+    const { dispatch, location, terminal } = this.props;
+
+    location.query = queryString.parse(location.search);
+    const { query, pathname } = location;
+    const { field, keyword, ...filters } = query;
+
+    Object.keys(filters).map(key => { filters[key] ? null : delete filters[key] });
+    if (field && keyword) {
+      filters.field = field;
+      filters.keyword = keyword;
+    }
+
+    const { list, listLoading, pagination } = terminal;
+
+    const searchProps = {
+      field,
+      keyword,
+      onSearch: (payload) => {
+        if (!payload.keyword.length) {
+          delete payload.field;
+          delete payload.keyword;
+        }
+        dispatch(routerRedux.push({
+          pathname,
+          search: queryString.stringify({
+            ...payload
+          })
+        }));
+      },
+      onAdd: () => {
+        dispatch(routerRedux.push({
+          pathname: '/terminal/user/add',
+          state: filters,
+        }));
+      }
+    };
+
+    const listProps = {
+      curStatus: filters.status,
+      dataSource: list,
+      loading: listLoading,
+      pagination,
+      location,
+      onChange: (pagination, filterArgs) => {
+        const getValue = obj => Object.keys(obj).map(key => obj[key]).join(',');
+        const tableFilters = Object.keys(filterArgs).reduce((obj, key) => {
+          const newObj = { ...obj };
+          newObj[key] = getValue(filterArgs[key]);
+          return newObj;
+        }, {});
+
+        const data = { ...filters, ...tableFilters };
+        Object.keys(data).map(key => data[key] ? null : delete data[key]);
+        dispatch(routerRedux.push({
+          pathname,
+          search: queryString.stringify({
+            ...data,
+            pageNo: pagination.current,
+            pageSize: pagination.pageSize,
+          }),
+        }));
+      },
+      onEditItem: (item) => {
+        dispatch(routerRedux.push({
+          pathname: `/terminal/user/edit/${item.id}`,
+          state: filters,
+          record: item,
+        }));
+      },
+      onDeleteItem: (id) => {
+        dispatch({
+          type: 'terminal/delete',
+          payload: id,
+          callback: () => {
+            dispatch(
+              routerRedux.push({
+                pathname,
+                search: queryString.stringify(filters),
+              })
+            );
+          }
+        });
+      },
+      onRecoverItem: (payload) => {
+        dispatch({
+          type: 'terminal/recover',
+          payload,
+          callback: () => {
+            dispatch(
+              routerRedux.push({
+                pathname,
+                search: queryString.stringify(filters),
+              })
+            );
+          }
+        });
+      }
+    };
+
+    return (
+      <PageHeaderLayout>
+        <Card>
+          <TerminalSearch { ...searchProps } />
+          <TerminalTableList { ...listProps } />
+        </Card>
+      </PageHeaderLayout>
+    );
+  }
+}

+ 45 - 0
src/routes/Terminal/List/search.js

@@ -0,0 +1,45 @@
+import react, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { Row, Col, Button, Icon } from 'antd';
+import DataSearch from '../../../components/DataSearch';
+
+export default class TerminalSearch extends Component {
+  static propTypes = {
+    onSearch: PropTypes.func,
+    onAdd: PropTypes.func,
+    field: PropTypes.string,
+    keyword: PropTypes.string,
+  };
+
+  render() {
+    const { field, keyword, onSearch, onAdd } = this.props;
+    const searchGroupProps = {
+      field,
+      keyword,
+      size: 'default',
+      select: true,
+      selectOptions: [{
+        value: 'name', name: '终端名称', type: 'input',
+      },{
+        value: 'code', name: '终端编号', type: 'input',
+      }],
+      selectProps: {
+        defaultValue: field || 'name',
+      },
+      onSearch: (value) => {
+        onSearch(value);
+      },
+    };
+
+    return (
+      <Row gutter={24}>
+        <Col lg={10} md={12} sm={16} xs={24} style={{ marginBottom: 16 }}>
+          <DataSearch { ...searchGroupProps } />
+        </Col>
+        <Col lg={{ offset: 7, span: 7 }} md={12} sm={8} xs={24} style={{ marginBottom: 16, textAlign: 'right' }}>
+          <Button type="primary" onClick={onAdd}><Icon type="plus-circle" />添加终端</Button>
+        </Col>
+      </Row>
+    );
+  }
+}

+ 104 - 0
src/routes/Terminal/List/table.js

@@ -0,0 +1,104 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import moment from 'moment';
+import classnames from 'classnames';
+import queryString from 'query-string';
+import { Divider, Table, Modal, Badge } from 'antd';
+import AnimTableBody from '../../../components/Animation/AnimTableBody';
+import styles from './table.less';
+import { Codes, terminalStatuses } from '../../../utils/config';
+
+export default class TerminalTableList extends Component {
+
+  handleOperateItem = (record) => {
+    const { onDeleteItem, onRecoverItem } = this.props;
+    Modal.confirm({
+      title: `您确定要${record.status === Codes.CODE_NORMAL ? '禁用' : '解禁'}该终端账号?`,
+      onOk () {
+        if (record.status === Codes.CODE_NORMAL) {
+          onDeleteItem(record.id);
+        } else {
+          onRecoverItem({ id: record.id, status: Codes.CODE_NORMAL });
+        }
+      },
+    });
+  }
+
+  render() {
+    const { onDeleteItem, onEditItem, curStatus, location, pagination, ...tableProps } = this.props;
+
+    // 从url中提取查询参数
+    location.query = queryString.parse(location.search);
+
+    const columns = [{
+      title: '终端编号',
+      dataIndex: 'code',
+      key: 'code',
+    },{
+      title: '终端名称',
+      dataIndex: 'name',
+      key: 'name',
+    },{
+      title: '校区',
+      dataIndex: 'campusName',
+      key: 'campusName',
+    },{
+      title: '渠道名称',
+      dataIndex: 'merchantId',
+      key: 'merchantId',
+      render: (text, record) => record.merchantName,
+    },{
+      title: '状态',
+      dataIndex: 'status',
+      key: 'status',
+      render: (text, record) => {
+        const statusMap = {[Codes.CODE_NORMAL]: 'success', [Codes.CODE_DISABLE]: 'error'};
+        return (<Badge status={statusMap[record.status]} text={terminalStatuses[record.status]} />);
+      },
+      filters: Object.keys(terminalStatuses).map(key => ({ text: terminalStatuses[key], value: key })),
+      filterMultiple: false,
+      filteredValue: [curStatus],
+    },{
+      title: '修改时间',
+      dataIndex: 'gmtModified',
+      key: 'gmtModified',
+      render: (text, record) => (
+        <div>{moment(text).format('YYYY-MM-DD HH:mm:ss')}</div>
+      )
+    },{
+      title: '操作',
+      dataIndex: 'operation',
+      key: 'operation',
+      render: (text, record) => (
+        <div>
+          <a onClick={() => onEditItem(record)}>编辑</a>
+          <Divider type="vertical" />
+          <a onClick={() => this.handleOperateItem(record)}>{record.status === Codes.CODE_NORMAL ? '禁用' : '解禁'}</a>
+        </div>
+      )
+    }];
+
+    columns.map(item => {
+      item.dataIndex === 'status' && !curStatus ? delete item.filteredValue : null;
+    });
+
+    tableProps.pagination = !!pagination && { ...pagination, showSizeChanger: true, showQuickJumper: true, showTotal: total => `共 ${total} 条`};
+    const getBodyWrapperProps = {
+      page: location.query.page,
+      current: tableProps.pagination.current,
+    };
+    const getBodyWrapper = (body) => (<AnimTableBody {...getBodyWrapperProps} body={body} />);
+
+    return (
+      <Table
+        simple
+        bordered
+        { ...tableProps }
+        columns={columns}
+        className={classnames({ [styles.table]: true, [styles.motion]: true })}
+        rowKey={record => record.id}
+        getBodyWrapper={getBodyWrapper}
+      />
+    );
+  }
+}

+ 14 - 6
src/routes/Terminal/table.less

@@ -1,5 +1,5 @@
 @import "~antd/lib/style/themes/default.less";
-@import "../../utils/utils.less";
+@import "../../../utils/utils.less";
 
 .table {
   :global {
@@ -14,23 +14,31 @@
       .ant-table-tbody > tr > td,
       .ant-table-thead > tr > th {
         &:nth-child(1) {
-          width: 20%;
+          width: 16%;
         }
 
         &:nth-child(2) {
-          width: 20%;
+          width: 12%;
         }
 
         &:nth-child(3) {
-          width: 30%;
+          width: 22%;
         }
 
         &:nth-child(4) {
-          width: 15%;
+          width: 10%;
         }
 
         &:nth-child(5) {
-          width: 15%;
+          width: 10%;
+        }
+
+        &:nth-child(6) {
+          width: 18%;
+        }
+
+        &:nth-child(7) {
+          width: 12%;
         }
       }
 

+ 0 - 109
src/routes/Terminal/index.js

@@ -1,109 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import queryString from 'query-string';
-import { connect } from 'dva';
-import { routerRedux } from 'dva/router';
-import { Card } from 'antd';
-import TableList from './table';
-import ModalForm from './modal';
-import Search from './search';
-import PageHeaderLayout from '../../layouts/PageHeaderLayout';
-
-function Terminal({ location, dispatch, terminal }) {
-  location.query = queryString.parse(location.search);
-  const { query, pathname } = location;
-  const { field, keyword } = query;
-  const { list, listLoading, pagination, currentItem, itemLoading, modalVisible, modalType } = terminal;
-
-  const modalProps = {
-    item: modalType === 'create' ? {} : currentItem,
-    visible: modalVisible,
-    maskClosable: false,
-    title: `${modalType === 'create' ? '添加终端' : '编辑终端'}`,
-    wrapClassName: 'vertical-center-modal',
-    onOk (data) {
-      dispatch({
-        type: `terminal/${modalType}`,
-        payload: data,
-      });
-    },
-    onCancel () {
-      dispatch({
-        type: 'terminal/hideModal',
-      });
-    },
-  };
-
-  const searchProps = {
-    field,
-    keyword,
-    onSearch: (payload) => {
-      if (!payload.keyword.length) {
-        delete payload.field;
-        delete payload.keyword;
-      }
-      dispatch(routerRedux.push({
-        pathname,
-        search: queryString.stringify({
-          ...payload
-        })
-      }));
-    },
-    onAdd: () => {
-      dispatch({
-        type: 'terminal/showModal',
-        payload: {
-          modalType: 'create',
-        },
-      });
-    }
-  };
-  const listProps = {
-    dataSource: list,
-    loading: listLoading,
-    pagination,
-    location,
-    onChange: (page) => {
-      dispatch(routerRedux.push({
-        pathname,
-        search: queryString.stringify({
-          ...query,
-          pageNo: page.current,
-          pageSize: page.pageSize,
-        }),
-      }));
-    },
-    onEditItem: (item) => {
-      dispatch({
-        type: 'terminal/showModal',
-        payload: {
-          modalType: 'update',
-          currentItem: item,
-        },
-      })
-    },
-    onDeleteItem: (id) => {
-      dispatch({
-        type: 'terminal/delete',
-        payload: id,
-      });
-    }
-  };
-  return (
-    <PageHeaderLayout>
-      <Card>
-        <Search { ...searchProps } />
-        <TableList { ...listProps } />
-        {modalVisible && <ModalForm { ...modalProps } />}
-      </Card>
-    </PageHeaderLayout>
-  );
-}
-
-Terminal.propTypes = {
-  Terminal: PropTypes.object,
-  location: PropTypes.object,
-  dispatch: PropTypes.func,
-}
-
-export default connect(({ terminal }) => ({ terminal }))(Terminal);

+ 0 - 81
src/routes/Terminal/modal.js

@@ -1,81 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { Form, Cascader, Switch, Input, Modal, Icon } from 'antd';
-import * as city from '../../utils/city';
-
-const FormItem = Form.Item
-
-const formItemLayout = {
-  labelCol: {
-    span: 7,
-  },
-  wrapperCol: {
-    span: 14,
-  },
-}
-
-const ModalForm = ({
-  item = {},
-  onOk,
-  form: {
-    getFieldDecorator,
-    getFieldsValue,
-    validateFields,
-  },
-  ...modalProps,
-}) => {
-  const handleOk = () => {
-    validateFields((errors) => {
-      if (errors) {
-        return
-      }
-      const data = {
-        ...getFieldsValue(),
-      };
-      data.status ? data.status = 'NORMAL' : data.status = 'DEL';
-      item.id ? data.id = item.id : null;
-      onOk(data);
-    })
-  }
-
-  const modalOpts = {
-    ...modalProps,
-    onOk: handleOk,
-  }
-
-  return (
-    <Modal {...modalOpts}>
-      <Form layout="horizontal">
-        <FormItem label="终端编号:" hasFeedback {...formItemLayout}>
-          {getFieldDecorator('code', {
-            initialValue: item.code,
-          })(<Input disabled={true} placeholder="请输入"/>)}
-        </FormItem>
-        <FormItem label="终端名称:" hasFeedback {...formItemLayout}>
-          {getFieldDecorator('name', {
-            initialValue: item.name,
-          })(<Input placeholder="请输入"/>)}
-        </FormItem>
-        <FormItem label="终端密码:" hasFeedback {...formItemLayout}>
-          {getFieldDecorator('password', {
-            initialValue: item.password,
-          })(<Input placeholder="请输入" type="password" addonBefore={<Icon type="edit" />}/>)}
-        </FormItem>
-        <FormItem label="账号状态:" {...formItemLayout}>
-          {getFieldDecorator('status', {
-            valuePropsName: 'checked',
-        })(<Switch defaultChecked={item.status === 'NORMAL' ? true : false} checkedChildren="使用中" unCheckedChildren="禁用中" />)}
-        </FormItem>
-      </Form>
-    </Modal>
-  )
-}
-
-ModalForm.propTypes = {
-  item: PropTypes.object,
-  form: PropTypes.object,
-  type: PropTypes.string,
-  onOk: PropTypes.func,
-}
-
-export default Form.create()(ModalForm);

+ 0 - 53
src/routes/Terminal/search.js

@@ -1,53 +0,0 @@
-import react, { PureComponent } from 'react';
-import PropTypes from 'prop-types';
-import { Button, Form, Row, Col, Icon } from 'antd';
-import DataSearch from '../../components/DataSearch';
-
-const Search = ({
-  field,
-  keyword,
-  onSearch,
-  onAdd
-}) => {
-  const searchGroupProps = {
-    field,
-    keyword,
-    size: 'default',
-    select: true,
-    selectOptions: [{
-      value: 'name', name: '终端名称'
-    },{
-      value: 'code', name: '终端编号'
-    },{
-      value: 'merchantId', name: '渠道平台'
-    },{
-      value: 'campusId', name: '校区名称'
-    }],
-    selectProps: {
-      defaultValue: field || 'name',
-    },
-    onSearch: (value) => {
-      onSearch(value);
-    },
-  }
-  return (
-    <Row gutter={24}>
-      <Col lg={10} md={12} sm={16} xs={24} style={{ marginBottom: 16 }}>
-        <DataSearch { ...searchGroupProps } />
-      </Col>
-      <Col lg={{ offset: 7, span: 7 }} md={12} sm={8} xs={24} style={{ marginBottom: 16, textAlign: 'right' }}>
-        <Button type="primary" onClick={onAdd}><Icon type="plus-circle" />添加终端</Button>
-      </Col>
-    </Row>
-  )
-}
-
-Search.propTypes = {
-  form: PropTypes.object.isRequired,
-  onSearch: PropTypes.func,
-  onAdd: PropTypes.func,
-  field: PropTypes.string,
-  keyword: PropTypes.string,
-}
-
-export default Form.create()(Search);

+ 0 - 80
src/routes/Terminal/table.js

@@ -1,80 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import moment from 'moment';
-import classnames from 'classnames';
-import queryString from 'query-string';
-import { Modal, Table, Popconfirm, Menu, Icon } from 'antd';
-import AnimTableBody from '../../components/Animation/AnimTableBody';
-import styles from './table.less';
-
-const confirm = Modal.confirm;
-
-const TableList = ({ onDeleteItem, onEditItem, location, pagination, ...tableProps }) => {
-  // 从url中提取查询参数
-  location.query = queryString.parse(location.search);
-  const handleDeleteItem = (record) => {
-    confirm({
-      title: `您确定要${record.status === 'NORMAL' ? '禁用' : '解禁'}该终端账号?`,
-      onOk () {
-        onDeleteItem(record.id);
-      },
-    })
-  }
-  const columns = [{
-    title: '终端编号',
-    dataIndex: 'code',
-    key: 'code',
-  },{
-    title: '终端名称',
-    dataIndex: 'name',
-    key: 'name',
-  },{
-    title: '校区',
-    dataIndex: 'campusName',
-    key: 'campusName',
-  },{
-    title: '添加时间',
-    dataIndex: 'gmtCreated',
-    key: 'gmtCreated',
-    render: (text, record) => (
-      <div>{moment(text).format('YYYY-MM-DD')}</div>
-    )
-  },{
-    title: '操作',
-    dataIndex: 'operation',
-    key: 'operation',
-    render: (text, record) => (
-      <div>
-        <a onClick={() => onEditItem(record)}>编辑</a>
-        <span className={styles.splitLine} />
-          <a onClick={() => handleDeleteItem(record)}>{record.status === 'NORMAL' ? '禁用' : '解禁'}</a>
-      </div>
-    )
-  }];
-  tableProps.pagination = !!pagination && { ...pagination, showSizeChanger: true, showQuickJumper: true, showTotal: total => `共 ${total} 条`};
-  const getBodyWrapperProps = {
-    page: location.query.page,
-    current: tableProps.pagination.current,
-  };
-  const getBodyWrapper = (body) => (<AnimTableBody {...getBodyWrapperProps} body={body} />);
-  return (
-    <Table
-      simple
-      bordered
-      { ...tableProps }
-      columns={columns}
-      className={classnames({ [styles.table]: true, [styles.motion]: true })}
-      rowKey={record => record.id}
-      getBodyWrapper={getBodyWrapper}
-    />
-  );
-}
-
-TableList.propTypes = {
-  location: PropTypes.object,
-  onChange: PropTypes.func.isRequired,
-  onDeleteItem: PropTypes.func.isRequired,
-  onEditItem: PropTypes.func.isRequired,
-}
-
-export default TableList;

+ 3 - 15
src/services/cmsuser.js

@@ -1,15 +1,3 @@
-// import { stringify } from 'qs';
-// import request from '../utils/request';
-// import { users, currentUser } from '../utils/api'
-//
-// export async function query(params) {
-//   return request(`${users}?${stringify(params)}`);
-// }
-//
-// export async function queryCurrent(params) {
-//   return request(`${currentUser}?${stringify(params)}`);
-// }
-//
 import { stringify } from 'qs';
 import request from '../utils/request';
 import { cmsUsers, cmsUser } from '../utils/api';
@@ -23,7 +11,7 @@ export async function create(params) {
     method: 'POST',
     body: JSON.stringify(params),
   };
-  return request(`${cmsUser.replace('/:id', '')}`, options);
+  return request(`${cmsUser}`, options);
 }
 
 export async function update(params) {
@@ -31,10 +19,10 @@ export async function update(params) {
     method: 'PUT',
     body: JSON.stringify(params),
   };
-  return request(`${cmsUser.replace('/:id', '')}`, options);
+  return request(`${cmsUser}`, options);
 }
 
 export async function remove({ id }) {
   const options = { method: 'DELETE' }
-  return request(`${cmsUser.replace('/:id', `/${id}`)}`, options);
+  return request(`${cmsUser}/${id}`, options);
 }

+ 5 - 11
src/services/terminal.js

@@ -11,7 +11,7 @@ export async function create(params) {
     method: 'POST',
     body: JSON.stringify(params),
   };
-  return request(`${terminal.replace('/:id', '')}`, options);
+  return request(`${terminal}`, options);
 }
 
 export async function update(params) {
@@ -19,16 +19,10 @@ export async function update(params) {
     method: 'PUT',
     body: JSON.stringify(params),
   };
-  return request(`${terminal.replace('/:id', '')}`, options);
+  return request(`${terminal}`, options);
 }
 
-export async function remove({ id }) {
-  const options = {
-    method: 'DELETE',
-  }
-  if (id) {
-    return request(`${terminal.replace(':id', id)}`);
-  } else {
-    return {};
-  }
+export async function remove(id) {
+  const options = { method: 'DELETE' };
+  return request(`${terminal}/${id}`, options);
 }

+ 2 - 2
src/utils/api.js

@@ -5,13 +5,13 @@ module.exports = {
   resource: `${config.apiHost}/resource/:id`,
   signature: `${config.apiHost}/oss/signature`,
   cmsUsers: `${config.apiHost}/cms/user/list`,
-  cmsUser: `${config.apiHost}/cms/user/:id`,
+  cmsUser: `${config.apiHost}/cms/user`,
   userLogin: `${config.apiHost}/login`,
   userLogout: `${config.apiHost}/logout`,
   campuses: `${config.apiHost}/campus/list`,
   campus: `${config.apiHost}/campus/:id`,
   terminals: `${config.apiHost}/user/list`,
-  terminal: `${config.apiHost}/user/:id`,
+  terminal: `${config.apiHost}/user`,
   merchants: `${config.apiHost}/merchant/list`,
   merchant: `${config.apiHost}/merchant`,
   recommend: `${config.apiHost}/merchant/recommend`,

+ 7 - 0
src/utils/config.js

@@ -8,6 +8,7 @@ Codes.CODE_IMAGE = 3;
 
 Codes.CODE_NORMAL = 'NORMAL';
 Codes.CODE_DELETE = 'DEL';
+Codes.CODE_DISABLE = 'DISABLE';
 
 Codes.CODE_WARE = 'WARE';
 Codes.CODE_LESSON = 'LESSON';
@@ -50,6 +51,11 @@ module.exports = {
     [Codes.CODE_NORMAL]: '在售',
     [Codes.CODE_DELETE]: '下架',
   },
+  // 终端账号状态
+  terminalStatuses: {
+    [Codes.CODE_NORMAL]: '使用中',
+    [Codes.CODE_DISABLE]: '禁用中',
+  },
   // 产品类型
   productType: {
     [Codes.CODE_COURSE] : '课程',
@@ -58,6 +64,7 @@ module.exports = {
   },
   // 平台代号
   domains: {
+    [Codes.CODE_LJ]: '平台方',
     [Codes.CODE_CP]: '供应商',
     [Codes.CODE_PJ]: '渠道商',
   },