import React, {Component} from 'react'
|
import PropTypes from 'prop-types'
|
import { fromJS } from 'immutable'
|
import { Form, Row, Col, Input, Radio, Select, Tooltip, Icon, notification, InputNumber, Modal, Table, Popconfirm, Typography, Button } from 'antd'
|
import moment from 'moment'
|
|
import Api from '@/api'
|
import Utils from '@/utils/utils.js'
|
import SettingUtils from './utils.jsx'
|
import CustomScript from './customscript'
|
import './index.scss'
|
|
const { TextArea } = Input
|
const { confirm } = Modal
|
const { Paragraph } = Typography
|
|
class SettingForm extends Component {
|
static propTpyes = {
|
type: PropTypes.string, // 菜单类型
|
dict: PropTypes.object, // 字典项
|
menu: PropTypes.object, // 菜单信息
|
config: PropTypes.object, // 页面配置信息
|
formlist: PropTypes.array, // 表单信息
|
inputSubmit: PropTypes.any // 回车提交事件
|
}
|
|
state = {
|
formlist: [],
|
btnloading: false,
|
setting: null,
|
view: 'normal',
|
systemScripts: [{
|
name: '默认sql',
|
value: ''
|
}],
|
scriptsColumns: [
|
{
|
title: 'SQL',
|
dataIndex: 'sql',
|
width: '70%',
|
render: (text) => (
|
<Paragraph copyable ellipsis={{ rows: 5, expandable: true }}>{text}</Paragraph>
|
)
|
},
|
{
|
title: '状态',
|
dataIndex: 'status',
|
width: '10%',
|
render: (text, record) => record.status === 'false' ?
|
(
|
<div>
|
{this.props.dict['header.form.status.forbidden']}
|
<Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
|
</div>
|
) :
|
(
|
<div>
|
{this.props.dict['header.form.status.open']}
|
<Icon style={{marginLeft: '5px'}} type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
|
</div>
|
)
|
},
|
{
|
title: '操作',
|
align: 'center',
|
width: '20%',
|
dataIndex: 'operation',
|
render: (text, record) =>
|
(<div>
|
<span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record)} style={{color: '#1890ff'}}><Icon type="edit" /></span>
|
<span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
|
<span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
|
<span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record)} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
|
<Popconfirm
|
title={this.props.dict['header.form.query.delete']}
|
okText={this.props.dict['model.confirm']}
|
cancelText={this.props.dict['header.cancel']}
|
onConfirm={() => this.handleDelete(record)
|
}>
|
<span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
|
</Popconfirm>
|
</div>)
|
}
|
]
|
}
|
|
UNSAFE_componentWillMount() {
|
let _formlist = fromJS(this.props.formlist).toJS()
|
let interType = 'inner'
|
|
_formlist.forEach(item => {
|
if (item.key === 'interType') {
|
interType = item.initVal
|
}
|
})
|
|
let _setting = fromJS(this.props.config.setting).toJS()
|
_setting.scripts = _setting.scripts || []
|
_setting.default = _setting.default || 'true'
|
|
this.setState({
|
setting: _setting,
|
formlist: _formlist.map(item => {
|
if (interType === 'inner' && ['sysInterface', 'interface', 'outerFunc'].includes(item.key)) {
|
item.hidden = true
|
} else if (interType === 'outer' && ['innerFunc', 'dataresource', 'queryType'].includes(item.key)) {
|
item.hidden = true
|
}
|
|
return item
|
})
|
})
|
}
|
|
componentDidMount () {
|
this.getsysScript()
|
}
|
|
getsysScript = () => {
|
let _scriptSql = `Select distinct func+Remark as funcname,longparam, s.Sort from s_custom_script s inner join (select OpenID from sapp where ID=@Appkey@) p on s.openid = case when s.appkey='' then s.openid else p.OpenID end order by s.Sort`
|
|
_scriptSql = Utils.formatOptions(_scriptSql)
|
|
let _sParam = {
|
func: 'sPC_Get_SelectedList',
|
LText: _scriptSql,
|
obj_name: 'data',
|
arr_field: 'funcname,longparam'
|
}
|
|
_sParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
|
_sParam.secretkey = Utils.encrypt(_sParam.LText, _sParam.timestamp)
|
|
Api.getSystemConfig(_sParam).then(res => {
|
if (res.status) {
|
let _scripts = res.data.map(item => {
|
let _item = {
|
name: item.funcname,
|
value: Utils.formatOptions(item.longparam, true)
|
}
|
|
return _item
|
})
|
|
this.setState({
|
systemScripts: [...this.state.systemScripts, ..._scripts]
|
})
|
} else {
|
notification.warning({
|
top: 92,
|
message: res.message,
|
duration: 5
|
})
|
}
|
})
|
}
|
|
handleConfirm = (otype) => {
|
const { menu } = this.props
|
const { view, setting } = this.state
|
// 表单提交时检查输入值是否正确
|
|
if (view !== 'custom') {
|
return new Promise((resolve, reject) => {
|
this.props.form.validateFieldsAndScroll((err, values) => {
|
if (!err) {
|
values = {...setting, ...values}
|
|
// 数据源前端验证
|
if (values.interType === 'inner' && !values.innerFunc && values.default !== 'false' && !values.dataresource) {
|
notification.warning({
|
top: 92,
|
message: '请填写内部函数或数据源!',
|
duration: 5
|
})
|
reject()
|
return
|
} else if (values.interType === 'inner' && !values.innerFunc && values.default !== 'false' && values.dataresource) {
|
let error = Utils.verifySql(values.dataresource)
|
|
if (error) {
|
notification.warning({
|
top: 92,
|
message: '数据源中不可使用' + error,
|
duration: 5
|
})
|
reject()
|
return
|
}
|
}
|
|
// 数据源保存
|
if (
|
values.interType === 'inner' && !values.innerFunc &&
|
values.default !== 'false' &&
|
/[^\s]+\s+[^\s]+/ig.test(values.dataresource) &&
|
this.props.config.setting.dataresource !== values.dataresource
|
) {
|
let param = {
|
func: 's_DataSrc_Save',
|
LText: values.dataresource,
|
MenuID: menu.MenuID
|
}
|
|
param.LText = Utils.formatOptions(param.LText)
|
param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
|
param.secretkey = Utils.encrypt(param.LText, param.timestamp)
|
|
Api.getLocalConfig(param)
|
}
|
|
if (otype === 'change') {
|
this.setState({
|
setting: values,
|
}, () => {
|
resolve()
|
})
|
} else {
|
values.customScript = this.getCustomScript(values)
|
|
this.sqlverify(values, resolve, reject)
|
}
|
} else {
|
reject(err)
|
}
|
})
|
})
|
} else {
|
let _setting = fromJS(this.state.setting).toJS()
|
_setting.customScript = this.getCustomScript(_setting)
|
|
let _this = this
|
|
return new Promise((resolve, reject) => {
|
if (this.scriptsForm && this.scriptsForm.props.form.getFieldValue('sql')) {
|
confirm({
|
content: `存在未保存项,确定提交吗?`,
|
okText: this.props.dict['model.confirm'],
|
cancelText: this.props.dict['header.cancel'],
|
onOk() {
|
_this.sqlverify(_setting, resolve, reject)
|
},
|
onCancel() {
|
reject()
|
}
|
})
|
} else {
|
this.sqlverify(_setting, resolve, reject)
|
}
|
})
|
}
|
}
|
|
getCustomScript = (setting) => {
|
let _customScript = ''
|
if (setting.scripts && setting.scripts.length > 0) {
|
setting.scripts.forEach(item => {
|
if (item.status === 'false') return
|
_customScript += `
|
${item.sql}
|
`
|
})
|
}
|
|
if (_customScript) {
|
_customScript = `declare @ErrorCode nvarchar(50),@retmsg nvarchar(4000) select @ErrorCode='',@retmsg =''
|
${_customScript}
|
`
|
}
|
|
return _customScript
|
}
|
|
sqlverify = (_setting, _resolve, _reject, isChange = false) => {
|
if (!isChange && _setting.interType === 'inner' && !_setting.innerFunc && _setting.default === 'false' && !_setting.customScript) {
|
notification.warning({
|
top: 92,
|
message: '不执行默认sql时,请添加自定义脚本!',
|
duration: 5
|
})
|
_reject()
|
return
|
}
|
|
if (_setting.interType === 'inner' && !_setting.innerFunc && _setting.default !== 'false') {
|
let param = {
|
func: 's_debug_sql',
|
LText: SettingUtils.getDebugSql(_setting)
|
}
|
param.LText = Utils.formatOptions(param.LText)
|
param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
|
param.secretkey = Utils.encrypt(param.LText, param.timestamp)
|
|
Api.getLocalConfig(param).then(result => {
|
if (result.status) {
|
_resolve(_setting)
|
} else {
|
_reject()
|
Modal.error({
|
title: result.message
|
})
|
}
|
})
|
} else {
|
_resolve(_setting)
|
}
|
}
|
|
selectChange = (key, val) => {
|
if (key === 'primaryKey' && val) {
|
this.props.form.setFieldsValue({
|
order: `${val} desc`
|
})
|
}
|
}
|
|
onRadioChange = (e, key) => {
|
let value = e.target.value
|
let _formlist = fromJS(this.state.formlist).toJS()
|
|
if (key === 'interType') {
|
this.setState({
|
formlist: _formlist.map(item => {
|
item.hidden = false
|
|
if (value === 'inner' && ['sysInterface', 'interface', 'outerFunc'].includes(item.key)) {
|
item.initVal = this.props.form.getFieldValue(item.key)
|
item.hidden = true
|
} else if (value === 'outer' && ['innerFunc', 'dataresource', 'queryType'].includes(item.key)) {
|
item.initVal = this.props.form.getFieldValue(item.key)
|
item.hidden = true
|
}
|
|
return item
|
})
|
})
|
} else if (key === 'sysInterface') {
|
if (value === 'true') {
|
this.props.form.setFieldsValue({
|
interface: window.GLOB.mainSystemApi || ''
|
})
|
}
|
this.setState({
|
formlist: _formlist.map(item => {
|
if (item.key === 'interface') {
|
item.readonly = value === 'true'
|
}
|
|
return item
|
})
|
})
|
}
|
}
|
|
changeView = () => {
|
const { view } = this.state
|
let _this = this
|
|
if (view === 'normal') {
|
this.handleConfirm('change').then(() => {
|
const { setting } = this.state
|
|
if (setting.interType !== 'inner' || (setting.interType === 'inner' && setting.innerFunc)) {
|
notification.warning({
|
top: 92,
|
message: '使用外部接口或内部接口的自定义函数,不可添加自定义设置!',
|
duration: 5
|
})
|
return
|
}
|
|
let _dataresource = setting.dataresource
|
|
if (/\s/.test(_dataresource)) {
|
_dataresource = '(' + _dataresource + ') tb'
|
}
|
|
let arr_field = `${setting.valueField}, ${setting.labelField}, ${setting.parentField}`
|
|
let LText = `select ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by @orderBy@) as rows from ${_dataresource}) tmptable order by tmptable.rows`
|
let _scripts = fromJS(this.state.systemScripts).toJS()
|
_scripts[0].value = LText
|
|
|
if (setting.default === 'false') {
|
this.setState({
|
view: 'custom',
|
btnloading: false,
|
systemScripts: _scripts
|
})
|
this.scrolltop()
|
} else {
|
this.setState({
|
btnloading: true
|
})
|
new Promise((resolve, reject) => {
|
this.sqlverify(setting, resolve, reject, true)
|
}).then(() => {
|
this.setState({
|
view: 'custom',
|
btnloading: false,
|
systemScripts: _scripts
|
})
|
this.scrolltop()
|
}, () => {
|
this.setState({
|
btnloading: false
|
})
|
})
|
}
|
})
|
} else {
|
let _loading = false
|
|
if (this.scriptsForm && this.scriptsForm.props.form.getFieldValue('sql')) {
|
_loading = true
|
}
|
|
if (_loading) {
|
confirm({
|
content: `存在未保存项,确定切换吗?`,
|
okText: this.props.dict['model.confirm'],
|
cancelText: this.props.dict['header.cancel'],
|
onOk() {
|
_this.setState({
|
view: 'normal'
|
})
|
|
_this.scrolltop()
|
},
|
onCancel() {}
|
})
|
} else {
|
_this.setState({
|
view: 'normal'
|
})
|
|
_this.scrolltop()
|
}
|
}
|
}
|
|
handleSubmit = (e) => {
|
e.preventDefault()
|
|
if (this.props.inputSubmit) {
|
this.props.inputSubmit()
|
}
|
}
|
|
getFields(formlist) {
|
const { getFieldDecorator } = this.props.form
|
const fields = []
|
|
formlist.forEach((item, index) => {
|
if (item.hidden || item.forbid) return
|
|
if (item.type === 'text') { // 文本搜索
|
let rules = item.rules || []
|
|
fields.push(
|
<Col span={12} key={index}>
|
<Form.Item label={item.tooltip ?
|
<Tooltip placement={item.placement || 'topLeft'} title={item.tooltip}>
|
<Icon type="question-circle" />
|
{item.label}
|
</Tooltip> : item.label
|
}>
|
{getFieldDecorator(item.key, {
|
initialValue: item.initVal || '',
|
rules: [
|
{
|
required: !!item.required,
|
message: this.props.dict['form.required.input'] + item.label + '!'
|
},
|
...rules
|
]
|
})(<Input placeholder={item.placeholder || ''} autoComplete="off" disabled={item.readonly} onPressEnter={this.handleSubmit} />)}
|
</Form.Item>
|
</Col>
|
)
|
} else if (item.type === 'number') {
|
fields.push(
|
<Col span={12} key={index}>
|
<Form.Item label={item.tooltip ?
|
<Tooltip placement="topLeft" title={item.tooltip}>
|
<Icon type="question-circle" />
|
{item.label}
|
</Tooltip> : item.label
|
}>
|
{getFieldDecorator(item.key, {
|
initialValue: item.initVal || 6,
|
rules: [
|
{
|
required: item.required,
|
message: this.props.dict['form.required.input'] + item.label + '!'
|
}
|
]
|
})(<InputNumber min={item.min} max={item.max} precision={0} />)}
|
</Form.Item>
|
</Col>
|
)
|
} else if (item.type === 'select') { // 下拉搜索
|
fields.push(
|
<Col span={12} key={index}>
|
<Form.Item label={item.label}>
|
{getFieldDecorator(item.key, {
|
initialValue: item.initVal || '',
|
rules: [
|
{
|
required: !!item.required,
|
message: this.props.dict['form.required.select'] + item.label + '!'
|
}
|
]
|
})(
|
<Select
|
showSearch
|
filterOption={(input, option) => {
|
return option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0 ||
|
option.props.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
}}
|
onChange={(value) => {this.selectChange(item.key, value)}}
|
getPopupContainer={() => document.getElementById('model-table-setting-form')}
|
>
|
{item.options.map((option, i) =>
|
<Select.Option id={i} key={i} value={option.value}>
|
{option.text}
|
</Select.Option>
|
)}
|
</Select>
|
)}
|
</Form.Item>
|
</Col>
|
)
|
} else if (item.type === 'radio') {
|
fields.push(
|
<Col span={12} key={index}>
|
<Form.Item label={item.tooltip ?
|
<Tooltip placement="topLeft" title={item.tooltip}>
|
<Icon type="question-circle" />
|
{item.label}
|
</Tooltip> : item.label
|
}>
|
{getFieldDecorator(item.key, {
|
initialValue: item.initVal,
|
rules: [
|
{
|
required: !!item.required,
|
message: this.props.dict['form.required.select'] + item.label + '!'
|
}
|
]
|
})(
|
<Radio.Group onChange={(e) => {this.onRadioChange(e, item.key)}}>
|
{
|
item.options.map((option, i) => {
|
return (
|
<Radio key={i} value={option.value}>{option.text}</Radio>
|
)
|
})
|
}
|
</Radio.Group>,
|
)}
|
</Form.Item>
|
</Col>
|
)
|
} else if (item.type === 'datasource') {
|
fields.push(
|
<Col span={24} key={index} style={{paddingLeft: '7px'}}>
|
<Form.Item labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} } help={item.help} label={
|
<Tooltip placement="topLeft" title={item.tooltip}>
|
<Icon type="question-circle" />
|
{item.label}
|
</Tooltip>
|
}>
|
{getFieldDecorator(item.key, {
|
initialValue: item.initVal
|
})(<TextArea rows={4} />)}
|
</Form.Item>
|
</Col>
|
)
|
} else if (item.type === 'textarea') {
|
fields.push(
|
<Col span={20} offset={4} key={index}>
|
<Form.Item className="text-area">
|
{getFieldDecorator(item.key, {
|
initialValue: item.initVal,
|
rules: [
|
{
|
required: !!item.required,
|
message: this.props.dict['form.required.input'] + item.label + '!'
|
}
|
]
|
})(<TextArea rows={4} />)}
|
</Form.Item>
|
</Col>
|
)
|
} else if (item.type === 'multiselect') { // 多选
|
fields.push(
|
<Col span={12} key={index}>
|
<Form.Item label={item.label}>
|
{getFieldDecorator(item.key, {
|
initialValue: item.initVal || []
|
})(
|
<Select
|
showSearch
|
mode="multiple"
|
filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
|
>
|
{item.options.map((option, i) =>
|
<Select.Option id={i} key={i} value={option.value}>{option.text}</Select.Option>
|
)}
|
</Select>
|
)}
|
</Form.Item>
|
</Col>
|
)
|
}
|
})
|
|
return fields
|
}
|
|
handleEdit = (record) => {
|
this.scriptsForm.edit(record)
|
|
this.scrolltop()
|
}
|
|
scrolltop = () => {
|
let node = document.getElementById('model-tree-setting-form-box').parentNode
|
|
if (node && node.scrollTop) {
|
let inter = Math.ceil(node.scrollTop / 10)
|
|
let timer = setInterval(() => {
|
if (node.scrollTop - inter > 0) {
|
node.scrollTop = node.scrollTop - inter
|
} else {
|
node.scrollTop = 0
|
clearInterval(timer)
|
}
|
}, 10)
|
}
|
}
|
|
handleUpDown = (record, direction) => {
|
let scripts = fromJS(this.state.setting.scripts).toJS()
|
let index = 0
|
|
scripts = scripts.filter((item, i) => {
|
if (item.uuid === record.uuid) {
|
index = i
|
}
|
|
return item.uuid !== record.uuid
|
})
|
if ((index === 0 && direction === 'up') || (index === scripts.length && direction === 'down')) {
|
return
|
}
|
|
if (direction === 'up') {
|
scripts.splice(index - 1, 0, record)
|
} else {
|
scripts.splice(index + 1, 0, record)
|
}
|
|
this.setState({
|
setting: {...this.state.setting, scripts: scripts}
|
})
|
}
|
|
handleStatus = (record) => {
|
let scripts = fromJS(this.state.setting.scripts).toJS()
|
record.status = record.status === 'false' ? 'true' : 'false'
|
|
scripts = scripts.map(item => {
|
if (item.uuid === record.uuid) {
|
return record
|
} else {
|
return item
|
}
|
})
|
|
this.setState({
|
setting: {...this.state.setting, scripts: scripts}
|
})
|
}
|
|
handleDelete = (record) => {
|
let scripts = fromJS(this.state.setting.scripts).toJS()
|
scripts = scripts.filter(item => item.uuid !== record.uuid)
|
|
this.setState({ setting: {...this.state.setting, scripts: scripts} })
|
}
|
|
scriptsChange = (values) => {
|
let scripts = fromJS(this.state.setting.scripts).toJS()
|
|
if (values.uuid) {
|
scripts = scripts.map(item => {
|
if (item.uuid === values.uuid) {
|
return values
|
} else {
|
return item
|
}
|
})
|
} else {
|
values.uuid = Utils.getuuid()
|
scripts.push(values)
|
}
|
|
this.setState({
|
setting: {...this.state.setting, scripts: scripts}
|
})
|
}
|
|
render() {
|
const { config, type } = this.props
|
const { formlist, view, setting, scriptsColumns, systemScripts, btnloading } = this.state
|
const formItemLayout = {
|
labelCol: {
|
xs: { span: 24 },
|
sm: { span: 8 }
|
},
|
wrapperCol: {
|
xs: { span: 24 },
|
sm: { span: 16 }
|
}
|
}
|
|
return (
|
<div className="model-tree-setting-form-box" id="model-tree-setting-form-box">
|
{view ==='custom' ? <div>
|
<Icon className="setting-custom-back" onClick={this.changeView} type="arrow-left" />
|
<CustomScript
|
type={type}
|
setting={setting}
|
dict={this.props.dict}
|
searches={config.search}
|
systemScripts={systemScripts}
|
scriptsChange={this.scriptsChange}
|
wrappedComponentRef={(inst) => this.scriptsForm = inst}
|
/>
|
<Table
|
bordered
|
rowKey="uuid"
|
className="custom-table"
|
dataSource={setting.scripts}
|
columns={scriptsColumns}
|
pagination={false}
|
/>
|
</div> : null }
|
<Form {...formItemLayout} className="model-tree-setting-form" id="model-table-setting-form">
|
{view !=='custom' ? <Row gutter={24}>{this.getFields(formlist)}</Row> : null}
|
<Row gutter={24}>
|
{view !=='custom' ? <Button onClick={this.changeView} className="to-custom-script" loading={btnloading}>自定义设置<Icon style={{marginLeft: 5}} type="right" /></Button> : null}
|
{view ==='custom' ? <span onClick={this.changeView} style={{float: 'left', color: '#1890ff', marginLeft: 12, marginTop: 15, cursor: 'pointer'}}><Icon style={{marginRight: 5}} type="left" />基础设置</span> : null}
|
</Row>
|
</Form>
|
</div>
|
)
|
}
|
}
|
|
export default Form.create()(SettingForm)
|