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