| | |
| | | import React, {Component} from 'react' |
| | | import PropTypes from 'prop-types' |
| | | import { is, fromJS } from 'immutable' |
| | | import { Table, Typography, Icon, Switch, Modal, Input, InputNumber, Tooltip, Button, notification, message } from 'antd' |
| | | import { Table, Typography, Switch, Modal, Input, InputNumber, Tooltip, Button, notification, message } from 'antd' |
| | | import { ExclamationCircleOutlined, EditOutlined, PlusOutlined } from '@ant-design/icons' |
| | | import moment from 'moment' |
| | | |
| | | import Api from '@/api' |
| | | import asyncComponent from '@/utils/asyncComponent' |
| | | import Utils, { getEditTableSql } from '@/utils/utils.js' |
| | | import Utils, { getEditTableSql, getMark } from '@/utils/utils.js' |
| | | import MkIcon from '@/components/mk-icon' |
| | | import MKEmitter from '@/utils/events.js' |
| | | import zhCN from '@/locales/zh-CN/main.js' |
| | | import enUS from '@/locales/en-US/main.js' |
| | |
| | | err: null |
| | | } |
| | | |
| | | getMark = (record, marks, style, content) => { |
| | | marks.some(mark => { |
| | | let originVal = record[mark.field[0]] + '' |
| | | let contrastVal = '' |
| | | let result = false |
| | | |
| | | if (mark.field[1] === 'static') { |
| | | contrastVal = mark.contrastValue + '' |
| | | } else { |
| | | contrastVal = record[mark.field[2]] + '' |
| | | } |
| | | |
| | | if (mark.match === '=') { |
| | | result = originVal === contrastVal |
| | | } else if (mark.match === '!=') { |
| | | result = originVal !== contrastVal |
| | | } else if (mark.match === 'like') { |
| | | result = originVal.indexOf(contrastVal) > -1 |
| | | } else if (mark.match === '>') { |
| | | try { |
| | | originVal = parseFloat(originVal) |
| | | contrastVal = parseFloat(contrastVal) |
| | | } catch (e) { |
| | | originVal = NaN |
| | | } |
| | | |
| | | if (!isNaN(originVal) && !isNaN(contrastVal) && originVal > contrastVal) { |
| | | result = true |
| | | } |
| | | } else if (mark.match === '<') { |
| | | try { |
| | | originVal = parseFloat(originVal) |
| | | contrastVal = parseFloat(contrastVal) |
| | | } catch (e) { |
| | | originVal = NaN |
| | | } |
| | | |
| | | if (!isNaN(originVal) && !isNaN(contrastVal) && originVal < contrastVal) { |
| | | result = true |
| | | } |
| | | } |
| | | |
| | | if (result) { |
| | | if (mark.signType[0] === 'font') { |
| | | style.color = mark.color |
| | | } else if (mark.signType[0] === 'background') { |
| | | style.background = mark.color |
| | | if (mark.fontColor) { |
| | | style.color = mark.fontColor |
| | | } |
| | | } else if (mark.signType[0] === 'underline') { |
| | | style.textDecoration = 'underline' |
| | | style.color = mark.color |
| | | } else if (mark.signType[0] === 'line-through') { |
| | | style.textDecoration = 'line-through' |
| | | style.color = mark.color |
| | | } else if (mark.signType[0] === 'icon') { |
| | | let icon = (<Icon style={{color: mark.color}} type={mark.signType[3]} />) |
| | | if (mark.signType[1] === 'front') { |
| | | content = <span>{icon} {content}</span> |
| | | } else { |
| | | content = <span>{content} {icon}</span> |
| | | } |
| | | } |
| | | } |
| | | return result |
| | | }) |
| | | |
| | | return content |
| | | } |
| | | |
| | | shouldComponentUpdate (nextProps, nextState) { |
| | | return !is(fromJS(this.props.record), fromJS(nextProps.record)) || |
| | | nextState.editing !== this.state.editing || |
| | |
| | | |
| | | tdFocus = (id) => { |
| | | const { col, record } = this.props |
| | | |
| | | if (id !== col.uuid + record.$Index) return |
| | | this.focus() |
| | | } |
| | |
| | | const { value } = this.state |
| | | |
| | | this.setState({editing: false}) |
| | | if (col.enter === '$next') { |
| | | MKEmitter.emit('nextLine', col, record.$Index) |
| | | } else { |
| | | MKEmitter.emit('tdFocus', col.enter + record.$Index) |
| | | } |
| | | setTimeout(() => { |
| | | if (col.enter === '$next') { |
| | | MKEmitter.emit('nextLine', col, record.$Index) |
| | | } else { |
| | | MKEmitter.emit('tdFocus', col.enter + record.$Index) |
| | | } |
| | | }, 50) |
| | | |
| | | if (value !== record[col.field]) { |
| | | MKEmitter.emit('changeRecord', col.tableId, {...record, [col.field]: value}) |
| | |
| | | } |
| | | |
| | | if (col.marks) { |
| | | style = style || {} |
| | | content = this.getMark(record, col.marks, style, content) |
| | | let mark = getMark(col.marks, record, style) |
| | | |
| | | style = mark.style |
| | | |
| | | if (mark.icon) { |
| | | if (mark.position === 'front') { |
| | | content = <span><MkIcon style={{color: mark.color}} type={mark.icon} /> {content}</span> |
| | | } else { |
| | | content = <span>{content} <MkIcon style={{color: mark.color}} type={mark.icon} /></span> |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (col.editable === 'true') { |
| | | if (editing) { |
| | | return (<td className="editing_table_cell"> |
| | | <Input id={col.uuid + record.$Index} defaultValue={value} onChange={(e) => this.onChange(e.target.value)} onPressEnter={this.enterPress} onBlur={this.onBlur}/> |
| | | {err ? <Tooltip title={err}><Icon type="exclamation-circle" /></Tooltip> : null} |
| | | {err ? <Tooltip title={err}><ExclamationCircleOutlined /></Tooltip> : null} |
| | | </td>) |
| | | } else { |
| | | return (<td className={className + ' pointer'} style={style}><div className="mk-mask" onClick={this.focus}></div>{content}</td>) |
| | |
| | | if (col.format === 'percent') { |
| | | content = content * 100 |
| | | decimal = decimal > 2 ? decimal - 2 : 0 |
| | | } else if (col.format === 'abs') { |
| | | content = Math.abs(content) |
| | | } |
| | | |
| | | content = content.toFixed(decimal) |
| | |
| | | } |
| | | |
| | | if (col.marks) { |
| | | style = style || {} |
| | | content = this.getMark(record, col.marks, style, content) |
| | | let mark = getMark(col.marks, record, style) |
| | | |
| | | style = mark.style |
| | | |
| | | if (mark.icon) { |
| | | if (mark.position === 'front') { |
| | | content = <span><MkIcon style={{color: mark.color}} type={mark.icon} /> {content}</span> |
| | | } else { |
| | | content = <span>{content} <MkIcon style={{color: mark.color}} type={mark.icon} /></span> |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (col.editable === 'true') { |
| | | if (editing) { |
| | | return (<td className="editing_table_cell"> |
| | | <InputNumber id={col.uuid + record.$Index} defaultValue={value} onChange={(val) => this.onChange(val)} onPressEnter={this.enterPress} onBlur={this.onBlur}/> |
| | | {err ? <Tooltip title={err}><Icon type="exclamation-circle" /></Tooltip> : null} |
| | | {err ? <Tooltip title={err}><ExclamationCircleOutlined /></Tooltip> : null} |
| | | </td>) |
| | | } else { |
| | | return (<td className={className + ' pointer'} style={style}><div className="mk-mask" onClick={this.focus}></div>{content}</td>) |
| | |
| | | {content ? <Paragraph copyable ellipsis={{ rows: 3, expandable: true }}>{content}</Paragraph> : null } |
| | | </div> |
| | | ) |
| | | } else if (col.type === 'formula') { |
| | | let content = col.formula |
| | | Object.keys(record).forEach(key => { |
| | | let reg = new RegExp('@' + key + '@', 'ig') |
| | | content = content.replace(reg, record[key]) |
| | | }) |
| | | |
| | | if (col.eval !== 'false') { |
| | | try { |
| | | // eslint-disable-next-line |
| | | content = eval(content) |
| | | } catch (e) { |
| | | content = '' |
| | | } |
| | | } |
| | | |
| | | content = content === undefined ? '' : content |
| | | |
| | | if (content !== '') { |
| | | content = `${col.prefix || ''}${content}${col.postfix || ''}` |
| | | |
| | | if (col.eval === 'false') { |
| | | content = content.replace(/\n/ig, '<br/>').replace(/\s/ig, ' ') |
| | | content = <span dangerouslySetInnerHTML={{__html: content}}></span> |
| | | } |
| | | } |
| | | |
| | | if (col.marks) { |
| | | let mark = getMark(col.marks, record, style) |
| | | |
| | | style = mark.style |
| | | |
| | | if (mark.icon) { |
| | | if (mark.position === 'front') { |
| | | content = <span><MkIcon style={{color: mark.color}} type={mark.icon} /> {content}</span> |
| | | } else { |
| | | content = <span>{content} <MkIcon style={{color: mark.color}} type={mark.icon} /></span> |
| | | } |
| | | } |
| | | } |
| | | |
| | | children = content |
| | | } else if (col.type === 'custom') { |
| | | style.padding = '0px' |
| | | if (col.style) { |
| | |
| | | fields: [], |
| | | pickup: false, // 收起未选择项 |
| | | orderfields: {}, // 排序id与field转换 |
| | | loading: false |
| | | loading: false, |
| | | editable: 'false', |
| | | pageOptions: [] |
| | | } |
| | | |
| | | UNSAFE_componentWillMount () { |
| | |
| | | if (item.type !== 'action') { |
| | | let _copy = fromJS(_item).toJS() |
| | | _copy.sorter = false |
| | | |
| | | if (item.editable === 'true') { |
| | | _copy.title = <span>{item.label}<EditOutlined className="system-color" style={{position: 'absolute', bottom: '2px', right: '5px'}}/></span> |
| | | } |
| | | edColumns.push(_copy) |
| | | } |
| | | _columns.push(_item) |
| | | }) |
| | | |
| | | edColumns.push({ |
| | | align: 'center', |
| | | dataIndex: 'mkoperation', |
| | | title: '操作', |
| | | sorter: false, |
| | | width: 100, |
| | | onCell: record => ({ |
| | | record, |
| | | col: {type: 'operation', tableId: tableId}, |
| | | if (setting.delable !== 'false') { |
| | | edColumns.push({ |
| | | align: 'center', |
| | | dataIndex: 'mkoperation', |
| | | title: '操作', |
| | | sorter: false, |
| | | width: 100, |
| | | onCell: record => ({ |
| | | record, |
| | | col: {type: 'operation', tableId: tableId}, |
| | | }) |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | if (setting.borderColor) { // 边框颜色 |
| | | let style = `#${tableId} table, #${tableId} tr, #${tableId} th, #${tableId} td {border-color: ${setting.borderColor}}` |
| | |
| | | document.getElementsByTagName('head')[0].appendChild(ele) |
| | | } |
| | | |
| | | let size = (setting.pageSize || 10) + '' |
| | | let pageOptions = ['10', '25', '50', '100', '500', '1000'] |
| | | |
| | | if (!pageOptions.includes(size)) { |
| | | pageOptions.push(size) |
| | | pageOptions = pageOptions.sort((a, b) => a - b) |
| | | } |
| | | |
| | | this.setState({ |
| | | pageSize: setting.pageSize || 10, |
| | | pageOptions, |
| | | data, |
| | | columns: _columns, |
| | | edColumns, |
| | | tableId, |
| | | orderfields, |
| | | initEditLine |
| | | initEditLine, |
| | | editable: setting.editable |
| | | }) |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | componentDidMount () { |
| | | const { fields, columns } = this.props |
| | | const { fields, setting } = this.props |
| | | const { data, editable } = this.state |
| | | |
| | | let _fields = [] |
| | | // let _fields = [] // 定义全部字段,不在从可编辑列中选取 |
| | | |
| | | let fieldType = {} |
| | | fields.forEach(item => { |
| | | fieldType[item.field] = item.datatype |
| | | }) |
| | | // let fieldType = {} |
| | | // fields.forEach(item => { |
| | | // fieldType[item.field] = item.datatype |
| | | // }) |
| | | |
| | | columns.forEach(col => { |
| | | if (!col.field || col.type === 'index') return |
| | | // columns.forEach(col => { |
| | | // if (!col.field || col.type === 'index') return |
| | | |
| | | _fields.push({...col, datatype: fieldType[col.field] || 'Nvarchar(50)'}) |
| | | }) |
| | | // _fields.push({...col, datatype: fieldType[col.field] || 'Nvarchar(50)'}) |
| | | // }) |
| | | |
| | | this.setState({ |
| | | fields: _fields, |
| | | fields: fields.filter(item => item.field !== setting.primaryKey), |
| | | }) |
| | | |
| | | if (editable === 'true' && data && data.length > 0) { |
| | | setTimeout(() => { |
| | | this.pickupChange() |
| | | }, 200) |
| | | } |
| | | |
| | | MKEmitter.addListener('nextLine', this.nextLine) |
| | | MKEmitter.addListener('delRecord', this.delRecord) |
| | |
| | | UNSAFE_componentWillReceiveProps(nextProps) { |
| | | if (!is(fromJS(this.props.data), fromJS(nextProps.data))) { |
| | | this.setState({data: nextProps.data || []}) |
| | | if (this.state.editable === 'true') { |
| | | setTimeout(() => { |
| | | this.pickupChange() |
| | | }, 200) |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | item.$Index = item.key + 1 + '' |
| | | |
| | | fields.forEach(col => { |
| | | item[col.field] = item[col.field] !== undefined ? item[col.field] : '' |
| | | |
| | | if (col.initval !== '$copy') { |
| | | item[col.field] = col.initval |
| | | } |
| | |
| | | if (isNaN(item[col.field])) { |
| | | item[col.field] = 0 |
| | | } |
| | | } |
| | | if (item[col.field] === undefined) { |
| | | item[col.field] = '' |
| | | } |
| | | }) |
| | | |
| | |
| | | } |
| | | |
| | | fields.forEach(col => { |
| | | item[col.field] = item[col.field] !== undefined ? item[col.field] : '' |
| | | |
| | | if (col.initval !== '$copy') { |
| | | item[col.field] = col.initval |
| | | } |
| | |
| | | if (isNaN(item[col.field])) { |
| | | item[col.field] = 0 |
| | | } |
| | | } |
| | | |
| | | if (item[col.field] === undefined) { |
| | | item[col.field] = '' |
| | | } |
| | | }) |
| | | |
| | |
| | | loading: false |
| | | }) |
| | | |
| | | if (submit.closetab === 'true') { |
| | | MKEmitter.emit('popclose') |
| | | } |
| | | if (submit.execSuccess !== 'never') { |
| | | this.repick() |
| | | MKEmitter.emit('refreshByButtonResult', submit.$menuId, submit.execSuccess, submit) |
| | |
| | | } |
| | | |
| | | pickupChange = () => { |
| | | const { submit } = this.props |
| | | const { data } = this.state |
| | | |
| | | let pickup = !this.state.pickup |
| | | |
| | | if (!submit.sheet) { |
| | | notification.warning({ |
| | | top: 92, |
| | | message: '提交按钮尚未设置,不可编辑!', |
| | | duration: 5 |
| | | }) |
| | | return |
| | | } |
| | | |
| | | if (!pickup && !is(fromJS(data), fromJS(this.state.edData))) { |
| | | const _this = this |
| | |
| | | data: [], |
| | | edData: [], |
| | | pickup, |
| | | loading: false |
| | | loading: false, |
| | | editable: 'false' |
| | | }, () => { |
| | | this.setState({ |
| | | data: data, |
| | |
| | | } |
| | | |
| | | render() { |
| | | const { setting, statFValue, lineMarks } = this.props |
| | | const { pickup, tableId, data, edData, columns, edColumns, loading } = this.state |
| | | const { setting, statFValue, lineMarks, submit } = this.props |
| | | const { pickup, tableId, data, edData, columns, edColumns, loading, pageOptions } = this.state |
| | | |
| | | const components = { |
| | | body: { |
| | |
| | | _pagination = { |
| | | current: this.state.pageIndex, |
| | | pageSize: this.state.pageSize, |
| | | pageSizeOptions: ['10', '25', '50', '100', '500', '1000'], |
| | | pageSizeOptions: pageOptions, |
| | | showSizeChanger: true, |
| | | total: this.props.total || 0, |
| | | showTotal: (total, range) => `${range[0]}-${range[1]} ${this.state.dict['main.pagination.of']} ${total} ${this.state.dict['main.pagination.items']}` |
| | |
| | | return ( |
| | | <div className={`edit-custom-table ${pickup ? 'editable' : ''} ${setting.tableHeader || ''} ${height ? 'fixed-height' : ''} ${setting.mode || ''}`} id={tableId}> |
| | | <Switch title="编辑" className="main-pickup" checkedChildren="开" unCheckedChildren="关" checked={pickup} onChange={this.pickupChange} /> |
| | | {pickup ? <Button onClick={() => setTimeout(() => {this.checkData()}, 10)} loading={loading} className="submit-table" type="link">提交</Button> : null} |
| | | {pickup ? <Button style={submit.style} onClick={() => setTimeout(() => {this.checkData()}, 10)} loading={loading} className="submit-table" type="link">提交</Button> : null} |
| | | <Table |
| | | components={components} |
| | | style={setting.style} |
| | |
| | | pagination={_pagination} |
| | | /> |
| | | {_footer ? <div className={'normal-table-footer ' + (_pagination ? 'pagination' : '')}>{_footer}</div> : null} |
| | | {pickup && setting.addable === 'true' ? <Button onClick={this.addLine} style={{display: 'block', width: '100%', color: '#26C281'}} icon="plus" type="link"></Button> : null} |
| | | {pickup && setting.addable === 'true' ? <Button onClick={this.addLine} style={{display: 'block', width: '100%', color: '#26C281', border: '1px solid #dddddd', borderRadius: 0}} type="link"><PlusOutlined /></Button> : null} |
| | | </div> |
| | | ) |
| | | } |