king
2019-09-20 4e837faa0307fda4d0d3bd463c88a7ef43817443
2019-09-20update
12个文件已修改
10个文件已添加
961 ■■■■■ 已修改文件
package.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/index.js 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/css/action.scss 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/css/main.scss 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/index.jsx 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/loading/index.jsx 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/mainAction/index.jsx 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/mainAction/index.scss 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/mainSearch/index.jsx 211 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/mainSearch/index.scss 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/mainTable/index.jsx 119 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/mainTable/index.scss 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/resetpwd/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tabview/index.jsx 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tabview/index.scss 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/index.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/en-US/main.js 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/zh-CN/main.js 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/commontable/index.jsx 185 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/commontable/index.scss 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils.js 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/main/index.scss 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
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",
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()
src/assets/css/action.scss
New file
@@ -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;
}
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;
}
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>
    )
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" />
    )
  }
}
src/components/mainAction/index.jsx
New file
@@ -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
src/components/mainAction/index.scss
New file
@@ -0,0 +1,8 @@
.button-list {
  padding: 10px 20px 5px;
  background: #ffffff;
  button {
    margin-right: 15px;
    margin-bottom: 10px;
  }
}
src/components/mainSearch/index.jsx
New file
@@ -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)
src/components/mainSearch/index.scss
New file
@@ -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;
  }
}
src/components/mainTable/index.jsx
New file
@@ -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>
    )
  }
}
src/components/mainTable/index.scss
New file
@@ -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);
  }
}
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 })
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,7 +118,8 @@
  render () {
    return (
      <section className="flex-container content-box">
      <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}>
@@ -127,6 +144,7 @@
            </Tabs>
          }
        </div>
        </ConfigProvider>
      </section>
    )
  }
@@ -135,6 +153,7 @@
const mapStateToProps = (state) => {
  return {
    tabviews: state.tabviews,
    collapse: state.collapse,
    isiframe: state.isiframe
  }
}
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);
}
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(
src/locales/en-US/main.js
New file
@@ -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'
}
src/locales/zh-CN/main.js
New file
@@ -0,0 +1,7 @@
export default {
  'main.search': '搜索',
  'main.reset': '重置',
  'main.copy.success': '复制成功',
  'main.pagination.of': '共',
  'main.pagination.items': '条'
}
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 = {
    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: ''
    }
  }
  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>
      )
  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
        })
    }
    return children
      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)
    }
  }
  handleSearch = e => {
    e.preventDefault()
    this.props.form.validateFields((err, values) => {
      console.log('Received values of form: ', values)
  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>
    )
  }
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;
}
src/utils/utils.js
New file
@@ -0,0 +1,78 @@
export default class Utils {
  /**
   * @description 生成32位uuid 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 () {
    // 产生一个新的GUID值
    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
  }
}
src/views/main/index.scss
@@ -1,5 +1,5 @@
.flex-container {
  display: flex;
  flex: auto;
  height: 100%;
  min-height: 100%;
}