import React, {Component} from 'react'
|
import PropTypes from 'prop-types'
|
import md5 from 'md5'
|
import { Table, message, Affix, Button, Typography, Modal } from 'antd'
|
import './index.scss'
|
|
const { Paragraph } = Typography
|
|
export default class MainTable extends Component {
|
static defaultProps = {
|
pagination: true,
|
total: 0,
|
menuType: 'normal'
|
}
|
|
static propTpyes = {
|
menuType: PropTypes.any, // 三级菜单类型,HS需特殊处理
|
tableId: PropTypes.string, // 列表Id
|
dict: PropTypes.object, // 字典项
|
MenuID: PropTypes.string, // 菜单Id
|
setting: PropTypes.object, // 表格全局设置:tableType(表格是否可选、单选、多选)、columnfixed(列固定)、actionfixed(按钮固定)
|
pickup: PropTypes.any, // 数据收起
|
columns: PropTypes.array, // 表格列
|
data: PropTypes.any, // 表格数据
|
total: PropTypes.any, // 总数
|
loading: PropTypes.bool, // 表格加载中
|
refreshdata: PropTypes.func, // 表格中排序列、页码的变化时刷新
|
buttonTrigger: PropTypes.func, // 表格中按钮触发操作
|
linkTrigger: PropTypes.func, // 字段透视
|
handleTableId: PropTypes.func, // 数据切换
|
pagination: PropTypes.any // 数据分页
|
}
|
|
state = {
|
selectedRowKeys: [], // 表格中选中行
|
pageIndex: 1, // 初始页面索引
|
pageSize: 10, // 每页数据条数
|
columns: null, // 显示列
|
imgShow: false, // 图片放大模态框
|
imgSrc: '' // 图片路径
|
}
|
|
UNSAFE_componentWillMount () {
|
const { columns, menuType } = this.props
|
let _columns = []
|
|
columns.forEach((item, index) => {
|
if (item.hidden === true || item.Hide === 'true') return
|
|
if (window.GLOB.dataFormat && menuType !== 'HS' && !Math.floor(Math.random() * 5)) {
|
item.format = true
|
}
|
|
let cell = {
|
align: item.Align,
|
dataIndex: item.field || item.uuid,
|
title: item.label,
|
sorter: item.field && item.IsSort === 'true',
|
width: item.Width || 120,
|
render: (text, record) => {
|
return this.getContent(item, record)
|
}
|
}
|
|
if (item.fixed === true || item.fixed === 'true') {
|
if (index < columns.length / 2) {
|
cell.fixed = 'left'
|
} else {
|
cell.fixed = 'right'
|
}
|
}
|
|
_columns.push(cell)
|
})
|
|
this.setState({
|
columns: _columns
|
})
|
}
|
|
triggerLink = (item, record) => {
|
let tabmenu = item.linkThdMenu
|
let iframes = ['Main/Index', 'bda/rdt', 'Home/rdt']
|
|
if (tabmenu.LinkUrl === 'CommonTable') {
|
tabmenu.type = 'CommonTable'
|
} else if (tabmenu.LinkUrl === 'DataManage') {
|
tabmenu.type = 'DataManage'
|
} else if (tabmenu.LinkUrl && iframes.includes(tabmenu.LinkUrl.split('?')[0])) {
|
tabmenu.type = 'iframe'
|
}
|
|
if (tabmenu.type !== 'iframe') {
|
try {
|
tabmenu.PageParam = JSON.parse(tabmenu.PageParam)
|
} catch (e) {
|
tabmenu.PageParam = {}
|
}
|
tabmenu.type = tabmenu.PageParam.Template || tabmenu.type
|
}
|
|
tabmenu.param = {
|
searchkey: item.field,
|
searchval: record[item.field] || ''
|
}
|
|
this.props.linkTrigger(tabmenu)
|
}
|
|
getContent = (item, record) => {
|
if (item.type === 'text') {
|
let content = ''
|
let match = false
|
if (item.field && record.hasOwnProperty(item.field)) {
|
content = `${record[item.field]}`
|
}
|
|
if (content && item.matchVal && content.indexOf(item.matchVal) > 0) {
|
match = true
|
}
|
|
content = (item.prefix || '') + content + (item.postfix || '')
|
|
if (item.format) {
|
content = md5(content)
|
}
|
|
if (item.linkThdMenu) {
|
return (
|
<div className={match ? item.color : ''}>
|
<div className="background link-menu" onDoubleClick={() => this.triggerLink(item, record)}></div>
|
<div className="content link-menu" style={{ minWidth: (item.Width || 120) + 'px' }} onDoubleClick={() => this.triggerLink(item, record)}>
|
{content}
|
</div>
|
</div>
|
)
|
} else {
|
return (
|
<div className={match ? item.color : ''}>
|
<div className="background"></div>
|
<div className="content" style={{ minWidth: (item.Width || 120) + 'px' }}>
|
{content}
|
</div>
|
</div>
|
)
|
}
|
} else if (item.type === 'number') {
|
let content = ''
|
let match = false
|
|
if (item.field && record.hasOwnProperty(item.field)) {
|
try {
|
content = parseFloat(record[item.field])
|
if (isNaN(content)) {
|
content = ''
|
}
|
} catch {
|
content = ''
|
}
|
}
|
|
if (content !== '') {
|
if (item.match && item.matchVal) {
|
if (item.match === '>') {
|
if (content > item.matchVal) {
|
match = true
|
}
|
} else if (item.match === '<') {
|
if (content < item.matchVal) {
|
match = true
|
}
|
} else if (item.match === '>=') {
|
if (content >= item.matchVal) {
|
match = true
|
}
|
} else if (item.match === '<=') {
|
if (content <= item.matchVal) {
|
match = true
|
}
|
}
|
}
|
|
if (item.format === 'percent') {
|
content = content * 100
|
}
|
|
content = content.toFixed(item.decimal || 0)
|
|
if (item.format === 'thdSeparator') {
|
content = content.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
|
}
|
|
content = (item.prefix || '') + content + (item.postfix || '')
|
}
|
|
if (item.format) {
|
content = md5(content)
|
}
|
|
if (item.linkThdMenu) {
|
return (
|
<div className={match ? item.color : ''}>
|
<div className="background link-menu" onDoubleClick={() => this.triggerLink(item, record)}></div>
|
<div className="content link-menu" style={{ minWidth: (item.Width || 120) + 'px' }} onDoubleClick={() => this.triggerLink(item, record)}>
|
{content}
|
</div>
|
</div>
|
)
|
} else {
|
return (
|
<div className={match ? item.color : ''}>
|
<div className={'background'}></div>
|
<div className="content" style={{ minWidth: (item.Width || 120) + 'px' }}>
|
{content}
|
</div>
|
</div>
|
)
|
}
|
} else if (item.type === 'picture') {
|
let photos = ''
|
if (item.field && record.hasOwnProperty(item.field)) {
|
photos = record[item.field].split(',')
|
} else {
|
photos = ''
|
}
|
|
let maxHeight = item.maxHeight || 128
|
return (
|
<div className="picture-col" style={{ minWidth: (item.Width || 120) + 'px' }}>
|
{photos && photos.map((url, i) => {
|
if (item.scale === 'true') {
|
return <img style={{maxHeight: maxHeight}} className="image-scale" onClick={this.imgScale} key={`${i}`} src={url} alt=""/>
|
} else {
|
return <img style={{maxHeight: maxHeight}} key={`${i}`} src={url} alt=""/>
|
}
|
})}
|
</div>
|
)
|
} else if (item.type === 'textarea') {
|
let content = ''
|
let match = false
|
if (item.field && record.hasOwnProperty(item.field)) {
|
content = `${record[item.field]}`
|
}
|
|
if (content && item.matchVal && content.indexOf(item.matchVal) > 0) {
|
match = true
|
}
|
|
content = (item.prefix || '') + content + (item.postfix || '')
|
|
if (item.format) {
|
content = md5(content)
|
}
|
|
return (
|
<div className={match ? item.color : ''}>
|
<div className="background"></div>
|
<div className="content" style={{ minWidth: (item.Width || 120) + 'px' }}>
|
{content ? <Paragraph copyable ellipsis={{ rows: 3, expandable: true }}>{content}</Paragraph> : null }
|
</div>
|
</div>
|
)
|
} else if (item.type === 'action') {
|
return (
|
<div className={item.style} style={{ minWidth: (item.Width || 120) + 'px' }}>
|
{item.operations.map(btn => {
|
return <Button
|
className={'mk-btn mk-' + btn.class}
|
icon={btn.icon}
|
key={btn.uuid}
|
onClick={(e) => {this.actionTrigger(e, btn, record)}}
|
>{btn.label}</Button>
|
})}
|
</div>
|
)
|
} else if (item.type === 'colspan') {
|
if (item.subColumn.length === 0) return ''
|
let ordertype = item.order
|
let contents = []
|
let images = []
|
|
item.subColumn.forEach(col => {
|
if (!col.field || !record.hasOwnProperty(col.field)) return
|
|
if (col.type === 'number') {
|
let content = ''
|
try {
|
content = parseFloat(record[col.field])
|
if (isNaN(content)) {
|
content = ''
|
}
|
} catch {
|
content = ''
|
}
|
|
if (content !== '') {
|
if (item.format === 'percent') {
|
content = content * 100
|
}
|
|
content = content.toFixed(col.decimal || 0)
|
|
if (col.format === 'thdSeparator') {
|
content = content.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
|
}
|
|
content = (col.prefix || '') + content + (col.postfix || '')
|
}
|
|
if (item.format) {
|
content = md5(content)
|
}
|
|
contents.push(content)
|
} else if (col.type === 'picture') {
|
let photos = []
|
try {
|
photos = record[col.field].split(',')
|
} catch {
|
photos = []
|
}
|
|
photos.forEach(photo => {
|
images.push({url: photo, scale: col.scale === 'true', maxHeight: col.maxHeight || 128})
|
})
|
} else {
|
let content = record[col.field]
|
|
if (content !== '') {
|
content = (col.prefix || '') + record[col.field] + (col.postfix || '')
|
}
|
|
if (item.format) {
|
content = md5(content)
|
}
|
|
contents.push(content)
|
}
|
})
|
|
if (images.length > 0 && ['vertical2', 'horizontal', 'vertical'].includes(ordertype)) {
|
ordertype = 'topPicBottomText'
|
}
|
|
return (
|
<div>
|
<div className="content" style={{ minWidth: (item.Width || 120) + 'px' }}>
|
{this.getCospanContent(ordertype, contents, images)}
|
</div>
|
</div>
|
)
|
}
|
}
|
|
getCospanContent = (type, contents, images) => {
|
if (type === 'vertical') {
|
return contents.map((content, index) => {
|
return (<p key={index}>{content}</p>)
|
})
|
} else if (type === 'horizontal') {
|
return contents.map((content, index) => {
|
return (<span key={index}>{content}</span>)
|
})
|
} else if (type === 'vertical2') {
|
return (
|
<div className="content-fence">
|
<div className="content-fence-left">
|
{contents.map((content, index) => {
|
if (index % 2 === 0) {
|
return (<p key={index}>{content}</p>)
|
} else {
|
return ''
|
}
|
})}
|
</div>
|
<div className="content-fence-right">
|
{contents.map((content, index) => {
|
if (index % 2 === 1) {
|
return (<p key={index}>{content}</p>)
|
} else {
|
return ''
|
}
|
})}
|
</div>
|
</div>
|
)
|
} else if (type === 'topPicBottomText') {
|
return (
|
<div className="content-fence">
|
<div className="content-fence-top">
|
{images.map((_img, index) => {
|
if (!_img.url) return ''
|
if (_img.scale) {
|
return <img style={{maxHeight: _img.maxHeight}} className="image-scale" onClick={this.imgScale} key={`${index}`} src={_img.url} alt=""/>
|
} else {
|
return (<img style={{maxHeight: _img.maxHeight}} key={`${index}`} src={_img.url} alt=""/>)
|
}
|
})}
|
</div>
|
<div className="content-fence-bottom">
|
{contents.map((content, index) => {
|
return (<p key={index}>{content}</p>)
|
})}
|
</div>
|
</div>
|
)
|
} else if (type === 'leftPicRightText') {
|
return (
|
<div className="content-fence">
|
<div className="content-fence-left">
|
{images.map((_img, index) => {
|
if (!_img.url) return ''
|
if (_img.scale) {
|
return <img style={{maxHeight: _img.maxHeight}} className="image-scale" onClick={this.imgScale} key={`${index}`} src={_img.url} alt=""/>
|
} else {
|
return (<img style={{maxHeight: _img.maxHeight}} key={`${index}`} src={_img.url} alt=""/>)
|
}
|
})}
|
</div>
|
<div className="content-fence-right">
|
{contents.map((content, index) => {
|
return (<p key={index}>{content}</p>)
|
})}
|
</div>
|
</div>
|
)
|
}
|
}
|
|
imgScaleClose = () => {
|
this.setState({
|
imgShow: false
|
})
|
}
|
imgScale = (e) => {
|
if (e.target.nodeName === 'IMG') {
|
this.setState({
|
imgShow: true,
|
imgSrc: e.target.src
|
})
|
}
|
}
|
|
actionTrigger = (e, btn, record) => {
|
e.stopPropagation()
|
this.props.buttonTrigger(btn, record)
|
}
|
|
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 => {
|
let index = ''
|
if (selectedRowKeys.length > 0) {
|
index = selectedRowKeys[selectedRowKeys.length - 1]
|
}
|
|
this.changedata(index)
|
|
this.setState({ selectedRowKeys })
|
}
|
|
changeRow = (record, index) => {
|
// 点击整行,触发切换,判断是否可选,单选或多选,进行对应操作
|
if (!this.props.setting.tableType || this.props.pickup) return
|
|
let newkeys = JSON.parse(JSON.stringify(this.state.selectedRowKeys))
|
let _re = newkeys.includes(index)
|
|
if (this.props.setting.tableType === 'radio') {
|
this.changedata(index)
|
this.setState({ selectedRowKeys: [index] })
|
} else {
|
if (_re) {
|
newkeys = newkeys.filter(item => item !== index)
|
this.changedata('')
|
} else {
|
newkeys.push(index)
|
this.changedata(index)
|
}
|
|
this.setState({ selectedRowKeys: newkeys })
|
}
|
}
|
|
changeTable = (pagination, filters, sorter) => {
|
this.setState({
|
pageIndex: pagination.current,
|
pageSize: pagination.pageSize,
|
selectedRowKeys: []
|
})
|
this.props.refreshdata(pagination, filters, sorter)
|
}
|
|
changedata = (index) => {
|
const { data, setting } = this.props
|
|
if (!this.props.tableId) return
|
|
let _id = ''
|
let _data = ''
|
|
if (data && data.length > 0 && index !== '') {
|
_id = data[index][setting.primaryKey] || ''
|
_data = data[index] || ''
|
}
|
|
this.props.handleTableId(this.props.tableId, _id, _data)
|
}
|
|
resetTable = () => {
|
this.setState({
|
pageIndex: 1,
|
selectedRowKeys: []
|
})
|
}
|
|
render() {
|
const { setting, pickup, pagination } = this.props
|
let { selectedRowKeys } = this.state
|
|
// 设置表格选择属性:单选、多选、不可选
|
let rowSelection = null
|
if (setting.tableType) {
|
rowSelection = {
|
selectedRowKeys,
|
type: (setting.tableType === 'radio') ? 'radio' : 'checkbox',
|
onChange: this.onSelectChange
|
}
|
}
|
|
// 表格头部固定于顶部时,判断距顶部高度
|
let offset = null
|
if (this.props.tableId === 'mainTable' && setting.columnfixed) {
|
if (!setting.actionfixed) {
|
offset = 48
|
} else {
|
let box = document.getElementById(this.props.MenuID + 'mainaction')
|
if (box) {
|
offset = 48 + box.offsetHeight
|
} else {
|
offset = 105
|
}
|
}
|
}
|
|
// 数据收起时,过滤已选数据
|
let _data = this.props.data ? this.props.data : []
|
|
if (pickup) {
|
_data = _data.filter((item, index) => selectedRowKeys.includes(index))
|
}
|
|
let _pagination = false
|
if (pagination) {
|
_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']}`
|
}
|
}
|
// rowClassName={(record) => record.$className || ''}
|
|
return (
|
<div className="normal-data-table">
|
{offset && <Affix offsetTop={offset} className="fix-header">
|
<Table
|
size="middle"
|
bordered={true}
|
rowSelection={rowSelection}
|
columns={this.state.columns.map(column => {
|
return {
|
align: column.align,
|
dataIndex: column.dataIndex,
|
title: column.title,
|
width: column.width
|
}
|
})}
|
/>
|
</Affix>}
|
<Table
|
size="middle"
|
bordered={true}
|
rowSelection={rowSelection}
|
columns={this.state.columns}
|
dataSource={_data}
|
loading={this.props.loading}
|
scroll={{ x: '100%', y: false }}
|
onRow={(record, index) => {
|
return {
|
onClick: () => {this.changeRow(record, index)}
|
}
|
}}
|
onChange={this.changeTable}
|
pagination={_pagination}
|
/>
|
<Modal
|
className="image-scale-modal"
|
visible={this.state.imgShow}
|
width="70vw"
|
maskClosable={true}
|
onCancel={this.imgScaleClose}
|
title={this.props.dict['main.form.picture.check']}
|
footer={[<span key="close" onClick={this.imgScaleClose}>{this.props.dict['main.close']}</span>]}
|
destroyOnClose
|
>
|
<img style={{maxWidth:'100%'}} src={this.state.imgSrc} alt="" />
|
</Modal>
|
</div>
|
)
|
}
|
}
|