From 4e837faa0307fda4d0d3bd463c88a7ef43817443 Mon Sep 17 00:00:00 2001
From: king <18310653075@163.com>
Date: 星期五, 20 九月 2019 16:06:41 +0800
Subject: [PATCH] 2019-09-20update

---
 src/components/tabview/index.jsx     |   71 ++-
 src/index.js                         |    1 
 src/components/tabview/index.scss    |   20 
 src/assets/css/action.scss           |  107 ++++++
 src/components/resetpwd/index.jsx    |    4 
 src/locales/zh-CN/main.js            |    7 
 src/components/header/index.jsx      |    8 
 src/components/mainAction/index.jsx  |   50 ++
 src/components/mainSearch/index.jsx  |  211 ++++++++++++
 src/views/main/index.scss            |    2 
 src/components/loading/index.jsx     |   12 
 src/tabviews/commontable/index.scss  |   31 
 src/components/mainAction/index.scss |    8 
 src/api/index.js                     |   34 ++
 src/components/mainTable/index.jsx   |  119 +++++++
 package.json                         |    1 
 src/components/mainSearch/index.scss |   14 
 src/components/mainTable/index.scss  |   36 ++
 src/locales/en-US/main.js            |    7 
 src/tabviews/commontable/index.jsx   |  189 ++++++++--
 src/utils/utils.js                   |   78 ++++
 src/assets/css/main.scss             |    5 
 22 files changed, 896 insertions(+), 119 deletions(-)

diff --git a/package.json b/package.json
index d718395..c3d8529 100644
--- a/package.json
+++ b/package.json
@@ -39,6 +39,7 @@
     "jest-watch-typeahead": "0.3.1",
     "md5": "^2.2.1",
     "mini-css-extract-plugin": "0.5.0",
+    "moment": "^2.24.0",
     "node-sass": "^4.12.0",
     "optimize-css-assets-webpack-plugin": "5.0.3",
     "pnp-webpack-plugin": "1.5.0",
diff --git a/src/api/index.js b/src/api/index.js
index 10ba34c..cdd6846 100644
--- a/src/api/index.js
+++ b/src/api/index.js
@@ -1,6 +1,7 @@
 import axios from 'axios'
 
 axios.defaults.crossDomain = true
+axios.defaults.headers.common['token'] = 'token'
 axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'
 axios.defaults.withCredentials = true
 
@@ -96,6 +97,39 @@
       }
     })
   }
+
+  /**
+   * @description 鑾峰彇椤甸潰閰嶇疆淇℃伅
+   * @param {String} MenuNo 椤甸潰鑿滃崟鍙傛暟
+   */
+  getMainConfigsData (MenuNo) {
+    return axios({
+      url: '/dostar',
+      data: {
+        func: 'GetMainConfigs',
+        MenuNo: MenuNo
+      }
+    })
+  }
+
+  /**
+   * @description 鑾峰彇椤甸潰鍒楄〃鏁版嵁
+   * @param {String} MenuNo 椤甸潰鑿滃崟鍙傛暟
+   */
+  getMainTableData (MenuNo, pageIndex = 1, pageSize = 10, orderColumn = '', orderType = '', search) {
+    return axios({
+      url: '/dostar',
+      data: {
+        func: 'GetMainData',
+        MenuNo: MenuNo,
+        PageIndex: pageIndex,
+        PageSize: pageSize,
+        orderColumn: orderColumn,
+        orderType: orderType,
+        search: search
+      }
+    })
+  }
 }
 
 export default new Api()
\ No newline at end of file
diff --git a/src/assets/css/action.scss b/src/assets/css/action.scss
new file mode 100644
index 0000000..46d850f
--- /dev/null
+++ b/src/assets/css/action.scss
@@ -0,0 +1,107 @@
+.mk-btn:hover {
+  opacity: 0.8;
+}
+
+// 钃濊壊
+.mk-primary, .mk-primary:hover, .mk-primary:active, .mk-primary:focus {
+  color: #fff;
+  background-color: #1890ff;
+  border-color: #1890ff;
+}
+
+.mk-border-primary, .mk-border-primary:hover, .mk-border-primary:active, .mk-border-primary:focus {
+  color: #1890ff;
+  background-color: #fff;
+  border-color: #1890ff;
+}
+
+// 榛樿涓庤櫄绾�
+.mk-default, .mk-default:hover, .mk-default:active, .mk-default:focus {
+  color: rgba(0, 0, 0, 0.65);
+  background-color: #fff;
+  border-color: #d9d9d9;
+}
+
+.mk-dashed, .mk-dashed:hover, .mk-dashed:active, .mk-dashed:focus {
+  color: rgba(0, 0, 0, 0.65);
+  background-color: #fff;
+  border-color: #d9d9d9;
+  border-style: dashed;
+}
+
+.mk-default:hover, .mk-dashed:hover {
+  color: #096dd9;
+  border-color: #096dd9;
+}
+
+// 绾㈣壊
+.mk-danger, .mk-danger:hover, .mk-danger:active, .mk-danger:focus {
+  color: #fff;
+  background-color: #ff4d4f;
+  border-color: #ff4d4f;
+}
+
+.mk-border-danger, .mk-border-danger:hover, .mk-border-danger:active, .mk-border-danger:focus {
+  color: #ff4d4f;
+  background-color: #fff;
+  border-color: #ff4d4f;
+}
+
+// 缁胯壊
+.mk-green, .mk-green:hover, .mk-green:active, .mk-green:focus {
+  color: #FFF;
+  background-color: #26C281;
+  border-color: #26C281;
+}
+
+.mk-border-green, .mk-border-green:hover, .mk-border-green:active, .mk-border-green:focus {
+  color: #26C281;
+  background-color: #fff;
+  border-color: #26C281;
+}
+
+// 娣辩豢鑹�
+.mk-dgreen, .mk-dgreen:hover, .mk-dgreen:active, .mk-dgreen:focus {
+  color: #FFF;
+  background-color: #32c5d2;
+  border-color: #32c5d2;
+}
+
+.mk-border-dgreen, .mk-border-dgreen:hover, .mk-border-dgreen:active, .mk-border-dgreen:focus {
+  color: #32c5d2;
+  background-color: #fff;
+  border-color: #32c5d2;
+}
+
+// 绱壊
+.mk-purple, .mk-purple:hover, .mk-purple:active, .mk-purple:focus {
+  color: #fff;
+  background-color: #8E44AD;
+  border-color: #8E44AD;
+}
+
+.mk-border-purple, .mk-border-purple:hover, .mk-border-purple:active, .mk-border-purple:focus {
+  color: #8E44AD;
+  background-color: #fff;
+  border-color: #8E44AD;
+}
+
+// 榛勮壊
+.mk-yellow, .mk-yellow:hover, .mk-yellow:active, .mk-yellow:focus {
+  color: #fff;
+  background-color: #c49f47;
+  border-color: #c49f47;
+}
+
+.mk-border-yellow, .mk-border-yellow:hover, .mk-border-yellow:active, .mk-border-yellow:focus {
+  color: #c49f47;
+  background-color: #fff;
+  border-color: #c49f47;
+}
+
+// 鐏拌壊
+.mk-gray, .mk-gray:hover, .mk-gray:active, .mk-gray:focus {
+  color: #666;
+  background-color: #e1e5ec;
+  border-color: #e1e5ec;
+}
diff --git a/src/assets/css/main.scss b/src/assets/css/main.scss
index e08db1b..83a238f 100644
--- a/src/assets/css/main.scss
+++ b/src/assets/css/main.scss
@@ -88,3 +88,8 @@
 //   border-radius: 0;
 //   background: rgba(0,0,0,0.1);
 // }
+
+// 閲嶇疆鎸夐挳涓枃瀛椾笌鍥炬爣璺濈
+.ant-btn > .anticon + span, .ant-btn > span + .anticon {
+  margin-left: 5px;
+}
diff --git a/src/components/header/index.jsx b/src/components/header/index.jsx
index 384a143..d4204be 100644
--- a/src/components/header/index.jsx
+++ b/src/components/header/index.jsx
@@ -59,7 +59,7 @@
   }
 
   async resetPwdSubmitexec (param) {
-    // 鐧诲綍鎻愪氦
+    // 閲嶇疆瀵嗙爜鎻愪氦锛屽叧闂ā鎬佹锛屾竻绌鸿〃鍗曟暟鎹�
     let password = this.md5Password(param.originpwd)
     let newpassword = this.md5Password(param.password)
     let result = await Api.resetpassword(password, newpassword)
@@ -68,6 +68,7 @@
         visible: false,
         confirmLoading: false
       })
+      this.formRef.resetfrom()
       message.success(this.state.dict['header.password.resetsuccess'])
     } else {
       message.warning(result.message)
@@ -78,10 +79,11 @@
   }
 
   handleCancel = () => {
-    // 鍙栨秷鏃跺叧闂慨鏀瑰瘑鐮佹ā鎬佹
+    // 鍙栨秷鏃跺叧闂慨鏀瑰瘑鐮佹ā鎬佹锛屾竻绌鸿〃鍗曟暟鎹�
     this.setState({
       visible: false
     })
+    this.formRef.resetfrom()
   }
 
   logout = () => {
@@ -182,7 +184,7 @@
           confirmLoading={this.state.confirmLoading}
           onCancel={this.handleCancel}
         >
-          {this.state.visible && (<Resetpwd dict={this.state.dict} wrappedComponentRef={(inst) => this.formRef = inst} resetPwdSubmit={this.resetPwdSubmit}/>)}
+          <Resetpwd dict={this.state.dict} wrappedComponentRef={(inst) => this.formRef = inst} resetPwdSubmit={this.resetPwdSubmit}/>
         </Modal>
       </header>
     )
diff --git a/src/components/loading/index.jsx b/src/components/loading/index.jsx
index 13f8789..c26cb48 100644
--- a/src/components/loading/index.jsx
+++ b/src/components/loading/index.jsx
@@ -1,18 +1,10 @@
 import React, {Component} from 'react'
+import { Spin } from 'antd'
 
 class Loading extends Component {
   render () {
     return (
-      <div className="page-loading-warp">
-        <div className="ant-spin ant-spin-lg ant-spin-spinning">
-          <span className="ant-spin-dot ant-spin-dot-spin">
-            <i className="ant-spin-dot-item"></i>
-            <i className="ant-spin-dot-item"></i>
-            <i className="ant-spin-dot-item"></i>
-            <i className="ant-spin-dot-item"></i>
-          </span>
-        </div>
-      </div>
+      <Spin style={{marginLeft: 'calc(50% - 22px)', marginTop: 'calc(50vh - 70px)'}} size="large" />
     )
   }
 }
diff --git a/src/components/mainAction/index.jsx b/src/components/mainAction/index.jsx
new file mode 100644
index 0000000..12149a1
--- /dev/null
+++ b/src/components/mainAction/index.jsx
@@ -0,0 +1,50 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+// import { is, fromJS } from 'immutable'
+import { Button, Affix } from 'antd'
+import './index.scss'
+
+class MainAction extends Component {
+  static propTpyes = {
+    actions: PropTypes.array, // 鎼滅储鏉′欢鍒楄〃
+    dict: PropTypes.object // 瀛楀吀椤�
+  }
+
+  state = {
+
+  }
+
+  actionTrigger = (item) => {
+    console.log(item)
+  }
+
+  UNSAFE_componentWillMount () {
+
+  }
+
+  // shouldComponentUpdate (nextProps, nextState) {
+  //   console.log(!is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState)))
+  //   return true
+  // }
+
+  render() {
+    return (
+      <Affix offsetTop={48}>
+        <div className="button-list">
+          {this.props.actions.map((item, index) => {
+            return (
+              <Button
+                className={'mk-btn ' + item.CssClass}
+                icon={item.Icon}
+                key={'action' + index}
+                onClick={() => {this.actionTrigger(item)}}
+              >{item.MenuName}</Button>
+            )
+          })}
+        </div>
+      </Affix>
+    )
+  }
+}
+
+export default MainAction
\ No newline at end of file
diff --git a/src/components/mainAction/index.scss b/src/components/mainAction/index.scss
new file mode 100644
index 0000000..1e4f0fa
--- /dev/null
+++ b/src/components/mainAction/index.scss
@@ -0,0 +1,8 @@
+.button-list {
+  padding: 10px 20px 5px;
+  background: #ffffff;
+  button {
+    margin-right: 15px;
+    margin-bottom: 10px;
+  }
+}
\ No newline at end of file
diff --git a/src/components/mainSearch/index.jsx b/src/components/mainSearch/index.jsx
new file mode 100644
index 0000000..0b2a608
--- /dev/null
+++ b/src/components/mainSearch/index.jsx
@@ -0,0 +1,211 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+// import { is, fromJS } from 'immutable'
+import { Form, Row, Col, Input, Button, Select, DatePicker } from 'antd'
+import moment from 'moment'
+import Utils from '@/utils/utils.js'
+import './index.scss'
+
+const {MonthPicker, WeekPicker} = DatePicker
+const dateFormat = 'YYYY-MM-DD'
+const weekFormat = 'YYYYMMDD'
+const monthFormat = 'YYYY-MM'
+
+class MainSearch extends Component {
+  static propTpyes = {
+    searchlist: PropTypes.array, // 鎼滅储鏉′欢鍒楄〃
+    dict: PropTypes.object // 瀛楀吀椤�
+  }
+
+  state = {
+    formats: null, // 浜嬩欢鏍¢獙瑙勫垯
+    match: null // 鎼滅储鏉′欢鍖归厤瑙勫垯
+  }
+
+  UNSAFE_componentWillMount () {
+    let formats = {}
+    let match = {}
+    this.props.searchlist.forEach(item => {
+      if (item.Type === 'date') {
+        // formats[item.FieldName] = dateFormat
+        formats[item.FieldName] = weekFormat
+      } else if (item.ID === 'WHE1400200905') {
+        formats[item.FieldName] = monthFormat
+      }
+      match[item.FieldName] = item.Op
+    })
+    this.setState({
+      formats: formats,
+      match: match
+    })
+  }
+
+  // shouldComponentUpdate (nextProps, nextState) {
+  //   return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
+  // }
+
+  getFields() {
+    const { getFieldDecorator } = this.props.form
+    const fields = []
+    this.props.searchlist.forEach((item, index) => {
+      if (item.Type === 'text' || item.Type === 'string') { // 鏂囨湰鎼滅储
+        fields.push(
+          <Col span={6} key={index}>
+            <Form.Item label={item.Label}>
+              {getFieldDecorator(item.FieldName)(<Input placeholder="" />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.Type === 'select') { // 涓嬫媺鎼滅储
+        fields.push(
+          <Col span={6} key={index}>
+            <Form.Item label={item.Label}>
+              {getFieldDecorator(item.FieldName, {initialValue: item.DynOptions[0].id })(
+                <Select
+                  showSearch
+                  onChange={(val) => {this.selectChange(item.FieldName, val)}}
+                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                >
+                  {item.DynOptions.map(option =>
+                    <Select.Option id={option.id} title={option.text} key={option.id} value={option.id}>{option.text}</Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.Type === 'date') { // 鏃堕棿鎼滅储
+        if (item.ID === 'WHE14002009024') {
+          fields.push(
+            <Col span={6} key={index}>
+              <Form.Item label={item.Label}>
+                {getFieldDecorator(item.FieldName, {initialValue: moment('2019-09-14', dateFormat) })(
+                  <DatePicker format={dateFormat} onChange={(val) => {this.timeChange(item.FieldName, val)}} />
+                )}
+              </Form.Item>
+            </Col>
+          )
+        } else if (item.ID === 'WHE1400200905') {
+          fields.push(
+            <Col span={6} key={index}>
+              <Form.Item label={item.Label}>
+                {getFieldDecorator(item.FieldName, {initialValue: moment('2019-09', monthFormat) })(
+                  <MonthPicker format={monthFormat} onChange={(val) => {this.timeChange(item.FieldName, val)}} />
+                )}
+              </Form.Item>
+            </Col>
+          )
+        } else if (item.ID === 'WHE1400200902') {
+          fields.push(
+            <Col span={6} key={index}>
+              <Form.Item label={item.Label}>
+                {getFieldDecorator(item.FieldName, {initialValue: moment('20190906', weekFormat) })(
+                  <WeekPicker onChange={(val) => {this.timeChange(item.FieldName, val)}} />
+                )}
+              </Form.Item>
+            </Col>
+          )
+        }
+      }
+    })
+
+    if (this.props.searchlist.length >= 4) { // 娣诲姞鎼滅储銆侀噸缃寜閽�
+      fields.push(
+        <Col span={this.props.searchlist.length % 4 ? 6 : 24} style={{ textAlign: 'right' }} key="actions">
+          <Button type="primary" htmlType="submit">
+            {this.props.dict['main.search']}
+          </Button>
+          <Button style={{ marginLeft: 8 }} onClick={this.handleReset}>
+            {this.props.dict['main.reset']}
+          </Button>
+        </Col>
+      )
+    } else {
+      fields.push(
+        <Col span={6} style={{ paddingTop: '4px' }} key="actions">
+          <Button type="primary" htmlType="submit">
+            {this.props.dict['main.search']}
+          </Button>
+          <Button style={{ marginLeft: 8 }} onClick={this.handleReset}>
+            {this.props.dict['main.reset']}
+          </Button>
+        </Col>
+      )
+    }
+    
+    return fields
+  }
+
+  handleSearch = (e) => {
+    // 鍥炶溅鎴栫偣鍑绘悳绱�
+    e.preventDefault()
+    this.props.form.validateFields((err, values) => {
+      this.getFieldsValues(values)
+    })
+  }
+
+  selectChange = (key, val) => {
+    // 鏉′欢閫夋嫨鍒囨崲
+    this.props.form.validateFields((err, values) => {
+      this.getFieldsValues(Object.assign({}, values, {[key]: val}))
+    })
+  }
+
+  timeChange = (key, val) => {
+    // 鏃堕棿鍒囨崲
+    this.props.form.validateFields((err, values) => {
+      this.getFieldsValues(Object.assign({}, values, {[key]: val}))
+    })
+  }
+
+  handleReset = () => {
+    // 閲嶇疆
+    this.props.form.resetFields()
+    this.props.form.validateFields((err, values) => {
+      this.getFieldsValues(values)
+    })
+  }
+
+  getFieldsValues = (searches) => {
+    // 鑾峰彇鎼滅储鏉′欢鍊�
+    let search = []
+    Object.keys(searches).forEach(key => {
+      if (searches[key] && typeof(searches[key]) === 'object') {
+        if (this.state.formats[key] === weekFormat) {
+          search.push({
+            type: 'date',
+            key: key,
+            value: moment(searches[key]).startOf('week').format(this.state.formats[key]) + ' ' + moment(searches[key]).endOf('week').format(this.state.formats[key]),
+            op: this.state.match[key]
+          })
+        } else {
+          search.push({
+            type: 'date',
+            key: key,
+            value: moment(searches[key]).format(this.state.formats[key]),
+            op: this.state.match[key]
+          })
+        }
+      } else if (searches[key] && searches[key] !== '-1') {
+        search.push({
+          type: 'text',
+          key: key,
+          value: searches[key],
+          op: this.state.match[key]
+        })
+      }
+    })
+    search = Utils.jointsearchkey(search)
+    this.props.refreshdata(search)
+  }
+
+  render() {
+    return (
+      <Form className="ant-advanced-search-form main-search" onSubmit={this.handleSearch}>
+        <Row gutter={24}>{this.getFields()}</Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(MainSearch)
\ No newline at end of file
diff --git a/src/components/mainSearch/index.scss b/src/components/mainSearch/index.scss
new file mode 100644
index 0000000..34418e4
--- /dev/null
+++ b/src/components/mainSearch/index.scss
@@ -0,0 +1,14 @@
+.ant-advanced-search-form.main-search {
+  padding: 0px 24px 20px;
+  border-bottom: 1px solid #d9d9d9;
+  .ant-form-item {
+    display: flex;
+    margin-bottom: 10px;
+  }
+  .ant-form-item-control-wrapper {
+    flex: 1;
+  }
+  .ant-form-item-label {
+    width: 100px;
+  }
+}
\ No newline at end of file
diff --git a/src/components/mainTable/index.jsx b/src/components/mainTable/index.jsx
new file mode 100644
index 0000000..32d95e8
--- /dev/null
+++ b/src/components/mainTable/index.jsx
@@ -0,0 +1,119 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Table, Icon, message } from 'antd'
+import './index.scss'
+
+export default class MainTable extends Component {
+  static propTpyes = {
+    loading: PropTypes.bool,
+    total: PropTypes.number,
+    select: PropTypes.object,
+    dict: PropTypes.object, // 瀛楀吀椤�
+    columns: PropTypes.array, // 琛ㄦ牸鍒�
+    data: PropTypes.oneOfType([
+      PropTypes.object,
+      PropTypes.array
+    ])
+  }
+
+  state = {
+    selectedRowKeys: [],
+    pageIndex: 1,
+    pageSize: 10,
+    columns: this.props.columns.map((item, index) => {
+      let _width = parseInt(item.Width) || 50
+      return {
+        align: item.Align,
+        dataIndex: item.FieldName,
+        title: item.Label,
+        sorter: item.IsSort === 'true',
+        filterMultiple: item.CDefine1 === 'true',
+        filters: item.CDefine2 && JSON.parse(item.CDefine2),
+        width: _width,
+        render: (text, record) => (
+          <div style={{ wordWrap: 'break-word', wordBreak: 'break-word', minWidth: _width + 'px' }}>
+            {text}
+            {item.FieldName === 'MenuNo' ? <Icon onClick={(e) => {this.copycontent(e, record[item.FieldName])}} type="copy"/> : ''}
+          </div>
+        )
+        // onHeaderCell: () => ({style:{textAlign: 'center'}})
+      }
+    })
+  }
+
+  copycontent = (e, content) => {
+    // 琛ㄦ牸涓唴瀹瑰鍒�
+    e.stopPropagation()
+    let oInput = document.createElement('input')
+    oInput.value = content
+    document.body.appendChild(oInput)
+    oInput.select()
+    document.execCommand('Copy')
+    oInput.className = 'oInput'
+    oInput.style.display='none'
+    message.success(this.props.dict['main.copy.success'])
+  }
+
+  onSelectChange = selectedRowKeys => {
+    this.setState({ selectedRowKeys })
+  }
+
+  changeRow = (record, index) => {
+    // 鐐瑰嚮鏁磋锛岃Е鍙戝垏鎹�
+    let newkeys = JSON.parse(JSON.stringify(this.state.selectedRowKeys))
+    let _re = newkeys.includes(index)
+    if (_re) {
+      newkeys = newkeys.filter(item => item !== index)
+    } else {
+      newkeys.push(index)
+    }
+    this.setState({ selectedRowKeys: newkeys })
+  }
+
+  changeTable = (pagination, filters, sorter) => {
+    this.setState({
+      pageIndex: pagination.current,
+      pageSize: pagination.pageSize
+    })
+    this.props.refreshdata(pagination, filters, sorter)
+  }
+
+  render() {
+    let { selectedRowKeys } = this.state
+    let rowSelection = null
+    if (this.props.select && this.props.select.selectable) {
+      rowSelection = {
+        selectedRowKeys,
+        type: this.props.select.selectType === 'radio' ? 'radio' : 'checkbox',
+        onChange: this.onSelectChange
+      }
+    }
+    return (
+      <div className="main-table">
+        <Table
+          bordered={true}
+          rowSelection={rowSelection}
+          size="middle"
+          columns={this.state.columns}
+          dataSource={this.props.data ? this.props.data : []}
+          loading={this.props.loading}
+          scroll={{ x: '100%', y: false }}
+          onRow={(record, index) => {
+            return {
+              onClick: () => {this.changeRow(record, index)}
+            }
+          }}
+          onChange={this.changeTable}
+          pagination={{
+            current: this.state.pageIndex,
+            pageSize: this.state.pageSize,
+            pageSizeOptions: ['10', '25', '50', '100', '500', '1000'],
+            showSizeChanger: true,
+            total: this.props.total,
+            showTotal: (total, range) => `${range[0]}-${range[1]} ${this.props.dict['main.pagination.of']} ${total} ${this.props.dict['main.pagination.items']}`
+          }}
+        />
+      </div>
+    )
+  }
+}
diff --git a/src/components/mainTable/index.scss b/src/components/mainTable/index.scss
new file mode 100644
index 0000000..d56f18f
--- /dev/null
+++ b/src/components/mainTable/index.scss
@@ -0,0 +1,36 @@
+.main-table {
+  padding: 0 20px 110px;
+  table {
+    max-width: 100%;
+    width: 100%;
+    .ant-table-column-title {
+      white-space: nowrap;
+    }
+    .ant-table-selection-column {
+      width: 60px;
+      min-width: 60px;
+      max-width: 60px;
+    }
+    .ant-table-tbody > tr.ant-table-row-selected td {
+      background-color: #c4ebfd;
+    }
+  }
+  .ant-table-body {
+    overflow-x: auto!important;
+  }
+  .ant-table-body::-webkit-scrollbar {
+    width: 8px;
+    height: 10px;
+  }
+  ::-webkit-scrollbar-thumb {
+    border-radius: 5px;
+    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
+    background: rgba(0, 0, 0, 0.13);
+  }
+  ::-webkit-scrollbar-track {/*婊氬姩鏉¢噷闈㈣建閬�*/
+    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
+    border-radius: 3px;
+    border: 1px solid rgba(0, 0, 0, 0.07);
+    background: rgba(0, 0, 0, 0);
+  }
+}
\ No newline at end of file
diff --git a/src/components/resetpwd/index.jsx b/src/components/resetpwd/index.jsx
index 448aea7..62d43b8 100644
--- a/src/components/resetpwd/index.jsx
+++ b/src/components/resetpwd/index.jsx
@@ -31,6 +31,10 @@
     })
   }
 
+  resetfrom = () => {
+    this.props.form.resetFields()
+  }
+
   handleConfirmBlur = e => {
     const { value } = e.target
     this.setState({ confirmDirty: this.state.confirmDirty || !!value })
diff --git a/src/components/tabview/index.jsx b/src/components/tabview/index.jsx
index 527a64c..3699fc6 100644
--- a/src/components/tabview/index.jsx
+++ b/src/components/tabview/index.jsx
@@ -2,21 +2,29 @@
 import PropTypes from 'prop-types'
 import {connect} from 'react-redux'
 import { is, fromJS } from 'immutable'
-import {Tabs, Icon} from 'antd'
+import {Tabs, Icon, ConfigProvider} from 'antd'
 import {modifyTabview, toggleIsiframe} from '@/store/action'
 import asyncComponent from '@/utils/asyncComponent'
 import NotFount from '@/components/404'
+import enUS from 'antd/es/locale/en_US'
+import zhCN from 'antd/es/locale/zh_CN'
+import moment from 'moment'
+import 'moment/locale/zh-cn'
 import './index.scss'
+
+
 let Comps = {}
 
 class Header extends Component {
   static propTpyes = {
+    collapse: PropTypes.bool,
     tabviews: PropTypes.array // 鏍囩椤垫暟缁�
   }
 
   state = {
     selectedTabId: '', // 褰撳墠閫変腑tab椤甸潰
-    iFrameHeight: 0
+    iFrameHeight: 0,
+    locale: (!sessionStorage.getItem('lang') || sessionStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS
   }
 
   handleTabview (menu) {
@@ -73,6 +81,14 @@
     }
   }
 
+  UNSAFE_componentWillMount () {
+    if (!sessionStorage.getItem('lang') || sessionStorage.getItem('lang') === 'zh-CN') {
+      moment.locale('zh-cn')
+    } else {
+      moment.locale('en')
+    }
+  }
+
   UNSAFE_componentWillReceiveProps (nextProps) {
     if (nextProps.tabviews && !is(fromJS(this.props.tabviews), fromJS(nextProps.tabviews))) {
       // tab绐楀彛椤靛鍔犳垨鍒犻櫎
@@ -102,31 +118,33 @@
 
   render () {
     return (
-      <section className="flex-container content-box">
-        <div className="content-header">
-          {this.props.tabviews && this.props.tabviews.length > 0 &&
-            <Tabs activeKey={this.state.selectedTabId}>
-              {this.props.tabviews.map(view => {
-                return (
-                  <Tabs.TabPane
-                    className="test"
-                    tab={
-                      <span>
-                        <span className="tab-name" onClick={() => {this.changeTab(view)}}>
-                          {view.MenuName}
+      <section className={'flex-container content-box' + (this.props.collapse ? ' collapsed' : '')}>
+        <ConfigProvider locale={this.state.locale}>
+          <div className="content-header">
+            {this.props.tabviews && this.props.tabviews.length > 0 &&
+              <Tabs activeKey={this.state.selectedTabId}>
+                {this.props.tabviews.map(view => {
+                  return (
+                    <Tabs.TabPane
+                      className="test"
+                      tab={
+                        <span>
+                          <span className="tab-name" onClick={() => {this.changeTab(view)}}>
+                            {view.MenuName}
+                          </span>
+                          <Icon type="close" onClick={() => {this.handleTabview(view)}}/>
                         </span>
-                        <Icon type="close" onClick={() => {this.handleTabview(view)}}/>
-                      </span>
-                    }
-                    key={view.MenuID}
-                  >
-                    {this.selectcomponent(view)}
-                  </Tabs.TabPane>
-                )
-              })}
-            </Tabs>
-          }
-        </div>
+                      }
+                      key={view.MenuID}
+                    >
+                      {this.selectcomponent(view)}
+                    </Tabs.TabPane>
+                  )
+                })}
+              </Tabs>
+            }
+          </div>
+        </ConfigProvider>
       </section>
     )
   }
@@ -135,6 +153,7 @@
 const mapStateToProps = (state) => {
   return {
     tabviews: state.tabviews,
+    collapse: state.collapse,
     isiframe: state.isiframe
   }
 }
diff --git a/src/components/tabview/index.scss b/src/components/tabview/index.scss
index eea5112..25ec811 100644
--- a/src/components/tabview/index.scss
+++ b/src/components/tabview/index.scss
@@ -1,6 +1,7 @@
 .content-box {
   padding-top: 48px;
-
+  max-width: calc(100% - 235px);
+  transition: max-width 0.2s;
   .content-header {
     width: 100%;
     height: 100%;
@@ -27,20 +28,9 @@
       height: calc(100vh - 115px);
       overflow-y: scroll;
       border: 0;
-      // &:-webkit-scrollbar {
-      //   width: 4px;
-      //   height: 4px;
-      // }
-      // &:-webkit-scrollbar-thumb {
-      //     border-radius: 5px;
-      //     box-shadow: inset 0 0 5px rgba(0,0,0,0.2);
-      //     background: rgba(0,0,0,0.2);
-      // }
-      // &:-webkit-scrollbar-track {/*婊氬姩鏉¢噷闈㈣建閬�*/
-      //     box-shadow: inset 0 0 5px rgba(0,0,0,0.2);
-      //     border-radius: 0;
-      //     background: rgba(0,0,0,0.1);
-      // }
     }
   }
+}
+.content-box.collapsed {
+  max-width: calc(100% - 80px);
 }
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
index 71cc3ab..e13361a 100644
--- a/src/index.js
+++ b/src/index.js
@@ -6,6 +6,7 @@
 import * as serviceWorker from './serviceWorker'
 import 'antd/dist/antd.css'
 import '@/assets/css/main.scss'
+import '@/assets/css/action.scss'
 
 const render  = Component => {
   ReactDOM.render(
diff --git a/src/locales/en-US/main.js b/src/locales/en-US/main.js
new file mode 100644
index 0000000..cc8e0c9
--- /dev/null
+++ b/src/locales/en-US/main.js
@@ -0,0 +1,7 @@
+export default {
+  'main.search': 'Search',
+  'main.reset': 'Reset',
+  'main.copy.success': 'Copy success',
+  'main.pagination.of': 'of',
+  'main.pagination.items': 'items'
+}
\ No newline at end of file
diff --git a/src/locales/zh-CN/main.js b/src/locales/zh-CN/main.js
new file mode 100644
index 0000000..2018b82
--- /dev/null
+++ b/src/locales/zh-CN/main.js
@@ -0,0 +1,7 @@
+export default {
+  'main.search': '鎼滅储',
+  'main.reset': '閲嶇疆',
+  'main.copy.success': '澶嶅埗鎴愬姛',
+  'main.pagination.of': '鍏�',
+  'main.pagination.items': '鏉�'
+}
\ No newline at end of file
diff --git a/src/tabviews/commontable/index.jsx b/src/tabviews/commontable/index.jsx
index 0acf50f..fc17a2b 100644
--- a/src/tabviews/commontable/index.jsx
+++ b/src/tabviews/commontable/index.jsx
@@ -1,65 +1,158 @@
 import React, {Component} from 'react'
-import { Form, Row, Col, Input, Button } from 'antd'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { BackTop, Button, message } from 'antd'
+import Api from '@/api'
+import MainSearch from '@/components/mainSearch'
+import MainAction from '@/components/mainAction'
+import MainTable from '@/components/mainTable'
+import Loading from '@/components/loading'
+import zhCN from '@/locales/zh-CN/main.js'
+import enUS from '@/locales/en-US/main.js'
 import './index.scss'
 
-class AdvancedSearchForm extends React.Component {
+export default class NormalTable extends Component {
+  static propTpyes = {
+    MenuNo: PropTypes.string // 鏍囩椤垫暟缁�
+  }
+
   state = {
-
-  }
-
-  getFields() {
-    const { getFieldDecorator } = this.props.form
-    const children = []
-    for (let i = 0; i < 10; i++) {
-      children.push(
-        <Col span={6} key={i}>
-          <Form.Item label={`鑿滃崟鍚嶇О寮�濮媊}>
-            {getFieldDecorator(`field-${i}`)(<Input placeholder="placeholder" />)}
-          </Form.Item>
-        </Col>
-      )
+    dict: (!sessionStorage.getItem('lang') || sessionStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS,
+    searchlist: null,
+    actions: null,
+    columns: null,
+    select: null,
+    data: null,
+    total: 0,
+    loading: true,
+    param: {
+      pageIndex: 1,
+      pageSize: 10,
+      orderColumn: '',
+      orderType: '',
+      search: ''
     }
-    return children
   }
 
-  handleSearch = e => {
-    e.preventDefault()
-    this.props.form.validateFields((err, values) => {
-      console.log('Received values of form: ', values)
+  async loadconfig () {
+    // 鑾峰彇涓昏彍鍗�
+    let result = await Api.getMainConfigsData(this.props.MenuNo)
+    if (result.status) {
+      let newconfig = {}
+      if (result.searches && result.searches.length > 0) {
+        newconfig.searchlist = result.searches.map(search => {
+          search.DynOptions = search.DynOptions ? JSON.parse(search.DynOptions) : ''
+          return search
+        })
+      }
+      if (result.actions && result.actions.length > 0) {
+        newconfig.actions = result.actions.map(action => {
+          return action
+        })
+      }
+      if (result.columns && result.columns.length > 0) {
+        newconfig.columns = result.columns.map(column => {
+          return column
+        })
+        // newconfig.columns.length = 4
+      }
+      newconfig.select = result.select
+      this.setState(newconfig)
+    }
+  }
+
+  async loadmaindata (pageIndex = 1, pageSize = 10, orderColumn = '', orderType = '', search = '') {
+    // 鑾峰彇鍒楄〃鏁版嵁
+    let result = await Api.getMainTableData(this.props.MenuNo, pageIndex, pageSize, orderColumn, orderType, search)
+    if (result.status) {
+      this.setState({
+        data: result.data.map((item, index) => {
+          item.key = index
+          item.rows = item.mkrows
+          return item
+        }),
+        total: result.total,
+        loading: false
+      })
+    }
+  }
+
+  refreshbysearch = (searches) => {
+    console.log(searches)
+    this.loadmaindata(this.state.param.pageIndex, this.state.param.pageSize, this.state.param.orderColumn, this.state.param.orderType, searches)
+    let param = Object.assign({}, this.state.param, {
+      search: searches
+    })
+    this.setState({
+      loading: true,
+      param: param
+    })
+    // window.print()
+  }
+
+  refreshbytable = (pagination, filters, sorter) => {
+    console.log(filters)
+    if (sorter.order) {
+      let _chg = {
+        ascend: 'asc',
+        descend: 'desc'
+      }
+      sorter.order = _chg[sorter.order]
+    }
+    this.loadmaindata(pagination.current, pagination.pageSize, sorter.field, sorter.order, this.state.param.search)
+    let param = Object.assign({}, this.state.param, {
+      pageIndex: pagination.current,
+      pageSize: pagination.pageSize,
+      orderColumn: sorter.field,
+      orderType: sorter.order
+    })
+    this.setState({
+      loading: true,
+      param: param
     })
   }
 
-  handleReset = () => {
-    this.props.form.resetFields()
+  copyMenuNo = (e) => {
+    e.stopPropagation()
+    let oInput = document.createElement('input')
+    oInput.value = this.props.MenuNo
+    document.body.appendChild(oInput)
+    oInput.select()
+    document.execCommand('Copy')
+    oInput.className = 'oInput'
+    oInput.style.display='none'
+    message.success(this.state.dict['main.copy.success'])
+  }
+
+  UNSAFE_componentWillMount () {
+    // 缁勪欢鍔犺浇鏃讹紝鑾峰彇鑿滃崟鏁版嵁
+    this.loadconfig()
+    this.loadmaindata()
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  componentDidMount () {
+    // console.log(this.props.MenuNo)
   }
 
   render() {
     return (
-      <Form className="ant-advanced-search-form" onSubmit={this.handleSearch}>
-        <Row gutter={24}>{this.getFields()}</Row>
-        <Row>
-          <Col span={24} style={{ textAlign: 'right' }}>
-            <Button type="primary" htmlType="submit">
-              鎼滅储
-            </Button>
-            <Button style={{ marginLeft: 8 }} onClick={this.handleReset}>
-              閲嶇疆
-            </Button>
-          </Col>
-        </Row>
-      </Form>
-    )
-  }
-}
-
-const WrappedAdvancedSearchForm = Form.create()(AdvancedSearchForm)
-
-export default class NormalTable extends Component {
-  render() {
-    return (
-      <div>
-        <WrappedAdvancedSearchForm />
-        <div className="search-result-list">Search Result List</div>
+      <div className="commontable">
+        {!this.state.searchlist && <Loading />}
+        {this.state.searchlist && <MainSearch refreshdata={this.refreshbysearch} searchlist={this.state.searchlist} dict={this.state.dict} />}
+        {this.state.actions && <MainAction actions={this.state.actions} dict={this.state.dict} />}
+        {this.state.columns && <MainTable refreshdata={this.refreshbytable} columns={this.state.columns} data={this.state.data} select={this.state.select} total={this.state.total} loading={this.state.loading} dict={this.state.dict} />}
+        <Button className="main-copy" icon="copy" onClick={this.copyMenuNo} shape="circle" />
+        <BackTop>
+          <div className="ant-back-top">
+            <div className="ant-back-top-content">
+              <div className="ant-back-top-icon"></div>
+            </div>
+          </div>
+        </BackTop>
       </div>
     )
   }
diff --git a/src/tabviews/commontable/index.scss b/src/tabviews/commontable/index.scss
index 4658327..2c3edaa 100644
--- a/src/tabviews/commontable/index.scss
+++ b/src/tabviews/commontable/index.scss
@@ -1,18 +1,17 @@
-.ant-advanced-search-form {
-  padding: 0px 24px 20px;
-  border-bottom: 1px solid #d9d9d9;
-  // border-radius: 6px;
+.commontable {
+  min-height: calc(100vh - 110px);
+  .main-copy {
+    position: fixed;
+    bottom: 75px;
+    right: 30px;
+    width: 40px;
+    height: 40px;
+    i {
+      font-size: 18px;
+    }
+  }
 }
-
-.ant-advanced-search-form .ant-form-item {
-  display: flex;
-  margin-bottom: 10px;
-}
-
-.ant-advanced-search-form .ant-form-item-control-wrapper {
-  flex: 1;
-}
-
-.ant-form-item-label {
-  width: 100px;
+.ant-back-top {
+  bottom: 30px;
+  right: 30px;
 }
\ No newline at end of file
diff --git a/src/utils/utils.js b/src/utils/utils.js
new file mode 100644
index 0000000..a126695
--- /dev/null
+++ b/src/utils/utils.js
@@ -0,0 +1,78 @@
+export default class Utils {
+  /**
+   * @description 鐢熸垚32浣島uid string + 鏃堕棿
+   * @return {String}  uuid
+   */
+  static getuuid () {
+    let uuid = []
+    let timestamp = new Date().getTime()
+    let options = '0123456789abcdefghigklmnopqrstuv'
+    for (let i = 0; i < 19; i++) {
+      uuid.push(options.substr(Math.floor(Math.random() * 0x20), 1))
+    }
+    uuid = uuid.join('') + timestamp
+    return uuid
+  }
+
+  /**
+   * @description 鐢熸垚GUID
+   * @return {String}  guid
+   */
+  static getguid () {
+    // 浜х敓涓�涓柊鐨凣UID鍊�
+    let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
+      let r = Math.random() * 16 | 0
+      // eslint-disable-next-line
+      let v = (c === 'x') ? r : (r & 0x3 | 0x8)
+      return v.toString(16)
+    })
+    return uuid
+  }
+
+  /**
+   * @description 鎷兼帴鎼滅储鏉′欢
+   * @param {Array}   searches     鎼滅储鏉′欢
+   * @return {String}  searchText  鎷兼帴缁撴灉
+   * ---杩囨护鏉′欢锛堟湭浣跨敤锛�---
+   * greaterorequal: ' >= '
+   * lessorequal: ' <= '
+   * like: ' LIKE '
+   * less: ' < '
+   * greater: ' > '
+   * equal: ' = '
+   * notlike: ' notlike '
+   * in: ' in '
+   * notin: ' notin '
+   * leftlike/startwith
+   * rightlike/endwith
+   * rightnotlike/endnotwith
+   * leftnotlike/startnotwith
+   */
+  static jointsearchkey (searches) {
+    if (!searches || searches.length === 0) return ''
+    let searchText = ''
+    searches.forEach(item => {
+      if (!item.value) return
+      // eslint-disable-next-line
+      searchText += (searchText !== '' ? ' ' + 'AND' + ' ' : '')
+      if (item.type === 'text') {
+        let options = item.key.split(',').map(op => {
+          // equal鏃朵笉娣诲姞%
+          // eslint-disable-next-line
+          let str = item.op === 'equal' ? '' : '%'
+          // eslint-disable-next-line
+          return op + ' ' + item.op + ' ' + '"' + str + item.value + str + '"'
+        })
+        // eslint-disable-next-line
+        searchText += '(' + options.join(' ' + 'OR' + ' ') + ')'
+      } else if (item.type === 'date') {
+        // eslint-disable-next-line
+        searchText += '(' + item.key + ' ' + item.op + ' ' + '"' + item.value + '")'
+      } else {
+        // eslint-disable-next-line
+        searchText += '(' + item.key + ' ' + item.op + ' ' + '"' + item.value + '")'
+      }
+    })
+    return searchText
+  }
+}
\ No newline at end of file
diff --git a/src/views/main/index.scss b/src/views/main/index.scss
index b97fd7f..0493020 100644
--- a/src/views/main/index.scss
+++ b/src/views/main/index.scss
@@ -1,5 +1,5 @@
 .flex-container {
   display: flex;
   flex: auto;
-  height: 100%;
+  min-height: 100%;
 }
\ No newline at end of file

--
Gitblit v1.8.0