| | |
| | | import React, {Component} from 'react' |
| | | import PropTypes from 'prop-types' |
| | | import {connect} from 'react-redux' |
| | | import { is, fromJS } from 'immutable' |
| | | import { Icon, Modal } from 'antd' |
| | | import { Modal, Button, notification } from 'antd' |
| | | import { SettingOutlined } from '@ant-design/icons' |
| | | |
| | | import zhCN from '@/locales/zh-CN/model.js' |
| | | import enUS from '@/locales/en-US/model.js' |
| | | import VerifyCard from './verifycard' |
| | | import CreateFunc from '@/templates/zshare/createfunc' |
| | | import MKEmitter from '@/utils/events.js' |
| | | import './index.scss' |
| | | |
| | | class DataSource extends Component { |
| | |
| | | } |
| | | |
| | | state = { |
| | | dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS, |
| | | appType: sessionStorage.getItem('appType'), |
| | | sourcelist: [], |
| | | mainSearch: [], |
| | | visible: false, |
| | | loading: false, |
| | | setting: null |
| | | } |
| | | |
| | | UNSAFE_componentWillMount () { |
| | | const { config } = this.props |
| | | |
| | | this.setState({setting: fromJS(config.setting).toJS()}) |
| | | this.props.updateConfig(config) // 触发菜单信息更新 |
| | | record: {} |
| | | } |
| | | |
| | | shouldComponentUpdate (nextProps, nextState) { |
| | |
| | | } |
| | | |
| | | editDataSource = () => { |
| | | const { config } = this.props |
| | | const { appType } = this.state |
| | | |
| | | let search = [] |
| | | let menu = fromJS(window.GLOB.customMenu).toJS() |
| | | |
| | | if (appType === 'mob') { |
| | | let ms = null |
| | | menu.components.forEach(item => { |
| | | if (item.type === 'topbar' && item.wrap.type !== 'navbar' && item.search) { |
| | | ms = item.search |
| | | } else if (item.type === 'search' && item.wrap.field) { |
| | | search.push({ |
| | | type: 'text', |
| | | label: item.wrap.label, |
| | | field: item.wrap.field, |
| | | match: item.wrap.match, |
| | | required: item.wrap.required, |
| | | value: item.wrap.initval || '' |
| | | }) |
| | | } |
| | | }) |
| | | |
| | | if (ms) { |
| | | if (ms.setting.type === 'search') { |
| | | search.push({ |
| | | type: 'text', |
| | | label: '搜索栏', |
| | | field: ms.setting.field, |
| | | match: ms.setting.match, |
| | | required: ms.setting.required, |
| | | value: ms.setting.initval || '' |
| | | }) |
| | | } |
| | | ms.fields.forEach(item => { |
| | | if (item.type === 'range') { |
| | | item.initval = `${item.minValue},${item.maxValue}` |
| | | } |
| | | search.push(item) |
| | | }) |
| | | |
| | | ms.groups.forEach(group => { |
| | | if (group.setting.type === 'search') { |
| | | search.push({ |
| | | type: 'text', |
| | | label: group.wrap.name, |
| | | field: group.setting.field, |
| | | match: group.setting.match, |
| | | required: group.setting.required, |
| | | value: group.setting.initval || '' |
| | | }) |
| | | } |
| | | |
| | | group.fields.forEach(item => { |
| | | if (item.type === 'range') { |
| | | item.initval = `${item.minValue},${item.maxValue}` |
| | | } |
| | | search.push(item) |
| | | }) |
| | | }) |
| | | } |
| | | } else if (config.type === 'interface') { |
| | | menu.components.forEach(item => { |
| | | if (item.type !== 'search') return |
| | | search = item.search |
| | | }) |
| | | } else { |
| | | let filterComponent = (box, mainSearch) => { |
| | | box.components.forEach(item => { |
| | | if (item.type !== 'search') return |
| | | mainSearch = item.search |
| | | }) |
| | | let has = false |
| | | box.components.forEach(item => { |
| | | if (item.uuid === config.uuid) { |
| | | has = true |
| | | } else if (item.type === 'group') { |
| | | item.components.forEach(m => { |
| | | if (m.uuid !== config.uuid) return |
| | | has = true |
| | | }) |
| | | } |
| | | }) |
| | | |
| | | if (has) { |
| | | search = mainSearch || [] |
| | | } else { |
| | | box.components.forEach(item => { |
| | | if (item.type !== 'tabs') return |
| | | |
| | | item.subtabs.forEach(tab => { |
| | | filterComponent(tab, mainSearch) |
| | | }) |
| | | }) |
| | | } |
| | | } |
| | | filterComponent(menu, null) |
| | | } |
| | | |
| | | this.setState({ |
| | | visible: true |
| | | visible: true, |
| | | mainSearch: search, |
| | | record: {...config.setting} |
| | | }) |
| | | } |
| | | |
| | |
| | | this.setState({loading: true}) |
| | | this.verifyRef.submitDataSource().then(res => { |
| | | |
| | | let MenuType = sessionStorage.getItem('MenuType') |
| | | |
| | | if (MenuType === 'billPrint') { |
| | | res.setting.supModule = ['empty'] |
| | | } |
| | | |
| | | if (!res.setting.primaryKey && res.columns && res.columns.length > 0) { |
| | | res.columns.forEach(col => { |
| | | if (col.field.toLowerCase() === 'id') { |
| | | res.setting.primaryKey = col.field |
| | | } |
| | | }) |
| | | } |
| | | |
| | | if (res.columns) { |
| | | res.columns = res.columns.map(item => { |
| | | if (/int/ig.test(item.datatype)) { |
| | | item.type = 'number' |
| | | item.decimal = 0 |
| | | } else if (/Decimal/ig.test(item.datatype)) { |
| | | item.type = 'number' |
| | | item.decimal = +item.datatype.replace(/^Decimal\(18,/ig, '').replace(/\)/ig, '') |
| | | } else if (/^date/ig.test(item.datatype)) { |
| | | item.type = 'text' |
| | | item.fieldlength = 50 |
| | | } else { |
| | | item.type = 'text' |
| | | item.fieldlength = +item.datatype.replace(/^Nvarchar\(/ig, '').replace(/\)/ig, '') |
| | | } |
| | | return item |
| | | }) |
| | | |
| | | if (!config.fixedCol) { |
| | | res.columns.reverse() |
| | | } |
| | | } |
| | | |
| | | let maxScript = 0 |
| | | let useExec = false |
| | | |
| | | let sFields = [] |
| | | res.searches && res.searches.forEach(item => { |
| | | if (!item.key) return |
| | | |
| | | if (item.type === 'date') { |
| | | if (sFields.includes(item.key)) { |
| | | sFields.push(item.key + '1') |
| | | } else { |
| | | sFields.push(item.key) |
| | | } |
| | | } else if (item.type === 'dateweek' || item.type === 'range' || (item.type === 'datemonth' && item.match !== '=')) { |
| | | sFields.push(item.key) |
| | | sFields.push(item.key + '1') |
| | | } else if (item.type === 'daterange') { |
| | | if (/,/.test(item.key)) { |
| | | sFields.push(item.key.split(',')[0]) |
| | | sFields.push(item.key.split(',')[1]) |
| | | } else { |
| | | sFields.push(item.key) |
| | | sFields.push(item.key + '1') |
| | | } |
| | | } else if (item.type === 'text' || item.type === 'select') { |
| | | item.key.split(',').forEach(field => { |
| | | sFields.push(field) |
| | | }) |
| | | } else { |
| | | sFields.push(item.key) |
| | | } |
| | | }) |
| | | delete res.searches |
| | | sFields = sFields.join('|') |
| | | |
| | | // if (window.GLOB.funcs && window.GLOB.funcs.length > 0) { |
| | | // window.GLOB.funcs.forEach(m => { |
| | | // let reg = new RegExp('\\$ex@' + m.func_code + '@ex\\$', 'ig') |
| | | // if (res.setting.dataresource) { |
| | | // res.setting.dataresource = res.setting.dataresource.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`) |
| | | // } |
| | | // res.scripts.forEach(item => { |
| | | // item.sql = item.sql.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`) |
| | | |
| | | // if (item.status === 'false') return |
| | | |
| | | // if (/exec\s/ig.test(item.sql)) { |
| | | // useExec = true |
| | | // maxScript = 1000 |
| | | // } else if (item.sql.length > maxScript) { |
| | | // maxScript = item.sql.length |
| | | // } |
| | | // }) |
| | | // }) |
| | | // } else { |
| | | // res.scripts.forEach(item => { |
| | | // if (item.status === 'false') return |
| | | |
| | | // if (/exec\s/ig.test(item.sql)) { |
| | | // useExec = true |
| | | // maxScript = 1000 |
| | | // } else if (item.sql.length > maxScript) { |
| | | // maxScript = item.sql.length |
| | | // } |
| | | // }) |
| | | // } |
| | | |
| | | if (res.setting.interType === 'system' && res.setting.dataresource && res.setting.execute !== 'false' && sFields) { |
| | | if (new RegExp(`@(${sFields})@`, 'ig').test(res.setting.dataresource)) { |
| | | maxScript = 1000 |
| | | } |
| | | } |
| | | |
| | | res.scripts.forEach(item => { |
| | | if (item.status === 'false') return |
| | | |
| | | if (/exec\s/ig.test(item.sql)) { |
| | | useExec = true |
| | | maxScript = 1000 |
| | | } else if (sFields && new RegExp(`@(${sFields})@`, 'ig').test(item.sql)) { |
| | | maxScript = 1000 |
| | | } else if (item.sql.length > maxScript) { |
| | | maxScript = item.sql.length |
| | | } |
| | | }) |
| | | |
| | | res.setting.maxScript = maxScript |
| | | |
| | | if (useExec && res.setting.sync === 'true') { |
| | | notification.warning({ |
| | | top: 92, |
| | | message: '当前数据源使用了同步查询且自定义脚本中存在函数exec,如遇接口报错需关闭同步查询后重新测试。', |
| | | duration: 5 |
| | | }) |
| | | } |
| | | |
| | | if (config.subtype !== 'dualdatacard') { |
| | | delete res.subColumns |
| | | if (config.type === 'interface') { |
| | | res.setting.laypage = 'false' |
| | | } |
| | | } else { |
| | | res.subColumns = res.subColumns.map(item => { |
| | | if (/int/ig.test(item.datatype)) { |
| | | item.type = 'number' |
| | | item.decimal = 0 |
| | | } else if (/Decimal/ig.test(item.datatype)) { |
| | | item.type = 'number' |
| | | item.decimal = +item.datatype.replace(/^Decimal\(18,/ig, '').replace(/\)/ig, '') |
| | | } else if (/^date/ig.test(item.datatype)) { |
| | | item.type = 'text' |
| | | item.fieldlength = 50 |
| | | } else { |
| | | item.type = 'text' |
| | | item.fieldlength = +item.datatype.replace(/^Nvarchar\(/ig, '').replace(/\)/ig, '') |
| | | } |
| | | return item |
| | | }) |
| | | |
| | | res.subColumns.reverse() |
| | | } |
| | | |
| | | if (this.verifyRef.state.debugId) { |
| | | res.setting.debugId = this.verifyRef.state.debugId |
| | | } else { |
| | | delete res.setting.debugId |
| | | } |
| | | |
| | | if (res.setting.interType === 'system' && res.setting.sync === 'true') { |
| | | res.scripts && res.scripts.forEach(script => { |
| | | if (script.status === 'false' || script.position !== 'back') return |
| | | |
| | | res.setting.sync = 'false' |
| | | }) |
| | | } |
| | | |
| | | this.setState({loading: false, visible: false}) |
| | | |
| | | if (res.cols) { |
| | | res.cols = [...config.cols, ...res.cols] |
| | | } else { |
| | | delete res.cols |
| | | } |
| | | this.props.updateConfig({...config, ...res}) |
| | | |
| | | if (res.setting && res.setting.tableName && config.setting && !config.setting.tableName) { |
| | | setTimeout(() => { |
| | | MKEmitter.emit('publicTableChange', res.setting.tableName, 'init') |
| | | }, 100) |
| | | } |
| | | |
| | | if ((config.type === 'card' && config.subtype === 'datacard') || (config.type === 'table' && config.subtype === 'normaltable')) { |
| | | setTimeout(() => { |
| | | MKEmitter.emit('mkUpdateInter', {uuid: config.uuid, columns: res.columns}, {delay: 0}) |
| | | }, 150) |
| | | } |
| | | }, () => { |
| | | this.setState({loading: false}) |
| | | }) |
| | | } |
| | | |
| | | cancel = () => { |
| | | this.verifyRef.closeDataSource(() => { |
| | | this.setState({ visible: false, loading: false }) |
| | | }) |
| | | } |
| | | |
| | | creatFunc = () => { |
| | | const { config } = this.props |
| | | const { mainSearch } = this.state |
| | | const menu = window.GLOB.customMenu |
| | | |
| | | return new Promise((resolve) => { |
| | | this.verifyRef.submitDataSource().then(res => { |
| | | let _config = fromJS(config).toJS() |
| | | _config.MenuName = menu.MenuName + '-' + _config.name |
| | | _config.menuNo = menu.MenuNo |
| | | _config.MenuID = menu.MenuID |
| | | _config.setting = res.setting |
| | | _config.columns = res.columns |
| | | _config.func = res.setting.innerFunc |
| | | _config.$type = 'table' |
| | | |
| | | if (res.setting.useMSearch === 'true') { // 使用主搜索条件 |
| | | _config.search = [..._config.search, ...mainSearch] |
| | | } |
| | | |
| | | resolve(_config) |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | render () { |
| | | const { config, menu } = this.props |
| | | const { visible, dict, loading } = this.state |
| | | const { config } = this.props |
| | | const { visible, loading, mainSearch, record } = this.state |
| | | |
| | | return ( |
| | | <div className="model-datasource"> |
| | | <Icon type="setting" onClick={() => this.editDataSource()} /> |
| | | <SettingOutlined title="数据源" onClick={() => this.editDataSource()} /> |
| | | <Modal |
| | | wrapClassName="model-datasource-verify-modal popview-modal" |
| | | title={'数据源配置'} |
| | | wrapClassName="mk-pop-modal" |
| | | title="" |
| | | visible={visible} |
| | | width={'75vw'} |
| | | maskClosable={false} |
| | | style={{minWidth: '900px', maxWidth: '1200px'}} |
| | | okText={dict['model.submit']} |
| | | onOk={this.verifySubmit} |
| | | confirmLoading={loading} |
| | | onCancel={() => { this.setState({ visible: false }) }} |
| | | okText="提交" |
| | | onCancel={() => {this.setState({ visible: false, loading: false }) }} |
| | | footer={[ |
| | | config.subtype !== 'dualdatacard' && record.interType === 'inner' ? <CreateFunc key="create" getMsg={this.creatFunc}/> : null, |
| | | <Button key="cancel" onClick={this.cancel}>取消</Button>, |
| | | <Button key="confirm" type="primary" loading={loading} onClick={this.verifySubmit}>确定</Button> |
| | | ]} |
| | | destroyOnClose |
| | | > |
| | | <VerifyCard |
| | | dict={dict} |
| | | menu={menu} |
| | | mainSearch={mainSearch} |
| | | config={config} |
| | | updRecord={(record) => this.setState({record: record})} |
| | | wrappedComponentRef={(inst) => this.verifyRef = inst} |
| | | /> |
| | | </Modal> |
| | |
| | | } |
| | | } |
| | | |
| | | const mapStateToProps = (state) => { |
| | | return { |
| | | menu: state.customMenu |
| | | } |
| | | } |
| | | |
| | | const mapDispatchToProps = () => { |
| | | return {} |
| | | } |
| | | |
| | | export default connect(mapStateToProps, mapDispatchToProps)(DataSource) |
| | | export default DataSource |