import React, {Component} from 'react'
|
import PropTypes from 'prop-types'
|
import { is, fromJS } from 'immutable'
|
import { Icon, Card, Dropdown, Menu, Spin, Empty, Tabs } from 'antd'
|
|
import './index.scss'
|
|
const { TabPane } = Tabs
|
|
class CardCell extends Component {
|
static propTpyes = {
|
card: PropTypes.object,
|
data: PropTypes.object,
|
selectKey: PropTypes.string,
|
colMap: PropTypes.any,
|
triggerBtn: PropTypes.func,
|
switchCard: PropTypes.func
|
}
|
|
state = {
|
card: null,
|
extra: null,
|
actions: null
|
}
|
|
UNSAFE_componentWillMount () {
|
const { card } = this.props
|
|
let extra = null
|
if (card.header && card.header.actions) {
|
let actions = card.header.actions.map(item => {
|
let _action = null
|
if (card.header.show === 'icon') {
|
_action = <span className="action-cell" onClick={() => this.triggerAction(item)} key={item.uuid}><Icon type={item.icon || 'dash'} /></span>
|
} else if (card.bottom.show === 'text') {
|
_action = <span className="action-cell" onClick={() => this.triggerAction(item)} key={item.uuid}>{item.label}</span>
|
} else {
|
_action = <span className="action-cell" onClick={() => this.triggerAction(item)} key={item.uuid}><Icon type={item.icon || 'dash'} /> {item.label}</span>
|
}
|
|
return _action
|
})
|
if (actions.length === 1) {
|
extra = actions[0]
|
} else {
|
extra = <Dropdown overlay={
|
<Menu>{actions.map((item, i) => <Menu.Item key={i}> {item} </Menu.Item>)}</Menu>
|
} placement="bottomRight">
|
Action
|
</Dropdown>
|
}
|
}
|
|
let _actions = null
|
if (card.bottom && card.bottom.actions) {
|
_actions = card.bottom.actions.map(item => {
|
let _action = null
|
if (card.bottom.show === 'icon') {
|
_action = <span className="action-cell" onClick={() => this.triggerAction(item)} key={item.uuid}><Icon type={item.icon || 'dash'} /></span>
|
} else if (card.bottom.show === 'text') {
|
_action = <span className="action-cell" onClick={() => this.triggerAction(item)} key={item.uuid}>{item.label}</span>
|
} else {
|
_action = <span className="action-cell" onClick={() => this.triggerAction(item)} key={item.uuid}><Icon type={item.icon || 'dash'} /> {item.label}</span>
|
}
|
|
return _action
|
})
|
}
|
|
this.setState({
|
actions: _actions,
|
extra: extra
|
})
|
}
|
|
shouldComponentUpdate (nextProps, nextState) {
|
return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
|
}
|
|
triggerAction = (btn) => {
|
this.props.triggerBtn(btn, [this.props.data])
|
}
|
|
getMark = (record, marks) => {
|
const { colMap } = this.props
|
let className = ''
|
let isIcon = false
|
let position = 'back'
|
let icon = ''
|
|
colMap && marks.some(mark => {
|
let originType = colMap.get(mark.field).type
|
|
let originVal = record.hasOwnProperty(mark.field) ? record[mark.field] : ''
|
let contrastVal = ''
|
if (mark.contrastType === 'static') {
|
contrastVal = mark.contrastValue
|
} else {
|
contrastVal = record.hasOwnProperty(mark.contrastField) ? record[mark.contrastField] : ''
|
}
|
|
if (originType === 'text') {
|
originVal = '' + originVal
|
contrastVal = '' + contrastVal
|
} else if (originType === 'number' && originVal !== '' && contrastVal !== '') {
|
try {
|
originVal = parseFloat(originVal)
|
contrastVal = parseFloat(contrastVal)
|
if (isNaN(originVal) || isNaN(contrastVal)) {
|
originVal = ''
|
}
|
} catch {
|
originVal = ''
|
}
|
}
|
|
if (originVal === '' || contrastVal === '') return false
|
|
if (mark.match === '=' && originVal === contrastVal) {
|
className = mark.color[1]
|
} else if (mark.match === 'like' && originVal.indexOf(contrastVal) > -1) {
|
className = mark.color[1]
|
} else if (mark.match === '>' && originVal > contrastVal) {
|
className = mark.color[1]
|
} else if (mark.match === '<' && originVal < contrastVal) {
|
className = mark.color[1]
|
}
|
|
if (!className) return false
|
|
if (mark.signType === 'font') {
|
className = 'font ' + className
|
} else if (mark.signType === 'icon') {
|
isIcon = true
|
if (mark.position === 'front') {
|
position = 'front'
|
}
|
icon = <Icon className={'font ' + className} type={mark.icon} />
|
className = ''
|
}
|
|
return true
|
})
|
|
return {
|
className: className,
|
isIcon: isIcon,
|
position: position,
|
icon: icon
|
}
|
}
|
|
getContent = (col) => {
|
const { data } = this.props
|
|
if (col.type === 'text') {
|
let content = ''
|
let className = ''
|
if (data.hasOwnProperty(col.field)) {
|
content = `${data[col.field]}`
|
}
|
|
content = content ? (col.prefix || '') + content + (col.postfix || '') : ''
|
|
if (col.marks) {
|
let result = this.getMark(data, col.marks)
|
|
if (result.className) {
|
className = result.className
|
} else if (result.isIcon) {
|
if (result.position === 'front') {
|
content = <span>{result.icon} {content}</span>
|
} else {
|
content = <span>{content} {result.icon}</span>
|
}
|
}
|
}
|
|
return (
|
<div className={className}>
|
{content}
|
</div>
|
)
|
} else if (col.type === 'number') {
|
let content = ''
|
let className = ''
|
|
if (data.hasOwnProperty(col.field)) {
|
try {
|
content = parseFloat(data[col.field])
|
if (isNaN(content)) {
|
content = ''
|
}
|
} catch {
|
content = ''
|
}
|
}
|
|
if (content !== '') {
|
if (col.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 (col.marks) {
|
let result = this.getMark(data, col.marks)
|
|
if (result.className) {
|
className = result.className
|
} else if (result.isIcon) {
|
if (result.position === 'front') {
|
content = <span>{result.icon} {content}</span>
|
} else {
|
content = <span>{content} {result.icon}</span>
|
}
|
}
|
}
|
|
return (
|
<div className={className}>
|
{content}
|
</div>
|
)
|
}
|
}
|
|
getAvatar = () => {
|
const { card, data } = this.props
|
|
if (card.avatar.type === 'picture') {
|
if (card.avatar.field && data.hasOwnProperty(card.avatar.field) && data[card.avatar.field]) {
|
return <img src={data[card.avatar.field]} alt=""/>
|
} else {
|
return null
|
}
|
} else if (card.avatar.type === 'icon') {
|
let result = this.getMark(data, card.avatar.marks)
|
|
if (result.isIcon) {
|
return result.icon
|
} else {
|
return null
|
}
|
}
|
}
|
|
switchCard = () => {
|
const { card, data } = this.props
|
|
if (!card.switch) return
|
|
this.props.switchCard(data)
|
}
|
|
render() {
|
const { card, selectKey, data } = this.props
|
const { extra, actions } = this.state
|
|
let title = null
|
if (card.header) {
|
if (card.header.column) {
|
title = this.getContent(card.header.column)
|
} else {
|
title = card.header.content
|
}
|
}
|
|
return (
|
<div className={'chart-card-box ' + card.outclass} style={card.outstyle || null} >
|
<Card
|
size="small"
|
className={'chart-card ' + (selectKey === data.key ? 'chart-card-selected' : '')}
|
title={title}
|
bordered={card.bordered}
|
extra={extra}
|
actions={actions}
|
>
|
<div className={'ant-card-meta' + (card.switch ? ' switch' : '')} onClick={this.switchCard}>
|
{card.avatar ?
|
<div className="ant-card-meta-avatar">
|
<span className="ant-avatar ant-avatar-circle ant-avatar-image" style={card.avatar.class}>
|
{this.getAvatar()}
|
</span>
|
</div> : null
|
}
|
<div className="ant-card-meta-detail" style={card.marginLeft || null}>
|
{card.details.map((detail, i) => {
|
return (
|
<div className={detail.class} key={i}>
|
{detail.column ? this.getContent(detail.column) : detail.content}
|
</div>
|
)
|
})}
|
</div>
|
</div>
|
</Card>
|
</div>
|
)
|
}
|
}
|
|
class CardChart extends Component {
|
static propTpyes = {
|
plot: PropTypes.object,
|
config: PropTypes.object,
|
tableId: PropTypes.string,
|
loading: PropTypes.bool,
|
data: PropTypes.array,
|
buttonTrigger: PropTypes.func,
|
handleTableId: PropTypes.func
|
}
|
|
state = {
|
card: null,
|
colMap: null,
|
selectKey: ''
|
}
|
|
UNSAFE_componentWillMount () {
|
const { plot, config } = this.props
|
let card = {}
|
|
let colMap = new Map() // 显示列
|
let actionMap = new Map() // 按钮组
|
let columns = fromJS(config.columns).toJS()
|
let actions = fromJS(config.action).toJS()
|
|
columns.forEach(col => {
|
if (col.field) {
|
colMap.set(col.field, col)
|
}
|
})
|
|
actions.forEach(item => {
|
if (item.Ot && item.Ot !== 'notRequired' && !['excelIn', 'excelOut'].includes(item.OpenType)) {
|
actionMap.set(item.uuid, item)
|
}
|
})
|
|
if (plot.subelement.includes('header')) {
|
card.header = { actions: [], show: plot.header.show }
|
if (plot.header.datatype === 'dynamic' && colMap.get(plot.header.field)) {
|
let col = fromJS(colMap.get(plot.header.field)).toJS()
|
if (col.marks) {
|
col.marks = col.marks.filter(mark => mark.signType === 'font' || mark.signType === 'icon')
|
}
|
card.header.column = col
|
} else if (plot.header.content) {
|
card.header.content = plot.header.content
|
}
|
|
if (plot.header.actions && plot.header.actions.length > 0) {
|
plot.header.actions.forEach(item => {
|
if (!actionMap.get(item.value)) return
|
card.header.actions.push(actionMap.get(item.value))
|
})
|
}
|
if (card.header.actions.length === 0) {
|
card.header.actions = null
|
}
|
}
|
|
if (plot.subelement.includes('avatar')) {
|
card.avatar = { type: plot.avatar.type }
|
if (card.avatar.type === 'icon' && colMap.get(plot.avatar.field)) {
|
let col = fromJS(colMap.get(plot.avatar.field)).toJS()
|
let _marks = []
|
if (col.marks) {
|
_marks = col.marks.filter(mark => mark.signType === 'icon')
|
}
|
|
if (_marks.length === 0) {
|
card.avatar = null
|
} else {
|
card.avatar.marks = _marks
|
card.avatar.outWidth = plot.avatar.size + 16
|
card.avatar.class = {width: plot.avatar.size, fontSize: plot.avatar.size + 'px'}
|
}
|
} else if (card.avatar.type === 'picture' && colMap.get(plot.avatar.field)) {
|
card.avatar.field = plot.avatar.field
|
card.avatar.outWidth = plot.avatar.width + 16
|
|
card.avatar.class = {width: plot.avatar.width}
|
}
|
}
|
|
if (card.avatar) {
|
card.marginLeft = {marginLeft: card.avatar.outWidth}
|
}
|
|
card.details = []
|
if (plot.details.length > 0) {
|
card.details = plot.details.map(item => {
|
if (item.datatype === 'dynamic' && colMap.get(item.field)) {
|
item.column = colMap.get(item.field)
|
} else {
|
item.datatype = 'static'
|
}
|
|
let _class = ''
|
if (item.bold === 'true') {
|
_class = ' ant-card-meta-title'
|
} else {
|
_class = ' ant-card-meta-description'
|
}
|
|
if (item.width) {
|
_class += ' ' + item.width
|
}
|
if (item.align) {
|
_class += ' ' + item.align
|
}
|
|
item.class = _class
|
|
return item
|
})
|
}
|
|
if (plot.subelement.includes('bottom')) {
|
card.bottom = { actions: [], show: plot.bottom.show }
|
|
if (plot.bottom.actions && plot.bottom.actions.length > 0) {
|
plot.bottom.actions.forEach(item => {
|
if (!actionMap.get(item.value)) return
|
|
card.bottom.actions.push(actionMap.get(item.value))
|
})
|
}
|
|
if (card.bottom.actions.length === 0) {
|
card.bottom = null
|
}
|
}
|
|
let outclass = ''
|
|
if (plot.widthType === 'ratio' && plot.over !== 'roll') {
|
outclass += ' ant-col ant-col-' + plot.cardWidth
|
}
|
|
card.outclass = outclass
|
card.bordered = plot.border !== 'hidden'
|
|
if (plot.widthType === 'absolute') {
|
card.outstyle = { width: plot.cardWidth }
|
}
|
|
if (plot.bgfield && colMap.get(plot.bgfield)) {
|
let col = fromJS(colMap.get(plot.bgfield)).toJS()
|
let _marks = []
|
if (col.marks) {
|
_marks = col.marks.filter(mark => mark.signType === 'card')
|
}
|
|
if (_marks.length > 0) {
|
card.bgmarks = _marks
|
}
|
}
|
|
card.switch = plot.switch !== 'false'
|
|
this.setState({card: card, colMap: colMap})
|
}
|
|
UNSAFE_componentWillReceiveProps(nextProps) {
|
const { card } = this.state
|
|
if (card && card.switch && !is(fromJS(this.props.data), fromJS(nextProps.data))) {
|
this.setState({selectKey: ''})
|
}
|
}
|
|
shouldComponentUpdate (nextProps, nextState) {
|
return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
|
}
|
triggerBtn = (btn, data) => {
|
this.props.buttonTrigger(btn, data)
|
}
|
|
switchCard = (data) => {
|
const { config } = this.props
|
|
let _id = data[config.setting.primaryKey] || ''
|
|
this.setState({selectKey: data.key})
|
|
this.props.handleTableId(this.props.tableId, _id, data)
|
}
|
|
render() {
|
const { plot, data, loading } = this.props
|
const { card, colMap, selectKey } = this.state
|
|
return (
|
<div className="card-row-box mingke-table" style={!plot.title ? {paddingTop: '15px'} : null}>
|
{loading ?
|
<div className="loading-mask">
|
<div className="ant-spin-blur"></div>
|
<Spin />
|
</div> : null
|
}
|
{plot.title ? <p className="chart-title">{plot.title}</p> : null}
|
{plot.over !== 'roll' && data && data.length > 0 &&
|
data.map((item, i) => (
|
<CardCell
|
key={i}
|
card={card}
|
data={item}
|
colMap={colMap}
|
selectKey={selectKey}
|
triggerBtn={this.triggerBtn}
|
switchCard={this.switchCard}
|
/>
|
))
|
}
|
{plot.over === 'roll' && data && data.length > 0 ?
|
<Tabs activeKey="">
|
{data.map((item, i) => (
|
<TabPane tab={<CardCell
|
card={card}
|
data={item}
|
colMap={colMap}
|
selectKey={selectKey}
|
triggerBtn={this.triggerBtn}
|
switchCard={this.switchCard}
|
/>} key={i}></TabPane>
|
|
))}
|
</Tabs> : null
|
}
|
{!data || data.length === 0 ? <Empty description={false}/> : null}
|
<div className="clear"></div>
|
</div>
|
)
|
}
|
}
|
|
export default CardChart
|